From c76874c5a1e57b4c3dc8d392f29b679d14a1d305 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Fri, 9 Feb 2018 23:57:09 +0300 Subject: Add git_reference class --- libbpkg/manifest.cxx | 37 ++++++++++++++++-- libbpkg/manifest.hxx | 50 +++++++++++++++++------- tests/repository-location/driver.cxx | 73 ++++++++++++++++++++++++------------ 3 files changed, 120 insertions(+), 40 deletions(-) diff --git a/libbpkg/manifest.cxx b/libbpkg/manifest.cxx index a972793..d7cf7cf 100644 --- a/libbpkg/manifest.cxx +++ b/libbpkg/manifest.cxx @@ -1770,9 +1770,9 @@ namespace bpkg } case repository_type::git: { - if (!url_.fragment) - throw invalid_argument ("missing branch/tag for git repository"); - + // Verify the URL fragment. + // + git_reference r (url_.fragment); break; } } @@ -1942,6 +1942,37 @@ namespace bpkg canonical_name_ += cp; } + // git_reference + // + git_reference:: + git_reference (const optional& frag) + { + if (frag) + { + const string& s (*frag); + + size_t p (s.find ('@')); + if (p != string::npos) + { + if (p != 0) + branch = string (s, 0, p); + + if (p + 1 != s.size ()) + commit = string (s, p + 1); + } + else if (!s.empty ()) + branch = s; + } + + if (!branch && !commit) + throw invalid_argument ( + "missing branch/tag or commit id for git repository"); + + if (commit && commit->size () != 40) + throw invalid_argument ( + "git repository commit id must be 40 characters long"); + } + // repository_manifest // repository_manifest:: diff --git a/libbpkg/manifest.hxx b/libbpkg/manifest.hxx index 8c20e76..9d19b2c 100644 --- a/libbpkg/manifest.hxx +++ b/libbpkg/manifest.hxx @@ -510,22 +510,24 @@ namespace bpkg // the URL matches the repository type. Throw std::invalid_argument if the // URL object is a relative local path. // - // @@ Note that the repository location string representation may differ - // from the original URL in the presence of the trailing slash. This - // may cause problems with some WEB servers that are sensitive to the - // trailing slash presence/absence. For example: + // Note that the repository location string representation may differ from + // the original URL in the presence of the trailing slash. This may cause + // problems with some WEB servers that are sensitive to the trailing slash + // presence/absence. For example: // - // $ git clone http://git.sv.gnu.org/r/config.git - // warning: redirecting to http://git.savannah.gnu.org/r/config.git/ + // $ git clone http://git.sv.gnu.org/r/config.git + // warning: redirecting to http://git.savannah.gnu.org/r/config.git/ // - // Also note that we disregard the slash presence/absence on multiple - // levels: + // Also note that we disregard the slash presence/absence on multiple + // levels: // - // - reduce absent path to an empty one in - // repository_url_traits::translate_scheme() (so a.com/ becomes a.com) - // - use path::*string() rather than path::*representation() functions - // in repository_url_traits::translate_*() functions - // - may append slash in repository_location ctor + // - reduce absent path to an empty one in + // repository_url_traits::translate_scheme() (so a.com/ becomes a.com) + // + // - use path::*string() rather than path::*representation() functions + // in repository_url_traits::translate_*() functions + // + // - may append slash in repository_location ctor // explicit repository_location (repository_url, repository_type); @@ -685,6 +687,28 @@ namespace bpkg return os << l.string (); } + // Branch and/or commit. At least one of them must be present. If both of + // them are present then the commit is expected to belong to the branch + // history. Note that the branch member can also denote a tag. + // + class LIBBPKG_EXPORT git_reference + { + public: + butl::optional branch; + butl::optional commit; + + public: + // Parse the [][@] repository URL fragment representation. + // + explicit + git_reference (const butl::optional&); + + git_reference (butl::optional b, + butl::optional c) + : branch (std::move (b)), + commit (std::move (c)) {} + }; + enum class repository_role { base, diff --git a/tests/repository-location/driver.cxx b/tests/repository-location/driver.cxx index 098ecab..e5a818a 100644 --- a/tests/repository-location/driver.cxx +++ b/tests/repository-location/driver.cxx @@ -150,7 +150,7 @@ namespace bpkg assert (bad_loc ("c:\\aaa\\bbb")); #endif - // No URL fragment. + // Invalid/absent URL fragment. // #ifndef _WIN32 assert (bad_loc ("file://localhost/", repository_type::git)); @@ -158,6 +158,18 @@ namespace bpkg assert (bad_loc ("file://localhost/c:/", repository_type::git)); #endif + assert (bad_loc ("https://www.example.com/test.git", + repository_type::git)); + + assert (bad_loc ("https://www.example.com/test.git#", + repository_type::git)); + + assert (bad_loc ("https://www.example.com/test.git#@", + repository_type::git)); + + assert (bad_loc ("https://www.example.com/test.git#@123", + repository_type::git)); + // Invalid version. // assert (bad_loc ("3/aaa/bbb")); @@ -410,25 +422,25 @@ namespace bpkg assert (l.type () == repository_type::bpkg); } { - repository_location l (loc ("git://github.com/test#master", + repository_location l (loc ("git://example.com/test#master", repository_type::git)); - assert (l.string () == "git://github.com/test#master"); - assert (l.canonical_name () == "git:github.com/test"); + assert (l.string () == "git://example.com/test#master"); + assert (l.canonical_name () == "git:example.com/test"); assert (l.proto () == proto::git); assert (l.type () == repository_type::git); } { - repository_location l (loc ("http://github.com/test.git#master", + repository_location l (loc ("http://example.com/test.git#master", repository_type::git)); - assert (l.string () == "http://github.com/test.git#master"); - assert (l.canonical_name () == "git:github.com/test"); + assert (l.string () == "http://example.com/test.git#master"); + assert (l.canonical_name () == "git:example.com/test"); assert (l.proto () == proto::http); } { - repository_location l (loc ("https://github.com/test.git#master", + repository_location l (loc ("https://example.com/test.git#master", repository_type::git)); - assert (l.string () == "https://github.com/test.git#master"); - assert (l.canonical_name () == "git:github.com/test"); + assert (l.string () == "https://example.com/test.git#master"); + assert (l.canonical_name () == "git:example.com/test"); assert (l.proto () == proto::https); assert (l.type () == repository_type::git); } @@ -487,22 +499,22 @@ namespace bpkg assert (l.canonical_name () == "bpkg:www.cppget.org/qw/a/b"); } { - repository_location l (loc ("https://git.github.com/test.git#master", + repository_location l (loc ("https://git.example.com/test.git#master", repository_type::git)); - assert (l.string () == "https://git.github.com/test.git#master"); - assert (l.canonical_name () == "git:github.com/test"); + assert (l.string () == "https://git.example.com/test.git#master"); + assert (l.canonical_name () == "git:example.com/test"); } { - repository_location l (loc ("https://scm.github.com/test.git#master", + repository_location l (loc ("https://scm.example.com/test.git#master", repository_type::git)); - assert (l.string () == "https://scm.github.com/test.git#master"); - assert (l.canonical_name () == "git:github.com/test"); + assert (l.string () == "https://scm.example.com/test.git#master"); + assert (l.canonical_name () == "git:example.com/test"); } { - repository_location l (loc ("https://www.github.com/test.git#master", + repository_location l (loc ("https://www.example.com/test.git#master", repository_type::git)); - assert (l.string () == "https://www.github.com/test.git#master"); - assert (l.canonical_name () == "git:github.com/test"); + assert (l.string () == "https://www.example.com/test.git#master"); + assert (l.canonical_name () == "git:example.com/test"); } { repository_location l (loc ("http://cppget.org/qw//1/a//b/")); @@ -711,14 +723,13 @@ namespace bpkg "http://cppget.org/foo/misc/stable"); } { - repository_location l ( - loc ("http://cppget.org/pkg/foo/1/misc/stable")); + repository_location l (loc ("http://cppget.org/pkg/foo/1/misc/stable")); assert (effective_url ("../..", l) == "http://cppget.org/pkg/foo/misc/stable"); } { - repository_location l (loc ("https://git.github.com/test.git#master", + repository_location l (loc ("https://git.example.com/test.git#master", repository_type::git)); assert (effective_url ("../..", l) == "../.."); } @@ -726,8 +737,7 @@ namespace bpkg repository_location l ( loc ("http://www.cppget.org/foo/bpkg/1/misc/stable")); - assert (effective_url ("../../..", l) == - "http://cppget.org/foo/misc"); + assert (effective_url ("../../..", l) == "http://cppget.org/foo/misc"); } { repository_location l (loc ("http://pkg.cppget.org/foo/pkg/1/misc")); @@ -741,6 +751,21 @@ namespace bpkg "http://cppget.org/foo/misc/abc"); } + // Repository URL fragments. + // + { + loc ("https://www.example.com/test.git#master", repository_type::git); + loc ("https://www.example.com/test.git#master@", repository_type::git); + + loc ("https://www.example.com/test.git#" + "@0a53e9ddeaddad63ad106860237bbf53411d11a7", + repository_type::git); + + loc ("https://www.example.com/test.git#" + "master@0a53e9ddeaddad63ad106860237bbf53411d11a7", + repository_type::git); + } + // repository_url // assert (repository_url ("git://example.com/test.git") == -- cgit v1.1