Skip to content
Open
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
180 changes: 97 additions & 83 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ members = [
"crates/vx-providers/hadolint",
# Jujutsu - Git-compatible DVCS
"crates/vx-providers/jj",
# Conda package manager
"crates/vx-providers/conda",
# Generic command bridge framework
"crates/vx-bridge",
# Workspace-hack crate (managed by cargo-hakari, reduces duplicate dependency compilations)
Expand Down Expand Up @@ -258,6 +260,7 @@ vx-provider-yq = { path = "crates/vx-providers/yq" }
vx-provider-starship = { path = "crates/vx-providers/starship" }
vx-provider-vcpkg = { path = "crates/vx-providers/vcpkg" }
vx-provider-jj = { path = "crates/vx-providers/jj" }
vx-provider-conda = { path = "crates/vx-providers/conda" }
vx-console = { path = "crates/vx-console" }
vx-manifest = { path = "crates/vx-manifest" }
vx-bridge = { path = "crates/vx-bridge" }
Expand Down
2 changes: 2 additions & 0 deletions crates/vx-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ vx-provider-starship = { workspace = true }
vx-provider-vcpkg = { workspace = true }
# Jujutsu - Git-compatible DVCS
vx-provider-jj = { workspace = true }
# Conda package manager
vx-provider-conda = { workspace = true }
# Bridge framework for embedded bridge binaries (MSBuild.exe etc.)
vx-bridge = { workspace = true }
clap = { workspace = true }
Expand Down
2 changes: 2 additions & 0 deletions crates/vx-cli/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ macro_rules! for_each_provider {
vcpkg,
// Jujutsu - Git-compatible DVCS
jj,
// Conda package manager
conda,
);
};
}
Expand Down
27 changes: 27 additions & 0 deletions crates/vx-providers/conda/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[package]
name = "vx-provider-conda"
version.workspace = true
edition.workspace = true
description = "Conda provider for vx - Package, dependency and environment management"
license.workspace = true
repository.workspace = true
homepage.workspace = true
authors.workspace = true
keywords.workspace = true
categories.workspace = true
rust-version.workspace = true

[dependencies]
vx-runtime = { workspace = true }
async-trait = { workspace = true }
anyhow = { workspace = true }
tracing = { workspace = true }
workspace-hack = { version = "0.1", path = "../../workspace-hack" }

[lib]
name = "vx_provider_conda"
path = "src/lib.rs"

[dev-dependencies]
tokio = { workspace = true, features = ["test-util"] }
rstest = { workspace = true }
209 changes: 209 additions & 0 deletions crates/vx-providers/conda/provider.star
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
# provider.star - Conda provider
#
# Conda ecosystem: micromamba (recommended), conda, and mamba
# for scientific computing, ML/AI, and cross-platform package management.
#
# Micromamba source: https://github.com/mamba-org/micromamba-releases
# Miniforge source: https://github.com/conda-forge/miniforge
#
# Inheritance pattern: Level 2 (custom download_url for multiple runtimes)

load("@vx//stdlib:github.star", "make_fetch_versions", "github_asset_url")
load("@vx//stdlib:platform.star", "is_windows", "exe_ext")

# ---------------------------------------------------------------------------
# Provider metadata
# ---------------------------------------------------------------------------

def name():
return "conda"

def description():
return "Conda package, dependency and environment management"

def homepage():
return "https://conda.io/"

def repository():
return "https://github.com/conda-forge/miniforge"

def license():
return "BSD-3-Clause"

def ecosystem():
return "python"

def aliases():
return ["miniforge", "miniconda"]

# ---------------------------------------------------------------------------
# Runtime definitions
# ---------------------------------------------------------------------------

runtimes = [
{
"name": "micromamba",
"executable": "micromamba",
"description": "Fast, minimal conda package manager (single binary)",
"aliases": ["umamba"],
"priority": 100,
},
{
"name": "conda",
"executable": "conda",
"description": "Conda package and environment manager (via Miniforge)",
"aliases": ["miniforge", "miniconda"],
"priority": 90,
},
{
"name": "mamba",
"executable": "mamba",
"description": "Fast conda-compatible package manager (bundled with Miniforge)",
"aliases": [],
"priority": 80,
},
]

