aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-03-14 14:29:43 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-03-14 14:29:43 +0200
commitcc7216e60cd6893974e687599682c5e6233e9b69 (patch)
tree2304123805fda221d189034b2b85b3aac56055f4
parent6be9c7746f92aa721782a4d0eaff5f901fc528cd (diff)
Initial implementation of new command
-rw-r--r--bdep/init.cxx180
-rw-r--r--bdep/init.hxx21
-rw-r--r--bdep/new-types.hxx21
-rw-r--r--bdep/new.cxx317
-rw-r--r--bdep/project.cli30
-rw-r--r--bdep/utility.hxx10
-rw-r--r--bdep/utility.txx44
7 files changed, 528 insertions, 95 deletions
diff --git a/bdep/init.cxx b/bdep/init.cxx
index a86079f..f41a62b 100644
--- a/bdep/init.cxx
+++ b/bdep/init.cxx
@@ -16,6 +16,99 @@ using namespace std;
namespace bdep
{
+ shared_ptr<configuration>
+ cmd_init_config (const configuration_name_options& o,
+ const dir_path& prj,
+ database& db,
+ const dir_path& cfg,
+ bool ca, bool cc)
+ {
+ const char* m (!ca ? "--config-create" :
+ !cc ? "--config-add" :
+ nullptr);
+
+ if (m == nullptr)
+ fail << "both --config-add and --config-create specified";
+
+ optional<string> name;
+ if (size_t n = o.config_name ().size ())
+ {
+ if (n > 1)
+ fail << "multiple configuration names specified for " << m;
+
+ name = o.config_name ()[0];
+ }
+
+ optional<uint64_t> id;
+ if (size_t n = o.config_id ().size ())
+ {
+ if (n > 1)
+ fail << "multiple configuration ids specified for " << m;
+
+ id = o.config_id ()[0];
+ }
+
+ return ca
+ ? cmd_config_add (prj,
+ db,
+ cfg,
+ move (name),
+ nullopt /* default */, // @@ TODO: --[no]-default
+ move (id))
+ : nullptr; // @@ TODO: create
+ }
+
+ void
+ cmd_init (const common_options& o,
+ const dir_path& prj,
+ database& db,
+ const configurations& cfgs,
+ const package_locations& pkgs)
+ {
+ // We do each configuration in a separate transaction so that our state
+ // reflects the bpkg configuration as closely as possible.
+ //
+ for (const shared_ptr<configuration>& c: cfgs)
+ {
+ transaction t (db.begin ());
+
+ // Add project repository to the configuration. Note that we don't fetch
+ // it since sync is going to do it anyway.
+ //
+ run_bpkg (o,
+ "add",
+ "-d", c->path,
+ "--type", "dir",
+ prj);
+
+ for (const package_location& p: pkgs)
+ {
+ if (find_if (c->packages.begin (),
+ c->packages.end (),
+ [&p] (const package_state& s)
+ {
+ return p.name == s.name;
+ }) != c->packages.end ())
+ {
+ if (verb)
+ info << "package " << p.name << " is already initialized "
+ << "in configuration " << *c;
+
+ continue;
+ }
+
+ c->packages.push_back (package_state {p.name});
+ }
+
+ db.update (c);
+ t.commit ();
+
+ //@@ --no-sync for some reason?
+ //
+ cmd_sync (o, prj, c);
+ }
+ }
+
int
cmd_init (const cmd_init_options& o, cli::scanner&)
{
@@ -68,40 +161,14 @@ namespace bdep
configurations cfgs;
if (ca || cc)
{
- const char* m (!ca ? "--config-create" :
- !cc ? "--config-add" :
- nullptr);
-
- if (m == nullptr)
- fail << "both --config-add and --config-create specified";
-
- optional<string> name;
- if (size_t n = o.config_name ().size ())
- {
- if (n > 1)
- fail << "multiple configuration names specified for " << m;
-
- name = o.config_name ()[0];
- }
-
- optional<uint64_t> id;
- if (size_t n = o.config_id ().size ())
- {
- if (n > 1)
- fail << "multiple configuration ids specified for " << m;
-
- id = o.config_id ()[0];
- }
-
cfgs.push_back (
- ca
- ? cmd_config_add (prj,
- db,
- o.config_add (),
- move (name),
- nullopt /* default */, // @@ TODO: --[no]-default
- move (id))
- : nullptr); // @@ TODO: create
+ cmd_init_config (
+ o,
+ prj,
+ db,
+ ca ? o.config_add () : o.config_create (),
+ ca,
+ cc));
// Fall through.
}
@@ -116,52 +183,11 @@ namespace bdep
t.commit ();
}
- // Initialize each package in each configuration skipping those that are
- // already initialized. Do each configuration in a separate transaction so
- // that our state reflects the bpkg configuration as closely as possible.
- // Then synchronize each configuration.
+ // Initialize each package in each configuration.
//
- for (const shared_ptr<configuration>& c: cfgs)
- {
- transaction t (db.begin ());
-
- // Add project repository to the configuration. Note that we don't fetch
- // it since sync is going to do it anyway.
- //
- run_bpkg (o,
- "add",
- "-d", c->path,
- "--type", "dir",
- prj);
-
- for (const package_location& p: pp.packages)
- {
- if (find_if (c->packages.begin (),
- c->packages.end (),
- [&p] (const package_state& s)
- {
- return p.name == s.name;
- }) != c->packages.end ())
- {
- if (verb)
- info << "package " << p.name << " is already initialized "
- << "in configuration " << *c;
-
- continue;
- }
-
- c->packages.push_back (package_state {p.name});
- }
-
- db.update (c);
- t.commit ();
-
- //@@ --no-sync for some reason?
- //
- cmd_sync (o, prj, c);
- }
+ cmd_init (o, prj, db, cfgs, pp.packages);
- //@@ TODO: print project/package(s) being initialized.
+ //@@ TODO: print project/package(s) being initialized? (analog to new?)
return 0;
}
diff --git a/bdep/init.hxx b/bdep/init.hxx
index f9a5181..f3397ff 100644
--- a/bdep/init.hxx
+++ b/bdep/init.hxx
@@ -8,10 +8,31 @@
#include <bdep/types.hxx>
#include <bdep/utility.hxx>
+#include <bdep/project.hxx>
#include <bdep/init-options.hxx>
namespace bdep
{
+ // Handle --config-create/add.
+ //
+ shared_ptr<configuration>
+ cmd_init_config (const configuration_name_options&,
+ const dir_path& prj,
+ database&,
+ const dir_path& cfg,
+ bool config_add_specified,
+ bool config_create_specified);
+
+ // Initialize each package in each configuration skipping those that are
+ // already initialized. Then synchronize each configuration.
+ //
+ void
+ cmd_init (const common_options&,
+ const dir_path& prj,
+ database&,
+ const configurations&,
+ const package_locations&);
+
int
cmd_init (const cmd_init_options&, cli::scanner& args);
}
diff --git a/bdep/new-types.hxx b/bdep/new-types.hxx
index 2612f62..0b2a4c6 100644
--- a/bdep/new-types.hxx
+++ b/bdep/new-types.hxx
@@ -5,6 +5,8 @@
#ifndef BDEP_NEW_TYPES_HXX
#define BDEP_NEW_TYPES_HXX
+#include <bdep/types.hxx>
+
namespace bdep
{
// We could have defined cmd_new_*_options in a separate .cli file, include
@@ -22,7 +24,7 @@ namespace bdep
typename BARE = cmd_new_bare_options>
struct cmd_new_type_template
{
- enum type_type {exe, lib, bare} type;
+ enum type_type {exe = 0, lib, bare} type; // Note: used as index.
operator type_type () const {return type;}
@@ -36,6 +38,21 @@ namespace bdep
// Default is bare with no options.
//
cmd_new_type_template (): type (bare) {bare_opt = BARE ();}
+
+ friend ostream&
+ operator<< (ostream& os, const cmd_new_type_template& t)
+ {
+ using type = cmd_new_type_template;
+
+ switch (t)
+ {
+ case type::exe: return os << "executable";
+ case type::lib: return os << "library";
+ case type::bare: return os << "bare";
+ }
+
+ return os;
+ }
};
using cmd_new_type = cmd_new_type_template<>;
@@ -49,7 +66,7 @@ namespace bdep
typename CXX = cmd_new_cxx_options>
struct cmd_new_lang_template
{
- enum lang_type {c, cxx} lang;
+ enum lang_type {c = 0, cxx} lang; // Note: used as index.
operator lang_type () const {return lang;}
diff --git a/bdep/new.cxx b/bdep/new.cxx
index f2975c8..7d7b9ec 100644
--- a/bdep/new.cxx
+++ b/bdep/new.cxx
@@ -4,8 +4,12 @@
#include <bdep/new.hxx>
+#include <bdep/project.hxx>
+#include <bdep/database.hxx>
#include <bdep/diagnostics.hxx>
+#include <bdep/init.hxx>
+
using namespace std;
namespace bdep
@@ -18,7 +22,318 @@ namespace bdep
{
tracer trace ("new");
- //@@ TODO: validate options (cpp/cxx, -A/-C, etc).
+ // Validate type options.
+ //
+ const type& t (o.type ());
+
+ // Validate language options.
+ //
+ const lang& l (o.lang ());
+
+ switch (l)
+ {
+ case lang::c:
+ {
+ break;
+ }
+ case lang::cxx:
+ {
+ auto& o (l.cxx_opt);
+
+ if (o.cpp () && o.cxx ())
+ fail << "'cxx' and 'cpp' are mutually exclusive c++ options";
+
+ break;
+ }
+ }
+
+ // Validate argument.
+ //
+ string n (args.more () ? args.next () : "");
+ if (n.empty ())
+ fail << "project name argument expected";
+
+ //@@ TODO: verify valid package name (put the helper in libbpkg).
+
+ if (o.type () == type::lib && n.compare (0, 3, "lib") != 0)
+ fail << "library name does not start with 'lib'";
+
+ dir_path prj (n);
+ prj.complete ();
+
+ // If the directory already exists, make sure it is empty. Otherwise
+ // create it.
+ //
+ if (!exists (prj))
+ mk (prj);
+ else if (!empty (prj))
+ fail << "directory " << prj << " already exists";
+
+ // Initialize the git repository. Do it before writing anything ourselves
+ // in case it fails.
+ //
+ if (!o.no_git ())
+ run ("git", "init", "-q", prj);
+
+ path f; // File currently being written.
+ try
+ {
+ ofdstream os;
+
+ // manifest
+ //
+ os.open (f = prj / "manifest");
+ os << ": 1" << endl
+ << "name: " << n << endl
+ << "version: 0.1.0-a.0.z" << endl
+ << "summary: new " << t << " project" << endl
+ << "license: proprietary" << endl
+ << "url: https://example.org/" << n << endl
+ << "email: you@example.org" << endl
+ << "depends: * build2 >= 0.7.0-" << endl
+ << "depends: * bpkg >= 0.7.0-" << endl;
+ os.close ();
+
+ // build/
+ //
+ dir_path bd (dir_path (prj) /= "build");
+ mk (bd);
+
+ // build/bootstrap.build
+ //
+ os.open (f = bd / "bootstrap.build");
+ os << "project = " << n << endl
+ << endl
+ << "using version" << endl
+ << "using config" << endl
+ << "using test" << endl
+ << "using dist" << endl
+ << "using install" << endl;
+ os.close ();
+
+ // build/root.build
+ //
+ os.open (f = bd / "root.build");
+ switch (l)
+ {
+ case lang::c:
+ {
+ // @@ TODO: 'latest' in c.std.
+ //
+ os //<< "c.std = latest" << endl
+ //<< endl
+ << "using c" << endl
+ << endl
+ << "h{*}: extension = h" << endl
+ << "c{*}: extension = c" << endl
+ << endl
+ << "c.poptions =+ \"-I$out_root\" \"-I$src_root\"" << endl;
+ break;
+ }
+ case lang::cxx:
+ {
+ const char* s (l.cxx_opt.cpp () ? "pp" : "xx");
+
+ os << "cxx.std = latest" << endl
+ << endl
+ << "using cxx" << endl
+ << endl
+ << "hxx{*}: extension = h" << s << endl
+ << "ixx{*}: extension = i" << s << endl
+ << "txx{*}: extension = t" << s << endl
+ << "cxx{*}: extension = c" << s << endl
+ << endl
+ << "cxx.poptions =+ \"-I$out_root\" \"-I$src_root\"" << endl;
+ break;
+ }
+ }
+ os.close ();
+
+ // build/.gitignore
+ //
+ if (!o.no_git ())
+ {
+ os.open (f = bd / ".gitignore");
+ os << "config.build" << endl
+ << "bootstrap/out-root.build" << endl;
+ os.close ();
+ }
+
+ // buildfile
+ //
+ os.open (f = prj / "buildfile");
+ os << "./: {*/ -build/} file{manifest}" << endl;
+ os.close ();
+
+ // .gitignore
+ //
+ if (!o.no_git ())
+ {
+ os.open (f = prj / ".gitignore");
+ os << "# Compiler/linker output." << endl
+ << "#" << endl
+ << "*.d" << endl
+ << "*.t" << endl
+ << "*.i" << endl
+ << "*.ii" << endl
+ << "*.o" << endl
+ << "*.obj" << endl
+ << "*.so" << endl
+ << "*.dll" << endl
+ << "*.a" << endl
+ << "*.lib" << endl
+ << "*.exp" << endl
+ << "*.pdb" << endl
+ << "*.ilk" << endl
+ << "*.exe" << endl
+ << "*.exe.dlls/" << endl
+ << "*.exe.manifest" << endl
+ << "*.pc" << endl;
+ os.close ();
+ }
+
+ // <name>/ (source subdirectory).
+ //
+ dir_path sd (dir_path (prj) /= n);
+
+ if (t != type::bare)
+ {
+ mk (sd);
+ os.open (f = sd / "buildfile");
+ }
+
+ switch (t)
+ {
+ case type::exe:
+ {
+ switch (l)
+ {
+ case lang::c:
+ {
+ // buildfile
+ //
+ os << "exe{" << n << "}: {h c}{*}" << endl;
+ os.close ();
+
+ // <name>.c
+ //
+ os.open (f = sd / n + ".c");
+ os << "#include <stdio.h>" << endl
+ << endl
+ << "int main ()" << endl
+ << "{" << endl
+ << " printf (\"Hello, World!\\n\");" << endl
+ << " return 0;" << endl
+ << "}" << endl;
+ os.close ();
+ break;
+ }
+ case lang::cxx:
+ {
+ // buildfile
+ //
+ os << "exe{" << n << "}: {hxx ixx txx cxx}{*}" << endl;
+ os.close ();
+
+ const char* s (l.cxx_opt.cpp () ? "pp" : "xx");
+
+ // <name>.c(xx|pp)
+ //
+ os.open (f = sd / n + ".c" + s);
+ os << "#include <iostream>" << endl
+ << endl
+ << "int main ()" << endl
+ << "{" << endl
+ << " std::cout << \"Hello, World!\" << std::endl;" << endl
+ << "}" << endl;
+ os.close ();
+ break;
+ }
+ }
+ break;
+ }
+ case type::lib:
+ {
+ switch (l)
+ {
+ case lang::c:
+ {
+ // buildfile
+ //
+ os << "lib{" << n << "}: {h c}{*}" << endl;
+ os.close ();
+
+ //@@ TODO
+
+ break;
+ }
+ case lang::cxx:
+ {
+ // buildfile
+ //
+ os << "lib{" << n << "}: {hxx ixx txx cxx}{*}" << endl;
+ os.close ();
+
+ //@@ TODO
+
+ break;
+ }
+ }
+ break;
+ }
+ case type::bare:
+ {
+ break;
+ }
+ }
+ }
+ catch (const io_error& e)
+ {
+ fail << "unable to write " << f << ": " << e;
+ }
+
+ if (verb)
+ text << "created new " << t << " project " << n << " in " << prj;
+
+ // --no-init
+ //
+ bool ca (o.config_add_specified ());
+ bool cc (o.config_create_specified ());
+
+ if (o.no_init ())
+ {
+ if (ca) fail << "both --no-init and --config-add specified";
+ if (cc) fail << "both --no-init and --config-create specified";
+
+ return 0;
+ }
+
+ // Create .bdep/.
+ //
+ {
+ dir_path d (prj / bdep_dir);
+ mk (prj / bdep_dir);
+ }
+
+ // Everything else requires a database.
+ //
+ database db (open (prj, trace, true /* create */));
+
+ if (ca || cc)
+ {
+ configurations cfgs {
+ cmd_init_config (
+ o,
+ prj,
+ db,
+ ca ? o.config_add () : o.config_create (),
+ ca,
+ cc)};
+
+ package_locations pkgs {{n, dir_path ()}}; // project == package
+
+ cmd_init (o, prj, db, cfgs, pkgs);
+ }
return 0;
}
diff --git a/bdep/project.cli b/bdep/project.cli
index 7680d99..c3f2e29 100644
--- a/bdep/project.cli
+++ b/bdep/project.cli
@@ -8,10 +8,16 @@ include <bdep/common.cli>;
namespace bdep
{
- // Common options for commands that accept @<cfg-name>.
+ // Common options for commands that accept --config-id and @<cfg-name>.
//
class configuration_name_options: common_options
{
+ vector<uint64_t> --config-id
+ {
+ "<num>",
+ "Specify the build configuration as an id."
+ };
+
// Storage for configuration names specified as @<cfg-name>.
//
// Note that we leave it undocumented so that it's not mentioned in
@@ -25,28 +31,22 @@ namespace bdep
//
class project_options: configuration_name_options
{
- bool --all|-a
- {
- "Use all build configurations."
- }
-
- dir_paths --config|-c
+ dir_paths --directory|-d
{
"<dir>",
- "Specify the build configuration to use as a directory."
+ "Assume project/package is in the specified directory rather than in the
+ current working directory."
}
- vector<uint64_t> --config-id
+ bool --all|-a
{
- "<num>",
- "Specify the build configuration to use as an id."
- };
+ "Use all build configurations."
+ }
- dir_paths --directory|-d
+ dir_paths --config|-c
{
"<dir>",
- "Assume project/package is in the specified directory rather than in the
- current working directory."
+ "Specify the build configuration as a directory."
}
};
}
diff --git a/bdep/utility.hxx b/bdep/utility.hxx
index d8a4983..f3e2c73 100644
--- a/bdep/utility.hxx
+++ b/bdep/utility.hxx
@@ -88,6 +88,16 @@ namespace bdep
void
rm (const path&, uint16_t verbosity = 3);
+ // Run a process.
+ //
+ template <typename I, typename O, typename E, typename P, typename... A>
+ process
+ start (I&& in, O&& out, E&& err, const P& prog, A&&... args);
+
+ template <typename P, typename... A>
+ void
+ run (const P& prog, A&&... args);
+
// Run the bpkg process.
//
class common_options;
diff --git a/bdep/utility.txx b/bdep/utility.txx
index b796f69..9e94196 100644
--- a/bdep/utility.txx
+++ b/bdep/utility.txx
@@ -12,6 +12,50 @@
namespace bdep
{
+ template <typename I, typename O, typename E, typename P, typename... A>
+ process
+ start (I&& in, O&& out, E&& err, const P& prog, A&&... args)
+ {
+ try
+ {
+ return process_start_callback (
+ [] (const char* const args[], size_t n)
+ {
+ if (verb >= 2)
+ print_process (args, n);
+ },
+ forward<I> (in),
+ forward<O> (out),
+ forward<E> (err),
+ prog,
+ forward<A> (args)...);
+ }
+ catch (const process_error& e)
+ {
+ fail << "unable to execute " << prog << ": " << e << endf;
+ }
+ }
+
+ template <typename P, typename... A>
+ void
+ run (const P& prog, A&&... args)
+ {
+ process pr (start (0 /* stdin */,
+ 1 /* stdout */,
+ 2 /* stderr */,
+ prog,
+ forward<A> (args)...));
+ if (!pr.wait ())
+ {
+ const process_exit& e (*pr.exit);
+
+ if (e.normal ())
+ throw failed (); // Assume the child issued diagnostics.
+
+ fail << "process " << prog << " " << e;
+ }
+ }
+
// *_bpkg()
//
template <typename O, typename E, typename... A>