diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | build.macros.in | 9 | ||||
-rwxr-xr-x | git-repository--after-tarball | 63 | ||||
-rwxr-xr-x | git-repository--apply-patch | 158 |
5 files changed, 235 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am index cc728de..5f6fbcb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -28,6 +28,8 @@ pkg_scripts = \ filter.sh \ find-lang.pl \ find-debuginfo.sh \ + git-repository--after-tarball \ + git-repository--apply-patch \ http.req \ magic.prov \ magic.req \ @@ -1,3 +1,6 @@ +- when %_with_git_repository is set, define %_after_setup and %_patch to use + the new scripts git-repository--after-tarball and git-repository--apply-patch + Version 1.88 - 7 January 2009, by Christophe Fergeau - fix ugly warning during invocation of php.req diff --git a/build.macros.in b/build.macros.in index 9ce5d86..15bfa83 100644 --- a/build.macros.in +++ b/build.macros.in @@ -7,6 +7,15 @@ # [Pixel, Dec 2008] deprecated, to remove as soon as rpm 4.6.0 dust settles down %defaultbuildroot %{_tmppath}/%{name}-%{version}-%{release}-buildroot + +# when %_with_git_repository is set, these macros modify the behaviour of "%prep" step: +%_after_setup %{?_with_git_repository:GIT_URL="%{?git_url}" GIT_REPOSITORY_CACHE=%{?git_repository_cache} @RPMVENDORDIR@/git-repository--after-tarball} +%_patch %{?_with_git_repository:PKG_NAME=%{name} @RPMVENDORDIR@/git-repository--apply-patch}%{?!_with_git_repository:%__patch} + +# used by "git-repository--after-tarball": +%git_repository_cache %_topdir/%{name}.git + + # Various programs used in rpm scripts %_update_desktop_database_bin %{_bindir}/update-desktop-database %_update_mime_database_bin %{_bindir}/update-mime-database diff --git a/git-repository--after-tarball b/git-repository--after-tarball new file mode 100755 index 0000000..5fda909 --- /dev/null +++ b/git-repository--after-tarball @@ -0,0 +1,63 @@ +#!/bin/sh -ex + +# usage: git-repository--after-tarball [<tarballs>] +# with optional environment variables: +# - GIT_URL="git://xxx/foo.git [branch]" +# - GIT_REPOSITORY_CACHE=/zzz/foo.git +# +# the GIT_REPOSITORY_CACHE can be used with or without GIT_URL +# - if GIT_URL is given, GIT_REPOSITORY_CACHE will be a "bare" clone of GIT_URL +# - otherwise, GIT_REPOSITORY_CACHE can be created using: +# % git clone --bare BUILD/foo-1 $GIT_REPOSITORY_CACHE +# where foo-1 is the previous version + + +tarballs="$*" + + +git_clone_in_cwd() { + URL=$1 + [ -n "$2" ] && BRANCH="origin/$2" + + git clone $URL .git-tmp + + cd .git-tmp + git checkout $BRANCH + cd .. + + mv .git-tmp/.git . + rm -r .git-tmp +} + +our_git_clone() { + URL=$1 + HEAD=$2 + + if [ -n "$GIT_REPOSITORY_CACHE" ]; then + if [ -d "$GIT_REPOSITORY_CACHE" ]; then + cd "$GIT_REPOSITORY_CACHE" + git fetch $GIT_URL + cd - + else + git clone --bare $URL "$GIT_REPOSITORY_CACHE" + fi + git_clone_in_cwd "$GIT_REPOSITORY_CACHE" $HEAD + else + git_clone_in_cwd $URL $HEAD + fi +} + +if [ ! -e .git ]; then + if [ -n "$GIT_URL" ]; then + our_git_clone $GIT_URL + elif [ -n "$GIT_REPOSITORY_CACHE" -a -d "$GIT_REPOSITORY_CACHE" ]; then + git_clone_in_cwd "$GIT_REPOSITORY_CACHE" vanilla + else + git init + fi +fi +git add . +git commit -q -a -m "imported $tarballs" +git branch -f vanilla +git branch -f patches-applied +git checkout patches-applied diff --git a/git-repository--apply-patch b/git-repository--apply-patch new file mode 100755 index 0000000..a4bdf8b --- /dev/null +++ b/git-repository--apply-patch @@ -0,0 +1,158 @@ +#!/usr/bin/perl + +# this script can be used instead of "/usr/bin/patch [options] -i xxx.patch" + + +use strict; +use warnings; + +my @argv = @ARGV; +my $verbose; + +my @patches; +while ($argv[-1] =~ /\.(patch|diff)$/) { + unshift @patches, pop @argv; +} + +@patches or die "git-repository--apply-patch can not work with compressed patches\n"; # happens when the patch is passed through stdin + +my @opts; +while (@argv) { + my $s = shift @argv; + if ($s eq '-b') { + # we don't want .xxx files + } elsif ($s eq '--suffix') { + # we don't want .xxx files + shift @argv; + } elsif ($s eq '-i') { + # ignore "-i" + } else { + push @opts, $s; + } +} + +# we really don't want .orig when using git (even when there are hunks) +push @opts, '--no-backup-if-mismatch'; + +foreach my $patch_file (@patches) { + my @header = get_patch_header($patch_file); + + if (grep { /^Subject:/ } @header) { + my $patch_file_ = fix_git_patch($patch_file); + system_("git am " . ($patch_file_ || $patch_file)); + $patch_file_ and unlink $patch_file_; + } else { + system_("patch @opts -i $patch_file"); + + my ($patch_name) = $patch_file =~ m!([^/]*)\.(patch|diff)$!; + + system_('git add .'); + git_commit(commit_line_from_patch_name($patch_name) . + (@header ? "\n\n" . join('', cleanup_patch_header(@header)) : ''), + # use the date of the patch for the commit: + (stat($patch_file))[9] . " +0000"); + } +} + +sub system_ { + my ($cmd) = @_; + print "$cmd\n" if $verbose; + system($cmd) == 0 or die "$cmd failed\n"; +} + +sub git_commit { + my ($msg, $date) = @_; + + $ENV{GIT_AUTHOR_DATE} = $date; + open(my $F, '| git commit -q --author="unknown <>" --file=-'); + print $F $msg; + close $F or die "git commit failed\n"; +} + +sub commit_line_from_patch_name { + my ($name) = @_; + + # remove prefix (eg: "libtool-1.5.26-xxx" => "xxx") + my $re_name = qr([a-z][\w+]*([_-][a-z][\w+]*)*)i; + my $re_rc = qr((rc\d*|RC\d+|beta\d*|pre\d*|p\d+|test)); + my $re_special_version = qr([a-z]([._-]$re_rc?)?|[._-]?$re_rc?|[a-z]); + $name =~ s/^ $re_name [._-] \d+ (\.\d+)+ $re_special_version [._-]//x; + + if (my $pkg_name = $ENV{PKG_NAME}) { + $name =~ s/^\Q$pkg_name\E[_-]//; + } + + # replace "-" (resp. "_") with spaces if there is no spaces nor "_" (resp. "-") + if ($name !~ /[\s_]/ && $name !~ /--/) { + $name =~ s/-/ /g; + } elsif ($name !~ /[\s-]/ && $name !~ /__/) { + $name =~ s/_/ /g; + } + $name; +} + +sub get_patch_header { + my ($file) = @_; + open(my $F, '<', $file) or die "can not open $file: $!\n"; + + my @header; + while (my $s = <$F>) { + last if $s =~ /^--- /; + push @header, $s; + } + pop @header while @header && $header[-1] !~ /^\s*$/; + + @header; +} + +sub cleanup_patch_header { + my (@header) = @_; + + my @r; + foreach (@header) { + s/^##\s// or last; + push @r, $_; + } + @r == @header and return @r; + + @header; +} + +# "git format-patch" and "git am" do not agree how to handle commit logs when +# the first line is not separated from the rest. +# eg: +# +# > Subject: [PATCH 01/34] Delay NSS initialization until actually used +# > - since NSS is allergic (ie becomes non-functional) after forking, delay +# > it's initialization until really needed, ie lazy init in rpmDigestInit() +# +# workarounding by transforming header to: +# +# > Subject: [PATCH 01/34] Delay NSS initialization until actually used +# > +# > - since NSS is allergic (ie becomes non-functional) after forking, delay +# > it's initialization until really needed, ie lazy init in rpmDigestInit() +sub fix_git_patch { + my ($file) = @_; + open(my $F, '<', $file) or die "can not open $file: $!\n"; + + my ($last_line, @l); + while (my $s = <$F>) { + push @l, $s; + + if ($s !~ /^\S+:\s/ && $last_line && $last_line =~ /^Subject:/) { + # argh, we are in the header, but the value is weird + # applying the fix + $l[-1] = "\n" . $l[-1]; + push @l, <$F>; + output("$file.tmp", @l); + return "$file.tmp"; + } elsif ($s =~ /^\s*$/ || $s =~ /^--- /) { + last; + } + $last_line = $s; + } + undef; +} + +sub output { my $f = shift; open(my $F, '>', $f) or die "output in file $f failed: $!\n"; print $F $_ foreach @_; 1 } |