aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbpkg/manifest.cxx86
-rw-r--r--libbpkg/manifest.hxx9
-rw-r--r--tests/repository-location/driver.cxx8
3 files changed, 64 insertions, 39 deletions
diff --git a/libbpkg/manifest.cxx b/libbpkg/manifest.cxx
index 9751e12..4f53fbc 100644
--- a/libbpkg/manifest.cxx
+++ b/libbpkg/manifest.cxx
@@ -1860,19 +1860,57 @@ namespace bpkg
// repository_url_traits
//
- repository_url_traits::scheme_type repository_url_traits::
+ optional<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)
+ optional<string_type>& fragment,
+ bool& rootless)
{
auto bad_url = [] (const char* d = "invalid URL")
{
throw invalid_argument (d);
};
+ // Consider non-empty URL as a path if the URL parsing failed. If the URL
+ // is empty then leave the basic_url ctor to throw.
+ //
+ if (scheme.empty ())
+ {
+ if (!url.empty ())
+ try
+ {
+ size_t p (url.find ('#'));
+
+ if (p != string::npos)
+ {
+ path = path_type (url.substr (0, p)).normalize ();
+ fragment = url.substr (p + 1);
+ }
+ else
+ path = path_type (url).normalize ();
+
+ rootless = false;
+ return scheme_type::file;
+ }
+ 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.
+ //
+ }
+
+ return nullopt;
+ }
+
+ if (!authority && !path && !query)
+ bad_url ("empty URL");
+
+ if (rootless)
+ bad_url ("rootless path");
+
auto translate_remote = [&authority, &path, &bad_url] ()
{
if (!authority || authority->host.empty ())
@@ -1972,33 +2010,6 @@ namespace bpkg
return scheme_type::file;
}
- // Consider non-empty URL as a path if the URL parsing failed. If the URL
- // is empty then leave the basic_url ctor to throw.
- //
- else if (scheme.empty ())
- {
- if (!url.empty ())
- try
- {
- size_t p (url.find ('#'));
-
- if (p != string::npos)
- {
- path = path_type (url.substr (0, p)).normalize ();
- fragment = url.substr (p + 1); // Note: set after path normalization.
- }
- else
- path = path_type (url).normalize ();
- }
- 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.
- //
- }
-
- return scheme_type::file;
- }
else
throw invalid_argument ("unknown scheme");
}
@@ -2009,7 +2020,8 @@ namespace bpkg
const optional<authority_type>& authority,
const optional<path_type>& path,
const optional<string_type>& /*query*/,
- const optional<string_type>& fragment)
+ const optional<string_type>& fragment,
+ bool /*rootless*/)
{
switch (scheme)
{
@@ -2046,7 +2058,7 @@ namespace bpkg
{
try
{
- return path_type (move (path));
+ return path_type (butl::url::decode (path));
}
catch (const invalid_path&)
{
@@ -2057,24 +2069,28 @@ namespace bpkg
repository_url_traits::string_type repository_url_traits::
translate_path (const path_type& path)
{
+ using butl::url;
+
// 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.
//
+ string r;
if (path.absolute ())
{
#ifndef _WIN32
- return path.leaf (dir_path ("/")).string ();
+ r = path.leaf (dir_path ("/")).string ();
#else
- string r (path.string ());
+ r = path.string ();
replace (r.begin (), r.end (), '\\', '/');
- return r;
#endif
}
+ else
+ r = path.posix_string ();
- return path.posix_string ();
+ return url::encode (r, [] (char& c) {return !url::path_char (c);});
}
// repository_type
diff --git a/libbpkg/manifest.hxx b/libbpkg/manifest.hxx
index 42e1a24..bae3ffe 100644
--- a/libbpkg/manifest.hxx
+++ b/libbpkg/manifest.hxx
@@ -619,13 +619,14 @@ namespace bpkg
using scheme_type = repository_protocol;
using authority_type = butl::basic_url_authority<string_type>;
- static scheme_type
+ static butl::optional<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>&);
+ butl::optional<string_type>&,
+ bool&);
static string_type
translate_scheme (string_type&,
@@ -633,7 +634,8 @@ namespace bpkg
const butl::optional<authority_type>&,
const butl::optional<path_type>&,
const butl::optional<string_type>&,
- const butl::optional<string_type>&);
+ const butl::optional<string_type>&,
+ bool);
static path_type
translate_path (string_type&&);
@@ -738,7 +740,6 @@ namespace bpkg
//
// - may append slash in repository_location ctor
//
- explicit
repository_location (repository_url, repository_type);
// Create a potentially relative pkg repository location. If base is not
diff --git a/tests/repository-location/driver.cxx b/tests/repository-location/driver.cxx
index bb55cf9..dc1ecb7 100644
--- a/tests/repository-location/driver.cxx
+++ b/tests/repository-location/driver.cxx
@@ -645,6 +645,14 @@ namespace bpkg
assert (l2.canonical_name () == "git:example.com/test#master");
assert (l2.proto () == proto::https);
}
+
+ {
+ repository_location l (loc ("http:repo/1/path", loc ()));
+ assert (l.string () == "http:repo/1/path");
+ assert (l.canonical_name ().empty ());
+ assert (l.proto () == proto::file);
+ }
+
#ifndef _WIN32
{
repository_location l1 (loc ("/var/r1/1/misc"));