diff options
author | Aleksey Kladov <[email protected]> | 2020-02-14 14:59:19 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-02-14 15:47:09 +0000 |
commit | ce29497e4324d3e2f2c7c696a212672dbdb46884 (patch) | |
tree | d75fa5d9994ec174371a16b1d42720833ecda85c /xtask | |
parent | bd3a41cc33a25491c19468aaf24dbba4b467edaf (diff) |
Replace Cmd with not-bash
Diffstat (limited to 'xtask')
-rw-r--r-- | xtask/src/cmd.rs | 56 | ||||
-rw-r--r-- | xtask/src/install.rs | 109 | ||||
-rw-r--r-- | xtask/src/lib.rs | 58 | ||||
-rw-r--r-- | xtask/src/not_bash.rs | 96 | ||||
-rw-r--r-- | xtask/src/pre_commit.rs | 6 |
5 files changed, 171 insertions, 154 deletions
diff --git a/xtask/src/cmd.rs b/xtask/src/cmd.rs deleted file mode 100644 index 37497fb74..000000000 --- a/xtask/src/cmd.rs +++ /dev/null | |||
@@ -1,56 +0,0 @@ | |||
1 | use std::process::{Command, Output, Stdio}; | ||
2 | |||
3 | use anyhow::{Context, Result}; | ||
4 | |||
5 | use crate::project_root; | ||
6 | |||
7 | pub struct Cmd<'a> { | ||
8 | pub unix: &'a str, | ||
9 | pub windows: &'a str, | ||
10 | pub work_dir: &'a str, | ||
11 | } | ||
12 | |||
13 | impl Cmd<'_> { | ||
14 | pub fn run(self) -> Result<()> { | ||
15 | if cfg!(windows) { | ||
16 | run(self.windows, self.work_dir) | ||
17 | } else { | ||
18 | run(self.unix, self.work_dir) | ||
19 | } | ||
20 | } | ||
21 | pub fn run_with_output(self) -> Result<String> { | ||
22 | if cfg!(windows) { | ||
23 | run_with_output(self.windows, self.work_dir) | ||
24 | } else { | ||
25 | run_with_output(self.unix, self.work_dir) | ||
26 | } | ||
27 | } | ||
28 | } | ||
29 | |||
30 | pub fn run(cmdline: &str, dir: &str) -> Result<()> { | ||
31 | do_run(cmdline, dir, &mut |c| { | ||
32 | c.stdout(Stdio::inherit()); | ||
33 | }) | ||
34 | .map(|_| ()) | ||
35 | } | ||
36 | |||
37 | pub fn run_with_output(cmdline: &str, dir: &str) -> Result<String> { | ||
38 | let output = do_run(cmdline, dir, &mut |_| {})?; | ||
39 | let stdout = String::from_utf8(output.stdout)?; | ||
40 | let stdout = stdout.trim().to_string(); | ||
41 | Ok(stdout) | ||
42 | } | ||
43 | |||
44 | fn do_run(cmdline: &str, dir: &str, f: &mut dyn FnMut(&mut Command)) -> Result<Output> { | ||
45 | eprintln!("\nwill run: {}", cmdline); | ||
46 | let proj_dir = project_root().join(dir); | ||
47 | let mut args = cmdline.split_whitespace(); | ||
48 | let exec = args.next().unwrap(); | ||
49 | let mut cmd = Command::new(exec); | ||
50 | f(cmd.args(args).current_dir(proj_dir).stderr(Stdio::inherit())); | ||
51 | let output = cmd.output().with_context(|| format!("running `{}`", cmdline))?; | ||
52 | if !output.status.success() { | ||
53 | anyhow::bail!("`{}` exited with {}", cmdline, output.status); | ||
54 | } | ||
55 | Ok(output) | ||
56 | } | ||
diff --git a/xtask/src/install.rs b/xtask/src/install.rs index 9bddc8d7f..f89c939b5 100644 --- a/xtask/src/install.rs +++ b/xtask/src/install.rs | |||
@@ -5,7 +5,7 @@ use std::{env, fs, path::PathBuf, str}; | |||
5 | use anyhow::{bail, format_err, Context, Result}; | 5 | use anyhow::{bail, format_err, Context, Result}; |
6 | use walkdir::WalkDir; | 6 | use walkdir::WalkDir; |
7 | 7 | ||
8 | use crate::cmd::{run, run_with_output, Cmd}; | 8 | use crate::not_bash::{pushd, run}; |
9 | 9 | ||
10 | // Latest stable, feel free to send a PR if this lags behind. | 10 | // Latest stable, feel free to send a PR if this lags behind. |
11 | const REQUIRED_RUST_VERSION: u32 = 41; | 11 | const REQUIRED_RUST_VERSION: u32 = 41; |
@@ -83,21 +83,9 @@ fn fix_path_for_mac() -> Result<()> { | |||
83 | } | 83 | } |
84 | 84 | ||
85 | fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> { | 85 | fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> { |
86 | let npm_version = Cmd { | 86 | let _dir = pushd("./editors/code"); |
87 | unix: r"npm --version", | ||
88 | windows: r"cmd.exe /c npm --version", | ||
89 | work_dir: "./editors/code", | ||
90 | } | ||
91 | .run(); | ||
92 | |||
93 | if npm_version.is_err() { | ||
94 | bail!("`npm --version` failed, `npm` is required to build the VS Code plugin") | ||
95 | } | ||
96 | 87 | ||
97 | Cmd { unix: r"npm install", windows: r"cmd.exe /c npm install", work_dir: "./editors/code" } | 88 | let list_vsixes = || { |
98 | .run()?; | ||
99 | |||
100 | let vsixes = || { | ||
101 | WalkDir::new("./editors/code") | 89 | WalkDir::new("./editors/code") |
102 | .max_depth(1) | 90 | .max_depth(1) |
103 | .into_iter() | 91 | .into_iter() |
@@ -106,50 +94,45 @@ fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> { | |||
106 | .filter(|it| it.file_name().unwrap_or_default().to_string_lossy().ends_with(".vsix")) | 94 | .filter(|it| it.file_name().unwrap_or_default().to_string_lossy().ends_with(".vsix")) |
107 | }; | 95 | }; |
108 | 96 | ||
109 | for path in vsixes() { | 97 | let find_code = |f: fn(&str) -> bool| -> Result<&'static str> { |
110 | fs::remove_file(path)? | 98 | ["code", "code-insiders", "codium", "code-oss"] |
111 | } | 99 | .iter() |
100 | .copied() | ||
101 | .find(|bin| f(bin)) | ||
102 | .ok_or_else(|| { | ||
103 | format_err!("Can't execute `code --version`. Perhaps it is not in $PATH?") | ||
104 | }) | ||
105 | }; | ||
112 | 106 | ||
113 | Cmd { | 107 | let installed_extensions; |
114 | unix: r"npm run package --scripts-prepend-node-path", | 108 | if cfg!(unix) { |
115 | windows: r"cmd.exe /c npm run package", | 109 | run!("npm --version").context("`npm` is required to build the VS Code plugin")?; |
116 | work_dir: "./editors/code", | 110 | run!("npm install")?; |
117 | } | ||
118 | .run()?; | ||
119 | |||
120 | let extension = vsixes().next().unwrap().file_name().unwrap().to_string_lossy().to_string(); | ||
121 | |||
122 | let code_binary = ["code", "code-insiders", "codium", "code-oss"] | ||
123 | .iter() | ||
124 | .find(|bin| { | ||
125 | Cmd { | ||
126 | unix: &format!("{} --version", bin), | ||
127 | windows: &format!("cmd.exe /c {}.cmd --version", bin), | ||
128 | work_dir: "./editors/code", | ||
129 | } | ||
130 | .run() | ||
131 | .is_ok() | ||
132 | }) | ||
133 | .ok_or_else(|| { | ||
134 | format_err!("Can't execute `code --version`. Perhaps it is not in $PATH?") | ||
135 | })?; | ||
136 | |||
137 | Cmd { | ||
138 | unix: &format!(r"{} --install-extension ./{} --force", code_binary, extension), | ||
139 | windows: &format!( | ||
140 | r"cmd.exe /c {}.cmd --install-extension ./{} --force", | ||
141 | code_binary, extension | ||
142 | ), | ||
143 | work_dir: "./editors/code", | ||
144 | } | ||
145 | .run()?; | ||
146 | 111 | ||
147 | let installed_extensions = Cmd { | 112 | let vsix_pkg = { |
148 | unix: &format!(r"{} --list-extensions", code_binary), | 113 | list_vsixes().try_for_each(fs::remove_file)?; |
149 | windows: &format!(r"cmd.exe /c {}.cmd --list-extensions", code_binary), | 114 | run!("npm run package --scripts-prepend-node-path")?; |
150 | work_dir: ".", | 115 | list_vsixes().next().unwrap().file_name().unwrap().to_string_lossy().to_string() |
116 | }; | ||
117 | |||
118 | let code = find_code(|bin| run!("{} --version", bin).is_ok())?; | ||
119 | run!("{} --install-extension ./{} --force", code, vsix_pkg)?; | ||
120 | installed_extensions = run!("{} --list-extensions", code; echo = false)?; | ||
121 | } else { | ||
122 | run!("cmd.exe /c npm --version") | ||
123 | .context("`npm` is required to build the VS Code plugin")?; | ||
124 | run!("cmd.exe /c npm install")?; | ||
125 | |||
126 | let vsix_pkg = { | ||
127 | list_vsixes().try_for_each(fs::remove_file)?; | ||
128 | run!("cmd.exe /c npm run package")?; | ||
129 | list_vsixes().next().unwrap().file_name().unwrap().to_string_lossy().to_string() | ||
130 | }; | ||
131 | |||
132 | let code = find_code(|bin| run!("cmd.exe /c {}.cmd --version", bin).is_ok())?; | ||
133 | run!(r"cmd.exe /c {}.cmd --install-extension ./{} --force", code, vsix_pkg)?; | ||
134 | installed_extensions = run!("cmd.exe /c {}.cmd --list-extensions", code; echo = false)?; | ||
151 | } | 135 | } |
152 | .run_with_output()?; | ||
153 | 136 | ||
154 | if !installed_extensions.contains("rust-analyzer") { | 137 | if !installed_extensions.contains("rust-analyzer") { |
155 | bail!( | 138 | bail!( |
@@ -163,8 +146,7 @@ fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> { | |||
163 | 146 | ||
164 | fn install_server(opts: ServerOpt) -> Result<()> { | 147 | fn install_server(opts: ServerOpt) -> Result<()> { |
165 | let mut old_rust = false; | 148 | let mut old_rust = false; |
166 | if let Ok(stdout) = run_with_output("cargo --version", ".") { | 149 | if let Ok(stdout) = run!("cargo --version") { |
167 | println!("{}", stdout); | ||
168 | if !check_version(&stdout, REQUIRED_RUST_VERSION) { | 150 | if !check_version(&stdout, REQUIRED_RUST_VERSION) { |
169 | old_rust = true; | 151 | old_rust = true; |
170 | } | 152 | } |
@@ -177,20 +159,17 @@ fn install_server(opts: ServerOpt) -> Result<()> { | |||
177 | ) | 159 | ) |
178 | } | 160 | } |
179 | 161 | ||
180 | let res = if opts.jemalloc { | 162 | let jemalloc = if opts.jemalloc { "--features jemalloc" } else { "" }; |
181 | run("cargo install --path crates/ra_lsp_server --locked --force --features jemalloc", ".") | 163 | let res = run!("cargo install --path crates/ra_lsp_server --locked --force {}", jemalloc); |
182 | } else { | ||
183 | run("cargo install --path crates/ra_lsp_server --locked --force", ".") | ||
184 | }; | ||
185 | 164 | ||
186 | if res.is_err() && old_rust { | 165 | if res.is_err() && old_rust { |
187 | eprintln!( | 166 | eprintln!( |
188 | "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n", | 167 | "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n", |
189 | REQUIRED_RUST_VERSION, | 168 | REQUIRED_RUST_VERSION, |
190 | ) | 169 | ); |
191 | } | 170 | } |
192 | 171 | ||
193 | res | 172 | res.map(drop) |
194 | } | 173 | } |
195 | 174 | ||
196 | fn check_version(version_output: &str, min_minor_version: u32) -> bool { | 175 | fn check_version(version_output: &str, min_minor_version: u32) -> bool { |
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index 1bb1882b0..d2ef2e95b 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | mod cmd; | 3 | pub mod not_bash; |
4 | pub mod install; | 4 | pub mod install; |
5 | pub mod pre_commit; | 5 | pub mod pre_commit; |
6 | 6 | ||
@@ -16,8 +16,8 @@ use std::{ | |||
16 | }; | 16 | }; |
17 | 17 | ||
18 | use crate::{ | 18 | use crate::{ |
19 | cmd::{run, run_with_output}, | ||
20 | codegen::Mode, | 19 | codegen::Mode, |
20 | not_bash::{pushd, run}, | ||
21 | }; | 21 | }; |
22 | 22 | ||
23 | pub use anyhow::Result; | 23 | pub use anyhow::Result; |
@@ -38,9 +38,9 @@ pub fn run_rustfmt(mode: Mode) -> Result<()> { | |||
38 | ensure_rustfmt()?; | 38 | ensure_rustfmt()?; |
39 | 39 | ||
40 | if mode == Mode::Verify { | 40 | if mode == Mode::Verify { |
41 | run(&format!("rustup run {} -- cargo fmt -- --check", TOOLCHAIN), ".")?; | 41 | run!("rustup run {} -- cargo fmt -- --check", TOOLCHAIN)?; |
42 | } else { | 42 | } else { |
43 | run(&format!("rustup run {} -- cargo fmt", TOOLCHAIN), ".")?; | 43 | run!("rustup run {} -- cargo fmt", TOOLCHAIN)?; |
44 | } | 44 | } |
45 | Ok(()) | 45 | Ok(()) |
46 | } | 46 | } |
@@ -70,8 +70,9 @@ fn ensure_rustfmt() -> Result<()> { | |||
70 | Ok(status) if status.success() => return Ok(()), | 70 | Ok(status) if status.success() => return Ok(()), |
71 | _ => (), | 71 | _ => (), |
72 | }; | 72 | }; |
73 | run(&format!("rustup toolchain install {}", TOOLCHAIN), ".")?; | 73 | run!("rustup toolchain install {}", TOOLCHAIN)?; |
74 | run(&format!("rustup component add rustfmt --toolchain {}", TOOLCHAIN), ".") | 74 | run!("rustup component add rustfmt --toolchain {}", TOOLCHAIN)?; |
75 | Ok(()) | ||
75 | } | 76 | } |
76 | 77 | ||
77 | pub fn run_clippy() -> Result<()> { | 78 | pub fn run_clippy() -> Result<()> { |
@@ -92,34 +93,31 @@ pub fn run_clippy() -> Result<()> { | |||
92 | "clippy::nonminimal_bool", | 93 | "clippy::nonminimal_bool", |
93 | "clippy::redundant_pattern_matching", | 94 | "clippy::redundant_pattern_matching", |
94 | ]; | 95 | ]; |
95 | run( | 96 | run!( |
96 | &format!( | 97 | "rustup run {} -- cargo clippy --all-features --all-targets -- -A {}", |
97 | "rustup run {} -- cargo clippy --all-features --all-targets -- -A {}", | 98 | TOOLCHAIN, |
98 | TOOLCHAIN, | 99 | allowed_lints.join(" -A ") |
99 | allowed_lints.join(" -A ") | ||
100 | ), | ||
101 | ".", | ||
102 | )?; | 100 | )?; |
103 | Ok(()) | 101 | Ok(()) |
104 | } | 102 | } |
105 | 103 | ||
106 | fn install_clippy() -> Result<()> { | 104 | fn install_clippy() -> Result<()> { |
107 | run(&format!("rustup toolchain install {}", TOOLCHAIN), ".")?; | 105 | run!("rustup toolchain install {}", TOOLCHAIN)?; |
108 | run(&format!("rustup component add clippy --toolchain {}", TOOLCHAIN), ".") | 106 | run!("rustup component add clippy --toolchain {}", TOOLCHAIN)?; |
107 | Ok(()) | ||
109 | } | 108 | } |
110 | 109 | ||
111 | pub fn run_fuzzer() -> Result<()> { | 110 | pub fn run_fuzzer() -> Result<()> { |
112 | match Command::new("cargo") | 111 | let _d = pushd("./crates/ra_syntax"); |
113 | .args(&["fuzz", "--help"]) | 112 | match run!("cargo fuzz --help") { |
114 | .stderr(Stdio::null()) | 113 | Ok(_) => (), |
115 | .stdout(Stdio::null()) | 114 | _ => { |
116 | .status() | 115 | run!("cargo install cargo-fuzz")?; |
117 | { | 116 | } |
118 | Ok(status) if status.success() => (), | ||
119 | _ => run("cargo install cargo-fuzz", ".")?, | ||
120 | }; | 117 | }; |
121 | 118 | ||
122 | run("rustup run nightly -- cargo fuzz run parser", "./crates/ra_syntax") | 119 | run!("rustup run nightly -- cargo fuzz run parser")?; |
120 | Ok(()) | ||
123 | } | 121 | } |
124 | 122 | ||
125 | /// Cleans the `./target` dir after the build such that only | 123 | /// Cleans the `./target` dir after the build such that only |
@@ -161,15 +159,15 @@ fn rm_rf(path: &Path) -> Result<()> { | |||
161 | } | 159 | } |
162 | 160 | ||
163 | pub fn run_release() -> Result<()> { | 161 | pub fn run_release() -> Result<()> { |
164 | run("git switch release", ".")?; | 162 | run!("git switch release")?; |
165 | run("git fetch upstream", ".")?; | 163 | run!("git fetch upstream")?; |
166 | run("git reset --hard upstream/master", ".")?; | 164 | run!("git reset --hard upstream/master")?; |
167 | run("git push", ".")?; | 165 | run!("git push")?; |
168 | 166 | ||
169 | let changelog_dir = project_root().join("../rust-analyzer.github.io/thisweek/_posts"); | 167 | let changelog_dir = project_root().join("../rust-analyzer.github.io/thisweek/_posts"); |
170 | 168 | ||
171 | let today = run_with_output("date --iso", ".")?; | 169 | let today = run!("date --iso")?; |
172 | let commit = run_with_output("git rev-parse HEAD", ".")?; | 170 | let commit = run!("git rev-parse HEAD")?; |
173 | let changelog_n = fs::read_dir(changelog_dir.as_path())?.count(); | 171 | let changelog_n = fs::read_dir(changelog_dir.as_path())?.count(); |
174 | 172 | ||
175 | let contents = format!( | 173 | let contents = format!( |
diff --git a/xtask/src/not_bash.rs b/xtask/src/not_bash.rs new file mode 100644 index 000000000..a2e47c7af --- /dev/null +++ b/xtask/src/not_bash.rs | |||
@@ -0,0 +1,96 @@ | |||
1 | //! A bad shell -- small cross platform module for writing glue code | ||
2 | use std::{ | ||
3 | cell::RefCell, | ||
4 | env, | ||
5 | path::PathBuf, | ||
6 | process::{Command, Stdio}, | ||
7 | }; | ||
8 | |||
9 | use anyhow::{bail, Context, Result}; | ||
10 | |||
11 | macro_rules! _run { | ||
12 | ($($expr:expr),*) => { | ||
13 | run!($($expr),*; echo = true) | ||
14 | }; | ||
15 | ($($expr:expr),* ; echo = $echo:expr) => { | ||
16 | $crate::not_bash::run_process(format!($($expr),*), $echo) | ||
17 | }; | ||
18 | } | ||
19 | pub(crate) use _run as run; | ||
20 | |||
21 | pub struct Pushd { | ||
22 | _p: (), | ||
23 | } | ||
24 | |||
25 | pub fn pushd(path: impl Into<PathBuf>) -> Pushd { | ||
26 | Env::with(|env| env.pushd(path.into())); | ||
27 | Pushd { _p: () } | ||
28 | } | ||
29 | |||
30 | impl Drop for Pushd { | ||
31 | fn drop(&mut self) { | ||
32 | Env::with(|env| env.popd()) | ||
33 | } | ||
34 | } | ||
35 | |||
36 | #[doc(hidden)] | ||
37 | pub fn run_process(cmd: String, echo: bool) -> Result<String> { | ||
38 | run_process_inner(&cmd, echo).with_context(|| format!("process `{}` failed", cmd)) | ||
39 | } | ||
40 | |||
41 | fn run_process_inner(cmd: &str, echo: bool) -> Result<String> { | ||
42 | let cwd = Env::with(|env| env.cwd()); | ||
43 | let mut args = shelx(cmd); | ||
44 | let binary = args.remove(0); | ||
45 | |||
46 | if echo { | ||
47 | println!("> {}", cmd) | ||
48 | } | ||
49 | |||
50 | let output = Command::new(binary) | ||
51 | .args(args) | ||
52 | .current_dir(cwd) | ||
53 | .stdin(Stdio::null()) | ||
54 | .stderr(Stdio::inherit()) | ||
55 | .output()?; | ||
56 | let stdout = String::from_utf8(output.stdout)?; | ||
57 | |||
58 | if echo { | ||
59 | print!("{}", stdout) | ||
60 | } | ||
61 | |||
62 | if !output.status.success() { | ||
63 | bail!("returned non-zero status: {}", output.status) | ||
64 | } | ||
65 | |||
66 | Ok(stdout) | ||
67 | } | ||
68 | |||
69 | // FIXME: some real shell lexing here | ||
70 | fn shelx(cmd: &str) -> Vec<String> { | ||
71 | cmd.split_whitespace().map(|it| it.to_string()).collect() | ||
72 | } | ||
73 | |||
74 | #[derive(Default)] | ||
75 | struct Env { | ||
76 | pushd_stack: Vec<PathBuf>, | ||
77 | } | ||
78 | |||
79 | impl Env { | ||
80 | fn with<F: FnOnce(&mut Env) -> T, T>(f: F) -> T { | ||
81 | thread_local! { | ||
82 | static ENV: RefCell<Env> = Default::default(); | ||
83 | } | ||
84 | ENV.with(|it| f(&mut *it.borrow_mut())) | ||
85 | } | ||
86 | |||
87 | fn pushd(&mut self, dir: PathBuf) { | ||
88 | self.pushd_stack.push(dir) | ||
89 | } | ||
90 | fn popd(&mut self) { | ||
91 | self.pushd_stack.pop().unwrap(); | ||
92 | } | ||
93 | fn cwd(&self) -> PathBuf { | ||
94 | self.pushd_stack.last().cloned().unwrap_or_else(|| env::current_dir().unwrap()) | ||
95 | } | ||
96 | } | ||
diff --git a/xtask/src/pre_commit.rs b/xtask/src/pre_commit.rs index 1533f64dc..056f34acf 100644 --- a/xtask/src/pre_commit.rs +++ b/xtask/src/pre_commit.rs | |||
@@ -4,18 +4,18 @@ use std::{fs, path::PathBuf}; | |||
4 | 4 | ||
5 | use anyhow::{bail, Result}; | 5 | use anyhow::{bail, Result}; |
6 | 6 | ||
7 | use crate::{cmd::run_with_output, project_root, run, run_rustfmt, Mode}; | 7 | use crate::{not_bash::run, project_root, run_rustfmt, Mode}; |
8 | 8 | ||
9 | // FIXME: if there are changed `.ts` files, also reformat TypeScript (by | 9 | // FIXME: if there are changed `.ts` files, also reformat TypeScript (by |
10 | // shelling out to `npm fmt`). | 10 | // shelling out to `npm fmt`). |
11 | pub fn run_hook() -> Result<()> { | 11 | pub fn run_hook() -> Result<()> { |
12 | run_rustfmt(Mode::Overwrite)?; | 12 | run_rustfmt(Mode::Overwrite)?; |
13 | 13 | ||
14 | let diff = run_with_output("git diff --diff-filter=MAR --name-only --cached", ".")?; | 14 | let diff = run!("git diff --diff-filter=MAR --name-only --cached")?; |
15 | 15 | ||
16 | let root = project_root(); | 16 | let root = project_root(); |
17 | for line in diff.lines() { | 17 | for line in diff.lines() { |
18 | run(&format!("git update-index --add {}", root.join(line).to_string_lossy()), ".")?; | 18 | run!("git update-index --add {}", root.join(line).display())?; |
19 | } | 19 | } |
20 | 20 | ||
21 | Ok(()) | 21 | Ok(()) |