fontist 1.7.3 → 1.8.1

Sign up to get free protection for your applications and to get access to all the features.
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