Skip to content

Commit

Permalink
Refactor implement from_str trait for Target data
Browse files Browse the repository at this point in the history
  • Loading branch information
blaggacao committed Aug 11, 2021
1 parent 71e7c40 commit 4f7e80c
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 98 deletions.
50 changes: 25 additions & 25 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<settings::Root>, GetDeploymentDataError> {
futures_util::stream::iter(flakes).then(|flake| async move {
Expand Down Expand Up @@ -275,7 +275,7 @@ struct PromptPart<'a> {

fn print_deployment(
parts: &[(
&data::DeployFlake<'_>,
&data::Target,
data::DeployData,
data::DeployDefs,
)],
Expand Down Expand Up @@ -318,7 +318,7 @@ pub enum PromptDeploymentError {

fn prompt_deployment(
parts: &[(
&data::DeployFlake<'_>,
&data::Target,
data::DeployData,
data::DeployDefs,
)],
Expand Down Expand Up @@ -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<data::DeployFlake<'_>>,
deploy_targets: Vec<data::Target>,
data: Vec<settings::Root>,
supports_flakes: bool,
check_sigs: bool,
Expand All @@ -412,11 +412,11 @@ async fn run_deploy(
log_dir: &Option<String>,
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,
Expand All @@ -428,7 +428,7 @@ async fn run_deploy(
};

vec![(
&deploy_flake,
&deploy_target,
&data,
(node_name.as_str(), node),
(profile_name.as_str(), profile),
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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);
Expand All @@ -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,
Expand All @@ -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 {
Expand All @@ -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,
Expand Down Expand Up @@ -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}")]
Expand All @@ -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<data::DeployFlake> = deploys
.iter()
.map(|f| data::parse_flake(f.as_str()))
.collect::<Result<Vec<data::DeployFlake>, data::ParseFlakeError>>()?;
let deploy_targets: Vec<data::Target> = deploys
.into_iter()
.map(|f| f.parse::<data::Target>())
.collect::<Result<Vec<data::Target>, data::ParseTargetError>>()?;

let cmd_overrides = data::CmdOverrides {
ssh_user: opts.ssh_user,
Expand All @@ -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,
Expand Down
149 changes: 76 additions & 73 deletions src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,144 +10,147 @@ 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<String>,
pub profile: Option<String>,
}

#[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<DeployFlake, ParseFlakeError> {
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<String> = None;
let mut profile: Option<String> = 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<Self, Self::Err> {
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<String> = None;
let mut profile: Option<String> = None;

for entry in first_child.children_with_tokens() {
let x: Option<String> = 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<String> = 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::<Target>().unwrap(),
Target {
repo: "../deploy/examples/system",
node: None,
profile: None,
}
);

assert_eq!(
parse_flake("../deploy/examples/system#").unwrap(),
DeployFlake {
"../deploy/examples/system#".parse::<Target>().unwrap(),
Target {
repo: "../deploy/examples/system",
node: None,
profile: None,
}
);

assert_eq!(
parse_flake("../deploy/examples/system#computer.\"something.nix\"").unwrap(),
DeployFlake {
"../deploy/examples/system#computer.\"something.nix\"".parse::<Target>().unwrap(),
Target {
repo: "../deploy/examples/system",
node: Some("computer".to_string()),
profile: Some("something.nix".to_string()),
}
);

assert_eq!(
parse_flake("../deploy/examples/system#\"example.com\".system").unwrap(),
DeployFlake {
"../deploy/examples/system#\"example.com\".system".parse::<Target>().unwrap(),
Target {
repo: "../deploy/examples/system",
node: Some("example.com".to_string()),
profile: Some("system".to_string()),
}
);

assert_eq!(
parse_flake("../deploy/examples/system#example").unwrap(),
DeployFlake {
"../deploy/examples/system#example".parse::<Target>().unwrap(),
Target {
repo: "../deploy/examples/system",
node: Some("example".to_string()),
profile: None
}
);

assert_eq!(
parse_flake("../deploy/examples/system#example.system").unwrap(),
DeployFlake {
"../deploy/examples/system#example.system".parse::<Target>().unwrap(),
Target {
repo: "../deploy/examples/system",
node: Some("example".to_string()),
profile: Some("system".to_string())
}
);

assert_eq!(
parse_flake("../deploy/examples/system").unwrap(),
DeployFlake {
"../deploy/examples/system".parse::<Target>().unwrap(),
Target {
repo: "../deploy/examples/system",
node: None,
profile: None,
Expand Down

0 comments on commit 4f7e80c

Please sign in to comment.