fontist 1.4.0 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +176 -6
- data/bin/fontist +1 -2
- data/fontist.gemspec +2 -0
- data/lib/fontist.rb +5 -0
- data/lib/fontist/cli.rb +59 -9
- data/lib/fontist/errors.rb +3 -0
- data/lib/fontist/font.rb +29 -6
- data/lib/fontist/font_formula.rb +35 -4
- data/lib/fontist/formula.rb +16 -1
- data/lib/fontist/formula_template.rb +41 -22
- data/lib/fontist/import/create_formula.rb +15 -30
- data/lib/fontist/import/files/collection_file.rb +11 -7
- data/lib/fontist/import/files/file_requirement.rb +17 -0
- data/lib/fontist/import/files/font_detector.rb +48 -0
- data/lib/fontist/import/formula_builder.rb +57 -6
- data/lib/fontist/import/google/skiplist.yml +2 -0
- data/lib/fontist/import/helpers/system_helper.rb +4 -1
- data/lib/fontist/import/otf/font_file.rb +20 -4
- data/lib/fontist/import/recursive_extraction.rb +99 -15
- data/lib/fontist/manifest.rb +2 -0
- data/lib/fontist/manifest/install.rb +32 -0
- data/lib/fontist/manifest/locations.rb +60 -0
- data/lib/fontist/system_font.rb +72 -6
- data/lib/fontist/system_index.rb +92 -0
- data/lib/fontist/utils.rb +1 -0
- data/lib/fontist/utils/cache.rb +27 -8
- data/lib/fontist/utils/downloader.rb +54 -10
- data/lib/fontist/utils/dsl.rb +4 -0
- data/lib/fontist/utils/dsl/collection_font.rb +36 -0
- data/lib/fontist/utils/dsl/font.rb +2 -1
- data/lib/fontist/utils/exe_extractor.rb +19 -9
- data/lib/fontist/utils/ui.rb +4 -0
- data/lib/fontist/utils/zip_extractor.rb +20 -11
- data/lib/fontist/version.rb +1 -1
- metadata +37 -3
- data/bin/stripttc +0 -0
data/lib/fontist/font_formula.rb
CHANGED
@@ -95,8 +95,10 @@ module Fontist
|
|
95
95
|
styles = options.fetch(:extract_styles_from_collection, [])
|
96
96
|
|
97
97
|
unless styles.empty?
|
98
|
-
styles.map do |
|
99
|
-
|
98
|
+
styles.map do |attributes|
|
99
|
+
filenames = temp_resource.slice(:filename, :source_filename)
|
100
|
+
Fontist::Utils::Dsl::CollectionFont.new(attributes.merge(filenames))
|
101
|
+
.attributes
|
100
102
|
end
|
101
103
|
end
|
102
104
|
end
|
@@ -109,8 +111,11 @@ module Fontist
|
|
109
111
|
end
|
110
112
|
|
111
113
|
def download_file(source)
|
114
|
+
url = source[:urls].first
|
115
|
+
Fontist.ui.say(%(Downloading font "#{key}" from #{url}))
|
116
|
+
|
112
117
|
downloaded_file = Fontist::Utils::Downloader.download(
|
113
|
-
|
118
|
+
url,
|
114
119
|
sha: source[:sha256],
|
115
120
|
file_size: source[:file_size],
|
116
121
|
progress_bar: is_progress_bar_enabled
|
@@ -121,7 +126,33 @@ module Fontist
|
|
121
126
|
end
|
122
127
|
|
123
128
|
def is_progress_bar_enabled
|
124
|
-
options.nil? ?
|
129
|
+
options.nil? ? true : options.fetch(:progress_bar, true)
|
130
|
+
end
|
131
|
+
|
132
|
+
def font_file?(filename)
|
133
|
+
source_files.include?(filename)
|
134
|
+
end
|
135
|
+
|
136
|
+
def source_files
|
137
|
+
@source_files ||= fonts.flat_map do |font|
|
138
|
+
font[:styles].map do |style|
|
139
|
+
style[:source_font] || style[:font]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def target_filename(source_filename)
|
145
|
+
target_filenames[source_filename]
|
146
|
+
end
|
147
|
+
|
148
|
+
def target_filenames
|
149
|
+
@target_filenames ||= fonts.flat_map do |font|
|
150
|
+
font[:styles].map do |style|
|
151
|
+
source = style[:source_font] || style[:font]
|
152
|
+
target = style[:font]
|
153
|
+
[source, target]
|
154
|
+
end
|
155
|
+
end.to_h
|
125
156
|
end
|
126
157
|
end
|
127
158
|
end
|
data/lib/fontist/formula.rb
CHANGED
@@ -2,6 +2,7 @@ module Fontist
|
|
2
2
|
class Formula
|
3
3
|
def initialize(options = {})
|
4
4
|
@font_name = options.fetch(:font_name, nil)
|
5
|
+
@style_name = options.fetch(:style_name, nil)
|
5
6
|
|
6
7
|
check_and_register_font_formulas
|
7
8
|
end
|
@@ -18,6 +19,10 @@ module Fontist
|
|
18
19
|
new(font_name: name).find_fonts
|
19
20
|
end
|
20
21
|
|
22
|
+
def self.find_styles(font, style)
|
23
|
+
new(font_name: font, style_name: style).find_styles
|
24
|
+
end
|
25
|
+
|
21
26
|
def all
|
22
27
|
@all ||= Fontist::Registry.instance.formulas
|
23
28
|
end
|
@@ -32,9 +37,19 @@ module Fontist
|
|
32
37
|
fonts.empty? ? nil : fonts
|
33
38
|
end
|
34
39
|
|
40
|
+
def find_styles
|
41
|
+
formulas.values.flat_map do |formula|
|
42
|
+
formula.fonts.flat_map do |f|
|
43
|
+
f.styles.select do |s|
|
44
|
+
f.name.casecmp?(font_name) && s.type.casecmp?(style_name)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
35
50
|
private
|
36
51
|
|
37
|
-
attr_reader :font_name
|
52
|
+
attr_reader :font_name, :style_name
|
38
53
|
|
39
54
|
def find_formula
|
40
55
|
find_by_key || find_by_font_name || find_by_font || []
|
@@ -2,9 +2,10 @@ module Fontist
|
|
2
2
|
class FormulaTemplate
|
3
3
|
def self.create_formula_class(formula)
|
4
4
|
Class.new(FontFormula) do |klass|
|
5
|
-
|
5
|
+
first_font = (formula.fonts || formula.font_collections.first.fonts).first
|
6
|
+
cleanname = first_font.name.gsub(/ /, "")
|
6
7
|
resource_name = formula.resources.to_h.keys.first
|
7
|
-
font_filename =
|
8
|
+
font_filename = first_font.styles.first.font
|
8
9
|
|
9
10
|
key formula.key&.to_sym || formula.name.gsub(/ /, "_").downcase.to_sym
|
10
11
|
display_progress_bar formula.display_progress_bar if formula.display_progress_bar
|
@@ -22,31 +23,47 @@ module Fontist
|
|
22
23
|
formula.font_collections.each do |collection|
|
23
24
|
provides_font_collection do
|
24
25
|
filename collection.filename
|
26
|
+
source_filename collection.source_filename
|
25
27
|
|
26
28
|
collection.fonts.each do |font|
|
27
|
-
|
28
|
-
|
29
|
+
provides_font(
|
30
|
+
font.name,
|
31
|
+
extract_styles_from_collection: font.styles.map do |style|
|
32
|
+
{
|
33
|
+
family_name: style.family_name,
|
34
|
+
style: style.type,
|
35
|
+
full_name: style.full_name,
|
36
|
+
post_script_name: style.post_script_name,
|
37
|
+
version: style.version,
|
38
|
+
description: style.description,
|
39
|
+
copyright: style.copyright,
|
40
|
+
}
|
41
|
+
end
|
42
|
+
)
|
29
43
|
end
|
30
44
|
end
|
31
45
|
end
|
32
46
|
end
|
33
47
|
|
34
|
-
formula.fonts
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
48
|
+
if formula.fonts
|
49
|
+
formula.fonts.each do |font|
|
50
|
+
provides_font(
|
51
|
+
font.name,
|
52
|
+
match_styles_from_file: font.styles.map do |style|
|
53
|
+
{
|
54
|
+
family_name: style.family_name,
|
55
|
+
style: style.type,
|
56
|
+
full_name: style.full_name,
|
57
|
+
post_script_name: style.post_script_name,
|
58
|
+
version: style.version,
|
59
|
+
description: style.description,
|
60
|
+
filename: style.font,
|
61
|
+
source_filename: style.source_font,
|
62
|
+
copyright: style.copyright,
|
63
|
+
}
|
64
|
+
end
|
65
|
+
)
|
66
|
+
end
|
50
67
|
end
|
51
68
|
|
52
69
|
klass.define_method :extract do
|
@@ -61,8 +78,10 @@ module Fontist
|
|
61
78
|
end
|
62
79
|
end
|
63
80
|
|
64
|
-
formula.fonts
|
65
|
-
|
81
|
+
if formula.fonts
|
82
|
+
formula.fonts.each do |font|
|
83
|
+
match_fonts(resource, font.name)
|
84
|
+
end
|
66
85
|
end
|
67
86
|
|
68
87
|
if formula.font_collections
|
@@ -8,10 +8,6 @@ require_relative "formula_builder"
|
|
8
8
|
module Fontist
|
9
9
|
module Import
|
10
10
|
class CreateFormula
|
11
|
-
FONT_PATTERN = /(\.ttf|\.otf)$/i.freeze
|
12
|
-
FONT_COLLECTION_PATTERN = /\.ttc$/i.freeze
|
13
|
-
LICENSE_PATTERN = /(OFL\.txt|UFL\.txt|LICENSE\.txt)$/i.freeze
|
14
|
-
|
15
11
|
def initialize(url, options = {})
|
16
12
|
@url = url
|
17
13
|
@options = options
|
@@ -26,41 +22,30 @@ module Fontist
|
|
26
22
|
def formula
|
27
23
|
builder = FormulaBuilder.new
|
28
24
|
builder.url = @url
|
29
|
-
builder.archive =
|
30
|
-
builder.extractor = extractor
|
25
|
+
builder.archive = archive
|
26
|
+
builder.extractor = extractor
|
31
27
|
builder.options = @options
|
32
|
-
builder.font_files = font_files
|
33
|
-
builder.font_collection_files = font_collection_files
|
34
|
-
builder.license_text =
|
28
|
+
builder.font_files = extractor.font_files
|
29
|
+
builder.font_collection_files = extractor.font_collection_files
|
30
|
+
builder.license_text = extractor.license_text
|
35
31
|
builder.formula
|
36
32
|
end
|
37
33
|
|
38
|
-
def
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
def extractor
|
35
|
+
@extractor ||=
|
36
|
+
RecursiveExtraction.new(archive,
|
37
|
+
subarchive: @options[:subarchive],
|
38
|
+
subdir: @options[:subdir])
|
42
39
|
end
|
43
40
|
|
44
|
-
def
|
45
|
-
|
41
|
+
def archive
|
42
|
+
@archive ||= download(@url)
|
46
43
|
end
|
47
44
|
|
48
|
-
def
|
49
|
-
|
50
|
-
Otf::FontFile.new(path)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def font_collection_files(extractor)
|
55
|
-
extractor.extract(FONT_COLLECTION_PATTERN) do |path|
|
56
|
-
Files::CollectionFile.new(path)
|
57
|
-
end
|
58
|
-
end
|
45
|
+
def download(url)
|
46
|
+
return url if File.exist?(url)
|
59
47
|
|
60
|
-
|
61
|
-
extractor.extract(LICENSE_PATTERN) do |path|
|
62
|
-
File.read(path)
|
63
|
-
end
|
48
|
+
Fontist::Utils::Downloader.download(url, progress_bar: true).path
|
64
49
|
end
|
65
50
|
|
66
51
|
def save(hash)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require "extract_ttc"
|
1
2
|
require "fontist/import/helpers/system_helper"
|
2
3
|
require_relative "../otf/font_file"
|
3
4
|
|
@@ -5,17 +6,20 @@ module Fontist
|
|
5
6
|
module Import
|
6
7
|
module Files
|
7
8
|
class CollectionFile
|
8
|
-
STRIP_TTC_BINARY = Fontist.root_path.join("bin", "stripttc")
|
9
|
-
|
10
9
|
attr_reader :fonts
|
11
10
|
|
12
11
|
def initialize(path)
|
13
12
|
@path = path
|
14
13
|
@fonts = read
|
14
|
+
@extension = "ttc"
|
15
15
|
end
|
16
16
|
|
17
17
|
def filename
|
18
|
-
File.basename(@path)
|
18
|
+
File.basename(@path, ".*") + "." + @extension
|
19
|
+
end
|
20
|
+
|
21
|
+
def source_filename
|
22
|
+
File.basename(@path) unless filename == File.basename(@path)
|
19
23
|
end
|
20
24
|
|
21
25
|
private
|
@@ -37,10 +41,10 @@ module Fontist
|
|
37
41
|
end
|
38
42
|
|
39
43
|
def extract_ttfs(tmp_dir)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
+
filenames = ExtractTtc.extract(@path)
|
45
|
+
filenames.map do |filename|
|
46
|
+
File.join(tmp_dir, filename)
|
47
|
+
end
|
44
48
|
end
|
45
49
|
end
|
46
50
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Fontist
|
2
|
+
module Import
|
3
|
+
module Files
|
4
|
+
class FileRequirement
|
5
|
+
def initialize
|
6
|
+
`file -v`
|
7
|
+
rescue Errno::ENOENT
|
8
|
+
abort "`file` is not available. (Or is PATH not setup properly?)"
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(path)
|
12
|
+
Helpers::SystemHelper.run("file --brief '#{path}'")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative "file_requirement"
|
2
|
+
|
3
|
+
module Fontist
|
4
|
+
module Import
|
5
|
+
module Files
|
6
|
+
class FontDetector
|
7
|
+
REQUIREMENTS = { file: FileRequirement.new }.freeze
|
8
|
+
|
9
|
+
FONT_LABELS = ["OpenType font data",
|
10
|
+
"TrueType Font data"].freeze
|
11
|
+
|
12
|
+
COLLECTION_LABEL = "TrueType font collection data".freeze
|
13
|
+
|
14
|
+
FONT_EXTENSIONS = {
|
15
|
+
"OpenType font data" => "otf",
|
16
|
+
"TrueType Font data" => "ttf",
|
17
|
+
"TrueType font collection data" => "ttc",
|
18
|
+
}.freeze
|
19
|
+
|
20
|
+
def self.detect(path)
|
21
|
+
brief = file_brief(path)
|
22
|
+
|
23
|
+
if brief.start_with?(*FONT_LABELS)
|
24
|
+
:font
|
25
|
+
elsif brief.start_with?(COLLECTION_LABEL)
|
26
|
+
:collection
|
27
|
+
else
|
28
|
+
:other
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.standard_extension(path)
|
33
|
+
brief = file_brief(path)
|
34
|
+
|
35
|
+
FONT_EXTENSIONS.each do |label, extension|
|
36
|
+
return extension if brief.start_with?(label)
|
37
|
+
end
|
38
|
+
|
39
|
+
raise Errors::UnknownFontTypeError.new(path)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.file_brief(path)
|
43
|
+
REQUIREMENTS[:file].call(path)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -39,7 +39,7 @@ module Fontist
|
|
39
39
|
|
40
40
|
def group_fonts
|
41
41
|
files = (@font_files + @font_collection_files.map(&:fonts)).flatten
|
42
|
-
raise FontNotFoundError, "No font found" if files.empty?
|
42
|
+
raise Errors::FontNotFoundError, "No font found" if files.empty?
|
43
43
|
|
44
44
|
files
|
45
45
|
end
|
@@ -55,10 +55,51 @@ module Fontist
|
|
55
55
|
def resources
|
56
56
|
filename = name.gsub(" ", "_") + "." + @extractor.extension
|
57
57
|
|
58
|
-
|
59
|
-
|
58
|
+
{ filename => resource_options }
|
59
|
+
end
|
60
|
+
|
61
|
+
def resource_options
|
62
|
+
urls = []
|
63
|
+
sha = []
|
64
|
+
downloads do |url, path|
|
65
|
+
urls << url
|
66
|
+
sha << Digest::SHA256.file(path).to_s
|
67
|
+
end
|
68
|
+
|
69
|
+
sha = prepare_sha256(sha)
|
70
|
+
|
71
|
+
{ urls: urls, sha256: sha }
|
72
|
+
end
|
73
|
+
|
74
|
+
def downloads
|
75
|
+
yield @url, @archive
|
76
|
+
|
77
|
+
mirrors.each do |url|
|
78
|
+
path = download(url)
|
79
|
+
next unless path
|
60
80
|
|
61
|
-
|
81
|
+
yield url, path
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def mirrors
|
86
|
+
@options[:mirror] || []
|
87
|
+
end
|
88
|
+
|
89
|
+
def download(url)
|
90
|
+
Fontist::Utils::Downloader.download(url, progress_bar: true).path
|
91
|
+
rescue Errors::InvalidResourceError
|
92
|
+
Fontist.ui.error("WARN: a mirror is not found '#{url}'")
|
93
|
+
nil
|
94
|
+
end
|
95
|
+
|
96
|
+
def prepare_sha256(input)
|
97
|
+
output = input.uniq
|
98
|
+
return output.first if output.size == 1
|
99
|
+
|
100
|
+
checksums = output.join(", ")
|
101
|
+
Fontist.ui.error("WARN: SHA256 differs (#{checksums})")
|
102
|
+
output
|
62
103
|
end
|
63
104
|
|
64
105
|
def font_collections
|
@@ -66,7 +107,10 @@ module Fontist
|
|
66
107
|
|
67
108
|
collections = @font_collection_files.map do |file|
|
68
109
|
fonts = fonts_from_files(file.fonts, :to_collection_style)
|
69
|
-
|
110
|
+
|
111
|
+
{ filename: file.filename,
|
112
|
+
source_filename: file.source_filename,
|
113
|
+
fonts: fonts }.compact
|
70
114
|
end
|
71
115
|
|
72
116
|
collections.sort_by do |x|
|
@@ -106,7 +150,14 @@ module Fontist
|
|
106
150
|
end
|
107
151
|
|
108
152
|
def open_license
|
109
|
-
|
153
|
+
unless @license_text
|
154
|
+
Fontist.ui.error("WARN: please add license manually")
|
155
|
+
return
|
156
|
+
end
|
157
|
+
|
158
|
+
Fontist.ui.error("WARN: ensure it's an open license, otherwise " \
|
159
|
+
"change the 'open_license' attribute to " \
|
160
|
+
"'requires_license_agreement'")
|
110
161
|
|
111
162
|
TextHelper.cleanup(@license_text)
|
112
163
|
end
|