fontist 1.8.6 → 1.8.11

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