git-if-needed: read patches from a series file.
Change-Id: I29c87e8448f89deaab0c04678296b25013982486
diff --git a/tools/git-if-needed/sh/git-if-needed b/tools/git-if-needed/sh/git-if-needed
index ec81f36..d2251fe 100755
--- a/tools/git-if-needed/sh/git-if-needed
+++ b/tools/git-if-needed/sh/git-if-needed
@@ -2,29 +2,104 @@
set -e
+usage()
+{
+ cat <<EOUSAGE
+Usage: git-if-needed command /path/to/file.patch
+ git-if-needed [-S] -s /path/to/series command
+
+Options:
+ -S short paths: only use the last component of the patch path
+ -s series file: apply all the patches in that file
+
+Examples:
+ git if-needed am /path/to/local.patch
+ git if-needed -s /path/to/many-patches/series am
+EOUSAGE
+}
+
+apply_single()
+{
+ local cmd="$1" fname="$2"
+
+ if [ ! -e "$fname" ] || [ ! -f "$fname" ] || [ ! -r "$fname" ]; then
+ echo "Not a readable regular file: $fname" 1>&2
+ exit 1
+ fi
+
+ local chgid="$(egrep -e '^[[:space:]]*Change-Id:[[:space:]]+I[0-9a-f]+$' -- "$fname" | awk '{ print $2 }')"
+ if ! expr "x$chgid" : 'xI[0-9a-f][0-9a-f]*$' > /dev/null; then
+ echo "Expected a single Change-Id line in $fname" 1>&2
+ exit 1
+ fi
+
+ if git --no-pager log | egrep -qe "^[[:space:]]+Change-Id:[[:space:]]+${chgid}\$"; then
+ echo "# Change $chgid already present in the Git history"
+ elif git --no-pager "$cmd" -- "$fname"; then
+ echo "# 'git $cmd $fname' succeeded"
+ else
+ echo "# 'git $cmd $fname' failed"
+ git --no-pager status || echo "# 'git status' also failed"
+ exit 1
+ fi
+}
+
+apply_series()
+{
+ local cmd="$1" series="$2" short="$3"
+
+ series="$(readlink -f -- "$series")"
+ series_dir="$(dirname -- "$series")"
+ curdir="$(readlink -f .)"
+
+ while read filename; do
+ dirname="$(dirname -- "$filename")"
+ if [ -n "$short" ]; then
+ dirname="$(basename -- "$dirname")"
+ fi
+
+ cd -- "$dirname"
+ apply_single "$cmd" "$series_dir/$filename"
+ cd -- "$curdir"
+ done < "$series"
+}
+
+unset series short
+while getopts 'Ss:' o; do
+ case "$o" in
+ S)
+ short=1
+ ;;
+
+ s)
+ series="$OPTARG"
+ ;;
+
+ *)
+ usage 1>&2
+ exit 1
+ ;;
+ esac
+done
+
+shift "$((OPTIND - 1))"
+
+if [ -n "$series" ]; then
+ if [ "$#" -ne 1 ]; then
+ usage 1>&2
+ exit 1
+ fi
+
+ cmd="$1"
+ apply_series "$cmd" "$series" "$short"
+ exit 0
+fi
+
if [ "$#" -ne 2 ]; then
- echo 'Usage: git if-needed command filename' 1>&2
+ usage 1>&2
exit 1
fi
cmd="$1"
fname="$2"
-if [ ! -e "$fname" ] || [ ! -f "$fname" ] || [ ! -r "$fname" ]; then
- echo "Not a readable regular file: $fname" 1>&2
- exit 1
-fi
-chgid="$(egrep -e '^[[:space:]]*Change-Id:[[:space:]]+I[0-9a-f]+$' -- "$fname" | awk '{ print $2 }')"
-if ! expr "x$chgid" : 'xI[0-9a-f][0-9a-f]*$' > /dev/null; then
- echo "Expected a single Change-Id line in $fname" 1>&2
- exit 1
-fi
-
-if git --no-pager log | egrep -qe "^[[:space:]]+Change-Id:[[:space:]]+${chgid}\$"; then
- echo "# Change $chgid already present in the Git history"
-elif git --no-pager "$cmd" -- "$fname"; then
- echo "# 'git $cmd $fname' succeeded"
-else
- echo "# 'git $cmd $fname' failed"
- git --no-pager status || echo "# 'git status' also failed"
- exit 1
-fi
+apply_single "$cmd" "$fname"
diff --git a/tools/git-if-needed/tests/data/openstack/cinder/add-readme.patch b/tools/git-if-needed/tests/data/openstack/cinder/add-readme.patch
new file mode 100644
index 0000000..a6012ce
--- /dev/null
+++ b/tools/git-if-needed/tests/data/openstack/cinder/add-readme.patch
@@ -0,0 +1,21 @@
+From 8d0a6195ee106f7d18ff9f6d6d33747cf5db6250 Mon Sep 17 00:00:00 2001
+From: Peter Penchev <openstack-dev@storpool.com>
+Date: Tue, 3 Dec 2019 16:11:08 +0200
+Subject: [PATCH 1/3] Add a README file.
+
+Change-Id: I81a662baca9813772f6b1b83a1c034bd1fe6d53f
+---
+ README.txt | 1 +
+ 1 file changed, 1 insertion(+)
+ create mode 100644 README.txt
+
+diff --git a/README.txt b/README.txt
+new file mode 100644
+index 0000000..4dd1ef7
+--- /dev/null
++++ b/README.txt
+@@ -0,0 +1 @@
++This is a file.
+--
+2.24.0
+
diff --git a/tools/git-if-needed/tests/data/openstack/cinder/another-file.patch b/tools/git-if-needed/tests/data/openstack/cinder/another-file.patch
new file mode 100644
index 0000000..7286cdb
--- /dev/null
+++ b/tools/git-if-needed/tests/data/openstack/cinder/another-file.patch
@@ -0,0 +1,21 @@
+From 5c71ff4ba69bd0b95a6f3747886f10480dc24db3 Mon Sep 17 00:00:00 2001
+From: Peter Penchev <openstack-dev@storpool.com>
+Date: Tue, 3 Dec 2019 16:11:53 +0200
+Subject: [PATCH 3/3] Add another file.
+
+Change-Id: Ieb2a7d5346a74e8af3569d08057a8c83a537a1ad
+---
+ TODO.txt | 1 +
+ 1 file changed, 1 insertion(+)
+ create mode 100644 TODO.txt
+
+diff --git a/TODO.txt b/TODO.txt
+new file mode 100644
+index 0000000..209db4a
+--- /dev/null
++++ b/TODO.txt
+@@ -0,0 +1 @@
++Things to do. Or something.
+--
+2.24.0
+
diff --git a/tools/git-if-needed/tests/data/openstack/cinder/conflict-in-readme.patch b/tools/git-if-needed/tests/data/openstack/cinder/conflict-in-readme.patch
new file mode 100644
index 0000000..82039e5
--- /dev/null
+++ b/tools/git-if-needed/tests/data/openstack/cinder/conflict-in-readme.patch
@@ -0,0 +1,20 @@
+From 81dd71b0300a7819d8babf73072965cfc5d3a604 Mon Sep 17 00:00:00 2001
+From: Peter Penchev <openstack-dev@storpool.com>
+Date: Tue, 3 Dec 2019 16:12:25 +0200
+Subject: [PATCH 2/2] Modify README.txt in a different way.
+
+Change-Id: I2e216842094051a30d999bf8dfebf87810202c17
+---
+ README.txt | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/README.txt b/README.txt
+index 4dd1ef7..b38c628 100644
+--- a/README.txt
++++ b/README.txt
+@@ -1 +1 @@
+-This is a file.
++This is a file. Or something. I guess.
+--
+2.24.0
+
diff --git a/tools/git-if-needed/tests/data/openstack/cinder/modify-readme.patch b/tools/git-if-needed/tests/data/openstack/cinder/modify-readme.patch
new file mode 100644
index 0000000..4c75ba2
--- /dev/null
+++ b/tools/git-if-needed/tests/data/openstack/cinder/modify-readme.patch
@@ -0,0 +1,20 @@
+From 54a7cac37658e17af661b34b541507d50a24f0c9 Mon Sep 17 00:00:00 2001
+From: Peter Penchev <openstack-dev@storpool.com>
+Date: Tue, 3 Dec 2019 16:11:21 +0200
+Subject: [PATCH 2/3] Modify the README file.
+
+Change-Id: If062e5daee091fc17d3a2cacbbbaa39522385184
+---
+ README.txt | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/README.txt b/README.txt
+index 4dd1ef7..5e7d880 100644
+--- a/README.txt
++++ b/README.txt
+@@ -1 +1 @@
+-This is a file.
++This is a file. It contains some text.
+--
+2.24.0
+
diff --git a/tools/git-if-needed/tests/data/openstack/nova/add-readme.patch b/tools/git-if-needed/tests/data/openstack/nova/add-readme.patch
new file mode 100644
index 0000000..5c09fa1
--- /dev/null
+++ b/tools/git-if-needed/tests/data/openstack/nova/add-readme.patch
@@ -0,0 +1,21 @@
+From 5fdf1ec10ca56c7b58328aa1a544d9ec395bd95f Mon Sep 17 00:00:00 2001
+From: Peter Penchev <openstack-dev@storpool.com>
+Date: Tue, 3 Dec 2019 16:15:52 +0200
+Subject: [PATCH] Add a README file in another repository.
+
+Change-Id: I227fed25c0565b65ad46fa6ff4386a4547f9af45
+---
+ README.txt | 1 +
+ 1 file changed, 1 insertion(+)
+ create mode 100644 README.txt
+
+diff --git a/README.txt b/README.txt
+new file mode 100644
+index 0000000..d4e7da7
+--- /dev/null
++++ b/README.txt
+@@ -0,0 +1 @@
++This is another file. It has no bearing on the first one.
+--
+2.24.0
+
diff --git a/tools/git-if-needed/tests/data/series b/tools/git-if-needed/tests/data/series
new file mode 100644
index 0000000..fbb68d7
--- /dev/null
+++ b/tools/git-if-needed/tests/data/series
@@ -0,0 +1,4 @@
+openstack/cinder/add-readme.patch
+openstack/cinder/modify-readme.patch
+openstack/nova/add-readme.patch
+openstack/cinder/another-file.patch
diff --git a/tools/git-if-needed/tests/gifn-test.pl b/tools/git-if-needed/tests/gifn-test.pl
index 5de957d..989cbfa 100755
--- a/tools/git-if-needed/tests/gifn-test.pl
+++ b/tools/git-if-needed/tests/gifn-test.pl
@@ -346,6 +346,77 @@
}
}
+sub setup_subdir_repos($)
+{
+ my ($cfg) = @_;
+
+ $cfg->{sub}->{full}->{base} = $cfg->{subrepo}->child('full');
+ $cfg->{sub}->{full}->{cinder} =
+ $cfg->{sub}->{full}->{base}->
+ child('openstack')->child('cinder');
+ $cfg->{sub}->{full}->{nova} =
+ $cfg->{sub}->{full}->{base}->
+ child('openstack')->child('nova');
+ $cfg->{sub}->{full}->{cinder}->mkpath({ mode => 0755 });
+ $cfg->{sub}->{full}->{nova}->mkpath({ mode => 0755 });
+
+ $cfg->{sub}->{short}->{base} = $cfg->{subrepo}->child('short');
+ $cfg->{sub}->{short}->{cinder} =
+ $cfg->{sub}->{short}->{base}->child('cinder');
+ $cfg->{sub}->{short}->{nova} =
+ $cfg->{sub}->{short}->{base}->child('nova');
+ $cfg->{sub}->{short}->{cinder}->mkpath({ mode => 0755 });
+ $cfg->{sub}->{short}->{nova}->mkpath({ mode => 0755 });
+
+ for my $part (qw(full short)) {
+ for my $comp (qw(cinder nova)) {
+ my $dir = $cfg->{sub}->{$part}->{$comp};
+ chdir($dir) or die "Could not change into $dir: $!\n";
+ run_command @{$cfg->{git}}, 'init';
+ git_status_ok $cfg;
+ }
+ }
+}
+
+sub test_subdir($ $ $ $)
+{
+ my ($cfg, $part, $expected, $opt) = @_;
+ my $run = $expected ? 'second' : 'first';
+ my $sub = $cfg->{sub}->{$part};
+
+ say "\ntest-subdir $part $run\n";
+
+ my $any = sub {
+ $sub->{cinder}->child('README.txt')->exists ||
+ $sub->{nova}->child('README.txt')->exists
+ };
+ my $all = sub {
+ $sub->{cinder}->child('README.txt')->exists &&
+ $sub->{nova}->child('README.txt')->exists
+ };
+
+ chdir $sub->{base} or die "Could not change into $sub->{base}: $!\n";
+ if ($expected && !$all->()) {
+ die "No $part files before the second run in $sub->{base}\n";
+ } elsif (!$expected && $any->()) {
+ die "Unexpected $part files in $sub->{base}\n";
+ }
+
+ run_command @{$cfg->{gifn}}, '-s', $cfg->{data}->child('series'),
+ @{$opt}, 'am';
+
+ if (!$all->()) {
+ my $run = $expected ? 'second' : 'first';
+ die "No $part files after the $run run in $sub->{base}\n";
+ }
+
+ for my $comp (qw(cinder nova)) {
+ chdir $sub->{$comp} or
+ die "Could not change into $sub->{comp}: $!\n";
+ git_status_ok $cfg;
+ }
+}
+
MAIN:
{
my %opts;
@@ -361,6 +432,9 @@
my $repodir = File::Temp->newdir(
TEMPLATE => 'gifn-test.XXXXXX',
TMPDIR => 1);
+ my $subrepodir = File::Temp->newdir(
+ TEMPLATE => 'gifn-test.XXXXXX',
+ TMPDIR => 1);
my $cfg = {
cwd => $cwd,
@@ -368,6 +442,7 @@
gifn => [@ARGV],
git => ['env', "LC_MESSAGES=$locale", 'git', '--no-pager'],
repo => path($repodir),
+ subrepo => path($subrepodir),
};
$cfg->{gifn}[0] = path($cfg->{gifn}[0])->absolute;
@@ -381,6 +456,13 @@
test_apply $cfg, @{PATCHFILES->{more}};
test_already_applied $cfg, (@{PATCHFILES->{initial}}, @{PATCHFILES->{more}});
test_fail_to_apply $cfg, @{PATCHFILES->{conflict}};
+
+ setup_subdir_repos $cfg;
+
+ test_subdir $cfg, 'full', 0, [];
+ test_subdir $cfg, 'short', 0, ['-S'];
+ test_subdir $cfg, 'full', 1, [];
+ test_subdir $cfg, 'short', 1, ['-S'];
};
my $err = $@;
chdir $cwd;