Skip to content

Commit e7c1097

Browse files
committed
update
1 parent 89f7f73 commit e7c1097

File tree

2 files changed

+121
-108
lines changed

2 files changed

+121
-108
lines changed

library/compiler-builtins/crates/josh-sync/src/main.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ fn main() -> anyhow::Result<()> {
3636
}
3737
}
3838
}
39-
["rustc-push", branch, github_username] => {
40-
sync.rustc_push(github_username, branch)?;
39+
["rustc-push", github_user, branch] => {
40+
sync.rustc_push(github_user, Some(branch))?;
41+
}
42+
["rustc-push", github_user] => {
43+
sync.rustc_push(github_user, None)?;
4144
}
4245
_ => {
4346
println!("{USAGE}");

library/compiler-builtins/crates/josh-sync/src/sync.rs

Lines changed: 116 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::io::{Write, stdout};
22
use std::ops::Not;
33
use std::path::PathBuf;
4-
use std::process::{Command, Stdio};
4+
use std::process::{Command, Stdio, exit};
55
use std::time::Duration;
66
use std::{env, fs, net, process};
77

@@ -10,6 +10,7 @@ use xshell::{Shell, cmd};
1010

1111
const PREPARING_COMMIT_MESSAGE: &str = "Preparing for merge from rustc";
1212
const MERGE_COMMIT_MESSAGE: &str = "Merge from rustc";
13+
const DEFAULT_PR_BRANCH: &str = "update-builtins";
1314

1415
pub struct GitSync {
1516
dir: PathBuf,
@@ -53,9 +54,7 @@ impl GitSync {
5354
sh.change_dir(&self.dir);
5455

5556
let upstream_head = commit.unwrap_or_else(|| {
56-
let out = cmd!(sh, "git ls-remote {upstream_url} {upstream_ref}")
57-
.read()
58-
.unwrap();
57+
let out = self.read(&["git", "ls-remote", upstream_url, upstream_ref]);
5958
out.split_whitespace()
6059
.next()
6160
.unwrap_or_else(|| panic!("could not split output: '{out}'"))
@@ -72,24 +71,25 @@ impl GitSync {
7271
let previous_base_commit = sh.read_file("rust-version").unwrap().trim().to_string();
7372
assert_ne!(previous_base_commit, upstream_head, "nothing to pull");
7473

75-
let orig_head = cmd!(sh, "git rev-parse HEAD").read().unwrap();
74+
let orig_head = self.read(["git", "rev-parse", "HEAD"]);
7675

7776
// Update rust-version file. As a separate commit, since making it part of
7877
// the merge has confused the heck out of josh in the past.
7978
// We pass `--no-verify` to avoid running git hooks.
8079
// We do this before the merge so that if there are merge conflicts, we have
8180
// the right rust-version file while resolving them.
8281
sh.write_file("rust-version", format!("{upstream_head}\n"))?;
83-
cmd!(
84-
sh,
85-
"git commit rust-version --no-verify -m {PREPARING_COMMIT_MESSAGE}"
86-
)
87-
.run()?;
82+
self.run([
83+
"git",
84+
"commit",
85+
"rust-version",
86+
"--no-verify",
87+
"-m",
88+
PREPARING_COMMIT_MESSAGE,
89+
]);
8890

8991
// Fetch given rustc commit.
90-
cmd!(sh, "git fetch {josh_url}")
91-
.run()
92-
.expect("FAILED to fetch new commits, something went wrong");
92+
self.run(["git", "fetch", &josh_url]);
9393

9494
// // Fetch given rustc commit.
9595
// if let Err(e) = cmd!(sh, "git fetch {josh_url}").run() {
@@ -106,139 +106,134 @@ impl GitSync {
106106

107107
// This should not add any new root commits. So count those before and after merging.
108108
let num_roots = || -> u32 {
109-
let out = cmd!(sh, "git rev-list HEAD --max-parents=0 --count")
110-
.read()
111-
.expect("failed to determine the number of root commits");
109+
let out = self.read(["git", "rev-list", "HEAD", "--max-parents=0", "--count"]);
112110
out.parse::<u32>()
113-
.unwrap_or_else(|e| panic!("failed to parse `out`: {e}"))
111+
.unwrap_or_else(|e| panic!("failed to parse `{out}`: {e}"))
114112
};
115113
let num_roots_before = num_roots();
116114

117-
let sha = cmd!(sh, "git rev-parse HEAD")
118-
.output()
119-
.expect("FAILED to get current commit")
120-
.stdout;
115+
let pre_merge_sha = self.read(["git", "rev-parse", "HEAD"]);
121116

122117
// Merge the fetched commit.
123-
cmd!(
124-
sh,
125-
"git merge FETCH_HEAD --no-verify --no-ff -m {MERGE_COMMIT_MESSAGE}"
126-
)
127-
.run()
128-
.expect("FAILED to merge new commits, something went wrong");
129-
130-
let current_sha = cmd!(sh, "git rev-parse HEAD")
131-
.output()
132-
.context("FAILED to get current commit")?
133-
.stdout;
134-
if current_sha == sha {
135-
cmd!(sh, "git reset --hard {orig_head}")
136-
.run()
137-
.expect("FAILED to clean up after creating the preparation commit");
118+
self.run([
119+
"git",
120+
"merge",
121+
"FETCH_HEAD",
122+
"--no-verify",
123+
"--no-ff",
124+
"-m",
125+
MERGE_COMMIT_MESSAGE,
126+
]);
127+
128+
let current_sha = self.read(["git", "rev-parse", "HEAD"]);
129+
if current_sha == pre_merge_sha {
130+
self.run(["git", "reset", "--hard", &orig_head]);
138131
eprintln!(
139132
"No merge was performed, no changes to pull were found. \
140133
Rolled back the preparation commit."
141134
);
142-
return Err(RustcPullError::NothingToPull);
135+
exit(1);
143136
}
144137

145138
// Check that the number of roots did not increase.
146-
if num_roots() != num_roots_before {
147-
return Err(anyhow::anyhow!(
148-
"Josh created a new root commit. This is probably not the history you want."
149-
)
150-
.into());
151-
}
139+
assert_eq!(
140+
num_roots(),
141+
num_roots_before,
142+
"Josh created a new root commit. This is probably not the history you want."
143+
);
152144

153145
Ok(())
154146
}
155147

156-
pub fn rustc_push(&self, github_user: &str, branch: &str) -> anyhow::Result<()> {
157-
let sh = Shell::new()?;
148+
pub fn rustc_push(&self, github_user: &str, branch: Option<&str>) -> anyhow::Result<()> {
158149
let Self {
159150
upstream_repo,
160151
josh_filter,
161152
josh_url_base,
153+
upstream_url,
162154
..
163155
} = self;
156+
157+
let sh = Shell::new()?;
164158
sh.change_dir(&self.dir);
165-
let base = sh.read_file("rust-version")?.trim().to_owned();
159+
160+
let branch = branch.unwrap_or(DEFAULT_PR_BRANCH);
161+
let josh_url = format!("{josh_url_base}/{github_user}/rust.git{josh_filter}.git");
162+
let user_rust_url = format!("git@github.com:{github_user}/rust.git");
163+
164+
let Ok(rustc_git) = env::var("RUSTC_GIT") else {
165+
panic!("the RUSTC_GIT environment variable must be set to a rust-lang/rust checkout")
166+
};
167+
166168
ensure_clean(&sh)?;
169+
let base = sh.read_file("rust-version")?.trim().to_owned();
167170

168171
// Make sure josh is running.
169172
let josh = self.start_josh()?;
170-
let josh_url = format!("{josh_url_base}/{github_user}/rust.git{josh_filter}.git");
171173

172-
// Find a repo we can do our preparation in.
173-
if let Ok(rustc_git) = env::var("RUSTC_GIT") {
174-
// If rustc_git is `Some`, we'll use an existing fork for the branch updates.
175-
sh.change_dir(rustc_git);
176-
} else {
177-
// Otherwise, do this in the local repo.
178-
println!(
179-
"This will pull a copy of the rust-lang/rust history into this checkout, growing it by about 1GB."
180-
);
181-
print!(
182-
"To avoid that, abort now and set the `RUSTC_GIT` environment variable to an existing rustc checkout. Proceed? [y/N] "
183-
);
184-
std::io::stdout().flush()?;
185-
let mut answer = String::new();
186-
std::io::stdin().read_line(&mut answer)?;
187-
if answer.trim().to_lowercase() != "y" {
188-
std::process::exit(1);
189-
}
190-
};
191174
// Prepare the branch. Pushing works much better if we use as base exactly
192175
// the commit that we pulled from last time, so we use the `rust-version`
193176
// file to find out which commit that would be.
194177
println!("Preparing {github_user}/rust (base: {base})...");
195-
if cmd!(
196-
sh,
197-
"git fetch https://github.com/{github_user}/rust {branch}"
198-
)
199-
.ignore_stderr()
200-
.read()
201-
.is_ok()
178+
179+
if Command::new("git")
180+
.args(["-C", &rustc_git, "fetch", &user_rust_url])
181+
.output()
182+
.expect("could not run fetch")
183+
.status
184+
.success()
202185
{
203-
println!(
204-
"The branch '{branch}' seems to already exist in 'https://github.com/{github_user}/rust'. Please delete it and try again."
186+
panic!(
187+
"The branch '{branch}' seems to already exist in '{user_rust_url}'. \
188+
Please delete it and try again."
205189
);
206-
std::process::exit(1);
207190
}
208-
cmd!(sh, "git fetch https://github.com/{upstream_repo} {base}").run()?;
209-
cmd!(
210-
sh,
211-
"git push https://github.com/{github_user}/rust {base}:refs/heads/{branch}"
212-
)
213-
.ignore_stdout()
214-
.ignore_stderr() // silence the "create GitHub PR" message
215-
.run()?;
216-
println!();
191+
192+
self.run([
193+
"git",
194+
"-C",
195+
&rustc_git,
196+
"fetch",
197+
&format!("https://github.com/{upstream_repo}"),
198+
&base,
199+
]);
200+
201+
self.run_args("git", |c| {
202+
c.args([
203+
"-C",
204+
&rustc_git,
205+
"push",
206+
&format!("https://github.com/{github_user}/rust"),
207+
&format!("{base}:refs/heads/{branch}"),
208+
])
209+
.stdout(Stdio::null())
210+
.stderr(Stdio::null()) // silence the "create GitHub PR" message
211+
});
212+
println!("pushed PR branch");
217213

218214
// Do the actual push.
219215
sh.change_dir(&self.dir);
220216
println!("Pushing changes...");
221-
cmd!(sh, "git push {josh_url} HEAD:{branch}").run()?;
217+
self.run(["git", "push", &josh_url, &format!("HEAD:{branch}")]);
222218
println!();
223219

224220
// Do a round-trip check to make sure the push worked as expected.
225-
cmd!(sh, "git fetch {josh_url} {branch}")
226-
.ignore_stderr()
227-
.read()?;
228-
let head = cmd!(sh, "git rev-parse HEAD").read()?;
229-
let fetch_head = cmd!(sh, "git rev-parse FETCH_HEAD").read()?;
230-
if head != fetch_head {
231-
bail!(
232-
"Josh created a non-roundtrip push! Do NOT merge this into rustc!\n\
233-
Expected {head}, got {fetch_head}."
234-
);
235-
}
221+
self.run(["git", "fetch", &josh_url, &branch]); // TODO depth=1?
222+
223+
let head = self.read(["git", "rev-parse", "HEAD"]);
224+
let fetch_head = self.read(["git", "rev-parse", "FETCH_HEAD"]);
225+
assert_eq!(
226+
head, fetch_head,
227+
"Josh created a non-roundtrip push! Do NOT merge this into rustc!\n\
228+
Expected {head}, got {fetch_head}."
229+
);
236230
println!(
237-
"Confirmed that the push round-trips back to rustc-dev-guide properly. Please create a rustc PR:"
231+
"Confirmed that the push round-trips back to rustc-dev-guide properly. Please \
232+
create a rustc PR:"
238233
);
234+
// Open PR with `subtree update` title to silence the `no-merges` triagebot check
239235
println!(
240-
// Open PR with `subtree update` title to silence the `no-merges` triagebot check
241-
" https://github.com/{upstream_repo}/compare/{github_user}:{branch}?quick_pull=1&title=rustc-dev-guide+subtree+update&body=r?+@ghost"
236+
" {upstream_url}/compare/{github_user}:{branch}?quick_pull=1&title=rustc-dev-guide+subtree+update&body=r?+@ghost"
242237
);
243238

244239
drop(josh);
@@ -263,16 +258,15 @@ impl GitSync {
263258
cmd.stderr(process::Stdio::null());
264259
let josh = cmd
265260
.spawn()
266-
.context("failed to start josh-proxy, make sure it is installed")?;
261+
.expect("failed to start josh-proxy, make sure it is installed");
267262

268263
// Create a wrapper that stops it on drop.
269264
struct Josh(process::Child);
270265
impl Drop for Josh {
271266
fn drop(&mut self) {
272-
#[cfg(unix)]
273-
{
267+
if cfg!(unix) {
274268
// Try to gracefully shut it down.
275-
process::Command::new("kill")
269+
Command::new("kill")
276270
.args(["-s", "INT", &self.0.id().to_string()])
277271
.output()
278272
.expect("failed to SIGINT josh-proxy");
@@ -290,7 +284,8 @@ impl GitSync {
290284
}
291285
// If that didn't work (or we're not on Unix), kill it hard.
292286
eprintln!(
293-
"I have to kill josh-proxy the hard way, let's hope this does not break anything."
287+
"I have to kill josh-proxy the hard way, let's hope this does not \
288+
break anything."
294289
);
295290
self.0.kill().expect("failed to SIGKILL josh-proxy");
296291
}
@@ -312,7 +307,22 @@ impl GitSync {
312307
bail!("Even after waiting for 1s, josh-proxy is still not available.")
313308
}
314309

315-
fn run(&self, prog: &str, f: impl FnOnce(&mut Command) -> &mut Command) -> String {
310+
fn run<'a, Args: AsRef<[&'a str]>>(&self, l: Args) {
311+
let l = l.as_ref();
312+
self.run_args(l[0], |c| c.args(&l[1..]))
313+
}
314+
315+
fn run_args(&self, prog: &str, f: impl FnOnce(&mut Command) -> &mut Command) {
316+
// self.read(l.as_ref());
317+
self.read_args(prog, |c| f(c.stdout(Stdio::inherit())));
318+
}
319+
320+
fn read<'a, Args: AsRef<[&'a str]>>(&self, l: Args) -> String {
321+
let l = l.as_ref();
322+
self.read_args(l[0], |c| c.args(&l[1..]))
323+
}
324+
325+
fn read_args(&self, prog: &str, f: impl FnOnce(&mut Command) -> &mut Command) -> String {
316326
let mut cmd = Command::new(prog);
317327
cmd.current_dir(&self.dir).stderr(Stdio::inherit());
318328
f(&mut cmd);

0 commit comments

Comments
 (0)