pax_global_header00006660000000000000000000000064142210372000014501gustar00rootroot0000000000000052 comment=54792e21456c3426ddd357a16ef7fd9d7c6217b2 bumpfontversion-0.4.0/000077500000000000000000000000001422103720000147425ustar00rootroot00000000000000bumpfontversion-0.4.0/README.md000066400000000000000000000022571422103720000162270ustar00rootroot00000000000000# bumpfontversion Version-bump your *source* font files. This tool, patterned after the wonderful [bumpversion](https://github.com/c4urself/bump2version), allows you to update the version of your font source files, as well as create commits and tags in git. It currently supports UFO and Glyphs format font files. ## Installation You can download and install the latest version of this software from the Python package index (PyPI) as follows: ```` pip install --upgrade bumpfontversion ``` ## Usage For users of bump2version, please note that the interface is slightly different. You can *either* use: ``` bumpfontversion --new-version 0.5 MyFont.ufo ``` to set the version directly, or ``` bumpfontversion --part minor MyFont.glyphs # Upgrade the minor version bumpfontversion --part major MyFont.glyphs # Upgrade the major version ``` As per bump2version, you can use `--commit` to commit the new version to git, and `--tag` to add a new git tag. ## See also * [bumpversion](https://github.com/c4urself/bump2version) * [font-v](https://github.com/source-foundry/font-v): Similar tool for font *binary* files ## License [Apache license](http://www.apache.org/licenses/LICENSE-2.0) bumpfontversion-0.4.0/bumpfontversion/000077500000000000000000000000001422103720000202025ustar00rootroot00000000000000bumpfontversion-0.4.0/bumpfontversion/__init__.py000066400000000000000000000000521422103720000223100ustar00rootroot00000000000000from bumpfontversion.__main__ import main bumpfontversion-0.4.0/bumpfontversion/__main__.py000077500000000000000000000142441422103720000223040ustar00rootroot00000000000000#!env python3 import sys from argparse import ArgumentParser from bumpversion.cli import ( _determine_vcs_dirty, _commit_to_vcs, _tag_in_vcs, _parse_new_version, ) from bumpversion.utils import ConfiguredFile from bumpversion.vcs import Git from bumpversion.version_part import VersionPart, VersionConfig import logging import os from datetime import datetime from fontTools.designspaceLib import DesignSpaceDocument from .ufohandler import UFOHandler from .glyphshandler import GlyphsHandler from .sfnthandler import SFNTHandler handlers = [UFOHandler(), GlyphsHandler(), SFNTHandler()] logging.basicConfig(format="%(name)s %(levelname)s: %(message)s") logger = logging.getLogger("bump2fontversion") time_context = {"now": datetime.now(), "utcnow": datetime.utcnow()} special_char_context = {c: c for c in ("#", ";")} parser = r"(?P\d+)\.(?P\d+)" serializer = "{major}.{minor}" vc = VersionConfig(parser, [serializer], None, None) def ufos_from_designspaces(designspaces): ufos = [] for fp in designspaces: ds = DesignSpaceDocument() ds.read(fp) for src in ds.sources: ufos.append(src.path) return ufos def main(): parser = ArgumentParser(description="Bump a font source version") parser.add_argument( "--dry-run", "-n", action="store_true", default=False, help="Don't write any files, just pretend.", ) parser.add_argument( "--verbose", "-V", action="store_true", default=False, help="Print verbose logging to stderr.", ) parser.add_argument( "--commit", action="store_true", dest="commit", help="Commit to version control", ) parser.add_argument( "--tag", action="store_true", dest="tag", help="Create a tag in version control", ) parser.add_argument( "--sign-tags", action="store_true", dest="sign_tags", help="Sign tags if created", ) parser.add_argument( "--tag-name", metavar="TAG_NAME", help="Tag name (only works with --tag)", default="v{new_version}", ) parser.add_argument( "--tag-message", metavar="TAG_MESSAGE", dest="tag_message", help="Tag message", default="Bump version: {current_version} → {new_version}", ) parser.add_argument( "--message", "-m", metavar="COMMIT_MSG", help="Commit message", default="Bump version: {current_version} → {new_version}", ) parser.add_argument( "--commit-args", metavar="COMMIT_ARGS", help="Extra arguments to commit command", default="", ) # This interface is slightly different than bump2version (but better!) gp = parser.add_mutually_exclusive_group(required=True) gp.add_argument( "--new-version", metavar="VERSION", help="New version that should be in the files", ) gp.add_argument( "--part", help="Part of the version to be bumped.", choices=["major", "minor"] ) parser.add_argument( "files", metavar="file", nargs="*", help="Files to change", ) args = parser.parse_args() defaults = {"allow_dirty": True} if args.verbose: logger.setLevel("INFO") print(logger.getEffectiveLevel()) if not args.files: print("No files to change; nothing to do") sys.exit(0) versions = {} new_version = None if args.new_version: new_version = _parse_new_version(args, None, vc) if new_version is None: logger.error(f"Bad version {args.new_version}; should be format X.Y") sys.exit(1) designspaces = [f for f in args.files if f.endswith(".designspace")] additional_ufos = ufos_from_designspaces(designspaces) if additional_ufos: args.files = [ f for f in args.files if not f.endswith(".designspace") ] + additional_ufos for f in args.files: handled = False if not os.path.exists(f): logger.warning("%s does not exist, skipping." % f) continue for h in handlers: if not h.applies_to(f): continue current_version = h.current_version(f) if not args.new_version: logger.info( f"Current version of {f} is {vc.serialize(current_version, {})}" ) new_version_for_this_file = current_version.bump( args.part, ["major", "minor"] ) else: new_version_for_this_file = new_version logger.info( f"New version of {f} is {vc.serialize(new_version_for_this_file, {})}" ) if not args.dry_run: h.set_version(f, new_version_for_this_file) versions.setdefault( (current_version, new_version_for_this_file), [] ).append(f) handled = True if not handled: logger.warning("No handler found for file %s, skipping." % f) if not args.commit and not args.tag: # All done sys.exit(0) vcs = _determine_vcs_dirty([Git], defaults) if vcs: for (old_version, new_version), files in versions.items(): files = [ConfiguredFile(f, True) for f in files] args.current_version = vc.serialize(old_version, {}) args.new_version = vc.serialize(new_version, {}) context = _commit_to_vcs( files, {}, None, False, vcs, args, old_version, new_version, ) _tag_in_vcs(vcs, context, args) def v_dict(version): major, minor = version return {"major": VersionPart(major), "minor": VersionPart(minor)} def bump_part(current, part): major, minor = current if part == "minor": return major, minor + 1 return major + 1, 0 def verify_version(new_version): parts = new_version.split(".") if len(parts) != 2: return None try: major, minor = parts return int(major), int(minor) except Exception: return None if __name__ == "__main__": main() bumpfontversion-0.4.0/bumpfontversion/glyphshandler.py000066400000000000000000000013671422103720000234270ustar00rootroot00000000000000from glyphsLib import GSFont import logging from bumpversion.version_part import Version, VersionPart logger = logging.getLogger(__name__) class GlyphsHandler: def applies_to(self, file): return file.endswith(".glyphs") def current_version(self, file): font = GSFont(file) return Version( { "major": VersionPart(str(font.versionMajor or 0)), "minor": VersionPart(str(font.versionMinor or 0)), } ) def set_version(self, file, new_version): font = GSFont(file) font.versionMajor = int(new_version["major"].value) font.versionMinor = int(new_version["minor"].value) logger.info(f"Saving file {file}") font.save(file) bumpfontversion-0.4.0/bumpfontversion/sfnthandler.py000066400000000000000000000034441422103720000230710ustar00rootroot00000000000000from fontTools.ttLib import TTFont from fontTools.varLib.instancer.names import _fontVersion, NameID import logging import re from bumpversion.version_part import Version, VersionPart logger = logging.getLogger(__name__) class SFNTHandler: def applies_to(self, file): return file.endswith((".ttf", ".otf", ".woff", ".woff2")) def current_version(self, file): font = TTFont(file) current = _fontVersion(font) major, minor = current.split(".") return Version( { "major": VersionPart(str(major or 0)), "minor": VersionPart(str(minor or 0)), } ) def set_version(self, file, new_version): font = TTFont(file) minor = new_version['minor'].value minor = minor.zfill(3) if int(minor) < 10 else minor major = new_version['major'].value version_string = f"{major}.{minor}" font["head"].fontRevision = float(version_string) current_version = _fontVersion(font) nametbl = font["name"] for rec in nametbl.names: if rec.nameID not in [NameID.VERSION_STRING, NameID.UNIQUE_FONT_IDENTIFIER]: logger.debug( f"Skipping ({rec.nameID}, {rec.platformID}, {rec.platEncID}, {rec.langID}): " f"{rec.toUnicode()}" ) continue new_string = re.sub(current_version, version_string, rec.toUnicode()) logger.info( f"Updating ({rec.nameID}, {rec.platformID}, {rec.platEncID}, {rec.langID}): " f"{rec.toUnicode()} --> {new_string}" ) nametbl.setName(new_string, rec.nameID, rec.platformID, rec.platEncID, rec.langID) logger.info(f"Saving file {file}") font.save(file) bumpfontversion-0.4.0/bumpfontversion/ufohandler.py000066400000000000000000000014551422103720000227100ustar00rootroot00000000000000import ufoLib2 import logging from bumpversion.version_part import Version, VersionPart logger = logging.getLogger(__name__) class UFOHandler: def applies_to(self, file): return file.endswith(".ufo") def current_version(self, file): font = ufoLib2.objects.Font.open(file) return Version( { "major": VersionPart(str(font.info.versionMajor or 0)), "minor": VersionPart(str(font.info.versionMinor or 0)), } ) def set_version(self, file, new_version): font = ufoLib2.objects.Font.open(file) font.info.versionMajor = int(new_version["major"].value) font.info.versionMinor = int(new_version["minor"].value) logger.info(f"Saving file {file}") font.save(file, overwrite=True) bumpfontversion-0.4.0/pyproject.toml000066400000000000000000000010121422103720000176500ustar00rootroot00000000000000[tool.poetry] name = "bumpfontversion" version = "0.4.0" description = "Bumps the version of a font source file" authors = ["Simon Cozens "] license = "Apache" readme = "README.md" [tool.poetry.dependencies] python = "^3.7" openstep-plist = "*" ufoLib2 = "*" glyphsLib = "6.0.0b4" fontTools = "*" bump2version = "1.0.1" [tool.poetry.dev-dependencies] [build-system] requires = ["poetry>=0.12"] build-backend = "poetry.masonry.api" [tool.poetry.scripts] bumpfontversion = 'bumpfontversion:main'