Skip to content

Commit 2950c89

Browse files
committed
Split config and rust-version files
1 parent d37dfec commit 2950c89

File tree

6 files changed

+83
-55
lines changed

6 files changed

+83
-55
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ $ cargo install --locked --git https://github.com/rust-lang/josh-sync
1313

1414
First, create a configuration file for a given subtree repo using `josh-sync init`. The config will be created under the path `josh-sync.toml`. Modify the file to fill in the name of the subtree repository (e.g. `stdarch`) and its relative path in the main `rust-lang/rust` repository (e.g. `library/stdarch`).
1515

16+
The `init` command will also create an empty `rust-version` file that stores the last upstream `rustc` SHA that was synced in the subtree.
17+
1618
## Performing pull
1719

1820
A pull operation fetches changes to the subtree subdirectory that were performed in `rust-lang/rust` and merges them into the subtree repository. After performing a pull, a pull request is sent against the *subtree repository*. We *pull from rustc*.

josh-sync.example.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
org = "rust-lang"
22
repo = "stdarch"
33
path = "library/stdarch"
4-
last_upstream_sha = "abcdef"

src/bin/josh_sync.rs

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
use anyhow::Context;
22
use clap::Parser;
3+
use josh_sync::SyncContext;
34
use josh_sync::config::{JoshConfig, load_config};
45
use josh_sync::josh::{JoshProxy, try_install_josh};
56
use josh_sync::sync::{GitSync, RustcPullError, UPSTREAM_REPO};
67
use josh_sync::utils::prompt;
78
use std::path::{Path, PathBuf};
89

910
const DEFAULT_CONFIG_PATH: &str = "josh-sync.toml";
11+
const DEFAULT_RUST_VERSION_PATH: &str = "rust-version";
1012

