Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/ci-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,24 @@ jobs:
if: always()
- run: cargo build --release --features=__test_powershell
if: always()

macos:
runs-on: macos-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
components: clippy, rustfmt
rustflags: ""
- uses: mamba-org/setup-micromamba@v2
env:
ACTIONS_STEP_DEBUG: true
- run: cargo test --no-default-features --features=__test_zsh
if: always()
- run: cargo fmt --check
if: always()
- run: cargo clippy --all-targets
if: always()
- run: cargo build --release --features=__test_zsh
if: always()
22 changes: 18 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ jobs:
- runs-on: ubuntu-latest
target: aarch64-unknown-linux-musl

- runs-on: macos-latest
target: x86_64-apple-darwin

- runs-on: macos-latest
target: aarch64-apple-darwin

steps:
- uses: actions/checkout@v4

Expand All @@ -63,8 +69,8 @@ jobs:
- name: Clean build cache
run: cargo clean

- name: Build (Windows)
if: ${{ matrix.runs-on == 'windows-latest' }}
- name: Build (Windows, macOS)
if: ${{ matrix.runs-on != 'ubuntu-latest' }}
run: cargo build --release --all-features --target=${{ matrix.target }}

- name: Build (Linux, cross compile)
Expand All @@ -80,9 +86,9 @@ jobs:
cp target/${{ matrix.target }}/release/csm.exe release/
Compress-Archive -Path release/ -DestinationPath csm-${{ github.ref_name }}-${{ matrix.target }}.zip

- name: Create a tar.gz (linux)
- name: Create a tar.gz (Linux, macOS)
id: create-tar
if: ${{ matrix.runs-on == 'ubuntu-latest' }}
if: ${{ matrix.runs-on != 'windows-latest' }}
run: |
mkdir release
cp LICENSE release/
Expand All @@ -108,6 +114,7 @@ jobs:
include:
- runs-on: windows-latest
- runs-on: ubuntu-latest
- runs-on: macos-latest
steps:
- name: Try latest release (linux)
if: ${{ matrix.runs-on == 'ubuntu-latest' }}
Expand All @@ -116,6 +123,13 @@ jobs:
tar -xvf csm-*.tar.gz
./release/csm --version

- name: Try latest release (macOS)
if: ${{ matrix.runs-on == 'macos-latest' }}
run: |
wget https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/csm-${{ github.ref_name }}-aarch64-apple-darwin.tar.gz
tar -xvf csm-*.tar.gz
./release/csm --version

- name: Try latest release (windows)
if: ${{ matrix.runs-on == 'windows-latest' }}
run: |
Expand Down
117 changes: 97 additions & 20 deletions src/micromamba/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::csmrc::Config;
use log::{debug, info};
use rustls::ClientConfig;
use rustls_platform_verifier::ConfigVerifierExt;
use std::env;
use std::error::Error;
use std::fmt;
use std::fs;
Expand Down Expand Up @@ -73,7 +74,7 @@ impl fmt::Display for DownloadError {
/// OS-target-specific: Return the final executable name
#[inline]
const fn micromamba_executable_name() -> Result<&'static str, DownloadError> {
if cfg!(target_os = "linux") {
if cfg!(any(target_os = "linux", target_os = "macos")) {
Ok("micromamba")
} else if cfg!(target_os = "windows") {
Ok("micromamba.exe")
Expand All @@ -100,29 +101,40 @@ fn csm_cache_dir(config: &Config) -> io::Result<PathBuf> {
Ok(cache)
}

/// Determine the download URL for micromamba
fn micromamba_url() -> Result<String, DownloadError> {
let os_arch = if cfg!(target_os = "linux") {
if cfg!(target_arch = "x86_64") {
"linux-64"
} else if cfg!(target_arch = "aarch64") {
"linux-aarch64"
} else {
return Err(DownloadError::IncompatibleArch);
struct OsArch {
os: &'static str,
arch: &'static str,
}

impl OsArch {
pub fn from_env() -> Self {
OsArch {
os: env::consts::OS,
arch: env::consts::ARCH,
}
} else if cfg!(target_os = "windows") {
if cfg!(target_arch = "x86_64") {
"win-64"
} else {
return Err(DownloadError::IncompatibleArch);
}

fn micromamba_url_path(&self) -> Result<&'static str, DownloadError> {
match (self.os, self.arch) {
("windows", "x86_64") => Ok("win-64"),
("windows", _) => Err(DownloadError::IncompatibleArch),
("linux", "x86_64") => Ok("linux-64"),
("linux", "aarch64") => Ok("linux-aarch64"),
("linux", _) => Err(DownloadError::IncompatibleArch),
("macos", "x86_64") => Ok("osx-64"),
("macos", "aarch64") => Ok("osx-arm64"),
("macos", _) => Err(DownloadError::IncompatibleArch),
_ => Err(DownloadError::IncompatibleOS),
}
} else {
return Err(DownloadError::IncompatibleOS);
};
}
}

/// Determine the download URL for micromamba
fn micromamba_url() -> Result<String, DownloadError> {
let os_arch = OsArch::from_env().micromamba_url_path()?;
Ok(format!(
"https://micro.mamba.pm/api/micromamba/{}/latest",
os_arch
os_arch,
))
}

Expand Down Expand Up @@ -157,7 +169,7 @@ fn write_micromamba<R: Read>(
fn find_micromamba_in_archive<'a, R: Read>(
tar_archive: &'a mut tar::Archive<R>,
) -> Result<tar::Entry<'a, R>, DownloadError> {
let archive_binary_dir = if cfg!(target_os = "linux") {
let archive_binary_dir = if cfg!(any(target_os = "linux", target_os = "macos")) {
PathBuf::from("bin")
} else if cfg!(target_os = "windows") {
PathBuf::from("Library").join("bin")
Expand Down Expand Up @@ -213,3 +225,68 @@ pub fn download_micromamba(config: &Config) -> Result<PathBuf, DownloadError> {
let entry = find_micromamba_in_archive(&mut tar_archive)?;
write_micromamba(config, entry)
}

#[cfg(test)]
mod tests {
use super::{DownloadError, OsArch};

#[test]
fn test_os_arch_micromamba_url_path() {
let green_path_cases = [
("linux", "aarch64", "linux-aarch64"),
("linux", "x86_64", "linux-64"),
("windows", "x86_64", "win-64"),
("macos", "aarch64", "osx-arm64"),
("macos", "x86_64", "osx-64"),
];
for (os, arch, expected) in green_path_cases {
let os_arch = OsArch { os, arch };
assert!(
matches!(os_arch.micromamba_url_path(), Ok(s) if s == expected),
"{}, {}",
os,
arch
);
}

let incompat_arch_cases = [
("linux", "m68k"),
("windows", "aarch64"),
("windows", "arm"),
("macos", "powerpc64"),
("macos", "powerpc"),
];
for (os, arch) in incompat_arch_cases {
let os_arch = OsArch { os, arch };
assert!(
matches!(
os_arch.micromamba_url_path(),
Err(DownloadError::IncompatibleArch),
),
"{}, {}",
os,
arch
);
}

let incompat_os_cases = [
("freebsd", "m68k"),
("openbsd", "aarch64"),
("android", "arm"),
("beos", "powerpc64"),
("haiku", "powerpc"),
];
for (os, arch) in incompat_os_cases {
let os_arch = OsArch { os, arch };
assert!(
matches!(
os_arch.micromamba_url_path(),
Err(DownloadError::IncompatibleOS),
),
"{}, {}",
os,
arch
);
}
}
}