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 }