Skip to content

Commit

Permalink
refactor for checkout to use fs::Context (#301)
Browse files Browse the repository at this point in the history
The latter should be useful when fully implementing all required
baseline capabilities of doing a correct checkout
  • Loading branch information
Byron committed Feb 28, 2022
1 parent f53c395 commit b14ac1e
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 76 deletions.
56 changes: 56 additions & 0 deletions git-worktree/src/fs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/// Common knowledge about the worktree that is needed across most interactions with the work tree
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
pub struct Context {
/// If true, the filesystem will store paths as decomposed unicode, i.e. `ä` becomes `"a\u{308}"`, which means that
/// we have to turn these forms back from decomposed to precomposed unicode before storing it in the index or generally
/// using it. This also applies to input received from the command-line, so callers may have to be aware of this and
/// perform conversions accordingly.
/// If false, no conversions will be performed.
pub precompose_unicode: bool,
/// If true, the filesystem ignores the case of input, which makes `A` the same file as `a`.
/// This is also called case-folding.
pub ignore_case: bool,
/// If true, we assume the the executable bit is honored as part of the files mode. If false, we assume the file system
/// ignores the executable bit, hence it will be reported as 'off' even though we just tried to set it to be on.
pub file_mode: bool,
/// If true, the file system supports symbolic links and we should try to create them. Otherwise symbolic links will be checked
/// out as files which contain the link as text.
pub symlink: bool,
}

#[cfg(windows)]
impl Default for Context {
fn default() -> Self {
Context {
precompose_unicode: false,
ignore_case: true,
file_mode: false,
symlink: false,
}
}
}

#[cfg(target_os = "macos")]
impl Default for Context {
fn default() -> Self {
Context {
precompose_unicode: true,
ignore_case: true,
file_mode: true,
symlink: true,
}
}
}

#[cfg(all(unix, not(target_os = "macos")))]
impl Default for Context {
fn default() -> Self {
Context {
precompose_unicode: false,
ignore_case: false,
file_mode: true,
symlink: true,
}
}
}
17 changes: 7 additions & 10 deletions git-worktree/src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@ pub mod checkout {
use bstr::BString;
use quick_error::quick_error;

#[derive(Clone, Copy)]
#[derive(Default, Clone, Copy)]
pub struct Options {
pub symlinks: bool,
}

impl Default for Options {
fn default() -> Self {
Options { symlinks: true }
}
/// capabilities of the file system
pub fs: crate::fs::Context,
}

quick_error! {
Expand Down Expand Up @@ -79,7 +74,9 @@ pub(crate) mod entry {
entry_path: &BStr,
find: &mut Find,
root: &std::path::Path,
index::checkout::Options { symlinks }: index::checkout::Options,
index::checkout::Options {
fs: crate::fs::Context { symlink, .. },
}: index::checkout::Options,
buf: &mut Vec<u8>,
) -> Result<(), index::checkout::Error>
where
Expand Down Expand Up @@ -124,7 +121,7 @@ pub(crate) mod entry {
})?;
let symlink_destination = git_features::path::from_byte_slice(obj.data)
.map_err(|_| index::checkout::Error::IllformedUtf8 { path: obj.data.into() })?;
if symlinks {
if symlink {
#[cfg(unix)]
std::os::unix::fs::symlink(symlink_destination, &dest)?;
#[cfg(windows)]
Expand Down
59 changes: 1 addition & 58 deletions git-worktree/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,63 +6,6 @@
#![forbid(unsafe_code, rust_2018_idioms)]

/// file system related utilities
pub mod fs {
/// Common knowledge about the worktree that is needed across most interactions with the work tree
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
pub struct Context {
/// If true, the filesystem will store paths as decomposed unicode, i.e. `ä` becomes `"a\u{308}"`, which means that
/// we have to turn these forms back from decomposed to precomposed unicode before storing it in the index or generally
/// using it. This also applies to input received from the command-line, so callers may have to be aware of this and
/// perform conversions accordingly.
/// If false, no conversions will be performed.
pub precompose_unicode: bool,
/// If true, the filesystem ignores the case of input, which makes `A` the same file as `a`.
/// This is also called case-folding.
pub ignore_case: bool,
/// If true, we assume the the executable bit is honored as part of the files mode. If false, we assume the file system
/// ignores the executable bit, hence it will be reported as 'off' even though we just tried to set it to be on.
pub file_mode: bool,
/// If true, the file system supports symbolic links and we should try to create them. Otherwise symbolic links will be checked
/// out as files which contain the link as text.
pub symlink: bool,
}

#[cfg(windows)]
impl Default for Context {
fn default() -> Self {
Context {
precompose_unicode: false,
ignore_case: true,
file_mode: false,
symlink: false,
}
}
}

#[cfg(target_os = "macos")]
impl Default for Context {
fn default() -> Self {
Context {
precompose_unicode: true,
ignore_case: true,
file_mode: true,
symlink: true,
}
}
}

#[cfg(all(unix, not(target_os = "macos")))]
impl Default for Context {
fn default() -> Self {
Context {
precompose_unicode: false,
ignore_case: false,
file_mode: true,
symlink: true,
}
}
}
}
pub mod fs;

pub mod index;
11 changes: 11 additions & 0 deletions git-worktree/tests/fixtures/make_ignorecase_collisions.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash
set -eu -o pipefail

git init -q
git config commit.gpgsign false

touch a A
git add a
echo A | git update-index --add --stdin

git commit -m "init"
File renamed without changes.
29 changes: 21 additions & 8 deletions git-worktree/tests/index/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,29 @@ mod checkout {

#[test]
fn allow_symlinks() -> crate::Result {
let opts = Default::default();
let (source_tree, destination) = setup_fixture_with_options(opts)?;
let opts = index::checkout::Options {
fs: git_worktree::fs::Context {
symlink: true,
..Default::default()
},
};
let (source_tree, destination) = setup_fixture_with_options(opts, "make_mixed_without_submodules")?;

assert_equality(&source_tree, &destination, opts.symlinks)?;
assert_equality(&source_tree, &destination, opts.fs.symlink)?;
Ok(())
}

#[test]
fn symlinks_become_files_if_disabled() -> crate::Result {
let opts = index::checkout::Options { symlinks: false };
let (source_tree, destination) = setup_fixture_with_options(opts)?;
let opts = index::checkout::Options {
fs: git_worktree::fs::Context {
symlink: false,
..Default::default()
},
};
let (source_tree, destination) = setup_fixture_with_options(opts, "make_mixed_without_submodules")?;

assert_equality(&source_tree, &destination, opts.symlinks)?;
assert_equality(&source_tree, &destination, opts.fs.symlink)?;

Ok(())
}
Expand Down Expand Up @@ -71,8 +81,11 @@ mod checkout {
files
}

fn setup_fixture_with_options(opts: git_worktree::index::checkout::Options) -> crate::Result<(PathBuf, TempDir)> {
let source_tree = fixture_path("make_repo");
fn setup_fixture_with_options(
opts: git_worktree::index::checkout::Options,
name: &str,
) -> crate::Result<(PathBuf, TempDir)> {
let source_tree = fixture_path(name);
let git_dir = source_tree.join(".git");
let mut index = git_index::File::at(git_dir.join("index"), Default::default())?;
let odb = git_odb::at(git_dir.join("objects"))?;
Expand Down

0 comments on commit b14ac1e

Please sign in to comment.