fontist 1.8.6 → 1.8.11

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rspec.yml +5 -14
  3. data/README.md +3 -3
  4. data/fontist.gemspec +3 -7
  5. data/lib/fontist/cli.rb +3 -1
  6. data/lib/fontist/font.rb +20 -15
  7. data/lib/fontist/font_installer.rb +40 -39
  8. data/lib/fontist/formula.rb +4 -0
  9. data/lib/fontist/import/helpers/system_helper.rb +1 -3
  10. data/lib/fontist/import/recursive_extraction.rb +25 -119
  11. data/lib/fontist/manifest/install.rb +10 -3
  12. data/lib/fontist/utils.rb +0 -8
  13. data/lib/fontist/utils/cache.rb +27 -8
  14. data/lib/fontist/utils/downloader.rb +81 -36
  15. data/lib/fontist/version.rb +1 -1
  16. metadata +14 -89
  17. data/lib/fontist/import/extractors.rb +0 -9
  18. data/lib/fontist/import/extractors/cab_extractor.rb +0 -37
  19. data/lib/fontist/import/extractors/cpio_extractor.rb +0 -39
  20. data/lib/fontist/import/extractors/extractor.rb +0 -19
  21. data/lib/fontist/import/extractors/gzip_extractor.rb +0 -27
  22. data/lib/fontist/import/extractors/ole_extractor.rb +0 -41
  23. data/lib/fontist/import/extractors/rpm_extractor.rb +0 -45
  24. data/lib/fontist/import/extractors/seven_zip_extractor.rb +0 -44
  25. data/lib/fontist/import/extractors/tar_extractor.rb +0 -47
  26. data/lib/fontist/import/extractors/zip_extractor.rb +0 -31
  27. data/lib/fontist/utils/cpio/cpio.rb +0 -199
  28. data/lib/fontist/utils/cpio_extractor.rb +0 -47
  29. data/lib/fontist/utils/exe_extractor.rb +0 -75
  30. data/lib/fontist/utils/gzip_extractor.rb +0 -24
  31. data/lib/fontist/utils/msi_extractor.rb +0 -31
  32. data/lib/fontist/utils/rpm_extractor.rb +0 -37
  33. data/lib/fontist/utils/seven_zip_extractor.rb +0 -41
  34. data/lib/fontist/utils/tar_extractor.rb +0 -61
  35. data/lib/fontist/utils/zip_extractor.rb +0 -52
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d13c412a0a68cdcf1845948c2f3b96c45187dc27193bae4a581d2ee1f3324201
4
- data.tar.gz: ed82b44bfc05274b749e4c4b2f2ace5e4ae115343c6ca9f99ac4fc552d71147f
3
+ metadata.gz: 44eeffc78fd8188b4084f8771b17fd8b007c52cc6aec24b1ec50a5468e03d7a6
4
+ data.tar.gz: c039bba16e70d0a5def84fa3d63e24812e18b91751f4ee32a0bd1d5a789762d5
5
5
  SHA512:
6
- metadata.gz: d8a08b20f1b2409b34749ad4f4531e2c727b3e39fa9e3b015d564d6ec14365dd9aa43274aa337845b72e4072bfcad50fe26412a69b805e7c83139934b009a6d6
7
- data.tar.gz: bb20f38a5c4c4e9714dc69b15f249636e10c76942359e10ac38dc08d98eac3cfc1c6efe879bc9e13596d38872bae75c4721ce6d3892e1ca2726bbe7f9cb50b41
6
+ metadata.gz: 51da44eb3fcb027b45a283d860a54fd8f3da7dcdc34bf341f6e6e87b80b69dd0fe200060d32f63efbde9f53589aa50155418f277be131b062b07462de1b3f19c
7
+ data.tar.gz: 6faf5f88267c1173e271cc662e3b177862bb35462916e19a85232c0fbec54260a709781b470fe513e25697be2173a73097e5760e9b312629c4443316a4f95d04
@@ -13,17 +13,17 @@ jobs:
13
13
  strategy:
