aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-04-01 16:46:03 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-04-01 16:46:03 +0200
commita133e7b03bd67c992cfb240bd300967ffab31ba2 (patch)
tree02c54f4c9b7f48aeb5230e230a4bb00bb1609c2c
parent2ae123ce8e8a874ada7e8c776abfc0742d862277 (diff)
Setup build infra
-rw-r--r--.gitignore13
-rw-r--r--INSTALL6
-rw-r--r--LICENSE20
-rw-r--r--NEWS0
-rw-r--r--README25
-rw-r--r--bbot/.gitignore3
-rw-r--r--bbot/agent.cli42
-rw-r--r--bbot/agent.cxx102
-rw-r--r--bbot/bbot-version81
-rw-r--r--bbot/buildfile39
-rw-r--r--bbot/common.cli9
-rw-r--r--bbot/diagnostics196
-rw-r--r--bbot/diagnostics.cxx47
-rw-r--r--bbot/types97
-rw-r--r--bbot/types-parsers38
-rw-r--r--bbot/types-parsers.cxx51
-rw-r--r--bbot/utility42
-rw-r--r--bbot/utility.cxx14
-rw-r--r--build/.gitignore1
-rw-r--r--build/bootstrap.build20
-rw-r--r--build/root.build26
-rw-r--r--buildfile10
-rw-r--r--manifest17
-rw-r--r--version1
24 files changed, 900 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..01994ef
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+# Compiler/linker output.
+#
+*.d
+*.o
+*.obj
+*.so
+*.dll
+*.a
+*.lib
+*.exp
+*.exe
+*.exe.dlls/
+*.exe.manifest
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..680e976
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,6 @@
+The easiest way to build this package is with the bpkg package manager:
+
+$ bpkg build bbot
+
+But if you don't want to use the package manager, then you can also build it
+manually using the standard build2 build system.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..91c0877
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2014-2017 Code Synthesis Ltd
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..a280118
--- /dev/null
+++ b/README
@@ -0,0 +1,25 @@
+This package contains the build2 build bot.
+
+build2 is an open source, cross-platform toolchain for building and packaging
+C++ code. Its aim is a modern build system and package manager for the C++
+language that provide a consistent, out of the box interface across multiple
+platforms and compilers. For more information see:
+
+https://build2.org/
+
+This library defines the types and utilities for working with build2 build
+tasks. In particular, it provides C++ classes as well as the parser and
+serializer implementations that can be used to read, manipulate, and write
+machine, task, result, task request/response and result request manifests.
+
+See the NEWS file for the user-visible changes from the previous release.
+
+See the LICENSE file for the distribution conditions.
+
+See the INSTALL file for the prerequisites and installation instructions.
+
+See the doc/ directory for documentation.
+
+Send questions, bug reports, or any other feedback to the users@build2.org
+mailing list. You can post without subscribing. See https://lists.build2.org
+for searchable archives, posting guidelines, etc.
diff --git a/bbot/.gitignore b/bbot/.gitignore
new file mode 100644
index 0000000..579654d
--- /dev/null
+++ b/bbot/.gitignore
@@ -0,0 +1,3 @@
+*-options
+*-options.?xx
+bbot-agent
diff --git a/bbot/agent.cli b/bbot/agent.cli
new file mode 100644
index 0000000..a52579f
--- /dev/null
+++ b/bbot/agent.cli
@@ -0,0 +1,42 @@
+// file : bbot/agent.cli
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+include <bbot/common.cli>;
+
+"\section=1"
+"\name=bbot-agent"
+"\summary=build bot agent"
+
+namespace bbot
+{
+ {
+ "<options> <file>",
+
+ "
+ \h|SYNOPSIS|
+
+ \cb{bbot-agent --help}\n
+ \cb{bbot-agent --version}\n
+ \c{\b{bbot-agent} [<options>] <toolchain>}
+
+ \h|DESCRIPTION|
+
+ \cb{bbot-agent} @@ TODO.
+ "
+ }
+
+ class agent_options
+ {
+ "\h|OPTIONS|"
+
+ bool --help {"Print usage information and exit."}
+ bool --version {"Print version and exit."}
+ };
+
+ "
+ \h|EXIT STATUS|
+
+ Non-zero exit status is returned in case of an error.
+ "
+}
diff --git a/bbot/agent.cxx b/bbot/agent.cxx
new file mode 100644
index 0000000..54940f4
--- /dev/null
+++ b/bbot/agent.cxx
@@ -0,0 +1,102 @@
+// file : bbot/agent.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef _WIN32
+# include <signal.h> // signal()
+#else
+# include <stdlib.h> // getenv(), _putenv()
+#endif
+
+#include <iostream>
+
+#include <butl/pager>
+
+#include <bbot/types>
+#include <bbot/utility>
+
+#include <bbot/diagnostics>
+#include <bbot/bbot-version>
+
+#include <bbot/agent-options>
+
+using namespace std;
+using namespace butl;
+using namespace bbot;
+
+int
+main (int argc, char* argv[])
+try
+{
+ // This is a little hack to make out baseutils for Windows work when called
+ // with absolute path. In a nutshell, MSYS2's exec*p() doesn't search in the
+ // parent's executable directory, only in PATH. And since we are running
+ // without a shell (that would read /etc/profile which sets PATH to some
+ // sensible values), we are only getting Win32 PATH values. And MSYS2 /bin
+ // is not one of them. So what we are going to do is add /bin at the end of
+ // PATH (which will be passed as is by the MSYS2 machinery). This will make
+ // MSYS2 search in /bin (where our baseutils live). And for everyone else
+ // this should be harmless since it is not a valid Win32 path.
+ //
+#ifdef _WIN32
+ {
+ string mp ("PATH=");
+ if (const char* p = getenv ("PATH"))
+ {
+ mp += p;
+ mp += ';';
+ }
+ mp += "/bin";
+
+ _putenv (mp.c_str ());
+ }
+#endif
+
+ // On POSIX ignore SIGPIPE which is signaled to a pipe-writing process if
+ // the pipe reading end is closed. Note that by default this signal
+ // terminates a process. Also note that there is no way to disable this
+ // behavior on a file descriptor basis or for the write() function call.
+ //
+#ifndef _WIN32
+ if (signal (SIGPIPE, SIG_IGN) == SIG_ERR)
+ fail << "unable to ignore broken pipe (SIGPIPE) signal: "
+ << system_error (errno, generic_category ()); // Sanitize.
+#endif
+
+ cli::argv_scanner scan (argc, argv, true);
+ agent_options ops (scan);
+
+ // Version.
+ //
+ if (ops.version ())
+ {
+ cout << "bbot-agent " << BBOT_VERSION_STR << endl
+ << "libbbot " << LIBBBOT_VERSION_STR << endl
+ << "libbutl " << LIBBUTL_VERSION_STR << endl
+ << "Copyright (c) 2014-2017 Code Synthesis Ltd" << endl
+ << "MIT; see accompanying LICENSE file" << endl;
+
+ return 0;
+ }
+
+ // Help.
+ //
+ if (ops.help ())
+ {
+ pager p ("bbot-agent help", false);
+ print_bbot_agent_usage (p.stream ());
+
+ // If the pager failed, assume it has issued some diagnostics.
+ //
+ return p.wait () ? 0 : 1;
+ }
+}
+catch (const failed&)
+{
+ return 1; // Diagnostics has already been issued.
+}
+catch (const cli::exception& e)
+{
+ error << e;
+ return 1;
+}
diff --git a/bbot/bbot-version b/bbot/bbot-version
new file mode 100644
index 0000000..84dc85d
--- /dev/null
+++ b/bbot/bbot-version
@@ -0,0 +1,81 @@
+// file : bbot/bbot-version -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BBOT_VERSION // Note: using the version macro itself.
+
+#include <butl/version> // LIBBUTL_VERSION
+#include <bbot/version> // LIBBBOT_VERSION
+
+// Version format is AABBCCDD where
+//
+// AA - major version number
+// BB - minor version number
+// CC - bugfix version number
+// DD - alpha / beta (DD + 50) version number
+//
+// When DD is not 00, 1 is subtracted from AABBCC. For example:
+//
+// Version AABBCCDD
+// 2.0.0 02000000
+// 2.1.0 02010000
+// 2.1.1 02010100
+// 2.2.0-a1 02019901
+// 3.0.0-b2 02999952
+//
+#define BBOT_VERSION 49901
+#define BBOT_VERSION_STR "0.5.0-a1"
+
+// Generally, we expect minor versions to be source code backwards-
+// compatible, thought we might have a minimum version requirement.
+//
+// Note: does not apply during early development.
+//
+#if LIBBUTL_VERSION != 49901
+# error incompatible libbutl version
+#endif
+
+#if LIBBBOT_VERSION != 49901
+# error incompatible libbbot version
+#endif
+
+// User agent.
+//
+#if defined(_WIN32)
+# if defined(__MINGW32__)
+# define BBOT_OS "MinGW"
+# else
+# define BBOT_OS "Windows"
+# endif
+#elif defined(__linux)
+# define BBOT_OS "GNU/Linux"
+#elif defined(__APPLE__)
+# define BBOT_OS "MacOS"
+#elif defined(__CYGWIN__)
+# define BBOT_OS "Cygwin"
+#elif defined(__FreeBSD__)
+# define BBOT_OS "FreeBSD"
+#elif defined(__OpenBSD__)
+# define BBOT_OS "OpenBSD"
+#elif defined(__NetBSD__)
+# define BBOT_OS "NetBSD"
+#elif defined(__sun)
+# define BBOT_OS "Solaris"
+#elif defined(__hpux)
+# define BBOT_OS "HP-UX"
+#elif defined(_AIX)
+# define BBOT_OS "AIX"
+#elif defined(__unix)
+# define BBOT_OS "Unix"
+#elif defined(__posix)
+# define BBOT_OS "Posix"
+#else
+# define BBOT_OS "Other"
+#endif
+
+#define BBOT_USER_AGENT \
+ "bbot/" BBOT_VERSION_STR " (" BBOT_OS "; +https://build2.org)" \
+ " libbbot/" LIBBBOT_VERSION_STR \
+ " libbutl/" LIBBUTL_VERSION_STR
+
+#endif // BBOT_VERSION
diff --git a/bbot/buildfile b/bbot/buildfile
new file mode 100644
index 0000000..1f48062
--- /dev/null
+++ b/bbot/buildfile
@@ -0,0 +1,39 @@
+# file : bbot/buildfile
+# copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+# license : MIT; see accompanying LICENSE file
+
+import libs = libbutl%lib{butl}
+import libs += libbbot%lib{bbot}
+
+exe{bbot-agent}: \
+{ cxx}{ agent } {hxx ixx cxx}{ agent-options } \
+{hxx }{ bbot-version } \
+ {hxx ixx cxx}{ common-options } \
+{hxx cxx}{ diagnostics } \
+{hxx }{ types } \
+{hxx cxx}{ types-parsers } \
+{hxx cxx}{ utility } \
+ $libs
+
+# Generated options parser.
+#
+if $cli.configured
+{
+ cli.cxx{common-options}: cli{common}
+ cli.cxx{agent-options}: cli{agent}
+
+ cli.options += -I $src_root --include-with-brackets --include-prefix bbot \
+--guard-prefix BBOT --cxx-prologue "#include <bbot/types-parsers>" \
+--cli-namespace bbot::cli --generate-specifier
+
+ cli.cxx{common-options}: cli.options = $cli.options # No usage.
+
+ # Usage options.
+ #
+ cli.options += --suppress-undocumented --long-usage --ansi-color \
+--page-usage 'bbot::print_$name$_' --option-length 20
+
+ # Include generated cli files into the distribution.
+ #
+ cli.cxx{*}: dist = true
+}
diff --git a/bbot/common.cli b/bbot/common.cli
new file mode 100644
index 0000000..3b9f5bd
--- /dev/null
+++ b/bbot/common.cli
@@ -0,0 +1,9 @@
+// file : bbot/common.cli
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+include <bbot/types>;
+
+namespace bbot
+{
+}
diff --git a/bbot/diagnostics b/bbot/diagnostics
new file mode 100644
index 0000000..c849aae
--- /dev/null
+++ b/bbot/diagnostics
@@ -0,0 +1,196 @@
+// file : bbot/diagnostics -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BBOT_DIAGNOSTICS
+#define BBOT_DIAGNOSTICS
+
+#include <butl/diagnostics>
+
+#include <bbot/types>
+#include <bbot/utility>
+
+namespace bbot
+{
+ using butl::diag_record;
+
+ // Throw this exception to terminate the process. The handler should
+ // assume that the diagnostics has already been issued.
+ //
+ class failed: public std::exception {};
+
+ // Verbosity level. Update documentation for --verbose if changing.
+ //
+ // 0 - disabled
+ // 1 - high-level information messages
+ // 2 - essential underlying commands that are being executed
+ // 3 - all underlying commands that are being executed
+ // 4 - information that could be helpful to the user
+ // 5 - information that could be helpful to the developer
+ // 6 - even more detailed information
+ //
+ // While uint8 is more than enough, use uint16 for the ease of printing.
+ //
+ extern uint16_t verb;
+
+ template <typename F> inline void l1 (const F& f) {if (verb >= 1) f ();}
+ template <typename F> inline void l2 (const F& f) {if (verb >= 2) f ();}
+ template <typename F> inline void l3 (const F& f) {if (verb >= 3) f ();}
+ template <typename F> inline void l4 (const F& f) {if (verb >= 4) f ();}
+ template <typename F> inline void l5 (const F& f) {if (verb >= 5) f ();}
+ template <typename F> inline void l6 (const F& f) {if (verb >= 6) f ();}
+
+ // Diagnostic facility, base infrastructure.
+ //
+ using butl::diag_stream;
+ using butl::diag_epilogue;
+
+ // Diagnostic facility, project specifics.
+ //
+ struct simple_prologue_base
+ {
+ explicit
+ simple_prologue_base (const char* type, const char* name)
+ : type_ (type), name_ (name) {}
+
+ void
+ operator() (const diag_record& r) const;
+
+ private:
+ const char* type_;
+ const char* name_;
+ };
+
+ class location
+ {
+ public:
+ location () {}
+ location (string f, uint64_t l, uint64_t c)
+ : file (move (f)), line (l), column (c) {}
+
+ string file;
+ uint64_t line;
+ uint64_t column;
+ };
+
+ struct location_prologue_base
+ {
+ location_prologue_base (const char* type,
+ const char* name,
+ const location& l)
+ : type_ (type), name_ (name), loc_ (l) {}
+
+ void
+ operator() (const diag_record& r) const;
+
+ private:
+ const char* type_;
+ const char* name_;
+ const location loc_;
+ };
+
+ struct basic_mark_base
+ {
+ using simple_prologue = butl::diag_prologue<simple_prologue_base>;
+ using location_prologue = butl::diag_prologue<location_prologue_base>;
+
+ explicit
+ basic_mark_base (const char* type,
+ const char* name = nullptr,
+ const void* data = nullptr,
+ diag_epilogue* epilogue = nullptr)
+ : type_ (type), name_ (name), data_ (data), epilogue_ (epilogue) {}
+
+ simple_prologue
+ operator() () const
+ {
+ return simple_prologue (epilogue_, type_, name_);
+ }
+
+ location_prologue
+ operator() (const location& l) const
+ {
+ return location_prologue (epilogue_, type_, name_, l);
+ }
+
+ template <typename L>
+ location_prologue
+ operator() (const L& l) const
+ {
+ return location_prologue (
+ epilogue_, type_, name_, get_location (l, data_));
+ }
+
+ template <typename F, typename L, typename C>
+ location_prologue
+ operator() (F&& f, L&& l, C&& c) const
+ {
+ return location_prologue (
+ epilogue_,
+ type_,
+ name_,
+ location (forward<F> (f), forward<L> (l), forward<C> (c)));
+ }
+
+ protected:
+ const char* type_;
+ const char* name_;
+ const void* data_;
+ diag_epilogue* const epilogue_;
+ };
+ using basic_mark = butl::diag_mark<basic_mark_base>;
+
+ extern const basic_mark error;
+ extern const basic_mark warn;
+ extern const basic_mark info;
+ extern const basic_mark text;
+
+ // trace
+ //
+ struct trace_mark_base: basic_mark_base
+ {
+ explicit
+ trace_mark_base (const char* name, const void* data = nullptr)
+ : basic_mark_base ("trace", name, data) {}
+ };
+ using trace_mark = butl::diag_mark<trace_mark_base>;
+ using tracer = trace_mark;
+
+ // fail
+ //
+ struct fail_mark_base: basic_mark_base
+ {
+ explicit
+ fail_mark_base (const char* type,
+ const void* data = nullptr)
+ : basic_mark_base (type,
+ nullptr,
+ data,
+ [](const diag_record& r)
+ {
+ r.flush ();
+ throw failed ();
+ }) {}
+ };
+
+ using fail_mark = butl::diag_mark<fail_mark_base>;
+
+ struct fail_end_base
+ {
+ [[noreturn]] void
+ operator() (const diag_record& r) const
+ {
+ // If we just throw then the record's destructor will see an active
+ // exception and will not flush the record.
+ //
+ r.flush ();
+ throw failed ();
+ }
+ };
+ using fail_end = butl::diag_noreturn_end<fail_end_base>;
+
+ extern const fail_mark fail;
+ extern const fail_end endf;
+}
+
+#endif // BBOT_DIAGNOSTICS
diff --git a/bbot/diagnostics.cxx b/bbot/diagnostics.cxx
new file mode 100644
index 0000000..1aa58f0
--- /dev/null
+++ b/bbot/diagnostics.cxx
@@ -0,0 +1,47 @@
+// file : bbot/diagnostics.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <bbot/diagnostics>
+
+using namespace std;
+using namespace butl;
+
+namespace bbot
+{
+ // Diagnostics verbosity level.
+ //
+ uint16_t verb;
+
+ // Diagnostic facility, project specifics.
+ //
+
+ void simple_prologue_base::
+ operator() (const diag_record& r) const
+ {
+ if (type_ != nullptr)
+ r << type_ << ": ";
+
+ if (name_ != nullptr)
+ r << name_ << ": ";
+ }
+
+ void location_prologue_base::
+ operator() (const diag_record& r) const
+ {
+ r << loc_.file << ':' << loc_.line << ':' << loc_.column << ": ";
+
+ if (type_ != nullptr)
+ r << type_ << ": ";
+
+ if (name_ != nullptr)
+ r << name_ << ": ";
+ }
+
+ const basic_mark error ("error");
+ const basic_mark warn ("warning");
+ const basic_mark info ("info");
+ const basic_mark text (nullptr);
+ const fail_mark fail ("error");
+ const fail_end endf;
+}
diff --git a/bbot/types b/bbot/types
new file mode 100644
index 0000000..bd052aa
--- /dev/null
+++ b/bbot/types
@@ -0,0 +1,97 @@
+// file : bbot/types -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BBOT_TYPES
+#define BBOT_TYPES
+
+#include <vector>
+#include <string>
+#include <memory> // unique_ptr, shared_ptr
+#include <utility> // pair
+#include <cstddef> // size_t, nullptr_t
+#include <cstdint> // uint{8,16,32,64}_t
+#include <istream>
+#include <ostream>
+#include <functional> // function, reference_wrapper
+
+#include <ios> // ios_base::failure
+#include <exception> // exception
+#include <stdexcept> // logic_error, invalid_argument, runtime_error
+#include <system_error>
+
+#include <butl/path>
+#include <butl/optional>
+
+namespace bbot
+{
+ // Commonly-used types.
+ //
+ using std::uint8_t;
+ using std::uint16_t;
+ using std::uint32_t;
+ using std::uint64_t;
+
+ using std::size_t;
+ using std::nullptr_t;
+
+ using std::pair;
+ using std::string;
+ using std::function;
+ using std::reference_wrapper;
+
+ using std::unique_ptr;
+ using std::shared_ptr;
+ using std::weak_ptr;
+
+ using std::vector;
+
+ using strings = vector<string>;
+ using cstrings = vector<const char*>;
+
+ using std::istream;
+ using std::ostream;
+
+ // Exceptions. While <exception> is included, there is no using for
+ // std::exception -- use qualified.
+ //
+ using std::logic_error;
+ using std::invalid_argument;
+ using std::runtime_error;
+ using std::system_error;
+ using io_error = std::ios_base::failure;
+
+ // <butl/optional>
+ //
+ using butl::optional;
+ using butl::nullopt;
+
+ // <butl/path>
+ //
+ using butl::path;
+ using butl::dir_path;
+ using butl::basic_path;
+ using butl::invalid_path;
+
+ using paths = std::vector<path>;
+ using dir_paths = std::vector<dir_path>;
+}
+
+// In order to be found (via ADL) these have to be either in std:: or in
+// butl::. The latter is bad idea since libbutl includes the default
+// implementation.
+//
+namespace std
+{
+ // Custom path printing (canonicalized, with trailing slash for directories).
+ //
+ inline ostream&
+ operator<< (ostream& os, const ::butl::path& p)
+ {
+ string r (p.representation ());
+ ::butl::path::traits::canonicalize (r);
+ return os << r;
+ }
+}
+
+#endif // BBOT_TYPES
diff --git a/bbot/types-parsers b/bbot/types-parsers
new file mode 100644
index 0000000..1cb78f7
--- /dev/null
+++ b/bbot/types-parsers
@@ -0,0 +1,38 @@
+// file : bbot/types-parsers -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+// CLI parsers, included into the generated source files.
+//
+
+#ifndef BBOT_TYPES_PARSERS
+#define BBOT_TYPES_PARSERS
+
+#include <bbot/types>
+
+namespace bbot
+{
+ namespace cli
+ {
+ class scanner;
+
+ template <typename T>
+ struct parser;
+
+ template <>
+ struct parser<path>
+ {
+ static void
+ parse (path&, bool&, scanner&);
+ };
+
+ template <>
+ struct parser<dir_path>
+ {
+ static void
+ parse (dir_path&, bool&, scanner&);
+ };
+ }
+}
+
+#endif // BBOT_TYPES_PARSERS
diff --git a/bbot/types-parsers.cxx b/bbot/types-parsers.cxx
new file mode 100644
index 0000000..6a0e899
--- /dev/null
+++ b/bbot/types-parsers.cxx
@@ -0,0 +1,51 @@
+// file : bbot/types-parsers.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <bbot/types-parsers>
+
+#include <bbot/common-options> // bbot::cli namespace
+
+namespace bbot
+{
+ namespace cli
+ {
+ template <typename T>
+ static void
+ parse_path (T& x, scanner& s)
+ {
+ const char* o (s.next ());
+
+ if (!s.more ())
+ throw missing_value (o);
+
+ const char* v (s.next ());
+
+ try
+ {
+ x = T (v);
+
+ if (x.empty ())
+ throw invalid_value (o, v);
+ }
+ catch (const invalid_path&)
+ {
+ throw invalid_value (o, v);
+ }
+ }
+
+ void parser<path>::
+ parse (path& x, bool& xs, scanner& s)
+ {
+ xs = true;
+ parse_path (x, s);
+ }
+
+ void parser<dir_path>::
+ parse (dir_path& x, bool& xs, scanner& s)
+ {
+ xs = true;
+ parse_path (x, s);
+ }
+ }
+}
diff --git a/bbot/utility b/bbot/utility
new file mode 100644
index 0000000..05e90c7
--- /dev/null
+++ b/bbot/utility
@@ -0,0 +1,42 @@
+// file : bbot/utility -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BBOT_UTILITY
+#define BBOT_UTILITY
+
+#include <memory> // make_shared()
+#include <string> // to_string()
+#include <utility> // move(), forward(), declval(), make_pair()
+#include <cassert> // assert()
+#include <iterator> // make_move_iterator()
+
+#include <butl/ft/lang>
+
+#include <butl/utility> // casecmp(), reverse_iterate(), etc
+
+#include <butl/filesystem>
+
+#include <bbot/types>
+
+namespace bbot
+{
+ using std::move;
+ using std::forward;
+ using std::declval;
+
+ using std::make_pair;
+ using std::make_shared;
+ using std::make_move_iterator;
+ using std::to_string;
+
+ // <butl/utility>
+ //
+ using butl::casecmp;
+ using butl::reverse_iterate;
+
+ using butl::exception_guard;
+ using butl::make_exception_guard;
+}
+
+#endif // BBOT_UTILITY
diff --git a/bbot/utility.cxx b/bbot/utility.cxx
new file mode 100644
index 0000000..591ff52
--- /dev/null
+++ b/bbot/utility.cxx
@@ -0,0 +1,14 @@
+// file : bbot/utility.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <bbot/utility>
+
+#include <bbot/diagnostics>
+
+using namespace std;
+using namespace butl;
+
+namespace bbot
+{
+}
diff --git a/build/.gitignore b/build/.gitignore
new file mode 100644
index 0000000..225c27f
--- /dev/null
+++ b/build/.gitignore
@@ -0,0 +1 @@
+config.build
diff --git a/build/bootstrap.build b/build/bootstrap.build
new file mode 100644
index 0000000..26f9872
--- /dev/null
+++ b/build/bootstrap.build
@@ -0,0 +1,20 @@
+# file : build/bootstrap.build
+# copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+# license : MIT; see accompanying LICENSE file
+
+project = bbot
+
+using build@0.4.0
+
+version = 0.5.0-a1
+revision = 0
+
+dist.package = $project-$version
+
+if ($revision != 0)
+ dist.package += +$revision
+
+using config
+using dist
+using test
+using install
diff --git a/build/root.build b/build/root.build
new file mode 100644
index 0000000..f19d700
--- /dev/null
+++ b/build/root.build
@@ -0,0 +1,26 @@
+# file : build/root.build
+# copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+# license : MIT; see accompanying LICENSE file
+
+cxx.std = latest
+
+using cxx
+
+hxx{*}: extension =
+ixx{*}: extension = ixx
+txx{*}: extension = txx
+cxx{*}: extension = cxx
+
+cxx.poptions =+ "-I$out_root" "-I$src_root"
+
+# Load the cli module but only if it's available. This way a distribution
+# that includes pre-generated files can be built without installing cli.
+# This is also the reason why we need to explicitly spell out individual
+# source file prerequisites instead of using the cli.cxx{} group (it won't
+# be there unless the module is configured).
+#
+using? cli
+
+# All exe{} in tests/ are, well, tests.
+#
+tests/exe{*}: test = true
diff --git a/buildfile b/buildfile
new file mode 100644
index 0000000..b825c0a
--- /dev/null
+++ b/buildfile
@@ -0,0 +1,10 @@
+# file : buildfile
+# copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+# license : MIT; see accompanying LICENSE file
+
+./: bbot/ doc{INSTALL LICENSE NEWS README version} file{manifest}
+
+# Don't install tests or the INSTALL file.
+#
+dir{tests/}: install = false
+doc{INSTALL}@./: install = false
diff --git a/manifest b/manifest
new file mode 100644
index 0000000..45c54c5
--- /dev/null
+++ b/manifest
@@ -0,0 +1,17 @@
+: 1
+name: bbot
+version: 0.5.0-a1
+summary: build2 build bot
+license: MIT
+tags: build2, c++, build, bot, server, ci, continuous, integration, testing
+description-file: README
+changes-file: NEWS
+url: https://build2.org
+email: users@build2.org
+requires: c++14
+depends: * build2 >= 0.4.0
+depends: * bpkg >= 0.4.0
+# @@ Should probably become conditional dependency.
+requires: ? cli ; Only required if changing .cli files.
+depends: libbutl == 0.5.0-a1
+depends: libbbot == 0.5.0-a1
diff --git a/version b/version
new file mode 100644
index 0000000..d1f4eb1
--- /dev/null
+++ b/version
@@ -0,0 +1 @@
+0.5.0-a1