diff --git a/src/cli.rs b/src/cli.rs index 0491a658..d53a6ac9 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -171,7 +171,7 @@ pub enum GetDeploymentDataError { /// Evaluates the Nix in the given `repo` and return the processed Data from it async fn get_deployment_data( supports_flakes: bool, - flakes: &[data::DeployFlake<'_>], + flakes: &[data::Target], extra_build_args: &[String], ) -> Result, GetDeploymentDataError> { futures_util::stream::iter(flakes).then(|flake| async move { @@ -275,7 +275,7 @@ struct PromptPart<'a> { fn print_deployment( parts: &[( - &data::DeployFlake<'_>, + &data::Target, data::DeployData, data::DeployDefs, )], @@ -318,7 +318,7 @@ pub enum PromptDeploymentError { fn prompt_deployment( parts: &[( - &data::DeployFlake<'_>, + &data::Target, data::DeployData, data::DeployDefs, )], @@ -391,14 +391,14 @@ pub enum RunDeployError { } type ToDeploy<'a> = Vec<( - &'a data::DeployFlake<'a>, + &'a data::Target, &'a settings::Root, (&'a str, &'a settings::Node), (&'a str, &'a settings::Profile), )>; async fn run_deploy( - deploy_flakes: Vec>, + deploy_targets: Vec, data: Vec, supports_flakes: bool, check_sigs: bool, @@ -412,11 +412,11 @@ async fn run_deploy( log_dir: &Option, rollback_succeeded: bool, ) -> Result<(), RunDeployError> { - let to_deploy: ToDeploy = deploy_flakes + let to_deploy: ToDeploy = deploy_targets .iter() .zip(&data) - .map(|(deploy_flake, data)| { - let to_deploys: ToDeploy = match (&deploy_flake.node, &deploy_flake.profile) { + .map(|(deploy_target, data)| { + let to_deploys: ToDeploy = match (&deploy_target.node, &deploy_target.profile) { (Some(node_name), Some(profile_name)) => { let node = match data.nodes.get(node_name) { Some(x) => x, @@ -428,7 +428,7 @@ async fn run_deploy( }; vec![( - &deploy_flake, + &deploy_target, &data, (node_name.as_str(), node), (profile_name.as_str(), profile), @@ -464,7 +464,7 @@ async fn run_deploy( profiles_list .into_iter() - .map(|x| (deploy_flake, data, (node_name.as_str(), node), x)) + .map(|x| (deploy_target, data, (node_name.as_str(), node), x)) .collect() } (None, None) => { @@ -495,7 +495,7 @@ async fn run_deploy( let ll: ToDeploy = profiles_list .into_iter() - .map(|x| (deploy_flake, data, (node_name.as_str(), node), x)) + .map(|x| (deploy_target, data, (node_name.as_str(), node), x)) .collect(); l.extend(ll); @@ -513,12 +513,12 @@ async fn run_deploy( .collect(); let mut parts: Vec<( - &data::DeployFlake<'_>, + &data::Target, data::DeployData, data::DeployDefs, )> = Vec::new(); - for (deploy_flake, data, (node_name, node), (profile_name, profile)) in to_deploy { + for (deploy_target, data, (node_name, node), (profile_name, profile)) in to_deploy { let deploy_data = data::make_deploy_data( &data.generic_settings, node, @@ -532,7 +532,7 @@ async fn run_deploy( let deploy_defs = deploy_data.defs()?; - parts.push((deploy_flake, deploy_data, deploy_defs)); + parts.push((deploy_target, deploy_data, deploy_defs)); } if interactive { @@ -541,11 +541,11 @@ async fn run_deploy( print_deployment(&parts[..])?; } - for (deploy_flake, deploy_data, deploy_defs) in &parts { + for (deploy_target, deploy_data, deploy_defs) in &parts { deploy::push::push_profile(deploy::push::PushProfileData { supports_flakes, check_sigs, - repo: deploy_flake.repo, + repo: &deploy_target.repo, deploy_data: &deploy_data, deploy_defs: &deploy_defs, keep_result, @@ -600,7 +600,7 @@ pub enum RunError { #[error("Failed to evaluate deployment data: {0}")] GetDeploymentData(#[from] GetDeploymentDataError), #[error("Error parsing flake: {0}")] - ParseFlake(#[from] data::ParseFlakeError), + ParseFlake(#[from] data::ParseTargetError), #[error("Error initiating logger: {0}")] Logger(#[from] flexi_logger::FlexiLoggerError), #[error("{0}")] @@ -624,10 +624,10 @@ pub async fn run(args: Option<&ArgMatches>) -> Result<(), RunError> { .targets .unwrap_or_else(|| vec![opts.clone().target.unwrap_or(".".to_string())]); - let deploy_flakes: Vec = deploys - .iter() - .map(|f| data::parse_flake(f.as_str())) - .collect::, data::ParseFlakeError>>()?; + let deploy_targets: Vec = deploys + .into_iter() + .map(|f| f.parse::()) + .collect::, data::ParseTargetError>>()?; let cmd_overrides = data::CmdOverrides { ssh_user: opts.ssh_user, @@ -649,14 +649,14 @@ pub async fn run(args: Option<&ArgMatches>) -> Result<(), RunError> { } if !opts.skip_checks { - for deploy_flake in deploy_flakes.iter() { - check_deployment(supports_flakes, deploy_flake.repo, &opts.extra_build_args).await?; + for deploy_target in deploy_targets.iter() { + check_deployment(supports_flakes, &deploy_target.repo, &opts.extra_build_args).await?; } } let result_path = opts.result_path.as_deref(); - let data = get_deployment_data(supports_flakes, &deploy_flakes, &opts.extra_build_args).await?; + let data = get_deployment_data(supports_flakes, &deploy_targets, &opts.extra_build_args).await?; run_deploy( - deploy_flakes, + deploy_targets, data, supports_flakes, opts.checksigs, diff --git a/src/data.rs b/src/data.rs index 86e1b6cd..78154049 100644 --- a/src/data.rs +++ b/src/data.rs @@ -10,90 +10,93 @@ use thiserror::Error; use crate::settings; #[derive(PartialEq, Debug)] -pub struct DeployFlake<'a> { - pub repo: &'a str, +pub struct Target { + pub repo: String, pub node: Option, pub profile: Option, } #[derive(Error, Debug)] -pub enum ParseFlakeError { +pub enum ParseTargetError { #[error("The given path was too long, did you mean to put something in quotes?")] PathTooLong, #[error("Unrecognized node or token encountered")] Unrecognized, } - -pub fn parse_flake(flake: &str) -> Result { - let flake_fragment_start = flake.find('#'); - let (repo, maybe_fragment) = match flake_fragment_start { - Some(s) => (&flake[..s], Some(&flake[s + 1..])), - None => (flake, None), - }; - - let mut node: Option = None; - let mut profile: Option = None; - - if let Some(fragment) = maybe_fragment { - let ast = rnix::parse(fragment); - - let first_child = match ast.root().node().first_child() { - Some(x) => x, - None => { - return Ok(DeployFlake { - repo, - node: None, - profile: None, - }) - } +impl std::str::FromStr for Target { + type Err = ParseTargetError; + + fn from_str(s: &str) -> Result { + let flake_fragment_start = s.find('#'); + let (repo, maybe_fragment) = match flake_fragment_start { + Some(i) => (s[..i].to_string(), Some(&s[i + 1..])), + None => (s.to_string(), None), }; - let mut node_over = false; + let mut node: Option = None; + let mut profile: Option = None; - for entry in first_child.children_with_tokens() { - let x: Option = match (entry.kind(), node_over) { - (TOKEN_DOT, false) => { - node_over = true; - None - } - (TOKEN_DOT, true) => { - return Err(ParseFlakeError::PathTooLong); - } - (NODE_IDENT, _) => Some(entry.into_node().unwrap().text().to_string()), - (TOKEN_IDENT, _) => Some(entry.into_token().unwrap().text().to_string()), - (NODE_STRING, _) => { - let c = entry - .into_node() - .unwrap() - .children_with_tokens() - .nth(1) - .unwrap(); - - Some(c.into_token().unwrap().text().to_string()) + if let Some(fragment) = maybe_fragment { + let ast = rnix::parse(fragment); + + let first_child = match ast.root().node().first_child() { + Some(x) => x, + None => { + return Ok(Target { + repo, + node: None, + profile: None, + }) } - _ => return Err(ParseFlakeError::Unrecognized), }; - if !node_over { - node = x; - } else { - profile = x; + let mut node_over = false; + + for entry in first_child.children_with_tokens() { + let x: Option = match (entry.kind(), node_over) { + (TOKEN_DOT, false) => { + node_over = true; + None + } + (TOKEN_DOT, true) => { + return Err(ParseTargetError::PathTooLong); + } + (NODE_IDENT, _) => Some(entry.into_node().unwrap().text().to_string()), + (TOKEN_IDENT, _) => Some(entry.into_token().unwrap().text().to_string()), + (NODE_STRING, _) => { + let c = entry + .into_node() + .unwrap() + .children_with_tokens() + .nth(1) + .unwrap(); + + Some(c.into_token().unwrap().text().to_string()) + } + _ => return Err(ParseTargetError::Unrecognized), + }; + + if !node_over { + node = x; + } else { + profile = x; + } } } - } - Ok(DeployFlake { - repo, - node, - profile, - }) + Ok(Target { + repo, + node, + profile, + }) + } } #[test] -fn test_parse_flake() { +fn test_deploy_target_from_str() { assert_eq!( - parse_flake("../deploy/examples/system").unwrap(), - DeployFlake { + "../deploy/examples/system".parse::().unwrap(), + Target { repo: "../deploy/examples/system", node: None, profile: None, @@ -101,8 +104,8 @@ fn test_parse_flake() { ); assert_eq!( - parse_flake("../deploy/examples/system#").unwrap(), - DeployFlake { + "../deploy/examples/system#".parse::().unwrap(), + Target { repo: "../deploy/examples/system", node: None, profile: None, @@ -110,8 +113,8 @@ fn test_parse_flake() { ); assert_eq!( - parse_flake("../deploy/examples/system#computer.\"something.nix\"").unwrap(), - DeployFlake { + "../deploy/examples/system#computer.\"something.nix\"".parse::().unwrap(), + Target { repo: "../deploy/examples/system", node: Some("computer".to_string()), profile: Some("something.nix".to_string()), @@ -119,8 +122,8 @@ fn test_parse_flake() { ); assert_eq!( - parse_flake("../deploy/examples/system#\"example.com\".system").unwrap(), - DeployFlake { + "../deploy/examples/system#\"example.com\".system".parse::().unwrap(), + Target { repo: "../deploy/examples/system", node: Some("example.com".to_string()), profile: Some("system".to_string()), @@ -128,8 +131,8 @@ fn test_parse_flake() { ); assert_eq!( - parse_flake("../deploy/examples/system#example").unwrap(), - DeployFlake { + "../deploy/examples/system#example".parse::().unwrap(), + Target { repo: "../deploy/examples/system", node: Some("example".to_string()), profile: None @@ -137,8 +140,8 @@ fn test_parse_flake() { ); assert_eq!( - parse_flake("../deploy/examples/system#example.system").unwrap(), - DeployFlake { + "../deploy/examples/system#example.system".parse::().unwrap(), + Target { repo: "../deploy/examples/system", node: Some("example".to_string()), profile: Some("system".to_string()) @@ -146,8 +149,8 @@ fn test_parse_flake() { ); assert_eq!( - parse_flake("../deploy/examples/system").unwrap(), - DeployFlake { + "../deploy/examples/system".parse::().unwrap(), + Target { repo: "../deploy/examples/system", node: None, profile: None,