Skip to content

Commit e341a3f

Browse files
committed
miri-script: start and stop josh automatically
1 parent e1028fe commit e341a3f

File tree

7 files changed

+212
-25
lines changed

7 files changed

+212
-25
lines changed

.github/workflows/ci.yml

-2
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,6 @@ jobs:
189189
fetch-depth: 256 # get a bit more of the history
190190
- name: install josh-proxy
191191
run: cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r22.12.06
192-
- name: start josh-proxy
193-
run: josh-proxy --local=$HOME/.cache/josh --remote=https://github.com --no-background &
194192
- name: setup bot git name and email
195193
run: |
196194
git config --global user.name 'The Miri Conjob Bot'

CONTRIBUTING.md

+17-20
Original file line numberDiff line numberDiff line change
@@ -231,25 +231,16 @@ You can also directly run Miri on a Rust source file:
231231
## Advanced topic: Syncing with the rustc repo
232232

233233
We use the [`josh` proxy](https://github.com/josh-project/josh) to transmit changes between the
234-
rustc and Miri repositories.
234+
rustc and Miri repositories. You can install it as follows:
235235

236236
```sh
237237
cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r22.12.06
238-
josh-proxy --local=$HOME/.cache/josh --remote=https://github.com --no-background
239238
```
240239

241-
This uses a directory `$HOME/.cache/josh` as a cache, to speed up repeated pulling/pushing.
242-
243-
To make josh push via ssh instead of https, you can add the following to your `.gitconfig`:
244-
245-
```toml
246-
[url "git@github.com:"]
247-
pushInsteadOf = https://github.com/
248-
```
240+
Josh will automatically be started and stopped by `./miri`.
249241

250242
### Importing changes from the rustc repo
251243

252-
Josh needs to be running, as described above.
253244
We assume we start on an up-to-date master branch in the Miri repo.
254245

255246
```sh
@@ -268,16 +259,14 @@ needed.
268259

269260
### Exporting changes to the rustc repo
270261

271-
Keep in mind that pushing is the most complicated job that josh has to do --
272-
pulling just filters the rustc history, but pushing needs to construct a new
273-
rustc history that would filter to the given Miri history! To avoid problems, it
274-
is a good idea to always pull immediately before you push. In particular, you
275-
should never do two josh pushes without an intermediate pull; that can lead to
276-
duplicated commits.
262+
Keep in mind that pushing is the most complicated job that josh has to do -- pulling just filters
263+
the rustc history, but pushing needs to construct a new rustc history that would filter to the given
264+
Miri history! To avoid problems, it is a good idea to always pull immediately before you push. If
265+
you are getting strange errors, chances are you are running into [this josh
266+
bug](https://github.com/josh-project/josh/issues/998). In that case, please get in touch on Zulip.
277267

278-
Josh needs to be running, as described above. We will use the josh proxy to push
279-
to your fork of rustc. Run the following in the Miri repo, assuming we are on an
280-
up-to-date master branch:
268+
We will use the josh proxy to push to your fork of rustc. Run the following in the Miri repo,
269+
assuming we are on an up-to-date master branch:
281270

282271
```sh
283272
# Push the Miri changes to your rustc fork (substitute your github handle for YOUR_NAME).
@@ -287,3 +276,11 @@ up-to-date master branch:
287276
This will create a new branch called 'miri' in your fork, and the output should
288277
include a link to create a rustc PR that will integrate those changes into the
289278
main repository.
279+
280+
If this fails due to authentication problems, it can help to make josh push via ssh instead of
281+
https. Add the following to your `.gitconfig`:
282+
283+
```toml
284+
[url "git@github.com:"]
285+
pushInsteadOf = https://github.com/
286+
```

miri-script/Cargo.lock

+125
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

miri-script/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ anyhow = "1.0"
2020
xshell = "0.2"
2121
rustc_version = "0.4"
2222
dunce = "1.0.4"
23+
directories = "4"

miri-script/src/commands.rs

+66-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ use std::env;
22
use std::ffi::OsString;
33
use std::io::Write;
44
use std::ops::Not;
5+
use std::process;
6+
use std::thread;
7+
use std::time;
58

69
use anyhow::{anyhow, bail, Context, Result};
710
use path_macro::path;
@@ -14,6 +17,7 @@ use crate::Command;
1417
/// Used for rustc syncs.
1518
const JOSH_FILTER: &str =
1619
":rev(75dd959a3a40eb5b4574f8d2e23aa6efbeb33573:prefix=src/tools/miri):/src/tools/miri";
20+
const JOSH_PORT: &str = "42042";
1721

1822
impl MiriEnv {
1923
fn build_miri_sysroot(&mut self, quiet: bool) -> Result<()> {
@@ -81,6 +85,55 @@ impl Command {
8185
Ok(())
8286
}
8387

88+
fn start_josh() -> Result<impl Drop> {
89+
// Determine cache directory.
90+
let local_dir = {
91+
let user_dirs =
92+
directories::ProjectDirs::from("org", "rust-lang", "miri-josh").unwrap();
93+
user_dirs.cache_dir().to_owned()
94+
};
95+
96+
// Start josh, silencing its output.
97+
let mut cmd = process::Command::new("josh-proxy");
98+
cmd.arg("--local").arg(local_dir);
99+
cmd.arg("--remote").arg("https://github.com");
100+
cmd.arg("--port").arg(JOSH_PORT);
101+
cmd.arg("--no-background");
102+
cmd.stdout(process::Stdio::null());
103+
cmd.stderr(process::Stdio::null());
104+
let josh = cmd.spawn().context("failed to start josh-proxy, make sure it is installed")?;
105+
// Give it some time so hopefully the port is open. (10ms was not enough.)
106+
thread::sleep(time::Duration::from_millis(100));
107+
108+
// Create a wrapper that stops it on drop.
109+
struct Josh(process::Child);
110+
impl Drop for Josh {
111+
fn drop(&mut self) {
112+
#[cfg(unix)]
113+
{
114+
// Try to gracefully shut it down.
115+
process::Command::new("kill")
116+
.args(["-s", "INT", &self.0.id().to_string()])
117+
.output()
118+
.expect("failed to SIGINT josh-proxy");
119+
// Sadly there is no "wait with timeout"... so we just give it some time to finish.
120+
thread::sleep(time::Duration::from_millis(100));
121+
// Now hopefully it is gone.
122+
if self.0.try_wait().expect("failed to wait for josh-proxy").is_some() {
123+
return;
124+
}
125+
}
126+
// If that didn't work (or we're not on Unix), kill it hard.
127+
eprintln!(
128+
"I have to kill josh-proxy the hard way, let's hope this does not break anything."
129+
);
130+
self.0.kill().expect("failed to SIGKILL josh-proxy");
131+
}
132+
}
133+
134+
Ok(Josh(josh))
135+
}
136+
84137
pub fn exec(self) -> Result<()> {
85138
// First, and crucially only once, run the auto-actions -- but not for all commands.
86139
match &self {
@@ -174,6 +227,8 @@ impl Command {
174227
if cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty().not() {
175228
bail!("working directory must be clean before running `./miri rustc-pull`");
176229
}
230+
// Make sure josh is running.
231+
let josh = Self::start_josh()?;
177232

178233
// Update rust-version file. As a separate commit, since making it part of
179234
// the merge has confused the heck out of josh in the past.
@@ -186,7 +241,7 @@ impl Command {
186241
.context("FAILED to commit rust-version file, something went wrong")?;
187242

188243
// Fetch given rustc commit.
189-
cmd!(sh, "git fetch http://localhost:8000/rust-lang/rust.git@{commit}{JOSH_FILTER}.git")
244+
cmd!(sh, "git fetch http://localhost:{JOSH_PORT}/rust-lang/rust.git@{commit}{JOSH_FILTER}.git")
190245
.run()
191246
.map_err(|e| {
192247
// Try to un-do the previous `git commit`, to leave the repo in the state we found it it.
@@ -202,6 +257,8 @@ impl Command {
202257
cmd!(sh, "git merge FETCH_HEAD --no-verify --no-ff -m {MERGE_COMMIT_MESSAGE}")
203258
.run()
204259
.context("FAILED to merge new commits, something went wrong")?;
260+
261+
drop(josh);
205262
Ok(())
206263
}
207264

@@ -213,6 +270,8 @@ impl Command {
213270
if cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty().not() {
214271
bail!("working directory must be clean before running `./miri rustc-push`");
215272
}
273+
// Make sure josh is running.
274+
let josh = Self::start_josh()?;
216275

217276
// Find a repo we can do our preparation in.
218277
if let Ok(rustc_git) = env::var("RUSTC_GIT") {
@@ -249,6 +308,8 @@ impl Command {
249308
}
250309
cmd!(sh, "git fetch https://github.com/rust-lang/rust {base}").run()?;
251310
cmd!(sh, "git push https://github.com/{github_user}/rust {base}:refs/heads/{branch}")
311+
.ignore_stdout()
312+
.ignore_stderr() // silence the "create GitHub PR" message
252313
.run()?;
253314
println!();
254315

@@ -257,15 +318,15 @@ impl Command {
257318
println!("Pushing miri changes...");
258319
cmd!(
259320
sh,
260-
"git push http://localhost:8000/{github_user}/rust.git{JOSH_FILTER}.git HEAD:{branch}"
321+
"git push http://localhost:{JOSH_PORT}/{github_user}/rust.git{JOSH_FILTER}.git HEAD:{branch}"
261322
)
262323
.run()?;
263324
println!();
264325

265326
// Do a round-trip check to make sure the push worked as expected.
266327
cmd!(
267328
sh,
268-
"git fetch http://localhost:8000/{github_user}/rust.git{JOSH_FILTER}.git {branch}"
329+
"git fetch http://localhost:{JOSH_PORT}/{github_user}/rust.git{JOSH_FILTER}.git {branch}"
269330
)
270331
.ignore_stderr()
271332
.read()?;
@@ -278,6 +339,8 @@ impl Command {
278339
"Confirmed that the push round-trips back to Miri properly. Please create a rustc PR:"
279340
);
280341
println!(" https://github.com/{github_user}/rust/pull/new/{branch}");
342+
343+
drop(josh);
281344
Ok(())
282345
}
283346

miri-script/src/main.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![allow(clippy::needless_question_mark)]
2+
13
mod commands;
24
mod util;
35

0 commit comments

Comments
 (0)