diff options
Diffstat (limited to 'bpkg/fetch-git.cxx')
-rw-r--r-- | bpkg/fetch-git.cxx | 95 |
1 files changed, 73 insertions, 22 deletions
diff --git a/bpkg/fetch-git.cxx b/bpkg/fetch-git.cxx index 7ffaaaf..17c56c5 100644 --- a/bpkg/fetch-git.cxx +++ b/bpkg/fetch-git.cxx @@ -292,7 +292,7 @@ namespace bpkg // histories we will use the file URL notation for local repositories. // static string - git_url (const repository_url& url) + to_git_url (const repository_url& url) { if (url.scheme != repository_protocol::file) return url.string (); @@ -326,6 +326,23 @@ namespace bpkg #endif } + // Create the URL object from a string representation printed by git + // commands. + // + static repository_url + from_git_url (string&& u) + { + // Fix-up the broken Windows file URL notation (see to_git_url() for + // details). + // +#ifdef _WIN32 + if (casecmp (u, "file://", 7) == 0 && u[7] != '/') + u.insert (7, 1, '/'); +#endif + + return repository_url (u); + } + // Sense the git protocol capabilities for a specified URL. // // Protocols other than HTTP(S) are considered smart but without the @@ -477,7 +494,7 @@ namespace bpkg co.git_option (), "ls-remote", "--refs", - git_url (url))); + to_git_url (url))); pipe.out.close (); // Shouldn't throw, unless something is severely damaged. @@ -798,21 +815,12 @@ namespace bpkg try { - string u (git_string (co, "submodule URL", - co.git_option (), - "-C", dir, - "config", - "--get", - "submodule." + name + ".url")); - - // Fix-up the broken Windows file URL notation (see the git_url() - // function for details). - // -#ifdef _WIN32 - if (casecmp (u, "file://", 7) == 0 && u[7] != '/') - u.insert (7, 1, '/'); -#endif - url = repository_url (u); + url = from_git_url (git_string (co, "submodule URL", + co.git_option (), + "-C", dir, + "config", + "--get", + "submodule." + name + ".url")); } catch (const invalid_argument& e) { @@ -859,7 +867,7 @@ namespace bpkg "--name", name, "--path", sdir, - "--url", git_url (url), + "--url", to_git_url (url), shallow ? cstrings ({"--depth", "1"}) : cstrings (), @@ -978,7 +986,7 @@ namespace bpkg ref.commit ? opt ("--no-checkout") : nullopt, verb < 1 ? opt ("-q") : verb > 3 ? opt ("-v") : nullopt, - git_url (url), + to_git_url (url), d)) fail << "unable to clone " << url << endg; @@ -1012,12 +1020,55 @@ namespace bpkg assert (ref.branch); - capabilities cap (sense_capabilities (co, url)); - bool shallow (shallow_fetch (co, url, cap, ref)); - dir_path d (destdir); d /= dir_path (*ref.branch); + // If the repository location differs from the one that was used to clone + // the repository then we re-clone it from the new location. + // + // Another (more hairy) way of doing this would be fixing up the remote + // origin URLs recursively prior to fetching. + // + try + { + repository_url u (from_git_url (git_string (co, "remote repository URL", + co.git_option (), + "-C", d, + "config", + "--get", + "remote.origin.url"))); + if (u != url) + { + // Note that the repository canonical name can not change under the + // legal scenarios that lead to the location change. Changed canonical + // name means that the repository was manually amended. We could + // re-clone such repositories as well but want to leave the backdoor + // for tests. + // + u.fragment = rl.url ().fragment; // Restore the fragment. + repository_location l (u, rl.type ()); + + if (rl.canonical_name () == l.canonical_name ()) + { + if (verb) + info << "re-cloning " << rl.canonical_name () + << " due to location change" << + info << "new location " << rl.url () << + info << "old location " << u; + + rm_r (d); + return git_clone (co, rl, destdir); + } + } + } + catch (const invalid_argument& e) + { + fail << "invalid remote.origin.url configuration value: " << e << endg; + } + + capabilities cap (sense_capabilities (co, url)); + bool shallow (shallow_fetch (co, url, cap, ref)); + update_tree (co, d, dir_path (), |