diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c87a55a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,9 @@ +# Changelog + +# master + +* supporting `rustwrap --latest` for figuring out the next version by itself +* **BREAKING** homebrew now supports arm and intel, so template variables must carry an arch postfix: + * `__URL__[arm64]` or `__URL__[x86]` + * `__SHA__[arm64]` or `__SHA__[x86]` +* fixing archive logic diff --git a/README.md b/README.md index 6a0e2bb..e9b1bbd 100644 --- a/README.md +++ b/README.md @@ -85,8 +85,8 @@ brew: class Recon < Formula desc "recon" homepage "http://www.example.com" - url "__URL__" version "__VERSION__" + url "__URL__" sha256 "__SHA__" def install diff --git a/rustwrap.yaml b/rustwrap.yaml index b799242..24bdd77 100644 --- a/rustwrap.yaml +++ b/rustwrap.yaml @@ -13,7 +13,7 @@ targets: arch: arm64 url_template: https://github.com/rusty-ferris-club/rustwrap/releases/download/v__VERSION__/rustwrap-aarch64-macos.tar.xz brew: - name: rustwrap + name: rustwrap publish: true tap: rusty-ferris-club/homebrew-tap recipe_fname: rustwrap.rb @@ -21,12 +21,17 @@ brew: class Rustwrap < Formula desc "A tool that helps wrap binary releases for easy distribution" homepage "http://github.com/rusty-ferris-club/rustwrap" - url "__URL__" version "__VERSION__" - sha256 "__SHA__" + + if Hardware::CPU.intel? + url "__URL__[x64]" + sha256 "__SHA__[x64]" + elsif Hardware::CPU.arm? + url "__URL__[arm64]" + sha256 "__SHA__[arm64]" + end def install bin.install "rustwrap" end end - diff --git a/rustwrap/src/download.rs b/rustwrap/src/download.rs index cac97db..6f5b801 100644 --- a/rustwrap/src/download.rs +++ b/rustwrap/src/download.rs @@ -178,11 +178,7 @@ impl<'a> TargetsDownloader<'a> { .iter() .map(|t| { // if we have an archive and it exists on disk return it, otherwise download it - if t.archive.is_some() - && t.archive - .as_ref() - .map(|a| Path::new(&self.out_dir.join(a)).exists()) - .unwrap_or_default() + if t.archive.is_some() && t.archive.as_ref().is_some_and(|a| Path::new(&a).exists()) { Ok(t.clone()) } else { diff --git a/rustwrap/src/providers/brew.rs b/rustwrap/src/providers/brew.rs index 0b95f63..6b5cade 100644 --- a/rustwrap/src/providers/brew.rs +++ b/rustwrap/src/providers/brew.rs @@ -21,7 +21,7 @@ const VAR_URL: &str = "__URL__"; const VAR_SHA: &str = "__SHA__"; const VAR_VERSION: &str = "__VERSION__"; -#[derive(Deserialize)] +#[derive(Deserialize, Default)] pub struct BrewOpts { pub name: String, pub tap: String, @@ -45,11 +45,14 @@ impl BrewOpts { Ok(()) } - fn recipe(&self, version: &str, url: &str, sha: &str) -> String { - self.recipe_template - .replace(VAR_VERSION, version) - .replace(VAR_URL, url) - .replace(VAR_SHA, sha) + fn recipe(&self, version: &str, target_details: Vec<(Architecture, String, String)>) -> String { + let mut out = self.recipe_template.replace(VAR_VERSION, version); + for (arch, url, sha) in target_details { + out = out + .replace(&format!("{VAR_URL}[{arch}]"), &url) + .replace(&format!("{VAR_SHA}[{arch}]"), &sha); + } + out } fn recipe_file(&self) -> String { @@ -108,28 +111,37 @@ pub fn publish( opts.validate()?; - let target = targets + let mac_targets = targets .iter() - .find(|t| t.arch == Architecture::X64 && t.platform == Platform::Darwin) - .ok_or_else(|| anyhow::anyhow!("no Intel macOS compatible target found"))?; - - // - // prep: file name, template, hash, and render the url incl. version - // then, render the recipe file (ruby source) - // - let fname = target - .archive - .as_ref() - .ok_or_else(|| anyhow::anyhow!("archive '{:?}' was not found", target))?; - - let mut file = fs::File::open(fname)?; - - let mut hasher = sha2::Sha256::new(); - io::copy(&mut file, &mut hasher)?; - let hash = hasher.finalize(); - let sha = format!("{hash:x}"); + .filter(|t| { + (t.arch == Architecture::X64 || t.arch == Architecture::ARM64) + && t.platform == Platform::Darwin + }) + .collect::>(); - let recipe = opts.recipe(version, &target.url(version), &sha); + if mac_targets.is_empty() { + anyhow::bail!("no targets available"); + } + let mut target_details = Vec::new(); + for target in mac_targets { + // + // prep: file name, template, hash, and render the url incl. version + // then, render the recipe file (ruby source) + // + let fname = target + .archive + .as_ref() + .ok_or_else(|| anyhow::anyhow!("archive '{:?}' was not found", target))?; + + let mut file = fs::File::open(fname)?; + + let mut hasher = sha2::Sha256::new(); + io::copy(&mut file, &mut hasher)?; + let hash = hasher.finalize(); + let sha = format!("{hash:x}"); + target_details.push((target.arch.clone(), target.url(version), sha)); + } + let recipe = opts.recipe(version, target_details); tracing::info!(recipe, "rendered recipe"); // diff --git a/rustwrap/src/runner.rs b/rustwrap/src/runner.rs index 6a29c7c..820b7b3 100644 --- a/rustwrap/src/runner.rs +++ b/rustwrap/src/runner.rs @@ -67,23 +67,22 @@ pub fn run(version: Option, config_file: &Path, out_path: &Path) -> Resu if let Some(brew) = config.brew.as_ref() { let prefix = format!("{} {}", crate::console::COFFEE, style("brew").green()); - let latest_v = brew::latest(brew)?; - if latest_v < target_v { + if brew.publish { + let latest_v = brew::latest(brew)?; + if latest_v < target_v { + bail!("current latest version is newer, aborting publish") + } session.console.say(&format!( "{prefix} current: {latest_v}, publishing: {target_v}..." )); - brew::publish( - &mut session, - out_path, - &target_v.to_string(), - &versioned_targets, - brew, - )?; - } else { - session - .console - .say(&format!("{prefix} discovered version ({latest_v}) higher/equal to target version ({target_v}), skipping.")); } + brew::publish( + &mut session, + out_path, + &target_v.to_string(), + &versioned_targets, + brew, + )?; } Ok(()) }