# ---------------------------------------------------------------------------
# Permissions
# ---------------------------------------------------------------------------

permissions = {
"http": ["api.github.com", "github.com"],
"fs": [],
"exec": [],
}

# ---------------------------------------------------------------------------
# fetch_versions
# ---------------------------------------------------------------------------

# Micromamba has its own release repo
_fetch_micromamba = make_fetch_versions("mamba-org", "micromamba-releases")

# Conda and Mamba come from Miniforge
_fetch_miniforge = make_fetch_versions("conda-forge", "miniforge")

def fetch_versions(ctx, runtime_name = "micromamba"):
"""Fetch versions for the specified runtime."""
if runtime_name == "micromamba":
return _fetch_micromamba(ctx)
return _fetch_miniforge(ctx)

# ---------------------------------------------------------------------------
# download_url
# ---------------------------------------------------------------------------

def _micromamba_platform(ctx):
"""Map platform to micromamba platform string."""
os = ctx["platform"]["os"]
arch = ctx["platform"]["arch"]
platforms = {
"windows/x64": "win-64",
"macos/x64": "osx-64",
"macos/arm64": "osx-arm64",
"linux/x64": "linux-64",
"linux/arm64": "linux-aarch64",
}
return platforms.get("{}/{}".format(os, arch))

def _miniforge_filename(ctx, version):
"""Build Miniforge filename for the platform."""
os = ctx["platform"]["os"]
arch = ctx["platform"]["arch"]
files = {
"windows/x64": "Miniforge3-{}-Windows-x86_64.exe".format(version),
"macos/x64": "Miniforge3-{}-MacOSX-x86_64.sh".format(version),
"macos/arm64": "Miniforge3-{}-MacOSX-arm64.sh".format(version),
"linux/x64": "Miniforge3-{}-Linux-x86_64.sh".format(version),
"linux/arm64": "Miniforge3-{}-Linux-aarch64.sh".format(version),
}
return files.get("{}/{}".format(os, arch))

def download_url(ctx, version, runtime_name = "micromamba"):
"""Build download URL for conda ecosystem tools.

Args:
ctx: Provider context
version: Version string, e.g. "2.0.0-0"
runtime_name: Which runtime ("micromamba", "conda", "mamba")

Returns:
Download URL string, or None if platform is unsupported
"""
if runtime_name == "micromamba":
plat = _micromamba_platform(ctx)
if not plat:
return None
return github_asset_url(
"mamba-org", "micromamba-releases", version,
"micromamba-{}.tar.bz2".format(plat),
)

# conda and mamba both come from Miniforge
filename = _miniforge_filename(ctx, version)
if not filename:
return None
return github_asset_url("conda-forge", "miniforge", version, filename)

# ---------------------------------------------------------------------------
# install_layout
# ---------------------------------------------------------------------------

def install_layout(ctx, version, runtime_name = "micromamba"):
"""Describe how to extract the downloaded archive."""
os = ctx["platform"]["os"]

if runtime_name == "micromamba":
return {
"type": "archive",
"strip_prefix": "",
"executable_paths": [
"Library/bin/micromamba.exe" if os == "windows" else "bin/micromamba",
],
}

# Miniforge: conda and mamba
if runtime_name == "conda":
exe = "Scripts\\conda.exe" if os == "windows" else "bin/conda"
else:
exe = "Scripts\\mamba.exe" if os == "windows" else "bin/mamba"

return {
"type": "archive",
"executable_paths": [exe],
}

# ---------------------------------------------------------------------------
# environment
# ---------------------------------------------------------------------------

def environment(ctx, version, install_dir, runtime_name = "micromamba"):
"""Return environment variables to set for this runtime."""
if runtime_name == "micromamba":
return {
"MAMBA_ROOT_PREFIX": install_dir,
"PATH": install_dir + ("/Library/bin" if ctx["platform"]["os"] == "windows" else "/bin"),
}

return {
"CONDA_PREFIX": install_dir,
"PATH": install_dir + ("/Scripts" if ctx["platform"]["os"] == "windows" else "/bin"),
}

