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

Saving to .glyphspackage format? #953

Open
arrowtype opened this issue Oct 26, 2023 · 10 comments
Open

Saving to .glyphspackage format? #953

arrowtype opened this issue Oct 26, 2023 · 10 comments

Comments

@arrowtype
Copy link

It is awesome that glyphsLib (and fontmake) now support .glyphspackage files, as they are really nice for version control.

However, it looks like so far, glyphsLib only supports reading from .glyphspackage files (thanks to #803), but not writing back to them.

I am hoping to increment the version number of a glyphspackage source during a build process, so I would love it if glyphsLib could write to the new format, too.

As an example, here’s some Python I’m trying to use:

import sys
from glyphsLib import GSFont

glyphsSource = sys.argv[1]
versionMinor = sys.argv[2]

font = GSFont(glyphsSource)

font.versionMinor = int(versionMinor)

font.save(glyphsSource)

Unfortunately, running it currently gives this result:

▶ python source/01-build-scripts/helpers/update-glyphs-source-version.py source/familyname.glyphspackage 2
Traceback (most recent call last):
  File "/Users/stephennixon/type-repos/familyname/source/01-build-scripts/helpers/update-glyphs-source-version.py", line 11, in <module>
    font.save(glyphsSource)
  File "/Users/stephennixon/type-repos/familyname/venv/lib/python3.11/site-packages/glyphsLib/classes.py", line 4533, in save
    with open(path, "w", encoding="utf-8") as fp:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
IsADirectoryError: [Errno 21] Is a directory: 'source/familyname.glyphspackage'

So, partly I am just filing this issue as a feature request, in hopes that saving to glyphspackage might get support soonish.

I do also have two questions:

  1. Have I just missed something, and is this possible already?
  2. If this isn’t a feature yet, realistically, is this likely to be supported soonish? Or, is it a larger scope of work / not really a priority right now? (It’s all good either way, I’m just trying to plan for a couple of projects.)
  3. If it isn’t likely to happen soon, what might be a good way to handle this basic goal (incrementing versions for each build)? I could just use FontTools ttLib or font-v to write versions to font binaries only, or generate UFOs as a step of my build and edit the version number there... but is there another option that I might be missing?

Thanks so much for any insights and/or ideas!

@arrowtype
Copy link
Author

Re: question 3... I guess I could save to .glyphs format, then convert that to a glyphspackage. 🤔 I wonder if I’d lose any data that way. There’s one way to find out, I guess!

@anthrotype
Copy link
Member

We haven't implemented writing .glyphspackage yet (though it should not be too hard in theory).
If you're only interested in changing one field in the global fontinfo.plist just do that, loading the .glyphspackage in glyphsLib is expensive as it loads all the glyphs as well.
Use openstep_plist (which glyphsLib itself uses) to load the glyphspackage's fontinfo.plist, change the version and save it back

@arrowtype
Copy link
Author

Use openstep_plist (which glyphsLib itself uses) to load the glyphspackage's fontinfo.plist, change the version and save it back

Ah, awesome! I hoped someone might give a smart suggestion like this. Will try this out!

In the long run, yeah, I would love to be able to interact with glyphspackage files more fully via glyphsLib, but for now my need is very simple. Thanks for sharing that insight!

@arrowtype
Copy link
Author

arrowtype commented Oct 27, 2023

In case it helps anyone, here’s the code I ended up with. It seems to work well!

"""
    USAGE:
    python3 <path_to_script>/update-glyphs-source-version.py <path_to_glyphspackage>/familyname.glyphspackage <integer>
"""

import sys
import os
import openstep_plist

glyphsSource = sys.argv[1] # pass this in as first arg
versionMinor = sys.argv[2] # pass this in as second arg

# make path for fontinfo
fontinfoPath = os.path.join(glyphsSource, "fontinfo.plist")

# read the fontinfo.plist
with open(fontinfoPath, "r", encoding="utf-8") as fontinfo:
    data = openstep_plist.load(fontinfo, use_numbers=True)

# update the data from passed-in arg
data['versionMinor'] = int(versionMinor)

# write to the fontinfo.plist
with open(fontinfoPath, "w", encoding="utf-8") as fontinfo:

    # the extra args keep things closer to the formatting from GlyphsApp
    openstep_plist.dump(data, fontinfo, unicode_escape=False, indent=0, single_line_tuples=True)

# print the update
print(f'Updated {data["familyName"]} with version {data["versionMajor"]}.{str(data["versionMinor"]).zfill(3)}')

@arrowtype
Copy link
Author

I notice that the one drawback to my code is that it saves the plist with all feature code compressed onto single lines.

Is there a better way to handle that, to avoid meaningless Git commits?

image

@anthrotype
Copy link
Member

hm seems like openstep-plist writer always escapes newline characters and writes multi-line strings as a single line. There seems to be no option to pass through literal newlines:

https://github.com/fonttools/openstep-plist/blob/c9acd408ba3a374ba41dd62f595f43fa2e5bfa6f/src/openstep_plist/writer.pyx#L264-L265

I think glyphsLib only uses openstep-plist to parse, but not also to dump.
Anyway, apart from the git noise, both representation should be indentical and work the same.
Sorry about that

@arrowtype
Copy link
Author

Okay, thanks for confirming! I had explored the options, but wasn't getting closer.

I appreciate your help here!

@anthrotype
Copy link
Member

anthrotype commented Nov 2, 2023

If I remember correctly, once upon a time Glyphs.app would write multiline strings (e.g. features) with the newline escaped, even using octal codes \012 if I am not mistaken) then it got changed to write out the newlines as literal characters unescaped.
Anyway, openstep-plist will never match Glyphs.app 100% because it does not know about the quirks of the .glyphs format, it just treats everything the same way, cannot write e.g. unicodes one way or custom parameters antother way etc.

@schriftgestalt
Copy link
Collaborator

For simple changes like this, you could just read the file as a string and search and replace on it. That would keep the rest of the file unaffected.
Only adding new things might be a bit tricky.

@arrowtype
Copy link
Author

Ah, yeah, I guess I'm basically doing search and replace to fix things after changing them, so I could simplify it and just add the data the first time in glyphs, then search and replace only that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants