mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-24 10:09:01 -06:00
M0.1: enforce the asset rule in CI (cargo xtask assets); replace Adobe-published Source Sans 3 with Inter
Every image/icon/font/media/profile file must match an assets/ATTRIBUTION.md path pattern; Adobe profile/template formats and Adobe-named assets are rejected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c7be09429d
commit
f0ffa11333
+10
-8
@@ -2,19 +2,21 @@
|
|||||||
|
|
||||||
Every asset shipped in this repository is listed here (see the asset rules in `AGENTS.md`). No asset may come from
|
Every asset shipped in this repository is listed here (see the asset rules in `AGENTS.md`). No asset may come from
|
||||||
Adobe products. Add an entry in the same commit as the asset.
|
Adobe products. Add an entry in the same commit as the asset.
|
||||||
|
`cargo xtask assets` (part of `cargo xtask ci`) fails if any image, icon, font, sound, video, raw file or colour profile
|
||||||
|
in the repository is not matched by a path pattern in the first column (`*` = any characters except `/`; a trailing `/`
|
||||||
|
covers a whole directory), or if a licence file referenced in the Licence column is missing.
|
||||||
|
|
||||||
| Path | Asset | Creator | Source | Licence | Added | Modifications |
|
| Path | Asset | Creator | Source | Licence | Added | Modifications |
|
||||||
|---|---|---|---|---|---|---|
|
|---|---|---|---|---|---|---|
|
||||||
| `assets/fonts/SourceSans3-Regular.ttf`, `-Semibold.ttf`, `-Bold.ttf`, `-It.ttf` | Source Sans 3 | Paul D. Hunt | https://github.com/adobe-fonts/source-sans | SIL Open Font License 1.1 (`assets/fonts/OFL-SourceSans3.txt`) | 2026-09-30 | none |
|
| `assets/fonts/Inter-*.ttf` (Regular, Medium, SemiBold) | Inter | Rasmus Andersson | https://github.com/rsms/inter | SIL Open Font License 1.1 (`assets/fonts/OFL-Inter.txt`) | 2026-09-30 | none |
|
||||||
| `assets/fonts/Inter-Regular.ttf`, `-Medium.ttf`, `-SemiBold.ttf` | Inter | Rasmus Andersson | https://github.com/rsms/inter | SIL Open Font License 1.1 (`assets/fonts/OFL-Inter.txt`) | 2026-09-30 | none |
|
|
||||||
| `crates/scenes/` (generated images) | Procedural demo photographs | LightCraft contributors | original work (generated at runtime, no source imagery) | MIT OR Apache-2.0 | 2026-09-30 | n/a |
|
| `crates/scenes/` (generated images) | Procedural demo photographs | LightCraft contributors | original work (generated at runtime, no source imagery) | MIT OR Apache-2.0 | 2026-09-30 | n/a |
|
||||||
| `crates/ui-egui/src/icons.rs` | UI icons drawn as vector paths in code | LightCraft contributors | original work | MIT OR Apache-2.0 | 2026-09-30 | n/a |
|
| `crates/ui-egui/src/icons.rs` | UI icons drawn as vector paths in code | LightCraft contributors | original work | MIT OR Apache-2.0 | 2026-09-30 | n/a |
|
||||||
| `docs/images/*-tetons.jpg`, `grid-pd.jpg` (screenshots containing it) | "The Tetons and the Snake River" | Ansel Adams (1942), U.S. National Archives | https://commons.wikimedia.org/wiki/File:Adams_The_Tetons_and_the_Snake_River.jpg | Public domain (U.S. federal government work) | 2026-09-30 | developed in LightCraft; shown inside app screenshots |
|
| `docs/images/*-tetons.jpg`, `docs/images/grid-pd.jpg` (screenshots containing it) | "The Tetons and the Snake River" | Ansel Adams (1942), U.S. National Archives | https://commons.wikimedia.org/wiki/File:Adams_The_Tetons_and_the_Snake_River.jpg | Public domain (U.S. federal government work) | 2026-09-30 | developed in LightCraft; shown inside app screenshots |
|
||||||
| `docs/images/*-migrant-mother.jpg`, `grid-pd.jpg` | "Migrant Mother" | Dorothea Lange (1936), Farm Security Administration / Library of Congress | https://commons.wikimedia.org/wiki/File:Lange-MigrantMother02.jpg | Public domain (U.S. federal government work) | 2026-09-30 | developed in LightCraft; shown inside app screenshots |
|
| `docs/images/*-migrant-mother.jpg`, `docs/images/grid-pd.jpg` | "Migrant Mother" | Dorothea Lange (1936), Farm Security Administration / Library of Congress | https://commons.wikimedia.org/wiki/File:Lange-MigrantMother02.jpg | Public domain (U.S. federal government work) | 2026-09-30 | developed in LightCraft; shown inside app screenshots |
|
||||||
| `docs/images/*-earthrise.jpg`, `grid-pd.jpg` | "Earthrise" (AS08-14-2383) | NASA / Bill Anders, Apollo 8 (1968) | https://commons.wikimedia.org/wiki/File:NASA-Apollo8-Dec24-Earthrise.jpg | Public domain (NASA) | 2026-09-30 | developed in LightCraft; shown inside app screenshots |
|
| `docs/images/*-earthrise.jpg`, `docs/images/grid-pd.jpg` | "Earthrise" (AS08-14-2383) | NASA / Bill Anders, Apollo 8 (1968) | https://commons.wikimedia.org/wiki/File:NASA-Apollo8-Dec24-Earthrise.jpg | Public domain (NASA) | 2026-09-30 | developed in LightCraft; shown inside app screenshots |
|
||||||
| `docs/images/*-blue-marble.jpg`, `grid-pd.jpg` | "The Blue Marble" (AS17-148-22727) | NASA, Apollo 17 crew (1972) | https://commons.wikimedia.org/wiki/File:The_Earth_seen_from_Apollo_17.jpg | Public domain (NASA) | 2026-09-30 | developed in LightCraft; shown inside app screenshots |
|
| `docs/images/*-blue-marble.jpg`, `docs/images/grid-pd.jpg` | "The Blue Marble" (AS17-148-22727) | NASA, Apollo 17 crew (1972) | https://commons.wikimedia.org/wiki/File:The_Earth_seen_from_Apollo_17.jpg | Public domain (NASA) | 2026-09-30 | developed in LightCraft; shown inside app screenshots |
|
||||||
| `docs/images/*.jpg` (UI) | LightCraft application screenshots | LightCraft contributors | original work (captured with `docs/showcase/`) | MIT OR Apache-2.0 | 2026-09-30 | n/a |
|
| `docs/images/*.jpg` (UI) | LightCraft application screenshots | LightCraft contributors | original work (captured with `docs/showcase/`) | MIT OR Apache-2.0 | 2026-09-30 | n/a |
|
||||||
|
|
||||||
Notes
|
Notes
|
||||||
- Source Sans 3 is an open-source (OFL) typeface; it is used as a general-purpose UI font. It is distributed under the
|
- Fonts authored or published by Adobe (Source Sans/Serif/Code, Source Han, …) are not used, even though some are
|
||||||
OFL and is not an asset taken from any Adobe application.
|
OFL-licensed: the asset rule excludes anything from Adobe. Source Sans 3 was removed on 2026-09-30 and replaced by Inter.
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
Copyright 2010-2024 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries.
|
|
||||||
|
|
||||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
|
||||||
|
|
||||||
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------------------------------------------
|
|
||||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
||||||
-----------------------------------------------------------
|
|
||||||
|
|
||||||
PREAMBLE
|
|
||||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
||||||
development of collaborative font projects, to support the font creation
|
|
||||||
efforts of academic and linguistic communities, and to provide a free and
|
|
||||||
open framework in which fonts may be shared and improved in partnership
|
|
||||||
with others.
|
|
||||||
|
|
||||||
The OFL allows the licensed fonts to be used, studied, modified and
|
|
||||||
redistributed freely as long as they are not sold by themselves. The
|
|
||||||
fonts, including any derivative works, can be bundled, embedded,
|
|
||||||
redistributed and/or sold with any software provided that any reserved
|
|
||||||
names are not used by derivative works. The fonts and derivatives,
|
|
||||||
however, cannot be released under any other type of license. The
|
|
||||||
requirement for fonts to remain under this license does not apply
|
|
||||||
to any document created using the fonts or their derivatives.
|
|
||||||
|
|
||||||
DEFINITIONS
|
|
||||||
"Font Software" refers to the set of files released by the Copyright
|
|
||||||
Holder(s) under this license and clearly marked as such. This may
|
|
||||||
include source files, build scripts and documentation.
|
|
||||||
|
|
||||||
"Reserved Font Name" refers to any names specified as such after the
|
|
||||||
copyright statement(s).
|
|
||||||
|
|
||||||
"Original Version" refers to the collection of Font Software components as
|
|
||||||
distributed by the Copyright Holder(s).
|
|
||||||
|
|
||||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
||||||
or substituting -- in part or in whole -- any of the components of the
|
|
||||||
Original Version, by changing formats or by porting the Font Software to a
|
|
||||||
new environment.
|
|
||||||
|
|
||||||
"Author" refers to any designer, engineer, programmer, technical
|
|
||||||
writer or other person who contributed to the Font Software.
|
|
||||||
|
|
||||||
PERMISSION & CONDITIONS
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
||||||
redistribute, and sell modified and unmodified copies of the Font
|
|
||||||
Software, subject to the following conditions:
|
|
||||||
|
|
||||||
1) Neither the Font Software nor any of its individual components,
|
|
||||||
in Original or Modified Versions, may be sold by itself.
|
|
||||||
|
|
||||||
2) Original or Modified Versions of the Font Software may be bundled,
|
|
||||||
redistributed and/or sold with any software, provided that each copy
|
|
||||||
contains the above copyright notice and this license. These can be
|
|
||||||
included either as stand-alone text files, human-readable headers or
|
|
||||||
in the appropriate machine-readable metadata fields within text or
|
|
||||||
binary files as long as those fields can be easily viewed by the user.
|
|
||||||
|
|
||||||
3) No Modified Version of the Font Software may use the Reserved Font
|
|
||||||
Name(s) unless explicit written permission is granted by the corresponding
|
|
||||||
Copyright Holder. This restriction only applies to the primary font name as
|
|
||||||
presented to the users.
|
|
||||||
|
|
||||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
||||||
Software shall not be used to promote, endorse or advertise any
|
|
||||||
Modified Version, except to acknowledge the contribution(s) of the
|
|
||||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
||||||
permission.
|
|
||||||
|
|
||||||
5) The Font Software, modified or unmodified, in part or in whole,
|
|
||||||
must be distributed entirely under this license, and must not be
|
|
||||||
distributed under any other license. The requirement for fonts to
|
|
||||||
remain under this license does not apply to any document created
|
|
||||||
using the Font Software.
|
|
||||||
|
|
||||||
TERMINATION
|
|
||||||
This license becomes null and void if any of the above conditions are
|
|
||||||
not met.
|
|
||||||
|
|
||||||
DISCLAIMER
|
|
||||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
||||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
||||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
||||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
||||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -105,7 +105,7 @@ pub fn show(app: &mut LightcraftApp, ctx: &egui::Context) {
|
|||||||
Dialog::About => {
|
Dialog::About => {
|
||||||
ui.label(egui::RichText::new("LightCraft").font(t.semibold(20.0)).color(t.text));
|
ui.label(egui::RichText::new("LightCraft").font(t.semibold(20.0)).color(t.text));
|
||||||
ui.label(format!("Version {} — a clean-room, pure-Rust photo library and raw developer.", env!("CARGO_PKG_VERSION")));
|
ui.label(format!("Version {} — a clean-room, pure-Rust photo library and raw developer.", env!("CARGO_PKG_VERSION")));
|
||||||
ui.label("MIT OR Apache-2.0. Fonts: Source Sans 3 (OFL). Icons: original.");
|
ui.label("MIT OR Apache-2.0. Font: Inter (OFL). Icons: original.");
|
||||||
}
|
}
|
||||||
Dialog::Shortcuts => {
|
Dialog::Shortcuts => {
|
||||||
egui::ScrollArea::vertical().max_height(420.0).show(ui, |ui| {
|
egui::ScrollArea::vertical().max_height(420.0).show(ui, |ui| {
|
||||||
|
|||||||
@@ -107,15 +107,13 @@ impl Tokens {
|
|||||||
|
|
||||||
pub fn install_fonts(ctx: &egui::Context) {
|
pub fn install_fonts(ctx: &egui::Context) {
|
||||||
let mut fonts = FontDefinitions::default();
|
let mut fonts = FontDefinitions::default();
|
||||||
fonts.font_data.insert("SourceSans3".into(), Arc::new(FontData::from_static(include_bytes!("../../../assets/fonts/SourceSans3-Regular.ttf"))));
|
fonts.font_data.insert("Inter".into(), Arc::new(FontData::from_static(include_bytes!("../../../assets/fonts/Inter-Regular.ttf"))));
|
||||||
fonts
|
fonts.font_data.insert("Inter-SemiBold".into(), Arc::new(FontData::from_static(include_bytes!("../../../assets/fonts/Inter-SemiBold.ttf"))));
|
||||||
.font_data
|
|
||||||
.insert("SourceSans3-Semibold".into(), Arc::new(FontData::from_static(include_bytes!("../../../assets/fonts/SourceSans3-Semibold.ttf"))));
|
|
||||||
let fallback: Vec<String> = fonts.families.get(&FontFamily::Proportional).cloned().unwrap_or_default();
|
let fallback: Vec<String> = fonts.families.get(&FontFamily::Proportional).cloned().unwrap_or_default();
|
||||||
let mut prop = vec!["SourceSans3".to_string()];
|
let mut prop = vec!["Inter".to_string()];
|
||||||
prop.extend(fallback.clone());
|
prop.extend(fallback.clone());
|
||||||
fonts.families.insert(FontFamily::Proportional, prop);
|
fonts.families.insert(FontFamily::Proportional, prop);
|
||||||
let mut semi = vec!["SourceSans3-Semibold".to_string()];
|
let mut semi = vec!["Inter-SemiBold".to_string()];
|
||||||
semi.extend(fallback);
|
semi.extend(fallback);
|
||||||
fonts.families.insert(FontFamily::Name(FONT_SEMIBOLD.into()), semi);
|
fonts.families.insert(FontFamily::Name(FONT_SEMIBOLD.into()), semi);
|
||||||
ctx.set_fonts(fonts);
|
ctx.set_fonts(fonts);
|
||||||
|
|||||||
@@ -0,0 +1,135 @@
|
|||||||
|
//! Asset attribution check (AGENTS.md "Assets" rule): every image, icon, font, sound, video, raw
|
||||||
|
//! file or colour profile in the repository must be covered by a path pattern in the first column of
|
||||||
|
//! `assets/ATTRIBUTION.md`, licence files referenced there must exist, and nothing may look like it
|
||||||
|
//! came from an Adobe product.
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
/// Extensions treated as assets (lower-case).
|
||||||
|
const ASSET_EXT: &[&str] = &[
|
||||||
|
"png", "jpg", "jpeg", "gif", "webp", "avif", "svg", "ico", "icns", "bmp", "ttf", "otf", "woff", "woff2", "wav", "mp3", "ogg", "flac", "mp4",
|
||||||
|
"mov", "tif", "tiff", "dng", "cr2", "cr3", "nef", "arw", "raf", "orf", "rw2", "pef", "heic", "jxl", "psd", "cube", "icc", "icm", "xmp",
|
||||||
|
];
|
||||||
|
/// Adobe-specific formats we never ship (camera/lens profiles, Lightroom templates).
|
||||||
|
const FORBIDDEN_EXT: &[&str] = &["dcp", "lcp", "lrtemplate", "lrcat", "lrsmcol", "aco", "ase", "abr"];
|
||||||
|
const FORBIDDEN_NAME: &[&str] = &["adobe", "lightroom", "photoshop", "creative cloud", "creativecloud"];
|
||||||
|
|
||||||
|
/// `*` matches any run of characters except `/`; a pattern ending in `/` matches everything below it.
|
||||||
|
pub fn glob(pat: &str, path: &str) -> bool {
|
||||||
|
if let Some(dir) = pat.strip_suffix('/') {
|
||||||
|
return path.starts_with(dir) && path[dir.len()..].starts_with('/');
|
||||||
|
}
|
||||||
|
fn rec(p: &[u8], s: &[u8]) -> bool {
|
||||||
|
match (p.first(), s.first()) {
|
||||||
|
(None, None) => true,
|
||||||
|
(Some(b'*'), _) => rec(&p[1..], s) || (!s.is_empty() && s[0] != b'/' && rec(p, &s[1..])),
|
||||||
|
(Some(a), Some(b)) if a == b => rec(&p[1..], &s[1..]),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rec(pat.as_bytes(), path.as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn backticked(cell: &str) -> impl Iterator<Item = &str> {
|
||||||
|
cell.split('`').skip(1).step_by(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// (path patterns, referenced licence files) from the attribution table.
|
||||||
|
pub fn parse(md: &str) -> (Vec<String>, Vec<String>) {
|
||||||
|
let (mut pats, mut licences) = (Vec::new(), Vec::new());
|
||||||
|
for line in md.lines().filter(|l| l.trim_start().starts_with('|')) {
|
||||||
|
let cells: Vec<&str> = line.trim().trim_matches('|').split('|').collect();
|
||||||
|
if cells.len() < 5 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pats.extend(backticked(cells[0]).filter(|p| p.contains('/')).map(str::to_string));
|
||||||
|
licences.extend(backticked(cells[4]).filter(|p| p.contains('/')).map(str::to_string));
|
||||||
|
}
|
||||||
|
(pats, licences)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Problems with `files` given the attribution document `md`; `exists` checks licence files.
|
||||||
|
pub fn check(files: &[String], md: &str, exists: impl Fn(&str) -> bool) -> Vec<String> {
|
||||||
|
let (pats, licences) = parse(md);
|
||||||
|
let mut out = Vec::new();
|
||||||
|
for f in files {
|
||||||
|
let lower = f.to_ascii_lowercase();
|
||||||
|
let ext = Path::new(&lower).extension().and_then(|e| e.to_str()).unwrap_or("");
|
||||||
|
let name = Path::new(&lower).file_name().and_then(|e| e.to_str()).unwrap_or("");
|
||||||
|
if FORBIDDEN_EXT.contains(&ext) {
|
||||||
|
out.push(format!("{f}: `.{ext}` files (Adobe profile/template formats) must never be committed"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if !ASSET_EXT.contains(&ext) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if FORBIDDEN_NAME.iter().any(|n| name.contains(n)) {
|
||||||
|
out.push(format!("{f}: asset name suggests Adobe material; Adobe assets are forbidden (AGENTS.md)"));
|
||||||
|
}
|
||||||
|
if !pats.iter().any(|p| glob(p, f)) {
|
||||||
|
out.push(format!("{f}: no entry in assets/ATTRIBUTION.md (add path, creator, source, licence, date, modifications)"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for l in licences {
|
||||||
|
if !exists(&l) {
|
||||||
|
out.push(format!("assets/ATTRIBUTION.md references missing licence file `{l}`"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(root: &Path) -> Result<(), String> {
|
||||||
|
let out = Command::new("git")
|
||||||
|
.args(["ls-files", "--cached", "--others", "--exclude-standard"])
|
||||||
|
.current_dir(root)
|
||||||
|
.output()
|
||||||
|
.map_err(|e| format!("git ls-files: {e}"))?;
|
||||||
|
if !out.status.success() {
|
||||||
|
return Err("git ls-files failed".into());
|
||||||
|
}
|
||||||
|
let files: Vec<String> = String::from_utf8_lossy(&out.stdout).lines().filter(|f| root.join(f).exists()).map(str::to_string).collect();
|
||||||
|
let md = std::fs::read_to_string(root.join("assets/ATTRIBUTION.md")).map_err(|e| format!("assets/ATTRIBUTION.md: {e}"))?;
|
||||||
|
let problems = check(&files, &md, |p| root.join(p).exists());
|
||||||
|
if problems.is_empty() {
|
||||||
|
let n = files
|
||||||
|
.iter()
|
||||||
|
.filter(|f| Path::new(&f.to_ascii_lowercase()).extension().and_then(|e| e.to_str()).is_some_and(|e| ASSET_EXT.contains(&e)))
|
||||||
|
.count();
|
||||||
|
eprintln!("assets: {n} asset files, all attributed");
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format!("asset rule violations:\n {}", problems.join("\n ")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const MD: &str = "| Path | Asset | Creator | Source | Licence | Added | Mods |\n|---|---|---|---|---|---|---|\n\
|
||||||
|
| `assets/fonts/Foo-*.ttf` | Foo | A | url | OFL (`assets/fonts/OFL-Foo.txt`) | d | none |\n\
|
||||||
|
| `crates/scenes/` | gen | us | original | MIT | d | n/a |\n";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn globbing() {
|
||||||
|
assert!(glob("docs/images/*-tetons.jpg", "docs/images/ba-tetons.jpg"));
|
||||||
|
assert!(!glob("docs/images/*.jpg", "docs/images/sub/x.jpg"));
|
||||||
|
assert!(glob("crates/scenes/", "crates/scenes/a/b.png"));
|
||||||
|
assert!(!glob("crates/scenes/", "crates/scenesx/b.png"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn flags_unattributed_forbidden_and_missing_licence() {
|
||||||
|
let files: Vec<String> =
|
||||||
|
["assets/fonts/Foo-Bold.ttf", "assets/icons/x.svg", "crates/scenes/t.png", "src/lib.rs", "p/camera.dcp", "assets/fonts/Adobe-Foo.otf"]
|
||||||
|
.map(String::from)
|
||||||
|
.into();
|
||||||
|
let p = check(&files, MD, |_| false);
|
||||||
|
assert!(p.iter().any(|m| m.starts_with("assets/icons/x.svg: no entry")));
|
||||||
|
assert!(p.iter().any(|m| m.starts_with("p/camera.dcp")));
|
||||||
|
assert!(p.iter().any(|m| m.contains("Adobe-Foo.otf: asset name")));
|
||||||
|
assert!(p.iter().any(|m| m.contains("OFL-Foo.txt")));
|
||||||
|
assert!(!p.iter().any(|m| m.starts_with("assets/fonts/Foo-Bold.ttf") || m.starts_with("crates/scenes") || m.starts_with("src/")));
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-1
@@ -3,6 +3,7 @@
|
|||||||
//! Pure Rust (std + serde_json). External tools (`cargo`, `curl`, `tar`) are
|
//! Pure Rust (std + serde_json). External tools (`cargo`, `curl`, `tar`) are
|
||||||
//! invoked through `std::process::Command`.
|
//! invoked through `std::process::Command`.
|
||||||
|
|
||||||
|
mod assets;
|
||||||
mod layers;
|
mod layers;
|
||||||
mod stats;
|
mod stats;
|
||||||
|
|
||||||
@@ -13,9 +14,10 @@ const USAGE: &str = "\
|
|||||||
usage: cargo xtask <command>
|
usage: cargo xtask <command>
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
|
assets every image/icon/font/media file is attributed in assets/ATTRIBUTION.md; no Adobe assets
|
||||||
layers enforce the crate dependency layering (plan/architecture.md §3)
|
layers enforce the crate dependency layering (plan/architecture.md §3)
|
||||||
wasm cargo check --target wasm32-unknown-unknown for the wasm-safe crates
|
wasm cargo check --target wasm32-unknown-unknown for the wasm-safe crates
|
||||||
ci fmt --check, clippy -D warnings, test, layers, wasm (stops at first failure)
|
ci fmt --check, clippy -D warnings, test, layers, assets, wasm (stops at first failure)
|
||||||
corpus [--download]
|
corpus [--download]
|
||||||
show where test corpora live; --download fetches PngSuite into corpus/pngsuite
|
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`)
|
stats [--exact] count tests and lines per crate (--exact: ask the test harness via `-- --list`)
|
||||||
@@ -26,6 +28,7 @@ fn main() -> ExitCode {
|
|||||||
let rest: Vec<&str> = args.iter().skip(1).map(String::as_str).collect();
|
let rest: Vec<&str> = args.iter().skip(1).map(String::as_str).collect();
|
||||||
let result = match args.first().map(String::as_str) {
|
let result = match args.first().map(String::as_str) {
|
||||||
Some("layers") => cmd_layers(),
|
Some("layers") => cmd_layers(),
|
||||||
|
Some("assets") => assets::run(&root()),
|
||||||
Some("wasm") => cmd_wasm(),
|
Some("wasm") => cmd_wasm(),
|
||||||
Some("ci") => cmd_ci(),
|
Some("ci") => cmd_ci(),
|
||||||
Some("corpus") => cmd_corpus(rest.contains(&"--download")),
|
Some("corpus") => cmd_corpus(rest.contains(&"--download")),
|
||||||
@@ -164,6 +167,7 @@ fn cmd_ci() -> Result<(), String> {
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
("layers", Box::new(cmd_layers)),
|
("layers", Box::new(cmd_layers)),
|
||||||
|
("assets", Box::new(|| assets::run(&root()))),
|
||||||
("wasm", Box::new(cmd_wasm)),
|
("wasm", Box::new(cmd_wasm)),
|
||||||
];
|
];
|
||||||
let mut done = Vec::new();
|
let mut done = Vec::new();
|
||||||
|
|||||||
Reference in New Issue
Block a user