Skip to content

Commit

Permalink
Add huak_python_manager install
Browse files Browse the repository at this point in the history
  • Loading branch information
cnpryer committed Oct 15, 2023
1 parent 557a61a commit 30075f4
Show file tree
Hide file tree
Showing 11 changed files with 786 additions and 24 deletions.
656 changes: 637 additions & 19 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ license = "MIT"

[workspace.dependencies]
clap = { version = "4.4.2", features = ["cargo", "derive"] }
colored = "2.0.4"
glob = "0.3.1"
human-panic = "1.1.5"
pep440_rs = "0.3.11"
pep508_rs = "0.2.1"
tempfile = "3.7.1"
Expand Down
4 changes: 2 additions & 2 deletions crates/huak_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ license.workspace = true
[dependencies]
clap = { workspace = true }
clap_complete = "4.4.1"
colored = "2.0.4"
colored = { workspace = true }
huak_home = { version = "0.0.0", path = "../huak_home" }
huak_package_manager = { path = "../huak_package_manager"}
human-panic = "1.1.5"
human-panic = { workspace = true }
# included to build PyPi Wheels (see .github/workflow/README.md)
openssl = { version = "0.10.57", features = ["vendored"], optional = true }
termcolor = { workspace = true }
Expand Down
8 changes: 8 additions & 0 deletions crates/huak_python_manager/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@ authors.workspace = true
license.workspace = true

[dependencies]
anyhow = "1.0.75"
clap = { workspace = true }
colored = { workspace = true }
huak_home = { version = "0.0.0", path = "../huak_home" }
human-panic = { workspace = true }
reqwest = { version = "0.11.22", features = ["blocking", "json"] }
tar = "0.4.40"
tempfile = { workspace = true }
zstd = "0.13.0"

