mirror of
https://github.com/serokell/deploy-rs.git
synced 2024-11-25 21:13:43 +03:00
Use crude Nix parsing for parsing the flake path
This commit is contained in:
parent
a19af74789
commit
fa4c0a86cd
56
Cargo.lock
generated
56
Cargo.lock
generated
@ -44,6 +44,15 @@ version = "0.5.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
|
checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cbitset"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29b6ad25ae296159fb0da12b970b2fe179b234584d7cd294c891e2bbb284466b"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
@ -93,6 +102,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"merge",
|
"merge",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
|
"rnix",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@ -562,6 +572,34 @@ version = "0.6.18"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
|
checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rnix"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cbbea4c714e5bbf462fa4316ddf45875d8f0e28e5db81050b5f9ce99746c6863"
|
||||||
|
dependencies = [
|
||||||
|
"cbitset",
|
||||||
|
"rowan",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rowan"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ea7cadf87a9d8432e85cb4eb86bd2e765ace60c24ef86e79084dcae5d1c5a19"
|
||||||
|
dependencies = [
|
||||||
|
"rustc-hash",
|
||||||
|
"smol_str",
|
||||||
|
"text_unit",
|
||||||
|
"thin-dst",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
@ -612,6 +650,12 @@ version = "0.4.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smol_str"
|
||||||
|
version = "0.1.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6ca0f7ce3a29234210f0f4f0b56f8be2e722488b95cb522077943212da3b32eb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.3.15"
|
version = "0.3.15"
|
||||||
@ -650,6 +694,12 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "text_unit"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20431e104bfecc1a40872578dbc390e10290a0e9c35fffe3ce6f73c15a9dbfc2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
@ -659,6 +709,12 @@ dependencies = [
|
|||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thin-dst"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db3c46be180f1af9673ebb27bc1235396f61ef6965b3fe0dbb2e624deb604f0e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.21"
|
version = "1.0.21"
|
||||||
|
@ -26,6 +26,7 @@ fork = "0.1"
|
|||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
toml = "0.5"
|
toml = "0.5"
|
||||||
yn = "0.1"
|
yn = "0.1"
|
||||||
|
rnix = "0.8"
|
||||||
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
10
src/main.rs
10
src/main.rs
@ -338,7 +338,7 @@ async fn run_deploy(
|
|||||||
extra_build_args: &[String],
|
extra_build_args: &[String],
|
||||||
) -> Result<(), RunDeployError> {
|
) -> Result<(), RunDeployError> {
|
||||||
let to_deploy: Vec<((&str, &utils::data::Node), (&str, &utils::data::Profile))> =
|
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)) => {
|
(Some(node_name), Some(profile_name)) => {
|
||||||
let node = match data.nodes.get(node_name) {
|
let node = match data.nodes.get(node_name) {
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
@ -379,7 +379,7 @@ async fn run_deploy(
|
|||||||
|
|
||||||
profiles_list
|
profiles_list
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|x| ((node_name, node), x))
|
.map(|x| ((node_name.as_str(), node), x))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
(None, None) => {
|
(None, None) => {
|
||||||
@ -424,7 +424,7 @@ async fn run_deploy(
|
|||||||
|
|
||||||
let mut parts: Vec<(utils::DeployData, utils::DeployDefs)> = Vec::new();
|
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(
|
let deploy_data = utils::make_deploy_data(
|
||||||
&data.generic_settings,
|
&data.generic_settings,
|
||||||
node,
|
node,
|
||||||
@ -478,6 +478,8 @@ enum RunError {
|
|||||||
CheckDeploymentError(#[from] CheckDeploymentError),
|
CheckDeploymentError(#[from] CheckDeploymentError),
|
||||||
#[error("Failed to evaluate deployment data: {0}")]
|
#[error("Failed to evaluate deployment data: {0}")]
|
||||||
GetDeploymentDataError(#[from] GetDeploymentDataError),
|
GetDeploymentDataError(#[from] GetDeploymentDataError),
|
||||||
|
#[error("Error parsing flake: {0}")]
|
||||||
|
ParseFlakeError(#[from] utils::ParseFlakeError),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
RunDeployError(#[from] RunDeployError),
|
RunDeployError(#[from] RunDeployError),
|
||||||
}
|
}
|
||||||
@ -491,7 +493,7 @@ async fn run() -> Result<(), RunError> {
|
|||||||
|
|
||||||
let opts: Opts = Opts::parse();
|
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 {
|
let cmd_overrides = utils::CmdOverrides {
|
||||||
ssh_user: opts.ssh_user,
|
ssh_user: opts.ssh_user,
|
||||||
|
148
src/utils/mod.rs
148
src/utils/mod.rs
@ -2,6 +2,8 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use rnix::{types::*, NodeOrToken, SyntaxKind::*, SyntaxNode};
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use merge::Merge;
|
use merge::Merge;
|
||||||
@ -36,66 +38,86 @@ pub struct CmdOverrides {
|
|||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct DeployFlake<'a> {
|
pub struct DeployFlake<'a> {
|
||||||
pub repo: &'a str,
|
pub repo: &'a str,
|
||||||
pub node: Option<&'a str>,
|
pub node: Option<String>,
|
||||||
pub profile: Option<&'a str>,
|
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 flake_fragment_start = flake.find('#');
|
||||||
let (repo, maybe_fragment) = match flake_fragment_start {
|
let (repo, maybe_fragment) = match flake_fragment_start {
|
||||||
Some(s) => (&flake[..s], Some(&flake[s + 1..])),
|
Some(s) => (&flake[..s], Some(&flake[s + 1..])),
|
||||||
None => (flake, None),
|
None => (flake, None),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (node, profile) = match maybe_fragment {
|
let mut node: Option<String> = None;
|
||||||
Some(fragment) => {
|
let mut profile: Option<String> = None;
|
||||||
let fragment_profile_start = fragment.rfind('.');
|
|
||||||
|
|
||||||
match fragment_profile_start {
|
if let Some(fragment) = maybe_fragment {
|
||||||
Some(s) => (
|
let ast = rnix::parse(fragment);
|
||||||
Some(&fragment[..s]),
|
|
||||||
// Ignore the trailing `.`
|
let first_child = match ast.root().node().first_child() {
|
||||||
(if (s + 1) == fragment.len() {
|
Some(x) => x,
|
||||||
None
|
None => {
|
||||||
} else {
|
return Ok(DeployFlake {
|
||||||
Some(&fragment[s + 1..])
|
repo,
|
||||||
}),
|
node: None,
|
||||||
),
|
profile: None,
|
||||||
None => (Some(fragment), None),
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
None => (None, None),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DeployFlake {
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(DeployFlake {
|
||||||
repo,
|
repo,
|
||||||
node,
|
node,
|
||||||
profile,
|
profile,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_flake() {
|
fn test_parse_flake() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_flake("../deploy/examples/system#example"),
|
parse_flake("../deploy/examples/system").unwrap(),
|
||||||
DeployFlake {
|
|
||||||
repo: "../deploy/examples/system",
|
|
||||||
node: Some("example"),
|
|
||||||
profile: None
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
parse_flake("../deploy/examples/system#example.system"),
|
|
||||||
DeployFlake {
|
|
||||||
repo: "../deploy/examples/system",
|
|
||||||
node: Some("example"),
|
|
||||||
profile: Some("system")
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
parse_flake("../deploy/examples/system"),
|
|
||||||
DeployFlake {
|
DeployFlake {
|
||||||
repo: "../deploy/examples/system",
|
repo: "../deploy/examples/system",
|
||||||
node: None,
|
node: None,
|
||||||
@ -103,33 +125,57 @@ fn test_parse_flake() {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Trailing `.` should be ignored
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_flake("../deploy/examples/system#example."),
|
parse_flake("../deploy/examples/system#").unwrap(),
|
||||||
DeployFlake {
|
DeployFlake {
|
||||||
repo: "../deploy/examples/system",
|
repo: "../deploy/examples/system",
|
||||||
node: Some("example"),
|
node: None,
|
||||||
|
profile: None,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
parse_flake("../deploy/examples/system#computer.\"something.nix\"").unwrap(),
|
||||||
|
DeployFlake {
|
||||||
|
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 {
|
||||||
|
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 {
|
||||||
|
repo: "../deploy/examples/system",
|
||||||
|
node: Some("example".to_string()),
|
||||||
profile: None
|
profile: None
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// The last `.` should be used for splitting
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_flake("../deploy/examples/system#example.com.system"),
|
parse_flake("../deploy/examples/system#example.system").unwrap(),
|
||||||
DeployFlake {
|
DeployFlake {
|
||||||
repo: "../deploy/examples/system",
|
repo: "../deploy/examples/system",
|
||||||
node: Some("example.com"),
|
node: Some("example".to_string()),
|
||||||
profile: Some("system")
|
profile: Some("system".to_string())
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// The last `.` should be used for splitting, _and_ trailing `.` should be ignored
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_flake("../deploy/examples/system#example.com."),
|
parse_flake("../deploy/examples/system").unwrap(),
|
||||||
DeployFlake {
|
DeployFlake {
|
||||||
repo: "../deploy/examples/system",
|
repo: "../deploy/examples/system",
|
||||||
node: Some("example.com"),
|
node: None,
|
||||||
profile: None
|
profile: None,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user