Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit aff6f1f

Browse files
committedAug 26, 2021
Refactor move flake parsing into adapter file
1 parent a10cc65 commit aff6f1f

File tree

3 files changed

+173
-160
lines changed

3 files changed

+173
-160
lines changed
 

‎src/cli.rs

+5-160
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ use clap::{ArgMatches, Clap, FromArgMatches};
1010

1111
use crate as deploy;
1212

13-
use self::deploy::{data, settings};
14-
use futures_util::stream::{StreamExt, TryStreamExt};
13+
use self::deploy::{data, settings, flake};
1514
use log::{debug, error, info, warn};
1615
use serde::Serialize;
1716
use std::process::Stdio;
@@ -107,160 +106,6 @@ async fn test_flake_support() -> Result<bool, std::io::Error> {
107106
.success())
108107
}
109108

110-
#[derive(Error, Debug)]
111-
pub enum CheckDeploymentError {
112-
#[error("Failed to execute Nix checking command: {0}")]
113-
NixCheck(#[from] std::io::Error),
114-
#[error("Nix checking command resulted in a bad exit code: {0:?}")]
115-
NixCheckExit(Option<i32>),
116-
}
117-
118-
async fn check_deployment(
119-
supports_flakes: bool,
120-
repo: &str,
121-
extra_build_args: &[String],
122-
) -> Result<(), CheckDeploymentError> {
123-
info!("Running checks for flake in {}", repo);
124-
125-
let mut check_command = match supports_flakes {
126-
true => Command::new("nix"),
127-
false => Command::new("nix-build"),
128-
};
129-
130-
if supports_flakes {
131-
check_command.arg("flake").arg("check").arg(repo);
132-
} else {
133-
check_command.arg("-E")
134-
.arg("--no-out-link")
135-
.arg(format!("let r = import {}/.; x = (if builtins.isFunction r then (r {{}}) else r); in if x ? checks then x.checks.${{builtins.currentSystem}} else {{}}", repo));
136-
}
137-
138-
for extra_arg in extra_build_args {
139-
check_command.arg(extra_arg);
140-
}
141-
142-
let check_status = check_command.status().await?;
143-
144-
match check_status.code() {
145-
Some(0) => (),
146-
a => return Err(CheckDeploymentError::NixCheckExit(a)),
147-
};
148-
149-
Ok(())
150-
}
151-
152-
#[derive(Error, Debug)]
153-
pub enum GetDeploymentDataError {
154-
#[error("Failed to execute nix eval command: {0}")]
155-
NixEval(std::io::Error),
156-
#[error("Failed to read output from evaluation: {0}")]
157-
NixEvalOut(std::io::Error),
158-
#[error("Evaluation resulted in a bad exit code: {0:?}")]
159-
NixEvalExit(Option<i32>),
160-
#[error("Error converting evaluation output to utf8: {0}")]
161-
DecodeUtf8(#[from] std::string::FromUtf8Error),
162-
#[error("Error decoding the JSON from evaluation: {0}")]
163-
DecodeJson(#[from] serde_json::error::Error),
164-
#[error("Impossible happened: profile is set but node is not")]
165-
ProfileNoNode,
166-
}
167-
168-
/// Evaluates the Nix in the given `repo` and return the processed Data from it
169-
async fn get_deployment_data(
170-
supports_flakes: bool,
171-
flakes: &[data::Target],
172-
extra_build_args: &[String],
173-
) -> Result<Vec<settings::Root>, GetDeploymentDataError> {
174-
futures_util::stream::iter(flakes).then(|flake| async move {
175-
176-
info!("Evaluating flake in {}", flake.repo);
177-
178-
let mut c = if supports_flakes {
179-
Command::new("nix")
180-
} else {
181-
Command::new("nix-instantiate")
182-
};
183-
184-
if supports_flakes {
185-
c.arg("eval")
186-
.arg("--json")
187-
.arg(format!("{}#deploy", flake.repo))
188-
// We use --apply instead of --expr so that we don't have to deal with builtins.getFlake
189-
.arg("--apply");
190-
match (&flake.node, &flake.profile) {
191-
(Some(node), Some(profile)) => {
192-
// Ignore all nodes and all profiles but the one we're evaluating
193-
c.arg(format!(
194-
r#"
195-
deploy:
196-
(deploy // {{
197-
nodes = {{
198-
"{0}" = deploy.nodes."{0}" // {{
199-
profiles = {{
200-
inherit (deploy.nodes."{0}".profiles) "{1}";
201-
}};
202-
}};
203-
}};
204-
}})
205-
"#,
206-
node, profile
207-
))
208-
}
209-
(Some(node), None) => {
210-
// Ignore all nodes but the one we're evaluating
211-
c.arg(format!(
212-
r#"
213-
deploy:
214-
(deploy // {{
215-
nodes = {{
216-
inherit (deploy.nodes) "{}";
217-
}};
218-
}})
219-
"#,
220-
node
221-
))
222-
}
223-
(None, None) => {
224-
// We need to evaluate all profiles of all nodes anyway, so just do it strictly
225-
c.arg("deploy: deploy")
226-
}
227-
(None, Some(_)) => return Err(GetDeploymentDataError::ProfileNoNode),
228-
}
229-
} else {
230-
c
231-
.arg("--strict")
232-
.arg("--read-write-mode")
233-
.arg("--json")
234-
.arg("--eval")
235-
.arg("-E")
236-
.arg(format!("let r = import {}/.; in if builtins.isFunction r then (r {{}}).deploy else r.deploy", flake.repo))
237-
};
238-
239-
for extra_arg in extra_build_args {
240-
c.arg(extra_arg);
241-
}
242-
243-
let build_child = c
244-
.stdout(Stdio::piped())
245-
.spawn()
246-
.map_err(GetDeploymentDataError::NixEval)?;
247-
248-
let build_output = build_child
249-
.wait_with_output()
250-
.await
251-
.map_err(GetDeploymentDataError::NixEvalOut)?;
252-
253-
match build_output.status.code() {
254-
Some(0) => (),
255-
a => return Err(GetDeploymentDataError::NixEvalExit(a)),
256-
};
257-
258-
let data_json = String::from_utf8(build_output.stdout)?;
259-
260-
Ok(serde_json::from_str(&data_json)?)
261-
}).try_collect().await
262-
}
263-
264109
#[derive(Serialize)]
265110
struct PromptPart<'a> {
266111
user: &'a str,
@@ -591,9 +436,9 @@ pub enum RunError {
591436
#[error("Failed to test for flake support: {0}")]
592437
FlakeTest(std::io::Error),
593438
#[error("Failed to check deployment: {0}")]
594-
CheckDeployment(#[from] CheckDeploymentError),
439+
CheckDeployment(#[from] flake::CheckDeploymentError),
595440
#[error("Failed to evaluate deployment data: {0}")]
596-
GetDeploymentData(#[from] GetDeploymentDataError),
441+
GetDeploymentData(#[from] flake::GetDeploymentDataError),
597442
#[error("Error parsing flake: {0}")]
598443
ParseFlake(#[from] data::ParseTargetError),
599444
#[error("Error initiating logger: {0}")]
@@ -645,11 +490,11 @@ pub async fn run(args: Option<&ArgMatches>) -> Result<(), RunError> {
645490

646491
if !opts.skip_checks {
647492
for deploy_target in deploy_targets.iter() {
648-
check_deployment(supports_flakes, &deploy_target.repo, &opts.extra_build_args).await?;
493+
flake::check_deployment(supports_flakes, &deploy_target.repo, &opts.extra_build_args).await?;
649494
}
650495
}
651496
let result_path = opts.result_path.as_deref();
652-
let data = get_deployment_data(supports_flakes, &deploy_targets, &opts.extra_build_args).await?;
497+
let data = flake::get_deployment_data(supports_flakes, &deploy_targets, &opts.extra_build_args).await?;
653498
run_deploy(
654499
deploy_targets,
655500
data,

‎src/flake.rs

+167
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
// SPDX-FileCopyrightText: 2020 Serokell <https://serokell.io/>
2+
// SPDX-FileCopyrightText: 2021 Yannik Sander <contact@ysndr.de>
3+
//
4+
// SPDX-License-Identifier: MPL-2.0
5+
6+
use crate as deploy;
7+
8+
use self::deploy::{data, settings};
9+
use log::{error, info};
10+
use std::process::Stdio;
11+
use futures_util::stream::{StreamExt, TryStreamExt};
12+
use thiserror::Error;
13+
use tokio::process::Command;
14+
15+
#[derive(Error, Debug)]
16+
pub enum CheckDeploymentError {
17+
#[error("Failed to execute Nix checking command: {0}")]
18+
NixCheck(#[from] std::io::Error),
19+
#[error("Nix checking command resulted in a bad exit code: {0:?}")]
20+
NixCheckExit(Option<i32>),
21+
}
22+
23+
pub async fn check_deployment(
24+
supports_flakes: bool,
25+
repo: &str,
26+
extra_build_args: &[String],
27+
) -> Result<(), CheckDeploymentError> {
28+
info!("Running checks for flake in {}", repo);
29+
30+
let mut check_command = match supports_flakes {
31+
true => Command::new("nix"),
32+
false => Command::new("nix-build"),
33+
};
34+
35+
if supports_flakes {
36+
check_command.arg("flake").arg("check").arg(repo);
37+
} else {
38+
check_command.arg("-E")
39+
.arg("--no-out-link")
40+
.arg(format!("let r = import {}/.; x = (if builtins.isFunction r then (r {{}}) else r); in if x ? checks then x.checks.${{builtins.currentSystem}} else {{}}", repo));
41+
};
42+
43+
for extra_arg in extra_build_args {
44+
check_command.arg(extra_arg);
45+
}
46+
47+
let check_status = check_command.status().await?;
48+
49+
match check_status.code() {
50+
Some(0) => (),
51+
a => return Err(CheckDeploymentError::NixCheckExit(a)),
52+
};
53+
54+
Ok(())
55+
}
56+
57+
#[derive(Error, Debug)]
58+
pub enum GetDeploymentDataError {
59+
#[error("Failed to execute nix eval command: {0}")]
60+
NixEval(std::io::Error),
61+
#[error("Failed to read output from evaluation: {0}")]
62+
NixEvalOut(std::io::Error),
63+
#[error("Evaluation resulted in a bad exit code: {0:?}")]
64+
NixEvalExit(Option<i32>),
65+
#[error("Error converting evaluation output to utf8: {0}")]
66+
DecodeUtf8(#[from] std::string::FromUtf8Error),
67+
#[error("Error decoding the JSON from evaluation: {0}")]
68+
DecodeJson(#[from] serde_json::error::Error),
69+
#[error("Impossible happened: profile is set but node is not")]
70+
ProfileNoNode,
71+
}
72+
73+
/// Evaluates the Nix in the given `repo` and return the processed Data from it
74+
pub async fn get_deployment_data(
75+
supports_flakes: bool,
76+
flakes: &[data::Target],
77+
extra_build_args: &[String],
78+
) -> Result<Vec<settings::Root>, GetDeploymentDataError> {
79+
futures_util::stream::iter(flakes).then(|flake| async move {
80+
81+
info!("Evaluating flake in {}", flake.repo);
82+
83+
let mut c = if supports_flakes {
84+
Command::new("nix")
85+
} else {
86+
Command::new("nix-instantiate")
87+
};
88+
89+
if supports_flakes {
90+
c.arg("eval")
91+
.arg("--json")
92+
.arg(format!("{}#deploy", flake.repo))
93+
// We use --apply instead of --expr so that we don't have to deal with builtins.getFlake
94+
.arg("--apply");
95+
match (&flake.node, &flake.profile) {
96+
(Some(node), Some(profile)) => {
97+
// Ignore all nodes and all profiles but the one we're evaluating
98+
c.arg(format!(
99+
r#"
100+
deploy:
101+
(deploy // {{
102+
nodes = {{
103+
"{0}" = deploy.nodes."{0}" // {{
104+
profiles = {{
105+
inherit (deploy.nodes."{0}".profiles) "{1}";
106+
}};
107+
}};
108+
}};
109+
}})
110+
"#,
111+
node, profile
112+
))
113+
}
114+
(Some(node), None) => {
115+
// Ignore all nodes but the one we're evaluating
116+
c.arg(format!(
117+
r#"
118+
deploy:
119+
(deploy // {{
120+
nodes = {{
121+
inherit (deploy.nodes) "{}";
122+
}};
123+
}})
124+
"#,
125+
node
126+
))
127+
}
128+
(None, None) => {
129+
// We need to evaluate all profiles of all nodes anyway, so just do it strictly
130+
c.arg("deploy: deploy")
131+
}
132+
(None, Some(_)) => return Err(GetDeploymentDataError::ProfileNoNode),
133+
}
134+
} else {
135+
c
136+
.arg("--strict")
137+
.arg("--read-write-mode")
138+
.arg("--json")
139+
.arg("--eval")
140+
.arg("-E")
141+
.arg(format!("let r = import {}/.; in if builtins.isFunction r then (r {{}}).deploy else r.deploy", flake.repo))
142+
};
143+
144+
for extra_arg in extra_build_args {
145+
c.arg(extra_arg);
146+
}
147+
148+
let build_child = c
149+
.stdout(Stdio::piped())
150+
.spawn()
151+
.map_err(GetDeploymentDataError::NixEval)?;
152+
153+
let build_output = build_child
154+
.wait_with_output()
155+
.await
156+
.map_err(GetDeploymentDataError::NixEvalOut)?;
157+
158+
match build_output.status.code() {
159+
Some(0) => (),
160+
a => return Err(GetDeploymentDataError::NixEvalExit(a)),
161+
};
162+
163+
let data_json = String::from_utf8(build_output.stdout)?;
164+
165+
Ok(serde_json::from_str(&data_json)?)
166+
}).try_collect().await
167+
}

‎src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ pub fn init_logger(
141141

142142
pub mod settings;
143143
pub mod data;
144+
pub mod flake;
144145
pub mod deploy;
145146
pub mod push;
146147
pub mod cli;

0 commit comments

Comments
 (0)
Please sign in to comment.