Build tools for creating JustMyType font packs
Project description
justmytype-pack-tools
Build tools for creating JustMyType font packs. Fetch font families from the google/fonts repo (or any GitHub repo), assemble pack directories, and generate pack_manifest.json. Usable from the justmytype_essentials mono-repo or standalone.
Commands
- fetch — Download configured font families from upstream (GitHub API) into a cache. Requires
source.refinupstream.toml. - build — Copy fetched families from cache into the pack’s
fonts/dir, resolve licenses (auto-detect + allowlist), and generatepack_manifest.json. Fails if a family’s license is unknown and not overridden. - manifest — Generate
pack_manifest.jsononly (fonts must already be present). Use after manual copy or when licenses are defined in config.
Usage (mono-repo)
From repo root:
just fetch western-core # fetch families into cache/
just build western-core # copy from cache + manifest
just dist western-core # build wheel
Or via CLI with shared cache:
pack-tools fetch packs/western-core --cache-dir cache
pack-tools build packs/western-core --cache-dir cache
Usage (standalone / other repos)
- Add an
upstream.tomlnext to your pack (see schema below). - Run from the pack directory or pass the pack path:
pack-tools fetch . --cache-dir ./cache
pack-tools build . --cache-dir ./cache
No dependency on packs/<name> layout; --cache-dir and pack path can be any directories.
upstream.toml schema
- [pack] —
name(required),version,entry_point,priority; optionaldescription,source_url,package_dir,display_name. - [source] —
repo(e.g.https://github.com/google/fonts),ref(commit SHA, branch, or tag; required for fetch/build), optionalarchive_sha256. - families — List of paths relative to repo root (e.g.
["ofl/inter", "apache/sourceserif4"]). Must match the upstream repo exactly (fetch fails with 404 if a path does not exist). - [[licenses]] — Optional static list of
spdxandpath(used bymanifestcommand when not using build). - [[license_overrides]] — Optional allowlist:
familypath +spdx. Use when auto-detection fails or to override; build fails if a family has no detected license and no override.
Example:
[pack]
name = "my-font-pack"
version = "0.1.0"
entry_point = "my-pack"
priority = 100
[source]
repo = "https://github.com/google/fonts"
ref = "main"
families = ["ofl/inter", "ofl/notosans"]
[[license_overrides]]
family = "ofl/inter"
spdx = "OFL-1.1"
Pack metadata semantics
Pack identity and display text are resolved in one place and used by both manifest and README generation.
| Field | Source | Meaning |
|---|---|---|
| name | [pack].name (required) |
Canonical code/package identifier; used for pip install and manifest pack.name. |
| display_name | [pack].display_name (optional) |
Short human-friendly title; written to manifest when set, used for README H1. If unset, pack-tools derives it for README from name. |
| description | [pack].description (optional) |
Longer descriptive text; written to manifest and README. |
| package_dir | [pack].package_dir (optional) |
When set, pack-tools uses src/{package_dir}/fonts for font layout. |
Manifest includes pack.name (always), and optionally pack.description and pack.display_name. README title and install command use the same resolved values so they stay consistent. When display_name is absent, the recommended fallback is pack.name; each application may choose what is most appropriate (e.g. humanizing pack.name).
License detection
Build uses strict auto-detection from each family directory (e.g. OFL.txt, LICENSE.txt, UFL.txt, Apache markers). If detection fails or is ambiguous, build fails unless that family is listed in [[license_overrides]].
Programmatic API
Other tools can run the same logic without shelling out to the CLI. Use the pipeline functions with typed request/result objects.
Full build (copy from cache + manifest + README, same as pack-tools build):
from pathlib import Path
from justmytype_pack_tools import run_build, BuildRequest
result = run_build(BuildRequest(pack_dir=Path("packs/western-core"), cache_dir=Path("cache")))
# result.font_root, result.manifest_path, result.readme_path, result.licenses
Fetch only:
from justmytype_pack_tools import run_fetch, FetchRequest
result = run_fetch(FetchRequest(pack_dir=Path("."), cache_dir=Path("./cache")))
# result.cache_root, result.families
Manifest only (fonts already in place):
from justmytype_pack_tools import run_manifest, ManifestRequest
result = run_manifest(ManifestRequest(pack_dir=Path("."), font_root=Path("src/pkg/fonts")))
# result.output_path, result.manifest
Build with stages toggled (e.g. copy + licenses but no README, or no manifest):
result = run_build(BuildRequest(
pack_dir=Path("."),
generate_manifest=True,
generate_readme=False,
))
Raises FileNotFoundError or ValueError on config/cache errors; handle as needed.
Manifest build timestamp
By default, generated pack_manifest.json does not include build.timestamp. That keeps manifests deterministic and makes diffs easier to trace (only source.ref, file hashes, and tool_version change when inputs change). To record build time for provenance, pass include_timestamp=True when calling the API (e.g. BuildRequest(..., include_timestamp=True) or ManifestRequest(..., include_timestamp=True)). The CLI does not add a flag for this; use the programmatic API if you need it.
Environment
- GITHUB_TOKEN or GH_TOKEN — Optional; increases rate limit for GitHub API.
Installation
From this directory: uv pip install -e . (or pip install -e .).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file justmytype_pack_tools-0.2.1.tar.gz.
File metadata
- Download URL: justmytype_pack_tools-0.2.1.tar.gz
- Upload date:
- Size: 37.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
15fd936672a265927d55dec44042c0414838197799c069ceb6161268fa1e2196
|
|
| MD5 |
acafc0a512026b5fafe816539d223f8d
|
|
| BLAKE2b-256 |
9559c48a77eff3c09c6ddbe847c424ce6e9b5eb597f95e5febacb154ef3c4112
|
File details
Details for the file justmytype_pack_tools-0.2.1-py3-none-any.whl.
File metadata
- Download URL: justmytype_pack_tools-0.2.1-py3-none-any.whl
- Upload date:
- Size: 20.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1cb7f25f0695220c79564d7072724cc443b6c477e29714b2cffd7635f29fb998
|
|
| MD5 |
9c8c659482e70294a70eb6085ecc6dbd
|
|
| BLAKE2b-256 |
b5ced38487328db86c38fec685bb27ae1497f6e6ccb105c86f0d868d3c7898e6
|