fontist 1.8.12 → 1.10.0
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 +35 -0
- data/.github/workflows/rspec.yml +2 -12
- data/README.md +83 -7
- data/fontist.gemspec +1 -1
- data/lib/fontist.rb +51 -5
- data/lib/fontist/cli.rb +45 -4
- data/lib/fontist/errors.rb +20 -0
- data/lib/fontist/font.rb +10 -5
- data/lib/fontist/font_installer.rb +3 -2
- data/lib/fontist/formula.rb +2 -7
- data/lib/fontist/import/formula_builder.rb +5 -1
- data/lib/fontist/import/google_import.rb +4 -0
- data/lib/fontist/import/otf/font_file.rb +12 -3
- data/lib/fontist/import/otf_style.rb +10 -2
- data/lib/fontist/import/otfinfo/template.erb +6 -0
- data/lib/fontist/index.rb +37 -1
- data/lib/fontist/indexes/base_index.rb +12 -2
- 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/repo.rb +60 -0
- data/lib/fontist/repo_cli.rb +51 -0
- data/lib/fontist/system_font.rb +6 -11
- data/lib/fontist/system_index.rb +110 -27
- data/lib/fontist/update.rb +64 -0
- data/lib/fontist/utils/downloader.rb +14 -2
- data/lib/fontist/utils/locking.rb +1 -0
- data/lib/fontist/version.rb +1 -1
- metadata +11 -6
- data/lib/fontist/fontist_font.rb +0 -24
data/lib/fontist/errors.rb
CHANGED
@@ -3,17 +3,37 @@ module Fontist
|
|
3
3
|
class GeneralError < StandardError; end
|
4
4
|
|
5
5
|
class BinaryCallError < GeneralError; end
|
6
|
+
|
6
7
|
class FontIndexCorrupted < GeneralError; end
|
8
|
+
|
7
9
|
class FontNotFoundError < GeneralError; end
|
10
|
+
|
11
|
+
# for backward compatibility with metanorma,
|
12
|
+
# it depends on this exception to automatically download formulas
|
8
13
|
class FormulaIndexNotFoundError < GeneralError; end
|
14
|
+
|
15
|
+
class MainRepoNotFoundError < FormulaIndexNotFoundError; end
|
16
|
+
|
9
17
|
class InvalidResourceError < GeneralError; end
|
18
|
+
|
10
19
|
class LicensingError < GeneralError; end
|
20
|
+
|
11
21
|
class ManifestCouldNotBeFoundError < GeneralError; end
|
22
|
+
|
12
23
|
class ManifestCouldNotBeReadError < GeneralError; end
|
24
|
+
|
13
25
|
class MissingAttributeError < GeneralError; end
|
26
|
+
|
27
|
+
class RepoNotFoundError < GeneralError; end
|
28
|
+
|
29
|
+
class RepoCouldNotBeUpdatedError < GeneralError; end
|
30
|
+
|
14
31
|
class TamperedFileError < GeneralError; end
|
32
|
+
|
15
33
|
class TimeoutError < GeneralError; end
|
34
|
+
|
16
35
|
class UnknownFontTypeError < GeneralError; end
|
36
|
+
|
17
37
|
class UnknownArchiveError < GeneralError; end
|
18
38
|
|
19
39
|
class FontError < GeneralError
|
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
|
@@ -203,9 +208,9 @@ module Fontist
|
|
203
208
|
end
|
204
209
|
|
205
210
|
def font_list
|
206
|
-
return
|
211
|
+
return if formulas.empty?
|
207
212
|
|
208
|
-
list_styles(
|
213
|
+
list_styles(formulas)
|
209
214
|
end
|
210
215
|
|
211
216
|
def list_styles(formulas)
|
@@ -54,11 +54,12 @@ module Fontist
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def download_file(source)
|
57
|
-
|
57
|
+
request = source.urls.first
|
58
|
+
url = request.respond_to?(:url) ? request.url : request
|
58
59
|
Fontist.ui.say(%(Downloading font "#{@formula.key}" from #{url}))
|
59
60
|
|
60
61
|
Fontist::Utils::Downloader.download(
|
61
|
-
|
62
|
+
request,
|
62
63
|
sha: source.sha256,
|
63
64
|
file_size: source.file_size,
|
64
65
|
progress_bar: !@no_progress
|
data/lib/fontist/formula.rb
CHANGED
@@ -1,17 +1,12 @@
|
|
1
1
|
require "fontist/index"
|
2
2
|
require "fontist/helpers"
|
3
|
+
require "fontist/update"
|
3
4
|
require "git"
|
4
5
|
|
5
6
|
module Fontist
|
6
7
|
class Formula
|
7
8
|
def self.update_formulas_repo
|
8
|
-
|
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
|
9
|
+
Update.call
|
15
10
|
end
|
16
11
|
|
17
12
|
def self.all
|
@@ -129,7 +129,7 @@ module Fontist
|
|
129
129
|
|
130
130
|
fonts = groups.map do |name, group|
|
131
131
|
{ name: name,
|
132
|
-
styles: group
|
132
|
+
styles: styles_from_files(group, style_type) }
|
133
133
|
end
|
134
134
|
|
135
135
|
fonts.sort_by do |x|
|
@@ -137,6 +137,10 @@ module Fontist
|
|
137
137
|
end
|
138
138
|
end
|
139
139
|
|
140
|
+
def styles_from_files(files, style_type)
|
141
|
+
files.map(&style_type).sort_by { |x| x[:type] }
|
142
|
+
end
|
143
|
+
|
140
144
|
def extract
|
141
145
|
@extractor.operations
|
142
146
|
end
|
@@ -156,6 +156,10 @@ module Fontist
|
|
156
156
|
h.merge!(family_name: style.family_name,
|
157
157
|
type: style.style,
|
158
158
|
full_name: style.full_name)
|
159
|
+
if style.preferred_family_name
|
160
|
+
h[:preferred_family_name] = style.preferred_family_name
|
161
|
+
end
|
162
|
+
h[:preferred_type] = style.preferred_style if style.preferred_style
|
159
163
|
h.merge!(style.to_h.select do |k, _|
|
160
164
|
%i(post_script_name version description copyright).include?(k)
|
161
165
|
end.compact)
|
@@ -10,7 +10,8 @@ module Fontist
|
|
10
10
|
otfinfo: Otfinfo::OtfinfoRequirement.new,
|
11
11
|
}.freeze
|
12
12
|
|
13
|
-
STYLE_ATTRIBUTES = %i[family_name type
|
13
|
+
STYLE_ATTRIBUTES = %i[family_name type preferred_family_name
|
14
|
+
preferred_type full_name post_script_name
|
14
15
|
version description copyright font
|
15
16
|
source_font].freeze
|
16
17
|
|
@@ -35,11 +36,19 @@ module Fontist
|
|
35
36
|
end
|
36
37
|
|
37
38
|
def family_name
|
38
|
-
info["
|
39
|
+
info["Family"]
|
39
40
|
end
|
40
41
|
|
41
42
|
def type
|
42
|
-
info["
|
43
|
+
info["Subfamily"]
|
44
|
+
end
|
45
|
+
|
46
|
+
def preferred_family_name
|
47
|
+
info["Preferred family"]
|
48
|
+
end
|
49
|
+
|
50
|
+
def preferred_type
|
51
|
+
info["Preferred subfamily"]
|
43
52
|
end
|
44
53
|
|
45
54
|
def full_name
|
@@ -7,8 +7,8 @@ module Fontist
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def call
|
10
|
-
style = { family_name: @info["
|
11
|
-
style: @info["
|
10
|
+
style = { family_name: @info["Family"],
|
11
|
+
style: @info["Subfamily"],
|
12
12
|
full_name: @info["Full name"],
|
13
13
|
post_script_name: @info["PostScript name"],
|
14
14
|
version: version(@info["Version"]),
|
@@ -16,6 +16,14 @@ module Fontist
|
|
16
16
|
filename: File.basename(@path),
|
17
17
|
copyright: @info["Copyright"] }
|
18
18
|
|
19
|
+
if @info["Preferred family"]
|
20
|
+
style[:preferred_family_name] = @info["Preferred family"]
|
21
|
+
end
|
22
|
+
|
23
|
+
if @info["Preferred subfamily"]
|
24
|
+
style[:preferred_style] = @info["Preferred subfamily"]
|
25
|
+
end
|
26
|
+
|
19
27
|
OpenStruct.new(style)
|
20
28
|
end
|
21
29
|
|
@@ -2,6 +2,12 @@
|
|
2
2
|
{
|
3
3
|
family_name: "<%= s.family_name %>",
|
4
4
|
style: "<%= s.style %>",
|
5
|
+
<%- if s.preferred_family_name -%>
|
6
|
+
preferred_family_name: "<%= s.preferred_family_name %>",
|
7
|
+
<%- end -%>
|
8
|
+
<%- if s.preferred_style -%>
|
9
|
+
preferred_type: "<%= s.preferred_style %>",
|
10
|
+
<%- end -%>
|
5
11
|
full_name: "<%= s.full_name %>",
|
6
12
|
<%- if s.post_script_name -%>
|
7
13
|
post_script_name: "<%= s.post_script_name %>",
|
data/lib/fontist/index.rb
CHANGED
@@ -3,9 +3,45 @@ require_relative "indexes/filename_index"
|
|
3
3
|
|
4
4
|
module Fontist
|
5
5
|
class Index
|
6
|
+
def self.rebuild_for_main_repo
|
7
|
+
unless Dir.exist?(Fontist.private_formulas_path)
|
8
|
+
return do_rebuild_for_main_repo_with
|
9
|
+
end
|
10
|
+
|
11
|
+
Dir.mktmpdir do |dir|
|
12
|
+
tmp_private_path = File.join(dir, "private")
|
13
|
+
FileUtils.mv(Fontist.private_formulas_path, tmp_private_path)
|
14
|
+
|
15
|
+
do_rebuild_for_main_repo_with
|
16
|
+
|
17
|
+
FileUtils.mv(tmp_private_path, Fontist.private_formulas_path)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.do_rebuild_for_main_repo_with
|
22
|
+
Fontist.formula_preferred_family_index_path =
|
23
|
+
Fontist.formulas_repo_path.join("index.yml")
|
24
|
+
Fontist.formula_filename_index_path =
|
25
|
+
Fontist.formulas_repo_path.join("filename_index.yml")
|
26
|
+
|
27
|
+
rebuild
|
28
|
+
|
29
|
+
Fontist.formula_preferred_family_index_path = nil
|
30
|
+
Fontist.formula_filename_index_path = nil
|
31
|
+
end
|
32
|
+
|
6
33
|
def self.rebuild
|
7
|
-
Fontist::Indexes::
|
34
|
+
Fontist::Indexes::DefaultFamilyFontIndex.rebuild
|
35
|
+
Fontist::Indexes::PreferredFamilyFontIndex.rebuild
|
8
36
|
Fontist::Indexes::FilenameIndex.rebuild
|
37
|
+
|
38
|
+
reset_cache
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.reset_cache
|
42
|
+
Fontist::Indexes::DefaultFamilyFontIndex.reset_cache
|
43
|
+
Fontist::Indexes::PreferredFamilyFontIndex.reset_cache
|
44
|
+
Fontist::Indexes::FilenameIndex.reset_cache
|
9
45
|
end
|
10
46
|
end
|
11
47
|
end
|
@@ -5,10 +5,14 @@ module Fontist
|
|
5
5
|
class BaseIndex
|
6
6
|
def self.from_yaml
|
7
7
|
@from_yaml ||= begin
|
8
|
-
unless
|
9
|
-
raise Errors::
|
8
|
+
unless Dir.exist?(Fontist.formulas_repo_path)
|
9
|
+
raise Errors::MainRepoNotFoundError.new(
|
10
|
+
"Please fetch formulas with `fontist update`.",
|
11
|
+
)
|
10
12
|
end
|
11
13
|
|
14
|
+
rebuild unless File.exist?(path)
|
15
|
+
|
12
16
|
data = YAML.load_file(path)
|
13
17
|
new(data)
|
14
18
|
end
|
@@ -18,6 +22,10 @@ module Fontist
|
|
18
22
|
raise NotImplementedError, "Please define path of an index"
|
19
23
|
end
|
20
24
|
|
25
|
+
def self.reset_cache
|
26
|
+
@from_yaml = nil
|
27
|
+
end
|
28
|
+
|
21
29
|
def self.rebuild
|
22
30
|
index = new
|
23
31
|
index.build
|
@@ -59,6 +67,8 @@ module Fontist
|
|
59
67
|
end
|
60
68
|
|
61
69
|
def to_yaml
|
70
|
+
dir = File.dirname(self.class.path)
|
71
|
+
FileUtils.mkdir_p(dir) unless File.exist?(dir)
|
62
72
|
File.write(self.class.path, YAML.dump(to_h))
|
63
73
|
end
|
64
74
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative "base_index"
|
2
|
+
|
3
|
+
module Fontist
|
4
|
+
module Indexes
|
5
|
+
class DefaultFamilyFontIndex < BaseIndex
|
6
|
+
def self.path
|
7
|
+
Fontist.formula_index_path
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_formula(formula)
|
11
|
+
formula.fonts.each do |font|
|
12
|
+
add_index_formula(font.name, formula.to_index_formula)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def normalize_key(key)
|
17
|
+
key.downcase
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,21 +1,16 @@
|
|
1
|
-
require_relative "
|
1
|
+
require_relative "default_family_font_index"
|
2
|
+
require_relative "preferred_family_font_index"
|
2
3
|
|
3
4
|
module Fontist
|
4
5
|
module Indexes
|
5
|
-
class FontIndex
|
6
|
-
def self.
|
7
|
-
Fontist.
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
formula.fonts.each do |font|
|
12
|
-
add_index_formula(font.name, formula.to_index_formula)
|
6
|
+
class FontIndex
|
7
|
+
def self.from_yaml
|
8
|
+
if Fontist.preferred_family?
|
9
|
+
PreferredFamilyFontIndex.from_yaml
|
10
|
+
else
|
11
|
+
DefaultFamilyFontIndex.from_yaml
|
13
12
|
end
|
14
13
|
end
|
15
|
-
|
16
|
-
def normalize_key(key)
|
17
|
-
key.downcase
|
18
|
-
end
|
19
14
|
end
|
20
15
|
end
|
21
16
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative "base_index"
|
2
|
+
|
3
|
+
module Fontist
|
4
|
+
module Indexes
|
5
|
+
class PreferredFamilyFontIndex < BaseIndex
|
6
|
+
def self.path
|
7
|
+
Fontist.formula_preferred_family_index_path
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_formula(formula)
|
11
|
+
formula.fonts.each do |font|
|
12
|
+
font.styles.each do |style|
|
13
|
+
font_name = style.preferred_family_name || font.name
|
14
|
+
add_index_formula(font_name, formula.to_index_formula)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def normalize_key(key)
|
20
|
+
key.downcase
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/fontist/repo.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require "git"
|
2
|
+
|
3
|
+
module Fontist
|
4
|
+
class Repo
|
5
|
+
class << self
|
6
|
+
def setup(name, url)
|
7
|
+
ensure_private_formulas_path_exists
|
8
|
+
fetch_repo(name, url)
|
9
|
+
Index.rebuild
|
10
|
+
end
|
11
|
+
|
12
|
+
def update(name)
|
13
|
+
path = repo_path(name)
|
14
|
+
unless Dir.exist?(path)
|
15
|
+
raise(Errors::RepoNotFoundError, "No such repo '#{name}'.")
|
16
|
+
end
|
17
|
+
|
18
|
+
Git.open(path).pull
|
19
|
+
Index.rebuild
|
20
|
+
end
|
21
|
+
|
22
|
+
def remove(name)
|
23
|
+
path = repo_path(name)
|
24
|
+
unless Dir.exist?(path)
|
25
|
+
raise(Errors::RepoNotFoundError, "No such repo '#{name}'.")
|
26
|
+
end
|
27
|
+
|
28
|
+
FileUtils.rm_r(path)
|
29
|
+
Index.rebuild
|
30
|
+
end
|
31
|
+
|
32
|
+
def list
|
33
|
+
Dir.glob(Fontist.private_formulas_path.join("*"))
|
34
|
+
.select { |path| File.directory?(path) }
|
35
|
+
.map { |path| File.basename(path) }
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def ensure_private_formulas_path_exists
|
41
|
+
Fontist.private_formulas_path.tap do |path|
|
42
|
+
FileUtils.mkdir_p(path) unless Dir.exist?(path)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def fetch_repo(name, url)
|
47
|
+
path = repo_path(name)
|
48
|
+
if Dir.exist?(path)
|
49
|
+
Git.open(path).pull
|
50
|
+
else
|
51
|
+
Git.clone(url, path, depth: 1)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def repo_path(name)
|
56
|
+
Fontist.private_formulas_path.join(name)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Fontist
|
2
|
+
class RepoCLI < Thor
|
3
|
+
desc "setup NAME URL",
|
4
|
+
"Setup a custom fontist repo named NAME for the repository at URL " \
|
5
|
+
"and fetches its formulas"
|
6
|
+
def setup(name, url)
|
7
|
+
Repo.setup(name, url)
|
8
|
+
Fontist.ui.success(
|
9
|
+
"Fontist repo '#{name}' from '#{url}' has been successfully set up.",
|
10
|
+
)
|
11
|
+
CLI::STATUS_SUCCESS
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "update NAME", "Update formulas in a fontist repo named NAME"
|
15
|
+
def update(name)
|
16
|
+
Repo.update(name)
|
17
|
+
Fontist.ui.success(
|
18
|
+
"Fontist repo '#{name}' has been successfully updated.",
|
19
|
+
)
|
20
|
+
CLI::STATUS_SUCCESS
|
21
|
+
rescue Errors::RepoNotFoundError
|
22
|
+
handle_repo_not_found(name)
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "remove NAME", "Remove fontist repo named NAME"
|
26
|
+
def remove(name)
|
27
|
+
Repo.remove(name)
|
28
|
+
Fontist.ui.success(
|
29
|
+
"Fontist repo '#{name}' has been successfully removed.",
|
30
|
+
)
|
31
|
+
CLI::STATUS_SUCCESS
|
32
|
+
rescue Errors::RepoNotFoundError
|
33
|
+
handle_repo_not_found(name)
|
34
|
+
end
|
35
|
+
|
36
|
+
desc "list", "List fontist repos"
|
37
|
+
def list
|
38
|
+
Repo.list.each do |name|
|
39
|
+
Fontist.ui.say(name)
|
40
|
+
end
|
41
|
+
CLI::STATUS_SUCCESS
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def handle_repo_not_found(name)
|
47
|
+
Fontist.ui.error("Fontist repo '#{name}' is not found.")
|
48
|
+
CLI::STATUS_REPO_NOT_FOUND
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|