2
2
3
3
use snafu:: prelude:: * ;
4
4
5
+ use camino:: { Utf8Path , Utf8PathBuf } ;
5
6
use filetime:: FileTime ;
6
7
use git2:: { Diff , Oid , Repository } ;
7
8
use std:: collections:: { HashMap , HashSet } ;
8
- use std:: path :: { Path , PathBuf } ;
9
+ use std:: convert :: TryInto ;
9
10
use std:: sync:: { Arc , RwLock } ;
10
11
use std:: { env, fs} ;
11
12
@@ -30,6 +31,10 @@ pub enum Error {
30
31
PathError {
31
32
source : std:: path:: StripPrefixError ,
32
33
} ,
34
+ #[ snafu( display( "Path contains invalide Unicode:\n {}" , source) ) ]
35
+ PathEncodingError {
36
+ source : camino:: FromPathBufError ,
37
+ } ,
33
38
UnresolvedError { } ,
34
39
}
35
40
@@ -43,7 +48,7 @@ impl std::fmt::Debug for Error {
43
48
44
49
pub type Result < T , E = Error > = std:: result:: Result < T , E > ;
45
50
46
- pub type FileSet = HashSet < PathBuf > ;
51
+ pub type FileSet = HashSet < Utf8PathBuf > ;
47
52
48
53
/// Options passed to `reset_mtimes()`
49
54
#[ derive( Clone , Debug ) ]
@@ -144,14 +149,20 @@ pub fn get_repo() -> Result<Repository> {
144
149
}
145
150
146
151
/// 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())
153
164
} else {
154
- prefix. join ( path. clone ( ) )
165
+ prefix. join ( path)
155
166
} ;
156
167
Ok ( resolved_path)
157
168
}
@@ -204,7 +215,7 @@ fn gather_workdir_files(repo: &Repository) -> Result<FileSet> {
204
215
tree. walk ( git2:: TreeWalkMode :: PostOrder , |dir, entry| {
205
216
if let Some ( name) = entry. name ( ) {
206
217
let file = format ! ( "{}{}" , dir, name) ;
207
- let path = Path :: new ( & file) ;
218
+ let path = Utf8Path :: new ( & file) ;
208
219
if path. is_dir ( ) {
209
220
return git2:: TreeWalkResult :: Skip ;
210
221
}
@@ -216,7 +227,7 @@ fn gather_workdir_files(repo: &Repository) -> Result<FileSet> {
216
227
Ok ( workdir_files)
217
228
}
218
229
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 {
220
231
diff. deltas ( ) . any ( |delta| {
221
232
delta. new_file ( ) . id ( ) == * oid
222
233
&& delta
@@ -227,7 +238,7 @@ fn diff_affects_oid(diff: &Diff, oid: &Oid, touchable_path: &mut PathBuf) -> boo
227
238
} )
228
239
}
229
240
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 > {
231
242
let commit_time = FileTime :: from_unix_time ( time, 0 ) ;
232
243
let metadata = fs:: metadata ( & path) . context ( IoSnafu ) ?;
233
244
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> {
247
258
248
259
fn process_touchables ( repo : & Repository , touchables : FileSet , opts : & Options ) -> Result < FileSet > {
249
260
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 ( ) ;
251
262
let mut revwalk = repo. revwalk ( ) . context ( LibGitSnafu ) ?;
252
263
// See https://github.com/arkark/git-hist/blob/main/src/app/git.rs
253
264
revwalk. push_head ( ) . context ( LibGitSnafu ) ?;
@@ -261,9 +272,9 @@ fn process_touchables(repo: &Repository, touchables: FileSet, opts: &Options) ->
261
272
. tree ( )
262
273
. context ( LibGitSnafu ) ?;
263
274
touchables. iter ( ) . for_each ( |path| {
264
- let touchable_path = Path :: new ( & path) . to_path_buf ( ) ;
275
+ let touchable_path: Utf8PathBuf = path. into ( ) ;
265
276
let current_oid = latest_tree
266
- . get_path ( & touchable_path)
277
+ . get_path ( & touchable_path. clone ( ) . into_std_path_buf ( ) )
267
278
. and_then ( |entry| {
268
279
if let Some ( git2:: ObjectType :: Blob ) = entry. kind ( ) {
269
280
Ok ( entry)
0 commit comments