-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
twoliter: twoliter build
alpha
#108
Changes from all commits
cdfdcb7
d91004f
5a2d464
c344357
51905ce
9ff5444
66ba51f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,14 @@ | ||
use anyhow::Result; | ||
use crate::cargo_make::CargoMake; | ||
use crate::docker::DockerContainer; | ||
use crate::project; | ||
use crate::tools::{install_tools, tools_tempdir}; | ||
use anyhow::{Context, Result}; | ||
use clap::Parser; | ||
use std::path::PathBuf; | ||
use log::debug; | ||
use std::fs; | ||
use std::path::{Path, PathBuf}; | ||
use tempfile::TempDir; | ||
use tokio::fs::{remove_dir_all, remove_file}; | ||
|
||
#[derive(Debug, Parser)] | ||
pub(crate) enum BuildCommand { | ||
|
@@ -25,10 +33,95 @@ pub(crate) struct BuildVariant { | |
/// The architecture to build for. | ||
#[clap(long = "arch", default_value = "x86_64")] | ||
arch: String, | ||
|
||
/// The variant to build. | ||
variant: String, | ||
} | ||
|
||
impl BuildVariant { | ||
pub(super) async fn run(&self) -> Result<()> { | ||
Ok(()) | ||
let project = project::load_or_find_project(self.project_path.clone()).await?; | ||
let token = project.token(); | ||
let tempdir = tools_tempdir()?; | ||
install_tools(&tempdir).await?; | ||
let makefile_path = tempdir.path().join("Makefile.toml"); | ||
// A temporary directory in the `build` directory | ||
let build_temp_dir = TempDir::new_in(project.project_dir()) | ||
.context("Unable to create a tempdir for Twoliter's build")?; | ||
let packages_dir = build_temp_dir.path().join("sdk_rpms"); | ||
fs::create_dir_all(&packages_dir)?; | ||
|
||
let sdk_container = DockerContainer::new( | ||
format!("sdk-{}", token), | ||
project | ||
.sdk(&self.arch) | ||
.context(format!( | ||
"No SDK defined in {} for {}", | ||
project.filepath().display(), | ||
&self.arch | ||
))? | ||
.uri(), | ||
) | ||
.await?; | ||
sdk_container | ||
.cp_out(Path::new("twoliter/alpha/build/rpms"), &packages_dir) | ||
.await?; | ||
|
||
let rpms_dir = project.project_dir().join("build").join("rpms"); | ||
fs::create_dir_all(&rpms_dir)?; | ||
debug!("Moving rpms to build dir"); | ||
for maybe_file in fs::read_dir(packages_dir.join("rpms"))? { | ||
let file = maybe_file?; | ||
debug!("Moving '{}'", file.path().display()); | ||
fs::rename(file.path(), rpms_dir.join(file.file_name()))?; | ||
} | ||
|
||
let mut created_files = Vec::new(); | ||
|
||
let sbkeys_dir = project.project_dir().join("sbkeys"); | ||
if !sbkeys_dir.is_dir() { | ||
// Create a sbkeys directory in the main project | ||
debug!("sbkeys dir not found. Creating a temporary directory"); | ||
fs::create_dir_all(&sbkeys_dir)?; | ||
sdk_container | ||
.cp_out( | ||
Path::new("twoliter/alpha/sbkeys/generate-local-sbkeys"), | ||
&sbkeys_dir, | ||
) | ||
.await?; | ||
}; | ||
|
||
// TODO: Remove once models is no longer conditionally compiled. | ||
// Create the models directory for the sdk to mount | ||
let models_dir = project.project_dir().join("sources/models"); | ||
if !models_dir.is_dir() { | ||
debug!("models source dir not found. Creating a temporary directory"); | ||
fs::create_dir_all(&models_dir.join("src/variant")) | ||
.context("Unable to create models source directory")?; | ||
created_files.push(models_dir) | ||
} | ||
Comment on lines
+94
to
+102
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we |
||
|
||
// Hold the result of the cargo make call so we can clean up the project directory first. | ||
let res = CargoMake::new(&project, &self.arch)? | ||
.env("TWOLITER_TOOLS_DIR", tempdir.path().display().to_string()) | ||
.env("BUILDSYS_ARCH", &self.arch) | ||
.env("BUILDSYS_VARIANT", &self.variant) | ||
.env("BUILDSYS_SBKEYS_DIR", sbkeys_dir.display().to_string()) | ||
.makefile(makefile_path) | ||
.project_dir(project.project_dir()) | ||
.exec("build") | ||
.await; | ||
|
||
// Clean up all of the files we created | ||
for file_name in created_files { | ||
ecpullen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let added = Path::new(&file_name); | ||
if added.is_file() { | ||
remove_file(added).await?; | ||
} else if added.is_dir() { | ||
remove_dir_all(added).await?; | ||
} | ||
} | ||
Comment on lines
+116
to
+123
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a bit skeptical of this. The frequency with which it will never run (a previous error occurred, or the user cancelled the program), and that all it contains is the directory There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it hurt to try to clean it up? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess not, other than delaying the surprise of finding them until an error or cancelled execution has occurred. |
||
|
||
res | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
use crate::common::exec; | ||
use anyhow::Result; | ||
use log::{debug, log, Level}; | ||
use std::path::Path; | ||
use tokio::process::Command; | ||
|
||
pub(crate) struct DockerContainer { | ||
name: String, | ||
} | ||
|
||
impl DockerContainer { | ||
/// Create a docker image with the given name from the image by using `docker create`. | ||
pub(crate) async fn new<S1, S2>(container_name: S1, image: S2) -> Result<Self> | ||
where | ||
S1: Into<String>, | ||
S2: Into<String>, | ||
{ | ||
let name = container_name.into(); | ||
let image = image.into(); | ||
|
||
// Make sure previous versions of this container are stopped deleted. | ||
cleanup_container(&name, Level::Trace).await; | ||
|
||
debug!("Creating docker container '{name}' from image '{image}'"); | ||
|
||
// Create the new container. | ||
let args = vec![ | ||
"create".to_string(), | ||
"--rm".to_string(), | ||
ecpullen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"--name".to_string(), | ||
name.to_string(), | ||
image.to_string(), | ||
]; | ||
|
||
exec(Command::new("docker").args(args), true).await?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This gets repeated often enough that a |
||
Ok(Self { name }) | ||
} | ||
|
||
/// Copy the data from this container to a local destination. | ||
pub(crate) async fn cp_out<P1, P2>(&self, src: P1, dest: P2) -> Result<()> | ||
where | ||
P1: AsRef<Path>, | ||
P2: AsRef<Path>, | ||
{ | ||
debug!( | ||
"Copying '{}' from '{}' to '{}'", | ||
src.as_ref().display(), | ||
self.name, | ||
dest.as_ref().display() | ||
); | ||
let mut args = vec!["cp".to_string()]; | ||
args.push(format!("{}:{}", self.name, src.as_ref().display())); | ||
args.push(dest.as_ref().display().to_string()); | ||
exec(Command::new("docker").args(args), true).await | ||
} | ||
} | ||
|
||
impl Drop for DockerContainer { | ||
fn drop(&mut self) { | ||
let name = self.name.clone(); | ||
tokio::task::spawn(async move { cleanup_container(&name, Level::Error).await }); | ||
} | ||
} | ||
|
||
async fn cleanup_container(name: &str, log_level: Level) { | ||
let args = vec!["stop".to_string(), name.to_string()]; | ||
if let Err(e) = exec(Command::new("docker").args(args), true).await { | ||
log!(log_level, "Unable to stop container '{}': {e}", name) | ||
} | ||
let args = vec!["rm".to_string(), name.to_string()]; | ||
if let Err(e) = exec(Command::new("docker").args(args), true).await { | ||
log!(log_level, "Unable to remove container '{}': {e}", name) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
mod commands; | ||
mod container; | ||
mod image; | ||
|
||
#[allow(unused)] | ||
pub(crate) use self::container::DockerContainer; | ||
#[allow(unused_imports)] | ||
pub(crate) use self::image::{ImageArchUri, ImageUri}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to do this with Rust prior to the calling of
cargo make
and pass the found go modules with-e GO_MODULES
? I'm thinking now is as good a time as any to start moving logic away from Makefile.toml (or at least not adding more logic to it).