Skip to content

Commit

Permalink
Merge pull request #175097 from Aaron-212/fontcasker
Browse files Browse the repository at this point in the history
Add `brew font-casker` command
  • Loading branch information
krehel committed May 28, 2024
2 parents d9db799 + 22d3846 commit 0ff51c0
Showing 1 changed file with 143 additions and 0 deletions.
143 changes: 143 additions & 0 deletions cmd/font-casker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# frozen_string_literal: true

require "cli/parser"
require "open3"
require "digest"

module Homebrew
module_function

sig { returns(CLI::Parser) }
def font_casker_args
Homebrew::CLI::Parser.new do
usage_banner <<~EOS
`font-casker` <archive_path>
Generates cask stanzas from OTF/TTF files within <archive_path>.
EOS

named_args :archive_path, min: 1, max: 1

hide_from_man_page!
end
end

FONT_EXT_PATTERN = /.(otf|ttf)\Z/i

FONT_WEIGHTS = [
/black/i,
/bold/i,
/book/i,
/hairline/i,
/heavy/i,
/light/i,
/medium/i,
/normal/i,
/regular/i,
/roman/i,
/thin/i,
/ultra/i,
].freeze

FONT_STYLES = [
/italic/i,
/oblique/i,
/roman/i,
/slanted/i,
/upright/i,
].freeze

FONT_WIDTHS = [
/compressed/i,
/condensed/i,
/extended/i,
/narrow/i,
/wide/i,
].freeze

def mce(enum)
enum.group_by(&:itself).values.max_by(&:size).first
end

def eval_bin_cmd(cmd, blob)
IO.popen(cmd, "r+b") do |io|
io.print(blob)
io.close_write
io.read
end
end

def font_paths(archive)
cmd = ["zipinfo", "-1", archive]

IO.popen(cmd, "r", &:read)
.chomp.split("\n")
.grep(FONT_EXT_PATTERN)
.reject { |x| x.start_with?("__MACOSX") }
.grep_v(%r{(?:\A|/)\._})
.sort
end

def font_blobs(archive, paths)
paths.map { |x| IO.popen(["unzip", "-p", archive, x], "rb", &:read) }
end

def stanzify(stanza_name, val = "")
if val.respond_to?(:map)
val.map { |x| " #{stanza_name} \"#{x}\"" }.join("\n")
else
" #{stanza_name} \"#{val}\""
end
end

def caskify(family, version, sha, paths)
output = ["FAMILY: #{family}"]
output << ""
output << "cask 'FIXME' do"
output << stanzify("version", version)
output << stanzify("sha256", sha)
output << ""
output << stanzify("url", "")
output << stanzify("name", "")
output << stanzify("homepage", "")
output << ""
output << stanzify("font", paths)
output << ""
output << " # No zap stanza required"
output << "end"
output.join("\n")
end

def shasum(archive)
Digest::SHA256.file(archive)
end

def font_version(fontblobs)
cmd = ["otfinfo", "-v"]
versions = fontblobs.map { |x| eval_bin_cmd(cmd, x) }
.map { |x| (m = /\A(?:Version\s+)?(\d[^\s,;]*)/i.match(x)) ? m[1] : x.delete("\n") }
mce(versions)
end

def font_family(fontblobs)
cmd = ["otfinfo", "-a"]
families = fontblobs.map { |x| eval_bin_cmd(cmd, x) }
.map { |x| x.delete("\n") }
mce(families)
end

def font_casker
args = font_casker_args.parse
archive_path = args.named.first

paths = font_paths(archive_path)
blobs = font_blobs(archive_path, paths)

puts caskify(
font_family(blobs),
font_version(blobs),
shasum(archive_path),
paths,
)
end
end

0 comments on commit 0ff51c0

Please sign in to comment.