Skip to content

Commit

Permalink
refactor: avoid the GitHelper and instead keep data on the stack (#126)
Browse files Browse the repository at this point in the history
Co-authored-by: tison <wander4096@gmail.com>
  • Loading branch information
Byron and tisonkun authored Mar 25, 2024
1 parent 76ba70e commit 17a466e
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 99 deletions.
7 changes: 0 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion fmt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ repository.workspace = true
[dependencies]
gix = { version = "0.61", default-features = false, features = ["excludes"] }
ignore = "0.4.22"
pathdiff = "0.2.1"
regex = "1.10.3"
serde = { version = "1.0.197", features = ["derive"] }
snafu.workspace = true
Expand Down
7 changes: 0 additions & 7 deletions fmt/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,6 @@ pub enum Error {
loc: snafu::Location,
},

#[snafu(display("path not found {}", path))]
GixPathNotFount {
path: String,
#[snafu(implicit)]
loc: snafu::Location,
},

#[snafu(display("cannot resolve absolute path {}: {}", path, source))]
ResolveAbsolutePath {
path: String,
Expand Down
86 changes: 25 additions & 61 deletions fmt/src/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,80 +15,44 @@
use std::path::Path;

use gix::Repository;
use snafu::{IntoError, OptionExt, ResultExt};
use snafu::IntoError;
use tracing::info;

use crate::{
config,
error::{
GixCheckExcludeOpSnafu, GixDiscoverOpSnafu, GixExcludeOpSnafu, GixPathNotFountSnafu,
InvalidConfigSnafu, ResolveAbsolutePathSnafu,
},
error::{GixDiscoverOpSnafu, InvalidConfigSnafu},
Result,
};

pub struct GitHelper {
repo: Repository,
}

impl GitHelper {
pub fn create(basedir: &Path, config: config::Git) -> Result<Option<GitHelper>> {
if config.ignore.is_disable() {
return Ok(None);
}
pub fn discover(basedir: &Path, config: config::Git) -> Result<Option<Repository>> {
if config.ignore.is_disable() {
return Ok(None);
}

let is_auto = config.ignore.is_auto();
match gix::discover(basedir) {
Ok(repo) => match repo.worktree() {
None => {
let message = "bare repository detected";
if is_auto {
info!("git.ignore=auto is resolved to fallback; {message}");
Ok(None)
} else {
InvalidConfigSnafu { message }.fail()
}
}
Some(_) => {
info!("git.ignore=auto is resolved to enabled");
Ok(Some(GitHelper { repo }))
}
},
Err(err) => {
let is_auto = config.ignore.is_auto();
match gix::discover(basedir) {
Ok(repo) => match repo.worktree() {
None => {
let message = "bare repository detected";
if is_auto {
info!(?err, "git.ignore=auto is resolved to disabled");
info!("git.ignore=auto is resolved to fallback; {message}");
Ok(None)
} else {
Err(GixDiscoverOpSnafu {}.into_error(Box::new(err)))
InvalidConfigSnafu { message }.fail()
}
}
Some(_) => {
info!("git.ignore=auto is resolved to enabled");
Ok(Some(repo))
}
},
Err(err) => {
if is_auto {
info!(?err, "git.ignore=auto is resolved to disabled");
Ok(None)
} else {
Err(GixDiscoverOpSnafu {}.into_error(Box::new(err)))
}
}
}

pub fn ignored(&self, path: &Path, is_dir: bool) -> Result<bool> {
let path = path.canonicalize().context(ResolveAbsolutePathSnafu {
path: path.display().to_string(),
})?;
let workdir = self
.repo
.work_dir()
.context(GixPathNotFountSnafu { path: "workdir" })?;
let workdir = workdir.canonicalize().context(ResolveAbsolutePathSnafu {
path: workdir.display().to_string(),
})?;
let at_path = pathdiff::diff_paths(path, workdir)
.context(GixPathNotFountSnafu { path: "<relative>" })?;
let worktree = self
.repo
.worktree()
.context(GixPathNotFountSnafu { path: "worktree" })?;
let mut attrs = worktree
.excludes(None)
.map_err(Box::new)
.context(GixExcludeOpSnafu)?;
let platform = attrs
.at_path(at_path, Some(is_dir))
.context(GixCheckExcludeOpSnafu)?;
Ok(platform.is_excluded())
}
}
70 changes: 47 additions & 23 deletions fmt/src/selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use std::path::PathBuf;
use std::path::{Path, PathBuf};

use ignore::overrides::OverrideBuilder;
use snafu::{ensure, ResultExt};
Expand All @@ -21,9 +21,11 @@ use walkdir::WalkDir;

use crate::{
config,
error::{SelectFilesSnafu, SelectWithIgnoreSnafu, TraverseDirSnafu},
git::GitHelper,
Result,
error::{
GixCheckExcludeOpSnafu, GixExcludeOpSnafu, ResolveAbsolutePathSnafu, SelectFilesSnafu,
SelectWithIgnoreSnafu, TraverseDirSnafu,
},
git, Result,
};

pub struct Selection {
Expand Down Expand Up @@ -91,21 +93,17 @@ impl Selection {
},
);

let result = match GitHelper::create(&self.basedir, self.git)? {
let result = match git::discover(&self.basedir, self.git)? {
None => select_files_with_ignore(
&self.basedir,
&includes,
&excludes,
&reverse_excludes,
self.git.ignore.is_auto(),
)?,
Some(git_helper) => select_files_with_git(
&self.basedir,
&includes,
&excludes,
&reverse_excludes,
git_helper,
)?,
Some(repo) => {
select_files_with_git(&self.basedir, &includes, &excludes, &reverse_excludes, repo)?
}
};

debug!("selected files: {:?} (count: {})", result, result.len());
Expand All @@ -120,7 +118,7 @@ fn select_files_with_ignore(
reverse_excludes: &[String],
turn_on_git_ignore: bool,
) -> Result<Vec<PathBuf>> {
debug!("Selecting files with ignore crate");
debug!(turn_on_git_ignore, "Selecting files with ignore crate");
let mut result = vec![];

let walker = ignore::WalkBuilder::new(basedir)
Expand Down Expand Up @@ -158,11 +156,11 @@ fn select_files_with_ignore(
}

fn select_files_with_git(
basedir: &PathBuf,
basedir: &Path,
includes: &[String],
excludes: &[String],
reverse_excludes: &[String],
git_helper: GitHelper,
repo: gix::Repository,
) -> Result<Vec<PathBuf>> {
debug!("Selecting files with git helper");
let mut result = vec![];
Expand All @@ -182,15 +180,43 @@ fn select_files_with_git(
builder.build().context(SelectWithIgnoreSnafu)?
};

let mut it = WalkDir::new(basedir).into_iter();
let basedir = basedir
.canonicalize()
.with_context(|_| ResolveAbsolutePathSnafu {
path: basedir.display().to_string(),
})?;
let mut it = WalkDir::new(basedir).follow_links(false).into_iter();

let workdir = repo.work_dir().expect("workdir cannot be absent");
let workdir = workdir
.canonicalize()
.with_context(|_| ResolveAbsolutePathSnafu {
path: workdir.display().to_string(),
})?;
let worktree = repo.worktree().expect("worktree cannot be absent");
let mut excludes = worktree
.excludes(None)
.map_err(Box::new)
.context(GixExcludeOpSnafu)?;

while let Some(entry) = it.next() {
let entry = entry.context(TraverseDirSnafu)?;
let path = entry.path();
let file_type = entry.file_type();
if file_type.is_symlink() {
debug!("skip symlink: {:?}", path);
} else if file_type.is_dir() {
if git_helper.ignored(path, true)? {
if !file_type.is_file() && !file_type.is_dir() {
debug!(?file_type, "skip file: {path:?}");
continue;
}

let rela_path = path
.strip_prefix(&workdir)
.expect("git repository encloses iteration");
let platform = excludes
.at_path(rela_path, Some(file_type.is_dir()))
.context(GixCheckExcludeOpSnafu)?;

if file_type.is_dir() {
if platform.is_excluded() {
debug!("skip git ignored directory: {:?}", path);
it.skip_current_dir();
continue;
Expand All @@ -201,7 +227,7 @@ fn select_files_with_git(
continue;
}
} else if file_type.is_file() {
if git_helper.ignored(path, false)? {
if platform.is_excluded() {
debug!("skip git ignored file: {:?}", path);
continue;
}
Expand All @@ -210,8 +236,6 @@ fn select_files_with_git(
continue;
}
result.push(path.to_path_buf());
} else {
debug!("skip unknown file type ({:?}): {:?}", file_type, path);
}
}

Expand Down

0 comments on commit 17a466e

Please sign in to comment.