Initial Dever 0.0.1
This commit is contained in:
commit
81233d098c
1479 files changed
+163782
No files matched your search
@@ -0,0 +1,160 @@
|
||||
use super::super::Directory;
|
||||
use dever::compiler::project::Project;
|
||||
use serde::Serialize;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::{Cursor, Write};
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Clone, Serialize)]
|
||||
pub(super) struct Entry {
|
||||
pub name: String,
|
||||
pub version: String,
|
||||
pub sha256: String,
|
||||
pub bytes: u64,
|
||||
pub dependencies: Vec<Dependency>,
|
||||
pub manifest_sha256: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize)]
|
||||
pub(super) struct Dependency {
|
||||
pub name: String,
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
pub(super) struct Fixture {
|
||||
pub directory: Directory,
|
||||
pub entries: Vec<Entry>,
|
||||
pub assets: BTreeMap<String, Vec<u8>>,
|
||||
}
|
||||
|
||||
impl Fixture {
|
||||
pub fn new(roots: &[&str]) -> Self {
|
||||
let directory = Directory::new();
|
||||
write(
|
||||
&directory.0,
|
||||
"config/setting.json",
|
||||
serde_json::to_vec(&serde_json::json!({
|
||||
"package":{"registry":"https://packages.example.test","use":roots}
|
||||
}))
|
||||
.unwrap(),
|
||||
);
|
||||
Self {
|
||||
directory,
|
||||
entries: Vec::new(),
|
||||
assets: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn package(&mut self, name: &str, dependencies: &[(&str, &str)], files: &[(&str, &str)]) {
|
||||
let manifest = serde_json::to_vec(&serde_json::json!({
|
||||
"format":"dever-package-v1", "name":name, "version":"1.0.0",
|
||||
"dependencies":dependencies.iter().copied().collect::<BTreeMap<_, _>>(), "lib":[]
|
||||
}))
|
||||
.unwrap();
|
||||
let mut zip = zip::ZipWriter::new(Cursor::new(Vec::new()));
|
||||
let options = zip::write::SimpleFileOptions::default()
|
||||
.compression_method(zip::CompressionMethod::Deflated);
|
||||
zip.start_file("dever-package.json", options).unwrap();
|
||||
zip.write_all(&manifest).unwrap();
|
||||
for &(path, text) in files {
|
||||
zip.start_file(path, options).unwrap();
|
||||
zip.write_all(text.as_bytes()).unwrap();
|
||||
}
|
||||
let bytes = zip.finish().unwrap().into_inner();
|
||||
let entry = Entry {
|
||||
name: name.into(),
|
||||
version: "1.0.0".into(),
|
||||
sha256: digest(&bytes),
|
||||
bytes: bytes.len() as u64,
|
||||
dependencies: dependencies
|
||||
.iter()
|
||||
.map(|(name, _)| Dependency {
|
||||
name: (*name).into(),
|
||||
version: "1.0.0".into(),
|
||||
})
|
||||
.collect(),
|
||||
manifest_sha256: digest(&manifest),
|
||||
};
|
||||
self.assets.insert(entry.sha256.clone(), bytes);
|
||||
self.entries.push(entry);
|
||||
self.lock();
|
||||
}
|
||||
|
||||
pub fn lock(&mut self) {
|
||||
#[derive(Serialize)]
|
||||
struct Lock<'entries> {
|
||||
format: &'static str,
|
||||
toolchain: &'static str,
|
||||
libs: Vec<()>,
|
||||
workers: Vec<()>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
packages: &'entries Vec<Entry>,
|
||||
}
|
||||
self.entries
|
||||
.sort_by(|left, right| left.name.cmp(&right.name));
|
||||
for entry in &mut self.entries {
|
||||
entry
|
||||
.dependencies
|
||||
.sort_by(|left, right| left.name.cmp(&right.name));
|
||||
}
|
||||
let lock = Lock {
|
||||
format: "dever-lock-v6",
|
||||
toolchain: env!("CARGO_PKG_VERSION"),
|
||||
libs: vec![],
|
||||
workers: vec![],
|
||||
packages: &self.entries,
|
||||
};
|
||||
write(
|
||||
&self.directory.0,
|
||||
"dever.lock",
|
||||
serde_json::to_string_pretty(&lock).unwrap() + "\n",
|
||||
);
|
||||
}
|
||||
|
||||
pub fn mutate_archive(&mut self, name: &str, change: impl FnOnce(&mut Vec<u8>)) {
|
||||
let entry = self
|
||||
.entries
|
||||
.iter_mut()
|
||||
.find(|entry| entry.name == name)
|
||||
.unwrap();
|
||||
let mut bytes = self.assets.remove(&entry.sha256).unwrap();
|
||||
change(&mut bytes);
|
||||
entry.sha256 = digest(&bytes);
|
||||
entry.bytes = bytes.len() as u64;
|
||||
self.assets.insert(entry.sha256.clone(), bytes);
|
||||
self.lock();
|
||||
}
|
||||
|
||||
pub fn load(&self) -> Result<Project, String> {
|
||||
Project::load_with_artifacts(&self.directory.0, |sha256, _| {
|
||||
self.assets
|
||||
.get(sha256)
|
||||
.cloned()
|
||||
.ok_or_else(|| "locked asset is missing".into())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn reject(&self, needle: &str) {
|
||||
let error = self.load().err().expect("invalid dependencies accepted");
|
||||
assert!(error.contains(needle), "expected {needle}: {error}");
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn digest(bytes: &[u8]) -> String {
|
||||
format!("{:x}", Sha256::digest(bytes))
|
||||
}
|
||||
|
||||
pub(super) fn write(root: &Path, relative: &str, contents: impl AsRef<[u8]>) {
|
||||
let path = root.join(relative);
|
||||
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
|
||||
std::fs::write(path, contents).unwrap();
|
||||
}
|
||||
|
||||
pub(super) fn app(expression: &str) -> String {
|
||||
format!("value(input: Int) (answer: Int) {{ answer = {expression} }}\n")
|
||||
}
|
||||
|
||||
pub(super) fn command() -> String {
|
||||
"cmd value = app.value\n".to_owned()
|
||||
}
|
||||
Reference in new issue
Block a user