Skip to content

Commit

Permalink
switch back to dynamic subcommand so that default case is better
Browse files Browse the repository at this point in the history
  • Loading branch information
sgpthomas committed Aug 15, 2024
1 parent 4e7c221 commit 35e2a37
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 76 deletions.
53 changes: 40 additions & 13 deletions fud2/fud-core/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::config;
use crate::exec::{plan, Driver, Request, StateRef};
use crate::run::Run;
use anyhow::{anyhow, bail};
use argh::{FromArgs, SubCommand};
use argh::{DynamicSubCommand, FromArgs};
use camino::Utf8PathBuf;
use std::fmt::Display;
use std::str::FromStr;
Expand Down Expand Up @@ -104,16 +104,34 @@ pub struct GetResource {
#[argh(subcommand, name = "list")]
pub struct ListCommand {}

pub trait FakeSubCommand: SubCommand {
pub trait FakeCliExt: DynamicSubCommand {
fn run(&self, driver: &Driver) -> anyhow::Result<()>;
}

/// no extra command
#[derive(FromArgs)]
#[argh(subcommand, name = "none")]
pub struct DefaultDynamic {}
struct EmptyCliExt {}

impl DynamicSubCommand for EmptyCliExt {
fn commands() -> &'static [&'static argh::CommandInfo] {
&[]
}

fn try_redact_arg_values(
_command_name: &[&str],
_args: &[&str],
) -> Option<Result<Vec<String>, argh::EarlyExit>> {
None
}

fn try_from_args(
_command_name: &[&str],
_args: &[&str],
) -> Option<Result<Self, argh::EarlyExit>> {
None
}
}

impl FakeSubCommand for DefaultDynamic {
impl FakeCliExt for EmptyCliExt {
fn run(&self, _driver: &Driver) -> anyhow::Result<()> {
Ok(())
}
Expand All @@ -124,7 +142,7 @@ impl FakeSubCommand for DefaultDynamic {
#[argh(subcommand)]
pub enum Subcommand<T>
where
T: FakeSubCommand,
T: FakeCliExt,
{
/// edit the configuration file
EditConfig(EditConfig),
Expand All @@ -135,14 +153,15 @@ where
/// list the available states and ops
List(ListCommand),

#[argh(dynamic)]
Extended(T),
}

#[derive(FromArgs)]
/// A generic compiler driver.
pub struct FakeArgs<T>
where
T: FakeSubCommand,
T: FakeCliExt,
{
#[argh(subcommand)]
pub sub: Option<Subcommand<T>>,
Expand Down Expand Up @@ -228,7 +247,7 @@ fn get_states_with_errors(
Ok(states)
}

fn from_states<T: FakeSubCommand>(
fn from_states<T: FakeCliExt>(
driver: &Driver,
args: &FakeArgs<T>,
) -> anyhow::Result<Vec<StateRef>> {
Expand All @@ -242,7 +261,7 @@ fn from_states<T: FakeSubCommand>(
)
}

fn to_state<T: FakeSubCommand>(
fn to_state<T: FakeCliExt>(
driver: &Driver,
args: &FakeArgs<T>,
) -> anyhow::Result<Vec<StateRef>> {
Expand All @@ -256,7 +275,7 @@ fn to_state<T: FakeSubCommand>(
)
}

fn get_request<T: FakeSubCommand>(
fn get_request<T: FakeCliExt>(
driver: &Driver,
args: &FakeArgs<T>,
) -> anyhow::Result<Request> {
Expand Down Expand Up @@ -344,7 +363,11 @@ fn get_resource(driver: &Driver, cmd: GetResource) -> anyhow::Result<()> {
}

/// Given the name of a Driver, returns a config based on that name and CLI arguments.
pub fn config_from_cli<T: FakeSubCommand>(
pub fn config_from_cli(name: &str) -> anyhow::Result<figment::Figment> {
config_from_cli_ext::<EmptyCliExt>(name)
}

pub fn config_from_cli_ext<T: FakeCliExt>(
name: &str,
) -> anyhow::Result<figment::Figment> {
let args: FakeArgs<T> = argh::from_env();
Expand All @@ -364,7 +387,11 @@ pub fn config_from_cli<T: FakeSubCommand>(
Ok(config)
}

pub fn cli<T: FakeSubCommand>(
pub fn cli(driver: &Driver, config: &figment::Figment) -> anyhow::Result<()> {
cli_ext::<EmptyCliExt>(driver, config)
}

pub fn cli_ext<T: FakeCliExt>(
driver: &Driver,
config: &figment::Figment,
) -> anyhow::Result<()> {
Expand Down
1 change: 0 additions & 1 deletion fud2/fud-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@ pub mod run;
pub mod script;
pub mod utils;

pub use cli::DefaultDynamic;
pub use exec::{Driver, DriverBuilder};
159 changes: 101 additions & 58 deletions fud2/src/cli_pyenv.rs
Original file line number Diff line number Diff line change
@@ -1,68 +1,111 @@
use std::{fs, path::Path, process::Command};
use std::{fs, path::Path, process::Command, sync::OnceLock};

use argh::FromArgs;
use fud_core::{cli::FakeSubCommand, config};
use argh::{CommandInfo, DynamicSubCommand, FromArgs};
use fud_core::{cli::FakeCliExt, config};

/// initialize a fud2 python environment
#[derive(FromArgs)]
#[argh(subcommand, name = "env")]
pub struct PyenvCommand {}

impl FakeSubCommand for PyenvCommand {
pub enum Fud2CliExt {
Pyenv(PyenvCommand),
}

impl DynamicSubCommand for Fud2CliExt {
fn commands() -> &'static [&'static CommandInfo] {
static RET: OnceLock<Vec<&'static CommandInfo>> = OnceLock::new();
RET.get_or_init(|| {
vec![&*Box::leak(Box::new(CommandInfo {
name: "env",
description: "initialize a fud2 python environment",
}))]
})
}

fn try_redact_arg_values(
command_name: &[&str],
args: &[&str],
) -> Option<Result<Vec<String>, argh::EarlyExit>> {
if let Some(&"env") = command_name.last() {
return Some(PyenvCommand::redact_arg_values(command_name, args));
}
None
}

fn try_from_args(
command_name: &[&str],
args: &[&str],
) -> Option<Result<Self, argh::EarlyExit>> {
if let Some(&"env") = command_name.last() {
return Some(
PyenvCommand::from_args(command_name, args)
.map(Fud2CliExt::Pyenv),
);
}
None
}
}

impl FakeCliExt for Fud2CliExt {
fn run(&self, driver: &fud_core::Driver) -> anyhow::Result<()> {
let data_dir = config::data_dir(&driver.name);

fs::create_dir_all(&data_dir)?;

let pyenv = data_dir.join("venv");

// create new venv
Command::new("python3")
.args(["-m", "venv"])
.arg(&pyenv)
.stdout(std::io::stdout())
.output()?;

// install flit
Command::new(pyenv.join("bin").join("pip"))
.arg("install")
.arg("flit")
.stdout(std::io::stdout())
.output()?;

// grab the location of the calyx base install
let config = config::load_config(&driver.name);
let calyx_base: String = config.extract_inner("calyx.base")?;

// install fud python library
Command::new(pyenv.join("bin").join("python"))
.args(["-m", "flit", "install"])
.current_dir(Path::new(&calyx_base).join("fud"))
.stdout(std::io::stdout())
.output()?;

// install calyx-py library
Command::new(pyenv.join("bin").join("python"))
.args(["-m", "flit", "install"])
.current_dir(Path::new(&calyx_base).join("calyx-py"))
.stdout(std::io::stdout())
.output()?;

// add python location to fud2.toml
let config_path = config::config_path(&driver.name);
let contents = fs::read_to_string(&config_path)?;
let mut toml_doc: toml_edit::DocumentMut = contents.parse()?;

toml_doc["python"] = toml_edit::value(
pyenv
.join("bin")
.join("python")
.to_string_lossy()
.to_string(),
);

fs::write(&config_path, toml_doc.to_string())?;

Ok(())
match self {
Fud2CliExt::Pyenv(_cmd) => {
let data_dir = config::data_dir(&driver.name);

fs::create_dir_all(&data_dir)?;

let pyenv = data_dir.join("venv");

// create new venv
Command::new("python3")
.args(["-m", "venv"])
.arg(&pyenv)
.stdout(std::io::stdout())
.output()?;

// install flit
Command::new(pyenv.join("bin").join("pip"))
.arg("install")
.arg("flit")
.stdout(std::io::stdout())
.output()?;

// grab the location of the calyx base install
let config = config::load_config(&driver.name);
let calyx_base: String = config.extract_inner("calyx.base")?;

// install fud python library
Command::new(pyenv.join("bin").join("python"))
.args(["-m", "flit", "install"])
.current_dir(Path::new(&calyx_base).join("fud"))
.stdout(std::io::stdout())
.output()?;

// install calyx-py library
Command::new(pyenv.join("bin").join("python"))
.args(["-m", "flit", "install"])
.current_dir(Path::new(&calyx_base).join("calyx-py"))
.stdout(std::io::stdout())
.output()?;

// add python location to fud2.toml
let config_path = config::config_path(&driver.name);
let contents = fs::read_to_string(&config_path)?;
let mut toml_doc: toml_edit::DocumentMut = contents.parse()?;

toml_doc["python"] = toml_edit::value(
pyenv
.join("bin")
.join("python")
.to_string_lossy()
.to_string(),
);

fs::write(&config_path, toml_doc.to_string())?;

Ok(())
}
}
}
}
2 changes: 1 addition & 1 deletion fud2/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mod cli_pyenv;
pub use cli_pyenv::PyenvCommand;
pub use cli_pyenv::Fud2CliExt;

use std::str::FromStr;

Expand Down
6 changes: 3 additions & 3 deletions fud2/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use fud2::PyenvCommand;
use fud2::Fud2CliExt;
use fud_core::{
cli::{self},
DriverBuilder,
Expand Down Expand Up @@ -41,13 +41,13 @@ fn main() -> anyhow::Result<()> {
}

// Get config values from cli.
let config = cli::config_from_cli::<PyenvCommand>(&bld.name)?;
let config = cli::config_from_cli_ext::<Fud2CliExt>(&bld.name)?;

#[cfg(feature = "migrate_to_scripts")]
{
bld = bld.load_plugins(&config)?;
}

let driver = bld.build();
cli::cli::<PyenvCommand>(&driver, &config)
cli::cli_ext::<Fud2CliExt>(&driver, &config)
}

0 comments on commit 35e2a37

Please sign in to comment.