1
1
use super :: utils:: { repo, work_dir} ;
2
2
use crate :: error:: Result ;
3
3
use scopetime:: scope_time;
4
- use std:: { fs:: OpenOptions , io:: Write } ;
4
+ use std:: {
5
+ fs:: { File , OpenOptions } ,
6
+ io:: { Read , Seek , SeekFrom , Write } ,
7
+ path:: PathBuf ,
8
+ } ;
5
9
6
10
static GITIGNORE : & str = ".gitignore" ;
7
11
@@ -16,12 +20,110 @@ pub fn add_to_ignore(
16
20
17
21
let ignore_file = work_dir ( & repo) . join ( GITIGNORE ) ;
18
22
23
+ let optional_newline = ignore_file. exists ( )
24
+ && !file_ends_with_newline ( & ignore_file) ?;
25
+
19
26
let mut file = OpenOptions :: new ( )
20
27
. append ( true )
21
28
. create ( true )
22
29
. open ( ignore_file) ?;
23
30
24
- writeln ! ( file, "{}" , path_to_ignore) ?;
31
+ writeln ! (
32
+ file,
33
+ "{}{}" ,
34
+ if optional_newline { "\n " } else { "" } ,
35
+ path_to_ignore
36
+ ) ?;
25
37
26
38
Ok ( ( ) )
27
39
}
40
+
41
+ fn file_ends_with_newline ( file : & PathBuf ) -> Result < bool > {
42
+ let mut file = File :: open ( file) ?;
43
+ let size = file. metadata ( ) ?. len ( ) ;
44
+
45
+ file. seek ( SeekFrom :: Start ( size. saturating_sub ( 1 ) ) ) ?;
46
+ let mut last_char = String :: with_capacity ( 1 ) ;
47
+ file. read_to_string ( & mut last_char) ?;
48
+
49
+ dbg ! ( & last_char) ;
50
+
51
+ Ok ( last_char == "\n " )
52
+ }
53
+
54
+ #[ cfg( test) ]
55
+ mod tests {
56
+ use super :: * ;
57
+ use crate :: sync:: tests:: repo_init;
58
+ use io:: BufRead ;
59
+ use std:: { fs:: File , io, path:: Path } ;
60
+
61
+ #[ test]
62
+ fn test_empty ( ) -> Result < ( ) > {
63
+ let ignore_file_path = Path :: new ( ".gitignore" ) ;
64
+ let file_path = Path :: new ( "foo.txt" ) ;
65
+ let ( _td, repo) = repo_init ( ) ?;
66
+ let root = repo. path ( ) . parent ( ) . unwrap ( ) ;
67
+ let repo_path = root. as_os_str ( ) . to_str ( ) . unwrap ( ) ;
68
+
69
+ File :: create ( & root. join ( file_path) ) ?. write_all ( b"test" ) ?;
70
+
71
+ assert_eq ! ( root. join( ignore_file_path) . exists( ) , false ) ;
72
+ add_to_ignore ( repo_path, file_path. to_str ( ) . unwrap ( ) ) ?;
73
+ assert_eq ! ( root. join( ignore_file_path) . exists( ) , true ) ;
74
+
75
+ Ok ( ( ) )
76
+ }
77
+
78
+ fn read_lines < P > (
79
+ filename : P ,
80
+ ) -> io:: Result < io:: Lines < io:: BufReader < File > > >
81
+ where
82
+ P : AsRef < Path > ,
83
+ {
84
+ let file = File :: open ( filename) ?;
85
+ Ok ( io:: BufReader :: new ( file) . lines ( ) )
86
+ }
87
+
88
+ #[ test]
89
+ fn test_append ( ) -> Result < ( ) > {
90
+ let ignore_file_path = Path :: new ( ".gitignore" ) ;
91
+ let file_path = Path :: new ( "foo.txt" ) ;
92
+ let ( _td, repo) = repo_init ( ) ?;
93
+ let root = repo. path ( ) . parent ( ) . unwrap ( ) ;
94
+ let repo_path = root. as_os_str ( ) . to_str ( ) . unwrap ( ) ;
95
+
96
+ File :: create ( & root. join ( file_path) ) ?. write_all ( b"test" ) ?;
97
+ File :: create ( & root. join ( ignore_file_path) ) ?
98
+ . write_all ( b"foo\n " ) ?;
99
+
100
+ add_to_ignore ( repo_path, file_path. to_str ( ) . unwrap ( ) ) ?;
101
+
102
+ let mut lines =
103
+ read_lines ( & root. join ( ignore_file_path) ) . unwrap ( ) ;
104
+ assert_eq ! ( & lines. nth( 1 ) . unwrap( ) . unwrap( ) , "foo.txt" ) ;
105
+
106
+ Ok ( ( ) )
107
+ }
108
+
109
+ #[ test]
110
+ fn test_append_no_newline_at_end ( ) -> Result < ( ) > {
111
+ let ignore_file_path = Path :: new ( ".gitignore" ) ;
112
+ let file_path = Path :: new ( "foo.txt" ) ;
113
+ let ( _td, repo) = repo_init ( ) ?;
114
+ let root = repo. path ( ) . parent ( ) . unwrap ( ) ;
115
+ let repo_path = root. as_os_str ( ) . to_str ( ) . unwrap ( ) ;
116
+
117
+ File :: create ( & root. join ( file_path) ) ?. write_all ( b"test" ) ?;
118
+ File :: create ( & root. join ( ignore_file_path) ) ?
119
+ . write_all ( b"foo" ) ?;
120
+
121
+ add_to_ignore ( repo_path, file_path. to_str ( ) . unwrap ( ) ) ?;
122
+
123
+ let mut lines =
124
+ read_lines ( & root. join ( ignore_file_path) ) . unwrap ( ) ;
125
+ assert_eq ! ( & lines. nth( 1 ) . unwrap( ) . unwrap( ) , "foo.txt" ) ;
126
+
127
+ Ok ( ( ) )
128
+ }
129
+ }
0 commit comments