# ---------------------------------------------------------------------------
# constraints
# ---------------------------------------------------------------------------

constraints = [
{
"when": "*",
"recommends": [
{
"runtime": "python",
"version": ">=3.9",
"reason": "Conda environments commonly require Python",
},
],
},
]
48 changes: 48 additions & 0 deletions crates/vx-providers/conda/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//! Conda configuration and URL building

use vx_runtime::platform::Platform;
use vx_runtime::{Arch, Os};

/// Conda URL builder for consistent download URL generation
#[derive(Debug, Clone, Default)]
pub struct CondaUrlBuilder;

impl CondaUrlBuilder {
/// Generate download URL for Miniforge (Conda distribution)
///
/// Format: `https://github.com/conda-forge/miniforge/releases/download/{version}/Miniforge3-{version}-{os}-{arch}.{ext}`
pub fn conda_download_url(version: &str, platform: &Platform) -> Option<String> {
let (os_str, arch_str, ext) = match (&platform.os, &platform.arch) {
(Os::Windows, Arch::X86_64) => ("Windows", "x86_64", "exe"),
(Os::MacOS, Arch::X86_64) => ("MacOSX", "x86_64", "sh"),
(Os::MacOS, Arch::Aarch64) => ("MacOSX", "arm64", "sh"),
(Os::Linux, Arch::X86_64) => ("Linux", "x86_64", "sh"),
(Os::Linux, Arch::Aarch64) => ("Linux", "aarch64", "sh"),
_ => return None,
};

Some(format!(
"https://github.com/conda-forge/miniforge/releases/download/{}/Miniforge3-{}-{}-{}.{}",
version, version, os_str, arch_str, ext
))
}

/// Generate download URL for Micromamba
///
/// Format: `https://github.com/mamba-org/micromamba-releases/releases/download/{version}/micromamba-{platform}.tar.bz2`
pub fn micromamba_download_url(version: &str, platform: &Platform) -> Option<String> {
let platform_str = match (&platform.os, &platform.arch) {
(Os::Windows, Arch::X86_64) => "win-64",
(Os::MacOS, Arch::X86_64) => "osx-64",
(Os::MacOS, Arch::Aarch64) => "osx-arm64",
(Os::Linux, Arch::X86_64) => "linux-64",
(Os::Linux, Arch::Aarch64) => "linux-aarch64",
_ => return None,
};

Some(format!(
"https://github.com/mamba-org/micromamba-releases/releases/download/{}/micromamba-{}.tar.bz2",
version, platform_str
))
}
}
40 changes: 40 additions & 0 deletions crates/vx-providers/conda/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//! Conda provider for vx
//!
//! This crate provides the Conda provider for vx, enabling package, dependency
//! and environment management for any language, with special focus on Python
//! and scientific computing (including CUDA, PyTorch, TensorFlow).
//!
//! # Supported Runtimes
//!
//! - **`micromamba`** (Recommended) - Minimal standalone mamba, single binary
//! - `conda` - Full Conda installation (via Miniforge)
//! - `mamba` - Fast package manager (bundled with Miniforge)
//!
//! # Why Micromamba?
//!
//! Micromamba is recommended because:
//! - Single binary, no installer needed (fits vx's download → extract → use philosophy)
//! - Fast and lightweight (~10MB vs ~400MB+ for full Conda)
//! - Fully compatible with conda environments and packages
//! - Can install PyTorch, TensorFlow, CUDA, etc.
//!
//! # Example Usage
//!
//! ```bash
//! # Install micromamba
//! vx install micromamba
//!
//! # Create a conda environment with PyTorch and CUDA
//! vx micromamba create -n ml python=3.11 pytorch pytorch-cuda=12.1 -c pytorch -c nvidia
//!
//! # Run command in the environment
//! vx micromamba run -n ml python train.py
//! ```

mod config;
mod provider;
mod runtime;

pub use config::CondaUrlBuilder;
pub use provider::{CondaProvider, create_provider};
pub use runtime::{CondaRuntime, MambaRuntime, MicromambaRuntime};
Loading
Loading