aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-09-05 09:24:39 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-09-05 09:24:39 +0200
commita3925d12af6a6ae75897d5aab25a9de0edb642fb (patch)
treec7a95927bbc339f873f58ba3bab63916eced71fb
parent3469e1d984c6ae000b59c471e6ef84c4b43497f2 (diff)
Add support for build-time dependencies
-rw-r--r--bpkg/package.xml1
-rw-r--r--bpkg/pkg-build.cxx43
-rw-r--r--bpkg/pkg-configure.cxx26
-rw-r--r--bpkg/satisfaction9
-rw-r--r--bpkg/satisfaction.cxx91
-rw-r--r--bpkg/utility7
-rw-r--r--bpkg/utility.cxx15
7 files changed, 179 insertions, 13 deletions
diff --git a/bpkg/package.xml b/bpkg/package.xml
index 0602880..78a49d4 100644
--- a/bpkg/package.xml
+++ b/bpkg/package.xml
@@ -106,6 +106,7 @@
<column name="version_revision" type="INTEGER" null="true"/>
<column name="index" type="INTEGER" null="true"/>
<column name="conditional" type="INTEGER" null="true"/>
+ <column name="buildtime" type="INTEGER" null="true"/>
<column name="comment" type="TEXT" null="true"/>
<foreign-key name="object_id_fk" on-delete="CASCADE">
<column name="name"/>
diff --git a/bpkg/pkg-build.cxx b/bpkg/pkg-build.cxx
index a022130..d9847f2 100644
--- a/bpkg/pkg-build.cxx
+++ b/bpkg/pkg-build.cxx
@@ -499,6 +499,31 @@ namespace bpkg
fail << "multiple dependency alternatives not yet supported";
const dependency& d (da.front ());
+ const string& dn (d.name);
+
+ if (da.buildtime)
+ {
+ // Handle special names.
+ //
+ if (dn == "build2")
+ {
+ if (d.constraint)
+ satisfy_build2 (options, name, d);
+
+ continue;
+ }
+ else if (dn == "bpkg")
+ {
+ if (d.constraint)
+ satisfy_bpkg (options, name, d);
+
+ continue;
+ }
+ // else
+ //
+ // @@ TODO: in the future we would need to at least make sure the
+ // build and target machines are the same. See also pkg-configure.
+ }
// The first step is to always find the available package even
// if, in the end, it won't be the one we select. If we cannot
@@ -521,7 +546,7 @@ namespace bpkg
// either way, resolving it to 1.0.0 is the conservative choice and
// the user can always override it by explicitly building libhello.
//
- auto rp (find_available (db, d.name, ar, d.constraint));
+ auto rp (find_available (db, dn, ar, d.constraint));
shared_ptr<available_package>& dap (rp.first);
if (dap == nullptr)
@@ -550,14 +575,14 @@ namespace bpkg
if (dap->system_version () == nullptr)
fail << "prerequisite " << d << " of package " << name << " is "
<< "not available in source" <<
- info << "specify ?sys:" << d.name << " if it is available "
- << "from the system";
+ info << "specify ?sys:" << dn << " if it is available from the "
+ << "system";
if (!satisfies (*dap->system_version (), d.constraint))
{
fail << "prerequisite " << d << " of package " << name << " is "
<< "not available in source" <<
- info << "sys:" << d.name << "/" << *dap->system_version ()
+ info << "sys:" << dn << "/" << *dap->system_version ()
<< " does not satisfy the constrains";
}
@@ -579,11 +604,11 @@ namespace bpkg
// worse, downgrade).
//
bool force (false);
- shared_ptr<selected_package> dsp (db.find<selected_package> (d.name));
+ shared_ptr<selected_package> dsp (db.find<selected_package> (dn));
if (dsp != nullptr)
{
if (dsp->state == package_state::broken)
- fail << "unable to build broken package " << d.name <<
+ fail << "unable to build broken package " << dn <<
info << "use 'pkg-purge --force' to remove";
if (satisfies (dsp->version, d.constraint))
@@ -777,6 +802,12 @@ namespace bpkg
{
assert (!da.conditional && da.size () == 1); // @@ TODO
const dependency& d (da.front ());
+ const string& dn (d.name);
+
+ // Skip special names.
+ //
+ if (da.buildtime && (dn == "build2" || dn == "bpkg"))
+ continue;
update (order (d.name, false));
}
diff --git a/bpkg/pkg-configure.cxx b/bpkg/pkg-configure.cxx
index 81b1fe3..2bb834f 100644
--- a/bpkg/pkg-configure.cxx
+++ b/bpkg/pkg-configure.cxx
@@ -61,6 +61,32 @@ namespace bpkg
{
const string& n (d.name);
+ if (da.buildtime)
+ {
+ // Handle special names.
+ //
+ if (n == "build2")
+ {
+ if (d.constraint)
+ satisfy_build2 (o, m.name, d);
+
+ satisfied = true;
+ break;
+ }
+ else if (n == "bpkg")
+ {
+ if (d.constraint)
+ satisfy_bpkg (o, m.name, d);
+
+ satisfied = true;
+ break;
+ }
+ // else
+ //
+ // @@ TODO: in the future we would need to at least make sure the
+ // build and target machines are the same. See also pkg-build.
+ }
+
if (shared_ptr<selected_package> dp = db.find<selected_package> (n))
{
if (dp->state != package_state::configured)
diff --git a/bpkg/satisfaction b/bpkg/satisfaction
index a140b5f..ae78a98 100644
--- a/bpkg/satisfaction
+++ b/bpkg/satisfaction
@@ -9,6 +9,7 @@
#include <bpkg/utility>
#include <bpkg/package>
+#include <bpkg/common-options>
namespace bpkg
{
@@ -36,6 +37,14 @@ namespace bpkg
{
return l ? (!r || satisfies (*l, *r)) : !r;
}
+
+ // Special build-time dependencies.
+ //
+ void
+ satisfy_build2 (const common_options&, const string& pkg, const dependency&);
+
+ void
+ satisfy_bpkg (const common_options&, const string& pkg, const dependency&);
}
#endif // BPKG_SATISFACTION
diff --git a/bpkg/satisfaction.cxx b/bpkg/satisfaction.cxx
index bddf7e7..2e2b269 100644
--- a/bpkg/satisfaction.cxx
+++ b/bpkg/satisfaction.cxx
@@ -4,8 +4,13 @@
#include <bpkg/satisfaction>
+#include <butl/process>
+#include <butl/fdstream>
+
+#include <bpkg/utility>
#include <bpkg/package-odb>
#include <bpkg/diagnostics>
+#include <bpkg/bpkg-version>
using namespace std;
using namespace butl;
@@ -93,4 +98,90 @@ namespace bpkg
return s;
}
+
+ static version build2_version;
+
+ void
+ satisfy_build2 (const common_options& co,
+ const string& pkg,
+ const dependency& d)
+ {
+ assert (d.name == "build2");
+
+ // Extract, parse, and cache build2 version string.
+ //
+ if (build2_version.empty ())
+ {
+ const char* args[] = {name_b (co), "--version", nullptr};
+
+ try
+ {
+ process_path pp (process::path_search (args[0], exec_dir));
+
+ if (verb >= 3)
+ print_process (args);
+
+ process pr (pp, args, 0, -1); // Redirect STDOUT to pipe.
+
+ string l;
+ try
+ {
+ ifdstream is (pr.in_ofd, fdstream_mode::skip);
+ getline (is, l);
+ is.close ();
+
+ if (pr.wait () && l.compare (0, 7, "build2 ") == 0)
+ {
+ try
+ {
+ build2_version = version (string (l, 7));
+ }
+ catch (const invalid_argument&) {} // Fall through.
+ }
+
+ // Fall through.
+ }
+ catch (const ifdstream::failure&)
+ {
+ pr.wait ();
+ // Fall through.
+ }
+
+ if (build2_version.empty ())
+ fail << "unable to determine build2 version of " << args[0];
+ }
+ catch (const process_error& e)
+ {
+ error << "unable to execute " << args[0] << ": " << e.what ();
+
+ if (e.child ())
+ exit (1);
+
+ throw failed ();
+ }
+ }
+
+ if (!satisfies (build2_version, d.constraint))
+ fail << "unable to satisfy constraint (" << d << ") for package "
+ << pkg <<
+ info << "available build2 version is " << build2_version;
+ }
+
+ static version bpkg_version;
+
+ void
+ satisfy_bpkg (const common_options&, const string& pkg, const dependency& d)
+ {
+ assert (d.name == "bpkg");
+
+ // Parse and cache bpkg version string.
+ //
+ if (bpkg_version.empty ())
+ bpkg_version = version (BPKG_VERSION_STR);
+
+ if (!satisfies (bpkg_version, d.constraint))
+ fail << "unable to satisfy constraint (" << d << ") for package "
+ << pkg <<
+ info << "available bpkg version is " << bpkg_version;
+ }
}
diff --git a/bpkg/utility b/bpkg/utility
index a4bc6d3..b7dbf36 100644
--- a/bpkg/utility
+++ b/bpkg/utility
@@ -76,8 +76,8 @@ namespace bpkg
// Process.
//
- // The process command line is printed for verbosity >= 2 (essential
- // command lines).
+ // By default the process command line is printed for verbosity >= 2
+ // (essential command lines).
//
// If fallback is specified, then this directory is searched for the
// executable as a last resort.
@@ -102,6 +102,9 @@ namespace bpkg
//
class common_options;
+ const char*
+ name_b (const common_options&);
+
void
run_b (const common_options&,
const dir_path& configuration,
diff --git a/bpkg/utility.cxx b/bpkg/utility.cxx
index 002d316..5d37972 100644
--- a/bpkg/utility.cxx
+++ b/bpkg/utility.cxx
@@ -7,6 +7,7 @@
#include <iostream> // cout, cin
#include <butl/process>
+#include <butl/fdstream>
#include <bpkg/diagnostics>
#include <bpkg/common-options>
@@ -195,6 +196,14 @@ namespace bpkg
}
}
+ const char*
+ name_b (const common_options& co)
+ {
+ return co.build_specified ()
+ ? co.build ().string ().c_str ()
+ : "b" BPKG_EXE_SUFFIX;
+ }
+
void
run_b (const common_options& co,
const dir_path& c,
@@ -203,11 +212,7 @@ namespace bpkg
const strings& pvars,
const strings& cvars)
{
- const char* b (co.build_specified ()
- ? co.build ().string ().c_str ()
- : "b" BPKG_EXE_SUFFIX);
-
- cstrings args {b};
+ cstrings args {name_b (co)};
// Map verbosity level. If we are running quiet or at level 1,
// then run build2 quiet. Otherwise, run it at the same level