fontist 1.8.1 → 1.8.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/rspec.yml +2 -2
  3. data/README.md +14 -0
  4. data/fontist.gemspec +7 -5
  5. data/lib/fontist.rb +4 -0
  6. data/lib/fontist/cli.rb +22 -24
  7. data/lib/fontist/errors.rb +51 -2
  8. data/lib/fontist/font.rb +33 -54
  9. data/lib/fontist/font_installer.rb +4 -0
  10. data/lib/fontist/font_path.rb +29 -0
  11. data/lib/fontist/formula.rb +4 -4
  12. data/lib/fontist/import/create_formula.rb +3 -2
  13. data/lib/fontist/import/extractors.rb +4 -0
  14. data/lib/fontist/import/extractors/cpio_extractor.rb +39 -0
  15. data/lib/fontist/import/extractors/gzip_extractor.rb +27 -0
  16. data/lib/fontist/import/extractors/rpm_extractor.rb +45 -0
  17. data/lib/fontist/import/extractors/tar_extractor.rb +47 -0
  18. data/lib/fontist/import/google/skiplist.yml +3 -0
  19. data/lib/fontist/import/recursive_extraction.rb +21 -7
  20. data/lib/fontist/import/sil_import.rb +99 -0
  21. data/lib/fontist/index.rb +4 -65
  22. data/lib/fontist/indexes/base_index.rb +82 -0
  23. data/lib/fontist/indexes/filename_index.rb +19 -0
  24. data/lib/fontist/indexes/font_index.rb +21 -0
  25. data/lib/fontist/indexes/index_formula.rb +36 -0
  26. data/lib/fontist/manifest/install.rb +3 -2
  27. data/lib/fontist/manifest/locations.rb +1 -1
  28. data/lib/fontist/system_font.rb +33 -36
  29. data/lib/fontist/system_index.rb +46 -4
  30. data/lib/fontist/utils.rb +5 -0
  31. data/lib/fontist/utils/cache.rb +12 -4
  32. data/lib/fontist/utils/cpio/cpio.rb +199 -0
  33. data/lib/fontist/utils/cpio_extractor.rb +47 -0
  34. data/lib/fontist/utils/gzip_extractor.rb +24 -0
  35. data/lib/fontist/utils/locking.rb +17 -0
  36. data/lib/fontist/utils/rpm_extractor.rb +37 -0
  37. data/lib/fontist/utils/tar_extractor.rb +61 -0
  38. data/lib/fontist/version.rb +1 -1
  39. metadata +53 -13
  40. data/lib/fontist/index_formula.rb +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 0d083618f330800ccb94e30d93fa8b5bf65d5e0a
4
- data.tar.gz: 133e64a85156c8fa5dcfc284ef57b3047fdbec0e
2
+ SHA256:
3
+ metadata.gz: d13c412a0a68cdcf1845948c2f3b96c45187dc27193bae4a581d2ee1f3324201
4
+ data.tar.gz: ed82b44bfc05274b749e4c4b2f2ace5e4ae115343c6ca9f99ac4fc552d71147f
5
5
  SHA512:
6
- metadata.gz: f5a33afe8b4157afadbaa8530e39de7a0b51222904101c396668e6e5d030fc51f6895f9f60478d9a32dc46af1bda7f1cef1aff0f27e2bc10bc3ae0e7b661d71f
7
- data.tar.gz: 3b1d0e38e2b42cf5e24f568cec75a34666ff7b3a98b36b673969365a4ec87b4add38b5fe3dac79a16871596d19b9454eac9fd6ada0097764a26af364f7fd5fee
6
+ metadata.gz: d8a08b20f1b2409b34749ad4f4531e2c727b3e39fa9e3b015d564d6ec14365dd9aa43274aa337845b72e4072bfcad50fe26412a69b805e7c83139934b009a6d6
7
+ data.tar.gz: bb20f38a5c4c4e9714dc69b15f249636e10c76942359e10ac38dc08d98eac3cfc1c6efe879bc9e13596d38872bae75c4721ce6d3892e1ca2726bbe7f9cb50b41
@@ -37,8 +37,8 @@ jobs:
37
37
  - uses: actions/cache@v1
38
38
  with:
39
39
  path: vendor/bundle
40
- key: bundle-${{ matrix.os }}-${{ matrix.ruby }}-${{ hashFiles('**/*.gemspec') }}
41
- restore-keys: bundle-${{ matrix.os }}-${{ matrix.ruby }}
40
+ key: bundle-v2-${{ matrix.os }}-${{ matrix.ruby }}-${{ hashFiles('**/*.gemspec') }}
41
+ restore-keys: bundle-v2-${{ matrix.os }}-${{ matrix.ruby }}
42
42
 
