Skip to content

Commit b3eb71f

Browse files
committed
old
1 parent 95d06d9 commit b3eb71f

File tree

1 file changed

+86
-129
lines changed
  • library/compiler-builtins/crates/josh-sync/src

1 file changed

+86
-129
lines changed
Lines changed: 86 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,173 +1,169 @@
1-
use std::io::{Write, stdout};
1+
use std::io::Write;
22
use std::ops::Not;
33
use std::path::PathBuf;
4-
use std::process::{Command, Stdio};
54
use std::time::Duration;
6-
use std::{env, fs, net, process};
5+
use std::{env, net, process};
76

87
use anyhow::{Context, anyhow, bail};
98
use xshell::{Shell, cmd};
109

11-
const PREPARING_COMMIT_MESSAGE: &str = "Preparing for merge from rustc";
12-
const MERGE_COMMIT_MESSAGE: &str = "Merge from rustc";
10+
/// Used for rustc syncs.
11+
const JOSH_FILTER: &str = ":/src/doc/rustc-dev-guide";
12+
const JOSH_PORT: u16 = 42042;
13+
const UPSTREAM_REPO: &str = "rust-lang/rust";
14+
15+
pub enum RustcPullError {
16+
/// No changes are available to be pulled.
17+
NothingToPull,
18+
/// A rustc-pull has failed, probably a git operation error has occurred.
19+
PullFailed(anyhow::Error),
20+
}
21+
22+
impl<E> From<E> for RustcPullError
23+
where
24+
E: Into<anyhow::Error>,
25+
{
26+
fn from(error: E) -> Self {
27+
Self::PullFailed(error.into())
28+
}
29+
}
1330

1431
pub struct GitSync {
1532
dir: PathBuf,
16-
upstream_repo: String,
17-
upstream_ref: String,
18-
upstream_url: String,
19-
josh_filter: String,
20-
josh_port: u16,
21-
josh_url_base: String,
2233
}
2334

