aboutsummaryrefslogtreecommitdiff
path: root/bpkg/manifest-utility.cxx
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2017-12-23 19:05:22 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2017-12-28 17:39:03 +0300
commit42ae47c3033a8c9ce70f1e6fb4c88ed70ac679fb (patch)
treebdd2cdbf35b4dfbfbc77763156182f03d497ad16 /bpkg/manifest-utility.cxx
parentdc5296af63000cddc4b46fc205137c20578cb81f (diff)
Add repository type detection
Diffstat (limited to 'bpkg/manifest-utility.cxx')
-rw-r--r--bpkg/manifest-utility.cxx87
1 files changed, 81 insertions, 6 deletions
diff --git a/bpkg/manifest-utility.cxx b/bpkg/manifest-utility.cxx
index 850ce59..031d51a 100644
--- a/bpkg/manifest-utility.cxx
+++ b/bpkg/manifest-utility.cxx
@@ -7,6 +7,7 @@
#include <bpkg/diagnostics.hxx>
using namespace std;
+using namespace butl;
namespace bpkg
{
@@ -65,19 +66,93 @@ namespace bpkg
}
repository_location
- parse_location (const char* s)
+ parse_location (const char* s, optional<repository_type> ot)
try
{
- repository_location rl (s, repository_location ());
+ repository_url u (s);
- if (rl.relative ()) // Throws if the location is empty.
- rl = repository_location (
- dir_path (s).complete ().normalize ().string ());
+ if (u.empty ())
+ fail << "empty repository location";
- return rl;
+ assert (u.path);
+
+ // Make the relative path absolute using the current directory.
+ //
+ if (u.scheme == repository_protocol::file && u.path->relative ())
+ u.path->complete ().normalize ();
+
+ // Guess the repository type to construct the repository location:
+ //
+ // 1. If type is specified as an option use that (but validate
+ // incompatible scheme/type e.g., git/bpkg).
+ //
+ // 2. If scheme is git then git.
+ //
+ // 3. If scheme is http(s), then check if path has the .git extension,
+ // then git, otherwise bpkg.
+ //
+ // 4. If local (which will normally be without the .git extension), check
+ // if directory contains the .git/ subdirectory then git, otherwise
+ // bpkg.
+ //
+ repository_type t;
+
+ if (ot)
+ t = *ot;
+ else
+ {
+ switch (u.scheme)
+ {
+ case repository_protocol::git:
+ {
+ t = repository_type::git;
+ break;
+ }
+ case repository_protocol::http:
+ case repository_protocol::https:
+ {
+ t = u.path->extension () == "git"
+ ? repository_type::git
+ : repository_type::bpkg;
+ break;
+ }
+ case repository_protocol::file:
+ {
+ t = exists (path_cast<dir_path> (*u.path) / dir_path (".git"))
+ ? repository_type::git
+ : repository_type::bpkg;
+ break;
+ }
+ }
+ }
+
+ try
+ {
+ // Don't move the URL since it may still be needed for diagnostics.
+ //
+ return repository_location (u, t);
+ }
+ catch (const invalid_argument& e)
+ {
+ diag_record dr;
+ dr << fail << "invalid " << t << " repository location '" << u << "': "
+ << e;
+
+ // If the bpkg repository type was guessed, then suggest the user to
+ // specify the type explicitly.
+ //
+ if (!ot && t == repository_type::bpkg)
+ dr << info << "consider using --type to specify repository type";
+
+ dr << endf;
+ }
}
catch (const invalid_argument& e)
{
fail << "invalid repository location '" << s << "': " << e << endf;
}
+ catch (const invalid_path& e)
+ {
+ fail << "invalid repository path '" << s << "': " << e << endf;
+ }
}