diff options
-rw-r--r-- | libbpkg/manifest.cxx | 86 | ||||
-rw-r--r-- | libbpkg/manifest.hxx | 9 | ||||
-rw-r--r-- | tests/repository-location/driver.cxx | 8 |
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")); |