Mercurial > hg
comparison rust/rhg/src/commands/status.rs @ 48345:d5a91701f7dc
rhg: Fix status desambiguation of symlinks and executable files
Differential Revision: https://phab.mercurial-scm.org/D11774
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Tue, 23 Nov 2021 20:04:22 +0100 |
parents | b6d8eea9872c |
children | c12ed33558cb |
comparison
equal
deleted
inserted
replaced
48344:b6d8eea9872c | 48345:d5a91701f7dc |
---|---|
9 use crate::ui::{Ui, UiError}; | 9 use crate::ui::{Ui, UiError}; |
10 use crate::utils::path_utils::relativize_paths; | 10 use crate::utils::path_utils::relativize_paths; |
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}; |
22 use std::borrow::Cow; | 23 use std::borrow::Cow; |
23 | 24 |
300 | 301 |
301 /// Check if a file is modified by comparing actual repo store and file system. | 302 /// Check if a file is modified by comparing actual repo store and file system. |
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(|_| { |
318 HgError::corrupted("filelog missing node from manifest") | 333 HgError::corrupted("filelog missing node from manifest") |
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 } |