diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7b8dc79..7055ca6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,4 +46,4 @@ jobs: fontship-${{ env.VERSION }}.zip fontship-${{ env.VERSION }}.tar.xz env: - GITHUB_TOKEN: "${{ github.token }}" + GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/superlinter.yml b/.github/workflows/superlinter.yml index e774be2..32be764 100644 --- a/.github/workflows/superlinter.yml +++ b/.github/workflows/superlinter.yml @@ -12,4 +12,5 @@ jobs: - name: Super-Linter uses: github/super-linter@v3.6.0 env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VALIDATE_EDITORCONFIG: false + GITHUB_TOKEN: ${{ github.token }} diff --git a/Dockerfile b/Dockerfile index d6a5c7c..bcda245 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,13 +11,21 @@ RUN sed -i /etc/pacman.conf -e \ RUN echo 'keyserver pool.sks-keyservers.net' >> /etc/pacman.d/gnupg/gpg.conf RUN pacman-key --recv-keys 63CC496475267693 && pacman-key --lsign-key 63CC496475267693 +# This is a hack to convince Docker Hub that its cache is behind the times. +# This happens when the contents of our dependencies changes but the base +# system hasn't been refreshed. It's helpful to have this as a separate layer +# because it saves a lot of time for local builds, but it does periodically +# need a poke. Incrementing this when changing dependencies or just when the +# remote Docker Hub builds die should be enough. +ARG DOCKER_HUB_CACHE=1 + # Freshen all base system packages RUN pacman --needed --noconfirm -Syuq && yes | pacman -Sccq -# Install fontship run-time dependecies +# Install fontship run-time dependecies (increment cache var above) RUN pacman --needed --noconfirm -Syq \ diffutils entr font-v gftools git libarchive make psautohint python sfd2ufo sfdnormalize sfnt2woff-zopfli ttfautohint woff2 zsh \ - python-{babelfont,brotli,cffsubr,click,defcon,font{make,tools},fs,lxml,pcpp,pygit2,skia-pathops,ufo{2ft,lib2,normalizer},unicodedata2,zopfli} \ + python-{babelfont,brotli,cffsubr,click,defcon,font{make,tools},fs,lxml,pcpp,pygit2,skia-pathops,ufo{2ft,lib2,normalizer},unicodedata2,zopfli,vttlib} \ && yes | pacman -Sccq # Setup separate image to build fontship so we don't bloat the final image diff --git a/Makefile.am b/Makefile.am index 68ea6e2..8c22158 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,7 +6,7 @@ python_PYTHON = fontship.py dist_doc_DATA = README.md CHANGELOG.md dist_man_MANS = fontship.1 dist_license_DATA = LICENSE -dist_data_DATA = src/rules.mk src/functions.mk src/rules-glyphs.mk src/rules-sfd.mk src/rules-ufo.mk +dist_data_DATA = src/fontship.mk src/rules.mk src/functions.mk src/rules-glyphs.mk src/rules-sfd.mk src/rules-ufo.mk EXTRA_DIST = .version Dockerfile BUILT_SOURCES = .version diff --git a/fontship.in b/fontship.in index 4b1356c..8da43b4 100644 --- a/fontship.in +++ b/fontship.in @@ -46,6 +46,7 @@ def cli(debug, quiet, verbose): def make(ctx, target): """Build specified target(s).""" args = ['make'] + args += ['-f', SRCDIR + 'fontship.mk'] for fname in ['GNUmakefile', 'makefile', 'Makefile', 'rules.mk']: if os.path.isfile(fname): args += ['-f', fname] diff --git a/requirements.txt b/requirements.txt index d0ce2dc..99b5a69 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,8 +4,8 @@ click==7.1.2 defcon==0.7.2 font-v==1.0.2 fontmake==2.2.0 -fonttools[lxml,ufo,unicode,woff]==4.13.0 -gftools==0.4.1 +fonttools[lxml,ufo,unicode,woff]==4.14.0 +gftools==0.4.2 pcpp==1.21.0 psautohint==2.1.0 pygit2==1.2.1 @@ -14,3 +14,4 @@ sfdnormalize==0.3.0 skia-pathops==0.4.1 ufo2ft[cffsubr]==2.15.0 ufoLib2==0.8.0 +vttLib==0.9.1.post2 diff --git a/src/fontship.mk b/src/fontship.mk new file mode 100644 index 0000000..6397176 --- /dev/null +++ b/src/fontship.mk @@ -0,0 +1,48 @@ +# Defalut to running jobs in parallel, one for each CPU core +MAKEFLAGS += --jobs=$(shell nproc) --output-sync=target +# Default to not echoing commands before running +MAKEFLAGS += --silent +# Disable as much built in file type builds as possible +MAKEFLAGS += --no-builtin-rules +.SUFFIXES: + +# Run recipies in zsh, and all in one pass +SHELL := zsh +.SHELLFLAGS := +o nomatch -e -c +.ONESHELL: +.SECONDEXPANSION: + +# Don't drop intermediate artifacts (saves rebulid time and aids debugging) +.SECONDARY: +.PRECIOUS: % +.DELETE_ON_ERROR: + +CONTAINERIZED != test -f /.dockerenv && echo true || echo false + +# Initial environment setup +FONTSHIPDIR != cd "$(shell dirname $(lastword $(MAKEFILE_LIST)))/" && pwd +GITNAME := $(notdir $(or $(shell git remote get-url origin 2> /dev/null | sed 's,^.*/,,;s,.git$$,,' ||:),$(shell git worktree list | head -n1 | awk '{print $$1}'))) +PROJECT ?= $(shell $(PYTHON) $(PYTHONFLAGS) -c 'import re; print(re.sub(r"[-_]", " ", "$(GITNAME)".title()).replace(" ", ""))') +_PROJECTDIR != cd "$(shell dirname $(firstword $(MAKEFILE_LIST)))/" && pwd +PROJECTDIR ?= $(_PROJECTDIR) +PUBDIR ?= $(PROJECTDIR)/pub +SOURCEDIR ?= sources + +# Some Makefile shinanigans to avoid aggressive trimming +space := $() $() + +# Allow overriding executables used +FONTMAKE ?= fontmake +FONTV ?= font-v +GFTOOLS ?= gftools +PYTHON ?= python3 +SFNT2WOFF ?= sfnt2woff-zopfli +TTFAUTOHINT ?= ttfautohint +PSAUTOHINT ?= psautohint +SFDNORMALIZE ?= sfdnormalize +TTX ?= ttx +WOFF2COMPRESS ?= woff2_compress + +include $(FONTSHIPDIR)/functions.mk + + diff --git a/src/functions.mk b/src/functions.mk index 1165fc2..40c2bbf 100644 --- a/src/functions.mk +++ b/src/functions.mk @@ -2,7 +2,9 @@ glyphsFamilyNames ?= $(shell $(PYTHON) -c 'from glyphsLib import GSFont; print(G sfdFamilyNames ?= ufoFamilyNames ?= $(shell $(PYTHON) -c 'import babelfont; print(babelfont.OpenFont("$1").info.familyName.title().replace(" ", ""))') glyphsInstances ?= $(shell $(PYTHON) -c 'from glyphsLib import GSFont; list(map(lambda x: print(x.name), GSFont("$1").instances))') -ufoInstances ?= $(shell $(PYTHON) -c 'import babelfont; print(babelfont.OpenFont("$1").info.styleName)') +ufoInstances ?= $(shell $(PYTHON) -c 'import babelfont; print(babelfont.OpenFont("$1").info.styleName.replace(" ", ""))') +designspaceFamilyNames ?= $(shell $(PYTHON) -c 'from fontTools.designspaceLib import DesignSpaceDocument; d = DesignSpaceDocument(); d.read("$1"); for i in d.instances: print(i.familyName.replace(" ", ""))') +designspaceInstances ?= $(shell $(PYTHON) -c 'from fontTools.designspaceLib import DesignSpaceDocument; d = DesignSpaceDocument(); d.read("$1"); for i in d.instances: print(i.styleName.replace(" ", ""))') sfdInstances ?= file2family ?= $(shell $(PYTHON) -c 'import re; print(re.sub(r"(? /dev/null | sed 's,^.*/,,;s,.git$$,,' ||:),$(shell git worktree list | head -n1 | awk '{print $$1}'))) -PROJECT ?= $(shell $(PYTHON) $(PYTHONFLAGS) -c 'import re; print(re.sub(r"[-_]", " ", "$(GITNAME)".title()).replace(" ", ""))') -_PROJECTDIR != cd "$(shell dirname $(firstword $(MAKEFILE_LIST)))/" && pwd -PROJECTDIR ?= $(_PROJECTDIR) -PUBDIR ?= $(PROJECTDIR)/pub -SOURCEDIR ?= sources - -# Some Makefile shinanigans to avoid aggressive trimming -space := $() $() - -SOURCES ?= $(shell git ls-files -- '$(SOURCEDIR)/*.glyphs' '$(SOURCEDIR)/*.sfd' '$(SOURCEDIR)/*.ufo/*' | sed -e '/\.ufo/s,.ufo/.*,.ufo,' | uniq) -CANONICAL ?= $(or $(and $(filter %.glyphs,$(SOURCES)),glyphs),\ - $(and $(filter %.sfd,$(SOURCES)),sfd),\ - $(and $(filter %.ufo,$(SOURCES)),ufo)) +# If called using the fontship CLI the init rules will be sources before any +# project specific ones, then everything will be sourced in order. If people do +# a manual include to rules they may or may not know to source the +# initilazation rules first. this is to warn them. +ifeq ($(FONTSHIPDIR),) +$(error Please initialize Fontship by sourcing fontship.mk first, then include your project rules, then source this rules.mk file) +endif -# Output format selectors -STATICOTF ?= true -STATICTTF ?= true -STATICWOFF ?= true -STATICWOFF2 ?= true -VARIABLEOTF ?= -VARIABLETTF ?= true -VARIABLEWOFF ?= true -VARIABLEWOFF2 ?= true - -# Allow overriding executables used -FONTMAKE ?= fontmake -FONTV ?= font-v -GFTOOLS ?= gftools -PYTHON ?= python3 -SFNT2WOFF ?= sfnt2woff-zopfli -TTFAUTOHINT ?= ttfautohint -PSAUTOHINT ?= psautohint -SFDNORMALIZE ?= sfdnormalize -TTX ?= ttx -WOFF2COMPRESS ?= woff2_compress - -include $(FONTSHIPDIR)/functions.mk +SOURCES ?= $(shell git ls-files -- '$(SOURCEDIR)/*.glyphs' '$(SOURCEDIR)/*.sfd' '$(SOURCEDIR)/*.ufo/*' '$(SOURCEDIR)/*.designspace' | sed -e '/\.ufo/s,.ufo/.*,.ufo,' | uniq) +SOURCES_SFD ?= $(filter %.sfd,$(SOURCES)) +SOURCES_UFO ?= $(filter %.ufo,$(SOURCES)) +SOURCES_GLYPHS ?= $(filter %.glyphs,$(SOURCES)) +SOURCES_DESIGNSPACE ?= $(filter %.designspace,$(SOURCES)) +CANONICAL ?= $(or $(and $(SOURCES_GLYPHS),glyphs),$(and $(SOURCES_SFD),sfd),$(and $(SOURCES_UFO),ufo)) + +isVariable ?= $(and $(SOURCES_GLYPHS)$(SOURCES_DESIGNSPACE),true) # Read font name from metadata file or guess from repository name ifeq ($(CANONICAL),glyphs) -FamilyNames ?= $(foreach SOURCE,$(filter %.glyphs,$(SOURCES)),$(call glyphsFamilyNames,$(SOURCE))) -FontStyles ?= $(foreach SOURCE,$(filter %.glyphs,$(SOURCES)),$(call glyphsInstances,$(SOURCE))) -isVariable ?= true +FamilyNames ?= $(sort $(foreach SOURCE,$(SOURCES_GLYPHS),$(call glyphsFamilyNames,$(SOURCE)))) +FontStyles ?= $(sort $(foreach SOURCE,$(SOURCES_GLYPHS),$(call glyphsInstances,$(SOURCE)))) endif ifeq ($(CANONICAL),sfd) -FamilyNames ?= $(foreach SOURCE,$(filter %.sfd,$(SOURCES)),$(call sfdFamilyNames,$(SOURCE))) -# FontStyles = $(subst $(FontBase)-,,$(basename $(wildcard $(FontBase)-*.ufo))) +FamilyNames ?= $(sort $(foreach SOURCE,$(SOURCES_SFD),$(call sfdFamilyNames,$(SOURCE)))) +# FontStyles ?= endif ifeq ($(CANONICAL),ufo) -FamilyNames ?= $(foreach SOURCE,$(filter %.ufo,$(SOURCES)),$(call ufoFamilyNames,$(SOURCE))) -FontStyles ?= $(foreach SOURCE,$(filter %.ufo,$(SOURCES)),$(call ufoInstances,$(SOURCE))) +ifeq ($(isVariable),true) +FamilyNames ?= $(sort $(foreach SOURCE,$(SOURCES_DESIGNSPACE),$(call designspaceFamilyNames,$(SOURCE)))) +FontStyles ?= $(sort $(foreach SOURCE,$(SOURCES_DESIGNSPACE),$(call designspaceInstances,$(SOURCE)))) +else +FamilyNames ?= $(sort $(foreach SOURCE,$(SOURCES_UFO),$(call ufoFamilyNames,$(SOURCE)))) +FontStyles ?= $(sort $(foreach SOURCE,$(SOURCES_UFO),$(call ufoInstances,$(SOURCE)))) +endif endif FamilyName ?= $(shell $(CONTAINERIZED) || $(PYTHON) $(PYTHONFLAGS) -c 'print("$(PROJECT)".replace("-", " ").title())') +# Output format selectors +STATICOTF ?= true +STATICTTF ?= true +STATICWOFF ?= true +STATICWOFF2 ?= true +VARIABLEOTF ?= +VARIABLETTF ?= $(isVariable) +VARIABLEWOFF ?= $(isVariable) +VARIABLEWOFF2 ?= $(isVariable) + INSTANCES ?= $(foreach FamilyName,$(FamilyNames),$(foreach STYLE,$(FontStyles),$(FamilyName)-$(STYLE))) GITVER = --tags --abbrev=6 --match='*[0-9].[0-9][0-9][0-9]' @@ -175,7 +144,12 @@ debug: echo isTagged = $(isTagged) echo ---------------------------- echo CANONICAL = $(CANONICAL) + echo isVariable = $(isVariable) echo SOURCES = $(SOURCES) + echo SOURCES_SFD = $(SOURCES_SFD) + echo SOURCES_GLYPHS = $(SOURCES_GLYPHS) + echo SOURCES_UFO = $(SOURCES_UFO) + echo SOURCES_DESIGNSPACE = $(SOURCES_DESIGNSPACE) echo INSTANCES = $(INSTANCES) echo STATICOTFS = $(STATICOTFS) echo STATICTTFS = $(STATICTTFS) @@ -187,7 +161,7 @@ debug: echo VARIABLEWOFF2S = $(VARIABLEWOFF2S) .PHONY: _gha -_gha: +_gha: debug fontship --version echo "::set-output name=PROJECT::$(PROJECT)" echo "::set-output name=font-version::$(FontVersion)" @@ -256,7 +230,7 @@ variable-woff2: $$(VARIABLEWOFF2S) .PHONY: normalize normalize: NORMALIZE_MODE = true -normalize: $(filter %.glyphs %.sfd %.ufo,$(SOURCES)) +normalize: $(SOURCES) .PHONY: check check: $(addsuffix -check,$(SOURCES))