43
43
  - if: matrix.os == 'macos-latest'
44
44
  run: brew install lcdf-typetools
data/README.md CHANGED
@@ -434,6 +434,20 @@ git commit -m "Google Fonts update"
434
434
  git push
435
435
  ```
436
436
 
437
+ ### Import of SIL fonts
438
+
439
+ Fontist contains formulas of [SIL fonts](https://software.sil.org/fonts/). They
440
+ can be updated with:
441
+
442
+ ```sh
443
+ fontist import-sil
444
+ cd ~/.fontist/formulas
445
+ git add Formulas/sil
446
+ git add index.yml
447
+ git commit -m "SIL fonts update"
448
+ git push
449
+ ```
450
+
437
451
  ### Releasing
438
452
 
439
453
  Releasing is done automatically with GitHub Action. Just bump and tag with `gem-release`.
data/fontist.gemspec CHANGED
@@ -5,15 +5,15 @@ require "fontist/version"
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "fontist"
7
7
  spec.version = Fontist::VERSION
8
- spec.authors = ["Ribose Inc.", "Abu Nashir"]
9
- spec.email = ["operations@ribose.com", "abunashir@gmail.com"]
8
+ spec.authors = ["Ribose Inc."]
9
+ spec.email = ["open.source@ribose.com"]
10
10
 
11
- spec.summary = %q{A libarary find or download fonts}
12
- spec.description = %q{A libarary find or download fonts}
11
+ spec.summary = %q{Install openly-licensed fonts on Windows, Linux and Mac!}
12
+ spec.description = %q{Install openly-licensed fonts on Windows, Linux and Mac!}
13
13
  spec.homepage = "https://github.com/fontist/fontist"
14
14
  spec.license = "BSD-2-Clause"
15
15
 
16
- spec.post_install_message = "Please run `fontist update` to fetch formulas"
16
+ spec.post_install_message = "Please run `fontist update` to fetch formulas."
17
17
 
18
18
  spec.metadata["homepage_uri"] = spec.homepage
19
19
  spec.metadata["source_code_uri"] = "https://github.com/fontist/fontist"
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
27
27
  spec.executables = ["fontist"]
28
28
  spec.test_files = `git ls-files -- {spec}/*`.split("\n")
29
29
 
30
+ spec.add_runtime_dependency "arr-pm", "~> 0.0.1"
30
31
  spec.add_runtime_dependency "down", "~> 5.0"
31
32
  spec.add_runtime_dependency "libmspack", "~> 0.1.0"
32
33
  spec.add_runtime_dependency "rubyzip", "~> 2.3.0"
@@ -40,6 +41,7 @@ Gem::Specification.new do |spec|
40
41
  spec.add_development_dependency "pry"
41
42
  spec.add_development_dependency "bundler", "~> 2.0"
42
43
  spec.add_development_dependency "gem-release"
44
+ spec.add_development_dependency "nokogiri", "~> 1.0"
43
45
  spec.add_development_dependency "rake", "~> 12.3.3"
44
46
  spec.add_development_dependency "rspec", "~> 3.0"
45
47
  spec.add_development_dependency "rubocop", "0.75.0"
data/lib/fontist.rb CHANGED
@@ -62,4 +62,8 @@ module Fontist
62
62
  def self.formula_index_path
63
63
  Fontist.formulas_repo_path.join("index.yml")
64
64
  end
65
+
66
+ def self.formula_filename_index_path
67
+ Fontist.formulas_repo_path.join("filename_index.yml")
68
+ end
65
69
  end
data/lib/fontist/cli.rb CHANGED
@@ -9,15 +9,17 @@ module Fontist
9
9
  STATUS_LICENSING_ERROR = 4
10
10
  STATUS_MANIFEST_COULD_NOT_BE_FOUND_ERROR = 5
11
11
  STATUS_MANIFEST_COULD_NOT_BE_READ_ERROR = 6
12
+ STATUS_FONT_INDEX_CORRUPTED = 7
12
13
 
13
14
  ERROR_TO_STATUS = {
14
- Fontist::Errors::NonSupportedFontError => [STATUS_NON_SUPPORTED_FONT_ERROR],
15
+ Fontist::Errors::UnsupportedFontError => [STATUS_NON_SUPPORTED_FONT_ERROR],
15
16
  Fontist::Errors::MissingFontError => [STATUS_MISSING_FONT_ERROR],
16
17
  Fontist::Errors::LicensingError => [STATUS_LICENSING_ERROR],
17
18
  Fontist::Errors::ManifestCouldNotBeFoundError => [STATUS_MANIFEST_COULD_NOT_BE_FOUND_ERROR,
18
19
  "Manifest could not be found."],
19
20
  Fontist::Errors::ManifestCouldNotBeReadError => [STATUS_MANIFEST_COULD_NOT_BE_READ_ERROR,
20
21
  "Manifest could not be read."],
22
+ Fontist::Errors::FontIndexCorrupted => [STATUS_FONT_INDEX_CORRUPTED],
21
23
  }.freeze
22
24
 
23
25
  def self.exit_on_failure?
@@ -27,12 +29,14 @@ module Fontist
27
29
  desc "install FONT", "Install font"
28
30
  option :force, type: :boolean, aliases: :f,
29
31
  desc: "Install even if it's already installed in system"
30
- option :confirm_license, type: :boolean, desc: "Confirm license agreement"
32
+ option :accept_all_licenses, type: :boolean, aliases: "--confirm-license", desc: "Accept all license agreements"
33
+ option :hide_licenses, type: :boolean, desc: "Hide license texts"
31
34
  def install(font)
32
35
  Fontist::Font.install(
33
36
  font,
34
37
  force: options[:force],
35
- confirmation: options[:confirm_license] ? "yes" : "no"
38
+ confirmation: options[:accept_all_licenses] ? "yes" : "no",
39
+ hide_licenses: options[:hide_licenses]
36
40
  )
37
41
  success
38
42
  rescue Fontist::Errors::GeneralError => e
@@ -50,12 +54,11 @@ module Fontist
50
54
  end
51
55
  map remove: :uninstall
52
56
 
53
- desc "status [FONT]", "Show status of FONT or all fonts in fontist"
57
+ desc "status [FONT]", "Show paths of FONT or all fonts"
54
58
  def status(font = nil)
55
- formulas = Fontist::Font.status(font)
56
- return error("No font is installed.", STATUS_MISSING_FONT_ERROR) if formulas.empty?
59
+ paths = Fontist::Font.status(font)
60
+ return error("No font is installed.", STATUS_MISSING_FONT_ERROR) if paths.empty?
57
61
 
58
- print_formulas(formulas)
59
62
  success
60
63
  rescue Fontist::Errors::GeneralError => e
61
64
  handle_error(e)
@@ -88,11 +91,13 @@ module Fontist
88
91
  end
89
92
 
90
93
  desc "manifest-install MANIFEST", "Install fonts from MANIFEST (yaml)"
91
- option :confirm_license, type: :boolean, desc: "Confirm license agreement"
94
+ option :accept_all_licenses, type: :boolean, aliases: "--confirm-license", desc: "Accept all license agreements"
95
+ option :hide_licenses, type: :boolean, desc: "Hide license texts"
92
96
  def manifest_install(manifest)
93
97
  paths = Fontist::Manifest::Install.from_file(
94
98
  manifest,
95
- confirmation: options[:confirm_license] ? "yes" : "no"
99
+ confirmation: options[:accept_all_licenses] ? "yes" : "no",
100
+ hide_licenses: options[:hide_licenses]
96
101
  )
97
102
 
98
103
  print_yaml(paths)
@@ -105,7 +110,8 @@ module Fontist
105
110
  option :name, desc: "Example: Times New Roman"
106
111
  option :mirror, repeatable: true
107
112
  option :subarchive, desc: "Subarchive to choose when there are several ones"
108
- option :subdir, desc: "Subdirectory to take fonts from"
113
+ option :subdir, desc: "Subdirectory to take fonts from, starting with the " \
114
+ "root dir, e.g.: stixfonts-2.10/fonts/static_otf. May include `fnmatch` patterns."
109
115
  def create_formula(url)
110
116
  require "fontist/import/create_formula"
111
117
  name = Fontist::Import::CreateFormula.new(url, options).call
@@ -124,6 +130,12 @@ module Fontist
124
130
  STATUS_SUCCESS
125
131
  end
126
132
 
133
+ desc "import-sil", "Import formulas from SIL"
134
+ def import_sil
135
+ require "fontist/import/sil_import"
136
+ Fontist::Import::SilImport.new.call
137
+ end
138
+
127
139
  private
128
140
 
129
141
  def success
@@ -146,20 +158,6 @@ module Fontist
146
158
  Fontist.ui.say(YAML.dump(object))
147
159
  end
148
160
 
149
- def print_formulas(formulas)
150
- formulas.each do |formula, fonts|
151
- Fontist.ui.success(formula.key)
152
-
153
- fonts.each do |font, styles|
154
- Fontist.ui.success(" #{font.name}")
155
-
156
- styles.each do |style, path|
157
- Fontist.ui.success(" #{style.type} (#{path})")
158
- end
159
- end
160
- end
161
- end
162
-
163
161
  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
164
162
  def print_list(formulas)
165
163
  formulas.each do |formula, fonts|
@@ -1,7 +1,9 @@
1
1
  module Fontist
2
2
  module Errors
3
3
  class GeneralError < StandardError; end
4
+
4
5
  class BinaryCallError < GeneralError; end
6
+ class FontIndexCorrupted < GeneralError; end
5
7
  class FontNotFoundError < GeneralError; end
6
8
  class FormulaIndexNotFoundError < GeneralError; end
7
9
  class InvalidResourceError < GeneralError; end
@@ -9,10 +11,57 @@ module Fontist
9
11
  class ManifestCouldNotBeFoundError < GeneralError; end
10
12
  class ManifestCouldNotBeReadError < GeneralError; end
11
13
  class MissingAttributeError < GeneralError; end
12
- class MissingFontError < GeneralError; end
13
- class NonSupportedFontError < GeneralError; end
14
14
  class TamperedFileError < GeneralError; end
15
15
  class TimeoutError < GeneralError; end
16
16
  class UnknownFontTypeError < GeneralError; end
17
+ class UnknownArchiveError < GeneralError; end
18
+
19
+ class FontError < GeneralError
20
+ attr_reader :font, :style
21
+
22
+ def initialize(msg, font = nil, style = nil)
23
+ @font = font
24
+ @style = style
25
+
26
+ super(msg)
27
+ end
28
+
29
+ def name
30
+ messages = []
31
+ messages << "Font name: '#{@font}'"
32
+ messages << "Style: '#{@style}'" if @style
33
+ messages.join("; ")
34
+ end
35
+ end
36
+
37
+ class MissingFontError < FontError
38
+ def initialize(font, style = nil)
39
+ name = prepare_name(font, style)
40
+ msg = "#{name} font is missing, please run `fontist install '#{font}'` to download the font."
41
+
42
+ super(msg, font, style)
43
+ end
44
+
45
+ private
46
+
47
+ def prepare_name(font, style)
48
+ names = []
49
+ names << "'#{font}'"
50
+ names << "'#{style}'" if style
51
+ names.join(" ")
52
+ end
53
+ end
54
+
55
+ class UnsupportedFontError < FontError
56
+ def initialize(font)
57
+ msg = <<~MSG.chomp
58
+ Font '#{font}' not found locally nor available in the Fontist formula repository.
59
+ Perhaps it is available at the latest Fontist formula repository.
60
+ You can update the formula repository using the command `fontist update` and try again.
61
+ MSG
62
+
63
+ super(msg, font)
64
+ end
65
+ end
17
66
  end
18
67
  end
data/lib/fontist/font.rb CHANGED
@@ -1,11 +1,13 @@
1
1
  require "fontist/font_installer"
2
+ require "fontist/font_path"
2
3
 
3
4
  module Fontist
4
5
  class Font
5
6
  def initialize(options = {})
6
- @name = options.fetch(:name, nil)
7
- @confirmation = options.fetch(:confirmation, "no")
8
- @force = options.fetch(:force, false)
7
+ @name = options[:name]
8
+ @confirmation = options[:confirmation] || "no"
9
+ @hide_licenses = options[:hide_licenses]
10
+ @force = options[:force] || false
9
11
 
10
12
  check_or_create_fontist_path!
11
13
  end
@@ -18,8 +20,8 @@ module Fontist
18
20
  new(name: name).find
19
21
  end
20
22
 
21
- def self.install(name, confirmation: "no", force: false)
22
- new(name: name, confirmation: confirmation, force: force).install
23
+ def self.install(name, options = {})
24
+ new(options.merge(name: name)).install
23
25
  end
24
26
 
25
27
  def self.uninstall(name)
@@ -47,9 +49,9 @@ module Fontist
47
49
  end
48
50
 
49
51
  def status
50
- return installed_statuses unless @name
52
+ return installed_paths unless @name
51
53
 
52
- font_status || downloadable_font || raise_non_supported_font
54
+ find_system_font || downloadable_font || raise_non_supported_font
53
55
  end
54
56
 
55
57
  def list
@@ -73,9 +75,14 @@ module Fontist
73
75
  return
74
76
  end
75
77
 
78
+ print_paths(paths)
79
+ end
80
+
81
+ def print_paths(paths)
76
82
  Fontist.ui.say("Fonts found at:")
77
83
  paths.each do |path|
78
- Fontist.ui.say("- #{path}")
84
+ font_path = FontPath.new(path)
85
+ Fontist.ui.say(font_path.to_s)
79
86
  end
80
87
  end
81
88
 
@@ -96,12 +103,7 @@ module Fontist
96
103
 
97
104
  def downloadable_font
98
105
  if formula
99
- raise(
100
- Fontist::Errors::MissingFontError,
101
- "#{name} fonts are missing, please run " \
102
- "`fontist install '#{name}'` to " \
103
- "download the font."
104
- )
106
+ raise Fontist::Errors::MissingFontError.new(name)
105
107
  end
106
108
  end
107
109
 
@@ -118,19 +120,26 @@ module Fontist
118
120
  end
119
121
 
120
122
  def check_and_confirm_required_license(formula)
121
- if formula.license_required && !confirmation.casecmp("yes").zero?
122
- @confirmation = show_license_and_ask_for_input(formula.license)
123
+ if formula.license_required
124
+ show_license(formula.license) unless @hide_licenses
123
125
 
124
- if !confirmation.casecmp("yes").zero?
125
- raise Fontist::Errors::LicensingError.new(
126
- "Fontist will not download these fonts unless you accept the terms."
127
- )
126
+ unless confirmation.casecmp?("yes")
127
+ @confirmation = ask_for_agreement
128
+
129
+ unless confirmation&.casecmp?("yes")
130
+ raise Fontist::Errors::LicensingError.new(
131
+ "Fontist will not download these fonts unless you accept the terms."
132
+ )
133
+ end
128
134
  end
129
135
  end
130
136
  end
131
137
 
132
- def show_license_and_ask_for_input(license)
138
+ def show_license(license)
133
139
  Fontist.ui.say(license_agrement_message(license))
140
+ end
141
+
142
+ def ask_for_agreement
134
143
  Fontist.ui.ask(
135
144
  "\nDo you accept all presented font licenses, and want Fontist " \
136
145
  "to download these fonts for you? => TYPE 'Yes' or 'No':"
@@ -166,37 +175,14 @@ module Fontist
166
175
  Fontist::FontistFont.find(name)
167
176
  end
168
177
 
169
- def installed_statuses
170
- installed_styles(all_formulas)
178
+ def installed_paths
179
+ print_paths(SystemFont.font_paths)
171
180
  end
172
181
 
173
182
  def all_formulas
174
183
  Fontist::Formula.all
175
184
  end
176
185
 
177
- def font_status
178
- return unless formula
179
-
180
- statuses = installed_styles([formula])
181
- statuses.empty? ? nil : statuses
182
- end
183
-
184
- def installed_styles(formulas)
185
- filter_blank(formulas) do |formula|
186
- filter_blank(formula.fonts) do |font|
187
- filter_blank(font.styles) do |style|
188
- path(style)
189
- end
190
- end
191
- end
192
- end
193
-
194
- def filter_blank(elements)
195
- elements.map { |e| [e, yield(e)] }
196
- .to_h
197
- .reject { |_k, v| v.nil? || v.empty? }
198
- end
199
-
200
186
  def path(style)
201
187
  font_paths.detect do |path|
202
188
  File.basename(path) == style.font
@@ -236,14 +222,7 @@ module Fontist
236
222
  end
237
223
 
238
224
  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
- )
225
+ raise Fontist::Errors::UnsupportedFontError.new(@name)
247
226
  end
248
227
  end
249
228
  end
@@ -6,6 +6,10 @@ module Fontist
6
6
  include Utils::ExeExtractor
7
7
  include Utils::MsiExtractor
8
8
  include Utils::SevenZipExtractor
9
+ include Utils::RpmExtractor
10
+ include Utils::GzipExtractor
11
+ include Utils::CpioExtractor
12
+ include Utils::TarExtractor
9
13
 
10
14
  def initialize(formula)
11
15
  @formula = formula
@@ -0,0 +1,29 @@
1
+ require "fontist/indexes/filename_index"
2
+
3
+ module Fontist
4
+ class FontPath
5
+ def initialize(path)
6
+ @path = path
7
+ end
8
+
9
+ def to_s
10
+ [].tap do |s|
11
+ s << "-"
12
+ s << @path
13
+ s << "(from #{formulas.join(' or ')} formula)" if formulas.any?
14
+ end.join(" ")
15
+ end
16
+
17
+ def formulas
18
+ @formulas ||= if fontist_font?
19
+ Indexes::FilenameIndex.from_yaml.load_index_formulas(File.basename(@path)).map(&:name)
20
+ else
21
+ []
22
+ end
23
+ end
24
+
25
+ def fontist_font?
26
+ @path.start_with?(Fontist.fonts_path.to_s)
27
+ end
28
+ end
29
+ end