Skip to content

Commit

Permalink
make dockerfile build into a struct
Browse files Browse the repository at this point in the history
  • Loading branch information
Emilgardis committed Apr 5, 2022
1 parent 8d11d1d commit 8d7a435
Showing 1 changed file with 76 additions and 17 deletions.
93 changes: 76 additions & 17 deletions src/docker.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::io::Read;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::process::{Command, ExitStatus};
use std::{env, fs};
Expand Down Expand Up @@ -259,14 +259,20 @@ pub fn run(
.run_and_get_status(verbose)
}

/// (Assemble) and return the image to execute inside
pub fn image_assemble(
verbose: bool,
config: &Config,
target: &Target,
host_root: &Path,
) -> Result<String> {
if let Some(dockerfile) = config.dockerfile(target)? {
#[derive(Debug, PartialEq)]
pub enum Dockerfile<'a> {
File {
path: &'a str,
context: Option<&'a str>,
name: Option<&'a str>,
},
Stdin {
content: &'a str,
},
}

impl<'a> Dockerfile<'a> {
pub fn build(&self, verbose: bool, host_root: &Path) -> Result<String> {
let mut docker_build = docker_command("build")?;
docker_build.current_dir(host_root);
docker_build.env("DOCKER_SCAN_SUGGEST", "false");
Expand All @@ -277,34 +283,87 @@ pub fn image_assemble(

docker_build.args(["--iidfile".as_ref(), iidfile_path.as_os_str()]);

docker_build.args(["--file", &dockerfile]);

if let Some(image) = config.image(target)? {
if let Some(image) = self.image_name() {
docker_build.args(["--tag", &image]);
};

if let Some(context) = config.dockerfile_context(target)? {
if let Some(context) = self.context() {
docker_build.arg(&context);
} else {
// This `.` is techically the host_root, not cwd
// When using Dockerfile::Stdin, this will be ignored by docker.
docker_build.arg(".");
}

match self {
Dockerfile::File { path, .. } => {
docker_build.args(["--file", &path]);
}
Dockerfile::Stdin { content } => {
// XXX: Ugly hack to circumvent platform issues. we could use echo
let stdin_path = tempfile::NamedTempFile::new()
.wrap_err("could not create a temporary file")?
.into_temp_path();
let mut file = std::fs::File::options().write(true).open(&stdin_path)?;
file.write_all(content.as_bytes())?;
file.sync_data()?;
docker_build.arg("-").stdin(file);
}
}

docker_build
.run(verbose)
.wrap_err_with(|| format!("could not build dockerfile `{dockerfile}`"))?;
.wrap_err_with(|| format!("build failed"))?;

let image_name = if let Some(image) = config.image(target)? {
image
let image_name = if let Some(image) = self.image_name() {
image.to_owned()
} else {
let mut image_name = String::new();
std::fs::File::open(&iidfile_path)?.read_to_string(&mut image_name)?;
image_name
};

if image_name.is_empty() {
eyre::bail!("no image returned from docker build")
}
std::fs::remove_file(iidfile_path)?;
Ok(image_name)
}

fn image_name(&self) -> Option<&'a str> {
match self {
Dockerfile::File {
name: Some(name), ..
} => Some(name),
_ => None,
}
}

fn context(&self) -> Option<&'a str> {
match self {
Dockerfile::File {
context: Some(context),
..
} => Some(context),
_ => None,
}
}
}

/// (Assemble) and return the image to execute inside
pub fn image_assemble(
verbose: bool,
config: &Config,
target: &Target,
host_root: &Path,
) -> Result<String> {
if let Some(dockerfile) = config.dockerfile(target)? {
Dockerfile::File {
path: &dockerfile,
context: config.dockerfile_context(&target)?.as_deref(),
name: config.image(&target)?.as_deref(),
}
.build(verbose, host_root)
.wrap_err("when building dockerfile")
} else {
Ok(image(config, target)?)
}
Expand Down

0 comments on commit 8d7a435

Please sign in to comment.