summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/latex-git-log/latex-git-log
blob: e074d05a5ce0092441d0b35c301fc3c951d34db1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
#!/usr/bin/env perl
# @author Robin Schneider <ypid23@aol.de>
# @licence GPLv3+ <http://www.gnu.org/licenses/gpl.html>

# Modules and pragmas {{{
use strict;
use warnings;
use autodie;
use feature qw(say);
use utf8;
use open qw(:std :utf8);
binmode STDOUT, ':encoding(UTF-8)';
use IPC::System::Simple qw(capturex);
use Getopt::Long;
use Pod::Usage;

# Get the path where this script is located {{{
my $dirpath;

BEGIN {
    use File::Basename qw(fileparse);
    use Cwd qw(abs_path);
    $dirpath = ( fileparse( abs_path($0) ) )[1];
}
# }}}
use Locale::Maketext::Simple (
    Path   => $dirpath . 'po/',
    Decode => 1,
);
# }}}

# Optional parameters {{{
my $print_author = 0;
my $commit_count = 1;
my $width        = 0;
my $lang         = undef;
my $version      = 0;
my $help         = 0;
my $man          = 0;
my ( $git_user, $git_repo, $git_commit_address );
GetOptions(
    'author'        => \$print_author,
    'startcommit=s' => \$commit_count,
    'width=s'       => \$width,
    'git-c-add=s'   => \$git_commit_address,
    'user=s'        => \$git_user,
    'repo=s'        => \$git_repo,
    'lang=s'        => \$lang,
    'version'       => \$version,
    'help|?'        => \$help,
    'man'           => \$man,
);
pod2usage(1) if $help;
pod2usage( -verbose => 2,  -exitstatus => 0, )        if $man;
pod2usage( -verbose => 99, -sections   => 'Version' ) if $version;
my $git_remote = ( split /\n/xms, capturex(qw(git remote -v)) )[0];

