PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/source/texk/texlive/linked_scripts/svn-multi/svn-multi.pl

https://bitbucket.org/clerkma/eat
Perl | 372 lines | 278 code | 40 blank | 54 comment | 42 complexity | c095c6cb5b079d8a22c361d07f4036d3 MD5 | raw file
  1. #!/usr/bin/perl
  2. # --------------------------------------------------------------
  3. # svn-multi.pl for the svn-multi v2.0 LaTeX package
  4. # version 0.1, Mar 1st, 2009
  5. # --------------------------------------------------------------
  6. #
  7. # Copyright (C) 2006-2012 Martin Scharrer
  8. # E-mail: martin@scharrer-online.de
  9. # Code repository: https://bitbucket.org/martin_scharrer/svn-multi
  10. #
  11. # This program works only in combination with the LaTeX package 'svn-multi' and
  12. # generates .svx files with '\svnidlong' macros holding Subversion keywords for
  13. # files declared with '\svnexternal' inside the LaTeX document.
  14. #
  15. # This program is free software under the GPL v3 and LPPL v1.3c or later.
  16. #
  17. #
  18. # GPL v3:
  19. # This program is free software: you can redistribute it and/or modify
  20. # it under the terms of the GNU General Public License as published by
  21. # the Free Software Foundation, either version 3 of the License, or
  22. # (at your option) any later version.
  23. #
  24. # This program is distributed in the hope that it will be useful,
  25. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  27. # GNU General Public License for more details.
  28. #
  29. # You should have received a copy of the GNU General Public License
  30. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  31. #
  32. #
  33. # LPPL v1.3c:
  34. # This work may be distributed and/or modified under the
  35. # conditions of the LaTeX Project Public License, either version 1.3c
  36. # of this license or (at your option) any later version.
  37. # The latest version of this license is in
  38. # http://www.latex-project.org/lppl.txt
  39. # and version 1.3c or later is part of all distributions of LaTeX
  40. # version 2008/05/04 or later.
  41. #
  42. # This work has the LPPL maintenance status `maintained'.
  43. #
  44. # The Current Maintainer of this work is Martin Scharrer.
  45. #
  46. # This work consists of the files svn-multi.dtx, svn-multi-pl.dtx and
  47. # svn-multi.ins and the derived files svn-multi.sty, svnkw.sty and svn-multi.pl.
  48. #
  49. # The file 'svn-multi.pl' may be renamed to 'svn-multi' for installation
  50. # purposes.
  51. #
  52. #
  53. use strict;
  54. use warnings;
  55. use File::Basename;
  56. my $VERSION = "0.2";
  57. my ($REV,$DATE) =
  58. (split ' ','$Id$')[2,3];
  59. my $dollar = '$';
  60. my @PATH;
  61. my %EXCLUDE = map { $_ => 1 } qw(sty tex aux log out toc fff ttt svn svx);
  62. sub create_svxfile ($@);
  63. sub usage;
  64. if (!@ARGV or grep { $_ eq '--help' or $_ eq '-h' } @ARGV) {
  65. usage();
  66. }
  67. print STDOUT "This is svn-multi.pl, Version $VERSION-$REV, $DATE\n";
  68. my ($jobname, $dir, $suffix) = fileparse(shift @ARGV, qr/\.(tex|ltx|dtx|svn)$/);
  69. if ($dir && $dir ne './') {
  70. printf STDOUT "Main directory is '$dir'.\n";
  71. chdir($dir);
  72. }
  73. if ($jobname =~ /^-/) {
  74. usage();
  75. }
  76. my $outfile = "$jobname.svx";
  77. my %external;
  78. my $resvnexternalpath = qr/
  79. ^ # at begin of line
  80. \s* # allow for spaces
  81. \\\@svnexternalpath # the macro name
  82. \s*
  83. { # begin token group
  84. \s*
  85. (?: # paths:
  86. { # { of first path
  87. (.*) # everything else, e.g: 'patha}{pathb}{pathc'
  88. } # } of last path
  89. | # or nothing
  90. )
  91. \s*
  92. } # end token group
  93. \s*
  94. $ # end of line
  95. /x;
  96. my $resvnexternal = qr/
  97. ^ # at begin of line
  98. \s* # allow for spaces
  99. \\\@svnexternal # the macro name
  100. \s*
  101. (?: # optional:
  102. \[ # opening [
  103. ([^\]]*) # group name (everything until ])
  104. \] # closing ]
  105. )?
  106. \s*
  107. { # begin token group
  108. ([^}]+) # file name (everything until })
  109. } # end token group
  110. \s*
  111. { # begin token group
  112. \s*
  113. (?: # paths:
  114. { # { of first file
  115. (.*) # everything else, e.g: 'filea}{fileb}{filec'
  116. } # } of last file
  117. | # or nothing
  118. )
  119. \s*
  120. } # end token group
  121. \s*
  122. $ # end of line
  123. /x;
  124. if (-e "$jobname.aux" and open( my $svnfh, '<', "$jobname.aux")) {
  125. print STDOUT "Reading '$jobname.aux'.\n";
  126. while (<$svnfh>) {
  127. chomp;
  128. if (/$resvnexternalpath/) {
  129. push @PATH, ( split /}\s*{/, $1 );
  130. }
  131. elsif (/$resvnexternal/) {
  132. my ($group,$file,$list) = ($1||"",$2,$3||"");
  133. $file =~ s/^\.\///;
  134. push @{$external{$file}{$group} ||= []}, ( split /}\s*{/, $list );
  135. }
  136. }
  137. close ($svnfh);
  138. }
  139. else {
  140. warn "No .aux file found for '$jobname'!\n";
  141. }
  142. # Add TEXINPUTS to path
  143. push @PATH, map { $_ =~ s/(?<!\/)$/\//; $_ } grep { $_ }
  144. split(':', $ENV{'TEXINPUTS'}||"");
  145. my @mainfilepairs;
  146. my $maintex = "$jobname.tex";
  147. if (exists $external{$maintex}) {
  148. while ( my ($group,$list) = each %{$external{$maintex}} ) {
  149. push @mainfilepairs, [ $group, [ @$list ] ];
  150. }
  151. delete $external{$maintex};
  152. }
  153. push @mainfilepairs, parse_args(@ARGV);
  154. create_svxfile("$jobname.svx", @mainfilepairs )
  155. if @mainfilepairs;
  156. foreach my $file (keys %external) {
  157. my @pairs;
  158. my $svxfile = $file;
  159. $svxfile =~ s/\.(tex|ltx)$/.svx/;
  160. while ( my ($group,$list) = each %{$external{$file}} ) {
  161. push @pairs, [ $group, [ @$list ] ];
  162. }
  163. create_svxfile($svxfile, @pairs);
  164. }
  165. sub parse_args {
  166. my @args = @_;
  167. my $group = '';
  168. my @files;
  169. my $readfg;
  170. my @pairs;
  171. foreach my $arg (@args) {
  172. if ($readfg) {
  173. $readfg = 0;
  174. $group = $arg;
  175. $group =~ s/^["']|["']$//; # '
  176. }
  177. elsif ($arg =~ /^--group|^-?-fg/) {
  178. push @pairs, [ $group, [ @files ] ];
  179. @files = ();
  180. if ($arg =~ /^--group=(.*)/) {
  181. $group = $1;
  182. $group =~ s/^["']|["']$//; # '
  183. }
  184. else {
  185. $readfg = 1;
  186. }
  187. }
  188. elsif ($arg =~ /^--fls/) {
  189. push @files, read_fls("$jobname.fls");
  190. }
  191. else {
  192. push @files, $arg;
  193. }
  194. }
  195. push @pairs, [ $group, [ @files ] ] if @files;
  196. return @pairs;
  197. }
  198. sub path_search {
  199. my $file = shift;
  200. $file =~ s/##/#/g;
  201. return $file if not $file or -e $file or not @PATH;
  202. foreach my $dir (@PATH) {
  203. if (-e "$dir$file") {
  204. return "$dir$file";
  205. }
  206. }
  207. return $file;
  208. }
  209. sub create_svxfile ($@) {
  210. my ($svxfile, @fgpair) = @_;
  211. my $lastgroup;
  212. my $fgused = 0;
  213. my %seen;
  214. return if not @fgpair or not $svxfile;
  215. open(my $svxfh, '>', $svxfile) or do {
  216. warn "ERROR: Could not create SVX file '$svxfile'!\n";
  217. return;
  218. };
  219. print STDOUT "Generating .svx file '$svxfile'.\n";
  220. select $svxfh;
  221. print "% Generated by svn-multi.pl v$VERSION\n\n";
  222. while ( my ($group, $files) = @{shift @fgpair||[]}) {
  223. no warnings 'uninitialized';
  224. if ( (not defined $lastgroup and $group) or ($group ne $lastgroup) ) {
  225. print "\\svngroup{$group}\n";
  226. }
  227. use warnings;
  228. if ($group) {
  229. $fgused = 1;
  230. }
  231. foreach my $file (@$files) {
  232. $file = path_search($file);
  233. # Only print the file once per group and .svx file
  234. next if $seen{$group}{$file};
  235. $seen{$group}{$file} = 1;
  236. open(my $infoh, '-|', "svn info '$file' 2>/dev/null") or next;
  237. my %info = map { chomp; split /\s*:\s*/, $_, 2 } <$infoh>;
  238. close($infoh);
  239. if (not keys %info) {
  240. print "% Could not receive keywords for '$file'!\n\n";
  241. next;
  242. }
  243. print "% Keywords for '$file'\n";
  244. print svnidlong(\%info);
  245. print "\\svnexternalfile";
  246. print "[$group]" if $group;
  247. print "{$file}\n";
  248. print "\n"
  249. }
  250. $lastgroup = $group;
  251. }
  252. print "\n";
  253. close ($svxfh);
  254. }
  255. sub svnid {
  256. use Date::Parse;
  257. use Date::Format;
  258. my $href = shift;
  259. return "" if (not defined $href->{Name});
  260. my $date = time2str("%Y-%m-%d %XZ", str2time($href->{'Last Changed Date'}), 'Z');
  261. return <<"EOT";
  262. \\svnid{${dollar}Id: $href->{Name} $href->{'Last Changed Rev'} $date $href->{'Last Changed Author'} \$}
  263. EOT
  264. }
  265. sub svnidlong {
  266. my $href = shift;
  267. return <<"EOT";
  268. \\svnidlong
  269. {${dollar}HeadURL: $href->{URL} \$}
  270. {${dollar}LastChangedDate: $href->{'Last Changed Date'} \$}
  271. {${dollar}LastChangedRevision: $href->{'Last Changed Rev'} \$}
  272. {${dollar}LastChangedBy: $href->{'Last Changed Author'} \$}
  273. EOT
  274. }
  275. sub read_fls {
  276. my $fls = shift;
  277. my %stack;
  278. open (my $fh, '<', $fls) or return;
  279. while (<$fh>) {
  280. chomp;
  281. if (/^INPUT ([^\/].*)$/) {
  282. my $file = $1;
  283. my $ext = substr($file, rindex($file,'.')+1);
  284. $stack{$1} = 1 if not exists $EXCLUDE{$ext};
  285. }
  286. }
  287. close($fh);
  288. return keys %stack;
  289. }
  290. sub usage {
  291. print STDOUT <<'EOT';
  292. Usage:
  293. svn-multi.pl jobname[.tex] [--fls] [--group|-g <group name>] [input_files] ...
  294. ... [--group|-g <group name>] [input_files] ...
  295. Description:
  296. This LaTeX helper script collects Subversion keywords from non-(La)TeX files
  297. and provides it to the 'svn-multi' package using '.svx' files. It will first
  298. scan the file '<jobname>.aux' for files declared by the '\svnextern' macro but
  299. also allows to provide additional files including the corresponding groups. The
  300. keywords for the additional files will be written in the file '<jobname>.svx'.
  301. Options:
  302. jobname[.tex] : The LaTeX `jobname`, i.e. the basename of your main LaTeX file.
  303. --group <GN> : Use given group name <GN> for all following files,
  304. or -g <GN> including the one read by a '--fls' option, until the next
  305. group is specified.
  306. --fls : Read list of (additional) files from the file '<jobname>.fls'. This
  307. file is produced by LaTeX when run with the '--recorder' option and
  308. contains a list of all input and output files used by the LaTeX main
  309. file. Only input files with a relative path will be used. A
  310. previously selected group will be honoured.
  311. Examples:
  312. The main LaTeX file here is 'mymainlatexfile.tex'.
  313. svn-multi.pl mymainlatexfile
  314. Creates Subversion keywords for all files declared by '\svnextern' inside
  315. the LaTeX code.
  316. svn-multi.pl mymainlatexfile --group=FLS --fls
  317. Creates Subversion keywords for all files declared by '\svnextern' inside
  318. the LaTeX code. In addition it does the same for all relative input files
  319. mentioned in the .fls file which are placed in the 'FLS' group.
  320. svn-multi.pl mymainlatexfile a b c --group=B e d f
  321. In addition to the '\svnextern' declared files the keywords for the files
  322. 'a', 'b' and 'c' will be added without a specific group, i.e. the last group
  323. specified in the LaTeX file before the '\svnextern' macro will be used. The
  324. keywords for 'e', 'd', 'f' will be part of group 'B'.
  325. svn-multi.pl mymainlatexfile --group=A a --group=B b --group='' c
  326. File 'a' is in group 'A', 'b' is in 'B' and 'c' is not in any group.
  327. Further Information:
  328. See the svn-multi package manual for more information about this script.
  329. EOT
  330. exit(0);
  331. }
  332. __END__