Initial Dever 0.0.1
This commit is contained in:
commit
81233d098c
1479 files changed
+163782
No files matched your search
@@ -0,0 +1,195 @@
|
||||
use super::super::super::Directory;
|
||||
use base64::{Engine, engine::general_purpose::STANDARD};
|
||||
use dever::compiler::{
|
||||
project::dependency::{
|
||||
Lock, Store,
|
||||
library::{self, Spec, registry::Transport, runtime},
|
||||
worker::signed::SignedResources,
|
||||
},
|
||||
toolchain::BuildTarget,
|
||||
};
|
||||
use ring::signature::{Ed25519KeyPair, KeyPair};
|
||||
use serde_json::{Value, json};
|
||||
use sha2::{Digest, Sha256, Sha512};
|
||||
use std::{cell::RefCell, collections::BTreeMap, io::Cursor};
|
||||
|
||||
pub(super) fn hash(bytes: &[u8]) -> String {
|
||||
format!("{:x}", Sha256::digest(bytes))
|
||||
}
|
||||
|
||||
pub(super) fn archive(files: &BTreeMap<String, Vec<u8>>) -> Vec<u8> {
|
||||
let gzip = flate2::GzBuilder::new()
|
||||
.mtime(0)
|
||||
.write(Vec::new(), flate2::Compression::fast());
|
||||
let mut builder = tar::Builder::new(gzip);
|
||||
for (path, bytes) in files {
|
||||
let mut header = tar::Header::new_gnu();
|
||||
header.set_mode(if bytes.starts_with(b"#!") {
|
||||
0o755
|
||||
} else {
|
||||
0o644
|
||||
});
|
||||
header.set_size(bytes.len() as u64);
|
||||
header.set_cksum();
|
||||
builder
|
||||
.append_data(&mut header, path, Cursor::new(bytes))
|
||||
.unwrap();
|
||||
}
|
||||
builder.into_inner().unwrap().finish().unwrap()
|
||||
}
|
||||
|
||||
pub(super) struct Fixture {
|
||||
pub directory: Directory,
|
||||
pub documents: BTreeMap<String, Vec<u8>>,
|
||||
pub cache: RefCell<BTreeMap<String, Vec<u8>>>,
|
||||
pub reads: RefCell<Vec<(String, usize)>>,
|
||||
pub calls: RefCell<Vec<String>>,
|
||||
pub metadata: runtime::Metadata,
|
||||
pub target: BuildTarget,
|
||||
pub signed: SignedResources,
|
||||
pub lock: Lock,
|
||||
}
|
||||
|
||||
impl Fixture {
|
||||
pub fn new() -> Self {
|
||||
let directory = Directory::new();
|
||||
let target = BuildTarget::host().unwrap();
|
||||
let metadata = json!({"pack":{"name":"node","version":"22.1.0","sha256":hash(b"node pack")},"target":target.name(),"python_markers":null,"python_wheel_tags":[],"npm_libc":"glibc"});
|
||||
let signed = signed(
|
||||
&directory,
|
||||
&BTreeMap::from([(
|
||||
format!("runtime/npm/{}/manifest.json", target.name()),
|
||||
serde_json::to_vec(
|
||||
&json!({"format":"dever-registry-runtime-v1","runtime":metadata}),
|
||||
)
|
||||
.unwrap(),
|
||||
)]),
|
||||
);
|
||||
Self {
|
||||
directory,
|
||||
documents: BTreeMap::new(),
|
||||
cache: RefCell::new(BTreeMap::new()),
|
||||
reads: RefCell::new(vec![]),
|
||||
calls: RefCell::new(vec![]),
|
||||
metadata: serde_json::from_value(metadata).unwrap(),
|
||||
target,
|
||||
signed,
|
||||
lock: Lock::new(vec![]),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn package(&mut self, document: Value, extra: BTreeMap<String, Vec<u8>>) {
|
||||
let name = document["name"].as_str().unwrap();
|
||||
let version = document["version"].as_str().unwrap();
|
||||
let base = format!("https://registry.npmjs.org/{name}");
|
||||
let locator = format!("{base}/-/archive-{version}.tgz");
|
||||
let mut files = extra;
|
||||
files.insert(
|
||||
"package/package.json".into(),
|
||||
serde_json::to_vec(&document).unwrap(),
|
||||
);
|
||||
files.insert("package/index.js".into(), b"module.exports = 42;".to_vec());
|
||||
let bytes = archive(&files);
|
||||
let mut metadata = document.clone();
|
||||
metadata["dist"] = json!({"tarball":locator,"integrity":format!("sha512-{}",STANDARD.encode(Sha512::digest(&bytes)))});
|
||||
let mut index: Value = self
|
||||
.documents
|
||||
.get(&base)
|
||||
.map(|bytes| serde_json::from_slice(bytes).unwrap())
|
||||
.unwrap_or_else(|| json!({"name":name,"versions":{}}));
|
||||
index["versions"][version] = metadata.clone();
|
||||
self.documents
|
||||
.insert(base.clone(), serde_json::to_vec(&index).unwrap());
|
||||
self.documents.insert(
|
||||
format!("{base}/{version}"),
|
||||
serde_json::to_vec(&metadata).unwrap(),
|
||||
);
|
||||
self.documents.insert(locator, bytes);
|
||||
}
|
||||
|
||||
pub fn resolve(&mut self, roots: &[&str]) -> Result<(), String> {
|
||||
let specs = roots
|
||||
.iter()
|
||||
.map(|value| value.parse::<Spec>())
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let mut lock = self.lock.clone();
|
||||
library::npm::resolve(&specs, self.target, &self.metadata, self, self, &mut lock)?;
|
||||
self.lock = lock;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn graph(&self) -> library::npm::Environment {
|
||||
serde_json::from_value(self.lock.npm[0].clone()).unwrap()
|
||||
}
|
||||
|
||||
pub fn install(&self) -> Result<BTreeMap<String, Vec<u8>>, String> {
|
||||
library::npm::install(
|
||||
&self.lock,
|
||||
&self.graph().roots,
|
||||
self.target,
|
||||
self,
|
||||
&self.signed,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Transport for Fixture {
|
||||
fn get(&self, url: &str, limit: usize) -> Result<Vec<u8>, String> {
|
||||
library::registry::official(url)?;
|
||||
self.calls.borrow_mut().push(url.into());
|
||||
let bytes = self
|
||||
.documents
|
||||
.get(url)
|
||||
.ok_or_else(|| "registry returned HTTP 404".to_owned())?;
|
||||
assert!(bytes.len() <= limit);
|
||||
Ok(bytes.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Store for Fixture {
|
||||
fn get(&self, digest: &str, _: u64) -> Result<Option<Vec<u8>>, String> {
|
||||
let bytes = self.cache.borrow().get(digest).cloned();
|
||||
self.reads
|
||||
.borrow_mut()
|
||||
.push((digest.into(), bytes.as_ref().map_or(0, Vec::len)));
|
||||
Ok(bytes)
|
||||
}
|
||||
fn put(&self, bytes: &[u8]) -> Result<(), String> {
|
||||
self.cache.borrow_mut().insert(hash(bytes), bytes.to_vec());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn signed(directory: &Directory, files: &BTreeMap<String, Vec<u8>>) -> SignedResources {
|
||||
let root = directory.0.join("signed");
|
||||
let key = Ed25519KeyPair::from_seed_unchecked(&[72; 32]).unwrap();
|
||||
let hex = |bytes: &[u8]| {
|
||||
bytes
|
||||
.iter()
|
||||
.map(|byte| format!("{byte:02x}"))
|
||||
.collect::<String>()
|
||||
};
|
||||
let write = |path: &str, bytes: &[u8]| {
|
||||
let path = root.join(path);
|
||||
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
|
||||
std::fs::write(path, bytes).unwrap();
|
||||
};
|
||||
write(
|
||||
"state/trusted-release-key",
|
||||
hex(key.public_key().as_ref()).as_bytes(),
|
||||
);
|
||||
let mut artifacts = vec![json!({"path":"base.txt","bytes":4,"sha256":hash(b"base")})];
|
||||
let target = BuildTarget::host().unwrap();
|
||||
for (path, bytes) in files {
|
||||
artifacts.push(json!({"path":path,"bytes":bytes.len(),"sha256":hash(bytes)}));
|
||||
write(&format!("versions/0.0.1/{path}"), bytes);
|
||||
}
|
||||
write("versions/0.0.1/base.txt", b"base");
|
||||
let catalog=serde_json::to_vec(&json!({"format":"dever-release-v2","version":"0.0.1","platform":target.name(),"artifacts":artifacts,"extensions":[]})).unwrap();
|
||||
write("versions/0.0.1/manifest.json", &catalog);
|
||||
write(
|
||||
"versions/0.0.1/manifest.sig",
|
||||
hex(key.sign(&catalog).as_ref()).as_bytes(),
|
||||
);
|
||||
SignedResources::load(&root, "0.0.1").unwrap()
|
||||
}
|
||||
Reference in new issue
Block a user