aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2017-12-21 18:16:16 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2017-12-28 17:34:22 +0300
commit87392531922fa91f05672eb4806735745b195588 (patch)
treec08f9a25d7062e39ad16d85021533ef5b1e68a47
parenta54a89072f6cfb6df2dcfbe4c34001656757e9e1 (diff)
Add support for git repository locations
-rw-r--r--libbpkg/manifest.cxx618
-rw-r--r--libbpkg/manifest.hxx201
-rw-r--r--tests/repository-location/driver.cxx1156
3 files changed, 1168 insertions, 807 deletions
diff --git a/libbpkg/manifest.cxx b/libbpkg/manifest.cxx
index e8034f3..b38f85b 100644
--- a/libbpkg/manifest.cxx
+++ b/libbpkg/manifest.cxx
@@ -10,9 +10,8 @@
#include <cassert>
#include <cstring> // strncmp(), strcmp()
#include <utility> // move()
-#include <cstdint> // uint64_t, uint16_t, UINT16_MAX
-#include <iterator> // back_insert_iterator
-#include <algorithm> // find(), transform()
+#include <cstdint> // uint16_t, UINT16_MAX
+#include <algorithm> // find(), replace()
#include <stdexcept> // invalid_argument
#include <libbutl/path.mxx>
@@ -447,6 +446,8 @@ namespace bpkg
string version::
string (bool ignore_revision) const
{
+ using std::to_string; // Hidden by to_string (repository_type).
+
if (empty ())
throw logic_error ("empty version");
@@ -1410,200 +1411,266 @@ namespace bpkg
s.next ("", ""); // End of stream.
}
- // url_parts
+ // repository_url_traits
//
- struct url_parts
+ repository_url_traits::scheme_type repository_url_traits::
+ translate_scheme (const string_type& url,
+ string_type&& scheme,
+ optional<authority_type>& authority,
+ optional<path_type>& path,
+ optional<string_type>& query,
+ optional<string_type>& fragment)
{
- using protocol = repository_location::protocol;
-
- protocol proto;
- string host;
- uint16_t port;
- dir_path path;
-
- explicit
- url_parts (const string&);
- };
-
- // Return the URL protocol, or nullopt if location is not a URL.
- //
- static optional<url_parts::protocol>
- is_url (const string& location)
- {
- using protocol = url_parts::protocol;
-
- optional<protocol> p;
- if (casecmp (location, "http://", 7) == 0)
- p = protocol::http;
- else if (casecmp (location, "https://", 8) == 0)
- p = protocol::https;
-
- return p;
- }
-
- static string
- to_string (url_parts::protocol proto,
- const string& host,
- uint16_t port,
- const dir_path& path)
- {
- string u (
- (proto == url_parts::protocol::http ? "http://" : "https://") + host);
-
- if (port != 0)
- u += ":" + std::to_string (port);
-
- if (!path.empty ())
- u += "/" + path.posix_string ();
-
- return u;
- }
-
- url_parts::
- url_parts (const string& s)
- {
- optional<protocol> pr (is_url (s));
- if (!pr)
- throw invalid_argument ("invalid protocol");
-
- proto = *pr;
+ auto bad_url = [] (const char* d = "invalid URL")
+ {
+ throw invalid_argument (d);
+ };
- string::size_type host_offset (s.find ("//"));
- assert (host_offset != string::npos);
- host_offset += 2;
+ auto translate_remote = [&authority, &path, &query, &fragment, &bad_url] ()
+ {
+ if (!authority || authority->host.empty ())
+ bad_url ("invalid host");
- string::size_type p (s.find ('/', host_offset));
+ if (authority->host.kind != url_host_kind::name)
+ bad_url ("unsupported host type");
- if (p != string::npos)
- // Chop the path part. Path is saved as a relative one to be of the
- // same type on different operating systems including Windows.
+ // Normalize the host name.
//
- path = dir_path (s, p + 1, string::npos);
+ lcase (authority->host.value);
- // Put the lower-cased version of the host part into host.
- // Chances are good it will stay unmodified.
- //
- transform (s.cbegin () + host_offset,
- p == string::npos ? s.cend () : s.cbegin () + p,
- back_inserter (host),
- static_cast<char (*) (char)> (lcase));
+ // We don't distinguish between the absent and empty paths for the
+ // remote repository URLs.
+ //
+ if (!path)
+ path = path_type ();
- // Validate host name according to "2.3.1. Preferred name syntax" and
- // "2.3.4. Size limits" of https://tools.ietf.org/html/rfc1035.
- //
- // Check that there is no empty labels and ones containing chars
- // different from alpha-numeric and hyphen. Label should start from
- // letter, do not end with hypen and be not longer than 63 chars.
- // Total host name length should be not longer than 255 chars.
- //
- auto hb (host.cbegin ());
- auto he (host.cend ());
- auto ls (hb); // Host domain name label begin.
- auto pt (he); // Port begin.
+ if (path->absolute ())
+ bad_url ("absolute path");
+ };
- for (auto i (hb); i != he; ++i)
+ if (casecmp (scheme, "http") == 0)
{
- char c (*i);
-
- if (pt == he) // Didn't reach port specification yet.
+ translate_remote ();
+ return scheme_type::http;
+ }
+ else if (casecmp (scheme, "https") == 0)
+ {
+ translate_remote ();
+ return scheme_type::https;
+ }
+ else if (casecmp (scheme, "git") == 0)
+ {
+ translate_remote ();
+ return scheme_type::git;
+ }
+ else if (casecmp (scheme, "file") == 0)
+ {
+ if (authority)
{
- if (c == ':') // Port specification reached.
- pt = i;
- else
- {
- auto n (i + 1);
+ if (!authority->empty () &&
+ (casecmp (authority->host, "localhost") != 0 ||
+ authority->port != 0 ||
+ !authority->user.empty ()))
+ throw invalid_argument ("invalid authority");
+
+ // We don't distinguish between the absent, empty and localhost
+ // authorities for the local repository locations.
+ //
+ authority = nullopt;
+ }
- // Validate host name.
- //
+ if (!path)
+ bad_url ("absent path");
- // Is first label char.
- //
- bool flc (i == ls);
+ // On POSIX make the relative (to the authority "root") path absolute. On
+ // Windows it must already be an absolute path.
+ //
+#ifndef _WIN32
+ if (path->absolute ())
+ bad_url ("absolute path");
- // Is last label char.
- //
- bool llc (n == he || *n == '.' || *n == ':');
+ path = path_type ("/") / *path;
+#else
+ if (path->relative ())
+ bad_url ("relative path");
+#endif
- // Validate char.
- //
- bool valid (alpha (c) ||
- (digit (c) && !flc) ||
- ((c == '-' || c == '.') && !flc && !llc));
+ if (query)
+ bad_url ();
- // Validate length.
- //
- if (valid)
- valid = i - ls < 64 && i - hb < 256;
+ return scheme_type::file;
+ }
+ // Consider URL as a path if the URL parsing failed.
+ //
+ else if (scheme.empty ())
+ {
+ try
+ {
+ path = path_type (url);
+ }
+ catch (const invalid_path&)
+ {
+ // If this is not a valid path either, then let's consider the argument
+ // a broken URL, and leave the basic_url ctor to throw.
+ //
+ }
- if (!valid)
- throw invalid_argument ("invalid host");
+ return scheme_type::file;
+ }
+ else
+ throw invalid_argument ("unknown scheme");
+ }
- if (c == '.')
- ls = n;
- }
- }
- else
+ repository_url_traits::string_type repository_url_traits::
+ translate_scheme (string_type& url,
+ const scheme_type& scheme,
+ const optional<authority_type>& /*authority*/,
+ const optional<path_type>& path,
+ const optional<string_type>& /*query*/,
+ const optional<string_type>& fragment)
+ {
+ switch (scheme)
+ {
+ case scheme_type::http: return "http";
+ case scheme_type::https: return "https";
+ case scheme_type::git: return "git";
+ case scheme_type::file:
{
- // Validate port.
+ // If there is no fragment present then represent the URL object as a
+ // local path.
//
- if (!digit (c))
- throw invalid_argument ("invalid port");
+ assert (path);
+
+ if (fragment)
+ {
+ assert (path->absolute ());
+ return "file";
+ }
+
+ url = path->relative () ? path->posix_string () : path->string ();
+ return string_type ();
}
}
- // Chop the port, if present.
- //
- if (pt == he)
- port = 0;
- else
+ assert (false); // Can't be here.
+ return "";
+ }
+
+ repository_url_traits::path_type repository_url_traits::
+ translate_path (string_type&& path)
+ {
+ try
+ {
+ return path_type (move (path));
+ }
+ catch (const invalid_path&)
{
- unsigned long long n (++pt == he ? 0 : stoull (string (pt, he)));
- if (n == 0 || n > UINT16_MAX)
- throw invalid_argument ("invalid port");
+ throw invalid_argument ("invalid url");
+ }
+ }
- port = static_cast<uint16_t> (n);
- host.resize (pt - hb - 1);
+ repository_url_traits::string_type repository_url_traits::
+ translate_path (const path_type& path)
+ {
+ // If the path is absolute then this is a local URL object and the file://
+ // URL notation is being produced. Thus, on POSIX we need to make the path
+ // relative (to the authority "root"). On Windows the path should stay
+ // absolute but the directory separators must be converted to the POSIX
+ // ones.
+ //
+ if (path.absolute ())
+ {
+#ifndef _WIN32
+ return path.leaf (dir_path ("/")).string ();
+#else
+ string r (path.string ());
+ replace (r.begin (), r.end (), '\\', '/');
+ return r;
+#endif
+ }
+
+ return path.posix_string ();
+ }
+
+ // repository_type
+ //
+ string
+ to_string (repository_type t)
+ {
+ switch (t)
+ {
+ case repository_type::bpkg: return "bpkg";
+ case repository_type::git: return "git";
}
- if (host.empty ())
- throw invalid_argument ("invalid host");
+ assert (false); // Can't be here.
+ return string ();
+ }
+
+ repository_type
+ to_repository_type (const string& t)
+ {
+ if (t == "bpkg") return repository_type::bpkg;
+ else if (t == "git") return repository_type::git;
+ else throw invalid_argument ("invalid repository type '" + t + "'");
}
// repository_location
//
static string
- strip_domain (const string& host)
+ strip_domain (const string& host, repository_type type)
{
assert (!host.empty ()); // Should be repository location host.
- string h;
- bool bpkg (false);
+ optional<string> h;
- if (host.compare (0, 4, "www.") == 0 ||
- host.compare (0, 4, "pkg.") == 0 ||
- (bpkg = host.compare (0, 5, "bpkg.") == 0))
+ switch (type)
{
- if (h.assign (host, bpkg ? 5 : 4, string::npos).empty ())
- throw invalid_argument ("invalid host");
+ case repository_type::bpkg:
+ {
+ bool bpkg (false);
+ if (host.compare (0, 4, "www.") == 0 ||
+ host.compare (0, 4, "pkg.") == 0 ||
+ (bpkg = host.compare (0, 5, "bpkg.") == 0))
+ h = string (host, bpkg ? 5 : 4);
+
+ break;
+ }
+ case repository_type::git:
+ {
+ if (host.compare (0, 4, "www.") == 0 ||
+ host.compare (0, 4, "git.") == 0 ||
+ host.compare (0, 4, "scm.") == 0)
+ h = string (host, 4);
+
+ break;
+ }
}
- else
- h = host;
- return h;
+ if (h && h->empty ())
+ throw invalid_argument ("invalid host");
+
+ return h ? *h : host;
}
- // The 'pkg' path component stripping mode.
+ // The 'pkg' path component and '.git' extension stripping mode.
//
- enum class strip_mode {version, component, path};
+ enum class strip_mode {version, component, path, extension};
- static dir_path
- strip_path (const dir_path& path, strip_mode mode)
+ static path
+ strip_path (const path& p, strip_mode mode)
{
- // Should be repository location path.
+ if (mode == strip_mode::extension)
+ {
+ const char* e (p.extension_cstring ());
+ return e != nullptr && strcmp (e, "git") == 0 ? p.base () : p;
+ }
+
+ // Should be bpkg repository location path.
//
- assert (!path.empty () && *path.begin () != "..");
+ assert (!p.empty () && *p.begin () != "..");
- auto rb (path.rbegin ()), i (rb), re (path.rend ());
+ auto rb (p.rbegin ()), i (rb), re (p.rend ());
// Find the version component.
//
@@ -1623,7 +1690,7 @@ namespace bpkg
if (stoul (*i) != 1)
throw invalid_argument ("unsupported repository version");
- dir_path res (rb, i);
+ path res (rb, i);
// Canonical name prefix part ends with the special "pkg" component.
//
@@ -1633,30 +1700,31 @@ namespace bpkg
++i; // Strip the "pkg" component.
if (!pc || mode != strip_mode::path)
- res = dir_path (i, re) / res; // Concatenate prefix and path parts.
+ res = path (i, re) / res; // Concatenate prefix and path parts.
return res;
}
- // Location parameter type is fully qualified as compiler gets confused with
- // string() member.
- //
repository_location::
- repository_location (const std::string& l)
- : repository_location (l, repository_location ()) // Delegate.
+ repository_location (repository_url u, repository_type t)
+ : repository_location (move (u), t, repository_location ()) // Delegate.
{
if (!empty () && relative ())
throw invalid_argument ("relative filesystem path");
}
repository_location::
- repository_location (const std::string& l, const repository_location& b)
+ repository_location (repository_url u,
+ repository_type t,
+ const repository_location& b)
+ : url_ (move (u)),
+ type_ (t)
{
- // Otherwise compiler gets confused with string() member.
- //
- using std::string;
+ using std::string; // Hidden by string().
+ using std::to_string; // Hidden by to_string(repository_type).
+ using butl::path; // Hidden by path().
- if (l.empty ())
+ if (url_.empty ())
{
if (!b.empty ())
throw invalid_argument ("empty location");
@@ -1664,42 +1732,100 @@ namespace bpkg
return;
}
- // Base repository location can not be a relative path.
+ // Make sure that the URL object is properly constructed (see notes for the
+ // repository_url class in the header).
//
- if (!b.empty () && b.relative ())
- throw invalid_argument ("base relative filesystem path");
+ assert (url_.path &&
+ remote () == (url_.authority && !url_.authority->empty ()));
- if (is_url (l))
+ // Verify that the URL object matches the repository type.
+ //
+ switch (t)
{
- url_parts u (l);
- proto_ = u.proto;
- host_ = move (u.host);
- port_ = u.port;
- path_ = move (u.path);
+ case repository_type::bpkg:
+ {
+ if (url_.scheme == repository_protocol::git)
+ throw invalid_argument ("unsupported scheme for bpkg repository");
+
+ break;
+ }
+ case repository_type::git:
+ {
+ if (!url_.fragment)
+ throw invalid_argument ("missing branch/tag for git repository");
+
+ break;
+ }
+ }
+
+ // Base repository location is only meaningful for bpkg repository, and
+ // can not be a relative path.
+ //
+ if (!b.empty ())
+ {
+ if (type_ != repository_type::bpkg)
+ throw invalid_argument ("unexpected base location");
+
+ if (b.type () != repository_type::bpkg)
+ throw invalid_argument ("invalid base location");
+
+ if (b.relative ())
+ throw invalid_argument ("base location is relative filesystem path");
+ }
+
+ path& up (*url_.path);
+
+ // For the repositories that are "directories", make sure that the URL
+ // object's path is a directory (contains the trailing slash).
+ //
+ switch (t)
+ {
+ case repository_type::bpkg:
+ case repository_type::git:
+ {
+ if (!up.to_directory ())
+ up = path_cast<dir_path> (move (up));
+ break;
+ }
+ }
- canonical_name_ = strip_domain (host_);
+ if (remote ())
+ {
+ canonical_name_ = strip_domain (url_.authority->host, type_);
// For canonical name and for the HTTP protocol, treat a.com and
- // a.com:80 as the same name. The same rule applies to the HTTPS
- // protocol and port 443.
+ // a.com:80 as the same name. The same rule applies to the HTTPS (port
+ // 443) and GIT (port 9418) protocols.
//
- if (port_ != 0 && port_ != (proto_ == protocol::http ? 80 : 443))
- canonical_name_ += ':' + std::to_string (port_);
+ uint16_t port (url_.authority->port);
+ if (port != 0)
+ {
+ uint16_t def_port;
+
+ switch (url_.scheme)
+ {
+ case repository_protocol::http: def_port = 80; break;
+ case repository_protocol::https: def_port = 443; break;
+ case repository_protocol::git: def_port = 9418; break;
+ case repository_protocol::file: assert (false); // Can't be here.
+ }
+
+ if (port != def_port)
+ canonical_name_ += ':' + to_string (port);
+ }
}
else
{
- path_ = dir_path (l);
-
// Complete if we are relative and have base.
//
- if (!b.empty () && path_.relative ())
+ if (!b.empty () && up.relative ())
{
// Convert the relative path location to an absolute or remote one.
//
- proto_ = b.proto_;
- host_ = b.host_;
- port_ = b.port_;
- path_ = b.path_ / path_;
+ repository_url u (b.url ());
+ *u.path /= up;
+
+ url_ = move (u);
// Set canonical name to the base location canonical name host
// part. The path part of the canonical name is calculated below.
@@ -1716,26 +1842,27 @@ namespace bpkg
//
try
{
- path_.normalize ();
+ up.normalize ();
}
catch (const invalid_path&)
{
throw invalid_argument ("invalid path");
}
- // Need to check path for emptiness before proceeding further as a valid
- // non empty location can not have an empty path_ member (which can be the
- // case for the remote location, but not for the relative or absolute).
+ // For bpkg repository we need to check path for emptiness before
+ // proceeding further as a valid non empty location can not have an empty
+ // URL object path member (which can be the case for the remote location,
+ // but not for the relative or absolute).
//
- if (path_.empty ())
+ if (type_ == repository_type::bpkg && up.empty ())
throw invalid_argument ("empty path");
// Need to check that URL path do not go past the root directory of a WEB
// server. We can not rely on the above normalize() function call doing
- // this check as soon as path_ member contains a relative directory for the
- // remote location.
+ // this check as soon as URL object path member contains a relative
+ // directory for the remote location.
//
- if (remote () && *path_.begin () == "..")
+ if (remote () && !up.empty () && *up.begin () == "..")
throw invalid_argument ("invalid path");
// Finish calculating the canonical name, unless we are relative.
@@ -1746,19 +1873,29 @@ namespace bpkg
return;
}
- // Canonical name <prefix>/<path> part.
+ // Canonical name <prefix>/<path> part for the bpkg repository, and the
+ // full path with the .git extension stripped for the git repository.
//
- dir_path sp (strip_path (
- path_, remote () ? strip_mode::component : strip_mode::path));
+ path sp;
- // If for an absolute path location the stripping result is empty (which
- // also means <path> part is empty as well) then fallback to stripping
- // just the version component.
- //
- if (absolute () && sp.empty ())
- sp = strip_path (path_, strip_mode::version);
+ if (type_ == repository_type::bpkg)
+ {
+ sp = strip_path (up,
+ remote ()
+ ? strip_mode::component
+ : strip_mode::path);
+
+ // If for an absolute path location the stripping result is empty (which
+ // also means <path> part is empty as well) then fallback to stripping
+ // just the version component.
+ //
+ if (absolute () && sp.empty ())
+ sp = strip_path (up, strip_mode::version);
+ }
+ else
+ sp = strip_path (up, strip_mode::extension);
- string cp (sp.relative () ? sp.posix_string () : sp.string ());
+ string cp (sp.relative () ? sp.posix_string () : sp.string ());
// Note: allow empty paths (e.g., http://stable.cppget.org/1/).
//
@@ -1773,18 +1910,6 @@ namespace bpkg
throw invalid_argument ("empty repository name");
}
- string repository_location::
- string () const
- {
- if (empty ())
- return std::string (); // Also function name.
-
- if (local ())
- return relative () ? path_.posix_string () : path_.string ();
-
- return to_string (proto_, host_, port_, path_);
- }
-
// repository_manifest
//
repository_manifest::
@@ -1834,7 +1959,8 @@ namespace bpkg
// Call prerequisite repository location constructor, do not
// ammend relative path.
//
- location = repository_location (move (v), repository_location ());
+ location = repository_location (repository_url (move (v)),
+ repository_location ());
}
catch (const invalid_argument& e)
{
@@ -1947,7 +2073,12 @@ namespace bpkg
s.next ("", "1"); // Start of manifest.
if (!location.empty ())
+ {
+ if (location.remote () && location.type () != repository_type::bpkg)
+ bad_value ("invalid repository location");
+
s.next ("location", location.string ());
+ }
if (role)
{
@@ -2023,27 +2154,33 @@ namespace bpkg
optional<string> repository_manifest::
effective_url (const repository_location& l) const
{
+ static const char* invalid_location ("invalid repository location");
+
+ if (l.local () || l.type () != repository_type::bpkg)
+ throw invalid_argument (invalid_location);
+
if (!url || (*url)[0] != '.')
return url;
- const dir_path rp (*url);
+ const path rp (*url);
auto i (rp.begin ());
static const char* invalid_url ("invalid relative url");
- auto strip ([&i, &rp]() -> bool {
- if (i != rp.end ())
- {
- const auto& c (*i++);
- if (c == "..")
- return true;
+ auto strip = [&i, &rp]() -> bool
+ {
+ if (i != rp.end ())
+ {
+ const auto& c (*i++);
+ if (c == "..")
+ return true;
- if (c == ".")
- return false;
- }
+ if (c == ".")
+ return false;
+ }
- throw invalid_argument (invalid_url);
- });
+ throw invalid_argument (invalid_url);
+ };
bool strip_d (strip ()); // Strip domain.
bool strip_p (strip ()); // Strip path.
@@ -2051,10 +2188,14 @@ namespace bpkg
// The web interface relative path with the special first two components
// stripped.
//
- const dir_path rpath (i, rp.end ());
+ const path rpath (i, rp.end ());
assert (rpath.relative ());
- url_parts u (l.string ());
+ repository_url u (l.url ());
+
+ if (strip_d)
+ u.authority->host.value = strip_domain (u.authority->host,
+ repository_type::bpkg);
// Web interface URL path part.
//
@@ -2063,12 +2204,11 @@ namespace bpkg
// repository location http://a.com/foo/pkg/1/math will wrongly be
// http://a.com/foo/pkg instead of http://a.com.
//
- dir_path ipath (
- strip_path (
- u.path,
- strip_p ? strip_mode::component : strip_mode::version) / rpath);
-
- static const char* invalid_location ("invalid repository location");
+ path ipath (strip_path (*u.path,
+ strip_p
+ ? strip_mode::component
+ : strip_mode::version) /
+ rpath);
try
{
@@ -2084,8 +2224,10 @@ namespace bpkg
if (!ipath.empty () && *ipath.begin () == "..")
throw invalid_argument (invalid_location);
- return to_string (
- u.proto, strip_d ? strip_domain (u.host) : u.host, u.port, ipath);
+ // Strip the trailing slash for an empty path.
+ //
+ u.path = !ipath.empty () ? move (ipath) : optional<path> ();
+ return u.string ();
}
// repository_manifests
@@ -2118,7 +2260,7 @@ namespace bpkg
throw serialization (s.name (), "base repository manifest expected");
// @@ Should we check that there is location in all except the last
- // entry?
+ // entry?
//
for (const repository_manifest& r: *this)
r.serialize (s);
diff --git a/libbpkg/manifest.hxx b/libbpkg/manifest.hxx
index a72986a..7f5bcda 100644
--- a/libbpkg/manifest.hxx
+++ b/libbpkg/manifest.hxx
@@ -13,6 +13,7 @@
#include <utility> // move()
#include <stdexcept> // logic_error
+#include <libbutl/url.mxx>
#include <libbutl/path.mxx>
#include <libbutl/optional.mxx>
#include <libbutl/manifest-forward.hxx>
@@ -422,6 +423,95 @@ namespace bpkg
serialize (butl::manifest_serializer&) const;
};
+ // Traits class for the repository URL object.
+ //
+ enum class repository_protocol {file, http, https, git};
+
+ struct LIBBPKG_EXPORT repository_url_traits
+ {
+ using string_type = std::string;
+ using path_type = butl::path;
+
+ using scheme_type = repository_protocol;
+ using authority_type = butl::basic_url_authority<string_type>;
+
+ static scheme_type
+ translate_scheme (const string_type&,
+ string_type&&,
+ butl::optional<authority_type>&,
+ butl::optional<path_type>&,
+ butl::optional<string_type>&,
+ butl::optional<string_type>&);
+
+
+ static string_type
+ translate_scheme (string_type&,
+ const scheme_type&,
+ const butl::optional<authority_type>&,
+ const butl::optional<path_type>&,
+ const butl::optional<string_type>&,
+ const butl::optional<string_type>&);
+
+ static path_type
+ translate_path (string_type&&);
+
+ static string_type
+ translate_path (const path_type&);
+ };
+
+ // Repository URL. Note that it represents both the remote (http(s)://,
+ // git://, etc) and local (file:// as well as plain directory path)
+ // repository URLs. May also be empty.
+ //
+ // Notes:
+ //
+ // - For an empty URL object all components are absent. For a non-empty one
+ // the directory path is always present and normalized.
+ //
+ // - For the remote URL object the host name is in the lower case (IPv4/6 are
+ // not supported) and the path is relative.
+ //
+ // - For the local URL object the path can be relative or absolute. Query
+ // can not be present. Fragment can not be present for the relative path
+ // as there is no notation that can be used to represent it.
+ //
+ struct LIBBPKG_EXPORT repository_url: butl::basic_url<repository_protocol,
+ repository_url_traits>
+ {
+ using base_type = basic_url<repository_protocol, repository_url_traits>;
+
+ using base_type::base_type;
+
+ // Create an empty URL object.
+ //
+ repository_url () = default;
+
+ // If the argument is an empty string, then create an empty URL object. If
+ // the argument is a local path or a file URL then create a local URL
+ // object. Otherwise create a remote URL object.
+ //
+ // May throw std::invalid_argument (unknown URL schema, incorrect syntax,
+ // unexpected components, etc).
+ //
+ repository_url (const string_type& s): base_type (s) {}
+ };
+
+ // Repository type.
+ //
+ enum class repository_type {bpkg, git};
+
+ LIBBPKG_EXPORT std::string
+ to_string (repository_type);
+
+ LIBBPKG_EXPORT repository_type
+ to_repository_type (const std::string&); // May throw std::invalid_argument.
+
+ inline std::ostream&
+ operator<< (std::ostream& os, repository_type t)
+ {
+ return os << to_string (t);
+ }
+
class LIBBPKG_EXPORT repository_location
{
public:
@@ -429,28 +519,29 @@ namespace bpkg
//
repository_location () = default;
- // If the argument is not empty, create remote/absolute repository
- // location. Throw std::invalid_argument if the location is a relative
- // path. If the argument is empty, then create the special empty
- // location.
+ // Create remote, absolute or empty repository location making sure that
+ // the URL matches the repository type. Throw std::invalid_argument if the
+ // URL object is a relative local path.
//
explicit
- repository_location (const std::string&);
+ repository_location (repository_url, repository_type);
- // Create a potentially relative repository location. If base is not
- // empty, use it to complete the relative location to remote/absolute.
- // Throw std::invalid_argument if base is not empty but the location is
- // empty, base itself is relative, or the resulting completed location
+ // Create a potentially relative bpkg repository location. If base is not
+ // empty, use it to complete the relative location to the remote/absolute
+ // one. Throw std::invalid_argument if base is not empty but the location
+ // is empty, base itself is relative, or the resulting completed location
// is invalid.
//
- repository_location (const std::string&, const repository_location& base);
+ repository_location (repository_url u,
+ const repository_location& base)
+ : repository_location (std::move (u), repository_type::bpkg, base) {}
repository_location (const repository_location& l,
const repository_location& base)
- : repository_location (l.string (), base) {}
+ : repository_location (l.url (), l.type (), base) {}
- // Note that relative locations have no canonical name. Canonical
- // name of an empty location is the empty name.
+ // Note that relative locations have no canonical name. Canonical name of
+ // an empty location is the empty name.
//
const std::string&
canonical_name () const noexcept {return canonical_name_;}
@@ -462,7 +553,7 @@ namespace bpkg
// other predicates throw std::logic_error for an empty location.
//
bool
- empty () const noexcept {return path_.empty ();}
+ empty () const noexcept {return url_.empty ();}
bool
local () const
@@ -470,7 +561,7 @@ namespace bpkg
if (empty ())
throw std::logic_error ("empty location");
- return host_.empty ();
+ return url_.scheme == repository_protocol::file;
}
bool
@@ -487,22 +578,42 @@ namespace bpkg
// Note that in remote locations path is always relative.
//
- return path_.absolute ();
+ return url_.path->absolute ();
}
bool
relative () const
{
- return local () && path_.relative ();
+ return local () && url_.path->relative ();
+ }
+
+ repository_type
+ type () const
+ {
+ if (empty ())
+ throw std::logic_error ("empty location");
+
+ return type_;
+ }
+
+ // URL of an empty location is empty.
+ //
+ repository_url
+ url () const
+ {
+ return url_;
}
- const butl::dir_path&
+ // Repository path. Note that for repository types that refer to
+ // "directories" it always contains the trailing slash.
+ //
+ const butl::path&
path () const
{
if (empty ())
throw std::logic_error ("empty location");
- return path_;
+ return *url_.path;
}
const std::string&
@@ -511,7 +622,7 @@ namespace bpkg
if (local ())
throw std::logic_error ("local location");
- return host_;
+ return url_.authority->host;
}
// Value 0 indicated that no port was specified explicitly.
@@ -522,34 +633,46 @@ namespace bpkg
if (local ())
throw std::logic_error ("local location");
- return port_;
+ return url_.authority->port;
}
- enum class protocol {http, https};
-
- protocol
+ repository_protocol
proto () const
{
- if (local ())
- throw std::logic_error ("local location");
+ if (empty ())
+ throw std::logic_error ("empty location");
- return proto_;
+ return url_.scheme;
}
- // Note that this is not necessarily syntactically the same string
- // as what was used to initialize this location. But it should be
- // semantically equivalent. String representation of an empty
- // location is the empty string.
+ const butl::optional<std::string>&
+ fragment () const
+ {
+ if (relative ())
+ throw std::logic_error ("relative filesystem path");
+
+ return url_.fragment;
+ }
+
+ // String representation of an empty location is the empty string.
//
std::string
- string () const;
+ string () const
+ {
+ return url_.string ();
+ }
+
+ private:
+ // Used for delegating in public constructor.
+ //
+ repository_location (repository_url,
+ repository_type,
+ const repository_location& base);
private:
std::string canonical_name_;
- protocol proto_;
- std::string host_;
- std::uint16_t port_;
- butl::dir_path path_;
+ repository_url url_;
+ repository_type type_;
};
inline std::ostream&
@@ -570,7 +693,7 @@ namespace bpkg
public:
using email_type = bpkg::email;
- repository_location location;
+ repository_location location; // bpkg repository location.
butl::optional<repository_role> role;
// The following values may only be present for the base repository.
@@ -594,8 +717,8 @@ namespace bpkg
effective_role () const;
// Return the effective web interface URL based on the specified remote
- // repository location. If url is not present or doesn't start with '.',
- // then return it unchanged. Otherwise, process the relative format
+ // bpkg repository location. If url is not present or doesn't start with
+ // '.', then return it unchanged. Otherwise, process the relative format
// as described in the manifest specification. Throw std::invalid_argument
// if the relative url format is invalid or if the repository location is
// empty or local.
diff --git a/tests/repository-location/driver.cxx b/tests/repository-location/driver.cxx
index a12adad..0f7cfb1 100644
--- a/tests/repository-location/driver.cxx
+++ b/tests/repository-location/driver.cxx
@@ -6,10 +6,8 @@
#include <cassert>
#include <sstream>
#include <iostream>
-#include <exception>
-#include <stdexcept> // invalid_argument
+#include <stdexcept> // invalid_argument, logic_error
-#include <libbutl/utility.mxx> // operator<<(ostream, exception)
#include <libbutl/optional.mxx>
#include <libbutl/manifest-parser.mxx>
@@ -22,12 +20,30 @@ namespace bpkg
{
using butl::optional;
- static bool
- bad_location (const string& l)
+ inline static repository_location
+ loc ()
+ {
+ return repository_location ();
+ }
+
+ inline static repository_location
+ loc (const string& l, repository_type t = repository_type::bpkg)
+ {
+ return repository_location (repository_url (l), t);
+ }
+
+ inline static repository_location
+ loc (const string& l, const repository_location& b)
+ {
+ return repository_location (repository_url (l), b);
+ }
+
+ inline static bool
+ bad_loc (const string& l, repository_type t = repository_type::bpkg)
{
try
{
- repository_location bl (l);
+ repository_location bl (repository_url (l), t);
return false;
}
catch (const invalid_argument&)
@@ -36,12 +52,12 @@ namespace bpkg
}
}
- static bool
- bad_location (const string& l, const repository_location& b)
+ inline static bool
+ bad_loc (const string& l, const repository_location& b)
{
try
{
- repository_location bl (l, b);
+ repository_location bl (repository_url (l), b);
return false;
}
catch (const invalid_argument&)
@@ -62,7 +78,7 @@ namespace bpkg
return *u;
}
- static bool
+ inline static bool
bad_url (const string& l, const repository_location& r)
{
try
@@ -82,7 +98,7 @@ namespace bpkg
int
main (int argc, char* argv[])
{
- using protocol = repository_location::protocol;
+ using proto = repository_protocol;
if (argc != 1)
{
@@ -90,553 +106,633 @@ namespace bpkg
return 1;
}
- try
- {
- // Test invalid locations.
- //
- // Invalid host.
- //
- assert (bad_location ("http:///aa/bb"));
- assert (bad_location ("http://1/aa/bb"));
- assert (bad_location ("http:///1/aa/bb"));
- assert (bad_location ("http://1a/aa/bb"));
- assert (bad_location ("http://a..a/aa/bb"));
- assert (bad_location ("http://.a.a/aa/bb"));
- assert (bad_location ("http://a.a./aa/bb"));
- assert (bad_location ("http://a.1a/aa/bb"));
- assert (bad_location ("http://a.1a.a/aa/bb"));
- assert (bad_location ("http://a.-ab/aa/bb"));
- assert (bad_location ("http://a.-ab.a/aa/bb"));
- assert (bad_location ("http://a.ab-/aa/bb"));
- assert (bad_location ("http://a.ab-.a/aa/bb"));
- assert (bad_location ("http://a.ab-:80/aa/bb"));
- assert (bad_location ("http://a.ab.:80/aa/bb"));
- assert (bad_location ("http://1.1.1.1.r/1/b"));
- assert (bad_location ("http://www./aa/1/bb"));
-
- assert (
- bad_location ("http://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
- "aaaaaaaaaaaaaaaaaaaa.org/1/b/"));
-
- // Invalid port.
- //
- assert (bad_location ("http://a:/aa/bb"));
- assert (bad_location ("http://a:1b/aa/bb"));
- assert (bad_location ("http://c.ru:8a80/1/b"));
- assert (bad_location ("http://c.ru:8:80/1/b"));
- assert (bad_location ("http://a:0/aa/bb"));
- assert (bad_location ("http://c.ru:65536/1/b"));
-
- // Invalid path.
- //
- assert (
- bad_location ("",
- repository_location (
- "http://stable.cppget.org/1/misc")));
-
- assert (bad_location ("1"));
- assert (bad_location ("1/"));
- assert (bad_location ("1/.."));
- assert (bad_location ("bbb"));
- assert (bad_location ("aaa/bbb"));
- assert (bad_location ("http://aa"));
- assert (bad_location ("https://aa"));
- assert (bad_location ("http://aa/"));
- assert (bad_location ("http://aa/b/.."));
- assert (bad_location ("http://aa/."));
- assert (bad_location ("http://aa/bb"));
- assert (bad_location ("http://a.com/../c/1/aa"));
- assert (bad_location ("http://a.com/a/b/../../../c/1/aa"));
+ // Test invalid locations.
+ //
+ // Invalid host.
+ //
+ assert (bad_loc ("http:///aa/1/bb"));
+ assert (bad_loc ("http:///1/aa/bb"));
+ assert (bad_loc ("http://www./aa/1/bb"));
+ assert (bad_loc ("http://b|2.org/aa/1/bb"));
+ assert (bad_loc ("file://abc/"));
+
+ // Invalid port.
+ //
+ assert (bad_loc ("http://a:/aa/bb"));
+ assert (bad_loc ("http://a:1b/aa/bb"));
+ assert (bad_loc ("http://c.ru:8a80/1/b"));
+ assert (bad_loc ("http://c.ru:8:80/1/b"));
+ assert (bad_loc ("http://a:0/aa/bb"));
+ assert (bad_loc ("http://c.ru:65536/1/b"));
+
+ // Invalid path.
+ //
+ assert (bad_loc ("", loc ("http://stable.cppget.org/1/misc")));
+ assert (bad_loc ("1"));
+ assert (bad_loc ("1/"));
+ assert (bad_loc ("1/.."));
+ assert (bad_loc ("bbb"));
+ assert (bad_loc ("aaa/bbb"));
+ assert (bad_loc ("http://"));
+ assert (bad_loc ("http://aa"));
+ assert (bad_loc ("https://aa"));
+ assert (bad_loc ("http://aa/"));
+ assert (bad_loc ("http://aa/b/.."));
+ assert (bad_loc ("http://aa/."));
+ assert (bad_loc ("http://aa/bb"));
+ assert (bad_loc ("http://a.com/../c/1/aa"));
+ assert (bad_loc ("http://a.com/a/b/../../../c/1/aa"));
+ assert (bad_loc ("file://"));
#ifndef _WIN32
- assert (bad_location ("/aaa/bbb"));
+ assert (bad_loc ("/aaa/bbb"));
#else
- assert (bad_location ("c:\\aaa\\bbb"));
+ assert (bad_loc ("c:\\aaa\\bbb"));
#endif
- // Invalid version.
- //
- assert (bad_location ("3/aaa/bbb"));
+ // No URL fragment.
+ //
+#ifndef _WIN32
+ assert (bad_loc ("file://localhost/", repository_type::git));
+#else
+ assert (bad_loc ("file://localhost/c:/", repository_type::git));
+#endif
- // Invalid prerequisite repository location.
- //
- assert (bad_location ("a/c/1/bb"));
+ // Invalid version.
+ //
+ assert (bad_loc ("3/aaa/bbb"));
- assert (bad_location ("a/c/1/bb",
- repository_location ("./var/1/stable",
- repository_location ())));
+ // Invalid prerequisite repository location.
+ //
+ assert (bad_loc ("a/c/1/bb"));
- assert (bad_location ("../../../1/math",
- repository_location (
- "http://stable.cppget.org/1/misc")));
+ assert (bad_loc ("a/c/1/bb", loc ("./var/1/stable", loc ())));
+ assert (bad_loc ("../../../1/math",
+ loc ("http://stable.cppget.org/1/misc")));
- assert (bad_location ("../..",
- repository_location (
- "http://stable.cppget.org/1/misc")));
+ assert (bad_loc ("../..", loc ("http://stable.cppget.org/1/misc")));
- // Invalid web interface URL.
- //
- assert (bad_url (".a/..",
- repository_location (
- "http://stable.cppget.org/1/misc")));
+ assert (bad_loc ("http:/abc"));
+ assert (bad_loc ("http:///abc"));
+ assert (bad_loc ("http://1.1.1.1"));
+ assert (bad_loc ("http://[123]"));
- assert (bad_url ("../a/..",
- repository_location (
- "http://stable.cppget.org/1/misc")));
-
- assert (bad_url ("../.a",
- repository_location (
- "http://stable.cppget.org/1/misc")));
#ifndef _WIN32
- assert (bad_url ("../../..",
- repository_location (
- "/var/1/misc")));
-
- assert (bad_url ("../../..",
- repository_location (
- "/var/pkg/1/misc")));
+ assert (bad_loc ("file:////abc", repository_type::git));
+ assert (bad_loc ("zzz:/abc", repository_type::git));
#else
- assert (bad_url ("..\\..\\..",
- repository_location (
- "c:\\var\\1\\misc")));
+ assert (bad_loc ("file:/abc", repository_type::git));
+#endif
- assert (bad_url ("..\\..\\..",
- repository_location (
- "c:\\var\\pkg\\1\\misc")));
+ // Invalid web interface URL.
+ //
+ assert (bad_url (".a/..", loc ("http://stable.cppget.org/1/misc")));
+ assert (bad_url ("../a/..", loc ("http://stable.cppget.org/1/misc")));
+ assert (bad_url ("../.a", loc ("http://stable.cppget.org/1/misc")));
+#ifndef _WIN32
+ assert (bad_url ("../../..", loc ("/var/1/misc")));
+ assert (bad_url ("../../..", loc ("/var/pkg/1/misc")));
+#else
+ assert (bad_url ("..\\..\\..", loc ("c:\\var\\1\\misc")));
+ assert (bad_url ("..\\..\\..", loc ("c:\\var\\pkg\\1\\misc")));
#endif
- assert (bad_url ("../../..", repository_location ()));
+ assert (bad_url ("../../..", loc ()));
+
+ assert (bad_url ("../../../../..",
+ loc ("http://pkg.stable.cppget.org/foo/pkg/1/misc")));
- assert (bad_url ("../../../../..",
- repository_location (
- "http://pkg.stable.cppget.org/foo/pkg/1/misc")));
+ assert (bad_url ("../../../../../abc",
+ loc ("http://stable.cppget.org/foo/1/misc")));
- assert (bad_url ("../../../../../abc",
- repository_location (
- "http://stable.cppget.org/foo/1/misc")));
+ // Test valid locations.
+ //
+ {
+ repository_location l (loc (""));
+ assert (l.string ().empty ());
+ assert (l.canonical_name ().empty ());
+ }
+ {
+ repository_location l (loc ("1/aa/bb", loc ()));
+ assert (l.string () == "1/aa/bb");
- // Test valid locations.
+ // Relative locations have no canonical name.
//
- {
- repository_location l ("");
- assert (l.string ().empty ());
- assert (l.canonical_name ().empty ());
- }
- {
- repository_location l ("1/aa/bb", repository_location ());
- assert (l.string () == "1/aa/bb");
-
- // Relative locations have no canonical name.
- //
- assert (l.canonical_name ().empty ());
- }
- {
- repository_location l ("bpkg/1/aa/bb", repository_location ());
- assert (l.string () == "bpkg/1/aa/bb");
- assert (l.canonical_name ().empty ());
- }
- {
- repository_location l ("b/pkg/1/aa/bb", repository_location ());
- assert (l.string () == "b/pkg/1/aa/bb");
- assert (l.canonical_name ().empty ());
- }
- {
- repository_location l ("aa/..", repository_location ());
- assert (l.string () == ".");
- assert (l.canonical_name ().empty ());
- }
+ assert (l.canonical_name ().empty ());
+ }
+ {
+ repository_location l (loc ("bpkg/1/aa/bb", loc ()));
+ assert (l.string () == "bpkg/1/aa/bb");
+ assert (l.canonical_name ().empty ());
+ }
+ {
+ repository_location l (loc ("b/pkg/1/aa/bb", loc ()));
+ assert (l.string () == "b/pkg/1/aa/bb");
+ assert (l.canonical_name ().empty ());
+ }
+ {
+ repository_location l (loc ("aa/..", loc ()));
+ assert (l.string () == ".");
+ assert (l.canonical_name ().empty ());
+ }
+
#ifndef _WIN32
- {
- repository_location l ("/1/aa/bb", repository_location ());
- assert (l.string () == "/1/aa/bb");
- assert (l.canonical_name () == "/aa/bb");
- }
- {
- repository_location l ("/pkg/1/aa/bb", repository_location ());
- assert (l.string () == "/pkg/1/aa/bb");
- assert (l.canonical_name () == "aa/bb");
- }
- {
- repository_location l ("/var/bpkg/1", repository_location ());
- assert (l.string () == "/var/bpkg/1");
- assert (l.canonical_name () == "/var/bpkg");
- }
- {
- repository_location l ("/1", repository_location ());
- assert (l.string () == "/1");
- assert (l.canonical_name () == "/");
- }
- {
- repository_location l ("/var/pkg/1/example.org/math/testing",
- repository_location ());
- assert (l.string () == "/var/pkg/1/example.org/math/testing");
- assert (l.canonical_name () == "example.org/math/testing");
- }
- {
- repository_location l ("/var/pkg/example.org/1/math/testing",
- repository_location ());
- assert (l.string () == "/var/pkg/example.org/1/math/testing");
- assert (l.canonical_name () == "/var/pkg/example.org/math/testing");
- }
- {
- repository_location l ("/a/b/../c/1/aa/../bb", repository_location ());
- assert (l.string () == "/a/c/1/bb");
- assert (l.canonical_name () == "/a/c/bb");
- }
- {
- repository_location l ("/a/b/../c/pkg/1/aa/../bb",
- repository_location ());
- assert (l.string () == "/a/c/pkg/1/bb");
- assert (l.canonical_name () == "bb");
- }
+ {
+ repository_location l (loc ("/1/aa/bb", loc ()));
+ assert (l.string () == "/1/aa/bb");
+ assert (l.canonical_name () == "/aa/bb");
+ assert (l.type () == repository_type::bpkg);
+ }
+ {
+ repository_location l (loc ("/pkg/1/aa/bb", loc ()));
+ assert (l.string () == "/pkg/1/aa/bb");
+ assert (l.canonical_name () == "aa/bb");
+ }
+ {
+ repository_location l (loc ("/var/bpkg/1", loc ()));
+ assert (l.string () == "/var/bpkg/1");
+ assert (l.canonical_name () == "/var/bpkg");
+ }
+ {
+ repository_location l (loc ("/1", loc ()));
+ assert (l.string () == "/1");
+ assert (l.canonical_name () == "/");
+ }
+ {
+ repository_location l (loc ("/var/pkg/1/example.org/math/testing",
+ loc ()));
+ assert (l.string () == "/var/pkg/1/example.org/math/testing");
+ assert (l.canonical_name () == "example.org/math/testing");
+ }
+ {
+ repository_location l (loc ("/var/pkg/example.org/1/math/testing",
+ loc ()));
+ assert (l.string () == "/var/pkg/example.org/1/math/testing");
+ assert (l.canonical_name () == "/var/pkg/example.org/math/testing");
+ }
+ {
+ repository_location l (loc ("/a/b/../c/1/aa/../bb", loc ()));
+ assert (l.string () == "/a/c/1/bb");
+ assert (l.canonical_name () == "/a/c/bb");
+ }
+ {
+ repository_location l (loc ("/a/b/../c/pkg/1/aa/../bb", loc ()));
+ assert (l.string () == "/a/c/pkg/1/bb");
+ assert (l.canonical_name () == "bb");
+ }
+ {
+ repository_location l (loc ("file:///repo/1/path"));
+ assert (l.url () == loc ("file:/repo/1/path").url ());
+ assert (l.url () == loc ("/repo/1/path").url ());
+ assert (l.string () == "/repo/1/path");
+ assert (l.canonical_name () == "/repo/path");
+ }
+ {
+ repository_location l (loc ("file:/git/repo#branch",
+ repository_type::git));
+ assert (l.string () == "file:/git/repo#branch");
+ assert (l.canonical_name () == "/git/repo");
+ }
+ {
+ repository_location l (loc ("file://localhost/#master",
+ repository_type::git));
+ assert (l.string () == "file:/#master");
+ assert (l.canonical_name () == "/");
+ }
#else
- {
- repository_location l ("c:\\1\\aa\\bb", repository_location ());
- assert (l.string () == "c:\\1\\aa\\bb");
- assert (l.canonical_name () == "c:\\aa\\bb");
- }
- {
- repository_location l ("c:/1/aa/bb", repository_location ());
- assert (l.string () == "c:\\1\\aa\\bb");
- assert (l.canonical_name () == "c:\\aa\\bb");
- }
- {
- repository_location l ("c:\\pkg\\1\\aa\\bb", repository_location ());
- assert (l.string () == "c:\\pkg\\1\\aa\\bb");
- assert (l.canonical_name () == "aa/bb");
- }
- {
- repository_location l ("c:\\var\\pkg\\1\\example.org\\math\\testing",
- repository_location ());
- assert (l.string () == "c:\\var\\pkg\\1\\example.org\\math\\testing");
- assert (l.canonical_name () == "example.org/math/testing");
- }
- {
- repository_location l ("c:\\var\\pkg\\example.org\\1\\math\\testing",
- repository_location ());
- assert (l.string () == "c:\\var\\pkg\\example.org\\1\\math\\testing");
-
- assert (l.canonical_name () ==
- "c:\\var\\pkg\\example.org\\math\\testing");
- }
- {
- repository_location l ("c:/a/b/../c/1/aa/../bb",
- repository_location ());
-
- assert (l.string () == "c:\\a\\c\\1\\bb");
- assert (l.canonical_name () == "c:\\a\\c\\bb");
- }
- {
- repository_location l ("c:/a/b/../c/pkg/1/aa/../bb",
- repository_location ());
- assert (l.string () == "c:\\a\\c\\pkg\\1\\bb");
- assert (l.canonical_name () == "bb");
- }
+ {
+ repository_location l (loc ("c:\\1\\aa\\bb", loc ()));
+ assert (l.string () == "c:\\1\\aa\\bb");
+ assert (l.canonical_name () == "c:\\aa\\bb");
+ assert (l.type () == repository_type::bpkg);
+ }
+ {
+ repository_location l (loc ("c:/1/aa/bb", loc ()));
+ assert (l.string () == "c:\\1\\aa\\bb");
+ assert (l.canonical_name () == "c:\\aa\\bb");
+ }
+ {
+ repository_location l (loc ("c:\\pkg\\1\\aa\\bb", loc ()));
+ assert (l.string () == "c:\\pkg\\1\\aa\\bb");
+ assert (l.canonical_name () == "aa/bb");
+ }
+ {
+ repository_location l (loc ("c:\\var\\pkg\\1\\example.org\\math\\tst",
+ loc ()));
+ assert (l.string () == "c:\\var\\pkg\\1\\example.org\\math\\tst");
+ assert (l.canonical_name () == "example.org/math/tst");
+ }
+ {
+ repository_location l (loc ("c:\\var\\pkg\\example.org\\1\\math\\tst",
+ loc ()));
+ assert (l.string () == "c:\\var\\pkg\\example.org\\1\\math\\tst");
+
+ assert (l.canonical_name () == "c:\\var\\pkg\\example.org\\math\\tst");
+ }
+ {
+ repository_location l (loc ("c:/a/b/../c/1/aa/../bb", loc ()));
+
+ assert (l.string () == "c:\\a\\c\\1\\bb");
+ assert (l.canonical_name () == "c:\\a\\c\\bb");
+ }
+ {
+ repository_location l (loc ("c:/a/b/../c/pkg/1/aa/../bb", loc ()));
+ assert (l.string () == "c:\\a\\c\\pkg\\1\\bb");
+ assert (l.canonical_name () == "bb");
+ }
+ {
+ repository_location l (loc ("file:///c:/repo/1/path"));
+ assert (l.url () == loc ("file:/c:/repo/1/path").url ());
+ assert (l.url () == loc ("c:/repo/1/path").url ());
+ assert (l.string () == "c:\\repo\\1\\path");
+ assert (l.canonical_name () == "c:\\repo\\path");
+ }
+ {
+ repository_location l (loc ("file:/c:/git/repo#branch",
+ repository_type::git));
+ assert (l.string () == "file:/c:/git/repo#branch");
+ assert (l.canonical_name () == "c:\\git\\repo");
+ }
+ {
+ repository_location l (loc ("file://localhost/c:/#master",
+ repository_type::git));
+ assert (l.string () == "file:/c:#master");
+ assert (l.canonical_name () == "c:");
+ }
#endif
- {
- repository_location l ("../c/../c/./1/aa/../bb",
- repository_location ());
- assert (l.string () == "../c/1/bb");
- assert (l.canonical_name ().empty ());
- }
- {
- repository_location l ("http://www.a.com:80/1/aa/bb");
- assert (l.string () == "http://www.a.com:80/1/aa/bb");
- assert (l.canonical_name () == "a.com/aa/bb");
- assert (l.proto () == protocol::http);
- }
- {
- repository_location l ("https://www.a.com:443/1/aa/bb");
- assert (l.string () == "https://www.a.com:443/1/aa/bb");
- assert (l.canonical_name () == "a.com/aa/bb");
- assert (l.proto () == protocol::https);
- }
- {
- repository_location l ("http://www.a.com:8080/dd/1/aa/bb");
- assert (l.string () == "http://www.a.com:8080/dd/1/aa/bb");
- assert (l.canonical_name () == "a.com:8080/dd/aa/bb");
- assert (l.proto () == protocol::http);
- }
- {
- repository_location l ("http://www.a.com:8080/dd/pkg/1/aa/bb");
- assert (l.string () == "http://www.a.com:8080/dd/pkg/1/aa/bb");
- assert (l.canonical_name () == "a.com:8080/dd/aa/bb");
- assert (l.proto () == protocol::http);
- }
- {
- repository_location l ("http://www.a.com:8080/bpkg/dd/1/aa/bb");
- assert (l.string () == "http://www.a.com:8080/bpkg/dd/1/aa/bb");
- assert (l.canonical_name () == "a.com:8080/bpkg/dd/aa/bb");
- assert (l.proto () == protocol::http);
- }
- {
- repository_location l ("https://www.a.com:444/dd/1/aa/bb");
- assert (l.string () == "https://www.a.com:444/dd/1/aa/bb");
- assert (l.canonical_name () == "a.com:444/dd/aa/bb");
- assert (l.proto () == protocol::https);
- }
- {
- repository_location l ("http://a.com/a/b/../c/1/aa/../bb");
- assert (l.string () == "http://a.com/a/c/1/bb");
- assert (l.canonical_name () == "a.com/a/c/bb");
- }
- {
- repository_location l ("https://a.com/a/b/../c/1/aa/../bb");
- assert (l.string () == "https://a.com/a/c/1/bb");
- assert (l.canonical_name () == "a.com/a/c/bb");
- }
- {
- repository_location l ("http://www.CPPget.org/qw/1/a/b/");
- assert (l.string () == "http://www.cppget.org/qw/1/a/b");
- assert (l.canonical_name () == "cppget.org/qw/a/b");
- }
- {
- repository_location l ("http://pkg.CPPget.org/qw/1/a/b/");
- assert (l.string () == "http://pkg.cppget.org/qw/1/a/b");
- assert (l.canonical_name () == "cppget.org/qw/a/b");
- }
- {
- repository_location l ("http://bpkg.CPPget.org/qw/1/a/b/");
- assert (l.string () == "http://bpkg.cppget.org/qw/1/a/b");
- assert (l.canonical_name () == "cppget.org/qw/a/b");
- }
- {
- repository_location l ("http://abc.cppget.org/qw/1/a/b/");
- assert (l.string () == "http://abc.cppget.org/qw/1/a/b");
- assert (l.canonical_name () == "abc.cppget.org/qw/a/b");
- }
- {
- repository_location l ("http://pkg.www.cppget.org/qw/1/a/b/");
- assert (l.string () == "http://pkg.www.cppget.org/qw/1/a/b");
- assert (l.canonical_name () == "www.cppget.org/qw/a/b");
- }
- {
- repository_location l ("http://bpkg.www.cppget.org/qw/1/a/b/");
- assert (l.string () == "http://bpkg.www.cppget.org/qw/1/a/b");
- assert (l.canonical_name () == "www.cppget.org/qw/a/b");
- }
- {
- repository_location l ("http://cppget.org/qw//1/a//b/");
- assert (l.string () == "http://cppget.org/qw/1/a/b");
- assert (l.canonical_name () == "cppget.org/qw/a/b");
- }
- {
- repository_location l ("http://stable.cppget.org/1/");
- assert (l.canonical_name () == "stable.cppget.org");
- }
- {
- repository_location l1 ("http://stable.cppget.org/1/misc");
- repository_location l2 ("../../1/math", l1);
- assert (l2.string () == "http://stable.cppget.org/1/math");
- assert (l2.canonical_name () == "stable.cppget.org/math");
- }
- {
- repository_location l1 ("http://stable.cppget.org/1/misc");
- repository_location l2 ("../../pkg/1/math", l1);
- assert (l2.string () == "http://stable.cppget.org/pkg/1/math");
- assert (l2.canonical_name () == "stable.cppget.org/math");
- }
- {
- repository_location l1 ("https://stable.cppget.org/1/misc");
- repository_location l2 ("../../1/math", l1);
- assert (l2.string () == "https://stable.cppget.org/1/math");
- assert (l2.canonical_name () == "stable.cppget.org/math");
- }
- {
- repository_location l1 ("http://stable.cppget.org/1/misc");
- repository_location l2 ("../math", l1);
- assert (l2.string () == "http://stable.cppget.org/1/math");
- assert (l2.canonical_name () == "stable.cppget.org/math");
- }
- {
- repository_location l1 ("http://stable.cppget.org/1/misc");
- repository_location l2 ("math/..", l1);
- assert (l2.string () == "http://stable.cppget.org/1/misc");
- assert (l2.canonical_name () == "stable.cppget.org/misc");
- }
- {
- repository_location l1 ("http://stable.cppget.org/1/misc");
- repository_location l2 (".", l1);
- assert (l2.string () == "http://stable.cppget.org/1/misc");
- assert (l2.canonical_name () == "stable.cppget.org/misc");
- }
- {
- repository_location l1 ("http://www.stable.cppget.org:8080/1");
- repository_location l2 ("../1/math", l1);
- assert (l2.string () == "http://www.stable.cppget.org:8080/1/math");
- assert (l2.canonical_name () == "stable.cppget.org:8080/math");
- assert (l2.proto () == protocol::http);
- }
- {
- repository_location l1 ("https://www.stable.cppget.org:444/1");
- repository_location l2 ("../1/math", l1);
- assert (l2.string () == "https://www.stable.cppget.org:444/1/math");
- assert (l2.canonical_name () == "stable.cppget.org:444/math");
- assert (l2.proto () == protocol::https);
- }
+ {
+ repository_location l (loc ("../c/../c/./1/aa/../bb", loc ()));
+ assert (l.string () == "../c/1/bb");
+ assert (l.canonical_name ().empty ());
+ }
+ {
+ repository_location l (loc ("http://www.a.com:80/1/aa/bb"));
+ assert (l.string () == "http://www.a.com:80/1/aa/bb");
+ assert (l.canonical_name () == "a.com/aa/bb");
+ assert (l.proto () == proto::http);
+ assert (l.type () == repository_type::bpkg);
+ }
+ {
+ repository_location l (loc ("https://www.a.com:443/1/aa/bb"));
+ assert (l.string () == "https://www.a.com:443/1/aa/bb");
+ assert (l.canonical_name () == "a.com/aa/bb");
+ assert (l.proto () == proto::https);
+ assert (l.type () == repository_type::bpkg);
+ }
+ {
+ repository_location l (loc ("http://www.a.com:8080/dd/1/aa/bb"));
+ assert (l.string () == "http://www.a.com:8080/dd/1/aa/bb");
+ assert (l.canonical_name () == "a.com:8080/dd/aa/bb");
+ assert (l.proto () == proto::http);
+ assert (l.type () == repository_type::bpkg);
+ }
+ {
+ repository_location l (loc ("http://www.a.com:8080/dd/pkg/1/aa/bb"));
+ assert (l.string () == "http://www.a.com:8080/dd/pkg/1/aa/bb");
+ assert (l.canonical_name () == "a.com:8080/dd/aa/bb");
+ assert (l.proto () == proto::http);
+ assert (l.type () == repository_type::bpkg);
+ }
+ {
+ repository_location l (loc ("http://www.a.com:8080/bpkg/dd/1/aa/bb"));
+ assert (l.string () == "http://www.a.com:8080/bpkg/dd/1/aa/bb");
+ assert (l.canonical_name () == "a.com:8080/bpkg/dd/aa/bb");
+ assert (l.proto () == proto::http);
+ assert (l.type () == repository_type::bpkg);
+ }
+ {
+ repository_location l (loc ("https://www.a.com:444/dd/1/aa/bb"));
+ assert (l.string () == "https://www.a.com:444/dd/1/aa/bb");
+ assert (l.canonical_name () == "a.com:444/dd/aa/bb");
+ assert (l.proto () == proto::https);
+ assert (l.type () == repository_type::bpkg);
+ }
+ {
+ repository_location l (loc ("git://github.com/test#master",
+ repository_type::git));
+ assert (l.string () == "git://github.com/test#master");
+ assert (l.canonical_name () == "github.com/test");
+ assert (l.proto () == proto::git);
+ assert (l.type () == repository_type::git);
+ }
+ {
+ repository_location l (loc ("http://github.com/test.git#master",
+ repository_type::git));
+ assert (l.string () == "http://github.com/test.git#master");
+ assert (l.canonical_name () == "github.com/test");
+ assert (l.proto () == proto::http);
+ }
+ {
+ repository_location l (loc ("https://github.com/test.git#master",
+ repository_type::git));
+ assert (l.string () == "https://github.com/test.git#master");
+ assert (l.canonical_name () == "github.com/test");
+ assert (l.proto () == proto::https);
+ assert (l.type () == repository_type::git);
+ }
+ {
+ repository_location l (loc ("http://git.example.com#master",
+ repository_type::git));
+ assert (l.string () == "http://git.example.com/#master");
+ assert (l.canonical_name () == "example.com");
+ }
+ {
+ repository_location l (loc ("http://a.com/a/b/../c/1/aa/../bb"));
+ assert (l.string () == "http://a.com/a/c/1/bb");
+ assert (l.canonical_name () == "a.com/a/c/bb");
+ }
+ {
+ repository_location l (loc ("https://a.com/a/b/../c/1/aa/../bb"));
+ assert (l.string () == "https://a.com/a/c/1/bb");
+ assert (l.canonical_name () == "a.com/a/c/bb");
+ }
+ {
+ repository_location l (loc ("http://www.CPPget.org/qw/1/a/b/"));
+ assert (l.string () == "http://www.cppget.org/qw/1/a/b");
+ assert (l.canonical_name () == "cppget.org/qw/a/b");
+ }
+ {
+ repository_location l (loc ("http://pkg.CPPget.org/qw/1/a/b/"));
+ assert (l.string () == "http://pkg.cppget.org/qw/1/a/b");
+ assert (l.canonical_name () == "cppget.org/qw/a/b");
+ }
+ {
+ repository_location l (loc ("http://bpkg.CPPget.org/qw/1/a/b/"));
+ assert (l.string () == "http://bpkg.cppget.org/qw/1/a/b");
+ assert (l.canonical_name () == "cppget.org/qw/a/b");
+ }
+ {
+ repository_location l (loc ("http://abc.cppget.org/qw/1/a/b/"));
+ assert (l.string () == "http://abc.cppget.org/qw/1/a/b");
+ assert (l.canonical_name () == "abc.cppget.org/qw/a/b");
+ }
+ {
+ repository_location l (loc ("http://pkg.www.cppget.org/qw/1/a/b/"));
+ assert (l.string () == "http://pkg.www.cppget.org/qw/1/a/b");
+ assert (l.canonical_name () == "www.cppget.org/qw/a/b");
+ }
+ {
+ repository_location l (loc ("http://bpkg.www.cppget.org/qw/1/a/b/"));
+ assert (l.string () == "http://bpkg.www.cppget.org/qw/1/a/b");
+ assert (l.canonical_name () == "www.cppget.org/qw/a/b");
+ }
+ {
+ repository_location l (loc ("https://git.github.com/test.git#master",
+ repository_type::git));
+ assert (l.string () == "https://git.github.com/test.git#master");
+ assert (l.canonical_name () == "github.com/test");
+ }
+ {
+ repository_location l (loc ("https://scm.github.com/test.git#master",
+ repository_type::git));
+ assert (l.string () == "https://scm.github.com/test.git#master");
+ assert (l.canonical_name () == "github.com/test");
+ }
+ {
+ repository_location l (loc ("https://www.github.com/test.git#master",
+ repository_type::git));
+ assert (l.string () == "https://www.github.com/test.git#master");
+ assert (l.canonical_name () == "github.com/test");
+ }
+ {
+ repository_location l (loc ("http://cppget.org/qw//1/a//b/"));
+ assert (l.string () == "http://cppget.org/qw/1/a/b");
+ assert (l.canonical_name () == "cppget.org/qw/a/b");
+ }
+ {
+ repository_location l (loc ("http://stable.cppget.org/1/"));
+ assert (l.canonical_name () == "stable.cppget.org");
+ }
+ {
+ repository_location l1 (loc ("http://stable.cppget.org/1/misc"));
+ repository_location l2 (loc ("../../1/math", l1));
+ assert (l2.string () == "http://stable.cppget.org/1/math");
+ assert (l2.canonical_name () == "stable.cppget.org/math");
+ }
+ {
+ repository_location l1 (loc ("http://stable.cppget.org/1/misc"));
+ repository_location l2 (loc ("../../pkg/1/math", l1));
+ assert (l2.string () == "http://stable.cppget.org/pkg/1/math");
+ assert (l2.canonical_name () == "stable.cppget.org/math");
+ }
+ {
+ repository_location l1 (loc ("https://stable.cppget.org/1/misc"));
+ repository_location l2 (loc ("../../1/math", l1));
+ assert (l2.string () == "https://stable.cppget.org/1/math");
+ assert (l2.canonical_name () == "stable.cppget.org/math");
+ }
+ {
+ repository_location l1 (loc ("http://stable.cppget.org/1/misc"));
+ repository_location l2 (loc ("../math", l1));
+ assert (l2.string () == "http://stable.cppget.org/1/math");
+ assert (l2.canonical_name () == "stable.cppget.org/math");
+ }
+ {
+ repository_location l1 (loc ("http://stable.cppget.org/1/misc"));
+ repository_location l2 (loc ("math/..", l1));
+ assert (l2.string () == "http://stable.cppget.org/1/misc");
+ assert (l2.canonical_name () == "stable.cppget.org/misc");
+ }
+ {
+ repository_location l1 (loc ("http://stable.cppget.org/1/misc"));
+ repository_location l2 (loc (".", l1));
+ assert (l2.string () == "http://stable.cppget.org/1/misc");
+ assert (l2.canonical_name () == "stable.cppget.org/misc");
+ }
+ {
+ repository_location l1 (loc ("http://www.stable.cppget.org:8080/1"));
+
+ repository_location l2 (loc ("../1/math", l1));
+ assert (l2.string () == "http://www.stable.cppget.org:8080/1/math");
+ assert (l2.canonical_name () == "stable.cppget.org:8080/math");
+ assert (l2.proto () == proto::http);
+ }
+ {
+ repository_location l1 (loc ("https://www.stable.cppget.org:444/1"));
+ repository_location l2 (loc ("../1/math", l1));
+ assert (l2.string () == "https://www.stable.cppget.org:444/1/math");
+ assert (l2.canonical_name () == "stable.cppget.org:444/math");
+ assert (l2.proto () == proto::https);
+ }
#ifndef _WIN32
- {
- repository_location l1 ("/var/r1/1/misc");
- repository_location l2 ("../../../r2/1/math", l1);
- assert (l2.string () == "/var/r2/1/math");
- assert (l2.canonical_name () == "/var/r2/math");
- }
- {
- repository_location l1 ("/var/1/misc");
- repository_location l2 ("../math", l1);
- assert (l2.string () == "/var/1/math");
- assert (l2.canonical_name () == "/var/math");
- }
- {
- repository_location l1 ("/var/1/stable");
- repository_location l2 ("/var/1/test", l1);
- assert (l2.string () == "/var/1/test");
- assert (l2.canonical_name () == "/var/test");
- }
- {
- repository_location l1 ("http://stable.cppget.org/1/misc");
- repository_location l2 ("/var/1/test", l1);
- assert (l2.string () == "/var/1/test");
- assert (l2.canonical_name () == "/var/test");
- }
- {
- repository_location l1 ("/var/1/stable");
- repository_location l2 ("/var/1/stable", repository_location ());
- assert (l1.string () == l2.string ());
- assert (l1.canonical_name () == l2.canonical_name ());
- }
+ {
+ repository_location l1 (loc ("/var/r1/1/misc"));
+ repository_location l2 (loc ("../../../r2/1/math", l1));
+ assert (l2.string () == "/var/r2/1/math");
+ assert (l2.canonical_name () == "/var/r2/math");
+ }
+ {
+ repository_location l1 (loc ("/var/1/misc"));
+ repository_location l2 (loc ("../math", l1));
+ assert (l2.string () == "/var/1/math");
+ assert (l2.canonical_name () == "/var/math");
+ }
+ {
+ repository_location l1 (loc ("/var/1/stable"));
+ repository_location l2 (loc ("/var/1/test", l1));
+ assert (l2.string () == "/var/1/test");
+ assert (l2.canonical_name () == "/var/test");
+ }
+ {
+ repository_location l1 (loc ("http://stable.cppget.org/1/misc"));
+ repository_location l2 (loc ("/var/1/test", l1));
+ assert (l2.string () == "/var/1/test");
+ assert (l2.canonical_name () == "/var/test");
+ }
+ {
+ repository_location l1 (loc ("/var/1/stable"));
+ repository_location l2 (loc ("/var/1/stable", loc ()));
+ assert (l1.string () == l2.string ());
+ assert (l1.canonical_name () == l2.canonical_name ());
+ }
#else
- {
- repository_location l1 ("c:/var/r1/1/misc");
- repository_location l2 ("../../../r2/1/math", l1);
- assert (l2.string () == "c:\\var\\r2\\1\\math");
- assert (l2.canonical_name () == "c:\\var\\r2\\math");
- }
- {
- repository_location l1 ("c:/var/1/misc");
- repository_location l2 ("../math", l1);
- assert (l2.string () == "c:\\var\\1\\math");
- assert (l2.canonical_name () == "c:\\var\\math");
- }
- {
- repository_location l1 ("c:/var/1/stable");
- repository_location l2 ("c:\\var\\1\\test", l1);
- assert (l2.string () == "c:\\var\\1\\test");
- assert (l2.canonical_name () == "c:\\var\\test");
- }
- {
- repository_location l1 ("http://stable.cppget.org/1/misc");
- repository_location l2 ("c:/var/1/test", l1);
- assert (l2.string () == "c:\\var\\1\\test");
- assert (l2.canonical_name () == "c:\\var\\test");
- }
- {
- repository_location l1 ("c:/var/1/stable");
- repository_location l2 ("c:/var/1/stable", repository_location ());
- assert (l1.string () == l2.string ());
- assert (l1.canonical_name () == l2.canonical_name ());
- }
+ {
+ repository_location l1 (loc ("c:/var/r1/1/misc"));
+ repository_location l2 (loc ("../../../r2/1/math", l1));
+ assert (l2.string () == "c:\\var\\r2\\1\\math");
+ assert (l2.canonical_name () == "c:\\var\\r2\\math");
+ }
+ {
+ repository_location l1 (loc ("c:/var/1/misc"));
+ repository_location l2 (loc ("../math", l1));
+ assert (l2.string () == "c:\\var\\1\\math");
+ assert (l2.canonical_name () == "c:\\var\\math");
+ }
+ {
+ repository_location l1 (loc ("c:/var/1/stable"));
+ repository_location l2 (loc ("c:\\var\\1\\test", l1));
+ assert (l2.string () == "c:\\var\\1\\test");
+ assert (l2.canonical_name () == "c:\\var\\test");
+ }
+ {
+ repository_location l1 (loc ("http://stable.cppget.org/1/misc"));
+ repository_location l2 (loc ("c:/var/1/test", l1));
+ assert (l2.string () == "c:\\var\\1\\test");
+ assert (l2.canonical_name () == "c:\\var\\test");
+ }
+ {
+ repository_location l1 (loc ("c:/var/1/stable"));
+ repository_location l2 (loc ("c:/var/1/stable", loc ()));
+ assert (l1.string () == l2.string ());
+ assert (l1.canonical_name () == l2.canonical_name ());
+ }
#endif
- {
- repository_location l1 ("http://www.cppget.org/1/stable");
- repository_location l2 ("http://abc.com/1/test", l1);
- assert (l2.string () == "http://abc.com/1/test");
- assert (l2.canonical_name () == "abc.com/test");
- }
- {
- repository_location l1 ("http://stable.cppget.org/1/");
- repository_location l2 ("http://stable.cppget.org/1/",
- repository_location ());
- assert (l1.string () == l2.string ());
- assert (l1.canonical_name () == l2.canonical_name ());
- }
-
- // Test valid web interface locations.
- //
- {
- repository_location l ("http://cppget.org/1/misc");
- assert (effective_url ("http://cppget.org/pkg", l) ==
- "http://cppget.org/pkg");
- }
- {
- repository_location l ("http://cppget.org/1/misc");
- assert (effective_url ("https://cppget.org/pkg", l) ==
- "https://cppget.org/pkg");
- }
- {
- repository_location l ("http://pkg.cppget.org/foo/pkg/1/misc/stable");
- assert (effective_url ("./.", l) ==
- "http://pkg.cppget.org/foo/pkg/misc/stable");
- }
- {
- repository_location l ("http://cppget.org/foo/1/misc/stable");
- assert (effective_url ("./.", l) ==
- "http://cppget.org/foo/misc/stable");
- }
- {
- repository_location l ("http://pkg.cppget.org/foo/pkg/1/misc/stable");
- assert (effective_url ("././..", l) ==
- "http://pkg.cppget.org/foo/pkg/misc");
- }
- {
- repository_location l ("http://pkg.cppget.org/foo/pkg/1/misc");
- assert (effective_url ("././../../..", l) == "http://pkg.cppget.org");
- }
- {
- repository_location l ("https://pkg.cppget.org/foo/pkg/1/misc/stable");
- assert (effective_url ("../.", l) ==
- "https://cppget.org/foo/pkg/misc/stable");
- }
- {
- repository_location l ("https://pkg.cppget.org/foo/pkg/1/misc/stable");
- assert (effective_url (".././..", l) ==
- "https://cppget.org/foo/pkg/misc");
- }
- {
- repository_location l (
- "https://bpkg.cppget.org/foo/bpkg/1/misc/stable");
-
- assert (effective_url ("./..", l) ==
- "https://bpkg.cppget.org/foo/misc/stable");
- }
- {
- repository_location l (
- "https://bpkg.cppget.org/foo/bpkg/1/misc/stable");
-
- assert (effective_url ("./../..", l) ==
- "https://bpkg.cppget.org/foo/misc");
- }
- {
- repository_location l ("http://www.cppget.org/foo/bpkg/1/misc/stable");
- assert (effective_url ("../..", l) ==
- "http://cppget.org/foo/misc/stable");
- }
- {
- repository_location l ("http://cppget.org/pkg/foo/1/misc/stable");
- assert (effective_url ("../..", l) ==
- "http://cppget.org/pkg/foo/misc/stable");
- }
- {
- repository_location l ("http://www.cppget.org/foo/bpkg/1/misc/stable");
- assert (effective_url ("../../..", l) ==
- "http://cppget.org/foo/misc");
- }
- {
- repository_location l ("http://pkg.cppget.org/foo/pkg/1/misc");
- assert (effective_url ("../../../..", l) == "http://cppget.org");
- }
- {
- repository_location l ("http://www.cppget.org/foo/bpkg/1/misc/stable");
- assert (effective_url ("../../../abc", l) ==
- "http://cppget.org/foo/misc/abc");
- }
- }
- catch (const exception& e)
- {
- cerr << e << endl;
- return 1;
+ {
+ repository_location l1 (loc ("http://www.cppget.org/1/stable"));
+ repository_location l2 (loc ("http://abc.com/1/test", l1));
+ assert (l2.string () == "http://abc.com/1/test");
+ assert (l2.canonical_name () == "abc.com/test");
+ }
+ {
+ repository_location l1 (loc ("http://stable.cppget.org/1/"));
+ repository_location l2 (loc ("http://stable.cppget.org/1/", loc ()));
+ assert (l1.string () == l2.string ());
+ assert (l1.canonical_name () == l2.canonical_name ());
+ }
+
+ // Test valid web interface locations.
+ //
+ {
+ repository_location l (loc ("http://cppget.org/1/misc"));
+ assert (effective_url ("http://cppget.org/pkg", l) ==
+ "http://cppget.org/pkg");
}
+ {
+ repository_location l (loc ("http://cppget.org/1/misc"));
+ assert (effective_url ("https://cppget.org/pkg", l) ==
+ "https://cppget.org/pkg");
+ }
+ {
+ repository_location l (
+ loc ("http://pkg.cppget.org/foo/pkg/1/misc/stable"));
+
+ assert (effective_url ("./.", l) ==
+ "http://pkg.cppget.org/foo/pkg/misc/stable");
+ }
+ {
+ repository_location l (loc ("http://cppget.org/foo/1/misc/stable"));
+ assert (effective_url ("./.", l) ==
+ "http://cppget.org/foo/misc/stable");
+ }
+ {
+ repository_location l (
+ loc ("http://pkg.cppget.org/foo/pkg/1/misc/stable"));
+
+ assert (effective_url ("././..", l) ==
+ "http://pkg.cppget.org/foo/pkg/misc");
+ }
+ {
+ repository_location l (loc ("http://pkg.cppget.org/foo/pkg/1/misc"));
+ assert (effective_url ("././../../..", l) == "http://pkg.cppget.org");
+ }
+ {
+ repository_location l (
+ loc ("https://pkg.cppget.org/foo/pkg/1/misc/stable"));
+
+ assert (effective_url ("../.", l) ==
+ "https://cppget.org/foo/pkg/misc/stable");
+ }
+ {
+ repository_location l (
+ loc ("https://pkg.cppget.org/foo/pkg/1/misc/stable"));
+
+ assert (effective_url (".././..", l) ==
+ "https://cppget.org/foo/pkg/misc");
+ }
+ {
+ repository_location l (
+ loc ("https://bpkg.cppget.org/foo/bpkg/1/misc/stable"));
+
+ assert (effective_url ("./..", l) ==
+ "https://bpkg.cppget.org/foo/misc/stable");
+ }
+ {
+ repository_location l (
+ loc ("https://bpkg.cppget.org/foo/bpkg/1/misc/stable"));
+
+ assert (effective_url ("./../..", l) ==
+ "https://bpkg.cppget.org/foo/misc");
+ }
+ {
+ repository_location l (
+ loc ("http://www.cppget.org/foo/bpkg/1/misc/stable"));
+
+ assert (effective_url ("../..", l) ==
+ "http://cppget.org/foo/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 ("http://www.cppget.org/foo/bpkg/1/misc/stable"));
+
+ assert (effective_url ("../../..", l) ==
+ "http://cppget.org/foo/misc");
+ }
+ {
+ repository_location l (loc ("http://pkg.cppget.org/foo/pkg/1/misc"));
+ assert (effective_url ("../../../..", l) == "http://cppget.org");
+ }
+ {
+ repository_location l (
+ loc ("http://www.cppget.org/foo/bpkg/1/misc/stable"));
+
+ assert (effective_url ("../../../abc", l) ==
+ "http://cppget.org/foo/misc/abc");
+ }
+
+ // repository_url
+ //
+ assert (repository_url ("git://example.com/test.git") ==
+ repository_url (proto::git,
+ repository_url::host_type ("example.com"),
+ dir_path ("test.git")));
return 0;
}