Currently, git-archive does not properly determine the desired archive
format when both --output and --remote are provided, because
run_remote_archiver() does not initialize the archivers prior to calling
archive_format_from_filename(). This results in the remote archiver
always returning a TAR file, regardless of the requested format.
This patch initializes the TAR and ZIP archivers before calling
archive_format_from_filename(), which fixes format detection.
Steps to reproduce:
∫ git version
git version 2.19.1.568.g152ad8e336-goog
∫ cd ~/src/git
∫ git archive --output ~/good.zip HEAD
∫ file ~/good.zip
/home/steadmon/good.zip: Zip archive data, at least v1.0 to extract
∫ git archive --output ~/bad.zip --remote=. HEAD
∫ file ~/bad.zip
/home/steadmon/bad.zip: POSIX tar archive
(apply patch and build)
∫ ./bin-wrappers/git archive --output ~/fixed.zip --remote=. HEAD
∫ file ~/fixed.zip
/home/steadmon/fixed.zip: Zip archive data, at least v1.0 to extract
Josh Steadmon (1):
archive: init archivers before determining format
builtin/archive.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
--
2.19.1.568.g152ad8e336-goog
When passing both --remote and --output to git-archive, initialize the
archivers before attempting to determine the format from the output
filename. Without initialization, the format cannot be determined.
Signed-off-by: Josh Steadmon <redacted>
---
builtin/archive.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
Hrm. This code was added back in 56baa61d01 (archive: move file
extension format-guessing lower, 2011-06-21), and your example
invocation worked back then!
Unfortunately it was broken by the very next patch in the series,
08716b3c11 (archive: refactor file extension format-guessing,
2011-06-21). I guess that's what I get for not adding regression tests.
It's probably worth mentioning those points in the commit message.
Does this work with configured archiver extensions, too? I think so,
because we load them via init_tar_archiver().
Can we avoid repeating the list of archivers here? This needs to stay in
sync with the list in write_archive(). I know there are only two, but
can we factor out an init_archivers() call or something?
We also should probably just call it unconditionally when we start the
archiver command (I don't think there are any other bugs like this
lurking, but it doesn't cost very much to initialize these; it makes
sense to just do it early).
Other than those minor points (and the lack of test), your fix looks
good to me.
-Peff
Hrm. This code was added back in 56baa61d01 (archive: move file
extension format-guessing lower, 2011-06-21), and your example
invocation worked back then!
Unfortunately it was broken by the very next patch in the series,
08716b3c11 (archive: refactor file extension format-guessing,
2011-06-21). I guess that's what I get for not adding regression tests.
It's probably worth mentioning those points in the commit message.
Done.
Does this work with configured archiver extensions, too? I think so,
because we load them via init_tar_archiver().
If you mean things like .tgz and .tar.gz, then yes, they are affected by
the bug as well, and this patch fixes them. The test included in v2 uses
a .tgz file.
Can we avoid repeating the list of archivers here? This needs to stay in
sync with the list in write_archive(). I know there are only two, but
can we factor out an init_archivers() call or something?
Done.
We also should probably just call it unconditionally when we start the
archiver command (I don't think there are any other bugs like this
lurking, but it doesn't cost very much to initialize these; it makes
sense to just do it early).
Done.
Other than those minor points (and the lack of test), your fix looks
good to me.
From: Jeff King <hidden> Date: 2018-10-22 22:30:45
On Mon, Oct 22, 2018 at 02:47:56PM -0700, Josh Steadmon wrote:
quoted
Does this work with configured archiver extensions, too? I think so,
because we load them via init_tar_archiver().
If you mean things like .tgz and .tar.gz, then yes, they are affected by
the bug as well, and this patch fixes them. The test included in v2 uses
a .tgz file.
Yes, but also ones that are provided by the user. E.g., does:
git config tar.foo.command "foo"
git archive -o out.tar.foo HEAD
work? (I think the answer is yes, because we read git_tar_config in the
same place).
-Peff
From: Jeff King <hidden> Date: 2018-10-19 23:41:29
On Fri, Oct 19, 2018 at 04:19:27PM -0700, steadmon@google.com wrote:
Currently, git-archive does not properly determine the desired archive
format when both --output and --remote are provided, because
run_remote_archiver() does not initialize the archivers prior to calling
archive_format_from_filename(). This results in the remote archiver
always returning a TAR file, regardless of the requested format.
This patch initializes the TAR and ZIP archivers before calling
archive_format_from_filename(), which fixes format detection.
It seems like some of this content could be in the commit message of the
actual patch.
Steps to reproduce:
∫ git version
git version 2.19.1.568.g152ad8e336-goog
∫ cd ~/src/git
∫ git archive --output ~/good.zip HEAD
∫ file ~/good.zip
/home/steadmon/good.zip: Zip archive data, at least v1.0 to extract
∫ git archive --output ~/bad.zip --remote=. HEAD
∫ file ~/bad.zip
/home/steadmon/bad.zip: POSIX tar archive
And this could be in a test script in the actual patch. :)
-Peff
On Fri, Oct 19, 2018 at 04:19:27PM -0700, steadmon@google.com wrote:
quoted
Currently, git-archive does not properly determine the desired archive
format when both --output and --remote are provided, because
run_remote_archiver() does not initialize the archivers prior to calling
archive_format_from_filename(). This results in the remote archiver
always returning a TAR file, regardless of the requested format.
This patch initializes the TAR and ZIP archivers before calling
archive_format_from_filename(), which fixes format detection.
It seems like some of this content could be in the commit message of the
actual patch.
Ack. I'll be sending v2 shortly, please let me know if I've missed
anything that should be included.
quoted
Steps to reproduce:
∫ git version
git version 2.19.1.568.g152ad8e336-goog
∫ cd ~/src/git
∫ git archive --output ~/good.zip HEAD
∫ file ~/good.zip
/home/steadmon/good.zip: Zip archive data, at least v1.0 to extract
∫ git archive --output ~/bad.zip --remote=. HEAD
∫ file ~/bad.zip
/home/steadmon/bad.zip: POSIX tar archive
And this could be in a test script in the actual patch. :)
Initialize archivers as soon as possible when running git-archive and
git-upload-archive. Various non-obvious behavior depends on having the
archivers initialized, such as determining the desired archival format
from the provided filename.
Since 08716b3c11 ("archive: refactor file extension format-guessing",
2011-06-21), archive_format_from_filename() has used the registered
archivers to match filenames (provided via --output) to archival
formats. However, when git-archive is executed with --remote, format
detection happens before the archivers have been registered. This causes
archives from remotes to always be generated as TAR files, regardless of
the actual filename (unless an explicit --format is provided).
This patch fixes that behavior; archival format is determined properly
from the output filename, even when --remote is used.
Signed-off-by: Josh Steadmon <redacted>
Helped-by: Jeff King [off-list ref]
---
archive.c | 9 ++++++---
archive.h | 1 +
builtin/archive.c | 2 ++
builtin/upload-archive.c | 1 +
t/t5000-tar-tree.sh | 6 ++++++
5 files changed, 16 insertions(+), 3 deletions(-)
@@ -43,6 +43,7 @@ int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)}/* parse all options sent by the client */+init_archivers();returnwrite_archive(sent_argv.argc,sent_argv.argv,prefix,the_repository,NULL,1);}
From: Jeff King <hidden> Date: 2018-10-22 22:35:39
On Mon, Oct 22, 2018 at 02:48:11PM -0700, steadmon@google.com wrote:
Initialize archivers as soon as possible when running git-archive and
git-upload-archive. Various non-obvious behavior depends on having the
archivers initialized, such as determining the desired archival format
from the provided filename.
Since 08716b3c11 ("archive: refactor file extension format-guessing",
2011-06-21), archive_format_from_filename() has used the registered
archivers to match filenames (provided via --output) to archival
formats. However, when git-archive is executed with --remote, format
detection happens before the archivers have been registered. This causes
archives from remotes to always be generated as TAR files, regardless of
the actual filename (unless an explicit --format is provided).
This patch fixes that behavior; archival format is determined properly
from the output filename, even when --remote is used.
Signed-off-by: Josh Steadmon <redacted>
Helped-by: Jeff King [off-list ref]
Thanks, this looks good overall.
A few minor comments (that I'm not even sure are worth re-rolling for):
@@ -43,6 +43,7 @@ int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)}/* parse all options sent by the client */+init_archivers();returnwrite_archive(sent_argv.argc,sent_argv.argv,prefix,the_repository,NULL,1);}
This seems to separate the comment from what it describes. Any reason
not to just init_archivers() closer to the top of the function here
(probably after the enter_repo() call)?
@@ -206,6 +206,12 @@ test_expect_success 'git archive with --output, override inferred format' 'test_cmp_binb.tard4.zip'+test_expect_successGZIP'git archive with --output and --remote uses expected format''+gitarchive--output=d5.tgz--remote=.HEAD&&+gzip-d-c<d5.tgz>d5.tar&&+test_cmp_binb.tard5.tar+'
This nicely tests the more-interesting tgz case. But unfortunately it
won't run on machines without the GZIP prerequisite. I'd think that
would really be _most_ machines, but is it worth having a separate zip
test to cover machines without gzip? I guess that just creates the
opposite problem: not everybody has ZIP.
-Peff
On Mon, Oct 22, 2018 at 02:48:11PM -0700, steadmon@google.com wrote:
quoted
Initialize archivers as soon as possible when running git-archive and
git-upload-archive. Various non-obvious behavior depends on having the
archivers initialized, such as determining the desired archival format
from the provided filename.
Since 08716b3c11 ("archive: refactor file extension format-guessing",
2011-06-21), archive_format_from_filename() has used the registered
archivers to match filenames (provided via --output) to archival
formats. However, when git-archive is executed with --remote, format
detection happens before the archivers have been registered. This causes
archives from remotes to always be generated as TAR files, regardless of
the actual filename (unless an explicit --format is provided).
This patch fixes that behavior; archival format is determined properly
from the output filename, even when --remote is used.
Signed-off-by: Josh Steadmon <redacted>
Helped-by: Jeff King [off-list ref]
Thanks, this looks good overall.
A few minor comments (that I'm not even sure are worth re-rolling for):
@@ -43,6 +43,7 @@ int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)}/* parse all options sent by the client */+init_archivers();returnwrite_archive(sent_argv.argc,sent_argv.argv,prefix,the_repository,NULL,1);}
This seems to separate the comment from what it describes. Any reason
not to just init_archivers() closer to the top of the function here
(probably after the enter_repo() call)?
@@ -206,6 +206,12 @@ test_expect_success 'git archive with --output, override inferred format' 'test_cmp_binb.tard4.zip'+test_expect_successGZIP'git archive with --output and --remote uses expected format''+gitarchive--output=d5.tgz--remote=.HEAD&&+gzip-d-c<d5.tgz>d5.tar&&+test_cmp_binb.tard5.tar+'
This nicely tests the more-interesting tgz case. But unfortunately it
won't run on machines without the GZIP prerequisite. I'd think that
would really be _most_ machines, but is it worth having a separate zip
test to cover machines without gzip? I guess that just creates the
opposite problem: not everybody has ZIP.
Added a test to compare the file lists from the .zip file to the
reference .tar file. I'm not sure if this is the best way to do things,
but it at least verifies that a .zip is produced. However, it's brittle
if the output of "zip -sf" changes. Let me know if you have a better
idea.
This nicely tests the more-interesting tgz case. But unfortunately it
won't run on machines without the GZIP prerequisite. I'd think that
would really be _most_ machines, but is it worth having a separate zip
test to cover machines without gzip? I guess that just creates the
opposite problem: not everybody has ZIP.
Added a test to compare the file lists from the .zip file to the
reference .tar file. I'm not sure if this is the best way to do things,
but it at least verifies that a .zip is produced. However, it's brittle
if the output of "zip -sf" changes. Let me know if you have a better
idea.
I wonder if we could do something more black-box. What we really care
about here is not the exact output, but rather that "-o foo.zip"
produces the same output as "--format zip". Could we do that without
even relying on ZIP?
I think it should follow even for tgz, because we use "-n" for a
repeatable output. But there we are relying on an external gzip just to
_create_ the file, so we'd still need the GZIP prereq.
Hmm. Looks like we already have a similar test in t5003. So maybe just:
@@ -158,11 +158,16 @@ test_expect_success 'git archive --format=zip with --output' \'gitarchive--format=zip--output=d2.zipHEAD&&test_cmp_bind.zipd2.zip'-test_expect_success'git archive with --output, inferring format''+test_expect_success'git archive with --output, inferring format (local)''gitarchive--output=d3.zipHEAD&&test_cmp_bind.zipd3.zip'+test_expect_success'git archive with --output, ferring format (remote)''+gitarchive--remote=.--output=d4.zipHEAD&&+test_cmp_bind.zipd4.zip+'+ test_expect_success\'git archive --format=zip with prefix'\'git archive --format=zip --prefix=prefix/ HEAD >e.zip'
which I think exposes the bug and can run everywhere?
-Peff
This nicely tests the more-interesting tgz case. But unfortunately it
won't run on machines without the GZIP prerequisite. I'd think that
would really be _most_ machines, but is it worth having a separate zip
test to cover machines without gzip? I guess that just creates the
opposite problem: not everybody has ZIP.
Added a test to compare the file lists from the .zip file to the
reference .tar file. I'm not sure if this is the best way to do things,
but it at least verifies that a .zip is produced. However, it's brittle
if the output of "zip -sf" changes. Let me know if you have a better
idea.
I wonder if we could do something more black-box. What we really care
about here is not the exact output, but rather that "-o foo.zip"
produces the same output as "--format zip". Could we do that without
even relying on ZIP?
I think it should follow even for tgz, because we use "-n" for a
repeatable output. But there we are relying on an external gzip just to
_create_ the file, so we'd still need the GZIP prereq.
Hmm. Looks like we already have a similar test in t5003. So maybe just:
@@ -158,11 +158,16 @@ test_expect_success 'git archive --format=zip with --output' \'gitarchive--format=zip--output=d2.zipHEAD&&test_cmp_bind.zipd2.zip'-test_expect_success'git archive with --output, inferring format''+test_expect_success'git archive with --output, inferring format (local)''gitarchive--output=d3.zipHEAD&&test_cmp_bind.zipd3.zip'+test_expect_success'git archive with --output, ferring format (remote)''+gitarchive--remote=.--output=d4.zipHEAD&&+test_cmp_bind.zipd4.zip+'+ test_expect_success\'git archive --format=zip with prefix'\'git archive --format=zip --prefix=prefix/ HEAD >e.zip'
which I think exposes the bug and can run everywhere?
Initialize archivers as soon as possible when running git-archive.
Various non-obvious behavior depends on having the archivers
initialized, such as determining the desired archival format from the
provided filename.
Since 08716b3c11 ("archive: refactor file extension format-guessing",
2011-06-21), archive_format_from_filename() has used the registered
archivers to match filenames (provided via --output) to archival
formats. However, when git-archive is executed with --remote, format
detection happens before the archivers have been registered. This causes
archives from remotes to always be generated as TAR files, regardless of
the actual filename (unless an explicit --format is provided).
This patch fixes that behavior; archival format is determined properly
from the output filename, even when --remote is used.
Signed-off-by: Josh Steadmon <redacted>
Helped-by: Jeff King [off-list ref]
---
Range-diff against v2:
1: bc6f20274d ! 1: 39a4e7bf8f archive: initialize archivers earlier
@@ -78,26 +78,43 @@
--- a/builtin/upload-archive.c
+++ b/builtin/upload-archive.c
@@
- }
+ if (!enter_repo(argv[1], 0))
+ die("'%s' does not appear to be a git repository", argv[1]);
- /* parse all options sent by the client */
+ init_archivers();
- return write_archive(sent_argv.argc, sent_argv.argv, prefix,
- the_repository, NULL, 1);
- }
++
+ /* put received options in sent_argv[] */
+ argv_array_push(&sent_argv, "git-upload-archive");
+ for (;;) {
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@
+
+ test_lazy_prereq GZIP 'gzip --version'
+
++test_lazy_prereq ZIP 'zip --version'
++
+ get_pax_header() {
+ file=$1
+ header=$2=
+@@
test_cmp_bin b.tar d4.zip
'
-+test_expect_success GZIP 'git archive with --output and --remote uses expected format' '
++test_expect_success GZIP 'git archive with --output and --remote creates .tgz' '
+ git archive --output=d5.tgz --remote=. HEAD &&
+ gzip -d -c < d5.tgz > d5.tar &&
+ test_cmp_bin b.tar d5.tar
+'
++
++test_expect_success ZIP 'git archive with --output and --remote creates .zip' '
++ git archive --output=d6.zip --remote=. HEAD &&
++ zip -sf d6.zip | sed "/^[^ ]/d" | sed "s/^ //" | sort > zip_manifest &&
++ "$TAR" tf b.tar | sort > tar_manifest &&
++ test_cmp zip_manifest tar_manifest
++'
+
test_expect_success 'git archive --list outside of a git repo' '
nongit git archive --list
archive.c | 9 ++++++---
archive.h | 1 +
builtin/archive.c | 2 ++
builtin/upload-archive.c | 2 ++
t/t5000-tar-tree.sh | 15 +++++++++++++++
5 files changed, 26 insertions(+), 3 deletions(-)
@@ -28,6 +28,8 @@ int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)if(!enter_repo(argv[1],0))die("'%s' does not appear to be a git repository",argv[1]);+init_archivers();+/* put received options in sent_argv[] */argv_array_push(&sent_argv,"git-upload-archive");for(;;){
@@ -28,6 +28,8 @@ int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)if(!enter_repo(argv[1],0))die("'%s' does not appear to be a git repository",argv[1]);+init_archivers();+/* put received options in sent_argv[] */argv_array_push(&sent_argv,"git-upload-archive");for(;;){
@@ -158,11 +158,16 @@ test_expect_success 'git archive --format=zip with --output' \'gitarchive--format=zip--output=d2.zipHEAD&&test_cmp_bind.zipd2.zip'-test_expect_success'git archive with --output, inferring format''+test_expect_success'git archive with --output, inferring format (local)''gitarchive--output=d3.zipHEAD&&test_cmp_bind.zipd3.zip'+test_expect_success'git archive with --output, inferring format (remote)''+gitarchive--remote=.--output=d4.zipHEAD&&+test_cmp_bind.zipd4.zip+'+ test_expect_success\'git archive --format=zip with prefix'\'git archive --format=zip --prefix=prefix/ HEAD >e.zip'
Initialize archivers as soon as possible when running git-archive.
Various non-obvious behavior depends on having the archivers
initialized, such as determining the desired archival format from the
provided filename.
Since 08716b3c11 ("archive: refactor file extension format-guessing",
2011-06-21), archive_format_from_filename() has used the registered
archivers to match filenames (provided via --output) to archival
formats. However, when git-archive is executed with --remote, format
detection happens before the archivers have been registered. This causes
archives from remotes to always be generated as TAR files, regardless of
the actual filename (unless an explicit --format is provided).
This patch fixes that behavior; archival format is determined properly
from the output filename, even when --remote is used.
Signed-off-by: Josh Steadmon <redacted>
Helped-by: Jeff King [off-list ref]
---
Range-diff against v4:
1: 1d7b070928 ! 1: c85673cee7 archive: initialize archivers earlier
@@ -96,7 +96,7 @@
+test_expect_success GZIP 'git archive with --output and --remote creates .tgz' '
+ git archive --output=d5.tgz --remote=. HEAD &&
-+ gzip -d -c < d5.tgz > d5.tar &&
++ gzip -d -c <d5.tgz >d5.tar &&
+ test_cmp_bin b.tar d5.tar
+'
+
archive.c | 9 ++++++---
archive.h | 1 +
builtin/archive.c | 2 ++
builtin/upload-archive.c | 2 ++
t/t5000-tar-tree.sh | 6 ++++++
t/t5003-archive-zip.sh | 7 ++++++-
6 files changed, 23 insertions(+), 4 deletions(-)
@@ -28,6 +28,8 @@ int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)if(!enter_repo(argv[1],0))die("'%s' does not appear to be a git repository",argv[1]);+init_archivers();+/* put received options in sent_argv[] */argv_array_push(&sent_argv,"git-upload-archive");for(;;){
@@ -158,11 +158,16 @@ test_expect_success 'git archive --format=zip with --output' \'gitarchive--format=zip--output=d2.zipHEAD&&test_cmp_bind.zipd2.zip'-test_expect_success'git archive with --output, inferring format''+test_expect_success'git archive with --output, inferring format (local)''gitarchive--output=d3.zipHEAD&&test_cmp_bind.zipd3.zip'+test_expect_success'git archive with --output, inferring format (remote)''+gitarchive--remote=.--output=d4.zipHEAD&&+test_cmp_bind.zipd4.zip+'+ test_expect_success\'git archive --format=zip with prefix'\'git archive --format=zip --prefix=prefix/ HEAD >e.zip'
From: Jeff King <hidden> Date: 2018-10-25 21:12:07
On Thu, Oct 25, 2018 at 01:32:14PM -0700, steadmon@google.com wrote:
Initialize archivers as soon as possible when running git-archive.
Various non-obvious behavior depends on having the archivers
initialized, such as determining the desired archival format from the
provided filename.
Since 08716b3c11 ("archive: refactor file extension format-guessing",
2011-06-21), archive_format_from_filename() has used the registered
archivers to match filenames (provided via --output) to archival
formats. However, when git-archive is executed with --remote, format
detection happens before the archivers have been registered. This causes
archives from remotes to always be generated as TAR files, regardless of
the actual filename (unless an explicit --format is provided).
This patch fixes that behavior; archival format is determined properly
from the output filename, even when --remote is used.