Skip to content

Commit ea8b927

Browse files
avargitster
authored andcommitted
doc lint: lint relative section order
Add a linting script to check the relative order of the sections in the documentation. We should have NAME, then SYNOPSIS, DESCRIPTION, OPTIONS etc. in that order. That holds true throughout our documentation, except for a few exceptions which are hardcoded in the linting script. Signed-off-by: Ævar Arnfjörð Bjarmason <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent cafd982 commit ea8b927

File tree

2 files changed

+127
-1
lines changed

2 files changed

+127
-1
lines changed

Documentation/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,8 @@ lint-docs::
483483
--section=1 $(MAN1_TXT) \
484484
--section=5 $(MAN5_TXT) \
485485
--section=7 $(MAN7_TXT); \
486-
$(PERL_PATH) lint-man-end-blurb.perl $(MAN_TXT)
486+
$(PERL_PATH) lint-man-end-blurb.perl $(MAN_TXT); \
487+
$(PERL_PATH) lint-man-section-order.perl $(MAN_TXT);
487488

488489
ifeq ($(wildcard po/Makefile),po/Makefile)
489490
doc-l10n install-l10n::
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#!/usr/bin/perl
2+
3+
use strict;
4+
use warnings;
5+
6+
my %SECTIONS;
7+
{
8+
my $order = 0;
9+
%SECTIONS = (
10+
'NAME' => {
11+
required => 1,
12+
order => $order++,
13+
},
14+
'SYNOPSIS' => {
15+
required => 1,
16+
order => $order++,
17+
},
18+
'DESCRIPTION' => {
19+
required => 1,
20+
order => $order++,
21+
bad => {
22+
'git-mktag.txt' => 'OPTIONS',
23+
'git-cvsserver.txt' => 'OPTIONS',
24+
},
25+
},
26+
'OPTIONS' => {
27+
order => $order++,
28+
required => 0,
29+
bad => {
30+
'git-grep.txt' => 'CONFIGURATION',
31+
'git-rebase.txt' => 'CONFIGURATION',
32+
},
33+
},
34+
'CONFIGURATION' => {
35+
order => $order++,
36+
bad => {
37+
'git-svn.txt' => 'BUGS',
38+
},
39+
},
40+
'BUGS' => {
41+
order => $order++,
42+
},
43+
'SEE ALSO' => {
44+
order => $order++,
45+
},
46+
'GIT' => {
47+
required => 1,
48+
order => $order++,
49+
},
50+
);
51+
}
52+
my $SECTION_RX = do {
53+
my ($names) = join "|", keys %SECTIONS;
54+
qr/^($names)$/s;
55+
};
56+
57+
my $exit_code = 0;
58+
sub report {
59+
my ($msg) = @_;
60+
print "$ARGV:$.: $msg\n";
61+
$exit_code = 1;
62+
}
63+
64+
my $last_was_section;
65+
my @actual_order;
66+
while (my $line = <>) {
67+
chomp $line;
68+
if ($line =~ $SECTION_RX) {
69+
push @actual_order => $line;
70+
$last_was_section = 1;
71+
# Have no "last" section yet, processing NAME
72+
next if @actual_order == 1;
73+
74+
my @expected_order = sort {
75+
$SECTIONS{$a}->{order} <=> $SECTIONS{$b}->{order}
76+
} @actual_order;
77+
78+
my $expected_last = $expected_order[-2];
79+
my $actual_last = $actual_order[-2];
80+
my $except_last = $SECTIONS{$line}->{bad}->{$ARGV} || '';
81+
if (($SECTIONS{$line}->{bad}->{$ARGV} || '') eq $actual_last) {
82+
# Either we're whitelisted, or ...
83+
next
84+
} elsif (exists $SECTIONS{$actual_last}->{bad}->{$ARGV}) {
85+
# ... we're complaing about the next section
86+
# which is out of order because this one is,
87+
# don't complain about that one.
88+
next;
89+
} elsif ($actual_last ne $expected_last) {
90+
report("section '$line' incorrectly ordered, comes after '$actual_last'");
91+
}
92+
next;
93+
}
94+
if ($last_was_section) {
95+
my $last_section = $actual_order[-1];
96+
if (length $last_section ne length $line) {
97+
report("dashes under '$last_section' should match its length!");
98+
}
99+
if ($line !~ /^-+$/) {
100+
report("dashes under '$last_section' should be '-' dashes!");
101+
}
102+
$last_was_section = 0;
103+
}
104+
105+
if (eof) {
106+
# We have both a hash and an array to consider, for
107+
# convenience
108+
my %actual_sections;
109+
@actual_sections{@actual_order} = ();
110+
111+
for my $section (sort keys %SECTIONS) {
112+
next if !$SECTIONS{$section}->{required} or exists $actual_sections{$section};
113+
report("has no required '$section' section!");
114+
}
115+
116+
# Reset per-file state
117+
{
118+
@actual_order = ();
119+
# this resets our $. for each file
120+
close ARGV;
121+
}
122+
}
123+
}
124+
125+
exit $exit_code;

0 commit comments

Comments
 (0)