Skip to content

Commit a84ae09

Browse files
author
Stephan Dilly
committed
add_to_ignore failed on files without a newline at EOF (closes #191)
1 parent 658bb72 commit a84ae09

File tree

2 files changed

+105
-2
lines changed

2 files changed

+105
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
- removed unmaintained dependency `spin` ([#172](https://github.com/extrawurst/gitui/issues/172))
1111
- opening relative paths in external editor may fail in subpaths ([#184](https://github.com/extrawurst/gitui/issues/184))
1212
- crashes in revlog with utf8 commit messages ([#188](https://github.com/extrawurst/gitui/issues/188))
13+
- `add_to_ignore` failed on files without a newline at EOF ([#191](https://github.com/extrawurst/gitui/issues/191))
1314

1415
## [0.8.1] - 2020-07-07
1516

asyncgit/src/sync/ignore.rs

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
use super::utils::{repo, work_dir};
22
use crate::error::Result;
33
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+
};
59

610
static GITIGNORE: &str = ".gitignore";
711

@@ -16,12 +20,110 @@ pub fn add_to_ignore(
1620

1721
let ignore_file = work_dir(&repo).join(GITIGNORE);
1822

23+
let optional_newline = ignore_file.exists()
24+
&& !file_ends_with_newline(&ignore_file)?;
25+
1926
let mut file = OpenOptions::new()
2027
.append(true)
2128
.create(true)
2229
.open(ignore_file)?;
2330

24-
writeln!(file, "{}", path_to_ignore)?;
31+
writeln!(
32+
file,
33+
"{}{}",
34+
if optional_newline { "\n" } else { "" },
35+
path_to_ignore
36+
)?;
2537

2638
Ok(())
2739
}
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

Comments
 (0)