Skip to content

Commit 6c12d84

Browse files
committed
allow non-flake builds with flake-enabled nix
Adds a --file option, which forces the non-flake build logic to always run, regardless of whether or not the current nix is flake-enabled. This allows using deploy-rs with repositories which do not use flakes at all but use an external source-managing tool such as niv or npins (the previous behaviour could only really support flake-based repositories with a flake-compat fallback defined in default.nix).
1 parent aa07eb0 commit 6c12d84

File tree

3 files changed

+92
-5
lines changed

3 files changed

+92
-5
lines changed

nix/tests/default.nix

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,4 +162,9 @@ in {
162162
flakes = false;
163163
deployArgs = "-s .#server";
164164
};
165+
non-flake-with-flakes = mkTest {
166+
name = "non-flake-with-flakes";
167+
flakes = true;
168+
deployArgs = "--file . --targets server";
169+
};
165170
}

src/cli.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ pub struct Opts {
3030
/// A list of flakes to deploy alternatively
3131
#[clap(long, group = "deploy")]
3232
targets: Option<Vec<String>>,
33+
/// Treat targets as files instead of flakes
34+
#[clap(short, long)]
35+
file: Option<String>,
3336
/// Check signatures when using `nix copy`
3437
#[clap(short, long)]
3538
checksigs: bool,
@@ -672,15 +675,28 @@ pub async fn run(args: Option<&ArgMatches>) -> Result<(), RunError> {
672675
error!("Cannot use both --dry-activate & --boot!");
673676
}
674677

678+
// if opts.file.is_some() && (opts.targets.is_some() || opts.target.is_some()) {
679+
// error!("When using --file, only one target is supported!")
680+
// }
681+
675682
let deploys = opts
676683
.clone()
677684
.targets
678685
.unwrap_or_else(|| vec![opts.clone().target.unwrap_or_else(|| ".".to_string())]);
679686

680-
let deploy_flakes: Vec<DeployFlake> = deploys
687+
let deploy_flakes: Vec<DeployFlake> =
688+
if let Some(file) = &opts.file {
689+
deploys
690+
.iter()
691+
.map(|f| deploy::parse_file(file.as_str(), f.as_str()))
692+
.collect::<Result<Vec<DeployFlake>, ParseFlakeError>>()?
693+
}
694+
else {
695+
deploys
681696
.iter()
682697
.map(|f| deploy::parse_flake(f.as_str()))
683-
.collect::<Result<Vec<DeployFlake>, ParseFlakeError>>()?;
698+
.collect::<Result<Vec<DeployFlake>, ParseFlakeError>>()?
699+
};
684700

685701
let cmd_overrides = deploy::CmdOverrides {
686702
ssh_user: opts.ssh_user,
@@ -700,22 +716,29 @@ pub async fn run(args: Option<&ArgMatches>) -> Result<(), RunError> {
700716
};
701717

702718
let supports_flakes = test_flake_support().await.map_err(RunError::FlakeTest)?;
719+
let do_not_want_flakes = opts.file.is_some();
703720

704721
if !supports_flakes {
705722
warn!("A Nix version without flakes support was detected, support for this is work in progress");
706723
}
707724

725+
if do_not_want_flakes {
726+
warn!("The --file option for deployments without flakes is experimental");
727+
}
728+
729+
let using_flakes = supports_flakes && !do_not_want_flakes;
730+
708731
if !opts.skip_checks {
709732
for deploy_flake in &deploy_flakes {
710-
check_deployment(supports_flakes, deploy_flake.repo, &opts.extra_build_args).await?;
733+
check_deployment(using_flakes, deploy_flake.repo, &opts.extra_build_args).await?;
711734
}
712735
}
713736
let result_path = opts.result_path.as_deref();
714-
let data = get_deployment_data(supports_flakes, &deploy_flakes, &opts.extra_build_args).await?;
737+
let data = get_deployment_data(using_flakes, &deploy_flakes, &opts.extra_build_args).await?;
715738
run_deploy(
716739
deploy_flakes,
717740
data,
718-
supports_flakes,
741+
using_flakes,
719742
opts.checksigs,
720743
opts.interactive,
721744
&cmd_overrides,

src/lib.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,65 @@ fn test_parse_flake() {
315315
);
316316
}
317317

318+
pub fn parse_file<'a>(file: &'a str, attribute: &'a str) -> Result<DeployFlake<'a>, ParseFlakeError> {
319+
let repo = file; //format!("./{file}");
320+
321+
let mut node: Option<String> = None;
322+
let mut profile: Option<String> = None;
323+
324+
let ast = rnix::parse(attribute);
325+
326+
let first_child = match ast.root().node().first_child() {
327+
Some(x) => x,
328+
None => {
329+
return Ok(DeployFlake {
330+
repo: &repo,
331+
node: None,
332+
profile: None,
333+
})
334+
}
335+
};
336+
337+
let mut node_over = false;
338+
339+
for entry in first_child.children_with_tokens() {
340+
let x: Option<String> = match (entry.kind(), node_over) {
341+
(TOKEN_DOT, false) => {
342+
node_over = true;
343+
None
344+
}
345+
(TOKEN_DOT, true) => {
346+
return Err(ParseFlakeError::PathTooLong);
347+
}
348+
(NODE_IDENT, _) => Some(entry.into_node().unwrap().text().to_string()),
349+
(TOKEN_IDENT, _) => Some(entry.into_token().unwrap().text().to_string()),
350+
(NODE_STRING, _) => {
351+
let c = entry
352+
.into_node()
353+
.unwrap()
354+
.children_with_tokens()
355+
.nth(1)
356+
.unwrap();
357+
358+
Some(c.into_token().unwrap().text().to_string())
359+
}
360+
_ => return Err(ParseFlakeError::Unrecognized),
361+
};
362+
363+
if !node_over {
364+
node = x;
365+
} else {
366+
profile = x;
367+
}
368+
}
369+
370+
Ok(DeployFlake {
371+
repo: &repo,
372+
node,
373+
profile,
374+
})
375+
}
376+
318377
#[derive(Debug, Clone)]
319378
pub struct DeployData<'a> {
320379
pub node_name: &'a str,

0 commit comments

Comments
 (0)