14
14
  fail-fast: false
15
15
  matrix:
16
- ruby: [ '2.6', '2.5', '2.4' ]
16
+ ruby: [ '2.4', '2.5', '2.6', '2.7' ]
17
17
  os: [ ubuntu-latest, windows-latest, macos-latest ]
18
18
  experimental: [ false ]
19
19
  include:
20
- - ruby: '2.7'
20
+ - ruby: '3.0'
21
21
  os: 'ubuntu-latest'
22
22
  experimental: true
23
- - ruby: '2.7'
23
+ - ruby: '3.0'
24
24
  os: 'windows-latest'
25
25
  experimental: true
26
- - ruby: '2.7'
26
+ - ruby: '3.0'
27
27
  os: 'macos-latest'
28
28
  experimental: true
29
29
 
@@ -33,20 +33,11 @@ jobs:
33
33
  - uses: ruby/setup-ruby@v1
34
34
  with:
35
35
  ruby-version: ${{ matrix.ruby }}
36
-
37
- - uses: actions/cache@v1
38
- with:
39
- path: vendor/bundle
40
- key: bundle-v2-${{ matrix.os }}-${{ matrix.ruby }}-${{ hashFiles('**/*.gemspec') }}
41
- restore-keys: bundle-v2-${{ matrix.os }}-${{ matrix.ruby }}
36
+ bundler-cache: true
42
37
 
43
38
  - if: matrix.os == 'macos-latest'
44
39
  run: brew install lcdf-typetools
45
40
 
46
- - run: bundle config set path 'vendor/bundle'
47
-
48
- - run: bundle install --jobs 4 --retry 3
49
-
50
41
  - if: matrix.os == 'macos-latest'
51
42
  run: bundle exec rspec
52
43
  env:
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Fontist
2
2
 
