aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorstuebinm2025-05-04 16:04:07 +0200
committerstuebinm2025-05-04 17:05:05 +0200
commit98b947c731f4f74119e208cfe16df90181991a48 (patch)
treebf50d87ef79e1251d2f7384e078f06341af804c0
parentaa07eb05537d4cd025e2310397a6adcedfe72c76 (diff)
allow non-flake builds with flake-enabled nixnonflake-build-flag
This adds a --file option, which causes deploy-rs to always use its non-flake logic. Before this change, we would ask nix if it understood flakes, and only if not fall back to the non-flake logic. This has utility assuming one has a nix flake repository with flake-compat set up, but prevents use with alternative source-managing tools such as niv or npins if nix has the "flakes" experimental feature enabled.
-rw-r--r--src/cli.rs33
-rw-r--r--src/lib.rs59
2 files changed, 87 insertions, 5 deletions
diff --git a/src/cli.rs b/src/cli.rs
index f3bce4d..b8dc56d 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -30,6 +30,9 @@ pub struct Opts {
/// A list of flakes to deploy alternatively
#[clap(long, group = "deploy")]
targets: Option<Vec<String>>,
+ /// Treat targets as files instead of flakes
+ #[clap(short, long)]
+ file: Option<String>,
/// Check signatures when using `nix copy`
#[clap(short, long)]
checksigs: bool,
@@ -672,15 +675,28 @@ pub async fn run(args: Option<&ArgMatches>) -> Result<(), RunError> {
error!("Cannot use both --dry-activate & --boot!");
}
+ // if opts.file.is_some() && (opts.targets.is_some() || opts.target.is_some()) {
+ // error!("When using --file, only one target is supported!")
+ // }
+
let deploys = opts
.clone()
.targets
.unwrap_or_else(|| vec![opts.clone().target.unwrap_or_else(|| ".".to_string())]);
- let deploy_flakes: Vec<DeployFlake> = deploys
+ let deploy_flakes: Vec<DeployFlake> =
+ if let Some(file) = &opts.file {
+ deploys
+ .iter()
+ .map(|f| deploy::parse_file(file.as_str(), f.as_str()))
+ .collect::<Result<Vec<DeployFlake>, ParseFlakeError>>()?
+ }
+ else {
+ deploys
.iter()
.map(|f| deploy::parse_flake(f.as_str()))
- .collect::<Result<Vec<DeployFlake>, ParseFlakeError>>()?;
+ .collect::<Result<Vec<DeployFlake>, ParseFlakeError>>()?
+ };
let cmd_overrides = deploy::CmdOverrides {
ssh_user: opts.ssh_user,
@@ -700,22 +716,29 @@ pub async fn run(args: Option<&ArgMatches>) -> Result<(), RunError> {
};
let supports_flakes = test_flake_support().await.map_err(RunError::FlakeTest)?;
+ let do_not_want_flakes = opts.file.is_some();
if !supports_flakes {
warn!("A Nix version without flakes support was detected, support for this is work in progress");
}
+ if do_not_want_flakes {
+ warn!("The --file option for deployments without flakes is experimental");
+ }
+
+ let using_flakes = supports_flakes && !do_not_want_flakes;
+
if !opts.skip_checks {
for deploy_flake in &deploy_flakes {
- check_deployment(supports_flakes, deploy_flake.repo, &opts.extra_build_args).await?;
+ check_deployment(using_flakes, deploy_flake.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(using_flakes, &deploy_flakes, &opts.extra_build_args).await?;
run_deploy(
deploy_flakes,
data,
- supports_flakes,
+ using_flakes,
opts.checksigs,
opts.interactive,
&cmd_overrides,
diff --git a/src/lib.rs b/src/lib.rs
index 61fac6a..0ff9576 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -315,6 +315,65 @@ fn test_parse_flake() {
);
}
+pub fn parse_file<'a>(file: &'a str, attribute: &'a str) -> Result<DeployFlake<'a>, ParseFlakeError> {
+ let repo = file; //format!("./{file}");
+
+ let mut node: Option<String> = None;
+ let mut profile: Option<String> = None;
+
+ let ast = rnix::parse(attribute);
+
+ let first_child = match ast.root().node().first_child() {
+ Some(x) => x,
+ None => {
+ return Ok(DeployFlake {
+ repo: &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;
+ }
+ }
+
+ Ok(DeployFlake {
+ repo: &repo,
+ node,
+ profile,
+ })
+}
+
#[derive(Debug, Clone)]
pub struct DeployData<'a> {
pub node_name: &'a str,