diff options
author | Lars Wirzenius <liw@noreply.codeberg.org> | 2023-09-02 06:44:42 +0000 |
---|---|---|
committer | Lars Wirzenius <liw@noreply.codeberg.org> | 2023-09-02 06:44:42 +0000 |
commit | dcf990d1f1871c3f6d0f7be8eeab7e48570d9196 (patch) | |
tree | 6e8a3b81c383a7cb397cd300f4192a457b10213f | |
parent | f89bcc3784c86e719ee2118a9d4f8aece4f4bdc2 (diff) | |
parent | 17eb20a3ed9f11e302a7af41dcd02655f51e80ec (diff) | |
download | ambient-run-dcf990d1f1871c3f6d0f7be8eeab7e48570d9196.tar.gz |
Merge pull request 'Allow project to specify where build puts artifacts it produces' (#5) from artifact-output into main
Reviewed-on: https://codeberg.org/ambient/ambient-run/pulls/5
-rw-r--r-- | ambient-run.md | 90 | ||||
-rw-r--r-- | src/bin/ambient-run.rs | 4 | ||||
-rw-r--r-- | src/project.rs | 18 | ||||
-rw-r--r-- | src/qemu.rs | 28 |
4 files changed, 137 insertions, 3 deletions
diff --git a/ambient-run.md b/ambient-run.md index 1690cce..82eccab 100644 --- a/ambient-run.md +++ b/ambient-run.md @@ -165,6 +165,8 @@ source: . shell: | cargo test image: /my/image.qcow2 +artifact: null +artifact_max_size: null ~~~ ### Show per-build configuration @@ -226,6 +228,94 @@ shell: | image: image.qcow2 ~~~ +### Build produces an artifact + +_Requirement:_ The build can produce an artifact. + +_Justification:_ Without this a build can't produce something that can +be used after the build has finished. + +_Stakeholder:_ Lars. + +~~~scenario +given an installed ambient-run +given file artifact-project.yaml +given file foo/README.md from foo-project.yaml +given image file image.qcow2 specified for test suite +when I run ambient-run build artifact-project.yaml --log foo.log +then file foo.tar exists +when I run tar tf foo.tar +then stdout contains "README.md" +~~~ + + +~~~{#artifact-project.yaml .file .yaml} +source: foo +shell: | + #!/bin/bash + tar -cf /dev/vdc . +image: image.qcow2 +artifact: foo.tar +~~~ + +### Fail build that tries to produce an unwanted artifact + +_Requirement:_ If an artifact output is not specified for the project, +fail a build that tries to make one. + +_Justification:_ If a build tries to create an artifact, but one isn't +wanted, the build should fail. + +_Stakeholder:_ Lars. + +~~~scenario +given an installed ambient-run +given file no-artifact-project.yaml +given file foo/README.md from foo-project.yaml +given image file image.qcow2 specified for test suite +when I run ambient-run build no-artifact-project.yaml --log foo.log +then file foo.log contains "EXIT CODE: 2" +~~~ + + +~~~{#no-artifact-project.yaml .file .yaml} +source: foo +shell: | + #!/bin/bash + tar -cf /dev/vdc . +image: image.qcow2 +~~~ + +### Fail build that tries to produce an oversize artifact + +_Requirement:_ If a build produces an artifact that is too large, the +build should fail. + +_Justification:_ Without a limit, a malicious build could fill all +available storage space, which is a denial-of-service attack. + +_Stakeholder:_ Lars. + +~~~scenario +given an installed ambient-run +given file small-artifact-project.yaml +given file foo/README.md from foo-project.yaml +given image file image.qcow2 specified for test suite +when I run ambient-run build small-artifact-project.yaml --log foo.log +then file foo.log contains "EXIT CODE: 2" +~~~ + + +~~~{#small-artifact-project.yaml .file .yaml} +source: foo +shell: | + #!/bin/bash + tar -cf /dev/vdc . +image: image.qcow2 +artifact: foo.tar +artifact_max_size: 1 +~~~ + ### Build is given dependencies ### Cache is persistent between builds ### Build gets the resources is demands diff --git a/src/bin/ambient-run.rs b/src/bin/ambient-run.rs index e1f1b16..37054c2 100644 --- a/src/bin/ambient-run.rs +++ b/src/bin/ambient-run.rs @@ -215,7 +215,9 @@ impl BuildCommand { let project = Project::load(&self.filename, config)?; let mut qemu = Qemu::new(&project.image()) .with_shell(project.shell()) - .with_source(&project.source()); + .with_source(&project.source()) + .with_artifact(project.artifact()) + .with_artifact_max_size(project.artifact_max_size()); if let Some(log) = &self.log { qemu = qemu.with_log(log); } diff --git a/src/project.rs b/src/project.rs index 8a182bc..76f42dc 100644 --- a/src/project.rs +++ b/src/project.rs @@ -12,6 +12,8 @@ pub struct Project { source: PathBuf, shell: String, image: PathBuf, + artifact: Option<PathBuf>, + artifact_max_size: Option<u64>, } impl Project { @@ -43,6 +45,8 @@ impl Project { source: PathBuf::from("."), shell: "".into(), image, + artifact: None, + artifact_max_size: None, }; project.add_from(filename)?; if project.shell.is_empty() { @@ -68,6 +72,8 @@ impl Project { if let Some(x) = snippet.image { self.image = x; } + self.artifact = snippet.artifact; + self.artifact_max_size = snippet.artifact_max_size; Ok(()) } @@ -90,6 +96,16 @@ impl Project { pub fn shell(&self) -> &str { self.shell.as_ref() } + + /// Artifact file. + pub fn artifact(&self) -> &Option<PathBuf> { + &self.artifact + } + + /// Artifact file max size. + pub fn artifact_max_size(&self) -> Option<u64> { + self.artifact_max_size.clone() + } } #[derive(Debug, Deserialize)] @@ -98,6 +114,8 @@ struct ProjectSnippet { source: Option<PathBuf>, shell: Option<String>, image: Option<PathBuf>, + artifact: Option<PathBuf>, + artifact_max_size: Option<u64>, } /// Possible errors from configuration file handling. diff --git a/src/qemu.rs b/src/qemu.rs index c48213f..4c6efff 100644 --- a/src/qemu.rs +++ b/src/qemu.rs @@ -18,6 +18,8 @@ pub struct Qemu { log: Option<PathBuf>, source: PathBuf, shell: Option<String>, + artifact: Option<PathBuf>, + artifact_max_xize: u64, } impl Qemu { @@ -26,6 +28,7 @@ impl Qemu { Self { image: image.into(), source: PathBuf::from("."), + artifact_max_xize: MAX_OUTPUT_SIZE, ..Default::default() } } @@ -48,6 +51,18 @@ impl Qemu { self } + /// Set output artifact filename. + pub fn with_artifact(mut self, artifact: &Option<PathBuf>) -> Self { + self.artifact = artifact.clone(); + self + } + + /// Set maximum length of output artifact. + pub fn with_artifact_max_size(mut self, size: Option<u64>) -> Self { + self.artifact_max_xize = size.unwrap_or(MAX_OUTPUT_SIZE); + self + } + /// Run QEMU in the specified way. pub fn run(&self) -> Result<(), QemuError> { eprintln!("qemu run"); @@ -62,8 +77,17 @@ impl Qemu { copy(OVMF_FD, &vars).map_err(|e| QemuError::Copy(OVMF_FD.into(), e))?; eprintln!("output drive"); - let output_drive = - Self::create_tar_with_size(tmp.path().join("output"), empty.path(), MAX_OUTPUT_SIZE)?; + let output_drive = if let Some(filename) = &self.artifact { + eprintln!("output to {}", filename.display()); + Self::create_tar_with_size( + filename.to_path_buf(), + empty.path(), + self.artifact_max_xize, + )? + } else { + eprintln!("empty output drive"); + Self::create_tar_with_size(tmp.path().join("output"), empty.path(), 0)? + }; eprintln!("cache drive"); let cache_drive = |