From f6654cefc6f1909d27e3a2e5c48ef94f4e9f2801 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Fri, 13 Sep 2024 09:02:56 +0200 Subject: [PATCH] feat(imports): implement `imports` from local paths --- CHANGELOG.md | 4 + book/src/reference/import/path.md | 24 ++++++ book/src/reference/imports.md | 1 + src/data/import.rs | 3 + src/data/import/local.rs | 78 +++++++++++++++++++ .../build_expected/build-global.ninja | 34 ++++++++ .../build_expected/imports/testpath2 | 1 + .../build_expected/imports/testpath3_renamed | 1 + .../testpath2/foo.8352856137977294963.o | 1 + .../foo.8352856137977294963.o | 1 + .../testpath/foo.8352856137977294963.o | 1 + .../imported_app/imported_app.elf | 1 + .../imported_app2/imported_app2.elf | 1 + .../imported_app3/imported_app3.elf | 1 + .../laze-project.yml | 24 ++++++ src/tests/45_import_from_local_path/test.sh | 15 ++++ .../45_import_from_local_path/testpath/foo.c | 1 + .../testpath/laze.yml | 4 + .../45_import_from_local_path/testpath2/foo.c | 1 + .../testpath2/laze.yml | 4 + .../45_import_from_local_path/testpath3/foo.c | 1 + .../testpath3/laze.yml | 4 + 22 files changed, 206 insertions(+) create mode 100644 book/src/reference/import/path.md create mode 100644 src/data/import/local.rs create mode 100644 src/tests/45_import_from_local_path/build_expected/build-global.ninja create mode 120000 src/tests/45_import_from_local_path/build_expected/imports/testpath2 create mode 120000 src/tests/45_import_from_local_path/build_expected/imports/testpath3_renamed create mode 100644 src/tests/45_import_from_local_path/build_expected/objects/build/imports/testpath2/foo.8352856137977294963.o create mode 100644 src/tests/45_import_from_local_path/build_expected/objects/build/imports/testpath3_renamed/foo.8352856137977294963.o create mode 100644 src/tests/45_import_from_local_path/build_expected/objects/testpath/foo.8352856137977294963.o create mode 100644 src/tests/45_import_from_local_path/build_expected/single_builder/imported_app/imported_app.elf create mode 100644 src/tests/45_import_from_local_path/build_expected/single_builder/imported_app2/imported_app2.elf create mode 100644 src/tests/45_import_from_local_path/build_expected/single_builder/imported_app3/imported_app3.elf create mode 100644 src/tests/45_import_from_local_path/laze-project.yml create mode 100755 src/tests/45_import_from_local_path/test.sh create mode 100644 src/tests/45_import_from_local_path/testpath/foo.c create mode 100644 src/tests/45_import_from_local_path/testpath/laze.yml create mode 100644 src/tests/45_import_from_local_path/testpath2/foo.c create mode 100644 src/tests/45_import_from_local_path/testpath2/laze.yml create mode 100644 src/tests/45_import_from_local_path/testpath3/foo.c create mode 100644 src/tests/45_import_from_local_path/testpath3/laze.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index f538f866..ca8b426b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - ReleaseDate +### Added + +- implement `imports` from local paths + ## [0.1.23] - 2024-09-07 ## [0.1.22] - 2024-09-07 diff --git a/book/src/reference/import/path.md b/book/src/reference/import/path.md new file mode 100644 index 00000000..1e90df35 --- /dev/null +++ b/book/src/reference/import/path.md @@ -0,0 +1,24 @@ +# `path` + +A `path` import allows using a local directory as import source. + +If `path` is not absolute, it is considered relative to the project root. + +Optionally, `path` can be symlinked into the `imports` folder inside the laze +build directory by setting `symlink: true` in the import. +The symlink name within `$build_dir/imports` defaults to the last path component +of `path`. This can be changed by setting `name`. +Using a symlink helps turning absolute pathnames into relative ones. This might +be desirable for privacy reasons, or help with reproducible builds. + +Example: + +```yaml +imports: + - path: /path/to/local/folder + - path: /path/to/another/local/folder + symlink: true + - path: /path/to/a/third/local/folder + symlink: true + name: folder3 +``` diff --git a/book/src/reference/imports.md b/book/src/reference/imports.md index 4d4fbdb1..2b9c91ae 100644 --- a/book/src/reference/imports.md +++ b/book/src/reference/imports.md @@ -16,3 +16,4 @@ imports: - [`git`](./import/git.md) - [`laze`](./import/laze.md) +- [`path`](./import/path.md) diff --git a/src/data/import.rs b/src/data/import.rs index 7151e259..45e6dbe6 100644 --- a/src/data/import.rs +++ b/src/data/import.rs @@ -4,12 +4,14 @@ use serde::{Deserialize, Serialize}; mod cmd; mod download; +mod local; #[derive(Debug, Serialize, Deserialize, Hash)] #[serde(untagged)] pub enum ImportEntry { Download(crate::download::Download), Command(cmd::Command), + Local(local::Local), } impl ImportEntry { @@ -17,6 +19,7 @@ impl ImportEntry { match self { Self::Download(download) => download.handle(build_dir), Self::Command(command) => command.handle(build_dir), + Self::Local(local) => local.handle(build_dir), } } } diff --git a/src/data/import/local.rs b/src/data/import/local.rs new file mode 100644 index 00000000..6fa38919 --- /dev/null +++ b/src/data/import/local.rs @@ -0,0 +1,78 @@ +use anyhow::{Context, Error}; +use camino::{Utf8Path, Utf8PathBuf}; +use serde::{Deserialize, Serialize}; + +use crate::serde_bool_helpers::default_as_false; + +#[derive(Debug, Serialize, Deserialize, Hash)] +pub struct Local { + name: Option, + path: Utf8PathBuf, + dldir: Option, + #[serde(default = "default_as_false")] + symlink: bool, +} + +impl super::Import for Local { + fn get_path>(&self, build_dir: T) -> Result { + let mut res = Utf8PathBuf::from(build_dir.as_ref()); + res.push("imports"); + if let Some(dldir) = self.get_dldir() { + res.push(dldir); + } else if let Some(name) = self.get_name() { + res.push(name); + } else { + res.push(self.path.file_name().unwrap()); + } + Ok(res) + } + + fn get_name(&self) -> Option { + self.name.clone() + } + + fn get_dldir(&self) -> Option<&String> { + self.dldir.as_ref() + } + + fn handle>( + &self, + build_dir: T, + ) -> Result { + if self.symlink { + let path = self.get_path(&build_dir)?; + + let path_parent = path.parent().unwrap(); + std::fs::create_dir_all(path_parent).with_context(|| format!("creating {path}"))?; + + let link_target = if self.path.is_relative() { + let relpath = pathdiff::diff_utf8_paths(&self.path, path_parent).unwrap(); + relpath + } else { + self.path.clone() + }; + + let mut link_is_missing = true; + if path.is_symlink() { + if path.read_link().unwrap() == link_target { + link_is_missing = false; + } else { + std::fs::remove_file(&path).with_context(|| format!("removing {path}"))?; + } + } else if path.exists() { + return Err(anyhow!("import target {path} exists and is not empty!")); + } + + if link_is_missing { + // TODO: windows support + std::os::unix::fs::symlink(&link_target, &path) + .with_context(|| format!("creating symlink {link_target}")) + .with_context(|| format!("importing path {}", self.path))?; + } + // using `path` here as that is the path relative to the project root. + super::get_lazefile(&path) + } else { + super::get_lazefile(&self.path) + } + } +} diff --git a/src/tests/45_import_from_local_path/build_expected/build-global.ninja b/src/tests/45_import_from_local_path/build_expected/build-global.ninja new file mode 100644 index 00000000..dd288b4a --- /dev/null +++ b/src/tests/45_import_from_local_path/build_expected/build-global.ninja @@ -0,0 +1,34 @@ +builddir = build +build ALWAYS: phony +rule CC_7950216292150676175 + command = cat ${in} > ${out} + description = CC + +build build/objects/testpath/foo.8352856137977294963.o: $ + CC_7950216292150676175 $ + testpath/foo.c + +rule LINK_5506617845631750009 + command = cat ${in} > ${out} + description = LINK + +build build/single_builder/imported_app/imported_app.elf: $ + LINK_5506617845631750009 $ + build/objects/testpath/foo.8352856137977294963.o + +build build/objects/build/imports/testpath2/foo.8352856137977294963.o: $ + CC_7950216292150676175 $ + build/imports/testpath2/foo.c + +build build/single_builder/imported_app2/imported_app2.elf: $ + LINK_5506617845631750009 $ + build/objects/build/imports/testpath2/foo.8352856137977294963.o + +build build/objects/build/imports/testpath3_renamed/foo.8352856137977294963.o: $ + CC_7950216292150676175 $ + build/imports/testpath3_renamed/foo.c + +build build/single_builder/imported_app3/imported_app3.elf: $ + LINK_5506617845631750009 $ + build/objects/build/imports/testpath3_renamed/foo.8352856137977294963.o + diff --git a/src/tests/45_import_from_local_path/build_expected/imports/testpath2 b/src/tests/45_import_from_local_path/build_expected/imports/testpath2 new file mode 120000 index 00000000..6730e6f3 --- /dev/null +++ b/src/tests/45_import_from_local_path/build_expected/imports/testpath2 @@ -0,0 +1 @@ +../../testpath2 \ No newline at end of file diff --git a/src/tests/45_import_from_local_path/build_expected/imports/testpath3_renamed b/src/tests/45_import_from_local_path/build_expected/imports/testpath3_renamed new file mode 120000 index 00000000..e07f4e80 --- /dev/null +++ b/src/tests/45_import_from_local_path/build_expected/imports/testpath3_renamed @@ -0,0 +1 @@ +../../testpath3 \ No newline at end of file diff --git a/src/tests/45_import_from_local_path/build_expected/objects/build/imports/testpath2/foo.8352856137977294963.o b/src/tests/45_import_from_local_path/build_expected/objects/build/imports/testpath2/foo.8352856137977294963.o new file mode 100644 index 00000000..257cc564 --- /dev/null +++ b/src/tests/45_import_from_local_path/build_expected/objects/build/imports/testpath2/foo.8352856137977294963.o @@ -0,0 +1 @@ +foo diff --git a/src/tests/45_import_from_local_path/build_expected/objects/build/imports/testpath3_renamed/foo.8352856137977294963.o b/src/tests/45_import_from_local_path/build_expected/objects/build/imports/testpath3_renamed/foo.8352856137977294963.o new file mode 100644 index 00000000..257cc564 --- /dev/null +++ b/src/tests/45_import_from_local_path/build_expected/objects/build/imports/testpath3_renamed/foo.8352856137977294963.o @@ -0,0 +1 @@ +foo diff --git a/src/tests/45_import_from_local_path/build_expected/objects/testpath/foo.8352856137977294963.o b/src/tests/45_import_from_local_path/build_expected/objects/testpath/foo.8352856137977294963.o new file mode 100644 index 00000000..257cc564 --- /dev/null +++ b/src/tests/45_import_from_local_path/build_expected/objects/testpath/foo.8352856137977294963.o @@ -0,0 +1 @@ +foo diff --git a/src/tests/45_import_from_local_path/build_expected/single_builder/imported_app/imported_app.elf b/src/tests/45_import_from_local_path/build_expected/single_builder/imported_app/imported_app.elf new file mode 100644 index 00000000..257cc564 --- /dev/null +++ b/src/tests/45_import_from_local_path/build_expected/single_builder/imported_app/imported_app.elf @@ -0,0 +1 @@ +foo diff --git a/src/tests/45_import_from_local_path/build_expected/single_builder/imported_app2/imported_app2.elf b/src/tests/45_import_from_local_path/build_expected/single_builder/imported_app2/imported_app2.elf new file mode 100644 index 00000000..257cc564 --- /dev/null +++ b/src/tests/45_import_from_local_path/build_expected/single_builder/imported_app2/imported_app2.elf @@ -0,0 +1 @@ +foo diff --git a/src/tests/45_import_from_local_path/build_expected/single_builder/imported_app3/imported_app3.elf b/src/tests/45_import_from_local_path/build_expected/single_builder/imported_app3/imported_app3.elf new file mode 100644 index 00000000..257cc564 --- /dev/null +++ b/src/tests/45_import_from_local_path/build_expected/single_builder/imported_app3/imported_app3.elf @@ -0,0 +1 @@ +foo diff --git a/src/tests/45_import_from_local_path/laze-project.yml b/src/tests/45_import_from_local_path/laze-project.yml new file mode 100644 index 00000000..3816b96f --- /dev/null +++ b/src/tests/45_import_from_local_path/laze-project.yml @@ -0,0 +1,24 @@ +builders: + - name: single_builder + rules: + - name: CC + in: 'c' + out: 'o' + cmd: 'cat ${in} > ${out}' + - name: LINK + in: 'o' + cmd: 'cat ${in} > ${out}' + + env: + bindir: build/${builder}/${app} + +imports: + # test a relative import + - path: testpath + # test a relative import, symlinked + - path: testpath2 + symlink: true + # test a relative import, symlinked, renamed + - path: testpath3 + symlink: true + name: testpath3_renamed diff --git a/src/tests/45_import_from_local_path/test.sh b/src/tests/45_import_from_local_path/test.sh new file mode 100755 index 00000000..5c9085af --- /dev/null +++ b/src/tests/45_import_from_local_path/test.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +. ../test-common.sh + +cleanup + +${LAZE} build -g + +clean_temp_files + +diff -r build build_expected + +echo TEST_OK + +cleanup diff --git a/src/tests/45_import_from_local_path/testpath/foo.c b/src/tests/45_import_from_local_path/testpath/foo.c new file mode 100644 index 00000000..257cc564 --- /dev/null +++ b/src/tests/45_import_from_local_path/testpath/foo.c @@ -0,0 +1 @@ +foo diff --git a/src/tests/45_import_from_local_path/testpath/laze.yml b/src/tests/45_import_from_local_path/testpath/laze.yml new file mode 100644 index 00000000..461976b3 --- /dev/null +++ b/src/tests/45_import_from_local_path/testpath/laze.yml @@ -0,0 +1,4 @@ +apps: + - name: imported_app + sources: + - foo.c diff --git a/src/tests/45_import_from_local_path/testpath2/foo.c b/src/tests/45_import_from_local_path/testpath2/foo.c new file mode 100644 index 00000000..257cc564 --- /dev/null +++ b/src/tests/45_import_from_local_path/testpath2/foo.c @@ -0,0 +1 @@ +foo diff --git a/src/tests/45_import_from_local_path/testpath2/laze.yml b/src/tests/45_import_from_local_path/testpath2/laze.yml new file mode 100644 index 00000000..2752ae9e --- /dev/null +++ b/src/tests/45_import_from_local_path/testpath2/laze.yml @@ -0,0 +1,4 @@ +apps: + - name: imported_app2 + sources: + - foo.c diff --git a/src/tests/45_import_from_local_path/testpath3/foo.c b/src/tests/45_import_from_local_path/testpath3/foo.c new file mode 100644 index 00000000..257cc564 --- /dev/null +++ b/src/tests/45_import_from_local_path/testpath3/foo.c @@ -0,0 +1 @@ +foo diff --git a/src/tests/45_import_from_local_path/testpath3/laze.yml b/src/tests/45_import_from_local_path/testpath3/laze.yml new file mode 100644 index 00000000..3529b6ce --- /dev/null +++ b/src/tests/45_import_from_local_path/testpath3/laze.yml @@ -0,0 +1,4 @@ +apps: + - name: imported_app3 + sources: + - foo.c