aboutsummaryrefslogtreecommitdiff
path: root/xtask/src
diff options
context:
space:
mode:
Diffstat (limited to 'xtask/src')
-rw-r--r--xtask/src/cmd.rs56
-rw-r--r--xtask/src/install.rs118
-rw-r--r--xtask/src/lib.rs77
-rw-r--r--xtask/src/main.rs3
-rw-r--r--xtask/src/not_bash.rs165
-rw-r--r--xtask/src/pre_commit.rs6
6 files changed, 252 insertions, 173 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 @@
1use std::process::{Command, Output, Stdio};
2
3use anyhow::{Context, Result};
4
5use crate::project_root;
6
7pub struct Cmd<'a> {
8 pub unix: &'a str,
9 pub windows: &'a str,
10 pub work_dir: &'a str,
11}
12
13impl 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
30pub fn run(cmdline: &str, dir: &str) -> Result<()> {
31 do_run(cmdline, dir, &mut |c| {
32 c.stdout(Stdio::inherit());
33 })
34 .map(|_| ())
35}
36
37pub 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
44fn 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 99e1eddb1..00bbabce4 100644
--- a/xtask/src/install.rs
+++ b/xtask/src/install.rs
@@ -2,9 +2,9 @@
2 2
3use std::{env, path::PathBuf, str}; 3use std::{env, path::PathBuf, str};
4 4
5use anyhow::{Context, Result}; 5use anyhow::{bail, format_err, Context, Result};
6 6
7use crate::cmd::{run, run_with_output, Cmd}; 7use crate::not_bash::{ls, pushd, rm, run};
8 8
9// Latest stable, feel free to send a PR if this lags behind. 9// Latest stable, feel free to send a PR if this lags behind.
10const REQUIRED_RUST_VERSION: u32 = 41; 10const REQUIRED_RUST_VERSION: u32 = 41;
@@ -55,7 +55,7 @@ fn fix_path_for_mac() -> Result<()> {
55 const ROOT_DIR: &str = ""; 55 const ROOT_DIR: &str = "";
56 let home_dir = match env::var("HOME") { 56 let home_dir = match env::var("HOME") {
57 Ok(home) => home, 57 Ok(home) => home,
58 Err(e) => anyhow::bail!("Failed getting HOME from environment with error: {}.", e), 58 Err(e) => bail!("Failed getting HOME from environment with error: {}.", e),
59 }; 59 };
60 60
61 [ROOT_DIR, &home_dir] 61 [ROOT_DIR, &home_dir]
@@ -69,7 +69,7 @@ fn fix_path_for_mac() -> Result<()> {
69 if !vscode_path.is_empty() { 69 if !vscode_path.is_empty() {
70 let vars = match env::var_os("PATH") { 70 let vars = match env::var_os("PATH") {
71 Some(path) => path, 71 Some(path) => path,
72 None => anyhow::bail!("Could not get PATH variable from env."), 72 None => bail!("Could not get PATH variable from env."),
73 }; 73 };
74 74
75 let mut paths = env::split_paths(&vars).collect::<Vec<_>>(); 75 let mut paths = env::split_paths(&vars).collect::<Vec<_>>();
@@ -82,84 +82,61 @@ fn fix_path_for_mac() -> Result<()> {
82} 82}
83 83
84fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> { 84fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> {
85 let npm_version = Cmd { 85 let _dir = pushd("./editors/code");
86 unix: r"npm --version",
87 windows: r"cmd.exe /c npm --version",
88 work_dir: "./editors/code",
89 }
90 .run();
91
92 if npm_version.is_err() {
93 eprintln!("\nERROR: `npm --version` failed, `npm` is required to build the VS Code plugin")
94 }
95 86
96 Cmd { unix: r"npm install", windows: r"cmd.exe /c npm install", work_dir: "./editors/code" } 87 let find_code = |f: fn(&str) -> bool| -> Result<&'static str> {
97 .run()?; 88 ["code", "code-insiders", "codium", "code-oss"]
98 Cmd { 89 .iter()
99 unix: r"npm run package --scripts-prepend-node-path", 90 .copied()
100 windows: r"cmd.exe /c npm run package", 91 .find(|bin| f(bin))
101 work_dir: "./editors/code", 92 .ok_or_else(|| {
102 } 93 format_err!("Can't execute `code --version`. Perhaps it is not in $PATH?")
103 .run()?; 94 })
95 };
104 96
105 let code_binary = ["code", "code-insiders", "codium", "code-oss"].iter().find(|bin| { 97 let installed_extensions;
106 Cmd { 98 if cfg!(unix) {
107 unix: &format!("{} --version", bin), 99 run!("npm --version").context("`npm` is required to build the VS Code plugin")?;
108 windows: &format!("cmd.exe /c {}.cmd --version", bin), 100 run!("npm install")?;
109 work_dir: "./editors/code",
110 }
111 .run()
112 .is_ok()
113 });
114 101
115 let code_binary = match code_binary { 102 let vsix_pkg = {
116 Some(it) => it, 103 rm("*.vsix")?;
117 None => anyhow::bail!("Can't execute `code --version`. Perhaps it is not in $PATH?"), 104 run!("npm run package --scripts-prepend-node-path")?;
118 }; 105 ls("*.vsix")?.pop().unwrap()
106 };
119 107
120 Cmd { 108 let code = find_code(|bin| run!("{} --version", bin).is_ok())?;
121 unix: &format!(r"{} --install-extension ./rust-analyzer-0.1.0.vsix --force", code_binary), 109 run!("{} --install-extension {} --force", code, vsix_pkg.display())?;
122 windows: &format!( 110 installed_extensions = run!("{} --list-extensions", code; echo = false)?;
123 r"cmd.exe /c {}.cmd --install-extension ./rust-analyzer-0.1.0.vsix --force", 111 } else {
124 code_binary 112 run!("cmd.exe /c npm --version")
125 ), 113 .context("`npm` is required to build the VS Code plugin")?;
126 work_dir: "./editors/code", 114 run!("cmd.exe /c npm install")?;
127 } 115
128 .run()?; 116 let vsix_pkg = {
117 rm("*.vsix")?;
118 run!("cmd.exe /c npm run package")?;
119 ls("*.vsix")?.pop().unwrap()
120 };
129 121
130 let installed_extensions = Cmd { 122 let code = find_code(|bin| run!("cmd.exe /c {}.cmd --version", bin).is_ok())?;
131 unix: &format!(r"{} --list-extensions", code_binary), 123 run!(r"cmd.exe /c {}.cmd --install-extension {} --force", code, vsix_pkg.display())?;
132 windows: &format!(r"cmd.exe /c {}.cmd --list-extensions", code_binary), 124 installed_extensions = run!("cmd.exe /c {}.cmd --list-extensions", code; echo = false)?;
133 work_dir: ".",
134 } 125 }
135 .run_with_output()?;
136 126
137 if !installed_extensions.contains("rust-analyzer") { 127 if !installed_extensions.contains("rust-analyzer") {
138 anyhow::bail!( 128 bail!(
139 "Could not install the Visual Studio Code extension. \ 129 "Could not install the Visual Studio Code extension. \
140 Please make sure you have at least NodeJS 10.x together with the latest version of VS Code installed and try again." 130 Please make sure you have at least NodeJS 12.x together with the latest version of VS Code installed and try again."
141 ); 131 );
142 } 132 }
143 133
144 if installed_extensions.contains("ra-lsp") {
145 Cmd {
146 unix: &format!(r"{} --uninstall-extension matklad.ra-lsp", code_binary),
147 windows: &format!(
148 r"cmd.exe /c {}.cmd --uninstall-extension matklad.ra-lsp",
149 code_binary
150 ),
151 work_dir: "./editors/code",
152 }
153 .run()?;
154 }
155
156 Ok(()) 134 Ok(())
157} 135}
158 136
159fn install_server(opts: ServerOpt) -> Result<()> { 137fn install_server(opts: ServerOpt) -> Result<()> {
160 let mut old_rust = false; 138 let mut old_rust = false;
161 if let Ok(stdout) = run_with_output("cargo --version", ".") { 139 if let Ok(stdout) = run!("cargo --version") {
162 println!("{}", stdout);
163 if !check_version(&stdout, REQUIRED_RUST_VERSION) { 140 if !check_version(&stdout, REQUIRED_RUST_VERSION) {
164 old_rust = true; 141 old_rust = true;
165 } 142 }
@@ -172,20 +149,17 @@ fn install_server(opts: ServerOpt) -> Result<()> {
172 ) 149 )
173 } 150 }
174 151
175 let res = if opts.jemalloc { 152 let jemalloc = if opts.jemalloc { "--features jemalloc" } else { "" };
176 run("cargo install --path crates/ra_lsp_server --locked --force --features jemalloc", ".") 153 let res = run!("cargo install --path crates/ra_lsp_server --locked --force {}", jemalloc);
177 } else {
178 run("cargo install --path crates/ra_lsp_server --locked --force", ".")
179 };
180 154
181 if res.is_err() && old_rust { 155 if res.is_err() && old_rust {
182 eprintln!( 156 eprintln!(
183 "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n", 157 "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
184 REQUIRED_RUST_VERSION, 158 REQUIRED_RUST_VERSION,
185 ) 159 );
186 } 160 }
187 161
188 res 162 res.map(drop)
189} 163}
190 164
191fn check_version(version_output: &str, min_minor_version: u32) -> bool { 165fn check_version(version_output: &str, min_minor_version: u32) -> bool {
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs
index 1bb1882b0..2bcd76d60 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
3mod cmd; 3pub mod not_bash;
4pub mod install; 4pub mod install;
5pub mod pre_commit; 5pub mod pre_commit;
6 6
@@ -9,15 +9,15 @@ mod ast_src;
9 9
10use anyhow::Context; 10use anyhow::Context;
11use std::{ 11use std::{
12 env, fs, 12 env,
13 io::Write, 13 io::Write,
14 path::{Path, PathBuf}, 14 path::{Path, PathBuf},
15 process::{Command, Stdio}, 15 process::{Command, Stdio},
16}; 16};
17 17
18use crate::{ 18use crate::{
19 cmd::{run, run_with_output},
20 codegen::Mode, 19 codegen::Mode,
20 not_bash::{fs2, pushd, rm_rf, run},
21}; 21};
22 22
23pub use anyhow::Result; 23pub 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
77pub fn run_clippy() -> Result<()> { 78pub fn run_clippy() -> Result<()> {
@@ -92,34 +93,28 @@ 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
106fn install_clippy() -> Result<()> { 104fn 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
111pub fn run_fuzzer() -> Result<()> { 110pub fn run_fuzzer() -> Result<()> {
112 match Command::new("cargo") 111 let _d = pushd("./crates/ra_syntax");
113 .args(&["fuzz", "--help"]) 112 if run!("cargo fuzz --help").is_err() {
114 .stderr(Stdio::null()) 113 run!("cargo install cargo-fuzz")?;
115 .stdout(Stdio::null())
116 .status()
117 {
118 Ok(status) if status.success() => (),
119 _ => run("cargo install cargo-fuzz", ".")?,
120 }; 114 };
121 115
122 run("rustup run nightly -- cargo fuzz run parser", "./crates/ra_syntax") 116 run!("rustup run nightly -- cargo fuzz run parser")?;
117 Ok(())
123} 118}
124 119
125/// Cleans the `./target` dir after the build such that only 120/// Cleans the `./target` dir after the build such that only
@@ -141,7 +136,7 @@ pub fn run_pre_cache() -> Result<()> {
141 } 136 }
142 } 137 }
143 138
144 fs::remove_file("./target/.rustc_info.json")?; 139 fs2::remove_file("./target/.rustc_info.json")?;
145 let to_delete = ["ra_", "heavy_test"]; 140 let to_delete = ["ra_", "heavy_test"];
146 for &dir in ["./target/debug/deps", "target/debug/.fingerprint"].iter() { 141 for &dir in ["./target/debug/deps", "target/debug/.fingerprint"].iter() {
147 for entry in Path::new(dir).read_dir()? { 142 for entry in Path::new(dir).read_dir()? {
@@ -155,22 +150,20 @@ pub fn run_pre_cache() -> Result<()> {
155 Ok(()) 150 Ok(())
156} 151}
157 152
158fn rm_rf(path: &Path) -> Result<()> { 153pub fn run_release(dry_run: bool) -> Result<()> {
159 if path.is_file() { fs::remove_file(path) } else { fs::remove_dir_all(path) } 154 if !dry_run {
160 .with_context(|| format!("failed to remove {:?}", path)) 155 run!("git switch release")?;
161} 156 run!("git fetch upstream")?;
162 157 run!("git reset --hard upstream/master")?;
163pub fn run_release() -> Result<()> { 158 run!("git push")?;
164 run("git switch release", ".")?; 159 }
165 run("git fetch upstream", ".")?;
166 run("git reset --hard upstream/master", ".")?;
167 run("git push", ".")?;
168 160
169 let changelog_dir = project_root().join("../rust-analyzer.github.io/thisweek/_posts"); 161 let website_root = project_root().join("../rust-analyzer.github.io");
162 let changelog_dir = website_root.join("./thisweek/_posts");
170 163
171 let today = run_with_output("date --iso", ".")?; 164 let today = run!("date --iso")?;
172 let commit = run_with_output("git rev-parse HEAD", ".")?; 165 let commit = run!("git rev-parse HEAD")?;
173 let changelog_n = fs::read_dir(changelog_dir.as_path())?.count(); 166 let changelog_n = fs2::read_dir(changelog_dir.as_path())?.count();
174 167
175 let contents = format!( 168 let contents = format!(
176 "\ 169 "\
@@ -193,7 +186,9 @@ Release: release:{}[]
193 ); 186 );
194 187
195 let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n)); 188 let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n));
196 fs::write(&path, &contents)?; 189 fs2::write(&path, &contents)?;
190
191 fs2::copy(project_root().join("./docs/user/readme.adoc"), website_root.join("manual.adoc"))?;
197 192
198 Ok(()) 193 Ok(())
199} 194}
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index 7ca727bde..a7dffe2cc 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -93,8 +93,9 @@ FLAGS:
93 run_pre_cache() 93 run_pre_cache()
94 } 94 }
95 "release" => { 95 "release" => {
96 let dry_run = args.contains("--dry-run");
96 args.finish()?; 97 args.finish()?;
97 run_release() 98 run_release(dry_run)
98 } 99 }
99 _ => { 100 _ => {
100 eprintln!( 101 eprintln!(
diff --git a/xtask/src/not_bash.rs b/xtask/src/not_bash.rs
new file mode 100644
index 000000000..3e30e7279
--- /dev/null
+++ b/xtask/src/not_bash.rs
@@ -0,0 +1,165 @@
1//! A bad shell -- small cross platform module for writing glue code
2use std::{
3 cell::RefCell,
4 env,
5 ffi::OsStr,
6 fs,
7 path::{Path, PathBuf},
8 process::{Command, Stdio},
9};
10
11use anyhow::{bail, Context, Result};
12
13pub mod fs2 {
14 use std::{fs, path::Path};
15
16 use anyhow::{Context, Result};
17
18 pub fn read_dir<P: AsRef<Path>>(path: P) -> Result<fs::ReadDir> {
19 let path = path.as_ref();
20 fs::read_dir(path).with_context(|| format!("Failed to read {}", path.display()))
21 }
22
23 pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> {
24 let path = path.as_ref();
25 fs::write(path, contents).with_context(|| format!("Failed to write {}", path.display()))
26 }
27
28 pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<u64> {
29 let from = from.as_ref();
30 let to = to.as_ref();
31 fs::copy(from, to)
32 .with_context(|| format!("Failed to copy {} to {}", from.display(), to.display()))
33 }
34
35 pub fn remove_file<P: AsRef<Path>>(path: P) -> Result<()> {
36 let path = path.as_ref();
37 fs::remove_file(path).with_context(|| format!("Failed to remove file {}", path.display()))
38 }
39
40 pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> Result<()> {
41 let path = path.as_ref();
42 fs::remove_dir_all(path).with_context(|| format!("Failed to remove dir {}", path.display()))
43 }
44}
45
46macro_rules! _run {
47 ($($expr:expr),*) => {
48 run!($($expr),*; echo = true)
49 };
50 ($($expr:expr),* ; echo = $echo:expr) => {
51 $crate::not_bash::run_process(format!($($expr),*), $echo)
52 };
53}
54pub(crate) use _run as run;
55
56pub struct Pushd {
57 _p: (),
58}
59
60pub fn pushd(path: impl Into<PathBuf>) -> Pushd {
61 Env::with(|env| env.pushd(path.into()));
62 Pushd { _p: () }
63}
64
65impl Drop for Pushd {
66 fn drop(&mut self) {
67 Env::with(|env| env.popd())
68 }
69}
70
71pub fn rm(glob: &str) -> Result<()> {
72 let cwd = Env::with(|env| env.cwd());
73 ls(glob)?.into_iter().try_for_each(|it| fs::remove_file(cwd.join(it)))?;
74 Ok(())
75}
76
77pub fn rm_rf(path: impl AsRef<Path>) -> Result<()> {
78 let path = path.as_ref();
79 if path.is_file() {
80 fs2::remove_file(path)
81 } else {
82 fs2::remove_dir_all(path)
83 }
84}
85
86pub fn ls(glob: &str) -> Result<Vec<PathBuf>> {
87 let cwd = Env::with(|env| env.cwd());
88 let mut res = Vec::new();
89 for entry in fs::read_dir(&cwd)? {
90 let entry = entry?;
91 if matches(&entry.file_name(), glob) {
92 let path = entry.path();
93 let path = path.strip_prefix(&cwd).unwrap();
94 res.push(path.to_path_buf())
95 }
96 }
97 return Ok(res);
98
99 fn matches(file_name: &OsStr, glob: &str) -> bool {
100 assert!(glob.starts_with('*'));
101 file_name.to_string_lossy().ends_with(&glob[1..])
102 }
103}
104
105#[doc(hidden)]
106pub fn run_process(cmd: String, echo: bool) -> Result<String> {
107 run_process_inner(&cmd, echo).with_context(|| format!("process `{}` failed", cmd))
108}
109
110fn run_process_inner(cmd: &str, echo: bool) -> Result<String> {
111 let cwd = Env::with(|env| env.cwd());
112 let mut args = shelx(cmd);
113 let binary = args.remove(0);
114
115 if echo {
116 println!("> {}", cmd)
117 }
118
119 let output = Command::new(binary)
120 .args(args)
121 .current_dir(cwd)
122 .stdin(Stdio::null())
123 .stderr(Stdio::inherit())
124 .output()?;
125 let stdout = String::from_utf8(output.stdout)?;
126
127 if echo {
128 print!("{}", stdout)
129 }
130
131 if !output.status.success() {
132 bail!("{}", output.status)
133 }
134
135 Ok(stdout.trim().to_string())
136}
137
138// FIXME: some real shell lexing here
139fn shelx(cmd: &str) -> Vec<String> {
140 cmd.split_whitespace().map(|it| it.to_string()).collect()
141}
142
143#[derive(Default)]
144struct Env {
145 pushd_stack: Vec<PathBuf>,
146}
147
148impl Env {
149 fn with<F: FnOnce(&mut Env) -> T, T>(f: F) -> T {
150 thread_local! {
151 static ENV: RefCell<Env> = Default::default();
152 }
153 ENV.with(|it| f(&mut *it.borrow_mut()))
154 }
155
156 fn pushd(&mut self, dir: PathBuf) {
157 self.pushd_stack.push(dir)
158 }
159 fn popd(&mut self) {
160 self.pushd_stack.pop().unwrap();
161 }
162 fn cwd(&self) -> PathBuf {
163 self.pushd_stack.last().cloned().unwrap_or_else(|| env::current_dir().unwrap())
164 }
165}
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
5use anyhow::{bail, Result}; 5use anyhow::{bail, Result};
6 6
7use crate::{cmd::run_with_output, project_root, run, run_rustfmt, Mode}; 7use 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`).
11pub fn run_hook() -> Result<()> { 11pub 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(())