fontisan 0.4.46 → 0.4.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/BENCHMARKS.md +56 -0
- data/CHANGELOG.md +12 -0
- data/Cargo.lock +550 -0
- data/Cargo.toml +12 -0
- data/Gemfile +10 -0
- data/README.adoc +52 -0
- data/Rakefile +5 -1
- data/benchmark/baseline.json +5 -0
- data/benchmark/ci_gate.rb +217 -0
- data/benchmark/corpus/harness.rb +175 -0
- data/benchmark/corpus/ops.rb +150 -0
- data/benchmark/corpus/run.rb +182 -0
- data/benchmark/corpus/scan_child.rb +8 -0
- data/benchmark/corpus/tiers.rb +176 -0
- data/benchmark/tier_baseline.json +12 -0
- data/docs/.vitepress/config.ts +2 -1
- data/docs/guide/engines.md +117 -0
- data/docs/reference-facade.md +130 -0
- data/ext/fontisan_cdylib/Cargo.lock +313 -0
- data/ext/fontisan_cdylib/Cargo.toml +18 -0
- data/ext/fontisan_cdylib/build.rs +22 -0
- data/ext/fontisan_cdylib/extconf.rb +36 -0
- data/ext/fontisan_cdylib/src/lib.rs +13 -0
- data/ext/fontisan_native/Cargo.toml +21 -0
- data/ext/fontisan_native/build.rs +22 -0
- data/ext/fontisan_native/clippy.toml +10 -0
- data/ext/fontisan_native/extconf.rb +59 -0
- data/ext/fontisan_native/src/lib.rs +463 -0
- data/lib/fontisan/audit/checks/cmap_check.rb +7 -0
- data/lib/fontisan/audit/checks/hinting_check.rb +1 -1
- data/lib/fontisan/audit/checks/maxp_check.rb +1 -1
- data/lib/fontisan/audit/checks/opentype_conformance_check.rb +5 -2
- data/lib/fontisan/base_collection.rb +30 -0
- data/lib/fontisan/byte_ops.rb +219 -0
- data/lib/fontisan/cli.rb +5 -5
- data/lib/fontisan/commands/audit_command.rb +38 -43
- data/lib/fontisan/commands/convert_command.rb +53 -0
- data/lib/fontisan/commands/instance_command.rb +75 -0
- data/lib/fontisan/commands/subset_command.rb +43 -0
- data/lib/fontisan/commands/unpack_command.rb +56 -0
- data/lib/fontisan/converters/cff_table_builder.rb +1 -1
- data/lib/fontisan/converters/collection_converter.rb +13 -5
- data/lib/fontisan/converters/format_converter.rb +1 -1
- data/lib/fontisan/converters/woff2_encoder.rb +8 -6
- data/lib/fontisan/converters/woff_writer.rb +6 -5
- data/lib/fontisan/engine.rb +350 -0
- data/lib/fontisan/ffi/client.rb +121 -0
- data/lib/fontisan/ffi.rb +343 -0
- data/lib/fontisan/ffi_platform.rb +24 -0
- data/lib/fontisan/font_loader.rb +5 -1
- data/lib/fontisan/font_writer.rb +13 -1
- data/lib/fontisan/native.rb +231 -0
- data/lib/fontisan/pipeline/transformation_pipeline.rb +10 -8
- data/lib/fontisan/pipeline.rb +1 -1
- data/lib/fontisan/reference/table_digests.rb +251 -0
- data/lib/fontisan/reference.rb +619 -0
- data/lib/fontisan/scan.rb +372 -0
- data/lib/fontisan/sfnt_directory.rb +41 -0
- data/lib/fontisan/sfnt_font.rb +16 -6
- data/lib/fontisan/subset/builder.rb +2 -1
- data/lib/fontisan/tables/cff/charstring.rb +16 -0
- data/lib/fontisan/tables/cff.rb +15 -5
- data/lib/fontisan/tables/cmap.rb +11 -1
- data/lib/fontisan/tables/glyf.rb +4 -6
- data/lib/fontisan/tables/gpos.rb +7 -0
- data/lib/fontisan/tables/gsub.rb +7 -0
- data/lib/fontisan/tables/layout_common.rb +172 -0
- data/lib/fontisan/tables/name.rb +10 -4
- data/lib/fontisan/utilities/brotli_wrapper.rb +39 -4
- data/lib/fontisan/validators/opentype_validator.rb +15 -3
- data/lib/fontisan/variable/instancer.rb +23 -192
- data/lib/fontisan/variable/static_font_builder.rb +4 -1
- data/lib/fontisan/variable/table_updater.rb +4 -2
- data/lib/fontisan/variation/instance_generator.rb +3 -149
- data/lib/fontisan/variation/instancing/axis_space.rb +136 -0
- data/lib/fontisan/variation/instancing/glyph_outline.rb +204 -0
- data/lib/fontisan/variation/instancing/gvar_reader.rb +146 -0
- data/lib/fontisan/variation/instancing/item_variation_store.rb +92 -0
- data/lib/fontisan/variation/instancing/name_rewriter.rb +90 -0
- data/lib/fontisan/variation/instancing/true_type_instancer.rb +326 -0
- data/lib/fontisan/variation/instancing.rb +20 -0
- data/lib/fontisan/variation/variable_svg_generator.rb +19 -1
- data/lib/fontisan/variation.rb +1 -0
- data/lib/fontisan/version.rb +1 -1
- data/lib/fontisan/woff2/collection_decoder.rb +15 -1
- data/lib/fontisan/woff2/collection_encoder.rb +29 -6
- data/lib/fontisan/woff2/encoder_rules.rb +12 -4
- data/lib/fontisan/woff2/glyf_loca_reconstruct.rb +1 -1
- data/lib/fontisan/woff2_collection.rb +7 -5
- data/lib/fontisan/woff2_font.rb +12 -3
- data/lib/fontisan/woff_container.rb +83 -0
- data/lib/fontisan/woff_font.rb +24 -20
- data/lib/fontisan.rb +24 -1
- data/rakelib/bench.rake +9 -0
- data/rakelib/cdylib.rake +39 -0
- data/rakelib/corpus.rake +272 -0
- data/rakelib/corpus_convert.rake +43 -0
- data/rakelib/corpus_goldens.rake +22 -0
- data/rakelib/corpus_malformed.rake +20 -0
- data/rakelib/corpus_scan.rake +24 -0
- data/rakelib/java.rake +61 -0
- data/rakelib/native.rake +43 -0
- data/scripts/build-woff2.sh +57 -0
- data/scripts/corpus/generate_convert_goldens.rb +478 -0
- data/scripts/corpus/generate_goldens.rb +282 -0
- data/scripts/corpus/generate_malformed_goldens.rb +254 -0
- data/scripts/corpus/generate_scan_goldens.rb +98 -0
- data/scripts/tier_fallback.rb +219 -0
- data/scripts/tier_smoke.rb +64 -0
- metadata +75 -3
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../scripts/corpus/generate_convert_goldens"
|
|
4
|
+
|
|
5
|
+
# Convert goldens (card 0c). `corpus:convert:verify` only compares;
|
|
6
|
+
# `corpus:convert:regenerate` is the one task that writes. TIER=ci|large|all,
|
|
7
|
+
# ONLY=<font-id>[,<font-id>] narrows verify/regenerate. Needs `opentype-sanitizer`
|
|
8
|
+
# (OTS_PYTHON=<python with it>) and the pinned woff2_decompress.
|
|
9
|
+
module ConvertTasks
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
def tiers
|
|
13
|
+
Corpus.tiers_for(ENV.fetch("TIER", "ci"))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def only
|
|
17
|
+
ENV["ONLY"]&.split(",")
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
namespace :corpus do
|
|
22
|
+
namespace :convert do
|
|
23
|
+
desc "Regenerate convert goldens from the reference (TIER, ONLY)"
|
|
24
|
+
task regenerate: "corpus:fetch" do
|
|
25
|
+
files = ConvertGoldens.generate(ConvertTasks.tiers, only: ConvertTasks.only)
|
|
26
|
+
ConvertGoldens.write(files)
|
|
27
|
+
puts "[corpus:convert:regenerate] wrote #{files.size} goldens"
|
|
28
|
+
rescue ConvertGoldens::ToolMissing, Corpus::Error => e
|
|
29
|
+
abort "[corpus:convert:regenerate] #{e.message}"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
desc "Compare regenerated convert output with the committed goldens; never writes (TIER, ONLY)"
|
|
33
|
+
task verify: "corpus:fetch" do
|
|
34
|
+
problems = ConvertGoldens.verify(ConvertTasks.tiers, only: ConvertTasks.only)
|
|
35
|
+
problems.concat(ConvertGoldens.ots_failures.reject { |f| ConvertGoldens.listed_exceptions.include?(f) }
|
|
36
|
+
.map { |f| "#{f}: OTS failure not listed in corpus/TRIAGE_CONVERT.md" })
|
|
37
|
+
abort "[corpus:convert:verify] #{problems.size} problem(s):\n #{problems.join("\n ")}" unless problems.empty?
|
|
38
|
+
puts "[corpus:convert:verify] ok"
|
|
39
|
+
rescue ConvertGoldens::ToolMissing => e
|
|
40
|
+
abort "[corpus:convert:verify] #{e.message}"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Read goldens (fontist/fontisan#156 card 0b). `corpus:verify` compares only
|
|
4
|
+
# and never writes; `corpus:regenerate` rewrites the goldens and is explicit.
|
|
5
|
+
namespace :corpus do
|
|
6
|
+
desc "Compare the read goldens with fresh output (TIER=ci|large, default ci); never writes"
|
|
7
|
+
task verify: :fetch do
|
|
8
|
+
require_relative "../scripts/corpus/generate_goldens"
|
|
9
|
+
tier = ENV.fetch("TIER", "ci")
|
|
10
|
+
problems = CorpusGoldens.verify(tier)
|
|
11
|
+
abort "[corpus:verify] #{problems.size} problem(s):\n #{problems.join("\n ")}" unless problems.empty?
|
|
12
|
+
|
|
13
|
+
puts "[corpus:verify] tier #{tier}: #{CorpusGoldens.entries(tier).size} read goldens match"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
desc "Rewrite the read goldens from the corpus (TIER=ci|large); review the diff"
|
|
17
|
+
task regenerate: :fetch do
|
|
18
|
+
require_relative "../scripts/corpus/generate_goldens"
|
|
19
|
+
tier = ENV.fetch("TIER", "ci")
|
|
20
|
+
puts "[corpus:regenerate] wrote #{CorpusGoldens.write(tier)} goldens (tier #{tier})"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Malformed-input goldens (fontist/fontisan#156, card 0e).
|
|
4
|
+
namespace :corpus do
|
|
5
|
+
namespace :malformed do
|
|
6
|
+
desc "Check corpus/goldens/malformed against current Ruby behaviour"
|
|
7
|
+
task :verify do
|
|
8
|
+
require_relative "../scripts/corpus/generate_malformed_goldens"
|
|
9
|
+
problems = MalformedGoldens.verify
|
|
10
|
+
abort "[corpus:malformed:verify]\n #{problems.join("\n ")}" unless problems.empty?
|
|
11
|
+
puts "[corpus:malformed:verify] ok (#{MalformedGoldens.entries.size} kinds)"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
desc "Regenerate corpus/goldens/malformed (only in a PR that shows the golden diff)"
|
|
15
|
+
task :regenerate do
|
|
16
|
+
require_relative "../scripts/corpus/generate_malformed_goldens"
|
|
17
|
+
puts "[corpus:malformed:regenerate] wrote #{MalformedGoldens.regenerate} goldens"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Scan goldens (fontist/fontisan#156 card 0f). `corpus:scan:verify` compares
|
|
4
|
+
# only and never writes; `corpus:scan:regenerate` rewrites and is explicit.
|
|
5
|
+
namespace :corpus do
|
|
6
|
+
namespace :scan do
|
|
7
|
+
desc "Compare corpus/goldens/scan with fresh Reference.scan output (TIER=ci|large); never writes"
|
|
8
|
+
task verify: "corpus:fetch" do
|
|
9
|
+
require_relative "../scripts/corpus/generate_scan_goldens"
|
|
10
|
+
tier = ENV.fetch("TIER", "ci")
|
|
11
|
+
problems = ScanGoldens.verify(tier)
|
|
12
|
+
abort "[corpus:scan:verify] #{problems.size} problem(s):\n #{problems.join("\n ")}" unless problems.empty?
|
|
13
|
+
|
|
14
|
+
puts "[corpus:scan:verify] tier #{tier}: #{ScanGoldens.entries(tier).size} scan goldens match"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
desc "Rewrite the scan goldens (TIER=ci|large); review the diff"
|
|
18
|
+
task regenerate: "corpus:fetch" do
|
|
19
|
+
require_relative "../scripts/corpus/generate_scan_goldens"
|
|
20
|
+
tier = ENV.fetch("TIER", "ci")
|
|
21
|
+
puts "[corpus:scan:regenerate] wrote #{ScanGoldens.write(tier)} goldens (tier #{tier})"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
data/rakelib/java.rake
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# The `java`-platform gem (fontisan#156 card 2g). `brotli` is a C extension with
|
|
4
|
+
# no JRuby build, and a gemspec is evaluated when the gem is built, so JRuby
|
|
5
|
+
# gets its own gem: no `brotli`, no `rb_sys`, no magnus extension, a runtime
|
|
6
|
+
# dependency on `ffi`, and the cdylib for every bundled OS and architecture
|
|
7
|
+
# under lib/fontisan/ffi/<platform>/ (see Fontisan::FfiPlatform). WOFF2 there is
|
|
8
|
+
# served by the :ffi tier.
|
|
9
|
+
#
|
|
10
|
+
# rake java:gem # builds the host's cdylib, packs what is staged
|
|
11
|
+
# FONTISAN_JAVA_ALL=1 rake java:gem # CI: the four are already staged (extracted
|
|
12
|
+
# # from the platform gems); fail unless all are
|
|
13
|
+
# rake java:stage # only copies the host's cdylib into its directory
|
|
14
|
+
require "fileutils"
|
|
15
|
+
require "rubygems/package"
|
|
16
|
+
require_relative "../lib/fontisan/ffi_platform"
|
|
17
|
+
|
|
18
|
+
# Builds the java gem's specification from fontisan.gemspec.
|
|
19
|
+
module FontisanJavaGem
|
|
20
|
+
STAGED = "lib/fontisan/ffi/*/*fontisan_cdylib.{so,dylib,dll}"
|
|
21
|
+
|
|
22
|
+
def self.spec
|
|
23
|
+
# load caches its result: copy, or the mutations below reach the source spec.
|
|
24
|
+
base = Gem::Specification.load("fontisan.gemspec").dup
|
|
25
|
+
base.platform = "java"
|
|
26
|
+
base.extensions = []
|
|
27
|
+
base.dependencies.delete_if { |d| %w[brotli rb_sys].include?(d.name) }
|
|
28
|
+
base.add_dependency "ffi", "~> 1.15"
|
|
29
|
+
base.files = base.files.reject { |f| f.start_with?("ext/") } + Dir[STAGED]
|
|
30
|
+
base
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.staged_platforms
|
|
34
|
+
Dir[STAGED].map { |f| File.basename(File.dirname(f)) }.uniq
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
namespace :java do
|
|
39
|
+
desc "Build the host cdylib and copy it to lib/fontisan/ffi/<platform>/"
|
|
40
|
+
task :stage do
|
|
41
|
+
next if ENV["FONTISAN_JAVA_ALL"]
|
|
42
|
+
|
|
43
|
+
dir = Fontisan::FfiPlatform.dir or abort "no java-gem directory for #{RbConfig::CONFIG['host_os']}"
|
|
44
|
+
Rake::Task["cdylib:vendor"].invoke
|
|
45
|
+
dest = File.join("lib/fontisan/ffi", dir)
|
|
46
|
+
FileUtils.mkdir_p(dest)
|
|
47
|
+
FileUtils.cp(Dir["lib/fontisan/ffi/*fontisan_cdylib.{so,dylib,dll}"], dest)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
desc "Build pkg/fontisan-VERSION-java.gem without brotli, bundling the staged cdylibs"
|
|
51
|
+
task gem: :stage do
|
|
52
|
+
missing = Fontisan::FfiPlatform::DIRS - FontisanJavaGem.staged_platforms
|
|
53
|
+
abort "missing cdylibs for: #{missing.join(', ')}" if ENV["FONTISAN_JAVA_ALL"] && !missing.empty?
|
|
54
|
+
puts "bundling cdylibs for: #{FontisanJavaGem.staged_platforms.join(', ')}; not staged: #{missing.join(', ')}"
|
|
55
|
+
|
|
56
|
+
FileUtils.mkdir_p("pkg")
|
|
57
|
+
built = Gem::Package.build(FontisanJavaGem.spec)
|
|
58
|
+
FileUtils.mv(built, "pkg/")
|
|
59
|
+
puts "pkg/#{built}"
|
|
60
|
+
end
|
|
61
|
+
end
|
data/rakelib/native.rake
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Builds the :native tier (ext/fontisan_native, magnus + rb-sys) into
|
|
4
|
+
# lib/fontisan/native/ with `rake compile`, and the platform gems with
|
|
5
|
+
# `rake native gem` (this machine) or rb-sys-dock / oxidize-rb/actions/cross-gem
|
|
6
|
+
# (see .github/workflows/gem-build.yml). Needs a Rust toolchain: without cargo
|
|
7
|
+
# (or the rb_sys gem) the task is not defined and every other task still loads.
|
|
8
|
+
cargo = begin
|
|
9
|
+
system("cargo", "--version", out: File::NULL, err: File::NULL)
|
|
10
|
+
rescue SystemCallError
|
|
11
|
+
false
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# A musl cdylib cannot link with a static C runtime, and the native extension
|
|
15
|
+
# is itself a shared object. rb-sys-dock exports the target as RUST_TARGET.
|
|
16
|
+
rust_target = ENV["CARGO_BUILD_TARGET"] || ENV["RUST_TARGET"] || ENV.fetch("RUBY_TARGET", nil)
|
|
17
|
+
if rust_target.to_s.include?("musl") && !ENV.fetch("RUSTFLAGS", "").include?("crt-static")
|
|
18
|
+
ENV["RUSTFLAGS"] = [ENV.fetch("RUSTFLAGS", nil), "-C target-feature=-crt-static"].compact.join(" ")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
if cargo
|
|
22
|
+
begin
|
|
23
|
+
require "rb_sys/extensiontask"
|
|
24
|
+
|
|
25
|
+
RbSys::ExtensionTask.new("fontisan_native", Gem::Specification.load("fontisan.gemspec")) do |ext|
|
|
26
|
+
ext.ext_dir = "ext/fontisan_native"
|
|
27
|
+
ext.lib_dir = "lib/fontisan/native"
|
|
28
|
+
|
|
29
|
+
# Runs when a platform gem's spec is assembled. The platform gem carries
|
|
30
|
+
# its binaries and builds nothing at install: no extension, no rb_sys, no
|
|
31
|
+
# cdylib sources, and the cdylib built for this target (lib/fontisan/ffi)
|
|
32
|
+
# next to the magnus extension, so the :ffi tier works too.
|
|
33
|
+
ext.cross_compiling do |spec|
|
|
34
|
+
Rake::Task["cdylib:vendor"].invoke
|
|
35
|
+
spec.extensions.clear
|
|
36
|
+
spec.files.reject! { |f| f.start_with?("ext/") }
|
|
37
|
+
spec.files += Dir["lib/fontisan/ffi/*.{so,dylib,dll}"]
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
rescue LoadError
|
|
41
|
+
# rb_sys / rake-compiler absent: nothing to compile.
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Build Google's woff2_decompress from a pinned source commit (brotli comes
|
|
3
|
+
# pinned via the woff2 submodule). Used by the corpus to cross-check the
|
|
4
|
+
# WOFF2 collection and, later, to compare WOFF/WOFF2 encode output after
|
|
5
|
+
# decoding (compressed bytes depend on the brotli build, so they are not
|
|
6
|
+
# compared directly).
|
|
7
|
+
#
|
|
8
|
+
# Why `make` and not CMake: upstream's CMakeLists.txt resolves brotli with
|
|
9
|
+
# find_package (the SYSTEM brotli, measured: a CMake build on macOS linked
|
|
10
|
+
# /opt/homebrew brotli), which would silently un-pin brotli. The Makefile
|
|
11
|
+
# compiles the brotli submodule sources into the binary, so the whole decoder
|
|
12
|
+
# is pinned by one commit.
|
|
13
|
+
#
|
|
14
|
+
# Linux / macOS: needs git, make, a C/C++ compiler.
|
|
15
|
+
# Windows: run from an MSYS2 MINGW64 shell with
|
|
16
|
+
# pacman -S --needed git make mingw-w64-x86_64-gcc
|
|
17
|
+
# (upstream google/woff2 has no Windows CI; this path is untested upstream.)
|
|
18
|
+
#
|
|
19
|
+
# Output: prints the absolute path of woff2_decompress on stdout (last line).
|
|
20
|
+
# Override the install dir with WOFF2_DIR.
|
|
21
|
+
set -euo pipefail
|
|
22
|
+
|
|
23
|
+
PIN="7b67e12355fe7da148db5c19d4261f0a498a9537"
|
|
24
|
+
REPO="https://github.com/google/woff2.git"
|
|
25
|
+
root="$(cd "$(dirname "$0")/.." && pwd)"
|
|
26
|
+
dest="${WOFF2_DIR:-$root/corpus/fonts/.tools/woff2}"
|
|
27
|
+
src="$dest/src"
|
|
28
|
+
exe="$dest/bin/woff2_decompress"
|
|
29
|
+
case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) exe="$exe.exe" ;; esac
|
|
30
|
+
|
|
31
|
+
if [ -x "$exe" ] && [ "$(cat "$dest/PIN" 2>/dev/null || true)" = "$PIN make" ]; then
|
|
32
|
+
echo "woff2_decompress already built at pin $PIN" >&2
|
|
33
|
+
echo "$exe"
|
|
34
|
+
exit 0
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
command -v git >/dev/null || { echo "build-woff2: git is required" >&2; exit 1; }
|
|
38
|
+
command -v make >/dev/null || { echo "build-woff2: make is required" >&2; exit 1; }
|
|
39
|
+
|
|
40
|
+
rm -rf "$dest"
|
|
41
|
+
mkdir -p "$dest/bin"
|
|
42
|
+
git clone --recursive "$REPO" "$src" >&2
|
|
43
|
+
(
|
|
44
|
+
cd "$src"
|
|
45
|
+
git checkout --quiet "$PIN"
|
|
46
|
+
git submodule update --init --recursive >&2
|
|
47
|
+
test "$(git rev-parse HEAD)" = "$PIN"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
(cd "$src" && make woff2_decompress -j"$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 2)" >&2)
|
|
51
|
+
|
|
52
|
+
built="$src/woff2_decompress"
|
|
53
|
+
[ -f "$built" ] || built="$src/woff2_decompress.exe"
|
|
54
|
+
[ -f "$built" ] || { echo "build-woff2: woff2_decompress not produced" >&2; exit 1; }
|
|
55
|
+
cp "$built" "$exe"
|
|
56
|
+
echo "$PIN make" > "$dest/PIN"
|
|
57
|
+
echo "$exe"
|