Skip to content

Commit

Permalink
Merge pull request #102 from googlefonts/refactor-ninja
Browse files Browse the repository at this point in the history
Refactor ninja
  • Loading branch information
m4rc1e authored Nov 1, 2023
2 parents 1cc3d5d + fb23064 commit e426b83
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 416 deletions.
283 changes: 95 additions & 188 deletions src/diffenator2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from diffenator2.font import DFont, get_font_styles
from diffenator2.utils import partition
from diffenator2.matcher import FontMatcher
from pkg_resources import resource_filename
import shutil
import ninja

logger = logging.getLogger(__name__)
Expand All @@ -18,76 +20,93 @@
NINJA_BUILD_FILE = "build.ninja"


class NinjaBuilder:
NINJA_LOG_FILE = ".ninja_log"
NINJA_BUILD_FILE = "build.ninja"

def __init__(self, cli_args):
self.cli_args = cli_args
self.w = Writer(open(NINJA_BUILD_FILE, "w", encoding="utf8"))

def run(self):
self.w.close()
ninja._program("ninja", [])

def proof_fonts(self):
self.w = Writer(open(NINJA_BUILD_FILE, "w", encoding="utf8"))
self.w.rule("proofing", '_diffbrowsers "$args"')
self.w.newline()
self.w.build(self.cli_args["out"], "proofing", variables={"args": repr(self.cli_args)})
self.run()

def diff_fonts(self, fonts_before, fonts_after):
self.w = Writer(open(NINJA_BUILD_FILE, "w", encoding="utf8"))
if self.cli_args["diffbrowsers"]:
self.w.rule("diffbrowsers", '_diffbrowsers "$args"')
self.w.build(self.cli_args["out"], "diffbrowsers", variables={"args": repr(self.cli_args)})
self.w.newline()

if self.cli_args["diffenator"]:
self.w.rule("diffenator", '_diffenator "$args"')
matcher = FontMatcher(fonts_before, fonts_after)

getattr(matcher, self.cli_args["styles"])(self.cli_args["filter_styles"])
for old_style, new_style in zip(matcher.old_styles, matcher.new_styles):
coords = new_style.coords
style = new_style.name.replace(" ", "-")
o = os.path.join(self.cli_args["out"], style.replace(" ", "-"))
self.w.build(o, "diffenator", variables={"args": repr(
{**self.cli_args, **{
"coords": dict_coords_to_string(coords),
"old_font": old_style.font.ttFont.reader.file.name,
"new_font": new_style.font.ttFont.reader.file.name,
"out": o,
}}
)})
self.run()

def __enter__(self):
return self

def __exit__(self, exc_type, exc_val, exc_tb):
# rm ninja cache files so we can rerun the tool
if os.path.exists(self.NINJA_BUILD_FILE):
os.remove(self.NINJA_BUILD_FILE)
if os.path.exists(self.NINJA_LOG_FILE):
os.remove(self.NINJA_LOG_FILE)


def ninja_proof(
fonts: list[DFont],
fonts,
out: str = "out",
imgs: bool = False,
styles="instances",
filter_styles: str = "",
characters: str = ".*",
pt_size: int = 20,
command="proof",
user_wordlist: str = "",
**kwargs
):
if not os.path.exists(out):
os.mkdir(out)

if filter_styles:
_ninja_proof(fonts, out, imgs, styles, filter_styles, characters, pt_size, user_wordlist)
return

font_styles = get_font_styles(fonts, styles)
partitioned = partition(font_styles, MAX_STYLES)
for font_styles in partitioned:
filter_styles = "|".join(s.name for s in font_styles)
o = os.path.join(out, filter_styles.replace("|", "-"))
if not os.path.exists(o):
os.mkdir(o)
_ninja_proof(fonts, o, imgs, styles, filter_styles, characters, pt_size, user_wordlist)


def _ninja_proof(
fonts: list[DFont],
out: str = "out",
imgs: bool = False,
styles: str = "instances",
filter_styles: str = "",
characters=".*",
pt_size: int = 20,
user_wordlist = "",
):
w = Writer(open(NINJA_BUILD_FILE, "w", encoding="utf8"))
w.comment("Rules")
w.newline()
out_s = os.path.join("out", "diffbrowsers")

cmd = f'_diffbrowsers proof $fonts -s $styles -o $out -pt $pt_size -ch "$characters"'
if imgs:
cmd += " --imgs"
if filter_styles:
cmd += f' --filter-styles "$filters"'
if user_wordlist:
cmd += f' --user-wordlist "$user_wordlist"'
w.rule("proofing", cmd)
w.newline()

