mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-14 19:26:56 -04:00
refactor(pdf): use shared writer for export and print (PDF.W1)
This commit is contained in:
1 parent
ba5447bbd9
commit
a699a26221
24 files changed
+235
-54
No files matched your search
+5
-1
@@ -9,6 +9,7 @@ mod brands;
|
||||
mod bundle;
|
||||
mod ico;
|
||||
mod layers;
|
||||
mod pdf_deps;
|
||||
mod pngsuite;
|
||||
mod sha256;
|
||||
mod stats;
|
||||
@@ -24,9 +25,10 @@ usage: cargo xtask <command>
|
||||
commands:
|
||||
assets check that every icon/image/font/asset is attributed in ASSETS.md
|
||||
brands check that user-visible text (labels, params docs, MCP, docs, packaging) names no other vendor's products
|
||||
pdf-deps verify immutable shared PDF writer and patched Krilla sources
|
||||
layers enforce the crate dependency layering (plan/architecture.md §3)
|
||||
wasm cargo check --target wasm32-unknown-unknown for the wasm-safe crates
|
||||
ci fmt --check, clippy -D warnings, test, assets, brands, layers, wasm (stops at first failure)
|
||||
ci fmt --check, clippy -D warnings, test, pdf-deps, assets, brands, layers, wasm (stops at first failure)
|
||||
corpus [--download] [--affinity]
|
||||
show where test corpora live; --download fetches PngSuite into corpus/pngsuite,
|
||||
--affinity the pinned public Affinity documents into corpus/affinity
|
||||
@@ -45,6 +47,7 @@ fn main() -> ExitCode {
|
||||
Some("assets") => assets::run(&root()),
|
||||
Some("brands") => brands::run(&root()),
|
||||
Some("layers") => cmd_layers(),
|
||||
Some("pdf-deps") => pdf_deps::run(&root()),
|
||||
Some("wasm") => cmd_wasm(),
|
||||
Some("ci") => cmd_ci(),
|
||||
Some("corpus") if rest.contains(&"--affinity") => affinity_corpus::fetch(),
|
||||
@@ -200,6 +203,7 @@ fn cmd_ci() -> Result<(), String> {
|
||||
run(c, "cargo test --workspace")
|
||||
}),
|
||||
),
|
||||
("pdf-deps", Box::new(|| pdf_deps::run(&root()))),
|
||||
("assets", Box::new(|| assets::run(&root()))),
|
||||
("brands", Box::new(|| brands::run(&root()))),
|
||||
("layers", Box::new(cmd_layers)),
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
//! Verify that PDF writing uses one immutable shared crate and its patched writer backend.
|
||||
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
const REV: &str = "c3487320b2d1de657b860b3c8abb44e1f2b32bd8";
|
||||
const PACKAGES: &[(&str, &str)] = &[("craft-pdf", "0.1.0"), ("krilla", "0.8.2")];
|
||||
|
||||
pub fn run(root: &Path) -> Result<(), String> {
|
||||
let output = Command::new(std::env::var_os("CARGO").unwrap_or_else(|| "cargo".into()))
|
||||
.current_dir(root)
|
||||
.args(["metadata", "--locked", "--format-version", "1"])
|
||||
.output()
|
||||
.map_err(|e| format!("cargo metadata: {e}"))?;
|
||||
if !output.status.success() {
|
||||
return Err(format!("cargo metadata: {}", String::from_utf8_lossy(&output.stderr)));
|
||||
}
|
||||
let metadata: Value = serde_json::from_slice(&output.stdout).map_err(|e| format!("cargo metadata: {e}"))?;
|
||||
validate(&metadata)?;
|
||||
println!("PDF writer: shared crate and patched backend resolve once to {REV}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate(metadata: &Value) -> Result<(), String> {
|
||||
let packages = metadata.get("packages").and_then(Value::as_array).ok_or("cargo metadata has no packages")?;
|
||||
let source = format!("git+https://github.com/storytold/craft-libs?rev={REV}#{REV}");
|
||||
for &(name, version) in PACKAGES {
|
||||
let mut found = packages.iter().filter(|p| p.get("name").and_then(Value::as_str) == Some(name));
|
||||
let package = found.next().ok_or_else(|| format!("{name}: missing resolved package"))?;
|
||||
if found.next().is_some() {
|
||||
return Err(format!("{name}: expected one resolved package"));
|
||||
}
|
||||
if package.get("version").and_then(Value::as_str) != Some(version) || package.get("source").and_then(Value::as_str) != Some(source.as_str()) {
|
||||
return Err(format!("{name}: expected {version} from {source}; got {package}"));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_json::json;
|
||||
|
||||
fn metadata() -> Value {
|
||||
let packages: Vec<_> = PACKAGES
|
||||
.iter()
|
||||
.map(|(name, version)| {
|
||||
json!({
|
||||
"name":name, "version":version,
|
||||
"source":format!("git+https://github.com/storytold/craft-libs?rev={REV}#{REV}")
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
json!({"packages": packages})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accepts_the_pinned_writer_without_changing_reader_sources() {
|
||||
let mut m = metadata();
|
||||
m["packages"]
|
||||
.as_array_mut()
|
||||
.unwrap()
|
||||
.push(json!({"name":"hayro-syntax", "version":"0.7.2", "source":"registry+https://github.com/rust-lang/crates.io-index"}));
|
||||
assert!(validate(&m).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_missing_or_duplicate_writer_packages() {
|
||||
for index in 0..PACKAGES.len() {
|
||||
let mut m = metadata();
|
||||
m["packages"].as_array_mut().unwrap().remove(index);
|
||||
assert!(validate(&m).is_err());
|
||||
let mut m = metadata();
|
||||
let duplicate = m["packages"][index].clone();
|
||||
m["packages"].as_array_mut().unwrap().push(duplicate);
|
||||
assert!(validate(&m).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_registry_local_version_and_revision_drift() {
|
||||
for index in 0..PACKAGES.len() {
|
||||
for (field, value) in [
|
||||
("source", Value::Null),
|
||||
("source", json!("registry+https://github.com/rust-lang/crates.io-index")),
|
||||
("source", json!("git+https://github.com/storytold/craft-libs?branch=main#other")),
|
||||
("version", json!("0.99.0")),
|
||||
] {
|
||||
let mut m = metadata();
|
||||
m["packages"][index][field] = value;
|
||||
assert!(validate(&m).is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user