Skip to content

Commit

Permalink
Merge pull request #779 from googlefonts/fontra-copy2
Browse files Browse the repository at this point in the history
fontra-copy: a tool to copy a font from one backend to another
  • Loading branch information
justvanrossum authored Sep 5, 2023
2 parents 694e496 + bd2d310 commit 5d97f90
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 0 deletions.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Source = "https://github.com/googlefonts/fontra"

[project.scripts]
fontra = "fontra.__main__:main"
fontra-copy = "fontra.backends.copy:main"


[project.entry-points."fontra.views"]
Expand Down
74 changes: 74 additions & 0 deletions src/fontra/backends/copy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import argparse
import asyncio
import logging
import pathlib
import shutil

from . import getFileSystemBackend, newFileSystemBackend

logger = logging.getLogger(__name__)


async def copyFont(sourceBackend, destBackend, *, numTasks=8):
await destBackend.putGlobalAxes(await sourceBackend.getGlobalAxes())
glyphMap = await sourceBackend.getGlyphMap()
glyphNamesToCopy = sorted(glyphMap)

# Needed for rcjk backend, but is a bug there
# _ = await destBackend.getGlyphMap()

tasks = [
asyncio.create_task(
copyGlyphs(sourceBackend, destBackend, glyphMap, glyphNamesToCopy)
)
for i in range(numTasks)
]
done, pending = await asyncio.wait(tasks)
# await asyncio.sleep(4)
assert not pending


async def copyGlyphs(sourceBackend, destBackend, glyphMap, glyphNamesToCopy):
while glyphNamesToCopy:
glyphName = glyphNamesToCopy.pop(0)
logger.info(f"reading {glyphName}")
glyph = await sourceBackend.getGlyph(glyphName)
logger.info(f"writing {glyphName}")
error = await destBackend.putGlyph(glyphName, glyph, glyphMap[glyphName])
if error:
# FIXME: putGlyph should always raise, and not return some error string
# This may be unique to the rcjk backend, though.
raise ValueError(error)


async def mainAsync():
parser = argparse.ArgumentParser()
parser.add_argument("source")
parser.add_argument("destination")
parser.add_argument("--overwrite", type=bool, default=False)

args = parser.parse_args()

sourcePath = pathlib.Path(args.source)
assert sourcePath.exists()
destPath = pathlib.Path(args.destination)
if args:
if destPath.is_dir():
shutil.rmtree(destPath)
elif destPath.exists():
destPath.unlink()
elif destPath.exists():
raise argparse.ArgumentError("the destination file already exists")

sourceBackend = getFileSystemBackend(sourcePath)
destBackend = newFileSystemBackend(destPath)

await copyFont(sourceBackend, destBackend)


def main():
asyncio.run(mainAsync())


if __name__ == "__main__":
main()
42 changes: 42 additions & 0 deletions test-py/test_backend_copy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import pathlib
import subprocess

from test_backend_designspace import fileNamesFromDir

from fontra.backends import getFileSystemBackend, newFileSystemBackend
from fontra.backends.copy import copyFont

mutatorDSPath = (
pathlib.Path(__file__).resolve().parent
/ "data"
/ "mutatorsans"
/ "MutatorSans.designspace"
)


async def test_copyFont(tmpdir):
tmpdir = pathlib.Path(tmpdir)
destPath = tmpdir / "MutatorCopy.designspace"
sourceFont = getFileSystemBackend(mutatorDSPath)
destFont = newFileSystemBackend(destPath)
await copyFont(sourceFont, destFont)
assert [
"MutatorCopy.designspace",
"MutatorCopy_BoldCondensed.ufo",
"MutatorCopy_BoldWide.ufo",
"MutatorCopy_LightWide.ufo",
"MutatorCopy_Regular.ufo",
] == fileNamesFromDir(tmpdir)


def test_fontra_copy(tmpdir):
tmpdir = pathlib.Path(tmpdir)
destPath = tmpdir / "MutatorCopy.designspace"
subprocess.run(["fontra-copy", mutatorDSPath, destPath])
assert [
"MutatorCopy.designspace",
"MutatorCopy_BoldCondensed.ufo",
"MutatorCopy_BoldWide.ufo",
"MutatorCopy_LightWide.ufo",
"MutatorCopy_Regular.ufo",
] == fileNamesFromDir(tmpdir)

0 comments on commit 5d97f90

Please sign in to comment.