aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbpkg/manifest.cxx45
-rw-r--r--libbpkg/manifest.hxx37
-rw-r--r--tests/repository-location/driver.cxx26
3 files changed, 73 insertions, 35 deletions
diff --git a/libbpkg/manifest.cxx b/libbpkg/manifest.cxx
index ab3acf1..78e3f2e 100644
--- a/libbpkg/manifest.cxx
+++ b/libbpkg/manifest.cxx
@@ -2320,36 +2320,43 @@ namespace bpkg
// git_ref_filter
//
git_ref_filter::
- git_ref_filter (const string& frag)
+ git_ref_filter (const string& rf)
{
- size_t p (frag.find ('@'));
+ exclusion = rf[0] == '-';
+
+ // Strip the leading +/-.
+ //
+ const string& s (exclusion || rf[0] == '+' ? string (rf, 1) : rf);
+
+ size_t p (s.find ('@'));
+
if (p != string::npos)
{
if (p != 0)
- name = string (frag, 0, p);
+ name = string (s, 0, p);
- if (p + 1 != frag.size ())
- commit = string (frag, p + 1);
+ if (p + 1 != s.size ())
+ commit = string (s, p + 1);
}
- else if (!frag.empty ())
+ else if (!s.empty ())
{
// A 40-characters fragment that consists of only hexadecimal digits is
// assumed to be a commit id.
//
- if (frag.size () == 40 &&
- find_if_not (frag.begin (), frag.end (),
+ if (s.size () == 40 &&
+ find_if_not (s.begin (), s.end (),
// Resolve the required overload.
//
- static_cast<bool (*)(char)> (xdigit)) == frag.end ())
- commit = frag;
+ static_cast<bool (*)(char)> (xdigit)) == s.end ())
+ commit = s;
else
- name = frag;
+ name = s;
}
if (!name && !commit)
throw invalid_argument (
- "missing reference name or commit id for git repository");
+ "missing refname or commit id for git repository");
if (commit && commit->size () != 40)
throw invalid_argument (
@@ -2357,10 +2364,20 @@ namespace bpkg
}
git_ref_filters
- parse_git_ref_filters (const string& s)
+ parse_git_ref_filters (const optional<string>& fs)
{
+ if (!fs)
+ return git_ref_filters ({git_ref_filter ()});
+
+ const string& s (*fs);
+
git_ref_filters r;
- for (size_t p (0); p != string::npos; )
+ bool def (s[0] == '#');
+
+ if (def)
+ r.push_back (git_ref_filter ());
+
+ for (size_t p (def ? 1 : 0); p != string::npos; )
{
size_t e (s.find (',', p));
r.emplace_back (string (s, p, e != string::npos ? e - p : e));
diff --git a/libbpkg/manifest.hxx b/libbpkg/manifest.hxx
index 3716670..68c4bc7 100644
--- a/libbpkg/manifest.hxx
+++ b/libbpkg/manifest.hxx
@@ -835,40 +835,51 @@ namespace bpkg
return os << l.string ();
}
- // Git refname and/or commit. At least one of them must be present. If both
- // are present then the commit is expected to belong to the history of the
- // specified ref (e.g., tag or branch). Note that the name member can also
- // be an abbreviated commit id (full, 40-character commit ids should always
- // be stored in the commit member since then may refer to an unadvertised
- // commit).
+ // Git refname/pattern and/or commit. If none of them is present then the
+ // default reference set is assumed. If both are present then the commit is
+ // expected to belong to the history of the specified refs (e.g., tag or
+ // branch). Note that the name member can also be an abbreviated commit id
+ // (full, 40-character commit ids should always be stored in the commit
+ // member since they may refer to an unadvertised commit).
//
class LIBBPKG_EXPORT git_ref_filter
{
public:
butl::optional<std::string> name;
butl::optional<std::string> commit;
+ bool exclusion = false;
public:
- // Parse the [<name>][@<commit>] repository URL fragment representation.
- // Throw std::invalid_argument if the filter representation format is
- // invalid.
+ git_ref_filter () = default; // Default reference set.
+
+ // Parse the [+|-][<name>][@<commit>] reference filter representation.
+ // Throw std::invalid_argument if the string is empty or the filter
+ // representation format is invalid.
//
explicit
git_ref_filter (const std::string&);
git_ref_filter (butl::optional<std::string> n,
- butl::optional<std::string> c)
+ butl::optional<std::string> c,
+ bool e)
: name (std::move (n)),
- commit (std::move (c)) {}
+ commit (std::move (c)),
+ exclusion (e) {}
+
+ bool
+ default_refs () const {return !name && !commit;}
};
using git_ref_filters = std::vector<git_ref_filter>;
- // Parse a comma-separated list of git reference filters. Throw
+ // Parse a comma-separated list of git reference filters. If the argument
+ // starts with the '#' character then prepend the resulting list with the
+ // default reference set filter (see above). If the argument is absent then
+ // return the list containing a single default reference set filter. Throw
// std::invalid_argument if the filter list format is invalid.
//
LIBBPKG_EXPORT git_ref_filters
- parse_git_ref_filters (const std::string&);
+ parse_git_ref_filters (const butl::optional<std::string>&);
enum class repository_role
{
diff --git a/tests/repository-location/driver.cxx b/tests/repository-location/driver.cxx
index ee8fba1..8916df9 100644
--- a/tests/repository-location/driver.cxx
+++ b/tests/repository-location/driver.cxx
@@ -103,7 +103,8 @@ namespace bpkg
inline static bool
operator== (const git_ref_filter& x, const git_ref_filter& y)
{
- return x.commit == y.commit && x.name == y.name;
+ return x.commit == y.commit && x.name == y.name &&
+ x.exclusion == y.exclusion;
}
int
@@ -825,16 +826,25 @@ namespace bpkg
string n ("master");
string c ("0a53e9ddeaddad63ad106860237bbf53411d11a7");
- assert (git_ref_filter (n) == git_ref_filter (n, nullopt));
- assert (git_ref_filter (c + "@") == git_ref_filter (c, nullopt));
- assert (git_ref_filter (c) == git_ref_filter (nullopt, c));
- assert (git_ref_filter ("@" + c) == git_ref_filter (nullopt, c));
- assert (git_ref_filter (n + "@" + c) == git_ref_filter (n, c));
+ assert (git_ref_filter () == git_ref_filter (nullopt, nullopt, false));
+ assert (git_ref_filter (n) == git_ref_filter (n, nullopt, false));
+ assert (git_ref_filter ('+' + n) == git_ref_filter (n, nullopt, false));
+ assert (git_ref_filter ('-' + n) == git_ref_filter (n, nullopt, true));
+ assert (git_ref_filter (c + "@") == git_ref_filter (c, nullopt, false));
+ assert (git_ref_filter (c) == git_ref_filter (nullopt, c, false));
+ assert (git_ref_filter ("@" + c) == git_ref_filter (nullopt, c, false));
+ assert (git_ref_filter (n + "@" + c) == git_ref_filter (n, c, false));
- assert (parse_git_ref_filters ("tag") ==
+ assert (parse_git_ref_filters (nullopt) ==
+ git_ref_filters {git_ref_filter ()});
+
+ assert (parse_git_ref_filters (string ("tag")) ==
git_ref_filters ({git_ref_filter ("tag")}));
- assert (parse_git_ref_filters ("a,b") ==
+ assert (parse_git_ref_filters (string ("#tag")) ==
+ git_ref_filters ({git_ref_filter (), git_ref_filter ("tag")}));
+
+ assert (parse_git_ref_filters (string ("a,b")) ==
git_ref_filters ({git_ref_filter ("a"), git_ref_filter ("b")}));
}