##// END OF EJS Templates
rhg: Fix status desambiguation of symlinks and executable files...
Simon Sapin -
r49168:d5a91701 default
parent child Browse files
Show More
@@ -580,10 +580,8 b' impl DirstateEntry {'
580 &self,
580 &self,
581 filesystem_metadata: &std::fs::Metadata,
581 filesystem_metadata: &std::fs::Metadata,
582 ) -> bool {
582 ) -> bool {
583 use std::os::unix::fs::MetadataExt;
583 let dirstate_exec_bit = (self.mode() as u32 & EXEC_BIT_MASK) != 0;
584 const EXEC_BIT_MASK: u32 = 0o100;
584 let fs_exec_bit = has_exec_bit(filesystem_metadata);
585 let dirstate_exec_bit = (self.mode() as u32) & EXEC_BIT_MASK;
586 let fs_exec_bit = filesystem_metadata.mode() & EXEC_BIT_MASK;
587 dirstate_exec_bit != fs_exec_bit
585 dirstate_exec_bit != fs_exec_bit
588 }
586 }
589
587
@@ -641,3 +639,11 b' impl Into<u8> for EntryState {'
641 }
639 }
642 }
640 }
643 }
641 }
642
643 const EXEC_BIT_MASK: u32 = 0o100;
644
645 pub fn has_exec_bit(metadata: &std::fs::Metadata) -> bool {
646 // TODO: How to handle executable permissions on Windows?
647 use std::os::unix::fs::MetadataExt;
648 (metadata.mode() & EXEC_BIT_MASK) != 0
649 }
@@ -16,6 +16,22 b" impl Vfs<'_> {"
16 self.base.join(relative_path)
16 self.base.join(relative_path)
17 }
17 }
18
18
19 pub fn symlink_metadata(
20 &self,
21 relative_path: impl AsRef<Path>,
22 ) -> Result<std::fs::Metadata, HgError> {
23 let path = self.join(relative_path);
24 std::fs::symlink_metadata(&path).when_reading_file(&path)
25 }
26
27 pub fn read_link(
28 &self,
29 relative_path: impl AsRef<Path>,
30 ) -> Result<PathBuf, HgError> {
31 let path = self.join(relative_path);
32 std::fs::read_link(&path).when_reading_file(&path)
33 }
34
19 pub fn read(
35 pub fn read(
20 &self,
36 &self,
21 relative_path: impl AsRef<Path>,
37 relative_path: impl AsRef<Path>,
@@ -11,11 +11,12 b' use crate::utils::path_utils::relativize'
11 use clap::{Arg, SubCommand};
11 use clap::{Arg, SubCommand};
12 use hg;
12 use hg;
13 use hg::config::Config;
13 use hg::config::Config;
14 use hg::dirstate::TruncatedTimestamp;
14 use hg::dirstate::{has_exec_bit, TruncatedTimestamp};
15 use hg::errors::HgError;
15 use hg::errors::HgError;
16 use hg::manifest::Manifest;
16 use hg::manifest::Manifest;
17 use hg::matchers::AlwaysMatcher;
17 use hg::matchers::AlwaysMatcher;
18 use hg::repo::Repo;
18 use hg::repo::Repo;
19 use hg::utils::files::get_bytes_from_os_string;
19 use hg::utils::hg_path::{hg_path_to_os_string, HgPath};
20 use hg::utils::hg_path::{hg_path_to_os_string, HgPath};
20 use hg::{HgPathCow, StatusOptions};
21 use hg::{HgPathCow, StatusOptions};
21 use log::{info, warn};
22 use log::{info, warn};
@@ -302,16 +303,30 b' fn display_status_paths('
302 ///
303 ///
303 /// This meant to be used for those that the dirstate cannot resolve, due
304 /// This meant to be used for those that the dirstate cannot resolve, due
304 /// to time resolution limits.
305 /// to time resolution limits.
305 ///
306 /// TODO: detect permission bits and similar metadata modifications
307 fn unsure_is_modified(
306 fn unsure_is_modified(
308 repo: &Repo,
307 repo: &Repo,
309 manifest: &Manifest,
308 manifest: &Manifest,
310 hg_path: &HgPath,
309 hg_path: &HgPath,
311 ) -> Result<bool, HgError> {
310 ) -> Result<bool, HgError> {
311 let vfs = repo.working_directory_vfs();
312 let fs_path = hg_path_to_os_string(hg_path).expect("HgPath conversion");
313 let fs_metadata = vfs.symlink_metadata(&fs_path)?;
314 let is_symlink = fs_metadata.file_type().is_symlink();
315 // TODO: Also account for `FALLBACK_SYMLINK` and `FALLBACK_EXEC` from the dirstate
316 let fs_flags = if is_symlink {
317 Some(b'l')
318 } else if has_exec_bit(&fs_metadata) {
319 Some(b'x')
320 } else {
321 None
322 };
323
312 let entry = manifest
324 let entry = manifest
313 .find_file(hg_path)?
325 .find_file(hg_path)?
314 .expect("ambgious file not in p1");
326 .expect("ambgious file not in p1");
327 if entry.flags != fs_flags {
328 return Ok(true);
329 }
315 let filelog = repo.filelog(hg_path)?;
330 let filelog = repo.filelog(hg_path)?;
316 let filelog_entry =
331 let filelog_entry =
317 filelog.data_for_node(entry.node_id()?).map_err(|_| {
332 filelog.data_for_node(entry.node_id()?).map_err(|_| {
@@ -319,7 +334,10 b' fn unsure_is_modified('
319 })?;
334 })?;
320 let contents_in_p1 = filelog_entry.data()?;
335 let contents_in_p1 = filelog_entry.data()?;
321
336
322 let fs_path = hg_path_to_os_string(hg_path).expect("HgPath conversion");
337 let fs_contents = if is_symlink {
323 let fs_contents = repo.working_directory_vfs().read(fs_path)?;
338 get_bytes_from_os_string(vfs.read_link(fs_path)?.into_os_string())
339 } else {
340 vfs.read(fs_path)?
341 };
324 return Ok(contents_in_p1 != &*fs_contents);
342 return Ok(contents_in_p1 != &*fs_contents);
325 }
343 }
@@ -1,9 +1,5 b''
1 #require execbit
1 #require execbit
2
2
3 TODO: fix rhg bugs that make this test fail when status is enabled
4 $ unset RHG_STATUS
5
6
7 $ hg init
3 $ hg init
8 $ echo a > a
4 $ echo a > a
9 $ hg ci -Am'not executable'
5 $ hg ci -Am'not executable'
@@ -4,10 +4,6 b' Testing merge involving change to the ex'
4
4
5 #require execbit
5 #require execbit
6
6
7 TODO: fix rhg bugs that make this test fail when status is enabled
8 $ unset RHG_STATUS
9
10
11 Initial setup
7 Initial setup
12 ==============
8 ==============
13
9
@@ -1,9 +1,5 b''
1 #require symlink execbit
1 #require symlink execbit
2
2
3 TODO: fix rhg bugs that make this test fail when status is enabled
4 $ unset RHG_STATUS
5
6
7 $ tellmeabout() {
3 $ tellmeabout() {
8 > if [ -h $1 ]; then
4 > if [ -h $1 ]; then
9 > echo $1 is a symlink:
5 > echo $1 is a symlink:
@@ -11,10 +11,6 b''
11 > EOF
11 > EOF
12 #endif
12 #endif
13
13
14 TODO: fix rhg bugs that make this test fail when status is enabled
15 $ unset RHG_STATUS
16
17
18 == tests added in 0.7 ==
14 == tests added in 0.7 ==
19
15
20 $ hg init test-symlinks-0.7; cd test-symlinks-0.7;
16 $ hg init test-symlinks-0.7; cd test-symlinks-0.7;
General Comments 0
You need to be logged in to leave comments. Login now