Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use fontc as alternative gftools.builder compiler #1046

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 60 additions & 2 deletions Lib/gftools/builder/operations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,25 @@
import pkgutil
import importlib
import inspect
import logging
import sys
from os.path import dirname
from tempfile import NamedTemporaryFile

from gftools.builder.file import File
from gftools.utils import shell_quote

log = logging.getLogger(__name__)


# Grossness to allow class properties in Python
class classproperty:
def __init__(self, func):
self.fget = func

def __get__(self, instance, owner):
return self.fget(owner)


@dataclass
class OperationBase:
Expand Down Expand Up @@ -131,9 +143,24 @@ def validate(self):


class FontmakeOperationBase(OperationBase):
COMPILER_ENV_KEY = "GFTOOLS_COMPILER"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

couldn't we just have a different subclass of OperationBase, and switch to that dynamically? then we'd avoid junking up this class with fontc stuff, and I could properly handle the arguments...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you believe it would be cleaner, I would be happy to see it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only part I'm not sure about is how best to swap the classes in the presence of the CLI flag. Do you have any ideas?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, not really. Once a class is loaded in Python it's unpleasant to try to change its base class. This is why I suggested doing things the way that I did ...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not following why we'd need to change base, we should have two different classes and pick which one to create based on cli. I don't know the gftools codebase, is there something about it that makes that difficult?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're not changing base class, then you will need six different classes (one implementation each of buildTTF, buildOTF, buildVariable for fontc and fontbakery). This is less elegant than the solution I'm proposing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I would dispute the elegance of writing if self.compiler == :)

static = False
format = "ttf"

@classproperty
def rule(self):
if self.compiler == "fontmake":
return "fontmake --output-path $out -o $format $fontmake_type $in $args"
else:
# Construct a ninja rule which correctly builds the requested font type
# (Good luck with fontmake args...)
return "fontc -o $out $in $args"

@property
def variables(self):
vars = defaultdict(str)
vars["compiler"] = self.compiler
vars["format"] = self.format # buildTTF -> ttf, etc.
for k, v in self.original.items():
if k != "needs":
vars[k] = v
Expand All @@ -144,11 +171,42 @@ def variables(self):
vars["fontmake_type"] = "-m"
elif self.first_source.is_ufo:
vars["fontmake_type"] = "-u"
if "--verbose" not in vars["fontmake_args"]:
vars["fontmake_args"] += " --verbose WARNING "
if "--verbose" not in vars["args"]:
vars["args"] += " --verbose WARNING "

if "--filter" in vars["args"] and self.compiler == "fontc":
log.warning("Cannot use --filter with fontc, dropping arguments...")
del vars["args"]

return vars

@property
def compiler(self):
return self.original.get(
"compiler", os.environ.get(self.COMPILER_ENV_KEY, "fontmake")
)

def validate(self):
if self.static:
if not self.first_source.exists():
# We can't check this file (assume it was generated as part of the
# build), so user is on their own.
return
if (
self.first_source.is_glyphs
and len(self.first_source.gsfont.masters) > 1
):
raise ValueError(
f"Cannot build a static font from {self.first_source.path}"
)
if (
self.first_source.designspace
and len(self.first_source.designspace.sources) > 1
):
raise ValueError(
f"Cannot build a static font from {self.first_source.path}"
)


known_operations = {}

Expand Down
20 changes: 2 additions & 18 deletions Lib/gftools/builder/operations/buildOTF.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,5 @@

class BuildOTF(FontmakeOperationBase):
description = "Build a OTF from a source file"
rule = "fontmake --output-path $out -o otf $fontmake_type $in $args"

def validate(self):
if not self.first_source.exists():
# We can't check this file (assume it was generated as part of the
# build), so user is on their own.
return
if self.first_source.is_glyphs and len(self.first_source.gsfont.masters) > 1:
raise ValueError(
f"Cannot build a static font from {self.first_source.path}"
)
if (
self.first_source.designspace
and len(self.first_source.designspace.sources) > 1
):
raise ValueError(
f"Cannot build a static font from {self.first_source.path}"
)
format = "otf"
static = True
20 changes: 2 additions & 18 deletions Lib/gftools/builder/operations/buildTTF.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,5 @@

class BuildTTF(FontmakeOperationBase):
description = "Build a TTF from a source file"
rule = "fontmake --output-path $out -o ttf $fontmake_type $in $args"

def validate(self):
if not self.first_source.exists():
# We can't check this file (assume it was generated as part of the
# build), so user is on their own.
return
if self.first_source.is_glyphs and len(self.first_source.gsfont.masters) > 1:
raise ValueError(
f"Cannot build a static font from {self.first_source.path}"
)
if (
self.first_source.designspace
and len(self.first_source.designspace.sources) > 1
):
raise ValueError(
f"Cannot build a static font from {self.first_source.path}"
)
static = True
format = "ttf"
3 changes: 2 additions & 1 deletion Lib/gftools/builder/operations/buildVariable.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@

class BuildVariable(FontmakeOperationBase):
description = "Build a variable font from a source file"
rule = "fontmake --output-path $out -o variable $fontmake_type $in $args"
format = "variable"
static = False
1 change: 1 addition & 0 deletions Lib/gftools/builder/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,5 +109,6 @@
Optional("extraStaticFontmakeArgs"): Str(),
Optional("buildSmallCap"): Bool(),
Optional("splitItalic"): Bool(),
Optional("localMetadata"): Any(),
}
)
3 changes: 3 additions & 0 deletions docs/gftools-builder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,9 @@ The build can be customized by adding the following keys to the YAML file:
subspace them into separate roman and italic VF files to comply with
Google Fonts' specification. Defaults to true.

- `localMetadata`: A field that's ignored so you can put whatever you like in it.


## *Really* customizing the build process

If the options above aren't enough for you - let's say you want to run your
Expand Down
Loading