diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d6ee3548..18186add 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -22,15 +22,19 @@ jobs: - target: x86_64-unknown-linux-gnu os: ubuntu-latest output: cargo-binstall + archive: tgz - target: x86_64-apple-darwin os: macos-latest output: cargo-binstall + archive: tgz - target: armv7-unknown-linux-gnueabihf os: ubuntu-20.04 output: cargo-binstall + archive: tgz - target: x86_64-pc-windows-msvc os: windows-latest output: cargo-binstall.exe + archive: zip steps: - uses: actions/checkout@v2 @@ -93,28 +97,33 @@ jobs: command: build args: --target ${{ matrix.target }} --release - - name: Copy / Rename utility - run: | - cp target/${{ matrix.target }}/release/${{ matrix.output }} ${{ matrix.output }} - tar -czvf cargo-binstall-${{ matrix.target }}.tgz ${{ matrix.output }} + - name: Copy and rename utility + run: cp target/${{ matrix.target }}/release/${{ matrix.output }} ${{ matrix.output }} + + - name: Create archive (tgz) + if: ${{ matrix.target != 'x86_64-pc-windows-msvc' }} + run: tar -czvf cargo-binstall-${{ matrix.target }}.tgz ${{ matrix.output }} + + - name: Create archive (zip) + if: ${{ matrix.target == 'x86_64-pc-windows-msvc' }} + run: tar.exe -a -c -f cargo-binstall-${{ matrix.target }}.zip ${{ matrix.output }} - name: Upload artifacts uses: actions/upload-artifact@v1 with: - name: cargo-binstall-${{ matrix.target }}.tgz - path: cargo-binstall-${{ matrix.target }}.tgz + name: cargo-binstall-${{ matrix.target }}.${{ matrix.archive }} + path: cargo-binstall-${{ matrix.target }}.${{ matrix.archive }} - name: Upload binary to release if: ${{ startsWith(github.ref, 'refs/tags/v') }} uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} - file: cargo-binstall-${{ matrix.target }}.tgz - asset_name: cargo-binstall-${{ matrix.target }}.tgz + file: cargo-binstall-${{ matrix.target }}.${{ matrix.archive }} + asset_name: cargo-binstall-${{ matrix.target }}.${{ matrix.archive }} tag: ${{ github.ref }} overwrite: true - test: name: Test runs-on: ${{ matrix.os }} diff --git a/Cargo.lock b/Cargo.lock index d2c2dcc0..1889b065 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,10 +1,12 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] -name = "adler" -version = "0.2.3" +name = "adler32" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" [[package]] name = "aho-corasick" @@ -88,12 +90,39 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "bytes" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" +[[package]] +name = "bzip2" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.10+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17fa3d1ac1ca21c5c4e36a97f3c3eb25084576f6fc47bf0139c1123434216c6c" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "cargo-binstall" version = "0.1.0" @@ -120,6 +149,7 @@ dependencies = [ "tinytemplate", "tokio", "xz2", + "zip", ] [[package]] @@ -338,11 +368,11 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.19" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7411863d55df97a419aa64cb4d2f167103ea9d767e2c54a1868b7ac3f6b47129" +checksum = "2cfff41391129e0a856d6d822600b8d71179d46879e310417eb9c762eb178b42" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", "crc32fast", "libc", "miniz_oxide", @@ -838,12 +868,11 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.4.3" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" +checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" dependencies = [ - "adler", - "autocfg", + "adler32", ] [[package]] @@ -1541,6 +1570,26 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "thiserror" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "1.0.1" @@ -1952,3 +2001,17 @@ checksum = "c179869f34fc7c01830d3ce7ea2086bc3a07e0d35289b667d0a8bf910258926c" dependencies = [ "lzma-sys", ] + +[[package]] +name = "zip" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8264fcea9b7a036a4a5103d7153e988dbc2ebbafb34f68a3c2d404b6b82d74b6" +dependencies = [ + "byteorder", + "bzip2", + "crc32fast", + "flate2", + "thiserror", + "time", +] diff --git a/Cargo.toml b/Cargo.toml index 3eca536f..9743ea9f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,11 @@ license = "GPL-3.0" [package.metadata.binstall] -pkg-url = "{ repo }/releases/download/v{ version }/{ name }-{ target }.tgz" +pkg-url = "{ repo }/releases/download/v{ version }/{ name }-{ target }.{ format }" bin-dir = "{ bin }{ format }" +[package.metadata.binstall.overrides.x86_64-pc-windows-msvc] +pkg-fmt = "zip" [dependencies] crates_io_api = "0.6.1" @@ -25,7 +27,7 @@ simplelog = "0.9.0" anyhow = "1.0.40" reqwest = "0.10.10" tempdir = "0.3.7" -flate2 = "1.0.19" +flate2 = "1.0.14" tar = "0.4.30" cargo_toml = "0.8.1" serde = { version = "1.0.119", features = [ "derive" ] } @@ -36,6 +38,7 @@ serde_derive = "1.0.118" crates-index = "0.16.2" semver = "0.11.0" xz2 = "0.1.6" +zip = "0.5.11" [dev-dependencies] env_logger = "0.8.2" diff --git a/README.md b/README.md index de8f5aab..eae7f1c0 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ yes - [x] Tgz - [x] Txz - [x] Tar + - [x] Zip - [x] Bin - Extraction / Transformation - [x] Extract from subdirectory in archive (ie. support archives with platform or target subdirectories) @@ -79,12 +80,18 @@ Template variables use the format `{ VAR }` where `VAR` is the name of the varia - `bin` is the name of a specific binary, inferred from the crate configuration - `target` is the rust target name (defaults to your architecture, but can be overridden using the `--target` command line option if required(). +Package format can be overridden on a per-target basis, for example, if your `x86_64-pc-windows-msvc` builds use `zip` archives this can be set via: + +``` +[package.metadata.binstall.overrides.x86_64-pc-windows-msvc] +pkg-fmt = "zip" +``` ### Defaults By default `binstall` is setup to work with github releases, and expects to find: -- an archive named `{ name }-{ target }-v{ version }.tgz` +- an archive named `{ name }-{ target }-v{ version }.{ format }` - so that this does not overwrite different targets or versions when manually downloaded - located at `{ repo }/releases/download/v{ version }/` - compatible with github tags / releases diff --git a/src/helpers.rs b/src/helpers.rs index c2f019b8..bc1f3479 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -7,7 +7,7 @@ use cargo_toml::{Manifest}; use flate2::read::GzDecoder; use tar::Archive; use xz2::read::XzDecoder; - +use zip::read::ZipArchive; use crate::{Meta}; @@ -77,6 +77,15 @@ pub fn extract, P: AsRef>(source: S, fmt: PkgFmt, path: P) txz.unpack(path)?; }, + PkgFmt::Zip => { + // Extract to install dir + debug!("Decompressing from archive '{:?}' to `{:?}`", source.as_ref(), path.as_ref()); + + let dat = std::fs::File::open(source)?; + let mut zip = ZipArchive::new(dat)?; + + zip.extract(path)?; + }, PkgFmt::Bin => { debug!("Copying data from archive '{:?}' to `{:?}`", source.as_ref(), path.as_ref()); // Copy to install dir diff --git a/src/lib.rs b/src/lib.rs index 55271832..01faa24b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,6 @@ + +use std::collections::HashMap; + use serde::{Serialize, Deserialize}; use strum_macros::{Display, EnumString, EnumVariantNames}; use tinytemplate::TinyTemplate; @@ -21,6 +24,7 @@ pub const DEFAULT_BIN_PATH: &'static str = "{ name }-{ target }-v{ version }/{ b /// Binary format enumeration +/// This defaults to .zip on windows and .tgz on all other platforms #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] #[derive(Display, EnumString, EnumVariantNames)] #[strum(serialize_all = "snake_case")] @@ -32,6 +36,8 @@ pub enum PkgFmt { Tgz, /// Download format is TAR + XZ Txz, + /// Download format is Zip + Zip, /// Download format is raw / binary Bin, } @@ -68,6 +74,9 @@ pub struct PkgMeta { /// Public key for package verification (base64 encoded) pub pub_key: Option, + + /// Target specific overrides + pub overrides: HashMap, } impl Default for PkgMeta { @@ -77,10 +86,39 @@ impl Default for PkgMeta { pkg_fmt: PkgFmt::default(), bin_dir: DEFAULT_BIN_PATH.to_string(), pub_key: None, + overrides: HashMap::new(), } } } +impl PkgMeta { + /// Merge configuration overrides into object + pub fn merge(&mut self, pkg_override: &PkgOverride) { + if let Some(o) = pkg_override.pkg_fmt { + self.pkg_fmt = o; + } + } +} + +/// Target specific overrides for binary installation +/// +/// Exposed via `[package.metadata.TARGET]` in `Cargo.toml` +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case", default)] +pub struct PkgOverride { + /// Format for package downloads + pub pkg_fmt: Option, +} + +impl Default for PkgOverride { + fn default() -> Self { + Self { + pkg_fmt: None, + } + } +} + + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub struct BinMeta { diff --git a/src/main.rs b/src/main.rs index a3dab985..e232eee6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -97,11 +97,18 @@ async fn main() -> Result<(), anyhow::Error> { let manifest = load_manifest_path(manifest_path.join("Cargo.toml"))?; let package = manifest.package.unwrap(); - let (meta, binaries) = ( + let (mut meta, binaries) = ( package.metadata.map(|m| m.binstall ).flatten().unwrap_or(PkgMeta::default()), manifest.bin, ); + // Merge any overrides + if let Some(o) = meta.overrides.remove(&opts.target) { + meta.merge(&o); + } + + debug!("Found metadata: {:?}", meta); + // Generate context for URL interpolation let ctx = Context { name: opts.name.clone(),