3
- ![windows](https://github.com/fontist/fontist/workflows/windows/badge.svg)
4
- ![macos](https://github.com/fontist/fontist/workflows/macos/badge.svg)
5
- ![ubuntu](https://github.com/fontist/fontist/workflows/ubuntu/badge.svg)
3
+ [![Build Status](https://github.com/fontist/fontist/actions/workflows/rspec.yml/badge.svg)](https://github.com/fontist/fontist/actions/workflows/rspec.yml)
4
+ [![Gem Version](https://img.shields.io/gem/v/fontist.svg)](https://rubygems.org/gems/fontist")
5
+ [![Pull Requests](https://img.shields.io/github/issues-pr-raw/fontist/fontist.svg)](https://github.com/fontist/fontist/pulls)
6
6
 
7
7
  A simple library to find and download fonts for Windows, Linux and Mac.
8
8
 
data/fontist.gemspec CHANGED
@@ -27,22 +27,18 @@ 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"
31
30
  spec.add_runtime_dependency "down", "~> 5.0"
32
- spec.add_runtime_dependency "libmspack", "~> 0.1.0"
33
- spec.add_runtime_dependency "rubyzip", "~> 2.3.0"
34
- spec.add_runtime_dependency "seven_zip_ruby", "~> 1.0"
35
- spec.add_runtime_dependency "ruby-ole", "~> 1.0"
36
31
  spec.add_runtime_dependency "thor", "~> 1.0.1"
37
32
  spec.add_runtime_dependency "git", "~> 1.0"
38
- spec.add_runtime_dependency "ttfunk", "~> 1.0"
33
+ spec.add_runtime_dependency "ttfunk", "~> 1.6"
34
+ spec.add_runtime_dependency "excavate", "~> 0.1"
39
35
 
40
36
  spec.add_development_dependency "extract_ttc", "~> 0.1"
41
37
  spec.add_development_dependency "pry"
42
38
  spec.add_development_dependency "bundler", "~> 2.0"
43
39
  spec.add_development_dependency "gem-release"
44
40
  spec.add_development_dependency "nokogiri", "~> 1.0"
45
- spec.add_development_dependency "rake", "~> 12.3.3"
41
+ spec.add_development_dependency "rake", "~> 13"
46
42
  spec.add_development_dependency "rspec", "~> 3.0"
47
43
  spec.add_development_dependency "rubocop", "0.75.0"
48
44
  spec.add_development_dependency "rubocop-rails"
data/lib/fontist/cli.rb CHANGED
@@ -31,12 +31,14 @@ module Fontist
31
31
  desc: "Install even if it's already installed in system"
32
32
  option :accept_all_licenses, type: :boolean, aliases: "--confirm-license", desc: "Accept all license agreements"
33
33
  option :hide_licenses, type: :boolean, desc: "Hide license texts"
34
+ option :no_progress, type: :boolean, desc: "Hide download progress"
34
35
  def install(font)
35
36
  Fontist::Font.install(
36
37
  font,
37
38
  force: options[:force],
38
39
  confirmation: options[:accept_all_licenses] ? "yes" : "no",
39
- hide_licenses: options[:hide_licenses]
40
+ hide_licenses: options[:hide_licenses],
41
+ no_progress: options[:no_progress]
40
42
  )
41
43
  success
42
44
  rescue Fontist::Errors::GeneralError => e
data/lib/fontist/font.rb CHANGED
@@ -7,6 +7,7 @@ module Fontist
7
7
  @name = options[:name]
8
8
  @confirmation = options[:confirmation] || "no"
9
9
  @hide_licenses = options[:hide_licenses]
10
+ @no_progress = options[:no_progress] || false
10
11
  @force = options[:force] || false
11
12
 
12
13
  check_or_create_fontist_path!
@@ -66,7 +67,7 @@ module Fontist
66
67
 
67
68
  private
68
69
 
69
- attr_reader :name, :confirmation
70
+ attr_reader :name
70
71
 
71
72
  def find_system_font
72
73
  paths = Fontist::SystemFont.find(name)
@@ -94,13 +95,17 @@ module Fontist
94
95
  end
95
96
 
96
97
  def font_installer(formula)
97
- FontInstaller.new(formula)
98
+ FontInstaller.new(formula, no_progress: @no_progress)
98
99
  end
99
100
 
100
101
  def formula
101
102
  @formula ||= Fontist::Formula.find(name)
102
103
  end
103
104
 
105
+ def formulas
106
+ @formulas ||= Fontist::Formula.find_many(name)
107
+ end
108
+
104
109
  def downloadable_font
105
110
  if formula
106
111
  raise Fontist::Errors::MissingFontError.new(name)
@@ -108,8 +113,10 @@ module Fontist
108
113
  end
109
114
 
110
115
  def download_font
111
- if formula
112
- check_and_confirm_required_license(formula)
116
+ return if formulas.empty?
117
+
118
+ formulas.flat_map do |formula|
119
+ confirmation = check_and_confirm_required_license(formula)
113
120
  paths = font_installer(formula).install(confirmation: confirmation)
114
121
 
115
122
  Fontist.ui.say("Fonts installed at:")
@@ -120,19 +127,17 @@ module Fontist
120
127
  end
121
128
 
122
129
  def check_and_confirm_required_license(formula)
123
- if formula.license_required
124
- show_license(formula.license) unless @hide_licenses
130
+ return @confirmation unless formula.license_required
125
131
 
126
- unless confirmation.casecmp?("yes")
127
- @confirmation = ask_for_agreement
132
+ show_license(formula.license) unless @hide_licenses
133
+ return @confirmation if @confirmation.casecmp?("yes")
128
134
 
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
134
- end
135
- end
135
+ confirmation = ask_for_agreement
136
+ return confirmation if confirmation&.casecmp?("yes")
137
+
138
+ raise Fontist::Errors::LicensingError.new(
139
+ "Fontist will not download these fonts unless you accept the terms."
140
+ )
136
141
  end
137
142
 
138
143
  def show_license(license)
@@ -1,18 +1,11 @@
1
1
  require "fontist/utils"
2
+ require "excavate"
2
3
 
3
4
  module Fontist
4
5
  class FontInstaller
5
- include Utils::ZipExtractor
6
- include Utils::ExeExtractor
7
- include Utils::MsiExtractor
8
- include Utils::SevenZipExtractor
9
- include Utils::RpmExtractor
10
- include Utils::GzipExtractor
11
- include Utils::CpioExtractor
12
- include Utils::TarExtractor
13
-
14
- def initialize(formula)
6
+ def initialize(formula, no_progress: false)
15
7
  @formula = formula
8
+ @no_progress = no_progress
16
9
  end
17
10
 
18
11
  def install(confirmation:)
@@ -20,7 +13,6 @@ module Fontist
20
13
  raise(Fontist::Errors::LicensingError)
21
14
  end
22
15
 
23
- reinitialize
24
16
  install_font
25
17
  end
26
18
 
@@ -28,10 +20,6 @@ module Fontist
28
20
 
29
21
  attr_reader :formula
30
22
 
31
- def reinitialize
32
- @downloaded = false
33
- end
34
-
35
23
  def install_font
36
24
  fonts_paths = run_in_temp_dir { extract }
37
25
  fonts_paths.empty? ? nil : fonts_paths
@@ -50,47 +38,39 @@ module Fontist
50
38
  end
51
39
 
52
40
  def extract
53
- resource = @formula.resources.first
54
-
55
- [@formula.extract].flatten.each do |operation|
56
- resource = extract_by_operation(operation, resource)
57
- end
58
-
59
- fonts_paths = resource
41
+ archive = download_file(@formula.resources.first)
60
42
 
61
- fonts_paths
43
+ install_fonts_from_archive(archive)
62
44
  end
63
45
 
64
- def extract_by_operation(operation, resource)
65
- method = "#{operation.format}_extract"
66
- if operation.options
67
- send(method, resource, **operation.options.to_h)
68
- else
69
- send(method, resource)
70
- end
71
- end
46
+ def install_fonts_from_archive(archive)
47
+ Fontist.ui.say(%(Installing font "#{@formula.key}".))
72
48
 
73
- def fonts_path
74
- Fontist.fonts_path
49
+ Array.new.tap do |fonts_paths|
50
+ Excavate::Archive.new(archive.path).files(recursive_packages: true) do |path|
51
+ fonts_paths << install_font_file(path) if font_file?(path)
52
+ end
53
+ end
75
54
  end
76
55
 
77
56
  def download_file(source)
78
57
  url = source.urls.first
79
58
  Fontist.ui.say(%(Downloading font "#{@formula.key}" from #{url}))
80
59
 
81
- downloaded_file = Fontist::Utils::Downloader.download(
60
+ Fontist::Utils::Downloader.download(
82
61
  url,
83
62
  sha: source.sha256,
84
63
  file_size: source.file_size,
85
- progress_bar: true
64
+ progress_bar: !@no_progress
86
65
  )
66
+ end
87
67
 
88
- @downloaded = true
89
- downloaded_file
68
+ def font_file?(path)
69
+ source_file?(path) && font_directory?(path)
90
70
  end
91
71
 
92
- def font_file?(filename)
93
- source_files.include?(filename)
72
+ def source_file?(path)
73
+ source_files.include?(File.basename(path))
94
74
  end
95
75
 
96
76
  def source_files
@@ -101,6 +81,27 @@ module Fontist
101
81
  end
102
82
  end
103
83
 
84
+ def font_directory?(path)
85
+ return true unless subdirectory_pattern
86
+
87
+ File.fnmatch?(subdirectory_pattern, File.dirname(path))
88
+ end
89
+
90
+ def subdirectory_pattern
91
+ @subdirectory_pattern ||= "*" + subdirectories.first.chomp("/") unless subdirectories.empty?
92
+ end
93
+
94
+ def subdirectories
95
+ @subdirectories ||= [@formula.extract].flatten.map(&:options).compact.map(&:fonts_sub_dir).compact
96
+ end
97
+
98
+ def install_font_file(source)
99
+ target = Fontist.fonts_path.join(target_filename(File.basename(source))).to_s
100
+ FileUtils.mv(source, target)
101
+
102
+ target
103
+ end
104
+
104
105
  def target_filename(source_filename)
105
106
  target_filenames[source_filename]
106
107
  end
@@ -24,6 +24,10 @@ module Fontist
24
24
  Indexes::FontIndex.from_yaml.load_formulas(font_name).first
25
25
  end
26
26
 
27
+ def self.find_many(font_name)
28
+ Indexes::FontIndex.from_yaml.load_formulas(font_name)
29
+ end
30
+
27
31
  def self.find_fonts(font_name)
28
32
  formulas = Indexes::FontIndex.from_yaml.load_formulas(font_name)
29
33
 
@@ -4,9 +4,7 @@ module Fontist
4
4
  module SystemHelper
5
5
  class << self
6
6
  def run(command)
7
- unless ENV.fetch("TEST_ENV", "") === "CI"
8
- Fontist.ui.say("Run `#{command}`")
9
- end
7
+ Fontist.ui.say("Run `#{command}`")
10
8
 
11
9
  result = `#{command}`
12
10
  unless $CHILD_STATUS.to_i.zero?
@@ -1,21 +1,18 @@
1
- require "find"
2
- require_relative "extractors"
3
1
  require_relative "files/font_detector"
4
2
 
5
3
  module Fontist
6
4
  module Import
7
5
  class RecursiveExtraction
8
- FONTS_PATTERN = "**/*.{ttf,otf,ttc}".freeze
9
- ARCHIVE_EXTENSIONS = %w[zip msi exe cab].freeze
10
6
  LICENSE_PATTERN = /(ofl\.txt|ufl\.txt|licenses?\.txt|copying)$/i.freeze
11
7
 
12
8
  def initialize(archive, subarchive: nil, subdir: nil)
13
9
  @archive = archive
14
- @subarchive = subarchive
15
10
  @subdir = subdir
16
- @operations = []
11
+ @operations = {}
17
12
  @font_files = []
18
13
  @collection_files = []
14
+
15
+ save_operation_subdir
19
16
  end
20
17
 
21
18
  def extension
@@ -39,11 +36,18 @@ module Fontist
39
36
 
40
37
  def operations
41
38
  ensure_extracted
42
- @operations.size == 1 ? @operations.first : @operations
39
+ @operations
43
40
  end
44
41
 
45
42
  private
46
43
 
44
+ def save_operation_subdir
45
+ return unless @subdir
46
+
47
+ @operations[:options] ||= {}
48
+ @operations[:options][:fonts_sub_dir] = @subdir
49
+ end
50
+
47
51
  def fetch_extension(file)
48
52
  File.extname(filename(file)).sub(/^\./, "")
49
53
  end
@@ -57,68 +61,21 @@ module Fontist
57
61
  end
58
62
 
59
63
  def ensure_extracted
60
- extracted_path
61
- end
64
+ return if @extracted
62
65
 
63
- def extracted_path
64
- @extracted_path ||= extract_recursively(@archive)
66
+ extract_data(@archive)
67
+ @extracted = true
65
68
  end
66
69
 
67
- def extract_recursively(archive)
68
- path = operate_on_archive(archive)
69
- match_files(path)
70
- if matched?
71
- save_operation_subdir
72
- return path
73
- end
74
-
75
- next_archive = find_archive(path)
76
- extract_recursively(next_archive)
77
- end
78
-
79
- def operate_on_archive(archive)
80
- extractor = choose_extractor(archive)
81
- Fontist.ui.say("Extracting #{archive} with #{extractor.class.name}")
82
-
83
- save_operation(extractor)
84
- extractor.extract
85
- end
86
-
87
- # rubocop:disable Metrics/MethodLength
88
- def choose_extractor(archive)
89
- case fetch_extension(archive).downcase
90
- when "msi"
91
- Extractors::OleExtractor.new(archive)
92
- when "cab"
93
- Extractors::CabExtractor.new(archive)
94
- when "exe"
95
- extractor = Extractors::SevenZipExtractor.new(archive)
96
- extractor.try ? extractor : Extractors::CabExtractor.new(archive)
97
- when "zip"
98
- Extractors::ZipExtractor.new(archive)
99
- when "rpm"
100
- Extractors::RpmExtractor.new(archive)
101
- when "gz"
102
- Extractors::GzipExtractor.new(archive)
103
- when "cpio"
104
- Extractors::CpioExtractor.new(archive)
105
- when "tar"
106
- Extractors::TarExtractor.new(archive)
107
- else
108
- raise Errors::UnknownArchiveError, "Could not unarchive `#{filename(archive)}`."
70
+ def extract_data(archive)
71
+ Excavate::Archive.new(path(archive)).files(recursive_packages: true) do |path|
72
+ match_license(path)
73
+ match_font(path) if font_directory?(path)
109
74
  end
110
75
  end
111
- # rubocop:enable Metrics/MethodLength
112
76
 
113
- def save_operation(extractor)
114
- @operations << { format: extractor.format }
115
- end
116
-
117
- def match_files(dir_path)
118
- Find.find(dir_path) do |entry_path| # rubocop:disable Style/CollectionMethods
119
- match_license(entry_path)
120
- match_font(entry_path) if font_directory?(entry_path, dir_path)
121
- end
77
+ def path(file)
78
+ file.respond_to?(:path) ? file.path : file
122
79
  end
123
80
 
124
81
  def match_license(path)
@@ -129,18 +86,6 @@ module Fontist
129
86
  file.match?(LICENSE_PATTERN)
130
87
  end
131
88
 
132
- def font_directory?(path, base_path)
133
- return true unless @subdir
134
-
135
- # https://bugs.ruby-lang.org/issues/10011
136
- base_path = Pathname.new(base_path)
137
-
138
- relative_path = Pathname.new(path).relative_path_from(base_path).to_s
139
- dirname = File.dirname(relative_path)
140
- normalized_pattern = @subdir.chomp("/")
141
- File.fnmatch?(normalized_pattern, dirname)
142
- end
143
-
144
89
  def match_font(path)
145
90
  case Files::FontDetector.detect(path)
146
91
  when :font
@@ -150,53 +95,14 @@ module Fontist
150
95
  end
151
96
  end
152
97
 
153
- def matched?
154
- [@font_files, @collection_files].any? do |files|
155
- files.size.positive?
156
- end
157
- end
158
-
159
- def save_operation_subdir
160
- return unless @subdir
161
-
162
- @operations.last[:options] ||= {}
163
- @operations.last[:options][:fonts_sub_dir] = @subdir
164
- end
165
-
166
- def find_archive(path)
167
- children = Dir.entries(path) - [".", ".."] # ruby 2.4 compat
168
- paths = children.map { |file| File.join(path, file) }
169
- by_subarchive(paths) || by_size(paths)
170
- end
171
-
172
- def by_subarchive(paths)
173
- return unless @subarchive
174
-
175
- path_found = paths.detect do |path|
176
- @subarchive == File.basename(path)
177
- end
178
-
179
- return unless path_found
180
-
181
- save_operation_subarchive(path_found)
182
-
183
- path_found
184
- end
185
-
186
- def save_operation_subarchive(path)
187
- @operations.last[:options] ||= {}
188
- @operations.last[:options][:subarchive] = File.basename(path)
189
- end
98
+ def font_directory?(path)
99
+ return true unless subdirectory_pattern
190
100
 
191
- def by_size(paths)
192
- paths.max_by do |path|
193
- [file_type(path), File.size(path)]
194
- end
101
+ File.fnmatch?(subdirectory_pattern, File.dirname(path))
195
102
  end
196
103
 
197
- def file_type(file_path)
198
- extension = File.extname(file_path).delete(".")
199
- ARCHIVE_EXTENSIONS.include?(extension) ? 1 : 0
104
+ def subdirectory_pattern
105
+ @subdirectory_pattern ||= "*" + @subdir.chomp("/") if @subdir
200
106
  end
201
107
  end
202
108
  end