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