aboutsummaryrefslogtreecommitdiff
path: root/bdep
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2019-03-21 21:56:15 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2019-03-23 16:25:12 +0300
commit51e1d64dccf4967eb078858529a0d7f05b8b461e (patch)
treee8314c5d2ece0964f828dedb203465e79d5a634b /bdep
parentbba28902195a9aceb987d474cf2004d034932533 (diff)
Add --post-hook option to bdep-new
Diffstat (limited to 'bdep')
-rw-r--r--bdep/new-types.hxx50
-rw-r--r--bdep/new.cli66
-rw-r--r--bdep/new.cxx74
3 files changed, 176 insertions, 14 deletions
diff --git a/bdep/new-types.hxx b/bdep/new-types.hxx
index 9d19c48..96aaa7c 100644
--- a/bdep/new-types.hxx
+++ b/bdep/new-types.hxx
@@ -46,20 +46,26 @@ namespace bdep
//
cmd_new_type_template (): type (exe) {}
- friend ostream&
- operator<< (ostream& os, const cmd_new_type_template& t)
+ const std::string
+ string () const
{
using type = cmd_new_type_template;
- switch (t)
+ switch (*this)
{
- case type::exe: return os << "executable";
- case type::lib: return os << "library";
- case type::bare: return os << "bare";
- case type::empty: return os << "empty";
+ case type::exe: return "executable";
+ case type::lib: return "library";
+ case type::bare: return "bare";
+ case type::empty: return "empty";
}
- return os;
+ return string (); // Should never reach.
+ }
+
+ friend ostream&
+ operator<< (ostream& os, const cmd_new_type_template& t)
+ {
+ return os << t.string ();
}
};
@@ -84,6 +90,20 @@ namespace bdep
// Default is C++ with no options.
//
cmd_new_lang_template (): lang (cxx) {}
+
+ const std::string
+ string () const
+ {
+ using lang = cmd_new_lang_template;
+
+ switch (*this)
+ {
+ case lang::c: return "c";
+ case lang::cxx: return "c++";
+ }
+
+ return string (); // Should never reach.
+ }
};
using cmd_new_lang = cmd_new_lang_template<>;
@@ -107,6 +127,20 @@ namespace bdep
// Default is git with no options.
//
cmd_new_vcs_template (): vcs (git) {}
+
+ const std::string
+ string () const
+ {
+ using vcs = cmd_new_vcs_template;
+
+ switch (*this)
+ {
+ case vcs::git: return "git";
+ case vcs::none: return "none";
+ }
+
+ return string (); // Should never reach.
+ }
};
using cmd_new_vcs = cmd_new_vcs_template<>;
diff --git a/bdep/new.cli b/bdep/new.cli
index 8f64e8f..1e206df 100644
--- a/bdep/new.cli
+++ b/bdep/new.cli
@@ -81,8 +81,8 @@ namespace bdep
$ bdep init -C @gcc cc config.cxx=g++
\
- After executing these commands the \c{hello} project will contain two
- packages, \c{libhello} and \c{hello}.
+ After executing these commands the \cb{hello} project will contain two
+ packages, \cb{libhello} and \cb{hello}.
The \cb{--subdirectory} form operates \i{as-if} by first creating
according to <spec> a temporary project called <name> and then copying
@@ -102,8 +102,8 @@ namespace bdep
$ bdep init -C @gcc cc config.cxx=g++
\
- After executing these commands the \c{hello} project will contain two
- source subdirectories, \c{libhello/} and \c{hello/}.
+ After executing these commands the \cb{hello} project will contain two
+ source subdirectories, \cb{libhello/} and \cb{hello/}.
The project parameters such as type (executable, library, etc), language,
and version control system can be customized as described next. Some of
@@ -265,6 +265,18 @@ namespace bdep
\li|\cb{none}
Don't initialize a version control system inside the project.||
+
+ The newly created project, package, or subdirectory can be further
+ customized using the post-creation hooks specified with the
+ \cb{--post-hook} option. The hook commands are executed in the
+ newly created project, package, or source directory as their
+ current working directory. For example:
+
+ \
+ $ bdep new --post-hook \"echo .idea/ >>.gitignore\" hello
+ \
+
+ See the \cb{--post-hook} option documentation below for details.
"
}
@@ -387,6 +399,52 @@ namespace bdep
system-specific."
}
+ strings --post-hook
+ {
+ "<command>",
+ "Run the specified command in the newly created project, package, or
+ source directory.
+
+ The <command> value is interpreted as a whitespace-separated,
+ potentially quoted command line consisting of the program optionally
+ followed by arguments and redirects. Specifically, a single level of
+ quotes (either single or double) is removed and whitespaces are not
+ treated as separators inside such quoted fragments. Currently only the
+ \cb{stdout} redirect to a file is supported. For example:
+
+ \
+ $ bdep new --post-hook \"echo '.idea/ # IDE' >>.gitignore\" hello
+ \
+
+ The command line elements (program, arguments, etc) may optionally
+ contain substitutions \- variable names enclosed with the \cb{@}
+ substitution symbol \- which are replaced with the corresponding
+ variable values to produce the actual command. The following variable
+ names are recognized with the double substitution symbol (\cb{@@})
+ serving as an escape sequence.
+
+ \
+ @mode@ - one of 'project', 'package', or 'subdirectory'
+ @name@ - project, package, or subdirectory name
+ @base@ - name base (name without extension)
+ @stem@ - name stem (name base without 'lib' prefix)
+ @type@ - type (--type|-t value: 'exe', 'lib', etc)
+ @lang@ - language (--lang|-l value: 'c', 'c++', etc)
+ @vcs@ - version control system (--vcs|-s value: 'git', etc)
+ @root@ - project/package root directory
+ \
+
+ For example:
+
+ \
+ $ bdep new --post-hook \"echo bin/ >>@name@/.gitignore\" hello
+ \
+
+ These substitution variables are also made available to the hook program
+ as the \cb{BDEP_NEW_*} environment variables (\cb{BDEP_NEW_MODE},
+ \cb{BDEP_NEW_NAME}, etc)."
+ }
+
// @@ This should be a no-amalgamation type sub-options.
//
bool --no-amalgamation
diff --git a/bdep/new.cxx b/bdep/new.cxx
index 7d1815c..55b6f8c 100644
--- a/bdep/new.cxx
+++ b/bdep/new.cxx
@@ -6,6 +6,7 @@
#include <algorithm> // replace()
+#include <libbutl/command.mxx>
#include <libbutl/project-name.mxx>
#include <bdep/project.hxx>
@@ -17,11 +18,10 @@
#include <bdep/config.hxx>
using namespace std;
+using namespace butl;
namespace bdep
{
- using butl::project_name;
-
using type = cmd_new_type;
using lang = cmd_new_lang;
using vcs = cmd_new_vcs;
@@ -1596,6 +1596,76 @@ namespace bdep
fail << "unable to write " << f << ": " << e;
}
+ // Run post-hooks.
+ //
+ optional<process_env> env;
+ optional<command_substitution_map> subs;
+ strings vars;
+
+ if (!o.post_hook ().empty ())
+ {
+ subs = command_substitution_map ();
+
+ auto add_var = [&subs, &vars] (string name, string value)
+ {
+ vars.push_back ("BDEP_NEW_" +
+ ucase (const_cast<const string&> (name)) +
+ '=' +
+ value);
+
+ (*subs)[move (name)] = move (value);
+ };
+
+ add_var ("mode", sub ? "subdirectory" : pkg ? "package" : "project");
+ add_var ("name", n);
+ add_var ("base", move (b));
+ add_var ("stem", move (s));
+ add_var ("type", t.string ());
+ add_var ("lang", l.string ());
+ add_var ("vcs", vc.string ());
+ add_var ("root", prj.string ());
+
+ env = process_env (process_path (), out, vars);
+ }
+
+ for (const string& cmd: o.post_hook ())
+ {
+ try
+ {
+ // Note: out directory path is absolute and normalized.
+ //
+ process_exit e (command_run (cmd,
+ env,
+ subs,
+ '@',
+ [] (const char* const args[], size_t n)
+ {
+ if (verb >= 2)
+ {
+ print_process (args, n);
+ }
+ }));
+
+ if (!e)
+ {
+ if (e.normal ())
+ throw failed (); // Assume the command issued diagnostics.
+
+ fail << "post hook '" << cmd << "' " << e;
+ }
+ }
+ catch (const invalid_argument& e)
+ {
+ fail << "invalid post hook '" << cmd << "': " << e;
+ }
+ // Handle process_error and io_error (both derive from system_error).
+ //
+ catch (const system_error& e)
+ {
+ fail << "unable to execute post hook '" << cmd << "': " << e;
+ }
+ }
+
if (verb)
text << "created new " << t << ' ' << (sub ? "source subdirectory" :
pkg ? "package" : "project")