Skip to content

Commit

Permalink
Merge branch 'main' into cont_include_if
Browse files Browse the repository at this point in the history
Conflicts:
	git-path/tests/realpath/mod.rs
  • Loading branch information
Byron committed Jun 21, 2022
2 parents 5f11318 + 61abb0b commit 0e9df36
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 94 deletions.
3 changes: 2 additions & 1 deletion git-discover/src/upwards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,8 @@ pub(crate) mod function {
cursor = if cursor.as_os_str().is_empty() {
cwd.clone()
} else {
cursor.canonicalize().ok()
// TODO: realpath or absolutize? No test runs into this.
Some(git_path::absolutize(&cursor, cwd.as_deref()).into_owned())
}
.ok_or(Error::InaccessibleDirectory { path: cursor })?;
}
Expand Down
14 changes: 1 addition & 13 deletions git-discover/tests/upwards/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,6 @@ fn from_dir_with_dot_dot() -> crate::Result {
let dir = working_dir.join("some/very/deeply/nested/subdir/../../../../../..");
let (path, trust) = git_discover::upwards(&dir)?;
assert_eq!(path.kind(), Kind::WorkTree { linked_git_dir: None });
// On CI on windows we get a cursor like this with a question mark so our prefix check won't work.
// We recover, but that means this assertion will fail.
// &cursor = "\\\\?\\D:\\a\\gitoxide\\gitoxide\\.git"
// &cwd = "D:\\a\\gitoxide\\gitoxide\\git-repository"
#[cfg(not(windows))]
assert_eq!(
path.as_ref(),
std::path::Path::new(".."),
Expand Down Expand Up @@ -166,18 +161,11 @@ fn from_existing_worktree() -> crate::Result {

assert_eq!(trust, expected_trust());
let (git_dir, worktree) = path.into_repository_and_work_tree_directories();
#[cfg(not(windows))]
assert_eq!(
git_dir.strip_prefix(top_level_repo.canonicalize().unwrap()),
git_dir.strip_prefix(git_path::realpath(&top_level_repo, std::env::current_dir()?).unwrap()),
Ok(std::path::Path::new(expected_git_dir)),
"we don't skip over worktrees and discover their git dir (gitdir is absolute in file)"
);
#[cfg(windows)]
assert_eq!(
git_dir.canonicalize()?,
top_level_repo.join(expected_git_dir).canonicalize()?,
"we don't skip over worktrees and discover their git dir (gitdir is absolute in file)"
);
let worktree = worktree.expect("linked worktree is set");
assert_eq!(
worktree.strip_prefix(&top_level_repo),
Expand Down
7 changes: 5 additions & 2 deletions git-odb/src/alternate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub enum Error {
#[error(transparent)]
Io(#[from] io::Error),
#[error(transparent)]
Realpath(#[from] git_path::realpath::Error),
#[error(transparent)]
Parse(#[from] parse::Error),
#[error("Alternates form a cycle: {} -> {}", .0.iter().map(|p| format!("'{}'", p.display())).collect::<Vec<_>>().join(" -> "), .0.first().expect("more than one directories").display())]
Cycle(Vec<PathBuf>),
Expand All @@ -42,13 +44,14 @@ pub fn resolve(objects_directory: impl Into<PathBuf>) -> Result<Vec<PathBuf>, Er
let relative_base = objects_directory.into();
let mut dirs = vec![(0, relative_base.clone())];
let mut out = Vec::new();
let mut seen = vec![relative_base.canonicalize()?];
let cwd = std::env::current_dir()?;
let mut seen = vec![git_path::realpath(&relative_base, &cwd)?];
while let Some((depth, dir)) = dirs.pop() {
match fs::read(dir.join("info").join("alternates")) {
Ok(input) => {
for path in parse::content(&input)?.into_iter() {
let path = relative_base.join(path);
let path_canonicalized = path.canonicalize()?;
let path_canonicalized = git_path::realpath(&path, &cwd)?;
if seen.contains(&path_canonicalized) {
return Err(Error::Cycle(seen));
}
Expand Down
7 changes: 4 additions & 3 deletions git-path/tests/convert/absolutize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,19 @@ fn no_change_if_there_are_no_trailing_relative_components() {
}

#[test]
fn special_cases_around_cwd() {
let cwd = std::env::current_dir().unwrap();
fn special_cases_around_cwd() -> crate::Result {
let cwd = std::env::current_dir()?;
assert_eq!(
absolutize(p("a/.."), None::<&Path>),
p("."),
"empty paths are never returned as they are invalid"
);
assert_eq!(
absolutize(p("a/../.."), Some(&cwd)),
cwd.parent().unwrap(),
cwd.parent().expect("parent"),
"it automatically extends the poppable items by using the current working dir"
);
Ok(())
}

#[test]
Expand Down
2 changes: 2 additions & 0 deletions git-path/tests/path.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
pub type Result<T = ()> = std::result::Result<T, Box<dyn std::error::Error>>;

mod convert;
mod realpath;
104 changes: 48 additions & 56 deletions git-path/tests/realpath/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use std::path::Path;
use tempfile::tempdir;

#[test]
fn assorted() {
let cwd = tempdir().unwrap();
fn assorted() -> crate::Result {
let cwd = tempdir()?;
let cwd = cwd.path();
let symlinks_disabled = 0;

Expand All @@ -14,31 +14,31 @@ fn assorted() {
);

assert_eq!(
realpath_opts("b/.git", cwd, symlinks_disabled).unwrap(),
realpath_opts("b/.git", cwd, symlinks_disabled)?,
cwd.join("b").join(".git"),
"relative paths are prefixed with current dir"
);

assert_eq!(
realpath_opts("b//.git", cwd, symlinks_disabled).unwrap(),
realpath_opts("b//.git", cwd, symlinks_disabled)?,
cwd.join("b").join(".git"),
"empty path components are ignored"
);

assert_eq!(
realpath_opts("./tmp/.git", cwd, symlinks_disabled).unwrap(),
realpath_opts("./tmp/.git", cwd, symlinks_disabled)?,
cwd.join("tmp").join(".git"),
"path starting with dot is relative and is prefixed with current dir"
);

assert_eq!(
realpath_opts("./tmp/a/./.git", cwd, symlinks_disabled).unwrap(),
realpath_opts("./tmp/a/./.git", cwd, symlinks_disabled)?,
cwd.join("tmp").join("a").join(".git"),
"all ./ path components are ignored unless they the one at the beginning of the path"
);

assert_eq!(
realpath_opts("./b/../tmp/.git", cwd, symlinks_disabled).unwrap(),
realpath_opts("./b/../tmp/.git", cwd, symlinks_disabled)?,
cwd.join("tmp").join(".git"),
"dot dot goes to parent path component"
);
Expand All @@ -49,20 +49,23 @@ fn assorted() {
#[cfg(windows)]
let absolute_path = Path::new("C:\\c\\d\\.git");
assert_eq!(
realpath_opts(absolute_path, cwd, symlinks_disabled).unwrap(),
realpath_opts(absolute_path, cwd, symlinks_disabled)?,
absolute_path,
"absolute path without symlinks has nothing to resolve and remains unchanged"
);
}

Ok(())
}

#[test]
fn link_cycle_is_detected() {
let tmp_dir = CanonicalizedTempDir::new();
fn link_cycle_is_detected() -> crate::Result {
let tmp_dir = canonicalized_tempdir()?;
let dir = tmp_dir.path();
let link_name = "link";
let link_destination = tmp_dir.join(link_name);
let link_path = tmp_dir.join(link_name);
create_symlink(&link_path, &link_destination);
let link_destination = dir.join(link_name);
let link_path = dir.join(link_name);
create_symlink(&link_path, &link_destination)?;
let max_symlinks = 8;

assert!(
Expand All @@ -72,81 +75,70 @@ fn link_cycle_is_detected() {
),
"link cycle is detected"
);
Ok(())
}

#[test]
fn symlink_with_absolute_path_gets_expanded() {
let tmp_dir = CanonicalizedTempDir::new();
let link_from = tmp_dir.join("a").join("b").join("tmp_p_q_link");
let link_to = tmp_dir.join("p").join("q");
create_symlink(&link_from, &link_to);
fn symlink_with_absolute_path_gets_expanded() -> crate::Result {
let tmp_dir = canonicalized_tempdir()?;
let dir = tmp_dir.path();
let link_from = dir.join("a").join("b").join("tmp_p_q_link");
let link_to = dir.join("p").join("q");
create_symlink(&link_from, &link_to)?;
let max_symlinks = 8;
assert_eq!(
realpath_opts(link_from.join(".git"), tmp_dir, max_symlinks).unwrap(),
realpath_opts(link_from.join(".git"), tmp_dir, max_symlinks)?,
link_to.join(".git"),
"symlink with absolute path gets expanded"
);
Ok(())
}

#[test]
fn symlink_to_relative_path_gets_expanded_into_absolute_path() {
let cwd = CanonicalizedTempDir::new();
fn symlink_to_relative_path_gets_expanded_into_absolute_path() -> crate::Result {
let cwd = canonicalized_tempdir()?;
let dir = cwd.path();
let link_name = "pq_link";
create_symlink(&cwd.join("r").join(link_name), &Path::new("p").join("q"));
create_symlink(&dir.join("r").join(link_name), &Path::new("p").join("q"))?;
assert_eq!(
realpath_opts(Path::new(link_name).join(".git"), cwd.join("r"), 8).unwrap(),
cwd.join("r").join("p").join("q").join(".git"),
realpath_opts(Path::new(link_name).join(".git"), dir.join("r"), 8)?,
dir.join("r").join("p").join("q").join(".git"),
"symlink to relative path gets expanded into absolute path"
);
Ok(())
}

#[test]
fn symlink_processing_is_disabled_if_the_value_is_zero() {
let cwd = CanonicalizedTempDir::new();
fn symlink_processing_is_disabled_if_the_value_is_zero() -> crate::Result {
let cwd = canonicalized_tempdir()?;
let link_name = "x_link";
create_symlink(&cwd.join(link_name), Path::new("link destination does not exist"));
create_symlink(
&cwd.path().join(link_name),
Path::new("link destination does not exist"),
)?;
assert!(
matches!(
realpath_opts(&Path::new(link_name).join(".git"), &cwd, 0),
Err(Error::MaxSymlinksExceeded { max_symlinks: 0 })
),
"symlink processing is disabled if the value is zero"
);
Ok(())
}

pub struct CanonicalizedTempDir {
pub dir: tempfile::TempDir,
}
fn create_symlink(from: impl AsRef<Path>, to: impl AsRef<Path>) -> std::io::Result<()> {
std::fs::create_dir_all(from.as_ref().parent().unwrap())?;

pub fn create_symlink(from: &Path, to: &Path) {
std::fs::create_dir_all(from.parent().unwrap()).unwrap();
#[cfg(not(windows))]
std::os::unix::fs::symlink(to, &from).unwrap();
#[cfg(windows)]
std::os::windows::fs::symlink_file(to, &from).unwrap();
}

impl CanonicalizedTempDir {
pub fn new() -> Self {
#[cfg(windows)]
let canonicalized_tempdir = std::env::temp_dir();
#[cfg(not(windows))]
let canonicalized_tempdir = std::env::temp_dir().canonicalize().unwrap();
let dir = tempfile::tempdir_in(canonicalized_tempdir).unwrap();
Self { dir }
{
std::os::unix::fs::symlink(to, from)
}
}

impl AsRef<Path> for CanonicalizedTempDir {
fn as_ref(&self) -> &Path {
self
}
#[cfg(windows)]
std::os::windows::fs::symlink_file(to, from)
}

impl std::ops::Deref for CanonicalizedTempDir {
type Target = Path;

fn deref(&self) -> &Self::Target {
self.dir.path()
}
fn canonicalized_tempdir() -> crate::Result<tempfile::TempDir> {
let canonicalized_tempdir = git_path::realpath(std::env::temp_dir(), std::env::current_dir()?)?;
Ok(tempfile::tempdir_in(canonicalized_tempdir)?)
}
32 changes: 17 additions & 15 deletions git-repository/src/repository/location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,23 @@ impl crate::Repository {
// TODO: tests, details - there is a lot about environment variables to change things around.
pub fn prefix(&self) -> Option<std::io::Result<std::path::PathBuf>> {
self.work_tree.as_ref().map(|root| {
root.canonicalize().and_then(|root| {
std::env::current_dir().and_then(|cwd| {
cwd.strip_prefix(&root)
.map_err(|_| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!(
"CWD '{}' isn't within the work tree '{}'",
cwd.display(),
root.display()
),
)
})
.map(ToOwned::to_owned)
})
std::env::current_dir().and_then(|cwd| {
git_path::realpath(root, &cwd)
.map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))
.and_then(|root| {
cwd.strip_prefix(&root)
.map_err(|_| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!(
"CWD '{}' isn't within the work tree '{}'",
cwd.display(),
root.display()
),
)
})
.map(ToOwned::to_owned)
})
})
})
}
Expand Down
15 changes: 13 additions & 2 deletions git-sec/src/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,19 @@ mod impl_ {
let uid = unsafe { libc::geteuid() };
Ok(uid)
}

Ok(owner_from_path(path)? == owner_of_current_process()?)
use std::str::FromStr;

let owner_of_path = owner_from_path(path)?;
let owner_of_process = owner_of_current_process()?;
if owner_of_path == owner_of_process {
Ok(true)
} else if let Some(sudo_uid) =
std::env::var_os("SUDO_UID").and_then(|val| val.to_str().and_then(|val_str| u32::from_str(val_str).ok()))
{
Ok(owner_of_path == sudo_uid)
} else {
Ok(false)
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/porcelain/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,14 @@ pub struct EstimateHours {
}

mod validator {
use git_repository as git;
use std::{ffi::OsStr, path::PathBuf};

use anyhow::Context;

fn is_repo_inner(dir: &OsStr) -> anyhow::Result<()> {
let git_dir = PathBuf::from(dir).join(".git");
let p = git_dir
.canonicalize()
let p = git::path::realpath(&git_dir, std::env::current_dir()?)
.with_context(|| format!("Could not canonicalize git repository at '{}'", git_dir.display()))?;
if p.extension().unwrap_or_default() == "git"
|| p.file_name().unwrap_or_default() == ".git"
Expand Down

0 comments on commit 0e9df36

Please sign in to comment.