aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2023-06-20 20:22:29 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2023-06-21 12:01:03 +0300
commitfdfd3e0644095022b61316e220fce3f5a7a1a9ef (patch)
treeb4e8098437fe5e11920aebd71dd581212c4d2f10
parent8ae1780760db7f73c7045481e6fd18c7fbada60d (diff)
Add --mask-repository-uuid pkg-build option
-rw-r--r--bpkg/pkg-build.cli13
-rw-r--r--bpkg/pkg-build.cxx6
-rw-r--r--bpkg/rep-mask.cxx136
-rw-r--r--bpkg/rep-mask.hxx21
-rw-r--r--tests/config.testscript3
-rw-r--r--tests/pkg-build.testscript40
6 files changed, 185 insertions, 34 deletions
diff --git a/bpkg/pkg-build.cli b/bpkg/pkg-build.cli
index 3db6e9f..a365082 100644
--- a/bpkg/pkg-build.cli
+++ b/bpkg/pkg-build.cli
@@ -411,6 +411,19 @@ namespace bpkg
mask multiple repositories."
}
+ strings --mask-repository-uuid
+ {
+ "<v>",
+ "For the duration of the command execution pretend the specified
+ repository was removed from the specified configuration. Similar to
+ \cb{--mask-repository} but only masks the repository in a single
+ configuration. The option value is a key-value pair in the form:
+
+ \c{\i{config-uuid}\b{=}\i{rep}}
+
+ Repeat this option to mask multiple repositories."
+ }
+
bool --no-refinement
{
"Don't try to refine the configuration by offering to drop any unused
diff --git a/bpkg/pkg-build.cxx b/bpkg/pkg-build.cxx
index 6101826..848dc39 100644
--- a/bpkg/pkg-build.cxx
+++ b/bpkg/pkg-build.cxx
@@ -2000,8 +2000,10 @@ namespace bpkg
// Now, as repo_configs is filled and the repositories are fetched mask
// the repositories, if any.
//
- if (o.mask_repository_specified ())
- rep_mask (o.mask_repository ());
+ if (o.mask_repository_specified () || o.mask_repository_uuid_specified ())
+ rep_mask (o.mask_repository (),
+ o.mask_repository_uuid (),
+ current_configs);
// Expand the package specs into individual package args, parsing them
// into the package scheme, name, and version constraint components, and
diff --git a/bpkg/rep-mask.cxx b/bpkg/rep-mask.cxx
index 79aef42..d7f9c6a 100644
--- a/bpkg/rep-mask.cxx
+++ b/bpkg/rep-mask.cxx
@@ -26,16 +26,26 @@ namespace bpkg
const shared_ptr<repository>&,
bool mask);
- // The idea here is to start the transaction, remove all the specified
- // repositories recursively in all the configurations specified by
- // repo_configs, collect the remaining repositories and repository fragments
- // as unmasked, and rollback the transaction. Later on, the rep_masked*()
- // functions will refer to the configuration-specific unmasked repositories
- // and repository fragments lists to decide if the repository is masked or
- // not in the specific configuration.
+ // The overall plan is as follows:
+ //
+ // - Start the transaction.
+ //
+ // - Remove all the specified repositories recursively in all the
+ // configurations specified by repo_configs (repos) and/or configurations
+ // specified explicitly via UUIDs (config_uuid_repos).
+ //
+ // - Collect the remaining repositories and repository fragments as unmasked.
+ //
+ // - Rollback the transaction.
+ //
+ // Later on, the rep_masked*() functions will refer to the configuration-
+ // specific unmasked repositories and repository fragments lists to decide
+ // if the repository/fragment is masked or not in the specific configuration.
//
void
- rep_mask (const strings& repos)
+ rep_mask (const strings& repos,
+ const strings& config_uuid_repos,
+ linked_databases& current_configs)
{
tracer trace ("rep_mask");
@@ -55,22 +65,31 @@ namespace bpkg
transaction t (mdb);
+ // Add a repository from a database, suppressing duplicates.
+ //
+ auto add_repo = [&rs] (database& db, shared_ptr<repository>&& r)
+ {
+ if (find_if (rs.begin (), rs.end (),
+ [&db, &r] (const lazy_weak_ptr<repository>& lr)
+ {
+ return lr.database () == db && lr.object_id () == r->name;
+ }) == rs.end ())
+ rs.emplace_back (db, move (r));
+ };
+
+ // Collect the repositories masked in all configurations.
+ //
for (database& db: repo_configs)
{
for (size_t i (0); i != repos.size (); ++i)
{
// Add a repository, suppressing duplicates, and mark it as found.
//
- auto add = [&db, &rs, &found_repos, i] (shared_ptr<repository>&& r)
+ auto add = [&db,
+ &found_repos, i,
+ &add_repo] (shared_ptr<repository>&& r)
{
- if (find_if (rs.begin (), rs.end (),
- [&db, &r] (const lazy_weak_ptr<repository>& lr)
- {
- return lr.database () == db &&
- lr.object_id () == r->name;
- }) == rs.end ())
- rs.emplace_back (db, move (r));
-
+ add_repo (db, move (r));
found_repos[i] = true;
};
@@ -114,6 +133,89 @@ namespace bpkg
fail << "repository '" << repos[i] << "' cannot be masked: not found";
}
+ // Collect the repositories masked in specific configurations.
+ //
+ for (const string& cr: config_uuid_repos)
+ {
+ auto bad = [&cr] (const string& d)
+ {
+ fail << "configuration repository '" << cr << "' cannot be masked: "
+ << d;
+ };
+
+ size_t p (cr.find ('='));
+
+ if (p == string::npos)
+ bad ("missing '='");
+
+ uuid uid;
+ string uid_str (cr, 0, p);
+
+ try
+ {
+ uid = uuid (uid_str);
+ }
+ catch (const invalid_argument& e)
+ {
+ bad ("invalid configuration uuid '" + uid_str + "': " + e.what ());
+ }
+
+ database* db (nullptr);
+
+ for (database& cdb: current_configs)
+ {
+ if ((db = cdb.try_find_dependency_config (uid)) != nullptr)
+ break;
+ }
+
+ if (db == nullptr)
+ bad ("no configuration with uuid " + uid.string () +
+ " is linked with " +
+ (current_configs.size () == 1
+ ? mdb.config_orig.representation ()
+ : "specified current configurations"));
+
+ string rp (cr, p + 1);
+
+ if (repository_name (rp))
+ {
+ if (shared_ptr<repository> r = db->find<repository> (rp))
+ add_repo (*db, move (r));
+ else
+ bad ("repository name '" + rp + "' not found in configuration " +
+ uid.string ());
+ }
+ else
+ {
+ using query = query<repository>;
+
+ // Verify that the repository URL is not misspelled or empty.
+ //
+ try
+ {
+ repository_url u (rp);
+ assert (!u.empty ());
+ }
+ catch (const invalid_argument& e)
+ {
+ bad ("invalid repository location '" + rp + "': " + e.what ());
+ }
+
+ bool found (false);
+ for (shared_ptr<repository> r:
+ pointer_result (
+ db->query<repository> (query::location.url == rp)))
+ {
+ add_repo (*db, move (r));
+ found = true;
+ }
+
+ if (!found)
+ bad ("repository location '" + rp + "' not found in configuration " +
+ uid.string ());
+ }
+ }
+
// First, remove the repository references from the dependent repository
// fragments. Note that rep_remove() removes the dangling repositories.
//
diff --git a/bpkg/rep-mask.hxx b/bpkg/rep-mask.hxx
index dd9cedf..2185af2 100644
--- a/bpkg/rep-mask.hxx
+++ b/bpkg/rep-mask.hxx
@@ -13,15 +13,20 @@ namespace bpkg
// Note: not a command (at least not yet).
//
// Mask repositories to pretend they don't exist in the configurations that
- // are used as the repository information sources (repo_configs). Also mask
- // their complement and prerequisite repositories, recursively, excluding
- // those which are complements and/or prerequisites of other unmasked
- // repositories. The repositories can be specified either as repository
- // location canonical names or URLs. Issue diagnostics and fail if any of
- // the specified repositories don't exist in any configuration.
+ // are used as the repository information sources (repo_configs;
+ // repositories argument) and/or specific configurations
+ // (config_uuid_repositories argument). Also mask their complement and
+ // prerequisite repositories, recursively, excluding those which are
+ // complements and/or prerequisites of other unmasked repositories. The
+ // repositories can be specified either as repository location canonical
+ // names or URLs. Issue diagnostics and fail if any of the specified
+ // repositories don't exist in any configuration.
//
// Notes:
//
+ // - The current configurations are only used to resolve the configuration
+ // UUIDs, if any.
+ //
// - A repository may end up being masked in one configuration but not in
// another.
//
@@ -36,7 +41,9 @@ namespace bpkg
// NOTE: repo_configs needs to be filled prior to the function call.
//
void
- rep_mask (const strings&);
+ rep_mask (const strings& repositories, // <rep>
+ const strings& config_uuid_repositories, // <config-uuid>=<rep>
+ linked_databases& current_configs);
// Return true if a repository is masked in the specified configuration.
//
diff --git a/tests/config.testscript b/tests/config.testscript
index 70eef42..442cf36 100644
--- a/tests/config.testscript
+++ b/tests/config.testscript
@@ -9,7 +9,8 @@
# shared between multiple bpkg processes. Also we need to make sure that
# configurations are not cloned while being used by bpkg.
#
-+$cfg_create -d cfg 2>- &cfg/***
+cfg_uuid = "00000000-0000-0000-0000-000000000001"
++$cfg_create -d cfg --uuid $cfg_uuid 2>- &cfg/***
# The most commonly used configuration cloning command that copies it from the
# parent scope working directory.
diff --git a/tests/pkg-build.testscript b/tests/pkg-build.testscript
index c3ae96f..7c3da32 100644
--- a/tests/pkg-build.testscript
+++ b/tests/pkg-build.testscript
@@ -596,6 +596,27 @@ test.arguments += --sys-no-query
error: repository '' cannot be masked: invalid repository location: empty URL
EOE
+ : mask-repository-uuid-db-not-found
+ :
+ $clone_root_cfg;
+ $* --mask-repository-uuid '00000000-0000-0000-0000-123456789012=repo' libfoo 2>>/EOE != 0
+ error: configuration repository '00000000-0000-0000-0000-123456789012=repo' cannot be masked: no configuration with uuid 00000000-0000-0000-0000-123456789012 is linked with cfg/
+ EOE
+
+ : mask-repository-uuid-empty
+ :
+ $clone_root_cfg;
+ $* --mask-repository-uuid "$cfg_uuid=" libfoo 2>>EOE != 0
+ error: configuration repository '00000000-0000-0000-0000-000000000001=' cannot be masked: invalid repository location '': empty URL
+ EOE
+
+ : mask-repository-uuid-not-found
+ :
+ $clone_root_cfg;
+ $* --mask-repository-uuid "$cfg_uuid=https://example.com/1" libfoo 2>>/EOE != 0
+ error: configuration repository '00000000-0000-0000-0000-000000000001=https://example.com/1' cannot be masked: repository location 'https://example.com/1' not found in configuration 00000000-0000-0000-0000-000000000001
+ EOE
+
: archive
:
$clone_root_cfg;
@@ -1825,12 +1846,17 @@ test.arguments += --sys-no-query
$pkg_status libbar >'!libbar configured 1.2.0';
- # While at it, test using --mask-repository instead of rep-remove.
+ # While at it, test using --mask-repository* instead of rep-remove.
#
$* --upgrade --mask-repository $rep/t2 --mask-repository $rep/t5 2>>/EOE != 0;
error: libbar is not available
EOE
+ $* --upgrade --mask-repository-uuid "$cfg_uuid=($rep/t2)" \
+ --mask-repository-uuid "$cfg_uuid=($rep/t5)" 2>>/EOE != 0;
+ error: libbar is not available
+ EOE
+
$rep_remove $rep/t2 $rep/t5;
$* --upgrade 2>>/EOE != 0;
@@ -3262,7 +3288,7 @@ test.arguments += --sys-no-query
: satisfy-masked
:
- : As above but using --mask-repository instead of rep-remove.
+ : As above but using --mask-repository* instead of rep-remove.
:
{
$clone_cfg;
@@ -3304,7 +3330,7 @@ test.arguments += --sys-no-query
# Test that the selected package is left as there is no satisfactory
# available package.
#
- $* --mask-repository $rep/t0b --mask-repository $rep/t0a ?libbaz;
+ $* --mask-repository $rep/t0b --mask-repository-uuid "$cfg_uuid=($rep/t0a)" ?libbaz;
# Test that the above behavior is not triggered for the system package.
#
@@ -3848,13 +3874,13 @@ test.arguments += --sys-no-query
: unavailable-masked
:
- : As above but using --mask-repository instead of rep-remove.
+ : As above but using --mask-repository* instead of rep-remove.
:
{
$clone_cfg;
$* libbar --mask-repository $rep/t0a --mask-repository $rep/t0b \
- --mask-repository $rep/t0c --recursive --yes
+ --mask-repository-uuid "$cfg_uuid=($rep/t0c)" --recursive --yes
}
-$pkg_drop libbar libbaz libfoo
@@ -17959,7 +17985,7 @@ else
: basics-masked
:
- : As above but using --mask-repository instead of rep-remove.
+ : As above but using --mask-repository* instead of rep-remove.
:
{
$clone_root_cfg;
@@ -18051,7 +18077,7 @@ else
# Noop.
#
- $* --mask-repository $cn --deorphan ?libfoo;
+ $* --mask-repository-uuid "$cfg_uuid=$cn" --deorphan ?libfoo;
$pkg_status -r libbar >>EOO;
!libbar configured 1.1.0