2435
/// This code was adapted from the miri repository
2536
/// (https://github.com/rust-lang/miri/blob/6a68a79f38064c3bc30617cca4bdbfb2c336b140/miri-script/src/commands.rs#L236).
2637
impl GitSync {
2738
pub fn from_current_dir() -> anyhow::Result<Self> {
28-
let upstream_repo =
29-
env::var("UPSTREAM_ORG").unwrap_or_else(|_| "rust-lang".to_owned()) + "/rust";
30-
let josh_port = 42042;
3139
Ok(Self {
3240
dir: std::env::current_dir()?,
33-
upstream_url: format!("https://github.com/{upstream_repo}/"),
34-
upstream_repo,
35-
upstream_ref: env::var("UPSTREAM_REF").unwrap_or_else(|_| "HEAD".to_owned()),
36-
josh_filter: ":/library/compiler-builtins".to_owned(),
37-
josh_port,
38-
josh_url_base: format!("http://localhost:{josh_port}"),
3941
})
4042
}
4143

4244
pub fn rustc_pull(&self, commit: Option<String>) -> Result<(), RustcPullError> {
43-
let Self {
44-
upstream_repo,
45-
upstream_ref,
46-
upstream_url,
47-
josh_filter,
48-
josh_url_base,
49-
..
50-
} = self;
51-
5245
let sh = Shell::new()?;
5346
sh.change_dir(&self.dir);
54-
55-
let upstream_head = commit.unwrap_or_else(|| {
56-
let out = cmd!(sh, "git ls-remote {upstream_url} {upstream_ref}")
57-
.read()
58-
.unwrap();
59-
out.split_whitespace()
47+
let commit = commit.map(Ok).unwrap_or_else(|| {
48+
let rust_repo_head =
49+
cmd!(sh, "git ls-remote https://github.com/{UPSTREAM_REPO}/ HEAD").read()?;
50+
rust_repo_head
51+
.split_whitespace()
6052
.next()
61-
.unwrap_or_else(|| panic!("could not split output: '{out}'"))
62-
.to_owned()
63-
});
64-
65-
ensure_clean(&sh)?;
66-
53+
.map(|front| front.trim().to_owned())
54+
.ok_or_else(|| anyhow!("Could not obtain Rust repo HEAD from remote."))
55+
})?;
56+
// Make sure the repo is clean.
57+
if cmd!(sh, "git status --untracked-files=no --porcelain")
58+
.read()?
59+
.is_empty()
60+
.not()
61+
{
62+
return Err(anyhow::anyhow!(
63+
"working directory must be clean before performing rustc pull"
64+
)
65+
.into());
66+
}
6767
// Make sure josh is running.
68-
let _josh = self.start_josh()?;
68+
let josh = Self::start_josh()?;
6969
let josh_url =
70-
format!("{josh_url_base}/{upstream_repo}.git@{upstream_head}{josh_filter}.git");
70+
format!("http://localhost:{JOSH_PORT}/{UPSTREAM_REPO}.git@{commit}{JOSH_FILTER}.git");
7171

72-
let previous_base_commit = sh.read_file("rust-version").unwrap().trim().to_string();
73-
assert_ne!(previous_base_commit, upstream_head, "nothing to pull");
74-
75-
let orig_head = cmd!(sh, "git rev-parse HEAD").read().unwrap();
72+
let previous_base_commit = sh.read_file("rust-version")?.trim().to_string();
73+
if previous_base_commit == commit {
74+
return Err(RustcPullError::NothingToPull);
75+
}
7676

7777
// Update rust-version file. As a separate commit, since making it part of
7878
// the merge has confused the heck out of josh in the past.
7979
// We pass `--no-verify` to avoid running git hooks.
8080
// We do this before the merge so that if there are merge conflicts, we have
8181
// the right rust-version file while resolving them.
82-
sh.write_file("rust-version", format!("{upstream_head}\n"))?;
82+
sh.write_file("rust-version", format!("{commit}\n"))?;
83+
const PREPARING_COMMIT_MESSAGE: &str = "Preparing for merge from rustc";
8384
cmd!(
8485
sh,
8586
"git commit rust-version --no-verify -m {PREPARING_COMMIT_MESSAGE}"
8687
)
87-
.run()?;
88+
.run()
89+
.context("FAILED to commit rust-version file, something went wrong")?;
8890

8991
// Fetch given rustc commit.
9092
cmd!(sh, "git fetch {josh_url}")
9193
.run()
92-
.expect("FAILED to fetch new commits, something went wrong");
93-
94-
// // Fetch given rustc commit.
95-
// if let Err(e) = cmd!(sh, "git fetch {josh_url}").run() {
96-
// println!("FAILED to fetch new commits, something went wrong");
97-
98-
// // Try to un-do the previous `git commit`, to leave the repo in the state we found it.
99-
// cmd!(sh, "git reset --hard {orig_head}")
100-
// .run()
101-
// .expect("FAILED to clean up again after failed `git fetch`, sorry for that");
102-
103-
// println!("committing the rust-version file has been undone");
104-
// panic!("{e}");
105-
// }
94+
.inspect_err(|_| {
95+
// Try to un-do the previous `git commit`, to leave the repo in the state we found it.
96+
cmd!(sh, "git reset --hard HEAD^")
97+
.run()
98+
.expect("FAILED to clean up again after failed `git fetch`, sorry for that");
99+
})
100+
.context("FAILED to fetch new commits, something went wrong (committing the rust-version file has been undone)")?;
106101

107102
// This should not add any new root commits. So count those before and after merging.
108-
let num_roots = || -> u32 {
109-
let out = cmd!(sh, "git rev-list HEAD --max-parents=0 --count")
103+
let num_roots = || -> anyhow::Result<u32> {
104+
Ok(cmd!(sh, "git rev-list HEAD --max-parents=0 --count")
110105
.read()
111-
.expect("failed to determine the number of root commits");
112-
out.parse::<u32>()
113-
.unwrap_or_else(|e| panic!("failed to parse `out`: {e}"))
106+
.context("failed to determine the number of root commits")?
107+
.parse::<u32>()?)
114108
};
115-
let num_roots_before = num_roots();
109+
let num_roots_before = num_roots()?;
116110

117111
let sha = cmd!(sh, "git rev-parse HEAD")
118112
.output()
119-
.expect("FAILED to get current commit")
113+
.context("FAILED to get current commit")?
120114
.stdout;
121115

122116
// Merge the fetched commit.
117+
const MERGE_COMMIT_MESSAGE: &str = "Merge from rustc";
123118
cmd!(
124119
sh,
125120
"git merge FETCH_HEAD --no-verify --no-ff -m {MERGE_COMMIT_MESSAGE}"
126121
)
127122
.run()
128-
.expect("FAILED to merge new commits, something went wrong");
123+
.context("FAILED to merge new commits, something went wrong")?;
129124

130125
let current_sha = cmd!(sh, "git rev-parse HEAD")
131126
.output()
132127
.context("FAILED to get current commit")?
133128
.stdout;
134129
if current_sha == sha {
135-
cmd!(sh, "git reset --hard {orig_head}")
130+
cmd!(sh, "git reset --hard HEAD^")
136131
.run()
137132
.expect("FAILED to clean up after creating the preparation commit");
138133
eprintln!(
139-
"No merge was performed, no changes to pull were found. \
140-
Rolled back the preparation commit."
134+
"No merge was performed, no changes to pull were found. Rolled back the preparation commit."
141135
);
142136
return Err(RustcPullError::NothingToPull);
143137
}
144138

145139
// Check that the number of roots did not increase.
146-
if num_roots() != num_roots_before {
140+
if num_roots()? != num_roots_before {
147141
return Err(anyhow::anyhow!(
148142
"Josh created a new root commit. This is probably not the history you want."
149143
)
150144
.into());
151145
}
152146

147+
drop(josh);
153148
Ok(())
154149
}
155150

156151
pub fn rustc_push(&self, github_user: &str, branch: &str) -> anyhow::Result<()> {
157152
let sh = Shell::new()?;
158-
let Self {
159-
upstream_repo,
160-
josh_filter,
161-
josh_url_base,
162-
..
163-
} = self;
164153
sh.change_dir(&self.dir);
165154
let base = sh.read_file("rust-version")?.trim().to_owned();
166-
ensure_clean(&sh)?;
167-
155+
// Make sure the repo is clean.
156+
if cmd!(sh, "git status --untracked-files=no --porcelain")
157+
.read()?
158+
.is_empty()
159+
.not()
160+
{
161+
bail!("working directory must be clean before running `rustc-push`");
162+
}
168163
// Make sure josh is running.
169-
let josh = self.start_josh()?;
170-
let josh_url = format!("{josh_url_base}/{github_user}/rust.git{josh_filter}.git");
164+
let josh = Self::start_josh()?;
165+
let josh_url =
166+
format!("http://localhost:{JOSH_PORT}/{github_user}/rust.git{JOSH_FILTER}.git");
171167

172168
// Find a repo we can do our preparation in.
173169
if let Ok(rustc_git) = env::var("RUSTC_GIT") {
@@ -205,7 +201,7 @@ impl GitSync {
205201
);
206202
std::process::exit(1);
207203
}
208-
cmd!(sh, "git fetch https://github.com/{upstream_repo} {base}").run()?;
204+
cmd!(sh, "git fetch https://github.com/{UPSTREAM_REPO} {base}").run()?;
209205
cmd!(
210206
sh,
211207
"git push https://github.com/{github_user}/rust {base}:refs/heads/{branch}"
@@ -238,14 +234,14 @@ impl GitSync {
238234
);
239235
println!(
240236
// 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"
237+
" https://github.com/{UPSTREAM_REPO}/compare/{github_user}:{branch}?quick_pull=1&title=rustc-dev-guide+subtree+update&body=r?+@ghost"
242238
);
243239

244240
drop(josh);
245241
Ok(())
246242
}
247243

248-
fn start_josh(&self) -> anyhow::Result<impl Drop> {
244+
fn start_josh() -> anyhow::Result<impl Drop> {
249245
// Determine cache directory.
250246
let local_dir = {
251247
let user_dirs =
@@ -257,7 +253,7 @@ impl GitSync {
257253
let mut cmd = process::Command::new("josh-proxy");
258254
cmd.arg("--local").arg(local_dir);
259255
cmd.arg("--remote").arg("https://github.com");
260-
cmd.arg("--port").arg(self.josh_port.to_string());
256+
cmd.arg("--port").arg(JOSH_PORT.to_string());
261257
cmd.arg("--no-background");
262258
cmd.stdout(process::Stdio::null());
263259
cmd.stderr(process::Stdio::null());
@@ -300,7 +296,7 @@ impl GitSync {
300296
for _ in 0..100 {
301297
// This will generally fail immediately when the port is still closed.
302298
let josh_ready = net::TcpStream::connect_timeout(
303-
&net::SocketAddr::from(([127, 0, 0, 1], self.josh_port)),
299+
&net::SocketAddr::from(([127, 0, 0, 1], JOSH_PORT)),
304300
Duration::from_millis(1),
305301
);
306302
if josh_ready.is_ok() {
@@ -311,43 +307,4 @@ impl GitSync {
311307
}
312308
bail!("Even after waiting for 1s, josh-proxy is still not available.")
313309
}
314-
315-
fn run(&self, prog: &str, f: impl FnOnce(&mut Command) -> &mut Command) -> String {
316-
let mut cmd = Command::new(prog);
317-
cmd.current_dir(&self.dir).stderr(Stdio::inherit());
318-
f(&mut cmd);
319-
eprintln!("+ {cmd:?}");
320-
let out = cmd.output().expect("command failed");
321-
assert!(out.status.success());
322-
String::from_utf8(out.stdout).expect("non-UTF8 output")
323-
}
324-
}
325-
326-
fn ensure_clean(sh: &Shell) -> anyhow::Result<()> {
327-
// Make sure the repo is clean.
328-
if cmd!(sh, "git status --untracked-files=no --porcelain")
329-
.read()?
330-
.is_empty()
331-
.not()
332-
{
333-
bail!("working directory must be clean before performing rustc pull");
334-
}
335-
336-
Ok(())
337-
}
338-
339-
pub enum RustcPullError {
340-
/// No changes are available to be pulled.
341-
NothingToPull,
342-
/// A rustc-pull has failed, probably a git operation error has occurred.
343-
PullFailed(anyhow::Error),
344-
}
345-
346-
impl<E> From<E> for RustcPullError
347-
where
348-
E: Into<anyhow::Error>,
349-
{
350-
fn from(error: E) -> Self {
351-
Self::PullFailed(error.into())
352-
}
353310
}

0 commit comments

Comments
 (0)