mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-31 21:56:50 -06:00
Merge branch 'print-color' into print-color-x1a
# Conflicts: # Cargo.lock # Cargo.toml # xtask/src/pdf_deps.rs
This commit is contained in:
+52
-25
@@ -12,7 +12,7 @@ mod stats;
|
||||
mod version;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, ExitCode};
|
||||
use std::process::{Command, ExitCode, Stdio};
|
||||
|
||||
const USAGE: &str = "\
|
||||
usage: cargo xtask <command>
|
||||
@@ -20,12 +20,14 @@ usage: cargo xtask <command>
|
||||
commands:
|
||||
assets check that every icon/image/font/asset is attributed in ASSETS.md
|
||||
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, layers, wasm (stops at first failure)
|
||||
pdf-deps verify the pinned PDF backend, including Krilla dependencies
|
||||
wasm cargo check --target wasm32-unknown-unknown for the wasm-safe crates (one call)
|
||||
test workspace tests (cargo nextest when installed, else cargo test), then doctests
|
||||
ci fmt --check, pdf-deps, clippy -D warnings, test, doctest, assets, layers, wasm
|
||||
(stops at first failure)
|
||||
corpus [--download]
|
||||
show where test corpora live; --download fetches PngSuite into corpus/pngsuite
|
||||
stats [--exact] count tests and lines per crate (--exact: ask the test harness via `-- --list`)
|
||||
pdf-deps verify the pinned shared PDF writer and patched Krilla
|
||||
parity recompute the InDesign feature-parity summary in docs/parity-checklist.md
|
||||
ico <out.ico> <in.png>...
|
||||
pack square PNGs (<= 256 px) into a Windows .ico (see packaging/icons.sh)
|
||||
@@ -37,11 +39,12 @@ fn main() -> ExitCode {
|
||||
let result = match args.first().map(String::as_str) {
|
||||
Some("assets") => assets::run(&root()),
|
||||
Some("layers") => cmd_layers(),
|
||||
Some("pdf-deps") => pdf_deps::run(&root()),
|
||||
Some("wasm") => cmd_wasm(),
|
||||
Some("test") => cmd_test().and_then(|()| cmd_doctest()),
|
||||
Some("ci") => cmd_ci(),
|
||||
Some("corpus") => cmd_corpus(rest.contains(&"--download")),
|
||||
Some("stats") => stats::run(&root(), rest.contains(&"--exact")),
|
||||
Some("pdf-deps") => pdf_deps::run(&root()),
|
||||
Some("parity") => parity::run(&root()),
|
||||
Some("ico") => ico::run(&rest),
|
||||
Some("version") => version::run(&root(), &rest),
|
||||
@@ -134,21 +137,51 @@ fn wasm_set() -> Result<Vec<String>, String> {
|
||||
.collect())
|
||||
}
|
||||
|
||||
/// One `cargo check` for the whole set: each crate is checked once, and
|
||||
/// `--keep-going` still reports every failing crate. Features unify across the
|
||||
/// set, so each crate is checked with the union of the features the set enables.
|
||||
fn cmd_wasm() -> Result<(), String> {
|
||||
let set = wasm_set()?;
|
||||
let mut results = Vec::new();
|
||||
if set.is_empty() {
|
||||
return Err("no wasm-safe crates found in the workspace metadata".into());
|
||||
}
|
||||
let mut c = cargo();
|
||||
c.args(["check", "--target", "wasm32-unknown-unknown", "--keep-going"]);
|
||||
for pkg in &set {
|
||||
let mut c = cargo();
|
||||
c.args(["check", "--target", "wasm32-unknown-unknown", "-p", pkg]);
|
||||
let ok = run(c, &format!("cargo check --target wasm32-unknown-unknown -p {pkg}")).is_ok();
|
||||
results.push((pkg.clone(), ok));
|
||||
c.args(["-p", pkg]);
|
||||
}
|
||||
println!("\nwasm32-unknown-unknown check:");
|
||||
for (p, ok) in &results {
|
||||
println!(" {:<6} {p}", if *ok { "ok" } else { "FAIL" });
|
||||
}
|
||||
let failed = results.iter().filter(|r| !r.1).count();
|
||||
if failed == 0 { Ok(()) } else { Err(format!("{failed} crate(s) failed the wasm check")) }
|
||||
run(c, &format!("cargo check --target wasm32-unknown-unknown --keep-going -p {}", set.join(" -p ")))?;
|
||||
println!("\nwasm32-unknown-unknown check: ok ({} crates: {})", set.len(), set.join(", "));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test targets for the test build. Examples are left out so they aren't
|
||||
/// linked; clippy `--all-targets` still compiles them.
|
||||
const TEST_TARGETS: [&str; 4] = ["--workspace", "--lib", "--bins", "--tests"];
|
||||
|
||||
fn nextest_available() -> bool {
|
||||
cargo().args(["nextest", "--version"]).stdout(Stdio::null()).stderr(Stdio::null()).status().is_ok_and(|s| s.success())
|
||||
}
|
||||
|
||||
fn cmd_test() -> Result<(), String> {
|
||||
let mut c = cargo();
|
||||
let tool = if nextest_available() {
|
||||
c.args(["nextest", "run"]);
|
||||
"nextest run"
|
||||
} else {
|
||||
eprintln!("note: cargo-nextest is not installed, running cargo test (cargo install cargo-nextest --locked)");
|
||||
c.arg("test");
|
||||
"test"
|
||||
};
|
||||
c.args(TEST_TARGETS);
|
||||
run(c, &format!("cargo {tool} {}", TEST_TARGETS.join(" ")))
|
||||
}
|
||||
|
||||
/// nextest does not run doctests.
|
||||
fn cmd_doctest() -> Result<(), String> {
|
||||
let mut c = cargo();
|
||||
c.args(["test", "--workspace", "--doc"]);
|
||||
run(c, "cargo test --workspace --doc")
|
||||
}
|
||||
|
||||
fn cmd_ci() -> Result<(), String> {
|
||||
@@ -162,6 +195,7 @@ fn cmd_ci() -> Result<(), String> {
|
||||
run(c, "cargo fmt --all -- --check")
|
||||
}),
|
||||
),
|
||||
("pdf-deps", Box::new(|| pdf_deps::run(&root()))),
|
||||
(
|
||||
"clippy",
|
||||
Box::new(|| {
|
||||
@@ -170,15 +204,8 @@ fn cmd_ci() -> Result<(), String> {
|
||||
run(c, "cargo clippy --workspace --all-targets -- -D warnings")
|
||||
}),
|
||||
),
|
||||
(
|
||||
"test",
|
||||
Box::new(|| {
|
||||
let mut c = cargo();
|
||||
c.args(["test", "--workspace"]);
|
||||
run(c, "cargo test --workspace")
|
||||
}),
|
||||
),
|
||||
("pdf-deps", Box::new(|| pdf_deps::run(&root()))),
|
||||
("test", Box::new(cmd_test)),
|
||||
("doctest", Box::new(cmd_doctest)),
|
||||
("assets", Box::new(|| assets::run(&root()))),
|
||||
("layers", Box::new(cmd_layers)),
|
||||
("wasm", Box::new(cmd_wasm)),
|
||||
|
||||
+36
-8
@@ -1,4 +1,4 @@
|
||||
//! Check the shared writer source, including transitive users such as krilla-svg.
|
||||
//! Check the shared reader source, including the parser reached through Krilla.
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
@@ -6,7 +6,14 @@ use serde_json::Value;
|
||||
|
||||
const REPO: &str = "https://github.com/aiongg/craft-libs";
|
||||
const REV: &str = "d30598dcb4b389561c485b97d4a97a0c86bc36e4";
|
||||
const PACKAGES: &[(&str, &str)] = &[("craft-pdf", "0.1.0"), ("krilla", "0.8.2")];
|
||||
const PACKAGES: &[(&str, &str)] = &[
|
||||
("craft-pdf", "0.1.0"),
|
||||
("krilla", "0.8.2"),
|
||||
("hayro", "0.7.1"),
|
||||
("hayro-interpret", "0.7.0"),
|
||||
("hayro-syntax", "0.7.2"),
|
||||
("hayro-jbig2", "0.3.0"),
|
||||
];
|
||||
|
||||
pub fn run(root: &Path) -> Result<(), String> {
|
||||
let output = Command::new(std::env::var_os("CARGO").unwrap_or_else(|| "cargo".into()))
|
||||
@@ -19,7 +26,7 @@ pub fn run(root: &Path) -> Result<(), String> {
|
||||
}
|
||||
let metadata: Value = serde_json::from_slice(&output.stdout).map_err(|e| format!("cargo metadata: {e}"))?;
|
||||
validate(&metadata)?;
|
||||
println!("PDF writer: facade and patched Krilla resolve once to {REV}");
|
||||
println!("PDF backend: facade, Krilla and Hayro resolve once to {REV}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -35,6 +42,15 @@ fn validate(metadata: &Value) -> Result<(), String> {
|
||||
return Err(format!("{name}: expected {version} from {source}; got {package}"));
|
||||
}
|
||||
}
|
||||
let nodes = metadata.pointer("/resolve/nodes").and_then(Value::as_array).ok_or("cargo metadata has no resolved nodes")?;
|
||||
let facade = packages.iter().find(|p| p["name"] == "craft-pdf").ok_or("craft-pdf: missing package")?;
|
||||
let node = nodes.iter().find(|n| n["id"] == facade["id"]).ok_or("craft-pdf: missing resolved node")?;
|
||||
let features = node["features"].as_array().ok_or("craft-pdf: missing features")?;
|
||||
for required in ["read", "interpret", "raster", "write", "write-pdf"] {
|
||||
if !features.iter().any(|f| f.as_str() == Some(required)) {
|
||||
return Err(format!("craft-pdf: missing required {required} feature"));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -44,17 +60,17 @@ mod tests {
|
||||
use serde_json::json;
|
||||
|
||||
fn metadata() -> Value {
|
||||
json!({"packages": PACKAGES.iter().map(|(name, version)| json!({"name":name,"version":version,
|
||||
"source":format!("git+{REPO}?rev={REV}#{REV}")})).collect::<Vec<_>>()})
|
||||
json!({"packages": PACKAGES.iter().map(|(name, version)| json!({"id":name,"name":name,"version":version,
|
||||
"source":format!("git+{REPO}?rev={REV}#{REV}")})).collect::<Vec<_>>(), "resolve": {"nodes": [{"id": "craft-pdf", "features": ["read", "interpret", "raster", "write", "write-pdf"]}]}})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accepts_one_pinned_facade_and_writer() {
|
||||
fn accepts_one_pinned_facade_and_reader() {
|
||||
assert!(validate(&metadata()).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_unpatched_and_local_writer_sources() {
|
||||
fn rejects_unpatched_and_local_reader_sources() {
|
||||
for source in [Value::Null, json!("registry+https://github.com/rust-lang/crates.io-index")] {
|
||||
let mut m = metadata();
|
||||
m["packages"][1]["source"] = source;
|
||||
@@ -64,7 +80,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn rejects_missing_duplicate_and_wrong_version_packages() {
|
||||
for index in [0, 1] {
|
||||
for index in 0..PACKAGES.len() {
|
||||
let mut m = metadata();
|
||||
m["packages"][index]["version"] = json!("99.0.0");
|
||||
assert!(validate(&m).is_err());
|
||||
@@ -78,6 +94,18 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_missing_reader_or_writer_features() {
|
||||
for index in 0..5 {
|
||||
let mut m = metadata();
|
||||
m["resolve"]["nodes"][0]["features"].as_array_mut().unwrap().remove(index);
|
||||
assert!(validate(&m).is_err());
|
||||
}
|
||||
let mut m = metadata();
|
||||
m["resolve"] = Value::Null;
|
||||
assert!(validate(&m).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_facade_revision_drift_and_malformed_metadata() {
|
||||
let mut m = metadata();
|
||||
|
||||
Reference in New Issue
Block a user