rust/hg-core/src/dirstate_tree/status.rs
changeset 48745 94e36b230990
parent 48501 4afb9627dc77
child 48794 834c938227c6
equal deleted inserted replaced
48744:6e930bc45aeb 48745:94e36b230990
    63             (Box::new(|&_| true), vec![], None)
    63             (Box::new(|&_| true), vec![], None)
    64         };
    64         };
    65 
    65 
    66     let filesystem_time_at_status_start =
    66     let filesystem_time_at_status_start =
    67         filesystem_now(&root_dir).ok().map(TruncatedTimestamp::from);
    67         filesystem_now(&root_dir).ok().map(TruncatedTimestamp::from);
       
    68 
       
    69     // If the repository is under the current directory, prefer using a
       
    70     // relative path, so the kernel needs to traverse fewer directory in every
       
    71     // call to `read_dir` or `symlink_metadata`.
       
    72     // This is effective in the common case where the current directory is the
       
    73     // repository root.
       
    74 
       
    75     // TODO: Better yet would be to use libc functions like `openat` and
       
    76     // `fstatat` to remove such repeated traversals entirely, but the standard
       
    77     // library does not provide APIs based on those.
       
    78     // Maybe with a crate like https://crates.io/crates/openat instead?
       
    79     let root_dir = if let Some(relative) = std::env::current_dir()
       
    80         .ok()
       
    81         .and_then(|cwd| root_dir.strip_prefix(cwd).ok())
       
    82     {
       
    83         relative
       
    84     } else {
       
    85         &root_dir
       
    86     };
       
    87 
    68     let outcome = DirstateStatus {
    88     let outcome = DirstateStatus {
    69         filesystem_time_at_status_start,
    89         filesystem_time_at_status_start,
    70         ..Default::default()
    90         ..Default::default()
    71     };
    91     };
    72     let common = StatusCommon {
    92     let common = StatusCommon {
   750     ///
   770     ///
   751     /// * At the repository root, ignore that sub-directory
   771     /// * At the repository root, ignore that sub-directory
   752     /// * Elsewhere, we’re listing the content of a sub-repo. Return an empty
   772     /// * Elsewhere, we’re listing the content of a sub-repo. Return an empty
   753     ///   list instead.
   773     ///   list instead.
   754     fn read_dir(path: &Path, is_at_repo_root: bool) -> io::Result<Vec<Self>> {
   774     fn read_dir(path: &Path, is_at_repo_root: bool) -> io::Result<Vec<Self>> {
       
   775         // `read_dir` returns a "not found" error for the empty path
       
   776         let at_cwd = path == Path::new("");
       
   777         let read_dir_path = if at_cwd { Path::new(".") } else { path };
   755         let mut results = Vec::new();
   778         let mut results = Vec::new();
   756         for entry in path.read_dir()? {
   779         for entry in read_dir_path.read_dir()? {
   757             let entry = entry?;
   780             let entry = entry?;
   758             let metadata = entry.metadata()?;
   781             let metadata = entry.metadata()?;
   759             let name = get_bytes_from_os_string(entry.file_name());
   782             let file_name = entry.file_name();
   760             // FIXME don't do this when cached
   783             // FIXME don't do this when cached
   761             if name == b".hg" {
   784             if file_name == ".hg" {
   762                 if is_at_repo_root {
   785                 if is_at_repo_root {
   763                     // Skip the repo’s own .hg (might be a symlink)
   786                     // Skip the repo’s own .hg (might be a symlink)
   764                     continue;
   787                     continue;
   765                 } else if metadata.is_dir() {
   788                 } else if metadata.is_dir() {
   766                     // A .hg sub-directory at another location means a subrepo,
   789                     // A .hg sub-directory at another location means a subrepo,
   767                     // skip it entirely.
   790                     // skip it entirely.
   768                     return Ok(Vec::new());
   791                     return Ok(Vec::new());
   769                 }
   792                 }
   770             }
   793             }
       
   794             let full_path = if at_cwd {
       
   795                 file_name.clone().into()
       
   796             } else {
       
   797                 entry.path()
       
   798             };
       
   799             let base_name = get_bytes_from_os_string(file_name).into();
   771             results.push(DirEntry {
   800             results.push(DirEntry {
   772                 base_name: name.into(),
   801                 base_name,
   773                 full_path: entry.path(),
   802                 full_path,
   774                 metadata,
   803                 metadata,
   775             })
   804             })
   776         }
   805         }
   777         Ok(results)
   806         Ok(results)
   778     }
   807     }