2 # These two should go upon release to make the script Perl 5.005 compatible
8 make_patchnum.pl - make patchnum
12 miniperl make_patchnum.pl
18 This program creates the files holding the information
19 about locally applied patches to the source code. The created
20 files are C<git_version.h> and C<lib/Config_git.pl>.
22 =item C<lib/Config_git.pl>
24 Contains status information from git in a form meant to be processed
25 by the tied hash logic of Config.pm. It is actually optional,
26 although -V will look strange without it.
28 C<git_version.h> contains similar information in a C header file
29 format, designed to be used by patchlevel.h. This file is obtained
30 from stock_git_version.h if miniperl is not available, and then
31 later on replaced by the version created by this script.
35 Yves Orton, Kenichi Ishigaki, Max Maischein
39 Same terms as Perl itself.
45 while (!-e "$root/perl.c" and length($root)<100) {
52 die "Can't find toplevel" if !-e "$root/perl.c";
53 sub path_to { "$root/$_[0]" } # use $_[0] if this'd be placed in toplevel.
57 my $file = path_to(@_);
58 return "" unless -e $file;
59 open my $fh, '<', $file
60 or die "Failed to open for read '$file':$!";
61 return do { local $/; <$fh> };
65 my ($file, $content) = @_;
66 $file= path_to($file);
67 open my $fh, '>', $file
68 or die "Failed to open for write '$file':$!";
76 my @result= `$command`;
80 my $result= `$command`;
81 $result="" if ! defined $result;
88 my %content= map { /WARNING: '([^']+)'/ || die "Bad mojo!"; $1 => $_ } @_;
89 my @files= sort keys %content;
90 my $files= join " and ", map { "'$_'" } @files;
91 foreach my $file (@files) {
92 if (read_file($file) ne $content{$file}) {
93 print "Updating $files\n";
94 write_file($_,$content{$_}) for @files;
98 print "Reusing $files\n";
102 my $unpushed_commits = '/*no-op*/';
103 my ($read, $branch, $snapshot_created, $commit_id, $describe)= ("") x 5;
104 my ($changed, $extra_info, $commit_title, $new_patchnum, $status)= ("") x 5;
105 if (my $patch_file= read_file(".patch")) {
106 ($branch, $snapshot_created, $commit_id, $describe) = split /\s+/, $patch_file;
107 $extra_info = "git_snapshot_date='$snapshot_created'";
108 $commit_title = "Snapshot of:";
110 elsif (-d path_to('.git')) {
111 # git branch | awk 'BEGIN{ORS=""} /\*/ { print $2 }'
112 ($branch) = map { /\* ([^(]\S*)/ ? $1 : () } backtick('git branch');
114 if (length $branch) {
115 $merge= backtick("git config branch.$branch.merge");
116 $merge =~ s!^refs/heads/!!;
117 $remote= backtick("git config branch.$branch.remote");
119 $commit_id = backtick("git rev-parse HEAD");
120 $describe = backtick("git describe");
121 my $commit_created = backtick(qq{git log -1 --pretty="format:%ci"});
122 $new_patchnum = "describe: $describe";
123 $extra_info = "git_commit_date='$commit_created'";
124 if (length $branch && length $remote) {
125 # git cherry $remote/$branch | awk 'BEGIN{ORS=","} /\+/ {print $2}' | sed -e 's/,$//'
126 my $unpushed_commit_list =
127 join ",", map { (split /\s/, $_)[1] }
128 grep {/\+/} backtick("git cherry $remote/$merge");
129 # git cherry $remote/$branch | awk 'BEGIN{ORS="\t\\\\\n"} /\+/ {print ",\"" $2 "\""}'
131 join "", map { ',"'.(split /\s/, $_)[1]."\"\t\\\n" }
132 grep {/\+/} backtick("git cherry $remote/$merge");
133 if (length $unpushed_commits) {
134 $commit_title = "Local Commit:";
135 my $ancestor = backtick("git rev-parse $remote/$merge");
136 $extra_info = "$extra_info
137 git_ancestor='$ancestor'
138 git_remote_branch='$remote/$merge'
139 git_unpushed='$unpushed_commit_list'";
144 $commit_title = "Derived from:";
145 $status='"uncommitted-changes"'
147 $status='/*clean-working-directory*/'
149 $commit_title ||= "Commit id:";
152 # we extract the filename out of the warning header, so dont mess with that
153 exit(write_files(<<"EOF_HEADER", <<"EOF_CONFIG"));
154 /**************************************************************************
155 * WARNING: 'git_version.h' is automatically generated by make_patchnum.pl
156 * DO NOT EDIT DIRECTLY - edit make_patchnum.pl instead
157 ***************************************************************************/
158 #define PERL_GIT_UNCOMMITTED_CHANGES $status
159 #define PERL_PATCHNUM "$describe"
160 #define PERL_GIT_UNPUSHED_COMMITS\t\t\\
161 $unpushed_commits/*leave-this-comment*/
163 ######################################################################
164 # WARNING: 'lib/Config_git.pl' is generated by make_patchnum.pl
165 # DO NOT EDIT DIRECTLY - edit make_patchnum.pl instead
166 ######################################################################
167 \$Config::Git_Data=<<'ENDOFGIT';
168 git_commit_id='$commit_id'
169 git_describe='$describe'
171 git_uncommitted_changes='$changed'
172 git_commit_id_title='$commit_title'
176 # ex: set ts=4 sts=4 et ft=perl: