aboutsummaryrefslogtreecommitdiff
path: root/build2/dist/operation.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-03-20 17:19:04 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-03-20 17:19:04 +0200
commit82f596a82a09ba475ce28a0789210c9b5bbc52d2 (patch)
tree0410696117503fb919c6fffcac421bae02816f48 /build2/dist/operation.cxx
parent5c8fc857b790de371ba6f38b3eec214398f8eae0 (diff)
Reimplement compression for gzip, bzip2, and xz not to use tar's -a
This option is not supported by some tar implementations (like Mac OS) and may have issues (like MSYS2 BLODA).
Diffstat (limited to 'build2/dist/operation.cxx')
-rw-r--r--build2/dist/operation.cxx98
1 files changed, 89 insertions, 9 deletions
diff --git a/build2/dist/operation.cxx b/build2/dist/operation.cxx
index 612edc8..659b7b8 100644
--- a/build2/dist/operation.cxx
+++ b/build2/dist/operation.cxx
@@ -520,27 +520,107 @@ namespace build2
if (exists (ap, false))
rmfile (ap);
- // Use zip for .zip archives. Everything else goes to tar in the
- // auto-compress mode (-a).
+ // Use zip for .zip archives. Also recognize and handle a few well-known
+ // tar.xx cases (in case tar doesn't support -a or has other issues like
+ // MSYS). Everything else goes to tar in the auto-compress mode (-a).
//
cstrings args;
+
+ // Separate compressor (gzip, xz, etc) state.
+ //
+ size_t i (0); // Command line start or 0 if not used.
+ auto_rmfile out_rm; // Output file cleanup (must come first).
+ auto_fd out_fd; // Output file.
+
if (e == "zip")
- args = {"zip", "-rq",
- ap.string ().c_str (), pkg.c_str (), nullptr};
+ {
+ args = {"zip",
+ "-rq", ap.string ().c_str (),
+ pkg.c_str (),
+ nullptr};
+ }
else
- args = {"tar", "-a", "-cf",
- ap.string ().c_str (), pkg.c_str (), nullptr};
+ {
+ if (const char* c = (e == "tar.gz" ? "gzip" :
+ e == "tar.xz" ? "xz" :
+ e == "tar.bz2" ? "bzip2" :
+ nullptr))
+ {
+ args = {"tar",
+ "-cf", "-",
+ pkg.c_str (),
+ nullptr};
- process_path pp (run_search (args[0]));
+ i = args.size ();
+ args.push_back (c);
+ args.push_back (nullptr);
+ args.push_back (nullptr); // Pipe end.
+
+ try
+ {
+ out_fd = fdopen (ap,
+ fdopen_mode::out | fdopen_mode::binary |
+ fdopen_mode::truncate | fdopen_mode::create);
+ out_rm = auto_rmfile (ap);
+ }
+ catch (const io_error& e)
+ {
+ fail << "unable to open " << ap << ": " << e;
+ }
+ }
+ else if (e == "tar")
+ args = {"tar",
+ "-cf", ap.string ().c_str (),
+ pkg.c_str (),
+ nullptr};
+ else
+ args = {"tar",
+ "-a",
+ "-cf", ap.string ().c_str (),
+ pkg.c_str (),
+ nullptr};
+ }
+
+ process_path app; // Archiver path.
+ process_path cpp; // Compressor path.
+
+ app = run_search (args[0]);
+
+ if (i != 0)
+ cpp = run_search (args[i]);
if (verb >= 2)
print_process (args);
else if (verb)
text << args[0] << " " << ap;
- // Change child's working directory to dist_root.
+ process apr;
+ process cpr;
+
+ // Change the archiver's working directory to dist_root.
//
- run (pp, args, root);
+ apr = run_start (app,
+ args.data (),
+ 0 /* stdin */,
+ (i != 0 ? -1 : 1) /* stdout */,
+ true /* error */,
+ root);
+
+ // Start the compressor if required.
+ //
+ if (i != 0)
+ {
+ cpr = run_start (cpp,
+ args.data () + i,
+ apr.in_ofd.get () /* stdin */,
+ out_fd.get () /* stdout */);
+
+ cpr.in_ofd.reset (); // Close the archiver's stdout on our side.
+ run_finish (args.data () + i, cpr);
+ }
+
+ run_finish (args.data (), apr);
+ out_rm.cancel ();
}
const meta_operation_info mo_dist {