From 4ded41f4a37133a7e73156619cfb0fd8de767143 Mon Sep 17 00:00:00 2001 From: Rasmus Andersson Date: Sat, 5 Jan 2019 16:20:22 -0800 Subject: Adds docker toolchain for a simpler build setup --- .gitignore | 1 + CONTRIBUTING.md | 40 ++++++++++++++++++++++++++---- Makefile | 60 +++++++++++++++------------------------------ dockermake | 11 +++++++++ init.sh | 66 ++++++++++++++++++++++++++++++++++++++++---------- misc/docker/Dockerfile | 37 ++++++++++++++++++++++++++++ misc/docker/build.sh | 48 ++++++++++++++++++++++++++++++++++++ misc/tools/common.py | 8 ++++-- 8 files changed, 210 insertions(+), 61 deletions(-) create mode 100755 dockermake create mode 100644 misc/docker/Dockerfile create mode 100755 misc/docker/build.sh diff --git a/.gitignore b/.gitignore index 9c238042d..215a1df4e 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ build /docs/lab/_serve* /docs/lab/fonts /docs/_site +/githash.txt src/FontInspector.html src/svg diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2b961f3c5..6d2d6583b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,18 +34,48 @@ If these rules are not followed, generated styles will fail to build. ## Compiling font files -There are two ways by which you can generate font files (OTF, TTF, WOFF2, etc) from the sources files: +There are three ways to generate font files (OTF, TTF, WOFF2, etc) from the sources files: +- Using Inter UI's own build system: `dockermake` and locally (see ["Using the toolchain"](#using-the-toolchain)) - Using the "export" feature in font editors like [Glyphs](https://glyphsapp.com/) or [RoboFont](http://robofont.com/) -- Using Inter UI's own build system (which requires no external tools.) Exporting from font editors is a great alternative if you just want to test things out, but using Inter UI's own build system is the way to go for "production quality" font files. The rest of this section covers how to use Inter UI's own build system, aka _the toolchain_. + ### Using the toolchain -Currently the toolchain has only been tested on macOS, and all you need is [Python](https://www.python.org/), which comes pre-installed with macOS, so no need to install anything. Python can easily be installed in Windows, Linux and other OSes. +The Inter UI toolchain is a collection of programs setup to build everything +in a high-quality and reliable way. It can be fully automated and requires no +paid software. + +TL;DR: to make & test everything: + +``` +./dockermake -j test +``` + +There are two ways of using the toolchain: + +- `dockermake` — a [prebuild Docker image](https://cloud.docker.com/u/rsms/repository/docker/rsms/inter-ui-build) containing the complete toolchain is used. This is the easiest and quickest way to build Inter UI. Supports any platform that can run Docker, like Windows, macOS and Linux. +- locally — setup the toolchain locally using `init.sh` and then build using make. Only supports macOS and Linux. + +#### Using dockermake + +`dockermake` is simply `make` running in a docker image with the complete toolchain preinstalled. + +Simply edit source files and run `dockermake [make-arg ...]` + +Example: + +``` +$ ./dockermake -j Regular SemiBoldItalic +misc/fontbuild instancegen src/Inter-UI.designspace SemiBoldItalic +... +``` + +#### Local toolchain -You'll want to open a Terminal for this. +Currently the toolchain has only been tested on macOS and Linux. All you need to have preinstalled is [Python 3](https://www.python.org/downloads/). The first step is to initialize the toolchain itself: @@ -60,7 +90,7 @@ This will fetch, setup and configure everything needed to build and test Inter U We can now run `make` to build all font files: ``` -$ make -j +$ make -j Regular SemiBoldItalic ``` This may take a long time (a few minutes) the first time as it generates "font instances" (i.e. all styles that are derived through interpolation from the master styles) in addition to compiling the actual font files (OTF, TTF, etc.) diff --git a/Makefile b/Makefile index 23d6cc6f9..858acfdb5 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,14 @@ all_var: \ $(FONTDIR)/var/Inter-UI-upright.var.ttf \ $(FONTDIR)/var/Inter-UI-italic.var.ttf -# Disabled. See https://github.com/rsms/inter/issues/75 +all_ufo_masters = $(Thin_ufo_d) \ + $(ThinItalic_ufo_d) \ + $(Regular_ufo_d) \ + $(Italic_ufo_d) \ + $(Black_ufo_d) \ + $(BlackItalic_ufo_d) + +# Hinted variable font disabled. See https://github.com/rsms/inter/issues/75 # all_var_hinted: $(FONTDIR)/var-hinted/Inter-UI.var.ttf $(FONTDIR)/var-hinted/Inter-UI.var.woff2 # .PHONY: all_var_hinted @@ -79,43 +86,13 @@ build/%.woff: build/%.ttf # make sure intermediate TTFs are not gc'd by make .PRECIOUS: build/%.ttf -# TTF -> EOT (disabled) -# build/%.eot: build/%.ttf -# ttf2eot "$<" > "$@" - - -# Master UFO -> OTF, TTF - -all_ufo_masters = $(Thin_ufo_d) \ - $(ThinItalic_ufo_d) \ - $(Regular_ufo_d) \ - $(Italic_ufo_d) \ - $(Black_ufo_d) \ - $(BlackItalic_ufo_d) +# Master UFOs -> variable TTF $(FONTDIR)/var/%.var.ttf: src/%.designspace $(all_ufo_masters) misc/fontbuild compile-var -o $@ $< -$(FONTDIR)/const/Inter-UI-Thin.%: src/Inter-UI.designspace $(Thin_ufo_d) - misc/fontbuild compile -o $@ src/Inter-UI-Thin.ufo - -$(FONTDIR)/const/Inter-UI-ThinItalic.%: src/Inter-UI.designspace $(ThinItalic_ufo_d) - misc/fontbuild compile -o $@ src/Inter-UI-ThinItalic.ufo - -$(FONTDIR)/const/Inter-UI-Regular.%: src/Inter-UI.designspace $(Regular_ufo_d) - misc/fontbuild compile -o $@ src/Inter-UI-Regular.ufo -$(FONTDIR)/const/Inter-UI-Italic.%: src/Inter-UI.designspace $(Italic_ufo_d) - misc/fontbuild compile -o $@ src/Inter-UI-Italic.ufo - -$(FONTDIR)/const/Inter-UI-Black.%: src/Inter-UI.designspace $(Black_ufo_d) - misc/fontbuild compile -o $@ src/Inter-UI-Black.ufo - -$(FONTDIR)/const/Inter-UI-BlackItalic.%: src/Inter-UI.designspace $(BlackItalic_ufo_d) - misc/fontbuild compile -o $@ src/Inter-UI-BlackItalic.ufo - - -# Instance UFO -> OTF, TTF +# Instance UFO -> OTF, TTF (note: masters' rules in generated.make) $(FONTDIR)/const/Inter-UI-%.otf: build/ufo/Inter-UI-%.ufo misc/fontbuild compile -o $@ $< @@ -154,6 +131,8 @@ $(FONTDIR)/const-hinted/%.ttf: $(FONTDIR)/const/%.ttf mkdir -p "$(dir $@)" ttfautohint --fallback-stem-width=256 --no-info "$<" "$@" +# python -m ttfautohint --fallback-stem-width=256 --no-info "$<" "$@" + # $(FONTDIR)/var-hinted/%.ttf: $(FONTDIR)/var/%.ttf # mkdir -p "$(dir $@)" # ttfautohint --fallback-stem-width=256 --no-info "$<" "$@" @@ -200,13 +179,6 @@ $(FONTDIR)/samples: -# load version, used by zip and dist -VERSION := $(shell cat version.txt) - -# distribution zip files -ZIP_FILE_DIST := build/release/Inter-UI-${VERSION}.zip -ZIP_FILE_DEV := build/release/Inter-UI-${VERSION}-$(shell git rev-parse --short=10 HEAD).zip - ZD = build/tmp/zip # intermediate zip target that creates a zip file at build/tmp/a.zip build/tmp/a.zip: @@ -246,6 +218,12 @@ build/tmp/a.zip: cd "$(ZD)" && zip -q -X -r "../../../$@" * && cd ../.. @rm -rf "$(ZD)" +# load version, used by zip and dist +VERSION := $(shell cat version.txt) + +# distribution zip files +ZIP_FILE_DIST := build/release/Inter-UI-${VERSION}.zip + # zip build/release/Inter-UI-%.zip: build/tmp/a.zip @mkdir -p "$(shell dirname "$@")" @@ -255,7 +233,7 @@ build/release/Inter-UI-%.zip: build/tmp/a.zip zip: all $(MAKE) check - $(MAKE) ${ZIP_FILE_DEV} + $(MAKE) build/release/Inter-UI-${VERSION}-$(shell git rev-parse --short=10 HEAD).zip zip_dist: pre_dist all $(MAKE) check diff --git a/dockermake b/dockermake new file mode 100755 index 000000000..87b069923 --- /dev/null +++ b/dockermake @@ -0,0 +1,11 @@ +#!/bin/bash -e +# +# Runs make in a prebuilt docker image. +# All you need to have installed is docker for this to work. +# This is an alternative to building locally. +# +cd "$(dirname "$0")" +if [[ -d .git ]]; then + git rev-parse --short HEAD > githash.txt +fi +docker run --rm -it -v "$PWD:/host" rsms/inter-ui-build:latest make "$@" diff --git a/init.sh b/init.sh index 7e29ed6c4..18dbd0143 100755 --- a/init.sh +++ b/init.sh @@ -22,7 +22,7 @@ if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then pushd "$SRCDIR" >/dev/null SRCDIR_ABS=$(pwd) popd >/dev/null - export PYTHONPATH=$SRCDIR_ABS/misc/pylib + export PYTHONPATH=$SRCDIR_ABS/misc/tools fi else # Subshell @@ -41,6 +41,15 @@ else clean=true fi + platform=osx + UNAME=$(uname) + if [[ "$UNAME" == *"inux"* ]]; then + platform=linux + elif [[ "$UNAME" != *"arwin"* ]]; then + echo "Unsupported platform $UNAME (only macOS and Linux are supported)" >&2 + exit 1 + fi + # —————————————————————————————————————————————————————————————————— # virtualenv @@ -194,6 +203,7 @@ else rm -rf "$DEPS_DIR/woff2" exit 1 fi + LINK=true elif [[ ! -f "$VENV_DIR/bin/woff2_compress" ]]; then LINK=true fi @@ -265,7 +275,7 @@ else if [[ ! -f "$OTS_DIR/ots-sanitize" ]]; then mkdir -p "$OTS_DIR" fetch \ - https://github.com/khaledhosny/ots/releases/download/v${OTS_VERSION}/ots-${OTS_VERSION}-osx.zip \ + https://github.com/khaledhosny/ots/releases/download/v${OTS_VERSION}/ots-${OTS_VERSION}-${platform}.zip \ "$OTS_DIR/ots.zip" pushd "$OTS_DIR" >/dev/null unzip ots.zip @@ -288,20 +298,40 @@ else AUTOHINT_VERSION=1.8.2 + AUTOHINT_SRC_VERSION=1.8.2.8 LINK=false if [[ ! -f "$DEPS_DIR/ttfautohint-${AUTOHINT_VERSION}" ]]; then - fetch \ - https://download.savannah.gnu.org/releases/freetype/ttfautohint-${AUTOHINT_VERSION}-tty-osx.tar.gz - "$DEPS_DIR/ttfautohint.tar.gz" - tar -C "$DEPS_DIR" -xzf "$DEPS_DIR/ttfautohint.tar.gz" - rm "$DEPS_DIR/ttfautohint.tar.gz" - mv -f "$DEPS_DIR/ttfautohint" "$DEPS_DIR/ttfautohint-${AUTOHINT_VERSION}" + if [[ "$platform" == "osx" ]]; then + fetch \ + https://download.savannah.gnu.org/releases/freetype/ttfautohint-${AUTOHINT_VERSION}-tty-osx.tar.gz \ + "$DEPS_DIR/ttfautohint.tar.gz" + tar -C "$DEPS_DIR" -xzf "$DEPS_DIR/ttfautohint.tar.gz" + rm "$DEPS_DIR/ttfautohint.tar.gz" + mv -f "$DEPS_DIR/ttfautohint" "$DEPS_DIR/ttfautohint-${AUTOHINT_VERSION}" + else + fetch \ + https://github.com/source-foundry/ttfautohint-build/archive/v${AUTOHINT_SRC_VERSION}.tar.gz \ + "$DEPS_DIR/ttfautohint-build.tar.gz" + pushd "$DEPS_DIR" >/dev/null + tar -xzf ttfautohint-build.tar.gz + rm ttfautohint-build.tar.gz + rm -rf ttfautohint-build + mv -f ttfautohint*/ ./ttfautohint-build + pushd ttfautohint-build >/dev/null + ./ttfautohint-build.sh + popd >/dev/null + mv -f \ + /root/ttfautohint-build/ttfautohint*/frontend/ttfautohint \ + "ttfautohint-${AUTOHINT_VERSION}" + rm -rf /root/ttfautohint-build ttfautohint-build + popd >/dev/null + fi LINK=true elif [[ ! -f "$VENV_DIR/bin/ttfautohint" ]]; then LINK=true fi if $LINK; then - ln -vfs ../../deps/ttfautohint-1.8.2 "$VENV_DIR/bin/ttfautohint" + ln -vfs ../../deps/ttfautohint-${AUTOHINT_VERSION} "$VENV_DIR/bin/ttfautohint" fi if [[ ! -f "$VENV_DIR/bin/ttf2woff" ]] || [[ ! -f "$SRCDIR/misc/ttf2woff/ttf2woff" ]]; then @@ -378,8 +408,20 @@ else echo -n " src/Inter-UI-${style}.ufo/*.plist" >> "$GEN_MAKE_FILE" echo -n " src/Inter-UI-${style}.ufo/*.fea" >> "$GEN_MAKE_FILE" echo -n " src/Inter-UI-${style}.ufo/glyphs/*.plist" >> "$GEN_MAKE_FILE" - echo -n " src/Inter-UI-${style}.ufo/glyphs/*.glif" >> "$GEN_MAKE_FILE" - echo ")" >> "$GEN_MAKE_FILE" + # echo -n " src/Inter-UI-${style}.ufo/glyphs/*.glif" >> "$GEN_MAKE_FILE" + echo -n ")" >> "$GEN_MAKE_FILE" + echo " src/Inter-UI.designspace" >> "$GEN_MAKE_FILE" + done + + echo "" >> "$GEN_MAKE_FILE" + + # master OTF and TTF rules + for style in "${master_styles[@]}"; do + echo "${DIST_DIR_TOK}const/Inter-UI-${style}.otf: \$(${style}_ufo_d)" >> "$GEN_MAKE_FILE" + echo -e "\tmisc/fontbuild compile -o \$@ src/Inter-UI-${style}.ufo" >> "$GEN_MAKE_FILE" + echo "${DIST_DIR_TOK}const/Inter-UI-${style}.ttf: \$(${style}_ufo_d)" >> "$GEN_MAKE_FILE" + echo -e "\tmisc/fontbuild compile -o \$@ src/Inter-UI-${style}.ufo" >> "$GEN_MAKE_FILE" + echo "" >> "$GEN_MAKE_FILE" done # generate all_ufo: @@ -388,8 +430,6 @@ else # echo -n " \$(${style}_ufo_d)" >> "$GEN_MAKE_FILE" # done # echo "" >> "$GEN_MAKE_FILE" - - echo "" >> "$GEN_MAKE_FILE" # add derived styles to style array for e in "${derived_styles[@]}"; do diff --git a/misc/docker/Dockerfile b/misc/docker/Dockerfile new file mode 100644 index 000000000..34ffed119 --- /dev/null +++ b/misc/docker/Dockerfile @@ -0,0 +1,37 @@ +FROM python:3.7-stretch + +RUN apt-get -qq update \ + && apt-get install -y -qq --no-install-recommends \ + git curl unzip build-essential ca-certificates ttfautohint \ + && pip install virtualenv + +RUN mkdir /inter +WORKDIR /inter + +COPY . /inter/ +RUN rm Dockerfile + +RUN ln -s /host/src src \ + && ln -s /host/version.txt . \ + && ln -s /host/githash.txt . \ + && ln -s /host/Makefile . \ + && ./init.sh \ + && rm -rf build/fonts \ + && mkdir -p /host/build/fonts \ + && ln -s /host/build/fonts build/fonts + +RUN rm init.sh && ln -s /host/init.sh . \ + && echo "source /inter/init.sh" >> "$HOME/.bashrc" \ + && echo "alias l='ls -lAF'" >> "$HOME/.bashrc" \ + && echo 'export PS1="\[\e[33;1m\]\u@\w\[\e[0m\]\\\$ "' >> "$HOME/.bashrc" + +# cleanup +RUN apt-get -y autoremove \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +ENV PATH=/inter/build/venv/bin:$PATH + +VOLUME /host + +CMD "/bin/bash" diff --git a/misc/docker/build.sh b/misc/docker/build.sh new file mode 100755 index 000000000..39313dc5b --- /dev/null +++ b/misc/docker/build.sh @@ -0,0 +1,48 @@ +#!/bin/bash -e +# +# Builds the docker image +# + +cd "$(dirname "$0")" +DOCKER_DIR=$(pwd) +cd ../.. +ROOT_DIR=$(pwd) + +IMAGE_NAME=rsms/inter-ui-build +BUILD_DIR=$ROOT_DIR/build/docker + +# setup build dir +mkdir -p "$BUILD_DIR/misc/tools" + +# copy files to build dir +echo "Syncing build dir" +cp -a \ + init.sh \ + requirements.txt \ + "$DOCKER_DIR/Dockerfile" \ + "$BUILD_DIR/" & +rsync -v -acC --delete --filter="- *.pyc" --filter="- /*/" \ + "misc/tools/" \ + "$BUILD_DIR/misc/tools/" & +rsync -v -acC --delete \ + misc/fontbuild \ + misc/fonttools-3.34.2-psCharStrings.patch \ + misc/ttf2woff \ + "$BUILD_DIR/misc/" +wait + +# update githash.txt +git rev-parse --short HEAD > githash.txt + +pushd "$BUILD_DIR" >/dev/null + +# build the image +echo "Building image. This might take a while..." +# docker build -f Dockerfile -t $IMAGE_NAME --squash . +docker build -f Dockerfile -t $IMAGE_NAME . + +echo "You can push the image to Docker hub:" +echo " docker push $IMAGE_NAME:latest" +echo "" +echo "Run interactively:" +echo " docker run --rm -it -v \"$ROOT_DIR:/host\" $IMAGE_NAME:latest" diff --git a/misc/tools/common.py b/misc/tools/common.py index 132558c2b..8f25f1989 100644 --- a/misc/tools/common.py +++ b/misc/tools/common.py @@ -43,11 +43,15 @@ def getGitHash(): try: _gitHash = subprocess.check_output( ['git', '-C', BASEDIR, 'rev-parse', '--short', 'HEAD'], - shell=False, + stderr=subprocess.STDOUT, **_enc_kwargs ).strip() except: - pass + try: + # git rev-parse --short HEAD > githash.txt + _gitHash = readTextFile(pjoin(BASEDIR, 'githash.txt')).strip() + except: + pass return _gitHash -- cgit v1.2.3