diff options
-rw-r--r-- | libbpkg/manifest.cxx | 45 | ||||
-rw-r--r-- | libbpkg/manifest.hxx | 37 | ||||
-rw-r--r-- | tests/repository-location/driver.cxx | 26 |
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")})); } |