//! 只在开发 Pod 执行:读取已安装工具,组装临时签名输入;不安装或激活软件。 use super::{ Fixture, fixture::{archive, hash, signed}, }; use serde_json::json; use std::{collections::BTreeMap, fs, path::Path, process::Command}; pub(super) fn prepare(fixture: &mut Fixture) { let target = fixture.target.name(); let mut assets = BTreeMap::new(); let mut dependencies = BTreeMap::new(); let node = Path::new("/usr/local/bin/node"); let python = Path::new("/usr/bin/python3"); let node_bytes = fs::read(node).expect("Node must already exist in the development Pod"); let python_bytes = fs::read(python).expect("Python must already exist in the development Pod"); libraries(node, &mut dependencies); libraries(python, &mut dependencies); let markers = json!({"implementation_name":"cpython","implementation_version":"3.13.0","os_name":"posix","platform_machine":"x86_64","platform_python_implementation":"CPython","platform_release":"","platform_system":"Linux","platform_version":"","python_full_version":"3.13.0","python_version":"3.13","sys_platform":"linux"}); let node_pack=archive(&BTreeMap::from([ ("bin/node".into(),node_bytes), ("shared.txt".into(),b"shared runtime fixture".to_vec()), ("dever-runtime.json".into(),serde_json::to_vec(&json!({"format":"dever-worker-runtime-v1","ecosystem":"npm","target":target,"executable":"bin/node","arguments":[],"build":null,"python_wheel_tags":[],"python_extension_suffixes":[],"python_markers":null})).unwrap()), ])); let python_pack=archive(&BTreeMap::from([ ("bin/python3".into(),python_bytes), ("shared.txt".into(),b"shared runtime fixture".to_vec()), ("dever-runtime.json".into(),serde_json::to_vec(&json!({"format":"dever-worker-runtime-v1","ecosystem":"pip","target":target,"executable":"bin/python3","arguments":["-I","-S","-B"],"build":null,"python_wheel_tags":["py3-none-any"],"python_extension_suffixes":[".cpython-313-x86_64-linux-gnu.so"],"python_markers":markers})).unwrap()), ])); fixture.metadata.pack.sha256 = hash(&node_pack); fixture.metadata.pack.version = "24.21.0".into(); let python_identity = json!({"name":"python","version":"3.13.0","sha256":hash(&python_pack)}); let mut tools = BTreeMap::new(); let mut executables = Vec::new(); for (name, path) in [ ("sh", "/bin/sh"), ("cc", "/usr/bin/cc"), ("c++", "/usr/bin/c++"), ("as", "/usr/bin/as"), ("ld", "/usr/bin/ld"), ("ar", "/usr/bin/ar"), ("ranlib", "/usr/bin/ranlib"), ("make", "/usr/bin/make"), ("cc1", "/usr/libexec/gcc/x86_64-linux-gnu/14/cc1"), ("collect2", "/usr/libexec/gcc/x86_64-linux-gnu/14/collect2"), ] { let path = Path::new(path); libraries(path, &mut dependencies); let destination = format!("rootfs/usr/bin/{name}"); tools.insert(destination.clone(), fs::read(path).unwrap()); executables.push(destination); } files( Path::new("/usr/local/lib/node_modules/npm"), "npm/frontend/node_modules/npm/", &mut tools, ); tools.insert( "rootfs/usr/bin/fixture-node".into(), b"#!/usr/bin/env node\nprocess.stdout.write('signed script');\n".to_vec(), ); executables.push("rootfs/usr/bin/fixture-node".into()); tools.insert("dever-build.json".into(),serde_json::to_vec(&json!({"format":"dever-lib-build-v1","ecosystem":"npm","target":target,"runtime_sha256":fixture.metadata.pack.sha256,"python_runtime_sha256":python_identity["sha256"],"executables":executables})).unwrap()); let tools_pack = archive(&tools); assets.insert(format!("build/npm/{target}/manifest.json"),serde_json::to_vec(&json!({"format":"dever-registry-build-v1","ecosystem":"npm","target":target,"runtime_sha256":fixture.metadata.pack.sha256,"python_runtime_sha256":python_identity["sha256"],"sha256":hash(&tools_pack)})).unwrap()); assets.insert(format!("build/npm/{target}/build.pack"), tools_pack); assets.insert(format!("runtime/npm/{target}/runtime.pack"), node_pack); assets.insert(format!("runtime/pip/{target}/runtime.pack"), python_pack); assets.insert(format!("runtime/npm/{target}/manifest.json"),serde_json::to_vec(&json!({"format":"dever-registry-runtime-v1","runtime":{"pack":fixture.metadata.pack,"target":target,"python_markers":null,"python_wheel_tags":[],"npm_libc":"glibc"}})).unwrap()); assets.insert(format!("runtime/pip/{target}/manifest.json"),serde_json::to_vec(&json!({"format":"dever-registry-runtime-v1","runtime":{"pack":python_identity,"target":target,"python_markers":markers,"python_wheel_tags":["py3-none-any"]}})).unwrap()); for (name, bytes) in dependencies { assets.insert(format!("process-runtime/{target}/lib/{name}"), bytes); } fixture.signed = signed(&fixture.directory, &assets); } fn files(root: &Path, prefix: &str, output: &mut BTreeMap>) { for entry in fs::read_dir(root).unwrap() { let entry = entry.unwrap(); let name = entry.file_name().into_string().unwrap(); let kind = entry.file_type().unwrap(); if kind.is_dir() { files(&entry.path(), &format!("{prefix}{name}/"), output); } else if kind.is_file() { output.insert(format!("{prefix}{name}"), fs::read(entry.path()).unwrap()); } } } fn libraries(program: &Path, files: &mut BTreeMap>) { let output = Command::new("/usr/bin/ldd").arg(program).output().unwrap(); assert!( output.status.success(), "ldd fixture input {}", program.display() ); for path in String::from_utf8(output.stdout) .unwrap() .split_whitespace() .filter(|value| value.starts_with('/')) { let path = Path::new(path); let name = path.file_name().unwrap().to_str().unwrap().to_owned(); let bytes = fs::read(path).unwrap(); if let Some(previous) = files.insert(name, bytes.clone()) { assert_eq!(previous, bytes); } } }