loc_lang($lang) if ( defined $lang );
if (    not defined $git_user
    and not defined $git_repo
    and defined $git_remote
    and $git_remote =~ m#\s.*?:(?<user>\w+?)/(?<repo>.*?)\.git\ \(fetch\)\Z#xms )
{
    $git_user = $+{user};
    $git_repo = $+{repo};
}
say '%% This file was generated by the script latex-git-log';
my $git_command_commit_msg = '%s';
if ( defined $git_user and defined $git_repo ) {
    unless ( defined $git_commit_address ) {
        $git_commit_address = "https://github.com/$+{user}/$+{repo}/commit";
    }
    $git_command_commit_msg = '%H & %s';
    say '%% Base git commit URL: ' . $git_commit_address;
}
if ($width) {
    $width = "p{${width}cm}";
}
else {
    $width = 'l';
}
# }}}

# LaTeX template {{{
say '\begin{tabular}{lp{12cm}}
  \label{tabular:legend:git-log}
  \textbf{' . loc('acronym') . '} & \textbf{' . loc('meaning') . '} \\\\
  V & \texttt{' . loc('version') . '} \\\\
  ' . loc('tag') . ' & ' . loc('\texttt{git tag}') . ' \\\\
  ' . loc('MF') . ' & ' . loc('Number of \texttt{modified files}.') . ' \\\\
  ' . loc('AL') . ' & ' . loc('Number of \texttt{added lines}.') . ' \\\\
  ' . loc('DL') . ' & ' . loc('Number of \texttt{deleted lines}.') . ' \\\\
\end{tabular}

\bigskip

\iflanguage{ngerman}{\shorthandoff{"}}{}';

if ($print_author) {
    say "\\begin{longtable}{|rllllrrr|}";
}
else {
    say "\\begin{longtable}{|rll${width}rrr|}";
}
say '\hline \multicolumn{1}{|c}{\textbf{' . loc('V') . '}} & \multicolumn{1}{c}{\textbf{' . loc('tag') . '}}';
say '& \multicolumn{1}{c}{\textbf{' . loc('author') . '}}' if $print_author;
say '& \multicolumn{1}{c}{\textbf{' . loc('date') . '}}
& \multicolumn{1}{c}{\textbf{' . loc('commit message') . '}} & \multicolumn{1}{c}{\textbf{' . loc('MF') . '}}
& \multicolumn{1}{c}{\textbf{' . loc('AL') . '}} & \multicolumn{1}{c|}{\textbf{' . loc('DL') . '}} \\\\ \hline
\endhead
';
if ($print_author) {
    say '\hline \multicolumn{8}{|r|}{\longtableendfoot} \\\\ \hline';
}
else {
    say '\hline \multicolumn{7}{|r|}{\longtableendfoot} \\\\ \hline';
}
say '\endfoot

\hline% \hline
\endlastfoot
';
# }}}

# Get version history from git log {{{
# git log --pretty=format:'%ai'
# git log --date=short --pretty=format:'%ad'
my @lines;
my @git_command = qw(git log --date=short --shortstat);
if ($print_author) {
    push( @git_command, qq(--pretty=format:%H & %an NoTinAuthorFiled& %ad & $git_command_commit_msg) );
}
else {
    push( @git_command, qq(--pretty=format:%H %ad & $git_command_commit_msg) );
}
@lines = reverse capturex(@git_command);
# }}}

# Get tags {{{
my @tags_commits = capturex( 'git', 'for-each-ref', '--format=%(refname:short) %(objectname)', 'refs/tags' );
my %commit_tags; # The key will be a SHA1 commit hash and the value a comma separated list of all tags.
for (@tags_commits) {
    my ( $tag, $c_hash ) = split /\s/xms, $_;
    chomp($c_hash);
    if ( defined $commit_tags{$c_hash} ) {
        $commit_tags{$c_hash} .= ", $tag";
    }
    else {
        $commit_tags{$c_hash} = $tag;
    }
}
# }}}

# Helper function {{{
sub latex_escape {
    # Source: http://ommammatips.blogspot.de/2011/01/perl-function-for-latex-escape.html
    my $paragraph = shift;

    # Replace a \ with $\backslash$
    # This is made more complicated because the dollars will be escaped
    # by the subsequent replacement. Easiest to add \backslash
    # now and then add the dollars
    $paragraph =~ s/\\/\\backslash/g;

    # Must be done after escape of \ since this command adds latex escapes
    # Replace characters that can be escaped
    $paragraph =~ s/([\$\#&%_{}])/\\$1/g;

    # Replace ^ characters with \^{} so that $^F works okay
    $paragraph =~ s/(\^)/\\$1\{\}/g;

    # Replace tilde (~) with \texttt{\~{}}
    # $paragraph =~ s/~/\\texttt\{\\~\{\}\}/g;
    $paragraph =~ s/~/\\~\{\}/g;

    # Now add the dollars around each \backslash
    $paragraph =~ s/(\\backslash)/\$$1\$/g;
    return $paragraph;
} ## end sub latex_escape
# }}}

# Loop over all commits {{{
my $which_line = 0;
my @changes;
for (@lines) {
    next if /\A\Z/xms;
    chomp;
    if ($which_line) {
        s/\A([0-9a-f]{40})\s//xms or die "Did not match the commit hash\n";
        my $tags = exists $commit_tags{$1} ? $commit_tags{$1} : q();
        my $date_author = '';
        my $c_msg;
        if ($print_author) {
            /(?:& )(.*?)NoTinAuthorFiled(& .*? &) (.*)/;
            $date_author = latex_escape($1) . $2;
            $c_msg       = $3;
        }
        else {
            /(.*? &) (.*)/;
            $date_author = $1;
            $c_msg       = $2;
        }
        if ( defined $git_user and defined $git_repo ) {
            $c_msg =~ /(.*?) & (.*)/;
            $c_msg = sprintf '\\href{%s/%s}{%s}', $git_commit_address, $1, latex_escape($2);
        }
        else {
            $c_msg = latex_escape($c_msg);
        }
        say "\\hline $commit_count & $tags & $date_author $c_msg & " . join( ' & ', @changes ) . ' \\\\';
        $commit_count++;
    } ## end if ($which_line)
    else {
        @changes = ( 0, 0, 0 );
        /(\d+) files? changed/ and $changes[0] = $1;
        /(\d+) insertions?/    and $changes[1] = $1;
        /(\d+) deletions?/     and $changes[2] = $1;
    }
    $which_line ^= 1; ## toggle bit
} ## end for (@lines)
say '\end{longtable}';
# }}}

__END__
# Documentation {{{

=head1 NAME

latex-git-log - Generates the version history of a git project as LaTeX source code.

=head1 SYNOPSIS

latex-git-log [options]

Options:

  --author          set this if you want the author included
  --startcommit     set the start value of count commit
  --width           set the width in cm of the commit message field in the LaTeX table
  --git-c-add       set an base URL to link to a commit
  --user            set a github user to derive the base URL
  --repo            set a github repository to derive the base URL
  --lang            language of the legend and all strings in the output
  --version, -v     print version of this script
  --help            brief help message
  --man             full documentation

=head1 OPTIONS

=over 8

=item B<--width>

Set the width in cm of the commit message field in the LaTeX table. If this
parameter is not set then the table is not vertically limited. That means that
if you have a very long commit message then the table will probably not fit on
the page and you will get a "Overfull" error message from TeX.

In this case you should specify the width of the column containing the commit messages.
I normally use something like --width=14 for DIN A4 in landscape.

=item B<--git-c-add>

Set an base URL to link to a commit.
This script will automatically try to use the base URL for github.

=item B<--lang>

Set the language of the legend and all strings in the output. Be default the
language of your system is used but you can overwrite this with this parameter.

Currently this script only supports English and German. If you need a translation
to another language then you can either create a .po file or I can register
this project on one of those websites for online translation.

=back

=head1 Example

You can use it like this:

    latex-git-log --width=6 --lang=en > example-output.tex

=head1 DEPENDENCIES

=head2 Of this script

This module requires these other modules and libraries:

    IPC::System::Simple
    Locale::Maketext::Simple

Everything else should already be installed.

=head2 To compile the output

The table is using the B<longtable> package and the links to a web resource for
each commit use the \href macro from B<hyperref>. So these two packages have to
be loaded.

Furthermore you need to defined the macro B<\longtableendfoot> which will be
expanded on the bottom of every page if the table will be continued on the next
page. You can defined it to a localized message to inform the reader that this
table is not complete and will be continued.

=head1 DESCRIPTION

B<This program> will output the entire version history as table written in
LaTeX if it is executed within a git repository.

It is intended that you redirect the standard output of this script to a file
which can then be included from your main TeX document.

Because the table can be very large you might want to put the thing on a
landscape page.

=head1 Version

0.9

=head1 AUTHOR

Robin Schneider <ypid23@aol.de>

=head1 Development

Source code repository: https://github.com/ypid/typesetting/tree/master/scripts/latex-git-log

Please report bugs and feature requests at https://github.com/ypid/typesetting/issues

=head1 LICENSE AND COPYRIGHT

Copyright (C) 2012-2013 by Robin Schneider

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

Dieses Programm ist Freie Software: Sie können es unter den Bedingungen
der GNU General Public License, wie von der Free Software Foundation,
Version 3 der Lizenz oder (nach Ihrer Option) jeder späteren
veröffentlichten Version, weiterverbreiten und/oder modifizieren.

Dieses Programm wird in der Hoffnung, dass es nützlich sein wird, aber
OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite
Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
Siehe die GNU General Public License für weitere Details.

Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
Programm erhalten haben. Wenn nicht, siehe <http://www.gnu.org/licenses/>.

=cut
# }}}