fontist 1.7.3 → 1.8.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.
Files changed (43) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/release.yml +38 -0
  3. data/.github/workflows/rspec.yml +58 -0
  4. data/README.md +34 -4
  5. data/{bin → exe}/fontist +0 -0
  6. data/fontist.gemspec +3 -2
  7. data/lib/fontist.rb +5 -2
  8. data/lib/fontist/cli.rb +53 -38
  9. data/lib/fontist/errors.rb +14 -12
  10. data/lib/fontist/font.rb +25 -27
  11. data/lib/fontist/font_installer.rb +114 -0
  12. data/lib/fontist/fontist_font.rb +3 -49
  13. data/lib/fontist/formula.rb +101 -35
  14. data/lib/fontist/formula_paths.rb +43 -0
  15. data/lib/fontist/helpers.rb +7 -0
  16. data/lib/fontist/import/google_check.rb +1 -1
  17. data/lib/fontist/import/google_import.rb +3 -4
  18. data/lib/fontist/import/otfinfo_generate.rb +1 -1
  19. data/lib/fontist/import/recursive_extraction.rb +5 -1
  20. data/lib/fontist/index.rb +72 -0
  21. data/lib/fontist/index_formula.rb +30 -0
  22. data/lib/fontist/manifest/install.rb +4 -5
  23. data/lib/fontist/manifest/locations.rb +9 -1
  24. data/lib/fontist/system_font.rb +2 -29
  25. data/lib/fontist/system_index.rb +1 -1
  26. data/lib/fontist/utils/exe_extractor.rb +1 -1
  27. data/lib/fontist/utils/zip_extractor.rb +1 -1
  28. data/lib/fontist/version.rb +1 -1
  29. metadata +27 -19
  30. data/.github/workflows/macosx.yml +0 -33
  31. data/.github/workflows/ubuntu.yml +0 -30
  32. data/.github/workflows/windows.yml +0 -32
  33. data/bin/check_google +0 -8
  34. data/bin/console +0 -11
  35. data/bin/convert_formulas +0 -8
  36. data/bin/generate_otfinfo +0 -8
  37. data/bin/import_google +0 -8
  38. data/bin/rspec +0 -29
  39. data/bin/setup +0 -7
  40. data/lib/fontist/font_formula.rb +0 -169
  41. data/lib/fontist/formula_template.rb +0 -122
  42. data/lib/fontist/formulas.rb +0 -56
  43. data/lib/fontist/registry.rb +0 -43
@@ -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
@@ -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
- return unless @font_name
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
- paths.empty? ? nil : paths
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
@@ -1,50 +1,43 @@
1
+ require "fontist/index"
2
+ require "fontist/helpers"
3
+ require "git"
4
+
1
5
  module Fontist
2
6
  class Formula
3
- def initialize(options = {})
4
- @font_name = options.fetch(:font_name, nil)
5
- @style_name = options.fetch(:style_name, nil)
6
-
7
- check_and_register_font_formulas
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
- new.all
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
- new(font_name: font_name).find
24
+ Index.from_yaml.load_formulas(font_name).first
16
25
  end
17
26
 
18
- def self.find_fonts(name)
19
- new(font_name: name).find_fonts
20
- end
21
-
22
- def self.find_styles(font, style)
23
- new(font_name: font, style_name: style).find_styles
24
- end
27
+ def self.find_fonts(font_name)
28
+ formulas = Index.from_yaml.load_formulas(font_name)
25
29
 
26
- def all
27
- @all ||= Fontist::Registry.instance.formulas
28
- end
29
-
30
- def find
31
- formulas.values.detect do |formula|
32
- formula.fonts.any? do |f|
33
- f.name.casecmp?(font_name)
34
- end
35
- end
36
- end
37
-
38
- def find_fonts
39
- formulas.values.map do |formula|
30
+ formulas.map do |formula|
40
31
  formula.fonts.select do |f|
41
32
  f.name.casecmp?(font_name)
42
33
  end
43
34
  end.flatten
44
35
  end
45
36
 
46
- def find_styles
47
- formulas.values.map do |formula|
37
+ def self.find_styles(font_name, style_name)
38
+ formulas = Index.from_yaml.load_formulas(font_name)
39
+
40
+ formulas.map do |formula|
48
41
  formula.fonts.map do |f|
49
42
  f.styles.select do |s|
50
43
  f.name.casecmp?(font_name) && s.type.casecmp?(style_name)
@@ -53,16 +46,89 @@ module Fontist
53
46
  end.flatten
54
47
  end
55
48
 
