summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@noreply.codeberg.org>2024-01-20 12:10:50 +0000
committerLars Wirzenius <liw@noreply.codeberg.org>2024-01-20 12:10:50 +0000
commit4e6d95c453d975305f3a3449a390bf45ab844839 (patch)
treee0065edb6e8bf6beb1e0659011a8bf5eaa667540
parent25aae0aeff4171d6fb6284cb98f23e2adee2dadc (diff)
parent3064f7e293228981340dec1b5c86788439d1b4d4 (diff)
downloadambient-driver-4e6d95c453d975305f3a3449a390bf45ab844839.tar.gz
Merge pull request 'cache' (#59) from cache into main
Reviewed-on: https://codeberg.org/ambient/ambient-driver/pulls/59
-rw-r--r--ambient-driver.md45
-rw-r--r--src/action.rs70
-rw-r--r--src/project.rs5
-rw-r--r--src/run.rs7
4 files changed, 97 insertions, 30 deletions
diff --git a/ambient-driver.md b/ambient-driver.md
index eab1226..5e20085 100644
--- a/ambient-driver.md
+++ b/ambient-driver.md
@@ -225,3 +225,48 @@ then stdout contains "pre_actions:\n"
then stdout contains "\nactions:\n"
then stdout contains "\npost_actions:\n"
~~~
+# Cache persists between CI runs
+
+_Requirement:_ Cache data is persisted between CI runs.
+
+_Justification:_ This allows incrementally building a project after
+changes.
+
+_Stakeholders:_ Lars
+
+~~~scenario
+given an installed ambient-driver
+given file .config/ambient-driver/config.yaml from config.yaml
+given an Ambient VM image ambient.qcow2
+given file cache.yaml
+given a directory srcdir
+
+when I run ambient-driver run cache.yaml
+then file ambient.log contains "counter is now 1."
+
+when I run ambient-driver run cache.yaml
+then file ambient.log contains "counter is now 2."
+
+when I run ambient-driver run cache.yaml
+then file ambient.log contains "counter is now 3."
+~~~
+
+~~~{#cache.yaml .file .yaml}
+projects:
+ hello:
+ image: ambient.qcow2
+ source: srcdir
+ plan:
+ - action: shell
+ shell: |
+ cache=/workspace/cache
+ counter="$cache/counter"
+ if [ -e "$counter" ]; then
+ n="$(expr "$(cat "$counter")" + 1)"
+ echo "$n" > "$counter"
+ else
+ echo 1 > "$counter"
+ fi
+ echo "counter is now $(cat "$counter")."
+ find "$cache" -ls
+~~~
diff --git a/src/action.rs b/src/action.rs
index 87aa002..c32a94a 100644
--- a/src/action.rs
+++ b/src/action.rs
@@ -12,6 +12,8 @@ use crate::{
vdrive::{VirtualDriveBuilder, VirtualDriveError},
};
+const RUST_ENVS: &[(&str, &str)] = &[("CARGO_TARGET_DIR", qemu::CACHE_DIR)];
+
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "action")]
#[serde(rename_all = "snake_case")]
@@ -138,7 +140,7 @@ impl Action {
Self::Mkdir { pathname } => mkdir(pathname),
Self::TarCreate { archive, directory } => tar_create(archive, directory),
Self::TarExtract { archive, directory } => tar_extract(archive, directory),
- Self::Spawn { argv } => spawn(argv),
+ Self::Spawn { argv } => spawn(argv, &[]),
Self::Shell { shell: snippet } => shell(snippet),
Self::RustupSetup => rustup_setup(),
Self::CargoFmt => cargo_fmt(),
@@ -202,7 +204,7 @@ fn tar_extract(archive: &Path, dirname: &Path) -> Result<(), ActionError> {
Ok(())
}
-fn spawn_in(argv: &[String], cwd: &Path) -> Result<(), ActionError> {
+fn spawn_in(argv: &[String], cwd: &Path, extra_env: &[(&str, &str)]) -> Result<(), ActionError> {
let argv0 = if let Some(argv0) = argv.first() {
argv0
} else {
@@ -212,6 +214,7 @@ fn spawn_in(argv: &[String], cwd: &Path) -> Result<(), ActionError> {
let mut cmd = Command::new(argv0)
.args(&argv[1..])
+ .envs(extra_env.iter().copied())
.stdin(Stdio::null())
.current_dir(cwd)
.spawn()
@@ -233,21 +236,21 @@ fn spawn_in(argv: &[String], cwd: &Path) -> Result<(), ActionError> {
fn spawn_str_in(argv: &[&str], cwd: &Path) -> Result<(), ActionError> {
let argv: Vec<String> = argv.iter().map(|s| s.to_string()).collect();
- spawn_in(&argv, cwd)
+ spawn_in(&argv, cwd, &[])
}
-fn spawn(argv: &[String]) -> Result<(), ActionError> {
- spawn_in(argv, Path::new(qemu::SOURCE_DIR))
+fn spawn(argv: &[String], extra_env: &[(&str, &str)]) -> Result<(), ActionError> {
+ spawn_in(argv, Path::new(qemu::SOURCE_DIR), extra_env)
}
fn shell(snippet: &str) -> Result<(), ActionError> {
let snippet = format!("set -xeuo pipefail\n{}", snippet);
- spawn(&["/bin/bash".into(), "-c".into(), snippet])
+ spawn(&["/bin/bash".into(), "-c".into(), snippet], &[])
}
-fn spawn_str(argv: &[&str]) -> Result<(), ActionError> {
+fn spawn_str(argv: &[&str], extra_env: &[(&str, &str)]) -> Result<(), ActionError> {
let argv: Vec<String> = argv.iter().map(|s| s.to_string()).collect();
- spawn(&argv)
+ spawn(&argv, extra_env)
}
fn rustup_setup() -> Result<(), ActionError> {
@@ -282,37 +285,46 @@ fn rustup_setup() -> Result<(), ActionError> {
}
fn cargo_fmt() -> Result<(), ActionError> {
- spawn_str(&["cargo", "fmt", "--offline", "--workspace", "--all-targets"])
+ spawn_str(
+ &["cargo", "fmt", "--offline", "--workspace", "--all-targets"],
+ RUST_ENVS,
+ )
}
fn cargo_clippy() -> Result<(), ActionError> {
- spawn_str(&["cargo", "clippy", "--all"])
+ spawn_str(&["cargo", "clippy", "--all"], RUST_ENVS)
}
fn cargo_build() -> Result<(), ActionError> {
- spawn_str(&[
- "cargo",
- "build",
- "--offline",
- "--workspace",
- "--all-targets",
- ])
+ spawn_str(
+ &[
+ "cargo",
+ "build",
+ "--offline",
+ "--workspace",
+ "--all-targets",
+ ],
+ RUST_ENVS,
+ )
}
fn cargo_test() -> Result<(), ActionError> {
- spawn_str(&["cargo", "test", "--offline", "--workspace"])
+ spawn_str(&["cargo", "test", "--offline", "--workspace"], RUST_ENVS)
}
fn cargo_install() -> Result<(), ActionError> {
- spawn_str(&[
- "cargo",
- "install",
- "--offline",
- "--bins",
- "--path=.",
- "--root",
- qemu::ARTIFACTS_DIR,
- ])
+ spawn_str(
+ &[
+ "cargo",
+ "install",
+ "--offline",
+ "--bins",
+ "--path=.",
+ "--root",
+ qemu::ARTIFACTS_DIR,
+ ],
+ RUST_ENVS,
+ )
}
fn deb() -> Result<(), ActionError> {
@@ -335,7 +347,7 @@ mv ../*_* {}
qemu::ARTIFACTS_DIR
);
- spawn_str(&["bash", "-c", &shell])
+ spawn_str(&["bash", "-c", &shell], RUST_ENVS)
}
#[derive(Debug, thiserror::Error)]
@@ -424,6 +436,6 @@ mod test {
// We can't use the Spawn action here, as it expects the
// SOURCE_DIR to exist. However, spawn_in does the same thing,
// except in a directory of our choosing.
- assert!(spawn_in(&["true".into()], Path::new("/")).is_ok());
+ assert!(spawn_in(&["true".into()], Path::new("/"), &[]).is_ok());
}
}
diff --git a/src/project.rs b/src/project.rs
index 1ef8fc0..2c5f23d 100644
--- a/src/project.rs
+++ b/src/project.rs
@@ -183,6 +183,11 @@ impl State {
Ok(())
}
+ /// Return cache directory for project.
+ pub fn cachedir(&self) -> PathBuf {
+ self.statedir.join("cache")
+ }
+
/// Return latest commit that CI has run on.
pub fn latest_commit(&self) -> Option<&str> {
self.latest_commit.as_deref()
diff --git a/src/run.rs b/src/run.rs
index be343e2..c45310a 100644
--- a/src/run.rs
+++ b/src/run.rs
@@ -52,6 +52,11 @@ fn cmd_run(config: &EffectiveConfig, run: &RunCommand) -> Result<(), RunError> {
if do_run {
info!("{}: running CI on {}", name, project.source().display());
+ let cachedir = state.cachedir();
+ if !cachedir.exists() {
+ mkdir(&cachedir)?;
+ }
+
debug!("Executing pre-plan steps");
for action in project.pre_plan() {
action.execute(project, statedir)?;
@@ -96,7 +101,7 @@ fn cmd_run(config: &EffectiveConfig, run: &RunCommand) -> Result<(), RunError> {
.with_artifact(&Some(artifact.clone()))
.with_artifact_max_size(project.artifact_max_size())
.with_dependencies(&Some(dependencies.clone()))
- .with_cache(&None)
+ .with_cache(&Some(cachedir.clone()))
.with_log(log);
let exit = qemu.run()?;
debug!("QEMU exit code {}", exit);