aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authornotgne22020-11-29 11:51:52 -0700
committernotgne22020-11-29 11:51:52 -0700
commitfa4c0a86cd608f5e98b50e8eb4b03db04a7726ce (patch)
tree2b9fead1176af0009a11ab1f6fd8e3c3c83f5093 /src
parenta19af74789c73601871df4c1fa46d223270d0575 (diff)
Use crude Nix parsing for parsing the flake path
Diffstat (limited to 'src')
-rw-r--r--src/main.rs10
-rw-r--r--src/utils/mod.rs130
2 files changed, 94 insertions, 46 deletions
diff --git a/src/main.rs b/src/main.rs
index 544f563..be7ad40 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -338,7 +338,7 @@ async fn run_deploy(
extra_build_args: &[String],
) -> Result<(), RunDeployError> {
let to_deploy: Vec<((&str, &utils::data::Node), (&str, &utils::data::Profile))> =
- match (deploy_flake.node, deploy_flake.profile) {
+ match (&deploy_flake.node, &deploy_flake.profile) {
(Some(node_name), Some(profile_name)) => {
let node = match data.nodes.get(node_name) {
Some(x) => x,
@@ -379,7 +379,7 @@ async fn run_deploy(
profiles_list
.into_iter()
- .map(|x| ((node_name, node), x))
+ .map(|x| ((node_name.as_str(), node), x))
.collect()
}
(None, None) => {
@@ -424,7 +424,7 @@ async fn run_deploy(
let mut parts: Vec<(utils::DeployData, utils::DeployDefs)> = Vec::new();
- for ((node_name, node), (profile_name, profile)) in &to_deploy {
+ for ((node_name, node), (profile_name, profile)) in to_deploy {
let deploy_data = utils::make_deploy_data(
&data.generic_settings,
node,
@@ -478,6 +478,8 @@ enum RunError {
CheckDeploymentError(#[from] CheckDeploymentError),
#[error("Failed to evaluate deployment data: {0}")]
GetDeploymentDataError(#[from] GetDeploymentDataError),
+ #[error("Error parsing flake: {0}")]
+ ParseFlakeError(#[from] utils::ParseFlakeError),
#[error("{0}")]
RunDeployError(#[from] RunDeployError),
}
@@ -491,7 +493,7 @@ async fn run() -> Result<(), RunError> {
let opts: Opts = Opts::parse();
- let deploy_flake = utils::parse_flake(opts.flake.as_str());
+ let deploy_flake = utils::parse_flake(opts.flake.as_str())?;
let cmd_overrides = utils::CmdOverrides {
ssh_user: opts.ssh_user,
diff --git a/src/utils/mod.rs b/src/utils/mod.rs
index 4fae7a6..deea78e 100644
--- a/src/utils/mod.rs
+++ b/src/utils/mod.rs
@@ -2,6 +2,8 @@
//
// SPDX-License-Identifier: MPL-2.0
+use rnix::{types::*, NodeOrToken, SyntaxKind::*, SyntaxNode};
+
use std::path::PathBuf;
use merge::Merge;
@@ -36,100 +38,144 @@ pub struct CmdOverrides {
#[derive(PartialEq, Debug)]
pub struct DeployFlake<'a> {
pub repo: &'a str,
- pub node: Option<&'a str>,
- pub profile: Option<&'a str>,
+ pub node: Option<String>,
+ pub profile: Option<String>,
}
-pub fn parse_flake(flake: &str) -> DeployFlake {
+#[derive(Error, Debug)]
+pub enum ParseFlakeError {
+ #[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 (node, profile) = match maybe_fragment {
- Some(fragment) => {
- let fragment_profile_start = fragment.rfind('.');
-
- match fragment_profile_start {
- Some(s) => (
- Some(&fragment[..s]),
- // Ignore the trailing `.`
- (if (s + 1) == fragment.len() {
- None
- } else {
- Some(&fragment[s + 1..])
- }),
- ),
- None => (Some(fragment), 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,
+ })
+ }
+ };
+
+ 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(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())
+ }
+ _ => return Err(ParseFlakeError::Unrecognized),
+ };
+
+ if !node_over {
+ node = x;
+ } else {
+ profile = x;
}
}
- None => (None, None),
- };
+ }
- DeployFlake {
+ Ok(DeployFlake {
repo,
node,
profile,
- }
+ })
}
#[test]
fn test_parse_flake() {
assert_eq!(
- parse_flake("../deploy/examples/system#example"),
+ parse_flake("../deploy/examples/system").unwrap(),
DeployFlake {
repo: "../deploy/examples/system",
- node: Some("example"),
- profile: None
+ node: None,
+ profile: None,
}
);
assert_eq!(
- parse_flake("../deploy/examples/system#example.system"),
+ parse_flake("../deploy/examples/system#").unwrap(),
DeployFlake {
repo: "../deploy/examples/system",
- node: Some("example"),
- profile: Some("system")
+ node: None,
+ profile: None,
}
);
assert_eq!(
- parse_flake("../deploy/examples/system"),
+ parse_flake("../deploy/examples/system#computer.\"something.nix\"").unwrap(),
DeployFlake {
repo: "../deploy/examples/system",
- node: None,
- profile: None,
+ node: Some("computer".to_string()),
+ profile: Some("something.nix".to_string()),
+ }
+ );
+
+ assert_eq!(
+ parse_flake("../deploy/examples/system#\"example.com\".system").unwrap(),
+ DeployFlake {
+ repo: "../deploy/examples/system",
+ node: Some("example.com".to_string()),
+ profile: Some("system".to_string()),
}
);
- // Trailing `.` should be ignored
assert_eq!(
- parse_flake("../deploy/examples/system#example."),
+ parse_flake("../deploy/examples/system#example").unwrap(),
DeployFlake {
repo: "../deploy/examples/system",
- node: Some("example"),
+ node: Some("example".to_string()),
profile: None
}
);
- // The last `.` should be used for splitting
assert_eq!(
- parse_flake("../deploy/examples/system#example.com.system"),
+ parse_flake("../deploy/examples/system#example.system").unwrap(),
DeployFlake {
repo: "../deploy/examples/system",
- node: Some("example.com"),
- profile: Some("system")
+ node: Some("example".to_string()),
+ profile: Some("system".to_string())
}
);
- // The last `.` should be used for splitting, _and_ trailing `.` should be ignored
assert_eq!(
- parse_flake("../deploy/examples/system#example.com."),
+ parse_flake("../deploy/examples/system").unwrap(),
DeployFlake {
repo: "../deploy/examples/system",
- node: Some("example.com"),
- profile: None
+ node: None,
+ profile: None,
}
);
}