1+ //! Determine if two directories have different contents.
2+ //!
3+ //! For now, only one function exists: are they different, or not? In the future,
4+ //! more functionality to actually determine the difference may be added.
5+ //!
6+ //! # Examples
7+ //!
8+ //! ```no_run
9+ //! extern crate dir_diff;
10+ //!
11+ //! assert!(dir_diff::is_different("dir/a", "dir/b").unwrap());
12+ //! ```
13+
14+ extern crate diff;
15+ extern crate walkdir;
16+
17+ use std:: fs:: File ;
18+ use std:: io:: prelude:: * ;
19+ use std:: path:: Path ;
20+
21+ use walkdir:: WalkDir ;
22+
23+ /// The various errors that can happen when diffing two directories
24+ #[ derive( Debug ) ]
25+ pub enum Error {
26+ Io ( std:: io:: Error ) ,
27+ StripPrefix ( std:: path:: StripPrefixError ) ,
28+ WalkDir ( walkdir:: Error ) ,
29+ }
30+
31+ /// Are two directories different?
32+ ///
33+ /// # Examples
34+ ///
35+ /// ```no_run
36+ /// extern crate dir_diff;
37+ ///
38+ /// assert!(dir_diff::is_different("dir/a", "dir/b").unwrap());
39+ /// ```
40+ pub fn is_different < A : AsRef < Path > , B : AsRef < Path > > ( a_base : A , b_base : B ) -> Result < bool , Error > {
41+ let a_base = a_base. as_ref ( ) ;
42+ let b_base = b_base. as_ref ( ) ;
43+
44+ for entry in WalkDir :: new ( a_base) {
45+ let entry = entry?;
46+ let a = entry. path ( ) ;
47+
48+ // calculate just the part of the path relative to a
49+ let no_prefix = a. strip_prefix ( a_base) ?;
50+
51+ // and then join that with b to get the path in b
52+ let b = b_base. join ( no_prefix) ;
53+
54+ if a. is_dir ( ) {
55+ if b. is_dir ( ) {
56+ // can't compare the contents of directories, so just continue
57+ continue ;
58+ } else {
59+ // if one is a file and one is a directory, we have a difference!
60+ return Ok ( false )
61+ }
62+ }
63+
64+ let a_text = read_to_string ( a) ?;
65+ let b_text = read_to_string ( b) ?;
66+
67+ for result in diff:: lines ( & a_text, & b_text) {
68+ match result {
69+ diff:: Result :: Both ( ..) => ( ) ,
70+ _ => return Ok ( false ) ,
71+ }
72+ }
73+ }
74+
75+ Ok ( true )
76+ }
77+
78+ fn read_to_string < P : AsRef < Path > > ( file : P ) -> Result < String , std:: io:: Error > {
79+ let mut data = String :: new ( ) ;
80+ let mut file = File :: open ( file. as_ref ( ) ) ?;
81+
82+ file. read_to_string ( & mut data) ?;
83+
84+ Ok ( data)
85+ }
86+
87+ impl From < std:: io:: Error > for Error {
88+ fn from ( e : std:: io:: Error ) -> Error {
89+ Error :: Io ( e)
90+ }
91+ }
92+
93+ impl From < std:: path:: StripPrefixError > for Error {
94+ fn from ( e : std:: path:: StripPrefixError ) -> Error {
95+ Error :: StripPrefix ( e)
96+ }
97+ }
98+
99+ impl From < walkdir:: Error > for Error {
100+ fn from ( e : walkdir:: Error ) -> Error {
101+ Error :: WalkDir ( e)
102+ }
103+ }
0 commit comments