diff --git a/Documentation/Makefile b/Documentation/Makefile index 747b849..8ce75d2 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -125,7 +125,7 @@ endif SHELL_PATH ?= $(SHELL) # Shell quote; -SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) #' +SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) # # Please note that there is a minor bug in asciidoc. @@ -320,12 +320,10 @@ howto-index.txt: howto-index.sh $(wildcard howto/*.txt) '$(SHELL_PATH_SQ)' ./howto-index.sh $(wildcard howto/*.txt) >$@+ && \ mv $@+ $@ -config-vars.txt: config-vars-src.txt $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT) - ./make-config-list.perl --mainlist=config-vars-src.txt \ - --ignore=config-vars.txt \ - $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT) \ - > config-vars.txt+ && \ - mv config-vars.txt+ config-vars.txt +config-vars.txt: config-vars-src.txt $(MAN_TXT) $(cmds_txt) + $(QUIET_GEN)$(PERL_PATH) ./make-config-list.perl \ + --mainlist=$< --ignore=$@ --ignore=merge-config.txt $(MAN_TXT) >$@+ && \ + mv $@+ $@ $(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt $(QUIET_ASCIIDOC)$(ASCIIDOC) $(ASCIIDOC_EXTRA) -b xhtml11 $*.txt diff --git a/Documentation/config-vars-src.txt b/Documentation/config-vars-src.txt index 949259c..a8d37a7 100644 --- a/Documentation/config-vars-src.txt +++ b/Documentation/config-vars-src.txt @@ -936,7 +936,7 @@ gitcvs.dbname:: gitcvs.dbdriver:: Used Perl DBI driver. You can specify any available driver - for this here, but it might not work. git-cvsserver is tested + for this here, but it might not work. git-cvsserver is tested with 'DBD::SQLite', reported to work with 'DBD::Pg', and reported *not* to work with 'DBD::mysql'. Experimental feature. May not contain double colons (`:`). Default: 'SQLite'. diff --git a/Documentation/make-config-list.perl b/Documentation/make-config-list.perl index f086867..2894d96 100755 --- a/Documentation/make-config-list.perl +++ b/Documentation/make-config-list.perl @@ -4,128 +4,165 @@ use strict; use warnings; use Getopt::Long; + my %ignore; - my $rc = GetOptions( "mainlist=s" => \my $mainlistfile, "ignore=s" => sub { $ignore{$_[1]} = 1 }, - "no-sort" => \my $no_sort, - ); +); -if (!$rc or (!-r $mainlistfile)) { +if (!$rc || !defined $mainlistfile) { print "$0 --mainlist= [--ignore=...] ...\n"; exit 1; } +my %var_manpages; +my %manpage_section; + +foreach my $name (@ARGV) { + read_man_txt($name); +} + +my ($mainlist, $mainvars) = read_varlist($mainlistfile); + +my @missing_vars = + grep { !exists $mainlist->{lc($_)} } keys %var_manpages; +my %missing_vars = + map { $_ => $var_manpages{$_} } @missing_vars; + +my %insert = find_insertion_points($mainlist, \%missing_vars); + +open my $fh, '<', $mainlistfile + or die "Couldn't open '$mainlistfile' for reading: $!"; +while (<$fh>) { + if (exists $insert{$.}) { + print vars_documentation($insert{$.}, \%missing_vars); + print "\n"; + } + print; +} +# special case: insertion after last line in $mainlistfile +print vars_documentation($insert{-1}, \%missing_vars) + if exists $insert{-1}; +close $fh + or die "Couldn't close '$mainlistfile': $!"; + +exit 0; + +# ---------------------------------------------------------------------- +# ---------------------------------------------------------------------- +# ---------------------------------------------------------------------- + sub read_varlist { - my ($file) = @_; + my ($filename) = @_; + + open my $fh, '<', $filename + or die "Couldn't open '$filename' for reading: $!"; - open my $fh, "<", $file or die "cannot open $file: $!"; my (%mainlist, @mainvars); - - my ($v, $last_v); - my $in_block = 0; while (<$fh>) { if (/^(\S+)::/) { - $v = lc $1; - $in_block = 0; - push @{$mainlist{$v}}, $_; + my $v = $1; push @mainvars, $v; - } elsif (/^$/ && !$in_block) { - if (defined $last_v && !$#{$mainlist{$last_v}}) { - $mainlist{$last_v} = $mainlist{$v}; - } - $last_v = $v; - } elsif (defined $v) { - push @{$mainlist{$v}}, $_; - $in_block = !$in_block if /^--$/; + $mainlist{lc($v)} = $.; } } - close $fh or die "eh? close failed: $!"; + close $fh + or die "Couldn't close '$filename': $!"; return \%mainlist, \@mainvars; } -my %vars; -my %sections; - -sub read_file { - my ($name, $main_name) = @_; - if (!defined $main_name) { - $main_name = $name; +sub read_man_txt { + my ($filename, $manpage) = @_; + if (!defined $manpage) { + $manpage = $filename; + $manpage =~ s/\.txt//; } - my $manpage_name = $main_name; - $manpage_name =~ s/\.txt//; - my $fp; - open $fp, '<', $name or die "open $name failed: $!"; - while (<$fp>) { - if ($. < 5 && /^$manpage_name\((\d+)\)/) { - $sections{$manpage_name} = $1; + + open my $fh, '<', $filename + or die "Couldn't open '$filename' for reading: $!"; + while (<$fh>) { + if ($. < 5 && /^$manpage\((\d+)\)/) { + $manpage_section{$manpage} = $1; } - if (/^([a-z0-9]+\.[a-z<>0-9.]+)::/) { - push @{$vars{$1}}, $manpage_name; + if (/^([a-z0-9]+\.[a-zA-Z<>0-9.]+)::/) { + push @{$var_manpages{$1}}, $manpage; } - if (/^include::\s*(\S+)\s*\[\]/ - && !exists $ignore{$1}) { - read_file($1, $main_name); + if (/^include::\s*(\S+)\s*\[\]/ && + !exists $ignore{$1}) { + read_man_txt($1, $manpage); } } - close $fp or die "close $name failed: $!"; -} - -foreach my $name (@ARGV) { - read_file($name); + close $fh + or die "Couldn't close '$filename': $!"; } -my ($mainlist, $mainvars) = read_varlist($mainlistfile); - -my @all_keys = @$mainvars; -foreach my $k (keys %vars) { - if (!exists $mainlist->{$k}) { - push @all_keys, $k; - } -} +sub find_insertion_points { + my ($mainlist, $missing_vars) = @_; + my %insert; -@all_keys = sort @all_keys unless $no_sort; + my %all_vars = (%$mainlist, %$missing_vars); + my $lineno = -1; # means after last line -my %out; -foreach my $k (@all_keys) { - if (exists $mainlist->{$k}) { - push @{$out{$k}}, @{$mainlist->{$k}}, "\n"; - } elsif (exists $vars{$k}) { - push @{$out{$k}}, $k . "::\n"; - push @{$out{$k}}, "\tSee "; - my $sep = " "; - foreach my $p (sort @{$vars{$k}}) { - next if ($p =~ /$mainlistfile/); - if (!exists $sections{$p}) { - warn "section for $p unknown"; - $sections{$p} = 1; + # reverse order because we want to find a place before which to insert + # generated documentation; it is easy to find where description + # of variable begins, but in general harder to find where it ends. + my @sorted_vars = reverse sort { lc($a) cmp lc($b) } keys %all_vars; + foreach my $key (@sorted_vars) { + my $val = $all_vars{$key}; + if (ref $val) { + # this came from %$missing_vars + push @{$insert{$lineno}}, $key; + } else { + # this came from %$mainlist + if ($lineno < 0) { + # $lineno < 0 means after end of file (special case) + $lineno = $val; + } else { + # this is in case of unsorted entries in $mainlistfile + $lineno = $val < $lineno ? $val : $lineno; # min($val, $lineno) } - push @{$out{$k}}, $sep . "linkgit:" . $p . "[" . $sections{$p} . "]"; - $sep = ", "; } - push @{$out{$k}}, ".\n\n"; - } else { - die "can't happen: $k not in any source"; } + return %insert; } -for (my $i = 0; $i < $#all_keys; $i++) { - next if $#{$out{$all_keys[$i]}} != $#{$out{$all_keys[$i+1]}}; - my $same = 1; - for (my $j = 1; $j <= $#{$out{$all_keys[$i]}}; $j++) { - if ($out{$all_keys[$i]}[$j] ne $out{$all_keys[$i+1]}[$j]) { - $same = 0; - last; - } +sub vars_documentation { + my ($keylist, $vars) = @_; + my @keys = sort @$keylist; + my %out; + + # generate output for each key now, because it is easier to compare + # strings than arrays; comparing which is needed for compacting output + foreach my $k (@keys) { + $out{$k} = "\tSee: ".gen_links($vars->{$k}).".\n"; } - if ($same) { - $out{$all_keys[$i]} = [$out{$all_keys[$i]}[0]]; + + my $output = ''; + while (my $k = pop @keys) { + $output .= $k."::\n"; + unless (@keys && $out{$k} eq $out{$keys[0]}) { + $output .= $out{$k}; + } } + return $output; } -foreach my $k (@all_keys) { - print @{$out{$k}}; +sub gen_links { + my $manpages = shift; + return join(", ", map { linkgit($_) } @$manpages); } + +sub linkgit { + my $manpage = shift; + + if (!exists $manpage_section{$manpage}) { + warn "section for $manpage unknown, assuming '1'\n"; + $manpage_section{$manpage} = 1; + } + return "linkgit:${manpage}[$manpage_section{$manpage}]"; +} + +__END__