aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2018-02-09 23:57:09 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2018-02-12 17:23:38 +0300
commitc76874c5a1e57b4c3dc8d392f29b679d14a1d305 (patch)
treeac5226264355d73c74a1dc2e374b5369f81da02f
parentcc2efd2c70b1cdd28c375674c62f9d5f131f6908 (diff)
Add git_reference class
-rw-r--r--libbpkg/manifest.cxx37
-rw-r--r--libbpkg/manifest.hxx50
-rw-r--r--tests/repository-location/driver.cxx73
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<string>& 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<std::string> branch;
+ butl::optional<std::string> commit;
+
+ public:
+ // Parse the [<branch>][@<commit>] repository URL fragment representation.
+ //
+ explicit
+ git_reference (const butl::optional<std::string>&);
+
+ git_reference (butl::optional<std::string> b,
+ butl::optional<std::string> 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") ==