49
+ def self.new_from_file(path)
50
+ data = YAML.load_file(path)
51
+ new(data, path)
52
+ end
53
+
54
+ def initialize(data, path)
55
+ @data = data
56
+ @path = path
57
+ end
58
+
59
+ def to_index_formula
60
+ IndexFormula.new(path)
61
+ end
62
+
63
+ def path
64
+ @path
65
+ end
66
+
67
+ def key
68
+ @data["key"] || default_key
69
+ end
70
+
71
+ def description
72
+ @data["description"]
73
+ end
74
+
75
+ def homepage
76
+ @data["homepage"]
77
+ end
78
+
79
+ def copyright
80
+ @data["copyright"]
81
+ end
82
+
83
+ def license_url
84
+ @data["license_url"]
85
+ end
86
+
87
+ def license
88
+ @data["open_license"] || @data["requires_license_agreement"]
89
+ end
90
+
91
+ def license_required
92
+ @data["requires_license_agreement"] ? true : false
93
+ end
94
+
95
+ def extract
96
+ Helpers.parse_to_object(@data["extract"])
97
+ end
98
+
99
+ def resources
100
+ Helpers.parse_to_object(@data["resources"].values)
101
+ end
102
+
103
+ def fonts
104
+ @fonts ||= Helpers.parse_to_object(hash_collection_fonts + hash_fonts)
105
+ end
106
+
56
107
  private
57
108
 
58
- attr_reader :font_name, :style_name
109
+ def default_key
110
+ escaped = Regexp.escape(Fontist.formulas_path.to_s + "/")
111
+ @path.sub(Regexp.new("^" + escaped), "").sub(/\.yml$/, "")
112
+ end
113
+
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"] }
59
120
 
60
- def formulas
61
- @formulas ||= all.to_h
121
+ coll["fonts"].map do |font|
122
+ { "name" => font["name"],
123
+ "styles" => font["styles"].map { |s| filenames.merge(s) } }
124
+ end
125
+ end
62
126
  end
63
127
 
64
- def check_and_register_font_formulas
65
- $check_and_register_font_formulas ||= Fontist::Formulas.register_formulas
128
+ def hash_fonts
129
+ return [] unless @data["fonts"]
130
+
131
+ @data["fonts"]
66
132
  end
67
133
  end
68
134
  end
@@ -0,0 +1,43 @@
1
+ module Fontist
2
+ class FormulaPaths
3
+ attr_reader :font_paths
4
+
5
+ def initialize(font_paths)
6
+ @font_paths = font_paths
7
+ end
8
+
9
+ def find(font, style = nil)
10
+ styles = find_styles_by_formulas(font, style)
11
+ return if styles.empty?
12
+
13
+ fonts = styles.uniq { |s| s["font"] }.flat_map do |s|
14
+ paths = search_font_paths(s["font"])
15
+ paths.map do |path|
16
+ { full_name: s["full_name"],
17
+ path: path }
18
+ end
19
+ end
20
+
21
+ fonts.empty? ? nil : fonts
22
+ end
23
+
24
+ private
25
+
26
+ def find_styles_by_formulas(font, style)
27
+ if style
28
+ Formula.find_styles(font, style)
29
+ else
30
+ fonts = Formula.find_fonts(font)
31
+ return [] unless fonts
32
+
33
+ fonts.flat_map(&:styles)
34
+ end
35
+ end
36
+
37
+ def search_font_paths(filename)
38
+ font_paths.select do |path|
39
+ File.basename(path) == filename
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,7 @@
1
+ module Fontist
2
+ module Helpers
3
+ def self.parse_to_object(data)
4
+ JSON.parse(data.to_json, object_class: OpenStruct)
5
+ end
6
+ end
7
+ end
@@ -12,7 +12,7 @@ module Fontist
12
12
  private
13
13
 
14
14
  def fetch_formulas
15
- Formulas.fetch_formulas
15
+ Formula.update_formulas_repo
16
16
  end
17
17
 
18
18
  def new_fonts
@@ -156,10 +156,9 @@ module Fontist
156
156
  h.merge!(family_name: style.family_name,
157
157
  type: style.style,
158
158
  full_name: style.full_name)
159
- h.merge!(style.to_h.slice(:post_script_name,
160
- :version,
161
- :description,
162
- :copyright).compact)
159
+ h.merge!(style.to_h.select do |k, _|
160
+ %i(post_script_name version description copyright).include?(k)
161
+ end.compact)
163
162
  h.merge!(font: fix_variable_filename(style.filename))
164
163
  end
165
164
  end
@@ -25,7 +25,7 @@ module Fontist
25
25
  def font_paths(font)
26
26
  formula = Fontist::Formula.find(font)
27
27
  font_formula = Object.const_get(formula.installer)
28
- font_formula.fetch_font(nil, confirmation: "yes")
28
+ font_formula.install(confirmation: "yes")
29
29
  end
30
30
 
31
31
  def generate_styles(paths)
@@ -118,6 +118,9 @@ module Fontist
118
118
  def font_directory?(path, base_path)
119
119
  return true unless @subdir
120
120
 
121
+ # https://bugs.ruby-lang.org/issues/10011
122
+ base_path = Pathname.new(base_path)
123
+
121
124
  relative_path = Pathname.new(path).relative_path_from(base_path).to_s
122
125
  dirname = File.dirname(relative_path)
123
126
  normalized_pattern = @subdir.chomp("/")
@@ -147,7 +150,8 @@ module Fontist
147
150
  end
148
151
 
149
152
  def find_archive(path)
150
- paths = Dir.children(path).map { |file| File.join(path, file) }
153
+ children = Dir.entries(path) - [".", ".."] # ruby 2.4 compat
154
+ paths = children.map { |file| File.join(path, file) }
151
155
  by_subarchive(paths) || by_size(paths)
152
156
  end
153
157