fontist 1.9.3 → 1.11.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/metanorma.yml +1 -1
- data/.github/workflows/rspec.yml +1 -1
- data/README.adoc +804 -0
- data/exe/fontist +24 -2
- data/fontist.gemspec +3 -2
- data/lib/fontist/cli.rb +23 -9
- data/lib/fontist/font.rb +8 -3
- data/lib/fontist/formula.rb +4 -0
- data/lib/fontist/google_cli.rb +29 -0
- data/lib/fontist/import/files/collection_file.rb +10 -1
- data/lib/fontist/import/formula_builder.rb +30 -5
- data/lib/fontist/import/google/new_fonts_fetcher.rb +44 -33
- data/lib/fontist/import/google.rb +18 -0
- data/lib/fontist/import/google_check.rb +0 -7
- data/lib/fontist/import/google_import.rb +26 -138
- data/lib/fontist/import/helpers/system_helper.rb +1 -1
- data/lib/fontist/import/otf/font_file.rb +17 -4
- data/lib/fontist/import/otf_parser.rb +2 -0
- data/lib/fontist/import/otf_style.rb +10 -2
- data/lib/fontist/import/otfinfo/template.erb +6 -0
- data/lib/fontist/import/recursive_extraction.rb +2 -1
- data/lib/fontist/index.rb +4 -28
- data/lib/fontist/indexes/default_family_font_index.rb +21 -0
- data/lib/fontist/indexes/font_index.rb +8 -13
- data/lib/fontist/indexes/preferred_family_font_index.rb +24 -0
- data/lib/fontist/system_font.rb +6 -16
- data/lib/fontist/system_index.rb +108 -29
- data/lib/fontist/update.rb +2 -2
- data/lib/fontist/utils/downloader.rb +14 -6
- data/lib/fontist/version.rb +1 -1
- data/lib/fontist.rb +43 -13
- metadata +26 -29
- data/.github/workflows/check_google.yml +0 -28
- data/README.md +0 -570
- data/lib/fontist/fontist_font.rb +0 -24
- data/lib/fontist/formula_paths.rb +0 -44
- data/lib/fontist/import/google/fonts_public.md +0 -10
- data/lib/fontist/import/google/fonts_public.pb.rb +0 -71
- data/lib/fontist/import/google/fonts_public.proto +0 -46
data/exe/fontist
CHANGED
@@ -3,5 +3,27 @@
|
|
3
3
|
require "fontist"
|
4
4
|
require "fontist/cli"
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
fontist_cli = proc {
|
7
|
+
status_code = Fontist::CLI.start(ARGV)
|
8
|
+
exit status_code.is_a?(Integer) ? status_code : 1
|
9
|
+
}
|
10
|
+
|
11
|
+
if ENV["SOCKS_PROXY"]
|
12
|
+
require "socksify"
|
13
|
+
require "uri"
|
14
|
+
begin
|
15
|
+
proxy = URI.parse(ENV["SOCKS_PROXY"])
|
16
|
+
if proxy.userinfo
|
17
|
+
user, pass = proxy.userinfo.split(":")
|
18
|
+
TCPSocket::socks_username = user
|
19
|
+
TCPSocket::socks_password = pass
|
20
|
+
end
|
21
|
+
Socksify::proxy(proxy.host, proxy.port, &fontist_cli)
|
22
|
+
rescue URI::InvalidURIError
|
23
|
+
warn "Value of ENV.SOCKS_PROXY=#{ENV['SOCKS_PROXY']} is invalid! Droping it"
|
24
|
+
ENV.delete("SOCKS_PROXY")
|
25
|
+
fontist_cli.call
|
26
|
+
end
|
27
|
+
else
|
28
|
+
fontist_cli.call
|
29
|
+
end
|
data/fontist.gemspec
CHANGED
@@ -28,12 +28,12 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.test_files = `git ls-files -- {spec}/*`.split("\n")
|
29
29
|
|
30
30
|
spec.add_runtime_dependency "down", "~> 5.0"
|
31
|
+
spec.add_runtime_dependency "extract_ttc", "~> 0.1"
|
31
32
|
spec.add_runtime_dependency "thor", "~> 1.0.1"
|
32
33
|
spec.add_runtime_dependency "git", "~> 1.0"
|
33
34
|
spec.add_runtime_dependency "ttfunk", "~> 1.6"
|
34
35
|
spec.add_runtime_dependency "excavate", "~> 0.1"
|
35
36
|
|
36
|
-
spec.add_development_dependency "extract_ttc", "~> 0.1"
|
37
37
|
spec.add_development_dependency "pry"
|
38
38
|
spec.add_development_dependency "bundler", "~> 2.0"
|
39
39
|
spec.add_development_dependency "gem-release"
|
@@ -43,5 +43,6 @@ Gem::Specification.new do |spec|
|
|
43
43
|
spec.add_development_dependency "rubocop", "1.5.2"
|
44
44
|
spec.add_development_dependency "rubocop-rails"
|
45
45
|
spec.add_development_dependency "rubocop-performance"
|
46
|
-
|
46
|
+
|
47
|
+
spec.add_runtime_dependency "socksify"
|
47
48
|
end
|
data/lib/fontist/cli.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "thor"
|
2
2
|
require "fontist/repo_cli"
|
3
|
+
require "fontist/google_cli"
|
3
4
|
|
4
5
|
module Fontist
|
5
6
|
class CLI < Thor
|
@@ -32,6 +33,10 @@ module Fontist
|
|
32
33
|
false
|
33
34
|
end
|
34
35
|
|
36
|
+
class_option :preferred_family,
|
37
|
+
type: :boolean,
|
38
|
+
desc: "Use Preferred Family when available"
|
39
|
+
|
35
40
|
desc "install FONT", "Install font"
|
36
41
|
option :force, type: :boolean, aliases: :f,
|
37
42
|
desc: "Install even if it's already installed in system"
|
@@ -39,6 +44,7 @@ module Fontist
|
|
39
44
|
option :hide_licenses, type: :boolean, desc: "Hide license texts"
|
40
45
|
option :no_progress, type: :boolean, desc: "Hide download progress"
|
41
46
|
def install(font)
|
47
|
+
handle_class_options(options)
|
42
48
|
Fontist::Font.install(
|
43
49
|
font,
|
44
50
|
force: options[:force],
|
@@ -53,6 +59,7 @@ module Fontist
|
|
53
59
|
|
54
60
|
desc "uninstall/remove FONT", "Uninstall font by font or formula"
|
55
61
|
def uninstall(font)
|
62
|
+
handle_class_options(options)
|
56
63
|
fonts_paths = Fontist::Font.uninstall(font)
|
57
64
|
Fontist.ui.success("These fonts are removed:")
|
58
65
|
Fontist.ui.success(fonts_paths.join("\n"))
|
@@ -64,6 +71,7 @@ module Fontist
|
|
64
71
|
|
65
72
|
desc "status [FONT]", "Show paths of FONT or all fonts"
|
66
73
|
def status(font = nil)
|
74
|
+
handle_class_options(options)
|
67
75
|
paths = Fontist::Font.status(font)
|
68
76
|
return error("No font is installed.", STATUS_MISSING_FONT_ERROR) if paths.empty?
|
69
77
|
|
@@ -74,6 +82,7 @@ module Fontist
|
|
74
82
|
|
75
83
|
desc "list [FONT]", "List installation status of FONT or fonts in fontist"
|
76
84
|
def list(font = nil)
|
85
|
+
handle_class_options(options)
|
77
86
|
formulas = Fontist::Font.list(font)
|
78
87
|
print_list(formulas)
|
79
88
|
success
|
@@ -83,6 +92,7 @@ module Fontist
|
|
83
92
|
|
84
93
|
desc "update", "Update formulas"
|
85
94
|
def update
|
95
|
+
handle_class_options(options)
|
86
96
|
Formula.update_formulas_repo
|
87
97
|
Fontist.ui.success("Formulas have been successfully updated.")
|
88
98
|
success
|
@@ -94,6 +104,7 @@ module Fontist
|
|
94
104
|
desc "manifest-locations MANIFEST",
|
95
105
|
"Get locations of fonts from MANIFEST (yaml)"
|
96
106
|
def manifest_locations(manifest)
|
107
|
+
handle_class_options(options)
|
97
108
|
paths = Fontist::Manifest::Locations.from_file(manifest)
|
98
109
|
print_yaml(paths)
|
99
110
|
success
|
@@ -105,6 +116,7 @@ module Fontist
|
|
105
116
|
option :accept_all_licenses, type: :boolean, aliases: "--confirm-license", desc: "Accept all license agreements"
|
106
117
|
option :hide_licenses, type: :boolean, desc: "Hide license texts"
|
107
118
|
def manifest_install(manifest)
|
119
|
+
handle_class_options(options)
|
108
120
|
paths = Fontist::Manifest::Install.from_file(
|
109
121
|
manifest,
|
110
122
|
confirmation: options[:accept_all_licenses] ? "yes" : "no",
|
@@ -124,6 +136,7 @@ module Fontist
|
|
124
136
|
option :subdir, desc: "Subdirectory to take fonts from, starting with the " \
|
125
137
|
"root dir, e.g.: stixfonts-2.10/fonts/static_otf. May include `fnmatch` patterns."
|
126
138
|
def create_formula(url)
|
139
|
+
handle_class_options(options)
|
127
140
|
require "fontist/import/create_formula"
|
128
141
|
name = Fontist::Import::CreateFormula.new(url, options).call
|
129
142
|
Fontist.ui.say("#{name} formula has been successfully created")
|
@@ -137,22 +150,16 @@ module Fontist
|
|
137
150
|
It is done automatically when formulas are updated, or private formulas
|
138
151
|
are set up.
|
139
152
|
LONGDESC
|
140
|
-
option :main_repo, type: :boolean,
|
141
|
-
desc: "Updates indexes in the main repo (for backward " \
|
142
|
-
"compatibility with versions prior to 1.9)"
|
143
153
|
def rebuild_index
|
144
|
-
|
145
|
-
|
146
|
-
else
|
147
|
-
Fontist::Index.rebuild
|
148
|
-
end
|
149
|
-
|
154
|
+
handle_class_options(options)
|
155
|
+
Fontist::Index.rebuild
|
150
156
|
Fontist.ui.say("Formula index has been rebuilt.")
|
151
157
|
STATUS_SUCCESS
|
152
158
|
end
|
153
159
|
|
154
160
|
desc "import-sil", "Import formulas from SIL"
|
155
161
|
def import_sil
|
162
|
+
handle_class_options(options)
|
156
163
|
require "fontist/import/sil_import"
|
157
164
|
Fontist::Import::SilImport.new.call
|
158
165
|
end
|
@@ -160,8 +167,15 @@ module Fontist
|
|
160
167
|
desc "repo SUBCOMMAND ...ARGS", "Manage custom repositories"
|
161
168
|
subcommand "repo", Fontist::RepoCLI
|
162
169
|
|
170
|
+
desc "google SUBCOMMAND ...ARGS", "Manage Google formulas"
|
171
|
+
subcommand "google", Fontist::GoogleCLI
|
172
|
+
|
163
173
|
private
|
164
174
|
|
175
|
+
def handle_class_options(options)
|
176
|
+
Fontist.preferred_family = options[:preferred_family]
|
177
|
+
end
|
178
|
+
|
165
179
|
def success
|
166
180
|
STATUS_SUCCESS
|
167
181
|
end
|
data/lib/fontist/font.rb
CHANGED
@@ -166,7 +166,7 @@ module Fontist
|
|
166
166
|
end
|
167
167
|
|
168
168
|
def uninstall_font
|
169
|
-
paths =
|
169
|
+
paths = find_fontist_paths
|
170
170
|
return unless paths
|
171
171
|
|
172
172
|
paths.each do |path|
|
@@ -176,8 +176,13 @@ module Fontist
|
|
176
176
|
paths
|
177
177
|
end
|
178
178
|
|
179
|
-
def
|
180
|
-
Fontist::
|
179
|
+
def find_fontist_paths
|
180
|
+
fonts = Fontist::SystemIndex.fontist_index.find(name, nil)
|
181
|
+
return unless fonts
|
182
|
+
|
183
|
+
fonts.map do |font|
|
184
|
+
font[:path]
|
185
|
+
end
|
181
186
|
end
|
182
187
|
|
183
188
|
def installed_paths
|
data/lib/fontist/formula.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Fontist
|
2
|
+
class GoogleCLI < Thor
|
3
|
+
class_option :formulas_path, type: :string, desc: "Path to formulas"
|
4
|
+
|
5
|
+
desc "check", "Check Google fonts for updates"
|
6
|
+
def check
|
7
|
+
handle_class_options(options)
|
8
|
+
require "fontist/import/google_check"
|
9
|
+
Fontist::Import::GoogleCheck.new.call
|
10
|
+
CLI::STATUS_SUCCESS
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "import", "Import Google fonts"
|
14
|
+
def import
|
15
|
+
handle_class_options(options)
|
16
|
+
require "fontist/import/google_import"
|
17
|
+
Fontist::Import::GoogleImport.new.call
|
18
|
+
CLI::STATUS_SUCCESS
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def handle_class_options(options)
|
24
|
+
if options[:formulas_path]
|
25
|
+
Fontist.formulas_path = Pathname.new(options[:formulas_path])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -11,7 +11,7 @@ module Fontist
|
|
11
11
|
def initialize(path)
|
12
12
|
@path = path
|
13
13
|
@fonts = read
|
14
|
-
@extension =
|
14
|
+
@extension = detect_extension
|
15
15
|
end
|
16
16
|
|
17
17
|
def filename
|
@@ -46,6 +46,15 @@ module Fontist
|
|
46
46
|
File.join(tmp_dir, filename)
|
47
47
|
end
|
48
48
|
end
|
49
|
+
|
50
|
+
def detect_extension
|
51
|
+
base_extension = "ttc"
|
52
|
+
|
53
|
+
file_extension = File.extname(File.basename(@path)).sub(/^\./, "")
|
54
|
+
return file_extension if file_extension.casecmp?(base_extension)
|
55
|
+
|
56
|
+
base_extension
|
57
|
+
end
|
49
58
|
end
|
50
59
|
end
|
51
60
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require "shellwords"
|
1
2
|
require_relative "text_helper"
|
2
3
|
|
3
4
|
module Fontist
|
@@ -5,7 +6,7 @@ module Fontist
|
|
5
6
|
class FormulaBuilder
|
6
7
|
FORMULA_ATTRIBUTES = %i[name description homepage resources
|
7
8
|
font_collections fonts extract copyright
|
8
|
-
license_url open_license].freeze
|
9
|
+
license_url open_license digest command].freeze
|
9
10
|
|
10
11
|
attr_accessor :archive,
|
11
12
|
:url,
|
@@ -49,7 +50,7 @@ module Fontist
|
|
49
50
|
end
|
50
51
|
|
51
52
|
def homepage
|
52
|
-
both_fonts.first
|
53
|
+
both_fonts.map(&:homepage).compact.first
|
53
54
|
end
|
54
55
|
|
55
56
|
def resources
|
@@ -59,6 +60,18 @@ module Fontist
|
|
59
60
|
end
|
60
61
|
|
61
62
|
def resource_options
|
63
|
+
if @options[:skip_sha]
|
64
|
+
resource_options_without_sha
|
65
|
+
else
|
66
|
+
resource_options_with_sha
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def resource_options_without_sha
|
71
|
+
{ urls: [@url] + mirrors }
|
72
|
+
end
|
73
|
+
|
74
|
+
def resource_options_with_sha
|
62
75
|
urls = []
|
63
76
|
sha = []
|
64
77
|
downloads do |url, path|
|
@@ -129,7 +142,7 @@ module Fontist
|
|
129
142
|
|
130
143
|
fonts = groups.map do |name, group|
|
131
144
|
{ name: name,
|
132
|
-
styles: group
|
145
|
+
styles: styles_from_files(group, style_type) }
|
133
146
|
end
|
134
147
|
|
135
148
|
fonts.sort_by do |x|
|
@@ -137,16 +150,20 @@ module Fontist
|
|
137
150
|
end
|
138
151
|
end
|
139
152
|
|
153
|
+
def styles_from_files(files, style_type)
|
154
|
+
files.map(&style_type).sort_by { |x| x[:type] }
|
155
|
+
end
|
156
|
+
|
140
157
|
def extract
|
141
158
|
@extractor.operations
|
142
159
|
end
|
143
160
|
|
144
161
|
def copyright
|
145
|
-
both_fonts.first
|
162
|
+
both_fonts.map(&:copyright).compact.first
|
146
163
|
end
|
147
164
|
|
148
165
|
def license_url
|
149
|
-
both_fonts.first
|
166
|
+
both_fonts.map(&:license_url).compact.first
|
150
167
|
end
|
151
168
|
|
152
169
|
def open_license
|
@@ -161,6 +178,14 @@ module Fontist
|
|
161
178
|
|
162
179
|
TextHelper.cleanup(@license_text)
|
163
180
|
end
|
181
|
+
|
182
|
+
def digest
|
183
|
+
@options[:digest]
|
184
|
+
end
|
185
|
+
|
186
|
+
def command
|
187
|
+
Shellwords.shelljoin(ARGV)
|
188
|
+
end
|
164
189
|
end
|
165
190
|
end
|
166
191
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require_relative "fonts_public.pb"
|
2
1
|
require_relative "../google"
|
3
2
|
require_relative "../otf_parser"
|
4
3
|
|
@@ -6,7 +5,7 @@ module Fontist
|
|
6
5
|
module Import
|
7
6
|
module Google
|
8
7
|
class NewFontsFetcher
|
9
|
-
REPO_PATH = Fontist.
|
8
|
+
REPO_PATH = Fontist.fontist_path.join("google", "fonts")
|
10
9
|
REPO_URL = "https://github.com/google/fonts.git".freeze
|
11
10
|
SKIPLIST_PATH = File.expand_path("skiplist.yml", __dir__)
|
12
11
|
|
@@ -25,7 +24,8 @@ module Fontist
|
|
25
24
|
if Dir.exist?(REPO_PATH)
|
26
25
|
`cd #{REPO_PATH} && git pull`
|
27
26
|
else
|
28
|
-
|
27
|
+
FileUtils.mkdir_p(File.dirname(REPO_PATH))
|
28
|
+
`git clone --depth 1 #{REPO_URL} #{REPO_PATH}`
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -53,23 +53,11 @@ module Fontist
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def new?(path)
|
56
|
-
|
57
|
-
return unless
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
def fetch_metadata(path)
|
63
|
-
metadata_path = File.join(path, "METADATA.pb")
|
64
|
-
return unless File.exists?(metadata_path)
|
65
|
-
|
66
|
-
::Google::Fonts::FamilyProto.parse_from_text(File.read(metadata_path))
|
67
|
-
end
|
68
|
-
|
69
|
-
def font_new?(metadata, path)
|
70
|
-
return if in_skiplist?(metadata.name)
|
71
|
-
return if up_to_date?(metadata, path)
|
72
|
-
return unless downloadable?(metadata.name)
|
56
|
+
metadata_name = Google.metadata_name(path)
|
57
|
+
return unless metadata_name
|
58
|
+
return if in_skiplist?(metadata_name)
|
59
|
+
return if up_to_date?(metadata_name, path)
|
60
|
+
return unless downloadable?(metadata_name)
|
73
61
|
|
74
62
|
true
|
75
63
|
end
|
@@ -79,29 +67,47 @@ module Fontist
|
|
79
67
|
@skiplist.include?(name)
|
80
68
|
end
|
81
69
|
|
82
|
-
def up_to_date?(
|
83
|
-
formula = formula(
|
70
|
+
def up_to_date?(metadata_name, path)
|
71
|
+
formula = formula(metadata_name)
|
84
72
|
return false unless formula
|
85
73
|
|
86
|
-
|
74
|
+
repo_digest_up_to_date?(formula, path) ||
|
75
|
+
fonts_up_to_date?(formula, path)
|
76
|
+
end
|
77
|
+
|
78
|
+
def repo_digest_up_to_date?(formula, path)
|
79
|
+
return unless formula.digest
|
87
80
|
|
88
|
-
|
89
|
-
|
81
|
+
formula.digest == Google.digest(path)
|
82
|
+
end
|
83
|
+
|
84
|
+
def fonts_up_to_date?(formula, path)
|
85
|
+
styles = formula_styles(formula)
|
86
|
+
repo_fonts(path).all? do |font|
|
87
|
+
style = styles.find { |s| s.font == repo_to_archive_name(font) }
|
88
|
+
return false unless style
|
89
|
+
|
90
|
+
otfinfo_version(font) == style.version
|
90
91
|
end
|
91
92
|
end
|
92
93
|
|
93
|
-
def formula
|
94
|
-
|
95
|
-
@formulas ||= Fontist::Formula.all
|
96
|
-
@formulas["Fontist::Formulas::#{klass}Font"]
|
94
|
+
def formula_styles(formula)
|
95
|
+
formula.fonts.map(&:styles).flatten
|
97
96
|
end
|
98
97
|
|
99
|
-
def
|
100
|
-
File.join(
|
98
|
+
def repo_fonts(path)
|
99
|
+
Dir.glob(File.join(path, "*.{ttf,otf}"))
|
101
100
|
end
|
102
101
|
|
103
|
-
def
|
104
|
-
|
102
|
+
def repo_to_archive_name(font_path)
|
103
|
+
File.basename(font_path)
|
104
|
+
.sub("[wght]", "-VariableFont_wght")
|
105
|
+
.sub("[opsz]", "-Regular-VariableFont_opsz")
|
106
|
+
end
|
107
|
+
|
108
|
+
def formula(font_name)
|
109
|
+
path = Fontist::Import::Google.formula_path(font_name)
|
110
|
+
Formula.new_from_file(path) if File.exist?(path)
|
105
111
|
end
|
106
112
|
|
107
113
|
def otfinfo_version(path)
|
@@ -110,10 +116,15 @@ module Fontist
|
|
110
116
|
end
|
111
117
|
|
112
118
|
def downloadable?(name)
|
119
|
+
retries ||= 0
|
120
|
+
retries += 1
|
113
121
|
Down.open("https://fonts.google.com/download?family=#{name}")
|
114
122
|
true
|
115
123
|
rescue Down::NotFound
|
116
124
|
false
|
125
|
+
rescue Down::TimeoutError
|
126
|
+
retry unless retries >= 3
|
127
|
+
false
|
117
128
|
end
|
118
129
|
end
|
119
130
|
end
|