Skip to content

Commit d6ea895

Browse files
committed
feat(lib): Simplify path handling by limiting to Unicode
1 parent 1b11652 commit d6ea895

File tree

4 files changed

+29
-17
lines changed

4 files changed

+29
-17
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ zsh = ["completions"]
3131
lto = true
3232

3333
[dependencies]
34+
camino = "1.1"
3435
filetime = "0.2"
3536
snafu = "0.8"
3637
snafu-cli-debug = "0.1"

README.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,10 @@ Then use the crate functions and types in your project something like this:
5757
```rust
5858
use git_warp_time::{get_repo, reset_mtimes};
5959
use git_warp_time::{FileSet, Options};
60-
use std::path::PathBuf;
6160

6261
let repo = get_repo().unwrap();
6362
let mut paths = FileSet::new();
64-
paths.insert(PathBuf::from("foo.txt"));
63+
paths.insert("foo.txt".into());
6564
let mut opts = Options::new();
6665
opts.verbose(true).paths(Some(paths));
6766
let files = reset_mtimes(repo, opts).unwrap();

src/lib.rs

+26-15
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
use snafu::prelude::*;
44

5+
use camino::{Utf8Path, Utf8PathBuf};
56
use filetime::FileTime;
67
use git2::{Diff, Oid, Repository};
78
use std::collections::{HashMap, HashSet};
8-
use std::path::{Path, PathBuf};
9+
use std::convert::TryInto;
910
use std::sync::{Arc, RwLock};
1011
use std::{env, fs};
1112

@@ -30,6 +31,10 @@ pub enum Error {
3031
PathError {
3132
source: std::path::StripPrefixError,
3233
},
34+
#[snafu(display("Path contains invalide Unicode:\n{}", source))]
35+
PathEncodingError {
36+
source: camino::FromPathBufError,
37+
},
3338
UnresolvedError {},
3439
}
3540

@@ -43,7 +48,7 @@ impl std::fmt::Debug for Error {
4348

4449
pub type Result<T, E = Error> = std::result::Result<T, E>;
4550

46-
pub type FileSet = HashSet<PathBuf>;
51+
pub type FileSet = HashSet<Utf8PathBuf>;
4752

4853
/// Options passed to `reset_mtimes()`
4954
#[derive(Clone, Debug)]
@@ -144,14 +149,20 @@ pub fn get_repo() -> Result<Repository> {
144149
}
145150

146151
/// Convert a path relative to the current working directory to be relative to the repository root
147-
pub fn resolve_repo_path(repo: &Repository, path: &String) -> Result<PathBuf> {
148-
let cwd = env::current_dir().context(IoSnafu)?;
149-
let root = repo.workdir().context(UnresolvedSnafu)?.to_path_buf();
150-
let prefix = cwd.strip_prefix(&root).context(PathSnafu)?;
151-
let resolved_path = if Path::new(&path).is_absolute() {
152-
PathBuf::from(path.clone())
152+
pub fn resolve_repo_path(repo: &Repository, path: impl Into<Utf8PathBuf>) -> Result<Utf8PathBuf> {
153+
let path: Utf8PathBuf = path.into();
154+
let cwd: Utf8PathBuf = env::current_dir()
155+
.context(IoSnafu)?
156+
.try_into()
157+
.context(PathEncodingSnafu)?;
158+
let root = repo.workdir().context(UnresolvedSnafu)?;
159+
let prefix: Utf8PathBuf = cwd.strip_prefix(root).context(PathSnafu)?.into();
160+
let resolved_path = if path.is_absolute() {
161+
path
162+
//path.clone().into()
163+
//Utf8PathBuf::from(path.clone())
153164
} else {
154-
prefix.join(path.clone())
165+
prefix.join(path)
155166
};
156167
Ok(resolved_path)
157168
}
@@ -204,7 +215,7 @@ fn gather_workdir_files(repo: &Repository) -> Result<FileSet> {
204215
tree.walk(git2::TreeWalkMode::PostOrder, |dir, entry| {
205216
if let Some(name) = entry.name() {
206217
let file = format!("{}{}", dir, name);
207-
let path = Path::new(&file);
218+
let path = Utf8Path::new(&file);
208219
if path.is_dir() {
209220
return git2::TreeWalkResult::Skip;
210221
}
@@ -216,7 +227,7 @@ fn gather_workdir_files(repo: &Repository) -> Result<FileSet> {
216227
Ok(workdir_files)
217228
}
218229

219-
fn diff_affects_oid(diff: &Diff, oid: &Oid, touchable_path: &mut PathBuf) -> bool {
230+
fn diff_affects_oid(diff: &Diff, oid: &Oid, touchable_path: &mut Utf8PathBuf) -> bool {
220231
diff.deltas().any(|delta| {
221232
delta.new_file().id() == *oid
222233
&& delta
@@ -227,7 +238,7 @@ fn diff_affects_oid(diff: &Diff, oid: &Oid, touchable_path: &mut PathBuf) -> boo
227238
})
228239
}
229240

230-
fn touch_if_older(path: PathBuf, time: i64, verbose: bool) -> Result<bool> {
241+
fn touch_if_older(path: Utf8PathBuf, time: i64, verbose: bool) -> Result<bool> {
231242
let commit_time = FileTime::from_unix_time(time, 0);
232243
let metadata = fs::metadata(&path).context(IoSnafu)?;
233244
let file_mtime = FileTime::from_last_modification_time(&metadata);
@@ -247,7 +258,7 @@ fn touch_if_older(path: PathBuf, time: i64, verbose: bool) -> Result<bool> {
247258

248259
fn process_touchables(repo: &Repository, touchables: FileSet, opts: &Options) -> Result<FileSet> {
249260
let touched = Arc::new(RwLock::new(FileSet::new()));
250-
let mut touchable_oids: HashMap<Oid, PathBuf> = HashMap::new();
261+
let mut touchable_oids: HashMap<Oid, Utf8PathBuf> = HashMap::new();
251262
let mut revwalk = repo.revwalk().context(LibGitSnafu)?;
252263
// See https://github.com/arkark/git-hist/blob/main/src/app/git.rs
253264
revwalk.push_head().context(LibGitSnafu)?;
@@ -261,9 +272,9 @@ fn process_touchables(repo: &Repository, touchables: FileSet, opts: &Options) ->
261272
.tree()
262273
.context(LibGitSnafu)?;
263274
touchables.iter().for_each(|path| {
264-
let touchable_path = Path::new(&path).to_path_buf();
275+
let touchable_path: Utf8PathBuf = path.into();
265276
let current_oid = latest_tree
266-
.get_path(&touchable_path)
277+
.get_path(&touchable_path.clone().into_std_path_buf())
267278
.and_then(|entry| {
268279
if let Some(git2::ObjectType::Blob) = entry.kind() {
269280
Ok(entry)

0 commit comments

Comments
 (0)