diff options
author | Alexander Bantyev | 2021-02-06 01:34:01 +0300 |
---|---|---|
committer | Alexander Bantyev | 2021-02-06 02:48:57 +0300 |
commit | 80ab1d753818752405acb8d4d3f3dc11ef83f5a9 (patch) | |
tree | c39ff0dd5b6a093d969a4946c80142d82991776a /src/bin/deploy.rs | |
parent | c00e29a39df47c8cdba8c4bb43868a27f32df3b8 (diff) |
Evaluate deploy output lazily
Currently, we evaluate the `#deploy` output strictly. This means
- Longer eval times
- Extraneous evaluation errors with `--skip-checks`
- `-- --impure` even when the path we're currently deploying is pure
- etc.
With this change, evaluation happens lazily -- we only evaluate the nodes
and profiles we really need. It is only implemented for flaky Nix, and
it is on by default. To get the old behavior, one can specify
`--strict-eval`.
I have tested that this indeed dramatically increases evaluation speed
in all of our repos, and removes the need to deploy Agora with
`--impure`. Hooray!
Diffstat (limited to 'src/bin/deploy.rs')
-rw-r--r-- | src/bin/deploy.rs | 92 |
1 files changed, 70 insertions, 22 deletions
diff --git a/src/bin/deploy.rs b/src/bin/deploy.rs index caf3d4e..6da2110 100644 --- a/src/bin/deploy.rs +++ b/src/bin/deploy.rs @@ -52,6 +52,10 @@ struct Opts { #[clap(short, long)] skip_checks: bool, + /// Always evaluate deploy attribute strictly + #[clap(long)] + strict_eval: bool, + /// Override the SSH user with the given value #[clap(long)] ssh_user: Option<String>, @@ -161,38 +165,83 @@ enum GetDeploymentDataError { /// Evaluates the Nix in the given `repo` and return the processed Data from it async fn get_deployment_data( supports_flakes: bool, - repo: &str, + strict_eval: bool, + flake: &deploy::DeployFlake<'_>, extra_build_args: &[String], ) -> Result<deploy::data::Data, GetDeploymentDataError> { - info!("Evaluating flake in {}", repo); + info!("Evaluating flake in {}", flake.repo); - let mut c = match supports_flakes { - true => Command::new("nix"), - false => Command::new("nix-instantiate"), + let mut c = if supports_flakes { + Command::new("nix") + } else { + Command::new("nix-instantiate") }; - let mut build_command = match supports_flakes { - true => { - c.arg("eval") + if supports_flakes { + c + .arg("eval") .arg("--json") - .arg(format!("{}#deploy", repo)) - } - false => { - c - .arg("--strict") - .arg("--read-write-mode") - .arg("--json") - .arg("--eval") - .arg("-E") - .arg(format!("let r = import {}/.; in if builtins.isFunction r then (r {{}}).deploy else r.deploy", repo)) + .arg(format!("{}#deploy", flake.repo)); + match (&flake.node, strict_eval) { + (Some(node), false) => { + // We use --apply instead of --expr so that we don't have to deal with builtins.getFlake + c.arg("--apply"); + info!("Evaluating the flake lazily; Use --strict-eval for old behavior"); + match &flake.profile { + None => { + // Ignore all nodes but the one we're evaluating + c.arg(format!( + r#" + deploy: + (deploy // {{ + nodes = {{ + inherit (deploy.nodes) "{}"; + }}; + }}) + "#, + node + )) + } + Some(profile) => { + // Ignore all nodes and all profiles but the one we're evaluating + c.arg(format!( + r#" + deploy: + (deploy // {{ + nodes = {{ + "{0}" = deploy.nodes."{0}" // {{ + profiles = {{ + inherit (deploy.nodes."{0}".profiles) "{1}"; + }}; + }}; + }}; + }}) + "#, + node, profile + )) + } + } + } + (_, _) => { + // We need to evaluate all profiles of all nodes anyway, so just do it strictly + &c + } } + } else { + c + .arg("--strict") + .arg("--read-write-mode") + .arg("--json") + .arg("--eval") + .arg("-E") + .arg(format!("let r = import {}/.; in if builtins.isFunction r then (r {{}}).deploy else r.deploy", flake.repo)) }; for extra_arg in extra_build_args { - build_command = build_command.arg(extra_arg); + c.arg(extra_arg); } - let build_child = build_command + let build_child = c .stdout(Stdio::piped()) .spawn() .map_err(GetDeploymentDataError::NixEval)?; @@ -524,8 +573,7 @@ async fn run() -> Result<(), RunError> { check_deployment(supports_flakes, deploy_flake.repo, &opts.extra_build_args).await?; } - let data = - get_deployment_data(supports_flakes, deploy_flake.repo, &opts.extra_build_args).await?; + let data = get_deployment_data(supports_flakes, opts.strict_eval, &deploy_flake, &opts.extra_build_args).await?; let result_path = opts.result_path.as_deref(); |