aboutsummaryrefslogtreecommitdiff
path: root/.run/src/bin
diff options
context:
space:
mode:
Diffstat (limited to '.run/src/bin')
-rw-r--r--.run/src/bin/release.rs145
1 files changed, 145 insertions, 0 deletions
diff --git a/.run/src/bin/release.rs b/.run/src/bin/release.rs
new file mode 100644
index 0000000..8cb4d1b
--- /dev/null
+++ b/.run/src/bin/release.rs
@@ -0,0 +1,145 @@
+use std::path::{Path, PathBuf};
+use std::process;
+use tools::dependency_order::{display_dependency_order, find_workspace_root};
+use tools::{
+ eprintln_cargo_style, println_cargo_style, run_cmd_capture_with_dir, run_cmd_with_dir,
+};
+
+/// Read the version from `[workspace.package].version` in the root Cargo.toml.
+fn read_workspace_version(workspace_root: &Path) -> Option<String> {
+ let content = std::fs::read_to_string(workspace_root.join("Cargo.toml")).ok()?;
+ let value: toml::Value = content.parse().ok()?;
+ value
+ .get("workspace")?
+ .get("package")?
+ .get("version")?
+ .as_str()
+ .map(String::from)
+}
+
+/// Replace `path = "crate_name"` with `version = "VERSION"` in the file content.
+fn update_path_to_version(content: &str, crate_name: &str, version: &str) -> String {
+ let old = format!("path = \"{}\"", crate_name);
+ let new = format!("version = \"{}\"", version);
+ content.replace(&old, &new)
+}
+
+/// Restore the backup and abort.
+fn abort(toml_path: &Path) -> ! {
+ let backup_path = toml_path.with_extension("toml.bkup");
+ if backup_path.exists() {
+ if let Err(e) = std::fs::copy(&backup_path, toml_path) {
+ eprintln_cargo_style!("failed to restore Cargo.toml from backup: {}", e);
+ } else {
+ eprintln_cargo_style!("restored Cargo.toml from backup");
+ }
+ }
+ process::exit(1);
+}
+
+fn main() {
+ // 1. Compute dependency order
+ let order = display_dependency_order();
+ if order.is_empty() {
+ eprintln_cargo_style!("could not find workspace root or mingling crates");
+ process::exit(1);
+ }
+
+ // 2. Locate workspace root
+ let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
+ let workspace_root = match find_workspace_root(&cwd) {
+ Some(r) => r,
+ None => {
+ eprintln_cargo_style!("could not find workspace root");
+ process::exit(1);
+ }
+ };
+
+ // 3. Read current version
+ let version = match read_workspace_version(&workspace_root) {
+ Some(v) => v,
+ None => {
+ eprintln_cargo_style!("could not read workspace.package.version from Cargo.toml");
+ process::exit(1);
+ }
+ };
+
+ println_cargo_style!("Version: detected version {}", version);
+
+ let toml_path = workspace_root.join("Cargo.toml");
+ let backup_path = workspace_root.join("Cargo.toml.bkup");
+
+ // 4. Backup Cargo.toml
+ if let Err(e) = std::fs::copy(&toml_path, &backup_path) {
+ eprintln_cargo_style!("failed to backup Cargo.toml: {}", e);
+ process::exit(1);
+ }
+ println_cargo_style!("Backup: created Cargo.toml.bkup");
+
+ // 5. Iterate crates in dependency order
+ for crate_name in &order {
+ let name = match crate_name.to_str() {
+ Some(n) => n,
+ None => {
+ eprintln_cargo_style!("invalid crate path: {}", crate_name.display());
+ abort(&toml_path);
+ }
+ };
+
+ let crate_dir = workspace_root.join(crate_name);
+
+ // 5a. Publish (capture output to check for warnings)
+ println_cargo_style!("Publish: {}", name);
+ let output = run_cmd_capture_with_dir("cargo publish", &crate_dir);
+ let output_str = match output {
+ Ok(o) => o,
+ Err((code, _)) => {
+ eprintln_cargo_style!("{} publish failed (exit code {})", name, code);
+ abort(&toml_path);
+ }
+ };
+
+ // Reject any warnings
+ let warnings: Vec<&str> = output_str
+ .lines()
+ .filter(|l| l.to_lowercase().contains("warning:"))
+ .collect();
+ if !warnings.is_empty() {
+ for w in &warnings {
+ eprintln_cargo_style!("warning detected: {}", w);
+ }
+ eprintln_cargo_style!(
+ "{} publish rejected due to {} warning(s)",
+ name,
+ warnings.len()
+ );
+ abort(&toml_path);
+ }
+
+ // 5b. Replace path with version in Cargo.toml
+ let content = match std::fs::read_to_string(&toml_path) {
+ Ok(c) => c,
+ Err(e) => {
+ eprintln_cargo_style!("failed to read Cargo.toml: {}", e);
+ abort(&toml_path);
+ }
+ };
+ let new_content = update_path_to_version(&content, name, &version);
+ if let Err(e) = std::fs::write(&toml_path, &new_content) {
+ eprintln_cargo_style!("failed to write Cargo.toml: {}", e);
+ abort(&toml_path);
+ }
+ println_cargo_style!("Dependency: {} path -> version \"{}\"", name, version);
+
+ // 5c. Verify workspace compiles
+ println_cargo_style!("Check: workspace");
+ if let Err(code) = run_cmd_with_dir("cargo check --workspace", &workspace_root) {
+ eprintln_cargo_style!("cargo check --workspace failed (exit code {})", code);
+ abort(&toml_path);
+ }
+
+ println_cargo_style!("Done: `{}` published", name);
+ }
+
+ println_cargo_style!("Done: all crates published successfully");
+}