1113
#[derive(clap::Parser)]
1214
struct Args {
@@ -16,20 +18,24 @@ struct Args {
1618

1719
#[derive(clap::Parser)]
1820
enum Command {
19-
/// Initialize a config file for this repository.
21+
/// Initialize a config file and an empty `rust-version` file for this repository.
2022
Init,
2123
/// Pull changes from the main `rust-lang/rust` repository.
2224
/// This creates new commits that should be then merged into this subtree repository.
2325
Pull {
2426
#[clap(long, default_value(DEFAULT_CONFIG_PATH))]
25-
config: PathBuf,
27+
config_path: PathBuf,
28+
#[clap(long, default_value(DEFAULT_RUST_VERSION_PATH))]
29+
rust_version_path: PathBuf,
2630
},
2731
/// Push changes into the main `rust-lang/rust` repository `branch` of a `rustc` fork under
2832
/// the given GitHub `username`.
2933
/// The pushed branch should then be merged into the `rustc` repository.
3034
Push {
3135
#[clap(long, default_value(DEFAULT_CONFIG_PATH))]
32-
config: PathBuf,
36+
config_path: PathBuf,
37+
#[clap(long, default_value(DEFAULT_RUST_VERSION_PATH))]
38+
rust_version_path: PathBuf,
3339
/// Branch that should be pushed to your remote
3440
branch: String,
3541
/// Your GitHub usename where the fork is located
@@ -45,22 +51,26 @@ fn main() -> anyhow::Result<()> {
4551
org: "rust-lang".to_string(),
4652
repo: "<repository-name>".to_string(),
4753
path: "<relative-subtree-path>".to_string(),
48-
last_upstream_sha: None,
4954
};
5055
config
5156
.write(Path::new(DEFAULT_CONFIG_PATH))
5257
.context("cannot write config")?;
5358
println!("Created config file at {DEFAULT_CONFIG_PATH}");
59+
std::fs::write(DEFAULT_RUST_VERSION_PATH, "")
60+
.context("cannot write rust-version file")?;
61+
println!("Created empty rust-version file at {DEFAULT_RUST_VERSION_PATH}");
5462
}
55-
Command::Pull { config } => {
56-
let config = load_config(&config)
57-
.context("cannot load config. Run the `init` command to initialize it.")?;
63+
Command::Pull {
64+
config_path,
65+
rust_version_path,
66+
} => {
67+
let ctx = load_context(&config_path, &rust_version_path)?;
5868
let josh = get_josh_proxy()?;
59-
let sync = GitSync::new(config.clone(), josh);
69+
let sync = GitSync::new(ctx.clone(), josh);
6070
match sync.rustc_pull() {
6171
Ok(result) => {
6272
maybe_create_gh_pr(
63-
&config.config.full_repo_name(),
73+
&ctx.config.full_repo_name(),
6474
"Rustc pull update",
6575
&result.merge_commit_message,
6676
)?;
@@ -78,27 +88,41 @@ fn main() -> anyhow::Result<()> {
7888
Command::Push {
7989
username,
8090
branch,
81-
config,
91+
config_path,
92+
rust_version_path,
8293
} => {
83-
let config = load_config(&config)
84-
.context("cannot load config. Run the `init` command to initialize it.")?;
94+
let ctx = load_context(&config_path, &rust_version_path)?;
8595
let josh = get_josh_proxy()?;
86-
let sync = GitSync::new(config.clone(), josh);
96+
let sync = GitSync::new(ctx.clone(), josh);
8797
sync.rustc_push(&username, &branch)
8898
.context("cannot perform push")?;
8999

90100
// Open PR with `subtree update` title to silence the `no-merges` triagebot check
91101
println!(
92102
r#"You can create the rustc PR using the following URL:
93103
https://github.com/{UPSTREAM_REPO}/compare/{username}:{branch}?quick_pull=1&title={}+subtree+update&body=r?+@ghost"#,
94-
config.config.repo
104+
ctx.config.repo
95105
);
96106
}
97107
}
98108

99109
Ok(())
100110
}
101111

112+
fn load_context(config_path: &Path, rust_version_path: &Path) -> anyhow::Result<SyncContext> {
113+
let config = load_config(&config_path)
114+
.context("cannot load config. Run the `init` command to initialize it.")?;
115+
let rust_version = std::fs::read_to_string(&rust_version_path)
116+
.inspect_err(|err| eprintln!("Cannot load rust-version file: {err:?}"))
117+
.map(Some)
118+
.unwrap_or_default();
119+
Ok(SyncContext {
120+
config,
121+
last_upstream_sha_path: rust_version_path.to_path_buf(),
122+
last_upstream_sha: rust_version,
123+
})
124+
}
125+
102126
fn maybe_create_gh_pr(repo: &str, title: &str, description: &str) -> anyhow::Result<bool> {
103127
let gh_available = which::which("gh").is_ok();
104128
if !gh_available {

src/config.rs

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use anyhow::Context;
2-
use std::path::{Path, PathBuf};
2+
use std::path::Path;
33

44
#[derive(serde::Serialize, serde::Deserialize, Clone)]
55
pub struct JoshConfig {
@@ -9,9 +9,6 @@ pub struct JoshConfig {
99
/// Relative path where the subtree is located in rust-lang/rust.
1010
/// For example `src/doc/rustc-dev-guide`.
1111
pub path: String,
12-
/// Last SHA of rust-lang/rust that was pulled into this subtree.
13-
#[serde(default)]
14-
pub last_upstream_sha: Option<String>,
1512
}
1613

1714
impl JoshConfig {
@@ -26,22 +23,13 @@ impl JoshConfig {
2623
}
2724
}
2825

29-
#[derive(Clone)]
30-
pub struct JoshConfigWithPath {
31-
pub config: JoshConfig,
32-
pub path: PathBuf,
33-
}
34-
3526
fn default_org() -> String {
3627
String::from("rust-lang")
3728
}
3829

39-
pub fn load_config(path: &Path) -> anyhow::Result<JoshConfigWithPath> {
30+
pub fn load_config(path: &Path) -> anyhow::Result<JoshConfig> {
4031
let data = std::fs::read_to_string(path)
4132
.with_context(|| format!("cannot load config file from {}", path.display()))?;
4233
let config: JoshConfig = toml::from_str(&data).context("cannot load config as TOML")?;
43-
Ok(JoshConfigWithPath {
44-
config,
45-
path: path.to_path_buf(),
46-
})
34+
Ok(config)
4735
}

src/lib.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,17 @@
1+
use crate::config::JoshConfig;
2+
use std::path::PathBuf;
3+
14
pub mod config;
25
pub mod josh;
36
pub mod sync;
47
pub mod utils;
8+
9+
#[derive(Clone)]
10+
pub struct SyncContext {
11+
pub config: JoshConfig,
12+
/// The last synced upstream SHA, which should be present
13+
/// if a pull was already performed at least once.
14+
pub last_upstream_sha: Option<String>,
15+
/// Path to a file that stores the last synced upstream SHA.
16+
pub last_upstream_sha_path: PathBuf,
17+
}

src/sync.rs

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::config::JoshConfigWithPath;
1+
use crate::SyncContext;
22
use crate::josh::JoshProxy;
33
use crate::utils::{check_output, check_output_at, ensure_clean_git_state};
44
use anyhow::{Context, Error};
@@ -29,13 +29,13 @@ pub struct PullResult {
2929
}
3030

3131
pub struct GitSync {
32-
config: JoshConfigWithPath,
32+
context: SyncContext,
3333
proxy: JoshProxy,
3434
}
3535

3636
impl GitSync {
37-
pub fn new(config: JoshConfigWithPath, proxy: JoshProxy) -> Self {
38-
Self { config, proxy }
37+
pub fn new(context: SyncContext, proxy: JoshProxy) -> Self {
38+
Self { context, proxy }
3939
}
4040

4141
pub fn rustc_pull(&self) -> Result<PullResult, RustcPullError> {
@@ -59,26 +59,26 @@ impl GitSync {
5959
// Make sure josh is running.
6060
let josh = self
6161
.proxy
62-
.start(&self.config.config)
62+
.start(&self.context.config)
6363
.context("cannot start josh-proxy")?;
6464
let josh_url = josh.git_url(
6565
UPSTREAM_REPO,
6666
Some(&upstream_sha),
67-
&construct_filter(&self.config.config.path),
67+
&construct_filter(&self.context.config.path),
6868
);
6969

7070
let orig_head = check_output(["git", "rev-parse", "HEAD"])?;
7171
println!(
7272
"previous upstream base: {:?}",
73-
self.config.config.last_upstream_sha
73+
self.context.last_upstream_sha
7474
);
7575
println!("new upstream base: {upstream_sha}");
7676
println!("original local HEAD: {orig_head}");
7777

78-
/// If the upstream SHA hasn't changed from the latest sync, there is nothing to pull
79-
/// We distinguish this situation for tools that might not want to consider this to
80-
/// be an error.
81-
if let Some(previous_base_commit) = self.config.config.last_upstream_sha.as_ref() {
78+
// If the upstream SHA hasn't changed from the latest sync, there is nothing to pull
79+
// We distinguish this situation for tools that might not want to consider this to
80+
// be an error.
81+
if let Some(previous_base_commit) = self.context.last_upstream_sha.as_ref() {
8282
if *previous_base_commit == upstream_sha {
8383
return Err(RustcPullError::NothingToPull);
8484
}
@@ -89,16 +89,23 @@ impl GitSync {
8989
// We pass `--no-verify` to avoid running git hooks.
9090
// We do this before the merge so that if there are merge conflicts, we have
9191
// the right rust-version file while resolving them.
92-
let mut config = self.config.config.clone();
93-
config.last_upstream_sha = Some(upstream_sha.clone());
94-
config.write(&self.config.path)?;
92+
std::fs::write(&self.context.last_upstream_sha_path, &upstream_sha).with_context(|| {
93+
anyhow::anyhow!(
94+
"cannot write upstream SHA to {}",
95+
self.context.last_upstream_sha_path.display()
96+
)
97+
})?;
9598

9699
let prep_message = format!(
97100
r#"Update the upstream Rust SHA to {upstream_sha}.
98101
To prepare for merging from {UPSTREAM_REPO}."#,
99102
);
100103

101-
let config_path = self.config.path.to_string_lossy().to_string();
104+
let config_path = self
105+
.context
106+
.last_upstream_sha_path
107+
.to_string_lossy()
108+
.to_string();
102109
check_output(&["git", "add", &config_path])?;
103110
check_output(&[
104111
"git",
@@ -143,7 +150,7 @@ Upstream ref: {upstream_sha}
143150
Filtered ref: {incoming_ref}
144151
"#,
145152
upstream_head_short = &upstream_sha[..12],
146-
filter = construct_filter(&self.config.config.path)
153+
filter = construct_filter(&self.context.config.path)
147154
);
148155

149156
// Merge the fetched commit.
@@ -186,22 +193,17 @@ Filtered ref: {incoming_ref}
186193
pub fn rustc_push(&self, username: &str, branch: &str) -> anyhow::Result<()> {
187194
ensure_clean_git_state();
188195

189-
let base_upstream_sha = self
190-
.config
191-
.config
192-
.last_upstream_sha
193-
.clone()
194-
.unwrap_or_default();
196+
let base_upstream_sha = self.context.last_upstream_sha.clone().unwrap_or_default();
195197

196198
// Make sure josh is running.
197199
let josh = self
198200
.proxy
199-
.start(&self.config.config)
201+
.start(&self.context.config)
200202
.context("cannot start josh-proxy")?;
201203
let josh_url = josh.git_url(
202204
&format!("{username}/rust"),
203205
None,
204-
&construct_filter(&self.config.config.path),
206+
&construct_filter(&self.context.config.path),
205207
);
206208
let user_upstream_url = format!("https://github.com/{username}/rust");
207209

@@ -273,7 +275,7 @@ Filtered ref: {incoming_ref}
273275
}
274276
println!(
275277
"Confirmed that the push round-trips back to {} properly. Please create a rustc PR.",
276-
self.config.config.repo
278+
self.context.config.repo
277279
);
278280

279281
Ok(())

0 commit comments

Comments
 (0)