aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2018-07-18 20:43:41 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2018-07-27 14:23:07 +0300
commitf283fbea934a1a2bad3fa1df25a82717e6b11aac (patch)
tree6f3180be8ca67a8a7efe6e79c98b0366d0e9c099
parent07fdebdbb02fde71d6e656ddd46b967347417502 (diff)
Implement temp directory facility
-rw-r--r--bdep/bdep.cxx73
-rw-r--r--bdep/new.cxx4
-rw-r--r--bdep/publish.cxx2
-rw-r--r--bdep/sync.cxx8
-rw-r--r--bdep/utility.cxx73
-rw-r--r--bdep/utility.hxx30
6 files changed, 166 insertions, 24 deletions
diff --git a/bdep/bdep.cxx b/bdep/bdep.cxx
index 339be05..f77870f 100644
--- a/bdep/bdep.cxx
+++ b/bdep/bdep.cxx
@@ -12,6 +12,7 @@
#include <bdep/types.hxx>
#include <bdep/utility.hxx>
+#include <bdep/project.hxx> // find_project()
#include <bdep/diagnostics.hxx>
#include <bdep/bdep-options.hxx>
#include <bdep/project-options.hxx>
@@ -68,9 +69,25 @@ cfg_name (...)
return false;
}
+// Find the project directory if it is possible for the option class O and
+// return empty path otherwise.
+//
+template <typename O>
+static inline auto
+prj_dir (const O* o) -> decltype(find_project (*o))
+{
+ return find_project (*o);
+}
+
+static inline auto
+prj_dir (...) -> const dir_path& {return empty_dir_path;}
+
template <typename O>
static O
-init (const common_options& co, cli::group_scanner& scan, strings& args)
+init (const common_options& co,
+ cli::group_scanner& scan,
+ strings& args,
+ bool tmp)
{
O o;
static_cast<common_options&> (o) = co;
@@ -124,6 +141,11 @@ init (const common_options& co, cli::group_scanner& scan, strings& args)
? o.verbose ()
: o.V () ? 3 : o.v () ? 2 : o.quiet () ? 0 : 1;
+ // Temporary directory.
+ //
+ if (tmp)
+ init_tmp (dir_path (prj_dir (&o)));
+
return o;
}
@@ -196,7 +218,7 @@ try
const common_options& co (o);
if (o.help ())
- return help (init<help_options> (co, scan, argsv), "", nullptr);
+ return help (init<help_options> (co, scan, argsv, false), "", nullptr);
// The next argument should be a command.
//
@@ -211,7 +233,7 @@ try
if (h)
{
- ho = init<help_options> (co, scan, argsv);
+ ho = init<help_options> (co, scan, argsv, false);
if (args.more ())
{
@@ -255,28 +277,31 @@ try
// break;
// }
//
-#define COMMAND_IMPL(ON, FN, SN) \
- if (cmd.ON ()) \
- { \
- if (h) \
- r = help (ho, SN, print_bdep_##FN##_usage); \
- else \
- r = cmd_##FN (init<cmd_##FN##_options> (co, scan, argsv), args); \
- \
- break; \
+#define COMMAND_IMPL(ON, FN, SN, TMP) \
+ if (cmd.ON ()) \
+ { \
+ if (h) \
+ r = help (ho, SN, print_bdep_##FN##_usage); \
+ else \
+ r = cmd_##FN (init<cmd_##FN##_options> (co, scan, argsv, TMP), args); \
+ \
+ break; \
}
- COMMAND_IMPL (new_, new, "new");
- COMMAND_IMPL (init, init, "init");
- COMMAND_IMPL (sync, sync, "sync");
- COMMAND_IMPL (fetch, fetch, "fetch");
- COMMAND_IMPL (status, status, "status");
- COMMAND_IMPL (publish, publish, "publish");
- COMMAND_IMPL (deinit, deinit, "deinit");
- COMMAND_IMPL (config, config, "config");
- COMMAND_IMPL (test, test, "test");
- COMMAND_IMPL (update, update, "update");
- COMMAND_IMPL (clean, clean, "clean");
+ // Temp dir is initialized manually for these commands.
+ //
+ COMMAND_IMPL (new_, new, "new", false);
+ COMMAND_IMPL (sync, sync, "sync", false);
+
+ COMMAND_IMPL (init, init, "init", true);
+ COMMAND_IMPL (fetch, fetch, "fetch", true);
+ COMMAND_IMPL (status, status, "status", true);
+ COMMAND_IMPL (publish, publish, "publish", true);
+ COMMAND_IMPL (deinit, deinit, "deinit", true);
+ COMMAND_IMPL (config, config, "config", true);
+ COMMAND_IMPL (test, test, "test", true);
+ COMMAND_IMPL (update, update, "update", true);
+ COMMAND_IMPL (clean, clean, "clean", true);
assert (false);
fail << "unhandled command";
@@ -287,6 +312,8 @@ try
break;
}
+ clean_tmp (true /* ignore_error */);
+
if (r != 0)
return r;
diff --git a/bdep/new.cxx b/bdep/new.cxx
index dc86b72..2287431 100644
--- a/bdep/new.cxx
+++ b/bdep/new.cxx
@@ -1105,6 +1105,10 @@ namespace bdep
//
mk (prj / bdep_dir);
+ // Initialize tmp directory.
+ //
+ init_tmp (prj);
+
// Everything else requires a database.
//
database db (open (prj, trace, true /* create */));
diff --git a/bdep/publish.cxx b/bdep/publish.cxx
index 0fbe02d..2a74262 100644
--- a/bdep/publish.cxx
+++ b/bdep/publish.cxx
@@ -333,7 +333,7 @@ namespace bdep
// Prepare package archives and calculate their checksums. Also verify
// each archive with bpkg-pkg-verify for good measure.
//
- auto_rmdir dr_rm (dir_path ("/tmp/publish")); //@@ TODO tmp facility like in bpkg.
+ auto_rmdir dr_rm (tmp_dir ("publish"));
const dir_path& dr (dr_rm.path); // dist.root
mk (dr);
diff --git a/bdep/sync.cxx b/bdep/sync.cxx
index 1620555..ff37925 100644
--- a/bdep/sync.cxx
+++ b/bdep/sync.cxx
@@ -656,6 +656,10 @@ namespace bdep
!dep_pkgs.empty () /* ignore_packages */,
false /* load_packages */));
+ // Initialize tmp directory.
+ //
+ init_tmp (pp.project);
+
// Load project configurations.
//
{
@@ -713,6 +717,10 @@ namespace bdep
if (cfgs.empty ())
return 0; // All configuration are already (being) synchronized.
+
+ // Initialize tmp directory.
+ //
+ init_tmp (empty_dir_path);
}
// Synchronize each configuration.
diff --git a/bdep/utility.cxx b/bdep/utility.cxx
index 2600de9..45f924a 100644
--- a/bdep/utility.cxx
+++ b/bdep/utility.cxx
@@ -29,6 +29,57 @@ namespace bdep
const char* argv0;
dir_path exec_dir;
+ dir_path temp_dir;
+
+ auto_rmfile
+ tmp_file (const string& p)
+ {
+ assert (!temp_dir.empty ());
+ return auto_rmfile (temp_dir / path::traits::temp_name (p));
+ }
+
+ auto_rmdir
+ tmp_dir (const string& p)
+ {
+ assert (!temp_dir.empty ());
+ return auto_rmdir (temp_dir / dir_path (path::traits::temp_name (p)));
+ }
+
+ void
+ init_tmp (const dir_path& prj)
+ {
+ // Whether the project is required or optional depends on the command so
+ // if the project directory does not exist or it is not a bdep project
+ // directory, we simply create tmp in a system one and let the command
+ // complain if necessary.
+ //
+ dir_path d (prj.empty () ||
+ !exists (prj / bdep_dir, true /* ignore_error */)
+ ? dir_path::temp_path ("bdep")
+ : prj / bdep_dir / dir_path ("tmp"));
+
+ if (exists (d))
+ rm_r (d, true /* dir_itself */, 2);
+
+ mk (d); // We shouldn't need mk_p().
+
+ temp_dir = move (d);
+ }
+
+ void
+ clean_tmp (bool ignore_error)
+ {
+ if (!temp_dir.empty () && exists (temp_dir))
+ {
+ rm_r (temp_dir,
+ true /* dir_itself */,
+ 3,
+ ignore_error ? rm_error_mode::ignore : rm_error_mode::fail);
+
+ temp_dir.clear ();
+ }
+ }
+
bool
exists (const path& f, bool ignore_error)
{
@@ -101,6 +152,28 @@ namespace bdep
}
}
+ void
+ rm_r (const dir_path& d, bool dir, uint16_t v, rm_error_mode m)
+ {
+ if (verb >= v)
+ text << (dir ? "rmdir -r " : "rm -r ") << (dir ? d : d / dir_path ("*"));
+
+ try
+ {
+ rmdir_r (d, dir, m == rm_error_mode::ignore);
+ }
+ catch (const system_error& e)
+ {
+ bool w (m == rm_error_mode::warn);
+
+ (w ? warn : error) << "unable to remove " << (dir ? "" : "contents of ")
+ << "directory " << d << ": " << e;
+
+ if (!w)
+ throw failed ();
+ }
+ }
+
const char*
name_bpkg (const common_options& co)
{
diff --git a/bdep/utility.hxx b/bdep/utility.hxx
index 7bc1522..a8a755b 100644
--- a/bdep/utility.hxx
+++ b/bdep/utility.hxx
@@ -84,6 +84,28 @@ namespace bdep
extern const path repositories_file; // repositories.manifest
extern const path configurations_file; // configurations.manifest
+ // Temporary directory facility.
+ //
+ // This is normally .bdep/tmp/ but can also be some system-wide directory
+ // (e.g., /tmp/bdep-XXX/) if there is no bdep project. This directory
+ // is automatically created and cleaned up for most commands in main() so
+ // you don't need to call init_tmp() explicitly except for certain special
+ // commands (like new).
+ //
+ extern dir_path temp_dir;
+
+ auto_rmfile
+ tmp_file (const string& prefix);
+
+ auto_rmdir
+ tmp_dir (const string& prefix);
+
+ void
+ init_tmp (const dir_path& prj);
+
+ void
+ clean_tmp (bool ignore_errors);
+
// Process path (argv[0]).
//
extern const char* argv0;
@@ -113,6 +135,14 @@ namespace bdep
void
rm (const path&, uint16_t verbosity = 3);
+ enum class rm_error_mode {ignore, warn, fail};
+
+ void
+ rm_r (const dir_path&,
+ bool dir_itself = true,
+ uint16_t verbosity = 3,
+ rm_error_mode = rm_error_mode::fail);
+
// Run a process.
//
template <typename I, typename O, typename E, typename P, typename... A>