git/Documentation/lint-gitlink.perl
Ævar Arnfjörð Bjarmason d2c9908076 doc lint: fix bugs in, simplify and improve lint script
The lint-gitlink.perl script added in ab81411ced (ci: validate
"linkgit:" in documentation, 2016-05-04) was more complex than it
needed to be. It:

 - Was using File::Find to recursively find *.txt files in
   Documentation/, let's instead use the Makefile as a source of truth
   for *.txt files, and pass it down to the script.

 - We now don't lint linkgit:* in RelNotes/* or technical/*, which we
   shouldn't have been doing in the first place anyway.

 - When the doc-diff script was added in beb188e22a (add a script to
   diff rendered documentation, 2018-08-06) we started sometimes having
   a "git worktree" under Documentation/.

   This tree contains a full checkout of git.git, as a result the
   "lint" script would recurse into that, and lint any *.txt file
   found in that entire repository.

   In practice the only in-tree "linkgit" outside of the
   Documentation/ tree is contrib/contacts/git-contacts.txt and
   contrib/subtree/git-subtree.txt, so this wouldn't emit any errors

Now we instead simply trust the Makefile to give us *.txt files.
Since the Makefile also knows what sections each page should be in we
don't have to open the files ourselves and try to parse that out. As a
bonus this will also catch bugs with the section line in the files
themselves being incorrect.

The structure of the new script is mostly based on
t/check-non-portable-shell.pl. As an added bonus it will also use
pos() to print where the problems it finds are, e.g. given an issue
like:

    diff --git a/Documentation/git-cherry.txt b/Documentation/git-cherry.txt
    [...]
     and line numbers.  git-cherry therefore detects when commits have been
    -"copied" by means of linkgit:git-cherry-pick[1], linkgit:git-am[1] or
    -linkgit:git-rebase[1].
    +"copied" by means of linkgit:git-cherry-pick[2], linkgit:git-am[3] or
    +linkgit:git-rebase[4].

We'll now emit:

    git-cherry.txt:20: error: git-cherry-pick[2]: wrong section (should be 1), shown with 'HERE' below:
    git-cherry.txt:20:      '"copied" by means of linkgit:git-cherry-pick[2]' <-- HERE
    git-cherry.txt:20: error: git-am[3]: wrong section (should be 1), shown with 'HERE' below:
    git-cherry.txt:20:      '"copied" by means of linkgit:git-cherry-pick[2], linkgit:git-am[3]' <-- HERE
    git-cherry.txt:21: error: git-rebase[4]: wrong section (should be 1), shown with 'HERE' below:
    git-cherry.txt:21:      'linkgit:git-rebase[4]' <-- HERE

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-04-10 23:36:34 -07:00

68 lines
1.4 KiB
Perl
Executable File

#!/usr/bin/perl
use strict;
use warnings;
# Parse arguments, a simple state machine for input like:
#
# howto/*.txt config/*.txt --section=1 git.txt git-add.txt [...] --to-lint git-add.txt a-file.txt [...]
my %TXT;
my %SECTION;
my $section;
my $lint_these = 0;
for my $arg (@ARGV) {
if (my ($sec) = $arg =~ /^--section=(\d+)$/s) {
$section = $sec;
next;
}
my ($name) = $arg =~ /^(.*?)\.txt$/s;
unless (defined $section) {
$TXT{$name} = $arg;
next;
}
$SECTION{$name} = $section;
}
my $exit_code = 0;
sub report {
my ($pos, $line, $target, $msg) = @_;
substr($line, $pos) = "' <-- HERE";
$line =~ s/^\s+//;
print "$ARGV:$.: error: $target: $msg, shown with 'HERE' below:\n";
print "$ARGV:$.:\t'$line\n";
$exit_code = 1;
}
@ARGV = sort values %TXT;
die "BUG: Nothing to process!" unless @ARGV;
while (<>) {
my $line = $_;
while ($line =~ m/linkgit:((.*?)\[(\d)\])/g) {
my $pos = pos $line;
my ($target, $page, $section) = ($1, $2, $3);
# De-AsciiDoc
$page =~ s/{litdd}/--/g;
if (!exists $TXT{$page}) {
report($pos, $line, $target, "link outside of our own docs");
next;
}
if (!exists $SECTION{$page}) {
report($pos, $line, $target, "link outside of our sectioned docs");
next;
}
my $real_section = $SECTION{$page};
if ($section != $SECTION{$page}) {
report($pos, $line, $target, "wrong section (should be $real_section)");
next;
}
}
# this resets our $. for each file
close ARGV if eof;
}
exit $exit_code;