From 748060f866090f2cd6b4b55898869d86ca0600d1 Mon Sep 17 00:00:00 2001 From: Rain Date: Fri, 20 Dec 2024 02:08:30 -0800 Subject: [PATCH 1/5] [spr] initial version Created using spr 1.3.6-beta.1 --- .gitignore | 2 +- src/config/identifier.rs | 170 +++++++++++++++++++++++++++++++ src/{config.rs => config/imp.rs} | 32 +++--- src/config/mod.rs | 9 ++ src/package.rs | 51 ++++++---- tests/mod.rs | 56 +++++----- 6 files changed, 258 insertions(+), 62 deletions(-) create mode 100644 src/config/identifier.rs rename src/{config.rs => config/imp.rs} (90%) create mode 100644 src/config/mod.rs diff --git a/.gitignore b/.gitignore index 088ba6b..321eccd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # Generated by Cargo # will have compiled files and executables -/target/ +/target # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html diff --git a/src/config/identifier.rs b/src/config/identifier.rs new file mode 100644 index 0000000..03e501b --- /dev/null +++ b/src/config/identifier.rs @@ -0,0 +1,170 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +use std::{borrow::Cow, fmt, str::FromStr}; + +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +/// A unique identifier for a configuration parameter. +/// +/// Config identifiers must be: +/// +/// * non-empty +/// * ASCII printable +/// * first character must be a letter +/// * contain only letters, numbers, underscores, and hyphens +/// +/// In general, config identifiers represent Rust package and Oxide service names. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] +#[serde(transparent)] +pub struct ConfigIdent(Cow<'static, str>); + +impl ConfigIdent { + /// Creates a new config identifier at runtime. + pub fn new>(s: S) -> Result { + let s = s.into(); + Self::validate(&s)?; + Ok(Self(Cow::Owned(s))) + } + + /// Creates a new config identifier from a static string. + pub fn new_static(s: &'static str) -> Result { + if let Err(error) = Self::validate(s) { + return Err(error); + } + Ok(Self(Cow::Borrowed(s))) + } + + /// Creates a new config identifier at compile time, panicking if the + /// identifier is invalid. + pub const fn new_const(s: &'static str) -> Self { + match Self::validate(s) { + Ok(_) => Self(Cow::Borrowed(s)), + Err(error) => panic!("{}", error.as_static_str()), + } + } + + const fn validate(id: &str) -> Result<(), InvalidConfigIdent> { + if id.is_empty() { + return Err(InvalidConfigIdent::Empty); + } + + let bytes = id.as_bytes(); + if !bytes[0].is_ascii_alphabetic() { + return Err(InvalidConfigIdent::StartsWithNonLetter); + } + + let mut bytes = match bytes { + [_, rest @ ..] => rest, + [] => panic!("already checked that it's non-empty"), + }; + while let [next, rest @ ..] = &bytes { + if !(next.is_ascii_alphanumeric() || *next == b'_' || *next == b'-') { + break; + } + bytes = rest; + } + + if !bytes.is_empty() { + return Err(InvalidConfigIdent::ContainsInvalidCharacters); + } + + Ok(()) + } + + /// Returns the identifier as a string. + #[inline] + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl FromStr for ConfigIdent { + type Err = InvalidConfigIdent; + + fn from_str(s: &str) -> Result { + Self::new(s) + } +} + +impl<'de> Deserialize<'de> for ConfigIdent { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + Self::new(s).map_err(serde::de::Error::custom) + } +} + +impl AsRef for ConfigIdent { + #[inline] + fn as_ref(&self) -> &str { + &self.0 + } +} + +impl std::fmt::Display for ConfigIdent { + #[inline] + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + self.0.fmt(f) + } +} + +/// Errors that can occur when creating a `ConfigIdent`. +#[derive(Clone, Debug, Error)] +pub enum InvalidConfigIdent { + Empty, + NonAsciiPrintable, + StartsWithNonLetter, + ContainsInvalidCharacters, +} + +impl InvalidConfigIdent { + pub const fn as_static_str(&self) -> &'static str { + match self { + Self::Empty => "config identifier must be non-empty", + Self::NonAsciiPrintable => "config identifier must be ASCII printable", + Self::StartsWithNonLetter => "config identifier must start with a letter", + Self::ContainsInvalidCharacters => { + "config identifier must contain only letters, numbers, underscores, and hyphens" + } + } + } +} + +impl fmt::Display for InvalidConfigIdent { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.as_static_str().fmt(f) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn valid_identifiers() { + let valid = [ + "a", "ab", "a1", "a_", "a-", "a_b", "a-b", "a1_", "a1-", "a1_b", "a1-b", + ]; + for &id in &valid { + ConfigIdent::new(id).unwrap_or_else(|error| { + panic!("{} should have succeeded, but failed with: {:?}", id, error); + }); + } + } + + #[test] + fn invalid_identifiers() { + let invalid = [ + "", "1", "_", "-", "1_", "-a", "_a", "a!", "a ", "a\n", "a\t", "a\r", "a\x7F", "aɑ", + ]; + for &id in &invalid { + ConfigIdent::new(id).expect_err(&format!("{} should have failed", id)); + } + } +} diff --git a/src/config.rs b/src/config/imp.rs similarity index 90% rename from src/config.rs rename to src/config/imp.rs index 041d52c..0e5a7d3 100644 --- a/src/config.rs +++ b/src/config/imp.rs @@ -12,10 +12,12 @@ use std::path::Path; use thiserror::Error; use topological_sort::TopologicalSort; +use super::ConfigIdent; + /// Describes a set of packages to act upon. /// /// This structure maps "package name" to "package" -pub struct PackageMap<'a>(pub BTreeMap<&'a String, &'a Package>); +pub struct PackageMap<'a>(pub BTreeMap<&'a ConfigIdent, &'a Package>); // The name of a file which should be created by building a package. #[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] @@ -68,12 +70,12 @@ impl<'a> PackageMap<'a> { /// /// Returns packages in batches that may be built concurrently. pub struct PackageDependencyIter<'a> { - lookup_by_output: BTreeMap, + lookup_by_output: BTreeMap, outputs: TopologicalSort, } impl<'a> Iterator for PackageDependencyIter<'a> { - type Item = Vec<(&'a String, &'a Package)>; + type Item = Vec<(&'a ConfigIdent, &'a Package)>; fn next(&mut self) -> Option { if self.outputs.is_empty() { @@ -99,11 +101,11 @@ impl<'a> Iterator for PackageDependencyIter<'a> { } /// Describes the configuration for a set of packages. -#[derive(Deserialize, Debug)] +#[derive(Clone, Deserialize, Debug)] pub struct Config { /// Packages to be built and installed. #[serde(default, rename = "package")] - pub packages: BTreeMap, + pub packages: BTreeMap, } impl Config { @@ -159,18 +161,18 @@ mod test { #[test] fn test_order() { - let pkg_a_name = String::from("pkg-a"); + let pkg_a_name = ConfigIdent::new_const("pkg-a"); let pkg_a = Package { - service_name: String::from("a"), + service_name: ConfigIdent::new_const("a"), source: PackageSource::Manual, output: PackageOutput::Tarball, only_for_targets: None, setup_hint: None, }; - let pkg_b_name = String::from("pkg-b"); + let pkg_b_name = ConfigIdent::new_const("pkg-b"); let pkg_b = Package { - service_name: String::from("b"), + service_name: ConfigIdent::new_const("b"), source: PackageSource::Composite { packages: vec![pkg_a.get_output_file(&pkg_a_name)], }, @@ -199,10 +201,10 @@ mod test { #[test] #[should_panic(expected = "cyclic dependency in package manifest")] fn test_cyclic_dependency() { - let pkg_a_name = String::from("pkg-a"); - let pkg_b_name = String::from("pkg-b"); + let pkg_a_name = ConfigIdent::new_const("pkg-a"); + let pkg_b_name = ConfigIdent::new_const("pkg-b"); let pkg_a = Package { - service_name: String::from("a"), + service_name: ConfigIdent::new_const("a"), source: PackageSource::Composite { packages: vec![String::from("pkg-b.tar")], }, @@ -211,7 +213,7 @@ mod test { setup_hint: None, }; let pkg_b = Package { - service_name: String::from("b"), + service_name: ConfigIdent::new_const("b"), source: PackageSource::Composite { packages: vec![String::from("pkg-a.tar")], }, @@ -237,9 +239,9 @@ mod test { #[test] #[should_panic(expected = "Could not find a package which creates 'pkg-b.tar'")] fn test_missing_dependency() { - let pkg_a_name = String::from("pkg-a"); + let pkg_a_name = ConfigIdent::new_const("pkg-a"); let pkg_a = Package { - service_name: String::from("a"), + service_name: ConfigIdent::new_const("a"), source: PackageSource::Composite { packages: vec![String::from("pkg-b.tar")], }, diff --git a/src/config/mod.rs b/src/config/mod.rs new file mode 100644 index 0000000..de4ca23 --- /dev/null +++ b/src/config/mod.rs @@ -0,0 +1,9 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +mod identifier; +mod imp; + +pub use identifier::*; +pub use imp::*; diff --git a/src/package.rs b/src/package.rs index c148076..1c108cd 100644 --- a/src/package.rs +++ b/src/package.rs @@ -10,6 +10,7 @@ use crate::archive::{ }; use crate::blob::{self, BLOB}; use crate::cache::{Cache, CacheError}; +use crate::config::ConfigIdent; use crate::input::{BuildInput, BuildInputs, MappedPath, TargetDirectory, TargetPackage}; use crate::progress::{NoProgress, Progress}; use crate::target::Target; @@ -168,7 +169,7 @@ pub enum PackageOutput { #[derive(Clone, Deserialize, Debug, PartialEq)] pub struct Package { /// The name of the service name to be used on the target OS. - pub service_name: String, + pub service_name: ConfigIdent, /// Identifies from where the package originates. /// @@ -193,7 +194,7 @@ pub struct Package { const DEFAULT_VERSION: semver::Version = semver::Version::new(0, 0, 0); async fn new_zone_archive_builder( - package_name: &str, + package_name: &ConfigIdent, output_directory: &Utf8Path, ) -> Result>> { let tarfile = output_directory.join(format!("{}.tar.gz", package_name)); @@ -227,19 +228,27 @@ impl<'a> Default for BuildConfig<'a> { impl Package { /// The path of a package once it is built. - pub fn get_output_path(&self, name: &str, output_directory: &Utf8Path) -> Utf8PathBuf { - output_directory.join(self.get_output_file(name)) + pub fn get_output_path( + &self, + id: &ConfigIdent, + output_directory: &Utf8Path, + ) -> Utf8PathBuf { + output_directory.join(self.get_output_file(id)) } /// The path of a package after it has been "stamped" with a version. - pub fn get_stamped_output_path(&self, name: &str, output_directory: &Utf8Path) -> Utf8PathBuf { + pub fn get_stamped_output_path( + &self, + name: &ConfigIdent, + output_directory: &Utf8Path, + ) -> Utf8PathBuf { output_directory .join("versioned") .join(self.get_output_file(name)) } /// The filename of a package once it is built. - pub fn get_output_file(&self, name: &str) -> String { + pub fn get_output_file(&self, name: &ConfigIdent) -> String { match self.output { PackageOutput::Zone { .. } => format!("{}.tar.gz", name), PackageOutput::Tarball => format!("{}.tar", name), @@ -250,7 +259,7 @@ impl Package { pub async fn create_for_target( &self, target: &Target, - name: &str, + name: &ConfigIdent, output_directory: &Utf8Path, ) -> Result { let build_config = BuildConfig { @@ -263,7 +272,7 @@ impl Package { pub async fn create( &self, - name: &str, + name: &ConfigIdent, output_directory: &Utf8Path, build_config: &BuildConfig<'_>, ) -> Result { @@ -273,7 +282,7 @@ impl Package { pub async fn stamp( &self, - name: &str, + name: &ConfigIdent, output_directory: &Utf8Path, version: &semver::Version, ) -> Result { @@ -346,7 +355,7 @@ impl Package { &self, progress: &impl Progress, target: &Target, - name: &str, + name: &ConfigIdent, output_directory: &Utf8Path, ) -> Result { let config = BuildConfig { @@ -359,7 +368,7 @@ impl Package { async fn create_internal( &self, - name: &str, + name: &ConfigIdent, output_directory: &Utf8Path, config: &BuildConfig<'_>, ) -> Result { @@ -382,7 +391,7 @@ impl Package { // Adds the version file to the archive fn get_version_input( &self, - package_name: &str, + package_name: &ConfigIdent, version: Option<&semver::Version>, ) -> BuildInput { match &self.output { @@ -397,7 +406,7 @@ impl Package { let kvs = vec![ ("v", "1"), ("t", "layer"), - ("pkg", package_name), + ("pkg", package_name.as_ref()), ("version", version), ]; @@ -514,7 +523,7 @@ impl Package { fn get_all_inputs( &self, - package_name: &str, + package_name: &ConfigIdent, target: &Target, output_directory: &Utf8Path, zoned: bool, @@ -559,7 +568,7 @@ impl Package { let dst_directory = match self.output { PackageOutput::Zone { .. } => { let dst = Utf8Path::new("/opt/oxide") - .join(&self.service_name) + .join(self.service_name.as_str()) .join("bin"); inputs.0.extend( zone_get_all_parent_inputs(&dst)? @@ -589,7 +598,7 @@ impl Package { let destination_path = if zoned { zone_archive_path( &Utf8Path::new("/opt/oxide") - .join(&self.service_name) + .join(self.service_name.as_str()) .join(BLOB), )? } else { @@ -597,7 +606,9 @@ impl Package { }; if let Some(s3_blobs) = self.source.blobs() { inputs.0.extend(s3_blobs.iter().map(|blob| { - let from = download_directory.join(&self.service_name).join(blob); + let from = download_directory + .join(self.service_name.as_str()) + .join(blob); let to = destination_path.join(blob); BuildInput::AddBlob { path: MappedPath { from, to }, @@ -608,7 +619,7 @@ impl Package { if let Some(buildomat_blobs) = self.source.buildomat_blobs() { inputs.0.extend(buildomat_blobs.iter().map(|blob| { let from = download_directory - .join(&self.service_name) + .join(self.service_name.as_str()) .join(&blob.artifact); let to = destination_path.join(&blob.artifact); BuildInput::AddBlob { @@ -623,7 +634,7 @@ impl Package { async fn create_zone_package( &self, timer: &mut BuildTimer, - name: &str, + name: &ConfigIdent, output_directory: &Utf8Path, config: &BuildConfig<'_>, ) -> Result { @@ -762,7 +773,7 @@ impl Package { async fn create_tarball_package( &self, - name: &str, + name: &ConfigIdent, output_directory: &Utf8Path, config: &BuildConfig<'_>, ) -> Result { diff --git a/tests/mod.rs b/tests/mod.rs index c961bf7..2f3647f 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -12,11 +12,14 @@ mod test { use tar::Archive; use omicron_zone_package::blob::download; - use omicron_zone_package::config; + use omicron_zone_package::config::{self, ConfigIdent}; use omicron_zone_package::package::BuildConfig; use omicron_zone_package::progress::NoProgress; use omicron_zone_package::target::Target; + const MY_PACKAGE: ConfigIdent = ConfigIdent::new_const("my-package"); + const MY_SERVICE: ConfigIdent = ConfigIdent::new_const("my-service"); + fn entry_path<'a, R>(entry: &tar::Entry<'a, R>) -> Utf8PathBuf where R: 'a + Read, @@ -58,19 +61,18 @@ mod test { async fn test_package_as_zone() { // Parse the configuration let cfg = config::parse("tests/service-a/cfg.toml").unwrap(); - let package_name = "my-service"; - let package = cfg.packages.get(package_name).unwrap(); + let package = cfg.packages.get(&MY_SERVICE).unwrap(); // Create the packaged file let out = camino_tempfile::tempdir().unwrap(); let build_config = BuildConfig::default(); package - .create(package_name, out.path(), &build_config) + .create(&MY_SERVICE, out.path(), &build_config) .await .unwrap(); // Verify the contents - let path = package.get_output_path(package_name, out.path()); + let path = package.get_output_path(&MY_SERVICE, out.path()); assert!(path.exists()); let gzr = flate2::read::GzDecoder::new(File::open(path).unwrap()); let mut archive = Archive::new(gzr); @@ -97,19 +99,18 @@ mod test { async fn test_rust_package_as_zone() { // Parse the configuration let cfg = config::parse("tests/service-b/cfg.toml").unwrap(); - let package_name = "my-service"; - let package = cfg.packages.get(package_name).unwrap(); + let package = cfg.packages.get(&MY_SERVICE).unwrap(); // Create the packaged file let out = camino_tempfile::tempdir().unwrap(); let build_config = BuildConfig::default(); package - .create(package_name, out.path(), &build_config) + .create(&MY_SERVICE, out.path(), &build_config) .await .unwrap(); // Verify the contents - let path = package.get_output_path(package_name, out.path()); + let path = package.get_output_path(&MY_SERVICE, out.path()); assert!(path.exists()); let gzr = flate2::read::GzDecoder::new(File::open(path).unwrap()); let mut archive = Archive::new(gzr); @@ -140,19 +141,18 @@ mod test { async fn test_rust_package_as_tarball() { // Parse the configuration let cfg = config::parse("tests/service-c/cfg.toml").unwrap(); - let package_name = "my-service"; - let package = cfg.packages.get(package_name).unwrap(); + let package = cfg.packages.get(&MY_SERVICE).unwrap(); // Create the packaged file let out = camino_tempfile::tempdir().unwrap(); let build_config = BuildConfig::default(); package - .create(package_name, out.path(), &build_config) + .create(&MY_SERVICE, out.path(), &build_config) .await .unwrap(); // Verify the contents - let path = package.get_output_path(package_name, out.path()); + let path = package.get_output_path(&MY_SERVICE, out.path()); assert!(path.exists()); let mut archive = Archive::new(File::open(path).unwrap()); let mut ents = archive.entries().unwrap(); @@ -168,7 +168,7 @@ mod test { // Try stamping it, verify the contents again let expected_semver = semver::Version::new(3, 3, 3); let path = package - .stamp(package_name, out.path(), &expected_semver) + .stamp(&MY_SERVICE, out.path(), &expected_semver) .await .unwrap(); assert!(path.exists()); @@ -192,22 +192,20 @@ mod test { async fn test_rust_package_with_distinct_service_name() { // Parse the configuration let cfg = config::parse("tests/service-d/cfg.toml").unwrap(); - let package_name = "my-package"; - let service_name = "my-service"; - let package = cfg.packages.get(package_name).unwrap(); + let package = cfg.packages.get(&MY_PACKAGE).unwrap(); - assert_eq!(package.service_name, service_name); + assert_eq!(package.service_name, MY_SERVICE); // Create the packaged file let out = camino_tempfile::tempdir().unwrap(); let build_config = BuildConfig::default(); package - .create(package_name, out.path(), &build_config) + .create(&MY_PACKAGE, out.path(), &build_config) .await .unwrap(); // Verify the contents - let path = package.get_output_path(package_name, out.path()); + let path = package.get_output_path(&MY_PACKAGE, out.path()); assert!(path.exists()); let mut archive = Archive::new(File::open(path).unwrap()); let mut ents = archive.entries().unwrap(); @@ -230,7 +228,13 @@ mod test { let batch = build_order.next().expect("Missing dependency batch"); let mut batch_pkg_names: Vec<_> = batch.iter().map(|(name, _)| *name).collect(); batch_pkg_names.sort(); - assert_eq!(batch_pkg_names, vec!["pkg-1", "pkg-2"]); + assert_eq!( + batch_pkg_names, + vec![ + &ConfigIdent::new_const("pkg-1"), + &ConfigIdent::new_const("pkg-2"), + ] + ); let build_config = BuildConfig::default(); for (package_name, package) in batch { // Create the packaged file @@ -243,17 +247,17 @@ mod test { // Build the composite package let batch = build_order.next().expect("Missing dependency batch"); let batch_pkg_names: Vec<_> = batch.iter().map(|(name, _)| *name).collect(); - let package_name = "pkg-3"; - assert_eq!(batch_pkg_names, vec![package_name]); - let package = cfg.packages.get(package_name).unwrap(); + let package_name = ConfigIdent::new_const("pkg-3"); + assert_eq!(batch_pkg_names, vec![&package_name]); + let package = cfg.packages.get(&package_name).unwrap(); let build_config = BuildConfig::default(); package - .create(package_name, out.path(), &build_config) + .create(&package_name, out.path(), &build_config) .await .unwrap(); // Verify the contents - let path = package.get_output_path(package_name, out.path()); + let path = package.get_output_path(&package_name, out.path()); assert!(path.exists()); let gzr = flate2::read::GzDecoder::new(File::open(path).unwrap()); let mut archive = Archive::new(gzr); From 0d4ee07554ba1967f5f251b01250f0e6a0a68e3d Mon Sep 17 00:00:00 2001 From: Rain Date: Fri, 20 Dec 2024 10:20:03 +0000 Subject: [PATCH 2/5] [spr] changes introduced through rebase Created using spr 1.3.6-beta.1 [skip ci] --- .github/workflows/rust.yml | 10 ++++++++++ .gitignore | 2 +- Cargo.toml | 6 +----- src/config.rs | 1 - src/package.rs | 2 +- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8adca91..2de3257 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -3,6 +3,9 @@ # name: Rust +env: + RUSTFLAGS: -D warnings + on: push: branches: [ main ] @@ -22,15 +25,22 @@ jobs: components: rustfmt - name: Check style run: cargo fmt -- --check + - name: Check clippy + run: cargo clippy --all-targets --all-features build-and-test: runs-on: ${{ matrix.os }} strategy: matrix: + # 1.81 is the MSRV. + toolchain: [ stable, "1.81" ] os: [ ubuntu-latest, macos-latest ] steps: # actions/checkout@v2 - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: dtolnay/rust-toolchain@v1 + with: + toolchain: ${{ matrix.toolchain }} - name: Build run: cargo build --tests --verbose - name: Run tests diff --git a/.gitignore b/.gitignore index 088ba6b..321eccd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # Generated by Cargo # will have compiled files and executables -/target/ +/target # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html diff --git a/Cargo.toml b/Cargo.toml index a6f130e..5f94e34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,11 +3,7 @@ name = "omicron-zone-package" version = "0.11.1" authors = ["Sean Klein "] edition = "2021" -# -# Report a specific error in the case that the toolchain is too old for -# let-else: -# -rust-version = "1.65.0" +rust-version = "1.81.0" license = "MPL-2.0" repository = "https://github.com/oxidecomputer/omicron-package" description = "Packaging tools for Oxide's control plane software" diff --git a/src/config.rs b/src/config.rs index 041d52c..10fdb02 100644 --- a/src/config.rs +++ b/src/config.rs @@ -113,7 +113,6 @@ impl Config { self.packages .iter() .filter(|(_, pkg)| target.includes_package(pkg)) - .map(|(name, pkg)| (name, pkg)) .collect(), ) } diff --git a/src/package.rs b/src/package.rs index c148076..c4221ce 100644 --- a/src/package.rs +++ b/src/package.rs @@ -215,7 +215,7 @@ pub struct BuildConfig<'a> { static DEFAULT_TARGET: Target = Target(BTreeMap::new()); static DEFAULT_PROGRESS: NoProgress = NoProgress::new(); -impl<'a> Default for BuildConfig<'a> { +impl Default for BuildConfig<'_> { fn default() -> Self { Self { target: &DEFAULT_TARGET, From f311eeddd732ac285f560c8ad8504d839ea66e83 Mon Sep 17 00:00:00 2001 From: Rain Date: Fri, 20 Dec 2024 10:23:25 +0000 Subject: [PATCH 3/5] [spr] changes introduced through rebase Created using spr 1.3.6-beta.1 [skip ci] --- .github/workflows/rust.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2de3257..04e2f97 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -10,7 +10,8 @@ on: push: branches: [ main ] pull_request: - branches: [ main ] + # Allow CI to run on all PRs, not just ones targeting main. This allows + # stacked PRs to be tested. jobs: check-style: From e652c2cb62f140441cf69fbe6517eb5f9da1bd48 Mon Sep 17 00:00:00 2001 From: Rain Date: Fri, 20 Dec 2024 23:59:15 +0000 Subject: [PATCH 4/5] add APIs required by omicron Created using spr 1.3.6-beta.1 --- src/config/identifier.rs | 6 ++++++ src/package.rs | 14 +++++++++++++- tests/mod.rs | 6 +++--- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/config/identifier.rs b/src/config/identifier.rs index 07fc7a3..759217b 100644 --- a/src/config/identifier.rs +++ b/src/config/identifier.rs @@ -31,6 +31,12 @@ macro_rules! ident_newtype { pub fn as_str(&self) -> &str { self.0.as_str() } + + #[inline] + #[allow(dead_code)] + pub(crate) fn as_ident(&self) -> &ConfigIdent { + &self.0 + } } impl AsRef for $id { diff --git a/src/package.rs b/src/package.rs index 7444774..e926cc4 100644 --- a/src/package.rs +++ b/src/package.rs @@ -232,6 +232,11 @@ impl Package { output_directory.join(self.get_output_file(id)) } + /// The path of the service name with respect to the install directory. + pub fn get_output_path_for_service(&self, install_directory: &Utf8Path) -> Utf8PathBuf { + install_directory.join(self.get_output_file_for_service()) + } + /// The path of a package after it has been "stamped" with a version. pub fn get_stamped_output_path( &self, @@ -251,6 +256,13 @@ impl Package { } } + pub fn get_output_file_for_service(&self) -> String { + match self.output { + PackageOutput::Zone { .. } => format!("{}.tar.gz", self.service_name), + PackageOutput::Tarball => format!("{}.tar", self.service_name), + } + } + #[deprecated = "Use 'Package::create', which now takes a 'BuildConfig', and implements 'Default'"] pub async fn create_for_target( &self, @@ -647,7 +659,7 @@ impl Package { .context("Identifying all input paths")?; progress.increment_total(inputs.0.len() as u64); - let output_file = self.get_output_file(name); + let output_file = self.get_output_file(&name); let output_path = output_directory.join(&output_file); // Decide whether or not to use a cached copy of the zone package diff --git a/tests/mod.rs b/tests/mod.rs index d165fee..13d7541 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -75,7 +75,7 @@ mod test { .unwrap(); // Verify the contents - let path = package.get_output_path(&MY_SERVICE_PACKAGE, out.path()); + let path = package.get_output_path_for_service(out.path()); assert!(path.exists()); let gzr = flate2::read::GzDecoder::new(File::open(path).unwrap()); let mut archive = Archive::new(gzr); @@ -113,7 +113,7 @@ mod test { .unwrap(); // Verify the contents - let path = package.get_output_path(&MY_SERVICE_PACKAGE, out.path()); + let path = package.get_output_path_for_service(out.path()); assert!(path.exists()); let gzr = flate2::read::GzDecoder::new(File::open(path).unwrap()); let mut archive = Archive::new(gzr); @@ -155,7 +155,7 @@ mod test { .unwrap(); // Verify the contents - let path = package.get_output_path(&MY_SERVICE_PACKAGE, out.path()); + let path = package.get_output_path_for_service(out.path()); assert!(path.exists()); let mut archive = Archive::new(File::open(path).unwrap()); let mut ents = archive.entries().unwrap(); From 8747e427c62434f5a981fb5d2d143982f9a3612d Mon Sep 17 00:00:00 2001 From: Rain Date: Sat, 21 Dec 2024 00:00:32 +0000 Subject: [PATCH 5/5] clippy Created using spr 1.3.6-beta.1 --- src/package.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.rs b/src/package.rs index e926cc4..ee75b1a 100644 --- a/src/package.rs +++ b/src/package.rs @@ -659,7 +659,7 @@ impl Package { .context("Identifying all input paths")?; progress.increment_total(inputs.0.len() as u64); - let output_file = self.get_output_file(&name); + let output_file = self.get_output_file(name); let output_path = output_directory.join(&output_file); // Decide whether or not to use a cached copy of the zone package