# Setup build
w.comment("Build rules")
variables = dict(
fonts=[f'"{os.path.abspath(f.ttFont.reader.file.name)}"' for f in fonts],
styles=styles,
out=out_s,
pt_size=pt_size,
characters=characters,
)
if imgs:
variables["imgs"] = imgs
if filter_styles:
variables["filters"] = filter_styles
if user_wordlist:
variables["user_wordlist"] = user_wordlist
w.build(out, "proofing", variables=variables)
w.close()
ninja._program("ninja", [])
args = {**locals(), **locals().pop("kwargs")}
with NinjaBuilder(cli_args=args) as builder:
if filter_styles:
builder.proof_fonts()
return

dfonts = [DFont(f) for f in fonts]
font_styles = get_font_styles(dfonts, styles)
partitioned = partition(font_styles, MAX_STYLES)
for font_styles in partitioned:
filter_styles = "|".join(s.name for s in font_styles)
o = os.path.join(out, filter_styles.replace("|", "-"))
if not os.path.exists(o):
os.mkdir(o)
builder.cli_args["out"] = o
builder.cli_args["filter_styles"] = filter_styles
builder.proof_fonts()


def ninja_diff(
Expand All @@ -101,34 +120,28 @@ def ninja_diff(
characters: str = ".*",
user_wordlist: str = "",
filter_styles: str = "",
font_size: int = 20,
pt_size: int = 20,
threshold: float = THRESHOLD,
precision: int = FONT_SIZE,
no_words: bool = False,
no_tables: bool = False,
diffenator_template = resource_filename(
"diffenator2", os.path.join("templates", "diffenator.html")
),
command="diff",
**kwargs
):
args = {**locals(), **locals().pop("kwargs")}
if not os.path.exists(out):
os.mkdir(out)

if filter_styles:
_ninja_diff(
fonts_before,
fonts_after,
diffbrowsers,
diffenator,
out,
imgs,
styles,
characters,
user_wordlist,
filter_styles,
pt_size,
threshold=threshold,
precision=precision,
no_words=no_words,
no_tables=no_tables,
)
return
fonts_before = [DFont(f) for f in fonts_before]
fonts_after = [DFont(f) for f in fonts_after]
with NinjaBuilder(cli_args=args) as builder:
if filter_styles:
builder.diff_fonts(fonts_before, fonts_after)
return

matcher = FontMatcher(fonts_before, fonts_after)
getattr(matcher, styles)()
Expand All @@ -139,119 +152,13 @@ def ninja_diff(
"both fonts have designspaces which overlap or ensure that both "
"sets of static fonts have some matching styles."
)

partitioned = partition(matcher.old_styles, MAX_STYLES)
for p in partitioned:
filter_styles = "|".join(style.name for style in p)
o = os.path.join(out, filter_styles.replace("|", "-"))
if not os.path.exists(o):
os.mkdir(o)
_ninja_diff(
fonts_before,
fonts_after,
diffbrowsers,
diffenator,
o,
imgs,
styles,
characters,
user_wordlist,
filter_styles,
pt_size,
threshold=threshold,
precision=precision,
no_words=no_words,
no_tables=no_tables,
)

def _ninja_diff(
fonts_before: list[DFont],
fonts_after: list[DFont],
diffbrowsers: bool = True,
diffenator: bool = True,
out: str = "out",
imgs: bool = False,
styles="instances",
characters=".*",
user_wordlist: str = "",
filter_styles: str = "",
pt_size: int = 20,
threshold: float = THRESHOLD,
precision: int = FONT_SIZE,
no_words: bool = False,
no_tables: bool = False,
):
w = Writer(open(NINJA_BUILD_FILE, "w", encoding="utf8"))
# Setup rules
w.comment("Rules")
w.newline()
w.comment("Build Hinting docs")
db_cmd = f'_diffbrowsers diff -fb $fonts_before -fa $fonts_after -s $styles -o $out -pt $pt_size -ch "$characters"'
if imgs:
db_cmd += " --imgs"
if filter_styles:
db_cmd += ' --filter-styles "$filters"'
if user_wordlist:
db_cmd += ' --user-wordlist "$user_wordlist"'
w.rule("diffbrowsers", db_cmd)
w.newline()

w.comment("Run diffenator VF")
diff_cmd = f'_diffenator $font_before $font_after --font-size $precision -t $threshold -o $out -ch "$characters"'
if user_wordlist:
diff_cmd += ' --user-wordlist "$user_wordlist"'
if no_words:
diff_cmd += ' --no-words'
if no_tables:
diff_cmd += ' --no-tables'
diff_inst_cmd = diff_cmd + " --coords $coords"
w.rule("diffenator", diff_cmd)
w.rule("diffenator-inst", diff_inst_cmd)
w.newline()

# Setup build
w.comment("Build rules")
if diffbrowsers:
diffbrowsers_out = os.path.join(out, "diffbrowsers")
db_variables = dict(
fonts_before=[f'"{os.path.abspath(f.ttFont.reader.file.name)}"' for f in fonts_before],
fonts_after=[f'"{os.path.abspath(f.ttFont.reader.file.name)}"' for f in fonts_after],
styles=styles,
out=diffbrowsers_out,
pt_size=pt_size,
characters=characters,
)
if filter_styles:
db_variables["filters"] = filter_styles
if user_wordlist:
db_variables["user_wordlist"] = user_wordlist
w.build(diffbrowsers_out, "diffbrowsers", variables=db_variables)
if diffenator:
matcher = FontMatcher(fonts_before, fonts_after)
getattr(matcher, styles)(filter_styles)
for old_style, new_style in zip(matcher.old_styles, matcher.new_styles):
coords = new_style.coords
style = new_style.name.replace(" ", "-")
diff_variables: dict[str,str] = dict(
font_before=f'"{old_style.font.ttFont.reader.file.name}"',
font_after=f'"{new_style.font.ttFont.reader.file.name}"',
out=style,
threshold=str(threshold),
characters=characters,
precision=str(precision),
)
if user_wordlist:
diff_variables["user_wordlist"] = user_wordlist
if coords:
diff_variables["coords"] = dict_coords_to_string(coords)
w.build(
os.path.join(out, style),
"diffenator-inst",
variables=diff_variables,
)
else:
w.build(
os.path.join(out, style), "diffenator", variables=diff_variables
)
w.close()
ninja._program("ninja", [])
builder.cli_args["out"] = o
builder.cli_args["filter_styles"] = filter_styles
builder.diff_fonts(fonts_before, fonts_after)
45 changes: 11 additions & 34 deletions src/diffenator2/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from diffenator2.font import DFont
from diffenator2.html import build_index_page
from diffenator2.renderer import FONT_SIZE

from pkg_resources import resource_filename


def main(**kwargs):
Expand Down Expand Up @@ -49,45 +49,22 @@ def main(**kwargs):
diff_parser.add_argument("--no-diffenator", default=False, action="store_true")
diff_parser.add_argument("--threshold", "-t", type=float, default=THRESHOLD)
diff_parser.add_argument("--precision", default=FONT_SIZE)
# TODO this can just be precision
diff_parser.add_argument("--font-size", default=FONT_SIZE)
diff_parser.add_argument("--no-tables", action="store_true", help="Skip diffing font tables")
diff_parser.add_argument("--no-words", action="store_true", help="Skip diffing wordlists")
parser.add_argument(
"--diffenator-template",
default=resource_filename(
"diffenator2", os.path.join("templates", "diffenator.html")
),
)
args = parser.parse_args()

if os.path.exists(NINJA_BUILD_FILE):
os.remove(NINJA_BUILD_FILE)
if os.path.exists(".ninja_log"):
os.remove(".ninja_log")
if args.command == "proof":
fonts = [DFont(f) for f in args.fonts]
ninja_proof(
fonts,
out=args.out,
imgs=args.imgs,
styles=args.styles,
filter_styles=args.filter_styles,
characters=args.characters,
pt_size=args.pt_size,
user_wordlist=args.user_wordlist,
)
ninja_proof(**vars(args))
elif args.command == "diff":
fonts_before = [DFont(f) for f in args.fonts_before]
fonts_after = [DFont(f) for f in args.fonts_after]
ninja_diff(
fonts_before,
fonts_after,
out=args.out,
imgs=args.imgs,
styles=args.styles,
characters=args.characters,
diffenator=False if args.no_diffenator else True,
user_wordlist=args.user_wordlist,
filter_styles=args.filter_styles,
pt_size=args.pt_size,
threshold=args.threshold,
precision=args.precision,
no_words=args.no_words,
no_tables=args.no_tables,
)
ninja_diff(**vars(args))
else:
raise NotImplementedError(f"{args.command} not supported")
# TODO (Marc F) find a better home for this when refactoring
Expand Down
Loading

0 comments on commit e426b83

Please sign in to comment.