Skip to content

Commit a3714ef

Browse files
committed
symlink probing (#301)
1 parent 3556af4 commit a3714ef

File tree

4 files changed

+56
-0
lines changed

4 files changed

+56
-0
lines changed

Cargo.lock

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

git-worktree/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ quick-error = "2.0.1"
2828
bstr = { version = "0.2.13", default-features = false }
2929

3030
document-features = { version = "0.2.0", optional = true }
31+
symlink = "0.1.0"
3132

3233
[dev-dependencies]
3334
git-testtools = { path = "../tests/tools" }

git-worktree/src/fs.rs

+43
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,49 @@ pub struct Context {
1919
pub symlink: bool,
2020
}
2121

22+
impl Context {
23+
/// try to determine all values in this context by probing them in the current working directory, which should be on the file system
24+
/// the git repository is located on.
25+
///
26+
/// All errors are ignored and interpreted on top of the default for the platform the binary is compiled for.
27+
pub fn from_probing_cwd() -> Self {
28+
let ctx = Context::default();
29+
Context {
30+
symlink: Self::probe_symlink().unwrap_or(ctx.symlink),
31+
..ctx
32+
}
33+
}
34+
35+
fn probe_symlink() -> Option<bool> {
36+
let src_path = "__link_src_file";
37+
std::fs::File::options()
38+
.create_new(true)
39+
.write(true)
40+
.open(src_path)
41+
.ok()?;
42+
let link_path = "__file_link";
43+
if symlink::symlink_file(src_path, link_path).is_err() {
44+
std::fs::remove_file(src_path).ok();
45+
return None;
46+
}
47+
let cleanup_all = || {
48+
std::fs::remove_file(src_path).ok();
49+
symlink::remove_symlink_file(link_path)
50+
.or_else(|_| std::fs::remove_file(link_path))
51+
.ok();
52+
};
53+
54+
let res = Some(
55+
std::fs::symlink_metadata(link_path)
56+
.map_err(|_| cleanup_all())
57+
.ok()?
58+
.is_symlink(),
59+
);
60+
cleanup_all();
61+
res
62+
}
63+
}
64+
2265
#[cfg(windows)]
2366
impl Default for Context {
2467
fn default() -> Self {

git-worktree/tests/index/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ mod checkout {
1717
#[test]
1818
fn allow_symlinks() -> crate::Result {
1919
let opts = opts_with_symlink(true);
20+
if !git_worktree::fs::Context::from_probing_cwd().symlink {
21+
eprintln!("IGNORING symlink test on file system without symlink support");
22+
// skip if symlinks aren't supported anyway.
23+
return Ok(());
24+
};
2025
let (source_tree, destination) = setup_fixture_with_options(opts, "make_mixed_without_submodules")?;
2126

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

0 commit comments

Comments
 (0)