fontist 1.7.0 → 1.8.2
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/.github/workflows/release.yml +38 -0
- data/.github/workflows/rspec.yml +58 -0
- data/README.md +123 -32
- data/{bin → exe}/fontist +0 -0
- data/fontist.gemspec +5 -2
- data/lib/fontist.rb +10 -3
- data/lib/fontist/cli.rb +62 -41
- data/lib/fontist/errors.rb +14 -12
- data/lib/fontist/font.rb +29 -31
- data/lib/fontist/font_installer.rb +114 -0
- data/lib/fontist/fontist_font.rb +3 -49
- data/lib/fontist/formula.rb +88 -66
- data/lib/fontist/formula_paths.rb +43 -0
- data/lib/fontist/helpers.rb +7 -0
- data/lib/fontist/import/create_formula.rb +3 -2
- data/lib/fontist/import/google/skiplist.yml +3 -0
- data/lib/fontist/import/google_check.rb +1 -1
- data/lib/fontist/import/google_import.rb +3 -4
- data/lib/fontist/import/otfinfo_generate.rb +1 -1
- data/lib/fontist/import/recursive_extraction.rb +6 -2
- data/lib/fontist/import/sil_import.rb +99 -0
- data/lib/fontist/index.rb +72 -0
- data/lib/fontist/index_formula.rb +30 -0
- data/lib/fontist/manifest/install.rb +4 -9
- data/lib/fontist/manifest/locations.rb +28 -20
- data/lib/fontist/system_font.rb +20 -60
- data/lib/fontist/system_index.rb +92 -0
- data/lib/fontist/utils/exe_extractor.rb +1 -1
- data/lib/fontist/utils/zip_extractor.rb +1 -1
- data/lib/fontist/version.rb +1 -1
- metadata +57 -20
- data/.github/workflows/macosx.yml +0 -33
- data/.github/workflows/ubuntu.yml +0 -30
- data/.github/workflows/windows.yml +0 -32
- data/bin/check_google +0 -8
- data/bin/console +0 -11
- data/bin/convert_formulas +0 -8
- data/bin/generate_otfinfo +0 -8
- data/bin/import_google +0 -8
- data/bin/rspec +0 -29
- data/bin/setup +0 -7
- data/lib/fontist/font_formula.rb +0 -158
- data/lib/fontist/formula_template.rb +0 -122
- data/lib/fontist/formulas.rb +0 -56
- data/lib/fontist/registry.rb +0 -43
data/lib/fontist/errors.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
module Fontist
|
2
2
|
module Errors
|
3
|
-
class
|
4
|
-
class
|
5
|
-
class
|
6
|
-
class
|
7
|
-
class InvalidResourceError <
|
8
|
-
class
|
9
|
-
class
|
10
|
-
class
|
11
|
-
class
|
12
|
-
class
|
13
|
-
class
|
14
|
-
class
|
3
|
+
class GeneralError < StandardError; end
|
4
|
+
class BinaryCallError < GeneralError; end
|
5
|
+
class FontNotFoundError < GeneralError; end
|
6
|
+
class FormulaIndexNotFoundError < GeneralError; end
|
7
|
+
class InvalidResourceError < GeneralError; end
|
8
|
+
class LicensingError < GeneralError; end
|
9
|
+
class ManifestCouldNotBeFoundError < GeneralError; end
|
10
|
+
class ManifestCouldNotBeReadError < GeneralError; end
|
11
|
+
class MissingAttributeError < GeneralError; end
|
12
|
+
class MissingFontError < GeneralError; end
|
13
|
+
class NonSupportedFontError < GeneralError; end
|
14
|
+
class TamperedFileError < GeneralError; end
|
15
|
+
class TimeoutError < GeneralError; end
|
16
|
+
class UnknownFontTypeError < GeneralError; end
|
15
17
|
end
|
16
18
|
end
|
data/lib/fontist/font.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
require "fontist/font_installer"
|
2
|
+
|
1
3
|
module Fontist
|
2
4
|
class Font
|
3
5
|
def initialize(options = {})
|
4
|
-
@name = options
|
5
|
-
@confirmation = options
|
6
|
-
@force = options
|
6
|
+
@name = options[:name]
|
7
|
+
@confirmation = options[:confirmation] || "no"
|
8
|
+
@force = options[:force] || false
|
7
9
|
|
8
10
|
check_or_create_fontist_path!
|
9
11
|
end
|
@@ -20,10 +22,6 @@ module Fontist
|
|
20
22
|
new(name: name, confirmation: confirmation, force: force).install
|
21
23
|
end
|
22
24
|
|
23
|
-
def self.try_install(name, confirmation: "no")
|
24
|
-
new(name: name, confirmation: confirmation).try_install
|
25
|
-
end
|
26
|
-
|
27
25
|
def self.uninstall(name)
|
28
26
|
new(name: name).uninstall
|
29
27
|
end
|
@@ -37,43 +35,31 @@ module Fontist
|
|
37
35
|
end
|
38
36
|
|
39
37
|
def find
|
40
|
-
find_system_font || downloadable_font ||
|
41
|
-
Fontist::Errors::NonSupportedFontError
|
42
|
-
)
|
38
|
+
find_system_font || downloadable_font || raise_non_supported_font
|
43
39
|
end
|
44
40
|
|
45
41
|
def install
|
46
|
-
(find_system_font unless @force) || download_font ||
|
47
|
-
Fontist::Errors::NonSupportedFontError
|
48
|
-
)
|
49
|
-
end
|
50
|
-
|
51
|
-
def try_install
|
52
|
-
download_font
|
42
|
+
(find_system_font unless @force) || download_font || raise_non_supported_font
|
53
43
|
end
|
54
44
|
|
55
45
|
def uninstall
|
56
|
-
uninstall_font || downloadable_font ||
|
57
|
-
Fontist::Errors::NonSupportedFontError
|
58
|
-
)
|
46
|
+
uninstall_font || downloadable_font || raise_non_supported_font
|
59
47
|
end
|
60
48
|
|
61
49
|
def status
|
62
50
|
return installed_statuses unless @name
|
63
51
|
|
64
|
-
font_status || downloadable_font ||
|
65
|
-
Fontist::Errors::NonSupportedFontError
|
66
|
-
)
|
52
|
+
font_status || downloadable_font || raise_non_supported_font
|
67
53
|
end
|
68
54
|
|
69
55
|
def list
|
70
56
|
return all_list unless @name
|
71
57
|
|
72
|
-
font_list ||
|
58
|
+
font_list || raise_non_supported_font
|
73
59
|
end
|
74
60
|
|
75
61
|
def all
|
76
|
-
Fontist::Formula.all.
|
62
|
+
Fontist::Formula.all.map(&:fonts).flatten
|
77
63
|
end
|
78
64
|
|
79
65
|
private
|
@@ -101,7 +87,7 @@ module Fontist
|
|
101
87
|
end
|
102
88
|
|
103
89
|
def font_installer(formula)
|
104
|
-
|
90
|
+
FontInstaller.new(formula)
|
105
91
|
end
|
106
92
|
|
107
93
|
def formula
|
@@ -122,8 +108,7 @@ module Fontist
|
|
122
108
|
def download_font
|
123
109
|
if formula
|
124
110
|
check_and_confirm_required_license(formula)
|
125
|
-
paths = font_installer(formula).
|
126
|
-
confirmation: confirmation)
|
111
|
+
paths = font_installer(formula).install(confirmation: confirmation)
|
127
112
|
|
128
113
|
Fontist.ui.say("Fonts installed at:")
|
129
114
|
paths.each do |path|
|
@@ -136,7 +121,7 @@ module Fontist
|
|
136
121
|
if formula.license_required && !confirmation.casecmp("yes").zero?
|
137
122
|
@confirmation = show_license_and_ask_for_input(formula.license)
|
138
123
|
|
139
|
-
|
124
|
+
unless confirmation&.casecmp?("yes")
|
140
125
|
raise Fontist::Errors::LicensingError.new(
|
141
126
|
"Fontist will not download these fonts unless you accept the terms."
|
142
127
|
)
|
@@ -186,7 +171,7 @@ module Fontist
|
|
186
171
|
end
|
187
172
|
|
188
173
|
def all_formulas
|
189
|
-
Fontist::Formula.all
|
174
|
+
Fontist::Formula.all
|
190
175
|
end
|
191
176
|
|
192
177
|
def font_status
|
@@ -213,7 +198,9 @@ module Fontist
|
|
213
198
|
end
|
214
199
|
|
215
200
|
def path(style)
|
216
|
-
font_paths.
|
201
|
+
font_paths.detect do |path|
|
202
|
+
File.basename(path) == style.font
|
203
|
+
end
|
217
204
|
end
|
218
205
|
|
219
206
|
def font_paths
|
@@ -247,5 +234,16 @@ module Fontist
|
|
247
234
|
def installed(style)
|
248
235
|
path(style) ? true : false
|
249
236
|
end
|
237
|
+
|
238
|
+
def raise_non_supported_font
|
239
|
+
raise Fontist::Errors::NonSupportedFontError.new(
|
240
|
+
"Font '#{@name}' not found locally nor available in the Fontist " \
|
241
|
+
"formula repository.\n" \
|
242
|
+
"Perhaps it is available at the latest Fontist formula " \
|
243
|
+
"repository.\n" \
|
244
|
+
"You can update the formula repository using the command " \
|
245
|
+
"`fontist update` and try again."
|
246
|
+
)
|
247
|
+
end
|
250
248
|
end
|
251
249
|
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require "fontist/utils"
|
2
|
+
|
3
|
+
module Fontist
|
4
|
+
class FontInstaller
|
5
|
+
include Utils::ZipExtractor
|
6
|
+
include Utils::ExeExtractor
|
7
|
+
include Utils::MsiExtractor
|
8
|
+
include Utils::SevenZipExtractor
|
9
|
+
|
10
|
+
def initialize(formula)
|
11
|
+
@formula = formula
|
12
|
+
end
|
13
|
+
|
14
|
+
def install(confirmation:)
|
15
|
+
if @formula.license_required && !"yes".casecmp?(confirmation)
|
16
|
+
raise(Fontist::Errors::LicensingError)
|
17
|
+
end
|
18
|
+
|
19
|
+
reinitialize
|
20
|
+
install_font
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_reader :formula
|
26
|
+
|
27
|
+
def reinitialize
|
28
|
+
@downloaded = false
|
29
|
+
end
|
30
|
+
|
31
|
+
def install_font
|
32
|
+
fonts_paths = run_in_temp_dir { extract }
|
33
|
+
fonts_paths.empty? ? nil : fonts_paths
|
34
|
+
end
|
35
|
+
|
36
|
+
def run_in_temp_dir
|
37
|
+
Dir.mktmpdir(nil, Dir.tmpdir) do |dir|
|
38
|
+
@temp_dir = Pathname.new(dir)
|
39
|
+
|
40
|
+
result = yield
|
41
|
+
|
42
|
+
@temp_dir = nil
|
43
|
+
|
44
|
+
result
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def extract
|
49
|
+
resource = @formula.resources.first
|
50
|
+
|
51
|
+
[@formula.extract].flatten.each do |operation|
|
52
|
+
resource = extract_by_operation(operation, resource)
|
53
|
+
end
|
54
|
+
|
55
|
+
fonts_paths = resource
|
56
|
+
|
57
|
+
fonts_paths
|
58
|
+
end
|
59
|
+
|
60
|
+
def extract_by_operation(operation, resource)
|
61
|
+
method = "#{operation.format}_extract"
|
62
|
+
if operation.options
|
63
|
+
send(method, resource, **operation.options.to_h)
|
64
|
+
else
|
65
|
+
send(method, resource)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def fonts_path
|
70
|
+
Fontist.fonts_path
|
71
|
+
end
|
72
|
+
|
73
|
+
def download_file(source)
|
74
|
+
url = source.urls.first
|
75
|
+
Fontist.ui.say(%(Downloading font "#{@formula.key}" from #{url}))
|
76
|
+
|
77
|
+
downloaded_file = Fontist::Utils::Downloader.download(
|
78
|
+
url,
|
79
|
+
sha: source.sha256,
|
80
|
+
file_size: source.file_size,
|
81
|
+
progress_bar: true
|
82
|
+
)
|
83
|
+
|
84
|
+
@downloaded = true
|
85
|
+
downloaded_file
|
86
|
+
end
|
87
|
+
|
88
|
+
def font_file?(filename)
|
89
|
+
source_files.include?(filename)
|
90
|
+
end
|
91
|
+
|
92
|
+
def source_files
|
93
|
+
@source_files ||= @formula.fonts.flat_map do |font|
|
94
|
+
font.styles.map do |style|
|
95
|
+
style.source_font || style.font
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def target_filename(source_filename)
|
101
|
+
target_filenames[source_filename]
|
102
|
+
end
|
103
|
+
|
104
|
+
def target_filenames
|
105
|
+
@target_filenames ||= @formula.fonts.flat_map do |font|
|
106
|
+
font.styles.map do |style|
|
107
|
+
source = style.source_font || style.font
|
108
|
+
target = style.font
|
109
|
+
[source, target]
|
110
|
+
end
|
111
|
+
end.to_h
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
data/lib/fontist/fontist_font.rb
CHANGED
@@ -2,8 +2,6 @@ module Fontist
|
|
2
2
|
class FontistFont
|
3
3
|
def initialize(font_name:)
|
4
4
|
@font_name = font_name
|
5
|
-
|
6
|
-
check_and_register_font_formulas
|
7
5
|
end
|
8
6
|
|
9
7
|
def self.find(name)
|
@@ -11,60 +9,16 @@ module Fontist
|
|
11
9
|
end
|
12
10
|
|
13
11
|
def find
|
14
|
-
|
15
|
-
|
16
|
-
filenames = fonts_filenames
|
17
|
-
return if filenames.empty?
|
18
|
-
|
19
|
-
paths = font_paths.select do |path|
|
20
|
-
filenames.any? { |f| File.basename(path).casecmp?(f) }
|
21
|
-
end
|
12
|
+
styles = FormulaPaths.new(font_paths).find(@font_name)
|
13
|
+
return unless styles
|
22
14
|
|
23
|
-
|
15
|
+
styles.map { |x| x[:path] }
|
24
16
|
end
|
25
17
|
|
26
18
|
private
|
27
19
|
|
28
|
-
def fonts_filenames
|
29
|
-
fonts.map { |font| font.styles.map(&:font) }.flatten
|
30
|
-
end
|
31
|
-
|
32
|
-
def fonts
|
33
|
-
by_key || by_name || []
|
34
|
-
end
|
35
|
-
|
36
|
-
def by_key
|
37
|
-
_key, formula = formulas.detect do |key, _value|
|
38
|
-
key.to_s.casecmp?(@font_name)
|
39
|
-
end
|
40
|
-
|
41
|
-
return unless formula
|
42
|
-
|
43
|
-
formula.fonts
|
44
|
-
end
|
45
|
-
|
46
|
-
def by_name
|
47
|
-
_key, formula = formulas.detect do |_key, value|
|
48
|
-
value.fonts.map(&:name).map(&:downcase).include?(@font_name.downcase)
|
49
|
-
end
|
50
|
-
|
51
|
-
return unless formula
|
52
|
-
|
53
|
-
formula.fonts.select do |font|
|
54
|
-
font.name.casecmp?(@font_name)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def formulas
|
59
|
-
@formulas ||= Fontist::Registry.instance.formulas.to_h
|
60
|
-
end
|
61
|
-
|
62
20
|
def font_paths
|
63
21
|
Dir.glob(Fontist.fonts_path.join("**"))
|
64
22
|
end
|
65
|
-
|
66
|
-
def check_and_register_font_formulas
|
67
|
-
$check_and_register_font_formulas ||= Fontist::Formulas.register_formulas
|
68
|
-
end
|
69
23
|
end
|
70
24
|
end
|
data/lib/fontist/formula.rb
CHANGED
@@ -1,112 +1,134 @@
|
|
1
|
+
require "fontist/index"
|
2
|
+
require "fontist/helpers"
|
3
|
+
require "git"
|
4
|
+
|
1
5
|
module Fontist
|
2
6
|
class Formula
|
3
|
-
def
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
7
|
+
def self.update_formulas_repo
|
8
|
+
if Dir.exist?(Fontist.formulas_repo_path)
|
9
|
+
Git.open(Fontist.formulas_repo_path).pull
|
10
|
+
else
|
11
|
+
Git.clone(Fontist.formulas_repo_url,
|
12
|
+
Fontist.formulas_repo_path,
|
13
|
+
depth: 1)
|
14
|
+
end
|
8
15
|
end
|
9
16
|
|
10
17
|
def self.all
|
11
|
-
|
18
|
+
Dir[Fontist.formulas_path.join("**/*.yml").to_s].map do |path|
|
19
|
+
Formula.new_from_file(path)
|
20
|
+
end
|
12
21
|
end
|
13
22
|
|
14
23
|
def self.find(font_name)
|
15
|
-
|
24
|
+
Index.from_yaml.load_formulas(font_name).first
|
16
25
|
end
|
17
26
|
|
18
|
-
def self.find_fonts(
|
19
|
-
|
27
|
+
def self.find_fonts(font_name)
|
28
|
+
formulas = Index.from_yaml.load_formulas(font_name)
|
29
|
+
|
30
|
+
formulas.map do |formula|
|
31
|
+
formula.fonts.select do |f|
|
32
|
+
f.name.casecmp?(font_name)
|
33
|
+
end
|
34
|
+
end.flatten
|
20
35
|
end
|
21
36
|
|
22
|
-
def self.
|
23
|
-
|
37
|
+
def self.find_styles(font_name, style_name)
|
38
|
+
formulas = Index.from_yaml.load_formulas(font_name)
|
39
|
+
|
40
|
+
formulas.map do |formula|
|
41
|
+
formula.fonts.map do |f|
|
42
|
+
f.styles.select do |s|
|
43
|
+
f.name.casecmp?(font_name) && s.type.casecmp?(style_name)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end.flatten
|
24
47
|
end
|
25
48
|
|
26
|
-
def
|
27
|
-
|
49
|
+
def self.new_from_file(path)
|
50
|
+
data = YAML.load_file(path)
|
51
|
+
new(data, path)
|
28
52
|
end
|
29
53
|
|
30
|
-
def
|
31
|
-
|
54
|
+
def initialize(data, path)
|
55
|
+
@data = data
|
56
|
+
@path = path
|
32
57
|
end
|
33
58
|
|
34
|
-
def
|
35
|
-
|
36
|
-
fonts = take_fonts(formulas)
|
37
|
-
fonts.empty? ? nil : fonts
|
59
|
+
def to_index_formula
|
60
|
+
IndexFormula.new(path)
|
38
61
|
end
|
39
62
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
selected = f.styles.select do |s|
|
44
|
-
f.name.casecmp?(font_name) && s.type.casecmp?(style_name)
|
45
|
-
end
|
63
|
+
def path
|
64
|
+
@path
|
65
|
+
end
|
46
66
|
|
47
|
-
|
48
|
-
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
67
|
+
def key
|
68
|
+
@data["key"] || default_key
|
52
69
|
end
|
53
70
|
|
54
|
-
|
71
|
+
def description
|
72
|
+
@data["description"]
|
73
|
+
end
|
55
74
|
|
56
|
-
|
75
|
+
def homepage
|
76
|
+
@data["homepage"]
|
77
|
+
end
|
57
78
|
|
58
|
-
def
|
59
|
-
|
79
|
+
def copyright
|
80
|
+
@data["copyright"]
|
60
81
|
end
|
61
82
|
|
62
|
-
def
|
63
|
-
@
|
83
|
+
def license_url
|
84
|
+
@data["license_url"]
|
64
85
|
end
|
65
86
|
|
66
|
-
def
|
67
|
-
|
87
|
+
def license
|
88
|
+
@data["open_license"] || @data["requires_license_agreement"]
|
68
89
|
end
|
69
90
|
|
70
|
-
def
|
71
|
-
|
72
|
-
|
73
|
-
end
|
91
|
+
def license_required
|
92
|
+
@data["requires_license_agreement"] ? true : false
|
93
|
+
end
|
74
94
|
|
75
|
-
|
95
|
+
def extract
|
96
|
+
Helpers.parse_to_object(@data["extract"])
|
76
97
|
end
|
77
98
|
|
78
|
-
def
|
79
|
-
|
80
|
-
|
81
|
-
end
|
99
|
+
def resources
|
100
|
+
Helpers.parse_to_object(@data["resources"].values)
|
101
|
+
end
|
82
102
|
|
83
|
-
|
103
|
+
def fonts
|
104
|
+
@fonts ||= Helpers.parse_to_object(hash_collection_fonts + hash_fonts)
|
84
105
|
end
|
85
106
|
|
86
|
-
|
87
|
-
#
|
88
|
-
# These interface recursively look into every single font styles,
|
89
|
-
# so ideally try to avoid using it when possible, and that's why
|
90
|
-
# we've added it as last option in formula finder.
|
91
|
-
#
|
92
|
-
def find_by_font
|
93
|
-
matched_formulas = formulas.select do |key, value|
|
94
|
-
match_in_font_styles?(value[:fonts])
|
95
|
-
end
|
107
|
+
private
|
96
108
|
|
97
|
-
|
109
|
+
def default_key
|
110
|
+
escaped = Regexp.escape(Fontist.formulas_path.to_s + "/")
|
111
|
+
@path.sub(Regexp.new("^" + escaped), "").sub(/\.yml$/, "")
|
98
112
|
end
|
99
113
|
|
100
|
-
def
|
101
|
-
|
102
|
-
|
103
|
-
|
114
|
+
def hash_collection_fonts
|
115
|
+
return [] unless @data["font_collections"]
|
116
|
+
|
117
|
+
@data["font_collections"].flat_map do |coll|
|
118
|
+
filenames = { "font" => coll["filename"],
|
119
|
+
"source_font" => coll["source_filename"] }
|
104
120
|
|
105
|
-
|
121
|
+
coll["fonts"].map do |font|
|
122
|
+
{ "name" => font["name"],
|
123
|
+
"styles" => font["styles"].map { |s| filenames.merge(s) } }
|
124
|
+
end
|
125
|
+
end
|
106
126
|
end
|
107
127
|
|
108
|
-
def
|
109
|
-
|
128
|
+
def hash_fonts
|
129
|
+
return [] unless @data["fonts"]
|
130
|
+
|
131
|
+
@data["fonts"]
|
110
132
|
end
|
111
133
|
end
|
112
134
|
end
|