From: Yves Orton Date: Wed, 31 Dec 2008 00:16:23 +0000 (+0100) Subject: much better git related version numbering in our (*nix for now) build process X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=46807d8e809cc127621bf85d9e9;p=p5sagit%2Fp5-mst-13.2.git much better git related version numbering in our (*nix for now) build process The net result of this patch is to make available via Config.pm and -v/-V the details about the git version info we have available for the build. When built within a git repository git is queried directly. When built from a snapshot or bundle it is assumed that the source is unchanged, and that the required details are avaialble in a file called .patch, whose format current is a four field string in the following format: "$branchname $date.$time $sha1 $describe". The generator of these files currently resides on camel.booking.com. * git-describe is now used more directly with -v. When the prefix of git-describe matches the version number as determined by the defines in patchlevel.h then we use ONLY the git-describe output, otherwise we include the git describe in parenthesis after the version number. Either way the describe text is optionally followed by a star should there be uncommitted changes. eg: This is perl, v5.11.0 (GitLive-blead-136-g58ca560) built for i686-linux or: This is perl, v5.11.0-1-g58ca560 built for i686-linux or: This is perl, v5.11.0 built for i686-linux * include the SHA1 in perl -V summary, and automatically include unpushed commits in the registered patches list * include various git/version/.patch details in %Config, as follows: git_commit_id # sha1 of HEAD git_ancestor # ancestor in $remote/$branch (presumably canonical) git_describe # git describe git_branch # current branch git_uncommitted_changes # "true" if there are any, empty otherwise git_unpushed_commits # List of sha1's of unpushed commits git_commit_id_title # Used to make the perl -V summary output Additionally one more value is added depending on build process used: when building from an rsynced snapshot (or any dist including a file called .patch) then the second field will be used to populate the "git_snapshot_date" field. Otherwise if built in a git directory (as is hopefully recommended these day) then the field will be "git_commit_date" which will be the commit date of HEAD. This patch introduces two new files (on top of .patchnum) that will be generated by make_patchnum.sh: "lib/Config_git.pl" and "unpushed.h", the former is used to make git data available to Config.pm/%Config without rebuilding everything else, and the second is used to expose unpushed commits (if any) via the registered patch facility of patchlevel.h --- diff --git a/.gitignore b/.gitignore index 4b430f9..362fc7a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ # these are generated by make_patchnum.sh from git or from a .patchfile .patchnum .sha1 +unpushed.h # ignore bug*.pl bug*.pl diff --git a/Makefile.SH b/Makefile.SH index ff50cfd..9ad8b6f 100644 --- a/Makefile.SH +++ b/Makefile.SH @@ -371,7 +371,10 @@ CCCMD = `sh $(shellflags) cflags "optimize='$(OPTIMIZE)'" $@` CCCMDSRC = `sh $(shellflags) cflags "optimize='$(OPTIMIZE)'" $<` +# we dont include lib/Config_git.pl here, as it causes circular dependencies CONFIGPM = lib/Config.pm lib/Config_heavy.pl +# so we add it here: +CONFIGPM_EXTRA = $(CONFIGPM) lib/Config_git.pl CONFIGPOD = lib/Config.pod @@ -540,7 +543,8 @@ sperl.i: perl.c $(h) make_patchnum: sh $(shellflags) make_patchnum.sh -perl$(OBJ_EXT): .patchnum .sha1 +# make sure that we recompile perl.c if .patchnum changes +perl$(OBJ_EXT): .patchnum unpushed.h translators: miniperl$(EXE_EXT) $(CONFIGPM) FORCE @echo " "; echo " Making x2p stuff"; cd x2p; $(LDLIBPTH) $(MAKE) all @@ -1217,7 +1221,8 @@ _tidy: -cd utils; $(LDLIBPTH) $(MAKE) clean -cd x2p; $(LDLIBPTH) $(MAKE) clean -rm .patchnum - -rm .sha1 + -rm lib/Config_git.pl + -rm unpushed.h -@for x in $(DYNALOADER) $(dynamic_ext) $(static_ext) $(nonxs_ext) ; do \ $(LDLIBPTH) sh ext/util/make_ext clean $$x MAKE=$(MAKE) ; \ done diff --git a/cflags.SH b/cflags.SH index 6e6e8a9..132f466 100755 --- a/cflags.SH +++ b/cflags.SH @@ -297,12 +297,12 @@ for file do opmini) ;; pad) ;; perl) - if [ -f .patchnum -a -n "$(cat .patchnum)" ] ; then - ccflags="-DPERL_PATCHNUM=`cat .patchnum` $ccflags" - fi - if [ -f .sha1 -a -n "$(cat .sha1)" ] ; then - ccflags="-DPERL_GIT_SHA1=`cat .sha1` $ccflags" + if [ -f .patchnum -a -n "$(awk 'BEGIN{ORS=""} /describe:/ {print $1}' .patchnum)" ] ; then + ccflags="-DPERL_PATCHNUM=$(awk 'BEGIN{ORS=""} /describe:/ {print $2}' .patchnum) $ccflags" fi + if [ -f .patchnum -a -n "$(awk 'BEGIN{ORS=""} /status:/ {print $2}' .patchnum)" ] ; then + ccflags="-DPERL_GIT_UNCOMMITTED_CHANGES=$(awk 'BEGIN{ORS=""} /status:/ {print $2}' .patchnum) $ccflags" + fi ;; perlapi) ;; perlmain) ;; diff --git a/configpm b/configpm index d781b50..af6f65a 100755 --- a/configpm +++ b/configpm @@ -458,7 +458,19 @@ my $summary_expanded; sub myconfig { return $summary_expanded if $summary_expanded; ($summary_expanded = $summary) =~ s{\$(\w+)} - { my $c = $Config::Config{$1}; defined($c) ? $c : 'undef' }ge; + { + my $c; + if ($1 eq 'git_ancestor_line') { + if ($Config::Config{git_ancestor}) { + $c= "\n Ancestor: $Config::Config{git_ancestor}"; + } else { + $c= ""; + } + } else { + $c = $Config::Config{$1}; + } + defined($c) ? $c : 'undef' + }ge; $summary_expanded; } @@ -535,6 +547,11 @@ foreach my $prefix (qw(libs libswanted)) { $heavy_txt .= "EOVIRTUAL\n"; +$heavy_txt .= <<'ENDOFGIT'; +require 'Config_git.pl'; +$Config_SH_expanded .= $Config::Git_Data; +ENDOFGIT + $heavy_txt .= $fetch_string; $config_txt .= <<'ENDOFEND'; diff --git a/install_lib.pl b/install_lib.pl index 7eeae1d..ae8ba0a 100644 --- a/install_lib.pl +++ b/install_lib.pl @@ -29,6 +29,7 @@ OS undef %Config::; delete $INC{"Config.pm"}; delete $INC{"Config_heavy.pl"}; + delete $INC{"Config_git.pl"}; # You never saw us. We weren't here. require Config; diff --git a/installperl b/installperl index da8f45e..d8d36be 100755 --- a/installperl +++ b/installperl @@ -759,7 +759,7 @@ sub installlib { if ($dir =~ /^auto/ || ($name =~ /^(.*)\.(?:pm|pod)$/ && $archpms{$1}) || ($name =~ /^(.*)\.(?:h|lib)$/i && ($Is_W32 || $Is_NetWare)) || - $name eq 'Config_heavy.pl' + $name=~/^Config_(heavy\|git)\.pl\z/ ) { $installlib = $installarchlib; return unless $do_installarchlib; diff --git a/lib/.gitignore b/lib/.gitignore index e6facd3..0fa004e 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -4,6 +4,7 @@ /Config.pm /Config.pod /Config_heavy.pl +/Config_git.pl /DB_File.pm /Data /Devel/DProf.pm diff --git a/make_patchnum.sh b/make_patchnum.sh index 9a2f946..c9c74af 100644 --- a/make_patchnum.sh +++ b/make_patchnum.sh @@ -1,35 +1,85 @@ #!/bin/sh -. ./config.sh +# this script is used to regenerate a number of special build files +# based on either information contained in a file called .patch or +# directly from git. +# The files involved are: +# .patchnum # information about the current checkout +# lib/Config_git.pl # holds some special configure settings related to git +# unpushed.h # header file used by patchlevel.h to store unpushed commits -Existing=`cat .patchnum 2>/dev/null` -Existing_Sha1=`cat .sha1 2>/dev/null` +existing_patchnum=$(cat .patchnum 2>/dev/null) +existing_config=$(cat lib/Config_git.pl 2>/dev/null) +existing_unpushed=$(cat unpushed.h 2>/dev/null) -if test -s ".patch" ; then - Current=`awk '{print $4}' .patch` - Sha1=`awk '{print $3}' .patch` -elif test -d ".git" ; then - # we should do something better here - Current=`git describe` - Sha1=`git rev-parse HEAD` - Changed=`git diff-index --name-only HEAD` - test -n "$Changed" && Current="$Current-with-uncommitted-changes" -fi +unpushed_commits='/*no-op*/' +if [ -s ".patch" ] ; then + read branch snapshot_created commit_id describe < .patch + changed="" + extra_info="git_snapshot_date='$snapshot_created'" + commit_title='Snapshot of:' +elif [ -d ".git" ]; then + branch=$(git branch | awk 'BEGIN{ORS=""} /\*/ { print $2 }') + test -n "$branch" && remote=$(git config branch.$branch.remote) + commit_id=$(git rev-parse HEAD) + changed=$(git diff-index --name-only HEAD) + describe=$(git describe --tags) + commit_created=$(git log -1 --pretty='format:%ci') + new_patchnum="describe: $describe" + extra_info="git_commit_date='$commit_created'" + if [ -n "$branch" ] && [ -n "$remote" ]; then + unpushed_commit_list=$(git cherry $remote/$branch | awk 'BEGIN{ORS=","} /+/ {print $2}' | sed -e 's/,$//') + unpushed_commits=$(git cherry $remote/$branch | awk 'BEGIN{ORS="\t\\\n"} /+/ {print ",\"" $2 "\""}') -if test "$Existing" != "$Current" -o "$Existing_Sha1" != "$Sha1" ; then - (echo "hi there\c" ; echo " ") >.echotmp - if $contains c .echotmp >/dev/null 2>&1 ; then - n='-n' - c='' - else - n='' - c='\c' + if [ -n "$unpushed_commits" ]; then + commit_title="Local Commit:" + ancestor=`git rev-parse $remote/$branch` + extra_info="$extra_info +git_ancestor='$ancestor' +git_unpushed='$unpushed_commit_list'" + fi + + fi + if [ -n "$changed" ]; then + changed="true" + commit_title="Derived from:" + new_patchnum="$new_patchnum +status: uncommitted-changes" fi - rm -f .echotmp - echo "Updating .patchnum and .sha1" - echo $n "$Current$c" > .patchnum - echo $n "$Sha1$c" > .sha1 + test -z "$commit_title" && commit_title='Commit id:' +fi +new_unpushed=$(cat < .patchnum + echo "$new_config" > lib/Config_git.pl + echo "$new_unpushed" > unpushed.h else - echo "Reusing .patchnum and .sha1" + echo "Reusing .patchnum and lib/Config_git.pl" fi + diff --git a/myconfig.SH b/myconfig.SH index 3dfd953..f5b432a 100644 --- a/myconfig.SH +++ b/myconfig.SH @@ -28,6 +28,7 @@ $startsh # Note that the text lines /^Summary of/ .. /^\s*$/ are copied into Config.pm. cat <<'!NO!SUBS!' Summary of my $package (revision $revision $version_patchlevel_string) configuration: + $git_commit_id_title $git_commit_id$git_ancestor_line Platform: osname=$osname, osvers=$osvers, archname=$archname uname='$myuname' diff --git a/patchlevel.h b/patchlevel.h index 391cb41..a17a6e6 100644 --- a/patchlevel.h +++ b/patchlevel.h @@ -116,9 +116,21 @@ hunk. */ #if !defined(PERL_PATCHLEVEL_H_IMPLICIT) && !defined(LOCAL_PATCH_COUNT) +#include "unpushed.h" +#if !defined(PERL_GIT_UNPUSHED_COMMITS) +#define PERL_GIT_UNPUSHED_COMMITS_PATCH /* no-op */ +#else +#define PERL_GIT_UNPUSHED_COMMITS_PATCH PERL_GIT_UNPUSHED_COMMITS +#endif +#if !defined(PERL_GIT_UNCOMMITTED_CHANGES) +#define PERL_GIT_UNCOMMITTED_CHANGES_PATCH /*no op*/ +#else +#define PERL_GIT_UNCOMMITTED_CHANGES_PATCH , STRINGIFY(PERL_GIT_UNCOMMITTED_CHANGES) +#endif static const char * const local_patches[] = { NULL - ,"DEVEL" + PERL_GIT_UNPUSHED_COMMITS_PATCH /* do not remove this line */ + PERL_GIT_UNCOMMITTED_CHANGES_PATCH /* do not remove this line */ ,NULL }; diff --git a/perl.c b/perl.c index 7c5da00..d224ca6 100644 --- a/perl.c +++ b/perl.c @@ -1904,7 +1904,6 @@ S_parse_body(pTHX_ char **env, XSINIT_t xsinit) #else sv_catpvs(opts_prog,"\"\\nCharacteristics of this binary (from libperl): \\n"); #endif - sv_catpvs(opts_prog," Source revision: " STRINGIFY(PERL_GIT_SHA1) "\\n"); sv_catpvs(opts_prog," Compile-time options: $_\\n\","); #if defined(LOCAL_PATCH_COUNT) @@ -1914,16 +1913,8 @@ S_parse_body(pTHX_ char **env, XSINIT_t xsinit) "\" Locally applied patches:\\n\","); for (i = 1; i <= LOCAL_PATCH_COUNT; i++) { if (PL_localpatches[i]) -#ifdef X_PERL_PATCHNUM -/* this is ifdef'ed out, we would enable this if we want to transform - "DEVEL" registered patches into the git name */ - if (strEQ(PL_localpatches[i],"DEVEL")) - Perl_sv_catpvf(aTHX_ opts_prog,"q%c\t%s\n%c,", - 0, STRINGIFY(PERL_PATCHNUM), 0); - else -#endif - Perl_sv_catpvf(aTHX_ opts_prog,"q%c\t%s\n%c,", - 0, PL_localpatches[i], 0); + Perl_sv_catpvf(aTHX_ opts_prog,"q%c\t%s\n%c,", + 0, PL_localpatches[i], 0); } } #endif @@ -3315,11 +3306,29 @@ Perl_moreswitches(pTHX_ const char *s) if (!sv_derived_from(PL_patchlevel, "version")) upg_version(PL_patchlevel, TRUE); #if !defined(DGUX) - PerlIO_printf(PerlIO_stdout(), + { + SV* level= vstringify(PL_patchlevel); +#ifdef PERL_PATCHNUM + SV* num= newSVpvn(STRINGIFY(PERL_PATCHNUM),sizeof(STRINGIFY(PERL_PATCHNUM))-1); +#ifdef PERL_GIT_UNCOMMITTED_CHANGES + sv_catpvf(num,"%s","*"); +#endif + + if (sv_len(num)>=sv_len(level) && strnEQ(SvPV_nolen(num),SvPV_nolen(level),sv_len(level))) { + SvREFCNT_dec(level); + level= num; + } else { + sv_catpvf(level, " (%s)",SvPV_nolen(num)); + SvREFCNT_dec(num); + } + #endif + PerlIO_printf(PerlIO_stdout(), "\nThis is perl, %"SVf " built for %s", - SVfARG(vstringify(PL_patchlevel)), + level, ARCHNAME); + SvREFCNT_dec(level); + } #else /* DGUX */ /* Adjust verbose output as in the perl that ships with the DG/UX OS from EMC */ PerlIO_printf(PerlIO_stdout(), @@ -3332,9 +3341,6 @@ Perl_moreswitches(pTHX_ const char *s) Perl_form(aTHX_ " OS Specific Release: %s\n", OSVERS)); #endif /* !DGUX */ -#if defined PERL_PATCHNUM - PerlIO_printf(PerlIO_stdout(),"\nCompiled from: %s",STRINGIFY(PERL_PATCHNUM)); -#endif #if defined(LOCAL_PATCH_COUNT) if (LOCAL_PATCH_COUNT > 0) PerlIO_printf(PerlIO_stdout(), diff --git a/t/run/switches.t b/t/run/switches.t index 0d91d8a..a9e23ea 100644 --- a/t/run/switches.t +++ b/t/run/switches.t @@ -260,10 +260,11 @@ SWTESTPM { local $TODO = ''; # these ones should work on VMS - + # there are definitely known build configs where this test will fail + # DG/UX comes to mind. Maybe we should remove these special cases? my $v = sprintf "%vd", $^V; like( runperl( switches => ['-v'] ), - qr/This is perl, v$v (?:DEVEL:[-A-Za-z0-9]+ )?built for \Q$Config{archname}\E.+Copyright.+Larry Wall.+Artistic License.+GNU General Public License/s, + qr/This is perl, v$v(?:[-\w]+| \([^)]+\))? built for \Q$Config{archname}\E.+Copyright.+Larry Wall.+Artistic License.+GNU General Public License/s, '-v looks okay' ); }