feat: ship slim releases with shared on-demand extensions and locked restore
This commit is contained in:
1 parent
83b78a0db6
commit
4fda7c8c1a
58 files changed
+3774
-425
No files matched your search
@@ -358,6 +358,56 @@ fn install_release(layout: &Layout, version: &Version, key: &Ed25519KeyPair) {
|
||||
MachineManager::new(layout.clone())
|
||||
.install_requested(version.as_str())
|
||||
.unwrap();
|
||||
// These opt-in whole-release fixtures explicitly prepare every declared resource.
|
||||
// Product installation only installs the base; each preparation still exercises
|
||||
// the ordinary signed extraction and immutable extension publication owner.
|
||||
struct PreparedInputs(PathBuf);
|
||||
impl dever_cli::toolchain::ExtensionSource for PreparedInputs {
|
||||
fn open(
|
||||
&self,
|
||||
_version: &Version,
|
||||
id: &dever_cli::toolchain::ExtensionId,
|
||||
) -> Result<Box<dyn std::io::Read>, String> {
|
||||
let catalog: dever_cli::toolchain::ReleaseManifest = serde_json::from_slice(
|
||||
&fs::read(self.0.join("manifest.json")).map_err(|error| error.to_string())?,
|
||||
)
|
||||
.map_err(|error| error.to_string())?;
|
||||
let extension = catalog
|
||||
.extensions
|
||||
.iter()
|
||||
.find(|extension| extension.id() == *id)
|
||||
.ok_or("fixture extension is undeclared")?;
|
||||
let mut encoder = zstd::stream::write::Encoder::new(Vec::new(), 1)
|
||||
.map_err(|error| error.to_string())?;
|
||||
encoder
|
||||
.include_checksum(true)
|
||||
.map_err(|error| error.to_string())?;
|
||||
let mut archive = tar::Builder::new(encoder);
|
||||
for artifact in &extension.artifacts {
|
||||
let mut header = tar::Header::new_ustar();
|
||||
header.set_size(artifact.bytes);
|
||||
header.set_mode(0o644);
|
||||
header.set_cksum();
|
||||
let file = fs::File::open(self.0.join(&artifact.path))
|
||||
.map_err(|error| error.to_string())?;
|
||||
archive
|
||||
.append_data(&mut header, &artifact.path, file)
|
||||
.map_err(|error| error.to_string())?;
|
||||
}
|
||||
let bytes = archive
|
||||
.into_inner()
|
||||
.map_err(|error| error.to_string())?
|
||||
.finish()
|
||||
.map_err(|error| error.to_string())?;
|
||||
Ok(Box::new(std::io::Cursor::new(bytes)))
|
||||
}
|
||||
}
|
||||
let resources = dever_cli::toolchain::SignedResources::load(layout, version).unwrap();
|
||||
let source = PreparedInputs(layout.downloads().join(version.as_str()));
|
||||
for extension in &resources.manifest().extensions {
|
||||
dever_cli::toolchain::prepare_extension_with(layout, version, &extension.id(), &source)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn archive_report(workspace: &Path) -> Value {
|
||||
|
||||
@@ -3,7 +3,7 @@ use super::*;
|
||||
use dever_cli::libs::{
|
||||
self, LibSpec, LockFile, LockedArtifact, LockedLib, LockedWorker, RegistryRuntime,
|
||||
};
|
||||
use dever_cli::toolchain::{Artifact, ReleaseManifest};
|
||||
use dever_cli::toolchain::{Artifact, Extension, ExtensionKind, ReleaseManifest};
|
||||
use dever_core::hir::ExternalWorkerContract;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::collections::BTreeMap;
|
||||
@@ -68,6 +68,7 @@ fn sign_target_runtimes(
|
||||
serde_json::to_vec(&json!({"format":"dever-registry-runtime-v1","runtime":runtime}))
|
||||
.unwrap(),
|
||||
);
|
||||
let mut artifacts = Vec::new();
|
||||
for leaf in ["manifest.json", "runtime.pack"] {
|
||||
let path = format!("{prefix}/{leaf}");
|
||||
assert!(
|
||||
@@ -76,17 +77,21 @@ fn sign_target_runtimes(
|
||||
.iter()
|
||||
.any(|artifact| artifact.path == path)
|
||||
);
|
||||
manifest.artifacts.push(Artifact {
|
||||
artifacts.push(Artifact {
|
||||
bytes: fs::metadata(release.join(&path)).unwrap().len(),
|
||||
sha256: sha256_file(&release.join(&path)).unwrap(),
|
||||
path,
|
||||
});
|
||||
}
|
||||
manifest.extensions.push(Extension {
|
||||
kind: ExtensionKind::Runtime(ecosystem.parse().unwrap()),
|
||||
target: TARGET,
|
||||
artifacts,
|
||||
});
|
||||
runtimes.insert(ecosystem.to_owned(), runtime);
|
||||
}
|
||||
manifest
|
||||
.artifacts
|
||||
.sort_by(|left, right| left.path.cmp(&right.path));
|
||||
manifest.extensions.sort_by_key(Extension::id);
|
||||
dever_cli::toolchain::validate_catalog(&manifest).unwrap();
|
||||
let encoded = serde_json::to_vec(&manifest).unwrap();
|
||||
fs::write(release.join("manifest.json"), &encoded).unwrap();
|
||||
fs::write(
|
||||
@@ -167,6 +172,7 @@ fn pure_package_lock(
|
||||
.unwrap();
|
||||
let sha256 = digest(&bytes);
|
||||
let artifact = LockedArtifact {
|
||||
source: None,
|
||||
target: TARGET.platform().into(),
|
||||
path: format!(
|
||||
"lib/{}/{}/{}/archive.{extension}",
|
||||
|
||||
@@ -121,8 +121,9 @@ fn sign_build_runtimes(
|
||||
for suffix in ["runtime.pack", "manifest.json"] {
|
||||
let name = format!("{prefix}/{suffix}");
|
||||
let artifact = manifest
|
||||
.artifacts
|
||||
.extensions
|
||||
.iter_mut()
|
||||
.flat_map(|extension| &mut extension.artifacts)
|
||||
.find(|artifact| artifact.path == name)
|
||||
.unwrap();
|
||||
artifact.bytes = fs::metadata(release.join(&name)).unwrap().len();
|
||||
@@ -311,8 +312,9 @@ fn signed_ecosystems_build_and_run_without_system_language_installations() {
|
||||
for ecosystem in ECOSYSTEMS {
|
||||
let path = format!("runtime/{ecosystem}/linux-x86_64/runtime.pack");
|
||||
let artifact = signed
|
||||
.artifacts
|
||||
.extensions
|
||||
.iter()
|
||||
.flat_map(|extension| &extension.artifacts)
|
||||
.find(|artifact| artifact.path == path)
|
||||
.unwrap();
|
||||
runtimes.insert(
|
||||
|
||||
@@ -148,8 +148,9 @@ fn ecosystem_archives_are_deterministic_and_signed_with_computed_identities() {
|
||||
);
|
||||
for path in [&metadata_path, &pack_path] {
|
||||
let signed = manifest
|
||||
.artifacts
|
||||
.extensions
|
||||
.iter()
|
||||
.flat_map(|extension| &extension.artifacts)
|
||||
.find(|artifact| &artifact.path == path)
|
||||
.unwrap();
|
||||
assert_eq!(signed.sha256, sha256_file(&first.join(path)).unwrap());
|
||||
@@ -286,8 +287,9 @@ fn go_cross_pack_binds_host_tools_and_arm_standard_library_separately() {
|
||||
let manifest = result.unwrap();
|
||||
assert!(
|
||||
manifest
|
||||
.artifacts
|
||||
.extensions
|
||||
.iter()
|
||||
.flat_map(|extension| &extension.artifacts)
|
||||
.any(|file| file.path == "runtime/go/linux-aarch64/runtime.pack")
|
||||
);
|
||||
}
|
||||
@@ -295,6 +297,7 @@ fn go_cross_pack_binds_host_tools_and_arm_standard_library_separately() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn sandbox_cross_assets_preserve_loader_mode_and_validate_deployment_target() {
|
||||
let mut files = vec![
|
||||
("bin/bwrap".into(), native_elf::static_executable()),
|
||||
@@ -312,7 +315,7 @@ fn sandbox_cross_assets_preserve_loader_mode_and_validate_deployment_target() {
|
||||
bytes[18..20].copy_from_slice(&183u16.to_le_bytes());
|
||||
}
|
||||
dever_sandbox::validate_assets_for_target(&files, "linux-aarch64").unwrap();
|
||||
let mut author = Author::new();
|
||||
let mut author = super::targets::cross_author();
|
||||
let inputs = files
|
||||
.iter()
|
||||
.map(|(path, bytes)| {
|
||||
|
||||
@@ -3,7 +3,7 @@ use dever_cli::toolchain::runtime_pack::RuntimePack;
|
||||
use dever_runtime::config::RuntimeProfile;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn cross_author() -> Author {
|
||||
pub(super) fn cross_author() -> Author {
|
||||
let mut author = Author::new();
|
||||
let target = BuildTarget::LinuxAarch64;
|
||||
let input = |name: &str, bytes: Vec<u8>| {
|
||||
@@ -80,6 +80,12 @@ fn host_core_packages_both_native_targets_with_separate_profiles_and_signed_clos
|
||||
manifest
|
||||
.artifacts
|
||||
.iter()
|
||||
.chain(
|
||||
manifest
|
||||
.extensions
|
||||
.iter()
|
||||
.flat_map(|extension| &extension.artifacts)
|
||||
)
|
||||
.any(|artifact| artifact.path == input.path
|
||||
&& artifact.sha256 == input.sha256
|
||||
&& artifact.bytes == input.bytes)
|
||||
|
||||
Reference in new issue
Block a user