aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-03-08 18:06:26 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-03-08 18:06:26 +0200
commitdf5e58e6e5eb2727a185bf9a98a462c18fa3a83d (patch)
treefb0cc76643865390ac3e45462d51ea02575a3175
parentf9ebe2d1e920df001be2dd543a63677f8728f53d (diff)
Setup project database infrastructure
-rw-r--r--bdep/.gitignore1
-rw-r--r--bdep/bdep.cxx8
-rw-r--r--bdep/buildfile34
-rw-r--r--bdep/config.cli4
-rw-r--r--bdep/configuration.cli35
-rw-r--r--bdep/database.cxx88
-rw-r--r--bdep/database.hxx82
-rw-r--r--bdep/diagnostics.cxx25
-rw-r--r--bdep/diagnostics.hxx18
-rw-r--r--bdep/init.cli4
-rwxr-xr-xbdep/odb.sh18
-rw-r--r--bdep/project.cli20
-rw-r--r--bdep/project.hxx37
-rw-r--r--bdep/project.xml11
-rw-r--r--bdep/utility.cxx2
-rw-r--r--bdep/utility.hxx2
-rw-r--r--bdep/version.hxx.in8
-rw-r--r--bdep/wrapper-traits.hxx59
-rw-r--r--manifest2
19 files changed, 404 insertions, 54 deletions
diff --git a/bdep/.gitignore b/bdep/.gitignore
index 15d9eb3..02a0554 100644
--- a/bdep/.gitignore
+++ b/bdep/.gitignore
@@ -1,3 +1,4 @@
bdep
+*-odb.?xx
*-options.?xx
version.hxx
diff --git a/bdep/bdep.cxx b/bdep/bdep.cxx
index ca6ff64..77dcd71 100644
--- a/bdep/bdep.cxx
+++ b/bdep/bdep.cxx
@@ -16,7 +16,7 @@
#include <bdep/diagnostics.hxx>
#include <bdep/bdep-options.hxx>
-#include <bdep/config-options.hxx>
+#include <bdep/project-options.hxx>
// Commands.
//
@@ -33,11 +33,11 @@ using namespace bdep;
// Once this is done, use the "final" values of the common options to do
// global initializations (verbosity level, etc).
//
-// If O is-a configuration_options, then also handle the @<cfg-name> arguments
-// and place them into configuration_options::config_name.
+// If O is-a project_options, then also handle the @<cfg-name> arguments and
+// place them into project_options::config_name.
//
static inline bool
-cfg_name (configuration_options* o, const char* a)
+cfg_name (project_options* o, const char* a)
{
string n (a);
diff --git a/bdep/buildfile b/bdep/buildfile
index 5ef9099..cd7c690 100644
--- a/bdep/buildfile
+++ b/bdep/buildfile
@@ -2,25 +2,41 @@
# copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
+# @@ ODB: these are ODB changelogs that are both generated and stored in the
+# repository (what if src != out?). Will need to think how to handle
+# them properly (always generate in src_base?).
+#
+define xml: file
+xml{*}: extension = xml
+
import libs = libbpkg%lib{bpkg}
import libs += libbutl%lib{butl}
+import libs += libodb%lib{odb}
+import libs += libodb-sqlite%lib{odb-sqlite}
-options_topics = \
-bdep-options \
-common-options \
-project-options \
-configuration-options \
-help-options \
-config-options \
+options_topics = \
+bdep-options \
+common-options \
+project-options \
+help-options \
+config-options \
init-options
-exe{bdep}: {hxx ixx txx cxx}{** -{$options_topics} -version} \
- {hxx ixx cxx}{$options_topics} {hxx}{version} $libs
+exe{bdep}: {hxx ixx txx cxx}{** -{$options_topics} -*-odb -version} \
+ {hxx ixx cxx}{$options_topics} {hxx ixx cxx}{project-odb} \
+ {hxx}{version} $libs
hxx{version}: in{version} $src_root/file{manifest}
obj{utility}: cxx.poptions += -DBDEP_EXE_SUFFIX='"'$bin.exe.suffix'"'
+# Disable "unknown pragma" warnings.
+#
+if ($cxx.class == 'msvc')
+ cxx.coptions += /wd4068
+elif ($cxx.class == 'gcc')
+ cxx.coptions += -Wno-unknown-pragmas
+
if $cli.configured
{
# General topics and common options.
diff --git a/bdep/config.cli b/bdep/config.cli
index 42a0fe6..434dfc2 100644
--- a/bdep/config.cli
+++ b/bdep/config.cli
@@ -2,7 +2,7 @@
// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
-include <bdep/configuration.cli>;
+include <bdep/project.cli>;
"\section=1"
"\name=bdep-config"
@@ -34,7 +34,7 @@ namespace bdep
// Note that not all project/configuration options are valid for all
// subcommands.
//
- class cmd_config_options: configuration_options
+ class cmd_config_options: project_options
{
"\h|CONFIG OPTIONS|"
diff --git a/bdep/configuration.cli b/bdep/configuration.cli
deleted file mode 100644
index e6e911a..0000000
--- a/bdep/configuration.cli
+++ /dev/null
@@ -1,35 +0,0 @@
-// file : bdep/configuration.cli
-// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
-// license : MIT; see accompanying LICENSE file
-
-include <bdep/project.cli>;
-
-"\name=configuration" // Not a man page.
-
-namespace bdep
-{
- // Common options for commands that operate on configurations (cfg-spec).
- // Note that all of them also operate on project/packages thus inheritance
- // from project_options.
- //
- class configuration_options: project_options
- {
- dir_paths --config|-c
- {
- "<dir>",
- "Specify the build configuration to use as a directory."
- }
-
- bool --all|-a
- {
- "Use all build configurations."
- }
-
- // Storage for configuration names specified as @<cfg-name>.
- //
- // Note that we leave it undocumented so that it's not mentioned in
- // documentation.
- //
- strings --config-name;
- };
-}
diff --git a/bdep/database.cxx b/bdep/database.cxx
new file mode 100644
index 0000000..c456961
--- /dev/null
+++ b/bdep/database.cxx
@@ -0,0 +1,88 @@
+// file : bdep/database.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <bdep/database.hxx>
+
+#include <odb/schema-catalog.hxx>
+#include <odb/sqlite/exceptions.hxx>
+
+#include <bdep/diagnostics.hxx>
+
+using namespace std;
+
+namespace bdep
+{
+ using namespace odb::sqlite;
+ using odb::schema_catalog;
+
+ database
+ open (const dir_path& d, tracer& tr, bool create)
+ {
+ tracer trace ("open");
+
+ path f (d / bdep_dir / "bdep.sqlite3");
+
+ if (!create && !exists (f))
+ fail << d << " does not look like an initialized project directory" <<
+ info << "run 'bdep init' to initialize";
+
+ try
+ {
+ // We don't need the thread pool.
+ //
+ unique_ptr<connection_factory> cf (new single_connection_factory);
+
+ database db (f.string (),
+ SQLITE_OPEN_READWRITE | (create ? SQLITE_OPEN_CREATE : 0),
+ true, // Enable FKs.
+ "", // Default VFS.
+ move (cf));
+
+ db.tracer (trace);
+
+ // Lock the database for as long as the connection is active. First we
+ // set locking_mode to EXCLUSIVE which instructs SQLite not to release
+ // any locks until the connection is closed. Then we force SQLite to
+ // acquire the write lock by starting exclusive transaction. See the
+ // locking_mode pragma documentation for details. This will also fail if
+ // the database is inaccessible (e.g., file does not exist, already used
+ // by another process, etc).
+ //
+ try
+ {
+ db.connection ()->execute ("PRAGMA locking_mode = EXCLUSIVE");
+ transaction t (db.begin_exclusive ());
+
+ if (create)
+ {
+ // Create the new schema.
+ //
+ if (db.schema_version () != 0)
+ fail << f << ": already has database schema";
+
+ schema_catalog::create_schema (db);
+ }
+ else
+ {
+ // Migrate the database if necessary.
+ //
+ schema_catalog::migrate (db);
+ }
+
+ t.commit ();
+ }
+ catch (odb::timeout&)
+ {
+ fail << "project " << d << " is already used by another process";
+ }
+
+ db.tracer (tr); // Switch to the caller's tracer.
+ return db;
+ }
+ catch (const database_exception& e)
+ {
+ fail << f << ": " << e.message () << endf;
+ }
+ }
+}
diff --git a/bdep/database.hxx b/bdep/database.hxx
new file mode 100644
index 0000000..76642bf
--- /dev/null
+++ b/bdep/database.hxx
@@ -0,0 +1,82 @@
+// file : bdep/database.hxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BDEP_DATABASE_HXX
+#define BDEP_DATABASE_HXX
+
+#include <type_traits> // remove_reference
+
+#include <odb/query.hxx>
+#include <odb/result.hxx>
+#include <odb/session.hxx>
+
+#include <odb/sqlite/database.hxx>
+
+#include <bdep/types.hxx>
+#include <bdep/utility.hxx>
+
+#include <bdep/diagnostics.hxx>
+
+namespace bdep
+{
+ using odb::query;
+ using odb::result;
+ using odb::session;
+
+ using odb::sqlite::database;
+ using odb::sqlite::transaction;
+
+ database
+ open (const dir_path& project, tracer&, bool create = false);
+
+ struct tracer_guard
+ {
+ tracer_guard (database& db, tracer& t)
+ : db_ (db), t_ (db.tracer ()) {db.tracer (t);}
+ ~tracer_guard () {db_.tracer (*t_);}
+
+ private:
+ database& db_;
+ odb::tracer* t_;
+ };
+
+ // Range-based for-loop iteration over query result that returns object
+ // pointers. For example:
+ //
+ // for (shared_ptr<object> o: pointer_result (db.query<object> (...)))
+ //
+ template <typename R>
+ class pointer_result_range
+ {
+ R r_;
+
+ public:
+ pointer_result_range (R&& r): r_ (forward<R> (r)) {}
+
+ using base_iterator = typename std::remove_reference<R>::type::iterator;
+
+ struct iterator: base_iterator
+ {
+ iterator () = default;
+
+ explicit
+ iterator (base_iterator i): base_iterator (move (i)) {}
+
+ typename base_iterator::pointer_type
+ operator* () {return this->load ();}
+ };
+
+ iterator begin () {return iterator (r_.begin ());}
+ iterator end () {return iterator (r_.end ());}
+ };
+
+ template <typename R>
+ inline pointer_result_range<R>
+ pointer_result (R&& r)
+ {
+ return pointer_result_range<R> (forward<R> (r));
+ }
+}
+
+#endif // BDEP_DATABASE_HXX
diff --git a/bdep/diagnostics.cxx b/bdep/diagnostics.cxx
index f596e49..cd77a91 100644
--- a/bdep/diagnostics.cxx
+++ b/bdep/diagnostics.cxx
@@ -4,6 +4,8 @@
#include <bdep/diagnostics.hxx>
+#include <odb/statement.hxx>
+
#include <libbutl/process.mxx>
#include <libbutl/process-io.mxx> // operator<<(ostream, process_arg)
@@ -58,6 +60,29 @@ namespace bdep
r << name_ << ": ";
}
+ // trace
+ //
+ void trace_mark_base::
+ prepare (odb::connection&, const odb::statement& s)
+ {
+ if (verb >= 6)
+ static_cast<trace_mark&> (*this) << "PREPARE " << s.text ();
+ }
+
+ void trace_mark_base::
+ execute (odb::connection&, const char* stmt)
+ {
+ if (verb >= 5)
+ static_cast<trace_mark&> (*this) << stmt;
+ }
+
+ void trace_mark_base::
+ deallocate (odb::connection&, const odb::statement& s)
+ {
+ if (verb >= 6)
+ static_cast<trace_mark&> (*this) << "DEALLOCATE " << s.text ();
+ }
+
// tracer
//
void tracer::
diff --git a/bdep/diagnostics.hxx b/bdep/diagnostics.hxx
index 366b6c0..9a233f0 100644
--- a/bdep/diagnostics.hxx
+++ b/bdep/diagnostics.hxx
@@ -5,6 +5,8 @@
#ifndef BDEP_DIAGNOSTICS_HXX
#define BDEP_DIAGNOSTICS_HXX
+#include <odb/tracer.hxx>
+
#include <libbutl/diagnostics.mxx>
#include <bdep/types.hxx> // Note: not <bdep/utility.hxx>
@@ -176,11 +178,25 @@ namespace bdep
// trace
//
- struct trace_mark_base: basic_mark_base
+ // Also implement the ODB tracer interface so that we can use it to trace
+ // database statement execution.
+ //
+ struct trace_mark_base: basic_mark_base, odb::tracer
{
explicit
trace_mark_base (const char* name, const void* data = nullptr)
: basic_mark_base ("trace", name, data) {}
+
+ // odb::tracer interface.
+ //
+ virtual void
+ prepare (odb::connection&, const odb::statement&);
+
+ virtual void
+ execute (odb::connection&, const char* statement);
+
+ virtual void
+ deallocate (odb::connection&, const odb::statement&);
};
using trace_mark = butl::diag_mark<trace_mark_base>;
diff --git a/bdep/init.cli b/bdep/init.cli
index 7eeeb6b..6e50f10 100644
--- a/bdep/init.cli
+++ b/bdep/init.cli
@@ -2,7 +2,7 @@
// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
-include <bdep/configuration.cli>;
+include <bdep/project.cli>;
"\section=1"
"\name=bdep-init"
@@ -57,7 +57,7 @@ namespace bdep
"
}
- class cmd_init_options: configuration_options
+ class cmd_init_options: project_options
{
"\h|INIT OPTIONS|"
diff --git a/bdep/odb.sh b/bdep/odb.sh
new file mode 100755
index 0000000..77372b9
--- /dev/null
+++ b/bdep/odb.sh
@@ -0,0 +1,18 @@
+#! /usr/bin/env bash
+
+trap 'exit 1' ERR
+
+odb=odb
+lib="\
+-I$HOME/work/odb/builds/default/libodb-sqlite-default \
+-I$HOME/work/odb/libodb-sqlite \
+-I$HOME/work/odb/builds/default/libodb-default \
+-I$HOME/work/odb/libodb"
+
+$odb $lib -I.. -I../../libbpkg -I../../libbutl \
+ -DLIBODB_BUILD2 -DLIBODB_SQLITE_BUILD2 --generate-schema \
+ -d sqlite --std c++11 --generate-query \
+ --odb-epilogue '#include <bdep/wrapper-traits.hxx>' \
+ --hxx-prologue '#include <bdep/wrapper-traits.hxx>' \
+ --include-with-brackets --include-prefix bdep --guard-prefix BDEP \
+ --sqlite-override-null project.hxx
diff --git a/bdep/project.cli b/bdep/project.cli
index 7b6af76..f080917 100644
--- a/bdep/project.cli
+++ b/bdep/project.cli
@@ -9,10 +9,28 @@ include <bdep/common.cli>;
namespace bdep
{
// Common options for commands that operate on project/packages (prj-spec
- // and pkg-spec).
+ // and pkg-spec) and configurations (cfg-spec).
//
class project_options: common_options
{
+ dir_paths --config|-c
+ {
+ "<dir>",
+ "Specify the build configuration to use as a directory."
+ }
+
+ bool --all|-a
+ {
+ "Use all build configurations."
+ }
+
+ // Storage for configuration names specified as @<cfg-name>.
+ //
+ // Note that we leave it undocumented so that it's not mentioned in
+ // documentation.
+ //
+ strings --config-name;
+
dir_paths --directory|-d
{
"<dir>",
diff --git a/bdep/project.hxx b/bdep/project.hxx
index 6a748d5..274455c 100644
--- a/bdep/project.hxx
+++ b/bdep/project.hxx
@@ -5,13 +5,50 @@
#ifndef BDEP_PROJECT_HXX
#define BDEP_PROJECT_HXX
+#include <odb/core.hxx>
+
#include <bdep/types.hxx>
#include <bdep/utility.hxx>
#include <bdep/project-options.hxx>
+#pragma db model version(1, 1, open)
+
+// Prevent assert() macro expansion in get/set expressions. This should appear
+// after all #include directives since the assert() macro is redefined in each
+// <assert.h> inclusion.
+//
+#ifdef ODB_COMPILER
+# undef assert
+# define assert assert
+void assert (int);
+#endif
+
namespace bdep
{
+ #pragma db map type(dir_path) as(string) \
+ to((?).string ()) from(bdep::dir_path (?))
+
+ //@@ TODO: do we need session/shared_ptr?
+
+ #pragma db object pointer(shared_ptr) session
+ class configuration
+ {
+ public:
+
+ dir_path path; // @@ TODO: relative or absolute?
+ string name;
+
+ // Database mapping.
+ //
+ #pragma db member(name) id
+ //#pragma db member(name) index
+
+ private:
+ friend class odb::access;
+ configuration () = default;
+ };
+
// Given project_options (and CWD) locate the packages and their project.
// The result is the absolute and normalized project directory and a vector
// of relative (to the project directory) package directories (which will be
diff --git a/bdep/project.xml b/bdep/project.xml
new file mode 100644
index 0000000..c3991bc
--- /dev/null
+++ b/bdep/project.xml
@@ -0,0 +1,11 @@
+<changelog xmlns="http://www.codesynthesis.com/xmlns/odb/changelog" database="sqlite" version="1">
+ <model version="1">
+ <table name="configuration" kind="object">
+ <column name="path" type="TEXT" null="true"/>
+ <column name="name" type="TEXT" null="true"/>
+ <primary-key>
+ <column name="name"/>
+ </primary-key>
+ </table>
+ </model>
+</changelog>
diff --git a/bdep/utility.cxx b/bdep/utility.cxx
index edfdc41..93f0458 100644
--- a/bdep/utility.cxx
+++ b/bdep/utility.cxx
@@ -20,6 +20,8 @@ namespace bdep
const path empty_path;
const dir_path empty_dir_path;
+ const dir_path bdep_dir (".bdep");
+
const path manifest_file ("manifest");
const path packages_file ("packages.manifest");
const path configurations_file ("configurations.manifest");
diff --git a/bdep/utility.hxx b/bdep/utility.hxx
index 8bca172..54e17fb 100644
--- a/bdep/utility.hxx
+++ b/bdep/utility.hxx
@@ -56,6 +56,8 @@ namespace bdep
// Widely-used paths.
//
+ extern const dir_path bdep_dir; // .bdep/
+
extern const path manifest_file; // manifest
extern const path packages_file; // packages.manifest
extern const path configurations_file; // configurations.manifest
diff --git a/bdep/version.hxx.in b/bdep/version.hxx.in
index c243114..73b2df9 100644
--- a/bdep/version.hxx.in
+++ b/bdep/version.hxx.in
@@ -45,4 +45,12 @@ $libbutl.check(LIBBUTL_VERSION, LIBBUTL_SNAPSHOT)$
$libbpkg.check(LIBBPKG_VERSION, LIBBPKG_SNAPSHOT)$
+#include <odb/version.hxx>
+
+$libodb.check(LIBODB_VERSION, LIBODB_SNAPSHOT)$
+
+#include <odb/sqlite/version.hxx>
+
+$libodb-sqlite.check(LIBODB_SQLITE_VERSION, LIBODB_SQLITE_SNAPSHOT)$
+
#endif // BDEP_VERSION
diff --git a/bdep/wrapper-traits.hxx b/bdep/wrapper-traits.hxx
new file mode 100644
index 0000000..80b0cff
--- /dev/null
+++ b/bdep/wrapper-traits.hxx
@@ -0,0 +1,59 @@
+// file : bdep/wrapper-traits.hxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BDEP_WRAPPER_TRAITS_HXX
+#define BDEP_WRAPPER_TRAITS_HXX
+
+#include <libbutl/optional.mxx>
+
+#include <odb/wrapper-traits.hxx>
+
+namespace odb
+{
+ template <typename T>
+ class wrapper_traits<butl::optional<T>>
+ {
+ public:
+ typedef T wrapped_type;
+ typedef butl::optional<T> wrapper_type;
+
+ // T can be const.
+ //
+ typedef
+ typename odb::details::meta::remove_const<T>::result
+ unrestricted_wrapped_type;
+
+ static const bool null_handler = true;
+ static const bool null_default = true;
+
+ static bool
+ get_null (const wrapper_type& o)
+ {
+ return !o;
+ }
+
+ static void
+ set_null (wrapper_type& o)
+ {
+ o = wrapper_type ();
+ }
+
+ static const wrapped_type&
+ get_ref (const wrapper_type& o)
+ {
+ return *o;
+ }
+
+ static unrestricted_wrapped_type&
+ set_ref (wrapper_type& o)
+ {
+ if (!o)
+ o = unrestricted_wrapped_type ();
+
+ return const_cast<unrestricted_wrapped_type&> (*o);
+ }
+ };
+}
+
+#endif // BDEP_WRAPPER_TRAITS_HXX
diff --git a/manifest b/manifest
index debfdce..c7eb306 100644
--- a/manifest
+++ b/manifest
@@ -16,5 +16,7 @@ depends: * build2 >= 0.7.0-
depends: * bpkg >= 0.7.0-
# @@ Should probably become conditional dependency.
requires: ? cli ; Only required if changing .cli files.
+depends: libodb [2.5.0-b.6.1 2.5.0-b.7)
+depends: libodb-sqlite [2.5.0-b.6.1 2.5.0-b.7)
depends: libbutl [0.7.0-a.0.1 0.7.0-a.1)
depends: libbpkg [0.7.0-a.0.1 0.7.0-a.1)