-
-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathbuild.rs
More file actions
120 lines (98 loc) · 3.59 KB
/
build.rs
File metadata and controls
120 lines (98 loc) · 3.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use std::{
fmt::Debug,
process::{Command, Stdio},
};
use snafu::{OptionExt, ResultExt, Snafu, ensure};
use crate::{
cli::BuildArguments,
config::Config,
core::bakefile::{self, Bakefile},
utils::CommandExt,
};
#[derive(Debug, Snafu)]
pub enum Error {
#[snafu(display("failed to create bakefile"))]
CreateBakefile { source: bakefile::Error },
#[snafu(display("failed to write image manifest URIs to file"))]
WriteImageManifestUrisFile { source: std::io::Error },
#[snafu(display("failed to serialize bakefile as JSON"))]
SerializeBakefile { source: serde_json::Error },
#[snafu(display("failed to acquire stdin handle"))]
AcquireStdinHandle,
#[snafu(display("failed to run child process"))]
RunChildProcess { source: std::io::Error },
#[snafu(display("failed to spawn child process"))]
SpawnChildProcess { source: std::io::Error },
#[snafu(display(
"the docker child process failed with code {code}",
code = code.map_or("unknown".to_owned(), |c| c.to_string())
))]
ChildProcessFailed { code: Option<i32> },
#[snafu(display("encountered invalid image version, must not include any build metadata"))]
InvalidImageVersion,
}
/// This is the `boil build` command handler function.
pub fn run_command(args: Box<BuildArguments>, config: Config) -> Result<(), Error> {
// TODO (@Techassi): Parse Dockerfile instead to build the target graph
// Validation
ensure!(
args.image_version.build.is_empty(),
InvalidImageVersionSnafu
);
// Create bakefile
let bakefile = Bakefile::from_cli_args(&args, config).context(CreateBakefileSnafu)?;
let image_manifest_uris = bakefile.image_manifest_uris();
let count = image_manifest_uris.len();
// Write the image manifest URIs to file if requested
if let Some(path) = args.write_image_manifest_uris {
std::fs::write(path, image_manifest_uris.join("\n"))
.context(WriteImageManifestUrisFileSnafu)?;
}
// Output the bakefile contents if in dry-run mode
if args.dry_run {
return serde_json::to_writer_pretty(std::io::stdout(), &bakefile)
.context(SerializeBakefileSnafu);
}
// TODO (@Techassi): Invoke this directly using the Docker daemon via bollard
// or by building the image ourself.
// Finally invoke the docker buildx bake command
#[allow(deprecated)]
let mut child = Command::new("docker")
.arg("buildx")
.arg("bake")
.arg_if(args.load, "--load")
.args(args.rest)
.arg("--file")
.arg("-")
.stdin(Stdio::piped())
.spawn()
.context(SpawnChildProcessSnafu)?;
// Acquire stdin handle to pipe the bakefile as JSON to it
let stdin_handle = child.stdin.take().with_context(|| {
child
.kill()
.expect("killing the child process must succeed");
AcquireStdinHandleSnafu
})?;
serde_json::to_writer(stdin_handle, &bakefile).with_context(|_| {
child
.kill()
.expect("killing the child process must succeed");
SerializeBakefileSnafu
})?;
// Wait for successful completion of the child process
let status = child.wait().context(RunChildProcessSnafu)?;
// Return an error if the child process failed
ensure!(
status.success(),
ChildProcessFailedSnafu {
code: status.code()
}
);
println!(
"Successfully built {count} image{plural}:\n{images}",
plural = if count > 1 { "s" } else { "" },
images = image_manifest_uris.join("\n")
);
Ok(())
}