[lints]
workspace = true
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ def get_checksum(url: str) -> str | None:
module += "\n\t" + release.to_rust_string() + ","
module += """\n];
#[derive(Copy, Clone)]
pub struct Release<'a> {
pub kind: &'a str,
pub version: Version,
Expand Down Expand Up @@ -152,6 +153,7 @@ def get_checksum(url: str) -> str | None:
}
}
#[derive(Copy, Clone)]
pub struct Version {
pub major: u8,
pub minor: u8,
Expand Down
45 changes: 45 additions & 0 deletions crates/huak_python_manager/src/cli.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use crate::version::RequestedVersion;
use anyhow::Error;
use clap::{Parser, Subcommand};

/// A Python interpreter management system for Huak.
#[derive(Parser)]
#[command(version, author, about, arg_required_else_help = true)]
pub(crate) struct Cli {
#[command(subcommand)]
command: Commands,
#[arg(short, long, global = true)]
quiet: bool,
#[arg(long, global = true)]
no_color: bool,
}

impl Cli {
pub(crate) fn run(self) -> Result<(), Error> {
match self.command {
Commands::Install { version } => cmd::install(&version),
}
}
}

// List of commands.
#[derive(Subcommand)]
#[clap(rename_all = "kebab-case")]
enum Commands {
/// Install a Python interpreter.
Install {
#[arg()]
version: RequestedVersion,
},
}

mod cmd {
use super::Error;
use super::RequestedVersion;
use crate::install;
use crate::resolve::Strategy;

pub(crate) fn install(version: &RequestedVersion) -> Result<(), Error> {
install::install_to_home(version, &Strategy::Auto)
}
}
46 changes: 46 additions & 0 deletions crates/huak_python_manager/src/install.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use crate::{
resolve::{get_release, Strategy},
version::RequestedVersion,
};
use anyhow::{bail, Context, Error, Ok}; // TODO(cnpryer): Use thiserror in library code.
use huak_home::huak_home_dir;
use std::{fs::File, path::PathBuf};
use tar::Archive;
use tempfile::TempDir;
use zstd::decode_all;

pub(crate) fn install_to_home(
version: &RequestedVersion,
strategy: &Strategy,
) -> Result<(), Error> {
let release = get_release(version, strategy).context("requested release data")?;
let tmp_dir = TempDir::new()?;
let tmp_name = "tmp.tar.zst";
let tmp_path = tmp_dir.path().join(tmp_name);
let target_dir = huak_home_dir()
.context("requested huak's home directory")?
.join("bin");

download_file(release.url, &tmp_path)?;

let mut archive = File::open(tmp_path)?;
let decoded = decode_all(&mut archive)?;

let mut archive = Archive::new(decoded.as_slice());
archive.unpack(target_dir)?;

Ok(())
}

fn download_file(url: &str, path: &PathBuf) -> Result<(), Error> {
let mut response = reqwest::blocking::get(url)?;

if !response.status().is_success() {
bail!("failed to download file from {url}");
}

let mut dest_file = File::create(path)?;
response.copy_to(&mut dest_file)?;

Ok(())
}
17 changes: 14 additions & 3 deletions crates/huak_python_manager/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
use huak_home::huak_home_dir;
use clap::Parser;
use cli::Cli;
use colored::Colorize;
use human_panic::setup_panic;

mod cli;
mod install;
mod releases;
mod resolve;
mod version;

fn main() {
println!("{:?}", huak_home_dir());
println!("{:?}", releases::RELEASES[0].url);
setup_panic!();

if let Err(e) = Cli::parse().run() {
eprintln!("{}{} {}", "error".red(), ":".bold(), e);
}
}
5 changes: 5 additions & 0 deletions crates/huak_python_manager/src/releases.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! This file was generated with `generate_python_releases.py`.
#[allow(dead_code)]
#[rustfmt::skip]
pub const RELEASES: &[Release] = &[
Release::new("cpython", Version::new(3, 10, 13), "apple", "aarch64", "pgo+lto", "a2635841454295c5bc2c18740346fd8308f2a8adcce2407b87c9faf261fed29c", "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13%2B20231002-aarch64-apple-darwin-pgo%2Blto-full.tar.zst"),
Expand Down Expand Up @@ -474,6 +475,7 @@ pub const RELEASES: &[Release] = &[
Release::new("cpython", Version::new(3, 9, 10), "linux", "x86_64", "pgo", "d23017bc20b640615af8f5eab0f1bf0c9264526bcb8c2a326f4a13b21725cff1", "https://github.com/indygreg/python-build-standalone/releases/download/20220227/cpython-3.9.10%2B20220227-x86_64-unknown-linux-gnu-pgo-full.tar.zst"),
];

#[derive(Copy, Clone)]
pub struct Release<'a> {
pub kind: &'a str,
pub version: Version,
Expand All @@ -485,6 +487,7 @@ pub struct Release<'a> {
}

impl Release<'static> {
#[allow(dead_code)]
const fn new(
kind: &'static str,
version: Version,
Expand All @@ -506,13 +509,15 @@ impl Release<'static> {
}
}

#[derive(Copy, Clone)]
pub struct Version {
pub major: u8,
pub minor: u8,
pub patch: u8,
}

impl Version {
#[allow(dead_code)]
const fn new(major: u8, minor: u8, patch: u8) -> Self {
Self {
major,
Expand Down
12 changes: 12 additions & 0 deletions crates/huak_python_manager/src/resolve.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use crate::{releases::Release, version::RequestedVersion};

pub(crate) fn get_release(
_version: &RequestedVersion,
_strategy: &Strategy,
) -> Option<Release<'static>> {
todo!()
}

pub(crate) enum Strategy {
Auto,
}
13 changes: 13 additions & 0 deletions crates/huak_python_manager/src/version.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use anyhow::Error;
use std::str::FromStr; // TODO(cnpryer): Library code should use thiserror

#[derive(Debug, Clone)]
pub struct RequestedVersion(String); // TODO(cnpryer)

impl FromStr for RequestedVersion {
type Err = Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(RequestedVersion(s.to_owned()))
}
}

0 comments on commit 30075f4

Please sign in to comment.