vectorcraft/xtask/src/affinity_corpus.rs

152 lines
7.7 KiB
Rust

//! `cargo xtask corpus --affinity`: public Affinity documents saved by Affinity 1.x to 3.x, from
//! their upstream repositories at pinned commits, each checked against `xtask/affinity-corpus.sha256`.
//! They land in `corpus/affinity/` (gitignored, never committed). `vectorcraft-affinity`'s
//! `real_files` test and the engine's `affinity_corpus` test use them when present.
//!
//! Only permissively licensed files (CC0, MIT, Apache-2.0) are listed. Fixture provenance and
//! exclusions are documented in docs/affinity-validation.md. Moving a pin: change the commit,
//! re-run, review the manifest diff. Metadata is never imported or published by the app.
use std::path::Path;
use std::process::Command;
use crate::{root, run, sha256};
/// (repository, commit, licence, [(path in the repository, file name in corpus/affinity)]).
type Source = (&'static str, &'static str, &'static str, &'static [(&'static str, &'static str)]);
const SOURCES: &[Source] = &[
(
"SethRobinson/Patchy",
"de84eab550758b30fa062e479f5778cce7693b73",
"MIT",
&[
("LICENSE", "patchy-LICENSE.txt"),
("NOTICE-THIRD-PARTY.md", "patchy-NOTICE.txt"),
("test-fixtures/af/tiny-adjust-curves.af", "patchy-adjust-curves.af"),
("test-fixtures/af/tiny-adjust-hsl.af", "patchy-adjust-hsl.af"),
("test-fixtures/af/tiny-artboards.af", "patchy-artboards.af"),
("test-fixtures/af/tiny-blend-affinity.af", "patchy-blend-affinity.af"),
("test-fixtures/af/tiny-cmyk.af", "patchy-cmyk.af"),
("test-fixtures/af/tiny-dpi300.af", "patchy-dpi300.af"),
("test-fixtures/af/tiny-embedded-jpeg.af", "patchy-embedded-jpeg.af"),
("test-fixtures/af/tiny-fx-blur.af", "patchy-fx-blur.af"),
("test-fixtures/af/tiny-fx-gradient.af", "patchy-fx-gradient.af"),
("test-fixtures/af/tiny-fx.af", "patchy-fx.af"),
("test-fixtures/af/tiny-group.af", "patchy-group.af"),
("test-fixtures/af/tiny-incremental-chain.af", "patchy-incremental-chain.af"),
("test-fixtures/af/tiny-lab.af", "patchy-lab.af"),
("test-fixtures/af/tiny-lazy-placed.af", "patchy-lazy-placed.af"),
("test-fixtures/af/tiny-live-filter.af", "patchy-live-filter.af"),
("test-fixtures/af/tiny-rgba16.af", "patchy-rgba16.af"),
("test-fixtures/af/tiny-rgba8.af", "patchy-rgba8.af"),
("test-fixtures/af/tiny-shapes-2.af", "patchy-shapes-2.af"),
("test-fixtures/af/tiny-shapes.af", "patchy-shapes.af"),
("test-fixtures/af/tiny-text-artistic.af", "patchy-text-artistic.af"),
("test-fixtures/af/tiny-text-caps.af", "patchy-text-caps.af"),
("test-fixtures/af/tiny-text-frame.af", "patchy-text-frame.af"),
("test-fixtures/af/tiny-text-indent.af", "patchy-text-indent.af"),
("test-fixtures/af/tiny-text-para-spacing.af", "patchy-text-para-spacing.af"),
("test-fixtures/af/tiny-text-rotated.af", "patchy-text-rotated.af"),
("test-fixtures/af/tiny-text-runs.af", "patchy-text-runs.af"),
("test-fixtures/af/tiny-transform.af", "patchy-transform.af"),
("test-fixtures/af/tiny-vector-mask.af", "patchy-vector-mask.af"),
("test-fixtures/af/tiny-vector.af", "patchy-vector.af"),
],
),
(
"samuel-etver/vector-art",
"255f8add3c8f0740196e22bd59502b811b532f0b",
"CC0-1.0",
&[
("simple/mexican-guy.af", "affinity3-mexican-guy.af"),
("simple/mexican-man.af", "affinity3-mexican-man.af"),
("simple/mexican-woman.af", "affinity3-mexican-woman.af"),
("simple/playing-cards.af", "affinity3-playing-cards.af"),
("simple/beer.afdesign", "designer-beer.afdesign"),
("simple/cactus.afdesign", "designer-cactus.afdesign"),
("simple/car.afdesign", "designer-car.afdesign"),
("simple/flowers.afdesign", "designer-flowers.afdesign"),
("simple/lion-track.afdesign", "designer-lion-track.afdesign"),
],
),
(
"NickBeeuwsaert/AFDesignLoad",
"a18dd50a7079fb861a28835eeefa0d015f03f4a1",
"MIT",
&[
("testDesigns/color.afdesign", "afdesignload-color.afdesign"),
("testDesigns/layer_mode.afdesign", "afdesignload-layer_mode.afdesign"),
("testDesigns/layer_test.afdesign", "afdesignload-layer_test.afdesign"),
("testDesigns/margins.afdesign", "afdesignload-margins.afdesign"),
("testDesigns/raster_test.afdesign", "afdesignload-raster_test.afdesign"),
("testDesigns/revision_test.afdesign", "afdesignload-revision_test.afdesign"),
("testDesigns/shape_test.afdesign", "afdesignload-shape_test.afdesign"),
("testDesigns/slice_test.afdesign", "afdesignload-slice_test.afdesign"),
("testDesigns/test_path.afdesign", "afdesignload-test_path.afdesign"),
],
),
(
"Jac21/Branding",
"57ae3f45bf4637f6927c0b07de25b922c55f944f",
"MIT",
&[
("Logos/JC/DesignerFiles/Affinity/SimpleLogo.afdesign", "jac21-SimpleLogo.afdesign"),
("Logos/JC/DesignerFiles/Affinity/SimpleLogoBanner.afdesign", "jac21-SimpleLogoBanner.afdesign"),
],
),
(
"eviltwo/AssetStoreTemplate",
"f671981ee89d15526285b3cc87b4393d3defe644",
"MIT",
&[("AssetStoreTemplate/AssetStore.aftemplate", "eviltwo-AssetStore.aftemplate")],
),
(
"square/leakcanary",
"00880a8fb66eb4046a0124bff8303a04874bc07e",
"Apache-2.0",
&[("docs/assets/vector_icon.afdesign", "leakcanary-vector_icon.afdesign")],
),
];
const MANIFEST: &str = "xtask/affinity-corpus.sha256";
pub fn fetch() -> Result<(), String> {
let root = root();
let manifest = std::fs::read_to_string(root.join(MANIFEST)).map_err(|e| format!("{MANIFEST}: {e}"))?;
let expected: Vec<(&str, &str)> = manifest.lines().filter_map(|l| l.split_once(" ")).collect();
let dest = root.join("corpus").join("affinity");
std::fs::create_dir_all(&dest).map_err(|e| format!("create {}: {e}", dest.display()))?;
let mut sources = String::from(
"# Public Affinity documents\n\nFetched by `cargo xtask corpus --affinity` and checked against `xtask/affinity-corpus.sha256`.\nGitignored; never commit these files.\n\n| File | Source | Licence |\n|---|---|---|\n",
);
let mut count = 0;
for (repo, commit, licence, files) in SOURCES {
for (path, name) in *files {
let sha = expected.iter().find(|(_, n)| n == name).map(|(s, _)| *s).ok_or_else(|| format!("{name} is missing from {MANIFEST}"))?;
let out = dest.join(name);
if !verified(&out, sha) {
let url = format!("https://raw.githubusercontent.com/{repo}/{commit}/{path}");
let mut curl = Command::new("curl");
curl.args(["-fsSL", "--retry", "3", "-A", "VectorCraft-dev", "-o"]).arg(&out).arg(&url);
run(curl, &format!("curl {url}"))?;
if !verified(&out, sha) {
let _ = std::fs::remove_file(&out);
return Err(format!("{name}: sha256 does not match {MANIFEST}"));
}
}
sources.push_str(&format!("| {name} | https://github.com/{repo}/blob/{commit}/{path} | {licence} |\n"));
if out.extension().is_some_and(|e| e != "txt") {
count += 1;
}
}
}
std::fs::write(dest.join("SOURCES.md"), sources).map_err(|e| format!("SOURCES.md: {e}"))?;
println!("Affinity: {count} documents verified in {}", dest.display());
Ok(())
}
fn verified(path: &Path, sha: &str) -> bool {
std::fs::read(path).is_ok_and(|b| sha256::hex(&b) == sha)
}