Browse files

'rake release' creates font with generated version number ♫

When a designer uses a font, it is critical that she or he can identify the
particular version unambigously. We also want to make sure that designers can
use our development snapshots. That’s why for every commit there needs to be a
potential version number. We could, theoretically, use git hashes as
identifiers. However, they look cryptic to end users, and they don’t provide
information about the chronology of versions.

Taking cues from the spec, our version number takes a form X.Y.Z.,
where X is the major version, Y the minor version, and Z the patch version.
Minor versions have a defined set of goals, and get tagged in Git, we started
with 0.0.0 and we are now working towards 0.1.0.

Our patch versions, are built from the source tree after each commit. So from
the first commit after 0.1.0 we can build 0.1.1.

To do a release, we use the ''git describe'' command to tell us the last tag
and the number of commits since that tag, whereupon we base a version number
that we bake into the ufo and thus into the generated font.
  • Loading branch information...
1 parent 4766f56 commit c01c1103bc8e17ba766fe492bae6a5fcd2988f9f @codingisacopingstrategy codingisacopingstrategy committed with Mar 16, 2011
Showing with 65 additions and 3 deletions.
  1. +65 −3 Rakefile
@@ -7,8 +7,6 @@
# the *corresponding* otf should be regenerated. This allows for additional
# font styles, and for the reuse of this Rakefile across font projects.
-# version = `python ./tools/`
UFO ='OpenBaskerville.ufo/**/*.*')
task :default => "OpenBaskerville.otf"
@@ -48,7 +46,7 @@ end
task :_has_otf_files do
if Dir["*.otf"].length == 0
abort "No otf files found. You can generate a working copy by running
+''rake''. You can build a release by running ''rake release''."
@@ -59,3 +57,67 @@ task :_has_git do
See on what git is and how to get it."
+# Check if the HEAD is clean
+task :_head_clean => :_has_git do
+ # This only works if Git >= 1.7.0
+ if `git status --porcelain` != ""
+ abort "You can only build releases from a clean working tree"
+ else
+ puts "HEAD clean"
+ end
+# Derive a version number from the current tag + number of commits (patch
+# version)
+task :_version_number => :_has_git do
+ git_describe = `git describe`.strip
+ # v0.0.0-49-gb5cc6c0 -> 0.0.49 (gb5cc6c0)
+ #
+ @version_number = git_describe.gsub /[v]?([0-9]+)\.([0-9]+)\.0-([0-9]+)-([\w]+)/ , '\1.\2.\3 (\4)'
+ if @version_number == git_describe
+ abort "Unable to automatically generate patch version number"
+ end
+ @version_number_short = @version_number.split[0]
+ puts "Generated version number #{@version_number}"
+task :_nokogiri do
+ require 'nokogiri'
+# Bake this version number into the UFO (and therefore, into generated OTF’s)
+task :_bake_version_number => [:_version_number, :_nokogiri] do
+# This would be cleaner to do with RoboFab, but Rakefiles need Ruby :)
+ f ="OpenBaskerville.ufo/fontinfo.plist","r")
+ doc = Nokogiri::XML(f)
+ f.close
+ keys = doc.css("dict key")
+ success = false
+ keys.each do |node|
+ if node.content == "openTypeNameVersion"
+ node.next_element.content = @version_number
+ success = true
+ elsif ["familyName","macintoshFONDName","postscriptFullName", "styleMapFamilyName"].include?(node.content)
+ node.next_element.content += ' ' + @version_number_short
+ elsif node.content == "postscriptFontName"
+ #No spaces in postscriptFontName
+ node.next_element.content += @version_number_short
+ end
+ end
+ g ="OpenBaskerville.ufo/fontinfo.plist","w")
+ g.write(doc)
+ g.close
+ if success
+ puts "Baked the generated version number into the UFO"
+ else
+ abort "Failed to bake the version number into the UFO"
+ end
+desc "Generate an OTF with proper version number in filename and metadata"
+task :release => [:_head_clean, :_bake_version_number, :fontlog] do
+ puts "Generating otf.."
+ sh "python ./tools/ OpenBaskerville.ufo OpenBaskerville-#{@version_number_short}.otf"
+ puts "Built release #{@version_number_short}!"

0 comments on commit c01c110

Please sign in to comment.