Skip to content

Commit

Permalink
Add huak python install command
Browse files Browse the repository at this point in the history
NOTE: I may want to delegate this to `huak toolchain` operations
  • Loading branch information
cnpryer committed Oct 26, 2023
1 parent 0e6a698 commit 137b90c
Show file tree
Hide file tree
Showing 15 changed files with 74 additions and 44 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
- uses: actions/setup-python@v1
# We install instead of just build for insta-cmd TODO(cnpryer)
- name: Install huak
run: cargo install --path crates/huak_cli
run: cargo install --path crates/huak-cli
- name: Test
run: cargo test --all-features

Expand Down
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/huak-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ license.workspace = true
clap = { workspace = true }
clap_complete = "4.4.1"
colored = { workspace = true }
huak-home = { version = "0.0.0", path = "../huak-home" }
huak-home = { path = "../huak-home" }
huak-package-manager = { path = "../huak-package-manager"}
huak-python-manager = { path = "../huak-python-manager" }
human-panic = { workspace = true }
# included to build PyPi Wheels (see .github/workflow/README.md)
openssl = { version = "0.10.57", features = ["vendored"], optional = true }
Expand Down
32 changes: 11 additions & 21 deletions crates/huak-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ use huak_package_manager::ops::{
};
use huak_package_manager::{
find_package_root, Config, Error as HuakError, HuakResult, InstallOptions, TerminalOptions,
Verbosity, Version, WorkspaceOptions,
Verbosity, WorkspaceOptions,
};
use huak_python_manager::RequestedVersion;
use std::{env::current_dir, path::PathBuf, process::ExitCode, str::FromStr};
use termcolor::ColorChoice;

Expand Down Expand Up @@ -174,7 +175,13 @@ enum Python {
Use {
/// A Python interpreter version number.
#[arg(required = true)]
version: PythonVersion,
version: RequestedVersion,
},
/// Install a version of Python.
Install {
/// The version of Python to install.
#[arg(required = true)]
version: RequestedVersion,
},
}

Expand Down Expand Up @@ -429,7 +436,8 @@ fn publish(config: &Config, options: &PublishOptions) -> HuakResult<()> {
fn python(command: Python, config: &Config) -> HuakResult<()> {
match command {
Python::List => ops::list_python(config),
Python::Use { version } => ops::use_python(&version.0, config),
Python::Use { version } => ops::use_python(&version.to_string(), config),
Python::Install { version } => ops::install_python(&version),
}
}

Expand Down Expand Up @@ -491,21 +499,3 @@ impl ToString for Dependency {
self.0.clone()
}
}

#[derive(Debug, Clone)]
pub struct PythonVersion(String);

impl FromStr for PythonVersion {
type Err = Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let version = Version::from_str(s).map_err(|_| {
Error::new(
HuakError::InternalError("failed to parse version".to_string()),
ExitCode::FAILURE,
)
})?;

Ok(Self(version.to_string()))
}
}
2 changes: 2 additions & 0 deletions crates/huak-package-manager/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ thiserror = { workspace = true }
toml = { version = "0.7.6", features = ["preserve_order"] }
toml_edit = "0.19.4"
regex = "1.9.5"
huak-python-manager = { path = "../huak-python-manager" }
huak-home = { path = "../huak-home" }

[dev-dependencies]
huak-dev = { path = "../huak-dev" }
Expand Down
6 changes: 6 additions & 0 deletions crates/huak-package-manager/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pub enum Error {
GlobPatternError(#[from] glob::PatternError),
#[error("a problem with huak configuration occurred: {0}")]
HuakConfigurationError(String),
#[error("a problem occurred resolving huak's home directory")]
HuakHomeNotFound,
#[error("a problem with huak's internals occurred: {0}")]
InternalError(String),
#[error("a version number could not be parsed: {0}")]
Expand All @@ -42,6 +44,10 @@ pub enum Error {
ProjectFound,
#[error("a python interpreter could not be found")]
PythonNotFound,
#[error("a problem occurred attempting to install python: {0}")]
PythonInstallError(String),
#[error("a python release could not be found: {0}")]
PythonReleaseNotFound(String),
#[error("a python environment could not be found")]
PythonEnvironmentNotFound,
#[error("a regex error occurred: {0}")]
Expand Down
2 changes: 1 addition & 1 deletion crates/huak-package-manager/src/ops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub use install::install_project_dependencies;
pub use lint::{lint_project, LintOptions};
pub use new::{new_app_project, new_lib_project};
pub use publish::{publish_project, PublishOptions};
pub use python::{list_python, use_python};
pub use python::{install_python, list_python, use_python};
pub use remove::{remove_project_dependencies, RemoveOptions};
pub use run::run_command_str;
use std::{path::PathBuf, process::Command};
Expand Down
28 changes: 28 additions & 0 deletions crates/huak-package-manager/src/ops/python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ use crate::{
active_python_env_path, directory_is_venv, venv_executables_dir_path, Config, Environment,
Error, HuakResult,
};
use huak_home::huak_home_dir;
use huak_python_manager::{
install_with_target, resolve_release, Options, RequestedVersion, Strategy,
};
use std::process::Command;
use termcolor::Color;

Expand Down Expand Up @@ -58,6 +62,30 @@ pub fn use_python(version: &str, config: &Config) -> HuakResult<()> {
config.terminal().run_command(&mut cmd)
}

pub fn install_python(version: &RequestedVersion) -> HuakResult<()> {
// Use default selection strategy to find the best match for the requested version.
let strategy = Strategy::Selection(Options {
version: Some(version.clone()),
..Default::default()
});

let Some(release) = resolve_release(&strategy) else {
return Err(Error::PythonReleaseNotFound(version.to_string()));
};

// Always install to Huak's toolchain.
let Some(target) = huak_home_dir().map(|it| {
it.join("toolchains").join(format!(
"huak-{}-{}-{}-{}",
release.kind, release.version, release.os, release.architecture
))
}) else {
return Err(Error::HuakHomeNotFound);
};

install_with_target(&release, target).map_err(|e| Error::PythonInstallError(e.to_string()))
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def get_checksum(url: str) -> str | None:
module += """\n];
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub(crate) struct Release<'a> {
pub struct Release<'a> {
pub kind: &'a str,
pub version: Version,
pub os: &'a str,
Expand Down Expand Up @@ -162,7 +162,7 @@ def get_checksum(url: str) -> str | None:
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub(crate) struct Version {
pub struct Version {
pub major: u8,
pub minor: u8,
pub patch: u8,
Expand Down
7 changes: 5 additions & 2 deletions crates/huak-python-manager/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ mod cmd {
use std::path::PathBuf;

use super::{Error, RequestedVersion};
use huak_python_manager::{install_with_target, Options, Strategy};
use anyhow::Context;
use huak_python_manager::{install_with_target, resolve_release, Options, Strategy};

pub(crate) fn install(version: RequestedVersion, target: PathBuf) -> Result<(), Error> {
println!("installing Python {version}...");
Expand All @@ -53,6 +54,8 @@ mod cmd {
..Default::default()
});

install_with_target(&strategy, target)
let release = resolve_release(&strategy).context("requested release data")?;

install_with_target(&release, target)
}
}
13 changes: 4 additions & 9 deletions crates/huak-python-manager/src/install.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
use crate::{
releases::Release,
resolve::{resolve_release, Strategy},
};
use anyhow::{bail, Context, Error, Ok}; // TODO(cnpryer): Use thiserror in library code.
use crate::releases::Release;
use anyhow::{bail, Error, Ok}; // TODO(cnpryer): Use thiserror in library code.
use sha2::{Digest, Sha256};
use std::path::PathBuf;
use tar::Archive;
use zstd::stream::read::Decoder;

pub fn install_with_target<T: Into<PathBuf>>(strategy: &Strategy, target: T) -> Result<(), Error> {
let release = resolve_release(strategy).context("requested release data")?;

let buffer = download_release(&release)?;
pub fn install_with_target<T: Into<PathBuf>>(release: &Release, target: T) -> Result<(), Error> {
let buffer = download_release(release)?;
validate_checksum(&buffer, release.checksum)?;

// TODO(cnpryer): Support more archive formats.
Expand Down
7 changes: 4 additions & 3 deletions crates/huak-python-manager/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
//!
//! ```no_run
//! use std::{str::FromStr, path::PathBuf};
//! use huak_python_manager::{Options, RequestedVersion, Strategy, install_with_target};
//! use huak_python_manager::{Options, RequestedVersion, Strategy, install_with_target, resolve_release};
//!
//!
//! // The version of the Python to install.
Expand All @@ -32,12 +32,13 @@
//! // Use selection strategy to resolve for the best matching release available.
//! let strategy = Strategy::Selection(Options { version: Some(version), kind: "cpython", os: "apple", architecture: "aarch64", build_configuration: "pgo+lto"});
//!
//! install_with_target(&strategy, target).unwrap();
//! let release = resolve_release(&strategy).unwrap();
//!
//! install_with_target(&release, target).unwrap();
//! ```
pub use crate::install::install_with_target;
pub use crate::resolve::{Options, RequestedVersion, Strategy};
pub use crate::resolve::{resolve_release, Options, RequestedVersion, Strategy};

mod install;
mod releases;
Expand Down
4 changes: 2 additions & 2 deletions crates/huak-python-manager/src/releases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ pub(crate) const RELEASES: &[Release] = &[
];

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub(crate) struct Release<'a> {
pub struct Release<'a> {
pub kind: &'a str,
pub version: Version,
pub os: &'a str,
Expand Down Expand Up @@ -513,7 +513,7 @@ impl Release<'static> {
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub(crate) struct Version {
pub struct Version {
pub major: u8,
pub minor: u8,
pub patch: u8,
Expand Down
3 changes: 2 additions & 1 deletion crates/huak-python-manager/src/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use std::{
};

/// Resolve a Python Release based on a resolution `Strategy`.
pub(crate) fn resolve_release(strategy: &Strategy) -> Option<Release<'static>> {
#[must_use]
pub fn resolve_release(strategy: &Strategy) -> Option<Release<'static>> {
match strategy {
Strategy::Latest => resolve_release_with_options(&Options::default()),
Strategy::Selection(options) => resolve_release_with_options(options),
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ repository = "https://github.com/cnpryer/huak"

[tool.maturin]
bindings = "bin"
manifest-path = "crates/huak_cli/Cargo.toml"
manifest-path = "crates/huak-cli/Cargo.toml"
module-name = "huak"
python-source = "python"
strip = true
Expand Down

0 comments on commit 137b90c

Please sign in to comment.