Release as much at once as possible

This commit is contained in:
Gwilym Kuiper 2022-08-04 22:17:54 +01:00
parent c3f803206a
commit 604395ec26

View file

@ -1,4 +1,5 @@
use clap::{Arg, ArgAction, ArgMatches}; use clap::{Arg, ArgAction, ArgMatches};
use std::collections::{HashMap, HashSet};
use std::fs; use std::fs;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::Command; use std::process::Command;
@ -40,28 +41,53 @@ pub fn publish(matches: &ArgMatches) -> Result<(), Error> {
let root_directory = find_agb_root_directory()?; let root_directory = find_agb_root_directory()?;
for crate_to_publish in CRATES_TO_PUBLISH.iter() { let mut fully_published_crates: HashSet<String> = HashSet::new();
let crate_dir = root_directory.join(crate_to_publish); let mut published_crates: HashSet<String> = HashSet::new();
let dependencies = build_dependency_graph(&root_directory, CRATES_TO_PUBLISH)?;
while published_crates.len() != CRATES_TO_PUBLISH.len() {
// find all crates which can be published now but haven't
let publishable_crates: Vec<_> = CRATES_TO_PUBLISH
.iter()
.filter(|&&crate_to_publish| !published_crates.contains(crate_to_publish))
.filter(|&&crate_to_publish| {
let dependencies_of_crate = &dependencies[crate_to_publish];
for dependency_of_crate in dependencies_of_crate {
if !fully_published_crates.contains(dependency_of_crate) {
return false;
}
}
true
})
.collect();
for publishable_crate in publishable_crates {
if *dry_run { if *dry_run {
println!( println!("Would execute cargo publish for {publishable_crate}");
"Would run `cargo publish` in {}",
crate_dir.to_string_lossy()
);
} else { } else {
let publish_result = Command::new("cargo") Command::new("cargo")
.arg("publish") .arg("publish")
.current_dir(&crate_dir) .current_dir(&root_directory.join(publishable_crate))
.spawn(); .spawn()
.map_err(|_| Error::PublishCrate)?;
}
if let Err(err) = publish_result { published_crates.insert(publishable_crate.to_string());
println!("Error while publishing crate {crate_to_publish}: {err}"); }
return Err(Error::PublishCrate);
for published_crate in published_crates.iter() {
if !fully_published_crates.contains(published_crate) {
let expected_version =
read_cargo_toml_version(&root_directory.join(published_crate))?;
if check_if_released(published_crate, &expected_version)? {
fully_published_crates.insert(published_crate.clone());
}
} }
} }
let expected_version = read_cargo_toml_version(&crate_dir)?; thread::sleep(Duration::from_secs(10));
wait_for_release(crate_to_publish, &expected_version)?;
} }
Ok(()) Ok(())
@ -80,27 +106,17 @@ fn find_agb_root_directory() -> Result<PathBuf, Error> {
Ok(current_path) Ok(current_path)
} }
fn wait_for_release(crate_to_publish: &str, expected_version: &str) -> Result<(), Error> { fn check_if_released(crate_to_publish: &str, expected_version: &str) -> Result<bool, Error> {
let url_to_poll = &get_url_to_poll(crate_to_publish); let url_to_poll = &get_url_to_poll(crate_to_publish);
for attempt in 0..15 { println!("Polling crates.io with URL {url_to_poll} for {crate_to_publish} hoping for version {expected_version}.");
println!(
"Polling crates.io with URL {url_to_poll} for {crate_to_publish} hoping for version {expected_version}. Attempt {attempt}"
);
let curl_result = Command::new("curl") let curl_result = Command::new("curl")
.arg(url_to_poll) .arg(url_to_poll)
.output() .output()
.map_err(|_| Error::Poll)?; .map_err(|_| Error::Poll)?;
if String::from_utf8_lossy(&curl_result.stdout).contains(expected_version) { Ok(String::from_utf8_lossy(&curl_result.stdout).contains(expected_version))
return Ok(());
}
thread::sleep(Duration::from_secs(30));
}
Ok(())
} }
fn get_url_to_poll(crate_name: &str) -> String { fn get_url_to_poll(crate_name: &str) -> String {
@ -130,6 +146,22 @@ fn read_cargo_toml_version(folder: &Path) -> Result<String, Error> {
Ok(version_value.to_owned()) Ok(version_value.to_owned())
} }
fn build_dependency_graph(
root: &Path,
agb_crates: &[&str],
) -> Result<HashMap<String, Vec<String>>, Error> {
let mut result = HashMap::new();
for agb_crate in agb_crates {
result.insert(
agb_crate.to_string(),
get_agb_dependencies(&root.join(agb_crate))?,
);
}
Ok(result)
}
fn get_agb_dependencies(folder: &Path) -> Result<Vec<String>, Error> { fn get_agb_dependencies(folder: &Path) -> Result<Vec<String>, Error> {
let cargo_toml = read_cargo_toml(folder)?; let cargo_toml = read_cargo_toml(folder)?;