@@ -104,6 +104,8 @@ pub struct Dirs {
104104 entries : Vec < PathBuf > ,
105105 /// The parent directory that contains all the sibling directories.
106106 parent : PathBuf ,
107+ /// Flag indicating whether the current directory is among the sibling directories.
108+ pub on_dirs : bool ,
107109 /// The index of the current directory in the `dirs` vector.
108110 current : usize ,
109111}
@@ -167,7 +169,7 @@ impl Dirs {
167169 ///
168170 /// # Returns
169171 ///
170- /// A [`Result`]<[`Dirs`]> instance.
172+ /// A [`Result`]<[`Dirs`], [`Error`] > instance.
171173 ///
172174 /// # Errors
173175 ///
@@ -202,34 +204,41 @@ impl Dirs {
202204 /// Create a new [`Dirs`] instance from the given file.
203205 /// The file should contain a list of directories, one per line.
204206 /// The first line can optionally specify the parent directory in the format `parent:/path/to`.
207+ /// If the current directory is not found in the list, the current index is set to 0.
208+ /// If `all_target` parameter is false, non-existent directories are skipped and
209+ /// the resultant list does not include them.
205210 ///
206211 /// # Returns
207- /// A [`Result`]<[`Dirs`]> instance.
212+ /// A [`Result`]<[`Dirs`], [`Error`] > instance.
208213 ///
209214 /// # Errors
210215 ///
211216 /// - Returns [`Error::Io`] if an I/O error occurs.
212217 /// - Returns [`Error::NotFile`] if the given path is not a file.
213218 /// - Returns [`Error::NotFound`] if the given path does not exist.
214- pub fn new_from_file < S : AsRef < str > > ( file : S ) -> Result < Self > {
219+ pub fn new_from_file_with < S : AsRef < str > > ( file : S , all_target : bool ) -> Result < Self > {
215220 log:: debug!( "Dirs::new_from_file(file={})" , file. as_ref( ) ) ;
216221 let file = file. as_ref ( ) ;
217222 if file == "-" {
218223 log:: info!( "Reading directories from stdin" ) ;
219- return Ok ( build_from_reader ( Box :: new ( std:: io:: stdin ( ) . lock ( ) ) ) ) ;
224+ return Ok ( build_from_reader ( Box :: new ( std:: io:: stdin ( ) . lock ( ) ) , all_target ) ) ;
220225 }
221226 let path = PathBuf :: from ( file) ;
222227 if !path. exists ( ) {
223- log:: error!( "Dirs::new_from_file: Not found: {}" , path. display( ) ) ;
228+ log:: error!( "Dirs::new_from_file: Not found: {}, pwd: {} " , path. display ( ) , std :: env :: current_dir ( ) . unwrap ( ) . display( ) ) ;
224229 Err ( Error :: NotFound ( path) )
225230 } else if path. is_dir ( ) {
226231 log:: error!( "Dirs::new_from_file: Not a file: {}" , path. display( ) ) ;
227232 Err ( Error :: NotFile ( path) )
228233 } else {
229- build_from_list ( & path)
234+ build_from_list ( & path, all_target )
230235 }
231236 }
232237
238+ pub fn new_from_file < S : AsRef < str > > ( file : S ) -> Result < Self > {
239+ Dirs :: new_from_file_with ( file, false )
240+ }
241+
233242 /// Get the parent directory path.
234243 #[ must_use]
235244 pub fn parent ( & self ) -> & Path {
@@ -281,20 +290,12 @@ fn build_dirs(parent: Option<&Path>, current: PathBuf) -> Result<Dirs> {
281290 let mut errs = vec ! [ ] ;
282291 let dirs = collect_dirs ( parent, & mut errs) ;
283292 if errs. is_empty ( ) {
284- let current_index = find_current ( & dirs, & current) ;
285- let index = if current_index == -1 {
286- log:: warn!(
287- "build_dirs: current directory not found in siblings: {}" ,
288- current. display( )
289- ) ;
290- 0
291- } else {
292- usize:: try_from ( current_index) . unwrap ( )
293- } ;
293+ let ( index, on_dirs) = find_current ( & dirs, & current) ;
294294 log:: info!( "build_dirs: siblings={}, current_index={index}" , dirs. len( ) ) ;
295295 Ok ( Dirs {
296296 entries : dirs,
297297 parent : parent. to_path_buf ( ) ,
298+ on_dirs : on_dirs,
298299 current : index,
299300 } )
300301 } else {
@@ -330,61 +331,77 @@ fn collect_dirs(parent: &Path, errs: &mut Vec<Error>) -> Vec<PathBuf> {
330331}
331332
332333/// Return the index of current in dirs, or 0 if not found.
333- fn find_current ( dirs : & [ PathBuf ] , current : & PathBuf ) -> i32 {
334+ fn find_current ( dirs : & [ PathBuf ] , current : & PathBuf ) -> ( usize , bool ) {
334335 let idx = dirs
335336 . iter ( )
336- . position ( |dir| dir == current)
337- . map_or ( -1 , |i| i32:: try_from ( i) . unwrap ( ) ) ;
338- log:: trace!( "find_current: index={} for {}" , idx, current. display( ) ) ;
339- idx
337+ . position ( |dir| dir == current) ;
338+ if let Some ( index) = idx {
339+ log:: trace!( "find_current: found current at index {index}" ) ;
340+ ( index, true )
341+ } else {
342+ log:: warn!( "find_current: current directory not found in siblings" ) ;
343+ ( 0 , false )
344+ }
340345}
341346
342347/// Parse lines from a reader; parent: sets base, remaining lines are directory entries.
343- fn build_from_reader ( reader : Box < dyn BufRead > ) -> Dirs {
344- let lines = reader
345- . lines ( )
346- . filter_map ( |line| line. map ( |n| n. trim ( ) . to_string ( ) ) . ok ( ) )
347- . collect :: < Vec < String > > ( ) ;
348- let base = if let Some ( base) = lines. iter ( ) . find ( |l| l. starts_with ( "parent:" ) ) {
349- base. chars ( ) . skip ( 7 ) . collect :: < String > ( ) . trim ( ) . to_string ( )
350- } else {
351- "." . to_string ( )
352- } ;
353- let dirs = lines
354- . iter ( )
355- . filter ( |l| !l. starts_with ( "parent:" ) )
356- . map ( PathBuf :: from)
357- . collect :: < Vec < PathBuf > > ( ) ;
358- log:: debug!( "build_from_reader: base='{}', entries={}" , base, dirs. len( ) ) ;
359- let current = find_current_dir_index ( & dirs) ;
360- if current == 0 {
361- log:: warn!( "build_from_reader: current directory not found in siblings" ) ;
348+ fn build_from_reader ( reader : Box < dyn BufRead > , all_target : bool ) -> Dirs {
349+ let mut parent = String :: from ( "." ) ;
350+ let mut lines = vec ! [ ] ;
351+ for line in reader. lines ( ) {
352+ if let Ok ( line) = line {
353+ if line. starts_with ( "parent:" ) {
354+ parent = line. chars ( ) . skip ( "parent:" . len ( ) ) . collect :: < String > ( ) . trim ( ) . to_string ( ) ;
355+ } else {
356+ let p = Path :: new ( line. trim ( ) ) ;
357+ if !all_target && not_exists ( p) {
358+ continue ;
359+ } else {
360+ lines. push ( p. to_path_buf ( ) ) ;
361+ }
362+ }
363+ }
364+ }
365+ log:: debug!( "build_from_reader: base='{}', entries={}" , parent, lines. len( ) ) ;
366+ let ( current, on_dirs) = find_current_dir_index ( & lines) ;
367+ if !on_dirs {
368+ log:: debug!( "build_from_reader: current directory not found in siblings" ) ;
362369 }
363370 Dirs {
364- entries : dirs,
365- parent : PathBuf :: from ( base) ,
371+ entries : lines,
372+ parent : PathBuf :: from ( parent) ,
373+ on_dirs,
366374 current,
367375 }
368376}
369377
370- fn find_current_dir_index ( dirs : & [ PathBuf ] ) -> usize {
378+ fn not_exists ( path : & Path ) -> bool {
379+ if path. exists ( ) {
380+ false
381+ } else {
382+ let sibling_p = Path :: new ( ".." ) . join ( path) ;
383+ !sibling_p. exists ( )
384+ }
385+ }
386+
387+ fn find_current_dir_index ( dirs : & [ PathBuf ] ) -> ( usize , bool ) {
371388 log:: trace!( "find_current_dir_index(dirs.len={})" , dirs. len( ) ) ;
372389 if let Ok ( pwd) = std:: env:: current_dir ( ) {
373390 let cwd = PathBuf :: from ( "." ) ;
374391 if let Some ( pos) = dirs
375392 . iter ( )
376393 . position ( |dir| dir == & cwd || pwd. ends_with ( dir) )
377394 {
378- return pos;
395+ return ( pos, true ) ;
379396 }
380397 }
381- 0
398+ ( 0 , false )
382399}
383400
384- fn build_from_list ( filename : & Path ) -> Result < Dirs > {
401+ fn build_from_list ( filename : & Path , all_target : bool ) -> Result < Dirs > {
385402 if let Ok ( f) = std:: fs:: File :: open ( filename) {
386403 let reader = BufReader :: new ( f) ;
387- Ok ( build_from_reader ( Box :: new ( reader) ) )
404+ Ok ( build_from_reader ( Box :: new ( reader) , all_target ) )
388405 } else {
389406 log:: error!( "build_from_list: I/O error: {}" , filename. display( ) ) ;
390407 Err ( Error :: Io ( std:: io:: Error :: last_os_error ( ) ) )
@@ -548,7 +565,7 @@ mod tests {
548565 let dirs = dirs. unwrap ( ) ;
549566 assert_eq ! ( dirs. len( ) , 4 ) ;
550567 assert_eq ! ( dirs. current, 1 ) ;
551- assert_eq ! ( dirs. parent, PathBuf :: from( "testdata/basic" ) ) ;
568+ assert_eq ! ( dirs. parent, PathBuf :: from( "../ testdata/basic" ) ) ;
552569 }
553570
554571 #[ test]
0 commit comments