4 # Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
6 # Permission is hereby granted, free of charge, to any person obtaining a
7 # copy of this software and associated documentation files (the "Software"),
8 # to deal in the Software without restriction, including without limitation
9 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 # and/or sell copies of the Software, and to permit persons to whom the
11 # Software is furnished to do so, subject to the following conditions:
13 # The above copyright notice and this permission notice (including the next
14 # paragraph) shall be included in all copies or substantial portions of the
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 # DEALINGS IN THE SOFTWARE.
33 # Currently available output formats:
34 # short - short log (default)
36 # html - short log with cgit links
39 # Input is provided as a list of modules with a from and to version, or
40 # "-" if no version is included, such as:
44 # applewmproto 1.4.1 1.4.1
45 # bdftopcf 1.0.2 1.0.3
49 my $output_type = 'short';
51 my $result = GetOptions
("type=s" => \
$output_type);
53 my $usage = "Usage: [--type=short|long|html|stat] <filename>\n";
56 (($output_type ne 'short') && ($output_type ne 'long') &&
57 ($output_type ne 'html')&& ($output_type ne 'stat') )) {
62 my @modtypes=qw(app data doc driver font lib proto util xcb .);
65 'libXres' => 'libXRes',
66 'libpthread-stubs' => 'pthread-stubs',
67 'util-macros' => 'macros',
68 'xbitmaps' => 'bitmaps',
69 'xcb-proto' => 'proto',
70 'xcursor-themes' => 'cursors',
71 'xorg-server' => 'xserver',
72 'xproto' => 'x11proto',
73 'xtrans' => 'libxtrans',
80 if ($_ =~ m/(\S+)\s+([\-\.\d]+)\s+([\.\d\-\*]+)/) {
81 my ($module, $old, $new) = ($1, $2, $3);
87 if (exists($modmap{$module})) {
88 $moddir = $modmap{$module};
91 if ($module =~ m/font-(.*)/) {
95 foreach my $m (@modtypes) {
96 if (-d
"$m/$moddir") {
103 if (($modtype ne '?') && (($old ne $new) || ($output_type eq 'html'))) {
104 if ($output_type ne 'html') {
105 print "======= $modtype/$module ($old..$new)\n\n";
107 my $oldtag = find_tag
($modtype, $moddir, $module, $old);
108 my $newtag = find_tag
($modtype, $moddir, $module, $new);
109 # print "$modtype/$module: $oldtag -> $newtag\n";
110 # system('git', "--git-dir=$modtype/$moddir/.git", 'log',
111 # '--pretty=short', "$oldtag..$newtag");
113 # special cases for X11R7.7
114 if ($module eq 'xkeyboard-config') {
115 $oldtag = 'xkeyboard-config-2.0';
118 my $tagrange = ($oldtag ne '') ?
"$oldtag..$newtag" : "$newtag";
120 my $output_flags = ($output_type eq 'long') ?
'' : '--pretty=short';
122 my $git_subcmd = ($output_type eq 'stat') ?
'diff --shortstat' : 'log';
124 my $git_log_cmd = "git --git-dir=$modtype/$moddir/.git" .
125 " $git_subcmd $output_flags $tagrange";
127 if ($output_type eq 'short') {
128 system("$git_log_cmd | git shortlog");
129 } elsif (($output_type eq 'long') || ($output_type eq 'stat')) {
130 system("$git_log_cmd");
133 open my $gsl, '-|', $git_log_cmd or die;
134 while (my $ll = <$gsl>) {
139 if ($ll =~ m{^commit (\w+)$}) {
142 while ($ll = <$gsl>) {
144 last if $ll =~ m{^\s*$};
145 if ($ll =~ m{^Author:\s*(.*)\s+\<.*\>}) {
147 } elsif ($ll !~ m{^Merge:}) {
148 die "Author match failed: $modtype/$module/$commit->{id}\n$ll\n";
153 while ($ll = <$gsl>) {
154 last if $ll =~ m{^\s*$};
159 $commit->{desc
} = $desc;
161 if (!exists $changes{$author}) {
162 $changes{$author} = [ ];
164 unshift @
{$changes{$author}}, $commit;
168 my $newtagdate = `git --git-dir=$modtype/$moddir/.git log -1 --tags --simplify-by-decoration --pretty="format:%ad" --date=short $newtag`;
169 $module_info{"$modtype/$module"} =
171 changes
=> \
%changes,
174 newtagdate
=> $newtagdate,
188 if ($output_type eq 'html') {
191 my $title = 'Consolidated ChangeLog for X11R7.7';
192 print $q->start_html(-title
=> $title,
193 -style
=>{-src
=>'http://cgit.freedesktop.org/cgit.css',
194 -code
=> '.modules { float: left; }' .
195 '.modules > td { padding-left: 3px; }'
197 -encoding
=> 'utf-8',
199 $q->Link({-rel
=> 'home',
200 -href
=> 'http://www.x.org/'}),
201 $q->Link({-rel
=> 'SHORTCUT ICON',
202 -href
=> 'favicon.ico'}),
203 $q->Link({-rel
=> 'up',
204 -href
=> 'index.html'}),
207 -itemtype
=> 'http://schema.org/WebPage'
210 $q->div({ -style
=> 'text-align: center;',
211 -itemprop
=> 'publisher', -content
=> 'X.Org Foundation' },
212 $q->a({ -href
=> 'http://www.x.org/', -rel
=> 'home'},
213 $q->img({ -src
=> 'logo.png', -border
=> '0',
214 -alt
=> 'X.Org Foundation' }))), "\n",
215 $q->h1($title), "\n";
217 print $q->start_table({ -class => 'modules', -cols
=> '4' }), "\n",
218 $q->Tr($q->th({-colspan
=>"2"}, 'Module'),
219 $q->th([' X11R7.6 ', ' X11R7.7 '])), "\n";
221 my $midpoint = scalar(keys %module_info) / 2;
223 foreach my $m (sort keys %module_info) {
224 my $modname = $module_info{$m}->{module
};
226 print $q->Tr($q->td( [
227 $module_info{$m}->{modtype
},
228 $q->a({href
=>"#$modname"},
229 $module_info{$m}->{moddir
}),
230 $module_info{$m}->{oldvers
},
231 $module_info{$m}->{newvers
}
233 if (--$midpoint == 0) {
234 print $q->end_table();
235 print $q->start_table({ -class => 'modules', -cols
=> '4' }).
236 $q->Tr($q->th({-colspan
=>"2"}, 'Module'),
237 $q->th([' X11R7.6 ', ' X11R7.7 '])), "\n";
240 print $q->end_table();
241 print $q->br({-clear
=> "all"}), "\n";
243 foreach my $m (sort keys %module_info) {
244 my $modname = $module_info{$m}->{module
};
245 my $modtype = $module_info{$m}->{modtype
};
246 my $moddir = $module_info{$m}->{moddir
};
247 my $modvers = $module_info{$m}->{newvers
};
248 my $modtar = "$modname-$modvers.tar.bz2";
250 $moddisplay =~ s{^\./}{};
252 $q->start_div({-class => "content", -itemscope
=> undef,
253 -itemtype
=>'http://schema.org/SoftwareApplication'}),
254 $q->h2($q->span({-itemprop
=> "name"},
255 cgit_link
($q, $modtype, $moddir, 'top', $modname, $moddisplay)),
256 $q->span({ -itemprop
=> 'version' }, $modvers)),
259 $q->a({ -href
=> "src/everything/$modtar",
260 -itemprop
=> 'downloadURL' }, $modtar),
261 ' — ', $q->span({ -itemprop
=> 'datePublished' },
262 $module_info{$m}->{newtagdate
}), "\n";
263 print $q->h3('Commits from',
264 ($module_info{$m}->{oldtag
} eq '') ?
266 cgit_link
($q, $modtype, $moddir, 'tag',
267 $module_info{$m}->{oldtag
},
268 $module_info{$m}->{oldtag
}
271 cgit_link
($q, $modtype, $moddir, 'tag',
272 $module_info{$m}->{newtag
},
273 $module_info{$m}->{newtag
}
277 print $q->start_ul({ -class => 'authors', -itemprop
=> 'versionChanges' });
278 my $changes = $module_info{$m}->{changes
};
279 foreach my $a (sort keys %{$changes}) {
280 my @au_changes = @
{$changes->{$a}};
281 my $count = scalar @au_changes;
282 print $q->li("$a ($count):",
283 $q->ul({ -class => 'commits' },
285 cgit_link
($q, $modtype, $moddir, 'commit',
286 $_->{id
}, $_->{desc
}) } @au_changes]))
290 print $q->end_div(), "\n";
292 print $q->end_html(), "\n";
296 my ($q, $modtype, $moddir, $type, $id, $body) = @_;
297 # http://cgit.freedesktop.org/xorg/xserver/tag/?id=xorg-server-1.7.1
298 # http://cgit.freedesktop.org/xorg/xserver/commit/?id=9a2f6135bfb0f12ec28f304c97917d2f7c64db05
299 if ($modtype ne 'xcb') {
300 if ($modtype eq '.') {
302 # special cases for X11R7.6
303 # if ($id eq '9edb9e9b4dde6f73dc5241d078425a7a70699ec9') {
307 $modtype = "xorg/$modtype";
310 my $modpath = "$modtype/$moddir";
311 if ($moddir eq "xkeyboard-config") {
312 $modpath = "xkeyboard-config";
315 my %link_attrs = (-href
=> "http://cgit.freedesktop.org/$modpath/");
316 if ($type eq 'top') {
317 $link_attrs{-name
} = $id;
319 $link_attrs{-href
} .= "$type/?id=$id";
321 my $link = $q->a(\
%link_attrs, $q->escapeHTML($body));
326 my ($modtype, $moddir, $module, $vers) = @_;
337 $oldvers =~ s/\./_/g;
339 if (-f
"$modtype/$moddir/.git/refs/tags/$module-$vers") {
340 return "$module-$vers";
341 } elsif (-f
"$modtype/$moddir/.git/refs/tags/$vers") {
344 if (-f
"$modtype/$moddir/.git/refs/tags/$module-$oldvers") {
345 return "$module-$oldvers";
351 open(my $tag_fh, '-|', "git --git-dir=$modtype/$moddir/.git tag -l")
352 or die "Failed to run git --git-dir=$modtype/$moddir/.git tag -l";
355 while (my $t = <$tag_fh>) {
357 if (($t =~ m/$vers$/) || ($t =~ m/$oldvers$/)) {
366 if (-f
"$modtype/$moddir/.git/refs/tags/XORG-7_1") {
373 # if [[ -d "$TOP/$d/.git" && ! -f "$TOP/$d/NO-PULL" ]] ; then
375 # LAST_TAG="$(git describe --abbrev=0)"
376 # if [[ -z "${LAST_TAG}" ]] ; then
377 # LAST_TAG="$(git describe --abbrev=0 --all HEAD^)"
379 # git log "${LAST_TAG}"..