Skip to content

Commit

Permalink
fix: normalize relative git submodule urls with ssh://
Browse files Browse the repository at this point in the history
Git only assumes a URL is a relative path if it starts with `./` or `../`.
See <https://git-scm.com/docs/git-submodule>. To fetch the current repo,
we need to construct the full submodule URL.

At this moment it comes with some limitations:

* GitHub only normalizes HTTPS protocol with relative path `..`.
  (`ssh://[email protected]/rust-lang/cargo.git/relative/..` is invalid)
* `url` crate cannot parse SCP-like URLs.
  (`[email protected]:rust-lang/cargo.git` is not a valid WHATWG URL)

For the first one, we use `url` crate to normalize. For the second one,
we append the relative path directly to parent URL. That says, the only
failing case downs to one: SCP-like parent remote URLs with relative
submodule URLs on GitHub or git services not normalizing them.
  • Loading branch information
weihanglo committed Jul 29, 2023
1 parent e999957 commit 2ea866f
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 10 deletions.
44 changes: 37 additions & 7 deletions src/cargo/sources/git/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,16 +441,46 @@ impl<'a> GitCheckout<'a> {
}

// Git only assumes a URL is a relative path if it starts with `./` or `../`.
// See [`git submodule add`] documentation.
// See <https://git-scm.com/docs/git-submodule>. To fetch the current repo,
// we need to construct the full submodule URL.
//
// [`git submodule add`]: https://git-scm.com/docs/git-submodule
// At this moment it comes with some limitations:
//
// * GitHub only normalizes HTTPS protocol with relative path `..`.
// (`ssh://[email protected]/rust-lang/cargo.git/relative/..` is invalid)
// * `url` crate cannot parse SCP-like URLs.
// (`[email protected]:rust-lang/cargo.git` is not a valid WHATWG URL)
//
// For the first one, we use `url` crate to normalize. For the second one,
// we append the relative path directly to parent URL. That says, the only
// failing case downs to one: SCP-like parent remote URLs with relative
// submodule URLs on GitHub or git services not normalizing them.
//
// See rust-lang/cargo#12404 and rust-lang/cargo#12295.
let child_remote_url = if ["./", "../"].iter().any(|p| child_url_str.starts_with(p)) {
let mut new_remote_url = parent_remote_url.to_string();
if !new_remote_url.ends_with('/') {
new_remote_url.push('/');
match Url::parse(parent_remote_url) {
Ok(mut parent_url) => {
let path = parent_url.path();
if !path.ends_with('/') {
parent_url.set_path(&format!("{path}/"));
}
let new_remote_url = parent_url.join(child_url_str).with_context(|| {
format!(
"failed to parse relative child submodule url `{child_url_str}` \
using parent base url `{parent_url}`"
)
})?;
Cow::from(new_remote_url.to_string())
}
Err(_) => {
let mut new_remote_url = parent_remote_url.to_string();
if !new_remote_url.ends_with('/') {
new_remote_url.push('/');
}
new_remote_url.push_str(child_url_str);
Cow::from(new_remote_url)
}
}
new_remote_url.push_str(child_url_str);
Cow::from(new_remote_url)
} else {
Cow::from(child_url_str)
};
Expand Down
6 changes: 3 additions & 3 deletions tests/testsuite/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3633,7 +3633,7 @@ fn different_user_relative_submodules() {
.file("Cargo.toml", &basic_lib_manifest("dep1"))
.file("src/lib.rs", "")
});
let _user2_git_project2 = git::new("user2/dep2", |project| {
let user2_git_project2 = git::new("user2/dep2", |project| {
project
.file("Cargo.toml", &basic_lib_manifest("dep1"))
.file("src/lib.rs", "")
Expand Down Expand Up @@ -3673,14 +3673,14 @@ fn different_user_relative_submodules() {
"\
[UPDATING] git repository `{}`
[UPDATING] git submodule `{}`
[UPDATING] git submodule `{}/../dep2`
[UPDATING] git submodule `{}`
[COMPILING] dep1 v0.5.0 ({}#[..])
[COMPILING] foo v0.5.0 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
path2url(&user1_git_project.root()),
path2url(&user2_git_project.root()),
path2url(&user2_git_project.root()),
path2url(&user2_git_project2.root()),
path2url(&user1_git_project.root()),
))
.run();
Expand Down

0 comments on commit 2ea866f

Please sign in to comment.