mirror of
https://github.com/facebook/sapling.git
synced 2024-10-11 09:17:30 +03:00
add symlink handling
Summary: Symlinks are treated as files with "special" mode and link target in contents. `hg diff --git` and `git` behaviours differ wrt to replacing files with symlinks: * git renders that as two operations: removing a file and adding a symlink * hg renders that as file modification I'm choosing the `hg --git` behaviour for now (as it was easier to implement) Reviewed By: krallin Differential Revision: D18169625 fbshipit-source-id: 9ef746c7d242f7142a5ac89924a3e9bed08cb383
This commit is contained in:
parent
c43c91d281
commit
93ad9cffee
@ -31,6 +31,10 @@ struct Opt {
|
||||
#[structopt(short, long)]
|
||||
move_: bool,
|
||||
|
||||
/// Do not follow symlinks - compare them instead (POSIX-only)
|
||||
#[structopt(short, long)]
|
||||
symlink: bool,
|
||||
|
||||
/// Number of lines of unified context (default: 3)
|
||||
#[structopt(short = "U", long, default_value = "3")]
|
||||
unified: usize,
|
||||
@ -40,17 +44,30 @@ fn main() -> Result<(), std::io::Error> {
|
||||
let opt = Opt::from_args();
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
fn file_mode(path: &Path) -> Result<FileType, std::io::Error> {
|
||||
if (path.metadata()?.permissions().mode() & EXEC_BIT) > 0 {
|
||||
Ok(FileType::Executable)
|
||||
fn file_mode_and_contents(
|
||||
opt: &Opt,
|
||||
path: &Path,
|
||||
) -> Result<(FileType, Vec<u8>), std::io::Error> {
|
||||
use std::ffi::OsStr;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
if opt.symlink && path.symlink_metadata()?.file_type().is_symlink() {
|
||||
let dest = path.read_link()?;
|
||||
let dest: &OsStr = dest.as_ref();
|
||||
Ok((FileType::Symlink, dest.as_bytes().to_owned()))
|
||||
} else if (path.metadata()?.permissions().mode() & EXEC_BIT) > 0 {
|
||||
Ok((FileType::Executable, fs::read(path)?))
|
||||
} else {
|
||||
Ok(FileType::Regular)
|
||||
Ok((FileType::Regular, fs::read(path)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_family = "windows")]
|
||||
fn file_mode(path: &Path) -> Result<FileType, std::io::Error> {
|
||||
Ok(FileType::Regular)
|
||||
fn file_mode_and_contents(
|
||||
_opt: &Opt,
|
||||
path: &Path,
|
||||
) -> Result<(FileType, Vec<u8>), std::io::Error> {
|
||||
Ok((FileType::Regular, fs::read(path)?))
|
||||
}
|
||||
|
||||
let copy_info = match (opt.copy, opt.move_) {
|
||||
@ -62,21 +79,15 @@ fn main() -> Result<(), std::io::Error> {
|
||||
|
||||
let a_path_str = opt.file_a.to_string_lossy();
|
||||
let a = if opt.file_a.is_file() {
|
||||
Some(DiffFile::new(
|
||||
a_path_str.as_bytes(),
|
||||
fs::read(&opt.file_a)?,
|
||||
file_mode(&opt.file_a)?,
|
||||
))
|
||||
let (mode, contents) = file_mode_and_contents(&opt, &opt.file_a)?;
|
||||
Some(DiffFile::new(a_path_str.as_bytes(), contents, mode))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let b_path_str = opt.file_b.to_string_lossy();
|
||||
let b = if opt.file_b.is_file() {
|
||||
Some(DiffFile::new(
|
||||
b_path_str.as_bytes(),
|
||||
fs::read(&opt.file_b)?,
|
||||
file_mode(&opt.file_b)?,
|
||||
))
|
||||
let (mode, contents) = file_mode_and_contents(&opt, &opt.file_b)?;
|
||||
Some(DiffFile::new(b_path_str.as_bytes(), contents, mode))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -491,10 +491,10 @@ where
|
||||
reduce,
|
||||
};
|
||||
fn file_type_to_mode(file_type: FileType) -> &'static [u8] {
|
||||
if let FileType::Executable = file_type {
|
||||
b"100755"
|
||||
} else {
|
||||
b"100644"
|
||||
match file_type {
|
||||
FileType::Executable => b"100755",
|
||||
FileType::Symlink => b"120000",
|
||||
FileType::Regular => b"100644",
|
||||
}
|
||||
}
|
||||
if let (None, None) = (&old_file, &new_file) {
|
||||
|
@ -136,3 +136,48 @@ Test with binary file
|
||||
diff --git a/binary_b b/binary_b
|
||||
deleted file mode 100644
|
||||
Binary file binary_b has changed
|
||||
|
||||
Test symlinks
|
||||
$ ln -s a link_to_a
|
||||
$ ln -s b link_to_b
|
||||
$ ln -s a_exec link_to_a_exec
|
||||
|
||||
$ xdiff -s link_to_a link_to_b
|
||||
diff --git a/link_to_a b/link_to_b
|
||||
--- a/link_to_a
|
||||
+++ b/link_to_b
|
||||
@@ -1,1 +1,1 @@
|
||||
-a
|
||||
\ No newline at end of file
|
||||
+b
|
||||
\ No newline at end of file
|
||||
|
||||
$ xdiff -s link_to_a link_to_a
|
||||
|
||||
$ xdiff -s link_to_a link_to_a_exec
|
||||
diff --git a/link_to_a b/link_to_a_exec
|
||||
--- a/link_to_a
|
||||
+++ b/link_to_a_exec
|
||||
@@ -1,1 +1,1 @@
|
||||
-a
|
||||
\ No newline at end of file
|
||||
+a_exec
|
||||
\ No newline at end of file
|
||||
|
||||
$ xdiff -s link_to_a a
|
||||
diff --git a/link_to_a b/a
|
||||
old mode 120000
|
||||
new mode 100644
|
||||
--- a/link_to_a
|
||||
+++ b/a
|
||||
@@ -1,1 +1,6 @@
|
||||
-a
|
||||
\ No newline at end of file
|
||||
+a
|
||||
+b
|
||||
+c
|
||||
+d
|
||||
+e
|
||||
+f
|
||||
|
||||
$ xdiff link_to_a a
|
||||
|
Loading…
Reference in New Issue
Block a user