Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions crates/ployz-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,11 @@ pub struct BuiltImage {
}

impl BuiltImage {
/// Name this manifest in the repository used by its Build.
/// Name this manifest in the caller's requested repository.
/// # Errors
/// Rejects missing or malformed repository evidence.
pub fn repository_reference(&self) -> Result<String, BuildError> {
let tag = self
.tags
.first()
.ok_or_else(|| BuildError::Result("Build image has no tags".into()))?;
let reference = tag
/// Rejects malformed repository references.
pub fn repository_reference(&self, image: &str) -> Result<String, BuildError> {
let reference = image
.parse::<oci_client::Reference>()
.map_err(|error| BuildError::Result(error.to_string()))?;
Ok(format!(
Expand Down
14 changes: 14 additions & 0 deletions crates/ployz-build/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,3 +552,17 @@ exit 0
);
std::fs::remove_dir_all(directory).unwrap();
}

#[test]
fn repository_reference_rejects_a_malformed_service_image() {
let image = BuiltImage {
reference: format!("sha256:{}", "1".repeat(64)),
tags: vec!["example.test/api:latest".into()],
platforms: vec!["linux/amd64".into()],
location: "unix:///var/run/docker.sock".into(),
};
assert!(matches!(
image.repository_reference("not a repository"),
Err(BuildError::Result(_))
));
}
2 changes: 1 addition & 1 deletion crates/ployz/src/compose/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,7 @@ fn ssh_paths(key: &Value) -> Result<(&str, &str), ComposeError> {
})
}

fn is_remote_context(source: &str) -> bool {
pub(super) fn is_remote_context(source: &str) -> bool {
source.contains("://") || source.starts_with("git@") || source.starts_with("service:")
}

Expand Down
83 changes: 2 additions & 81 deletions crates/ployz/src/compose/build_inputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ use sha2::{Digest as _, Sha256};

use super::ComposeError;

mod service;

/// Private, attempt-scoped copies. Never persisted as deployment history.
pub(super) struct BuildInputs {
root: PathBuf,
Expand Down Expand Up @@ -124,51 +126,6 @@ impl BuildInputs {
})
}

/// Isolate one target's generated recipe while retaining captured bytes.
pub(super) fn for_service(&self, name: &str) -> Result<Self, ComposeError> {
let inputs = Self::new()?;
// ponytail: copy the already-filtered capture per remote target. Select
// per-target source trees if large multi-Service captures become costly.
for area in ["source", "private"] {
let source = self.root.join(area);
for entry in entries(&source, &source, None).map_err(input_error)? {
copy(
&entry,
&inputs
.root
.join(area)
.join(entry.file_name().expect("entry")),
&source,
None,
)
.map_err(input_error)?;
}
}
let metadata = inputs.root.join("private/railpack.json");
if metadata.exists() {
let mut recipes: Vec<ployz_build::Railpack> =
serde_json::from_slice(&fs::read(&metadata).map_err(input_error)?)
.map_err(|error| ComposeError::Invalid(error.to_string()))?;
recipes.retain(|recipe| recipe.name == name);
fs::remove_file(metadata).map_err(input_error)?;
inputs.railpack(&recipes)?;
}
let mut recipe: serde_norway::Value = serde_norway::from_slice(
&fs::read(self.root.join("compose.yaml")).map_err(input_error)?,
)
.map_err(|error| ComposeError::Invalid(error.to_string()))?;
recipe
.get_mut("services")
.and_then(serde_norway::Value::as_mapping_mut)
.ok_or_else(|| ComposeError::Invalid("captured Build has no services".into()))?
.retain(|key, _| key.as_str() == Some(name));
inputs.compose(
&serde_norway::to_string(&recipe)
.map_err(|error| ComposeError::Invalid(error.to_string()))?,
)?;
Ok(inputs)
}

/// Copy a source once, rejecting edits observed during the copy.
///
/// # Errors
Expand Down Expand Up @@ -675,42 +632,6 @@ fn validate_link(path: &Path, root: &Path, selection: Option<&Selection>) -> io:
mod tests {
use super::*;

#[test]
fn per_service_capture_keeps_only_its_railpack_recipe() {
let inputs = BuildInputs::new().unwrap();
inputs
.compose("services: {api: {build: .}, web: {build: .}, base: {build: .}}\n")
.unwrap();
inputs
.railpack(&["api", "web"].map(|name| ployz_build::Railpack {
name: name.into(),
context: "source".into(),
variables: BTreeMap::new(),
refresh_cache: false,
}))
.unwrap();
for name in ["api", "web", "base"] {
let selected = inputs.for_service(name).unwrap();
let metadata = selected.root().join("private/railpack.json");
if name == "base" {
assert!(!metadata.exists());
} else {
let recipes: Vec<ployz_build::Railpack> =
serde_json::from_slice(&fs::read(metadata).unwrap()).unwrap();
assert_eq!(recipes.len(), 1);
assert_eq!(recipes.first().unwrap().name, name);
}
}
let original: Vec<ployz_build::Railpack> =
serde_json::from_slice(&fs::read(inputs.root().join("private/railpack.json")).unwrap())
.unwrap();
assert_eq!(
original.len(),
2,
"per-target selection changed the original capture"
);
}

use std::os::unix::net::UnixListener;

#[test]
Expand Down
Loading
Loading