-
Notifications
You must be signed in to change notification settings - Fork 343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fixes for paths on Windows #4188
base: main
Are you sure you want to change the base?
Changes from all commits
8c38b76
48366f5
d6f8ff6
1d6dc32
bed1ca1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,11 +18,12 @@ use std::borrow::Cow; | |
use std::collections::{BTreeMap, HashMap, HashSet}; | ||
use std::default::Default; | ||
use std::io::Read; | ||
use std::path::PathBuf; | ||
use std::path::{Path, PathBuf}; | ||
use std::{fmt, str}; | ||
|
||
use git2::Oid; | ||
use itertools::Itertools; | ||
use path_slash::PathBufExt; | ||
use tempfile::NamedTempFile; | ||
use thiserror::Error; | ||
|
||
|
@@ -1143,10 +1144,43 @@ pub fn rename_remote( | |
Ok(()) | ||
} | ||
|
||
fn looks_like_a_path_to_git(source: &str) -> bool { | ||
source.chars().nth(1) == Some(':') || // Looks like a Windows C:... path | ||
// Match Git's behavior, the URL syntax [is only recognized if there are no | ||
// slashes before the first | ||
// colon](https://git-scm.com/docs/git-clone#_git_urls) | ||
!source | ||
.split_once("/") | ||
.map_or(source, |(first, _)| first) | ||
.contains(":") | ||
} | ||
|
||
pub fn sanitize_git_url_if_path(cwd: &Path, source: &str) -> String { | ||
// Git appears to turn URL-like source to absolute path if local git directory | ||
// exits, and fails because '$PWD/https' is unsupported protocol. Since it would | ||
// be tedious to copy the exact git (or libgit2) behavior, we simply assume a | ||
// source containing ':' is a URL, SSH remote, or absolute path with Windows | ||
// drive letter. | ||
if looks_like_a_path_to_git(source) && Path::new(source).exists() { | ||
// TODO: This won't work for Windows UNC path or (less importantly) if the | ||
// original source is a non-UTF Windows path. For Windows UNC paths, we | ||
// could use dunce, though see also https://gitlab.com/kornelski/dunce/-/issues/7 | ||
// TODO: double-check about UNC paths; what does Git do? | ||
cwd.join(source).to_slash().map_or_else( | ||
// It's less likely that cwd isn't utf-8, so just fall back to original source. | ||
|| source.to_owned(), | ||
|s| s.to_string(), | ||
) | ||
} else { | ||
source.to_owned() | ||
} | ||
} | ||
|
||
pub fn set_remote_url( | ||
git_repo: &git2::Repository, | ||
remote_name: &str, | ||
new_remote_url: &str, | ||
cwd: &Path, | ||
) -> Result<(), GitRemoteManagementError> { | ||
if remote_name == REMOTE_NAME_FOR_LOCAL_GIT_REPO { | ||
return Err(GitRemoteManagementError::RemoteReservedForLocalGitRepo); | ||
|
@@ -1164,7 +1198,7 @@ pub fn set_remote_url( | |
})?; | ||
|
||
git_repo | ||
.remote_set_url(remote_name, new_remote_url) | ||
.remote_set_url(remote_name, &sanitize_git_url_if_path(cwd, new_remote_url)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: this should be handled by CLI because it's UI issue to resolve relative path. (BTW, I think it's good idea to move the path conversion function to library.) |
||
.map_err(GitRemoteManagementError::InternalGitError)?; | ||
Ok(()) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we simply do replace
MAIN_SEPARATOR
to slash (ifcfg!(windows)
)?path-slash
might be optimized if we have to deal withPath
/OsStr
, but here we buildString
anyway.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is on my list to try and see if it makes things saner (that is, makes it easier to make the merge with #4080 work).
My main worry (and the reason I didn't start with search-and-replace) is about UNC paths, especially the ones appearing in our tests. I would have to find out experimentally whether I can get rid of them via
dunce
, and/or I'd have to find out how libgit2 deals with paths like:\\?\C:/Path/
//?/C:/Path/
Neither of these is correct according to Microsoft, but I think
libgit2
definitely chokes on the correct\\?\C:\Path\
and I have a mild suspicion that it might prefer one f the incorrect options. I wish I knew what Git did; I think we'd have to ask or read the source to find out.(As for dependency on path-slash, that library hasn't been updated in years and it's probably pretty simple, so we could re-implement it if needed)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think something like
dunce::simplified(..).replace(MAIN_SEPARATOR, "/")
is good as a workaround. It might not work if the path couldn't be simplified, but that wouldn't be worse than the current state.