aboutsummaryrefslogtreecommitdiff
path: root/src/utils/mod.rs
diff options
context:
space:
mode:
authornotgne22020-11-29 11:51:52 -0700
committernotgne22020-11-29 11:51:52 -0700
commitfa4c0a86cd608f5e98b50e8eb4b03db04a7726ce (patch)
tree2b9fead1176af0009a11ab1f6fd8e3c3c83f5093 /src/utils/mod.rs
parenta19af74789c73601871df4c1fa46d223270d0575 (diff)
Use crude Nix parsing for parsing the flake path
Diffstat (limited to '')
-rw-r--r--src/utils/mod.rs130
1 files changed, 88 insertions, 42 deletions
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,
}
);
}