Reduce calls to fs::metadata in list_git_files

When walking over entries in the index of a git repository the file type can be
known without a syscall (in the form of a libc constant), but walking over
untracked files still requires a syscall to determine if it's a directory.
This commit is contained in:
Alex Crichton 2015-05-19 23:07:15 -07:00
parent e595e87762
commit 046a6c59e9

View file

@ -4,8 +4,9 @@ use std::fs;
use std::io::prelude::*; use std::io::prelude::*;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use glob::Pattern;
use git2; use git2;
use glob::Pattern;
use libc;
use core::{Package, PackageId, Summary, SourceId, Source, Dependency, Registry}; use core::{Package, PackageId, Summary, SourceId, Source, Dependency, Registry};
use ops; use ops;
@ -146,15 +147,19 @@ impl<'cfg> PathSource<'cfg> {
// Here we're also careful to look at both tracked an untracked files as // Here we're also careful to look at both tracked an untracked files as
// the untracked files are often part of a build and may become relevant // the untracked files are often part of a build and may become relevant
// as part of a future commit. // as part of a future commit.
let index_files = index.iter().map(|entry| join(&root, &entry.path)); let index_files = index.iter().map(|entry| {
let is_dir = entry.mode & (libc::S_IFMT as u32) ==
(libc::S_IFDIR as u32);
(join(&root, &entry.path), Some(is_dir))
});
let mut opts = git2::StatusOptions::new(); let mut opts = git2::StatusOptions::new();
opts.include_untracked(true); opts.include_untracked(true);
let statuses = try!(repo.statuses(Some(&mut opts))); let statuses = try!(repo.statuses(Some(&mut opts)));
let untracked = statuses.iter().map(|entry| { let untracked = statuses.iter().map(|entry| {
join(&root, entry.path_bytes()) (join(&root, entry.path_bytes()), None)
}); });
'outer: for file_path in index_files.chain(untracked) { 'outer: for (file_path, is_dir) in index_files.chain(untracked) {
let file_path = try!(file_path); let file_path = try!(file_path);
// Filter out files outside this package. // Filter out files outside this package.
@ -176,9 +181,10 @@ impl<'cfg> PathSource<'cfg> {
} }
} }
// TODO: the `entry` has a mode we should be able to look at instead let is_dir = is_dir.or_else(|| {
// of just calling stat() again fs::metadata(&file_path).ok().map(|m| m.is_dir())
if fs::metadata(&file_path).map(|m| m.is_dir()).unwrap_or(false) { }).unwrap_or(false);
if is_dir {
warn!(" found submodule {}", file_path.display()); warn!(" found submodule {}", file_path.display());
let rel = util::without_prefix(&file_path, &root).unwrap(); let rel = util::without_prefix(&file_path, &root).unwrap();
let rel = try!(rel.to_str().chain_error(|| { let rel = try!(rel.to_str().chain_error(|| {