fontist 1.11.3 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0461da7c09c672b443f4a0bad5443f3bf48294cb3e0aee5ea7082838825519ca
4
- data.tar.gz: 0e5931e6617e4484074b7d740fbe9f593dc3a31d9b524859167d90cdfc060498
3
+ metadata.gz: 709582759b1009bae25d302ab0590ed5f6fe92fe55d68d1cb57c918942b4f005
4
+ data.tar.gz: 165f75a0625995d8fcc388d46a26168008383d98d2705cb1ea5ed519abe41e80
5
5
  SHA512:
6
- metadata.gz: c0b30b8bfc0f01507d436dea54d5b122751c852a63d2309a5236a5a5f698c140892e54c2f665dbbce4bf0c6f6276c9a7cd1910f212aa7a27937ceca1b8ba510d
7
- data.tar.gz: de92e684e1368ee2a5c10d1789962181316590b87ea5b806d8fd0a959329c54dd0d95723d99334038f75e2865d277b12dbc2c17aeed39b5b57436506273e7be4
6
+ metadata.gz: fd3d62de512ff44e1d9b47c192889fdcefa5db9abea1f0966ac3d761c4ef5567fa547b7d57b4eda52720040d3ca82a03eec2e3d72b24d1f9522dbde1e092c625
7
+ data.tar.gz: 3adf2dcebf7714cc81fc3a6955ac69fdf7affe3e90a845f011f52d284332c856112bef7f8e98cf6d96175c043df299ad0965148ef96308b38c6eace46547ef52
@@ -14,7 +14,7 @@ jobs:
14
14
  fail-fast: false
15
15
  matrix:
16
16
  ruby: [ '2.4', '2.5', '2.6', '2.7', '3.0' ]
17
- os: [ ubuntu-latest, windows-latest, macos-latest ]
17
+ os: [ ubuntu-18.04, ubuntu-latest, windows-latest, macos-latest ]
18
18
  experimental: [ false ]
19
19
 
20
20
  steps:
@@ -33,7 +33,15 @@ jobs:
33
33
  env:
34
34
  TEST_ENV: CI
35
35
 
36
- - if: matrix.os != 'macos-latest'
36
+ - if: matrix.os == 'windows-latest' && matrix.ruby == '2.4'
37
+ run: curl -O https://curl.se/ca/cacert.pem
38
+
39
+ - if: matrix.os == 'windows-latest' && matrix.ruby == '2.4'
40
+ run: bundle exec rspec --tag ~dev
41
+ env:
42
+ SSL_CERT_FILE: cacert.pem
43
+
44
+ - if: matrix.os != 'macos-latest' || matrix.os == 'windows-latest' && matrix.ruby == '2.4'
37
45
  run: bundle exec rspec --tag ~dev
38
46
  env:
39
47
  TEST_ENV: CI
data/.rubocop.yml CHANGED
@@ -1,22 +1,5 @@
1
1
  inherit_from:
2
2
  - 'https://raw.githubusercontent.com/fontist/oss-guides/master/ci/rubocop.yml'
3
3
 
4
- AllCops:
5
- Exclude:
6
- - 'lib/fontist/import/google/fonts_public.pb.rb'
7
- - 'lib/fontist/formula_template.rb'
8
-
9
4
  Rails:
10
5
  Enabled: false
11
-
12
- Layout/LineLength:
13
- Exclude:
14
- - 'lib/fontist/formulas/**/*.rb'
15
-
16
- Layout/FirstHashElementIndentation:
17
- Exclude:
18
- - 'lib/fontist/formulas/**/*.rb'
19
-
20
- Layout/HeredocIndentation:
21
- Exclude:
22
- - 'lib/fontist/formulas/**/*.rb'
data/README.adoc CHANGED
@@ -618,7 +618,7 @@ repository https://github.com/fontist/formulas[formulas]:
618
618
 
619
619
  [source,sh]
620
620
  ----
621
- cd ~/.fontist/versions/v2/formulas
621
+ cd ~/.fontist/versions/{last_version}/formulas
622
622
  git add Formulas/google
623
623
  git commit -m "Google Fonts update"
624
624
  git push
@@ -640,12 +640,44 @@ They can be updated with:
640
640
  [source,sh]
641
641
  ----
642
642
  fontist import-sil
643
- cd ~/.fontist/formulas
644
- git add Formulas/sil index.yml filename_index.yml
643
+ cd ~/.fontist/versions/{last_version}/formulas
644
+ git add Formulas/sil
645
645
  git commit -m "SIL fonts update"
646
646
  git push
647
647
  ----
648
648
 
649
+ === Dynamically importing formulas from macOS
650
+
651
+ macOS provides https://support.apple.com/en-om/HT211240#download[fonts] which
652
+ can be manually downloaded with the Font Book app. When such font is requested,
653
+ fontist prints information on how to install it.
654
+
655
+ In order to know which fonts are available in a current version of macOS,
656
+ for each version there is a formula containing all supported fonts.
657
+
658
+ A new formula can be generated with:
659
+
660
+ [source,sh]
661
+ ----
662
+ fontist import macos --name "Big Sur" --fonts-link "https://support.apple.com/en-om/HT211240#download"
663
+ cd ~/.fontist/versions/{last_version}/formulas
664
+ git add Formulas/macos
665
+ git commit -m "Add Big Sur macOS formula"
666
+ git push
667
+ ----
668
+
669
+ Here `--fonts-link` is a link to a page containing a list of available fonts
670
+ in the Font Book app.
671
+
672
+ If the import is run on a different version of macOS, then a proper version
673
+ should be set in the `platforms` attribute of the generated formula:
674
+
675
+ [source,yaml]
676
+ ----
677
+ platforms:
678
+ - macos-20
679
+ ----
680
+
649
681
 
650
682
  == Development
651
683
 
@@ -685,8 +717,8 @@ one, please refer to its documentation.
685
717
  There is an ability to use private fonts via private Fontist repositories.
686
718
 
687
719
  A Fontist repository is a Git repo which contains YAML formula files. Formulas can be created
688
- manually (see https://github.com/fontist/formulas/tree/master/Formulas)[examples],
689
- or #auto-generate-a-formula[auto-generated from an archive].
720
+ manually (see https://github.com/fontist/formulas/tree/master/Formulas[examples]),
721
+ or xref:Authoring Fontist formulas[auto-generated from an archive].
690
722
 
691
723
  A repository can be either a HTTPS or SSH Git repo. In case of SSH, a
692
724
  corresponding SSH key should be setup with `ssh-agent` in order to access this
data/fontist.gemspec CHANGED
@@ -29,15 +29,17 @@ Gem::Specification.new do |spec|
29
29
 
30
30
  spec.add_runtime_dependency "down", "~> 5.0"
31
31
  spec.add_runtime_dependency "extract_ttc", "~> 0.1"
32
+ spec.add_runtime_dependency "nokogiri", "~> 1.0"
33
+ spec.add_runtime_dependency "sys-uname", "~> 1.2"
32
34
  spec.add_runtime_dependency "thor", "~> 1.0.1"
33
35
  spec.add_runtime_dependency "git", "~> 1.0"
34
36
  spec.add_runtime_dependency "ttfunk", "~> 1.6"
37
+ spec.add_runtime_dependency "plist", "~> 3.0"
35
38
  spec.add_runtime_dependency "excavate", "~> 0.1"
36
39
 
37
40
  spec.add_development_dependency "pry"
38
41
  spec.add_development_dependency "bundler", "~> 2.0"
39
42
  spec.add_development_dependency "gem-release"
40
- spec.add_development_dependency "nokogiri", "~> 1.0"
41
43
  spec.add_development_dependency "rake", "~> 13"
42
44
  spec.add_development_dependency "rspec", "~> 3.0"
43
45
  spec.add_development_dependency "rspec-benchmark", "~> 0.6"
data/lib/fontist/cli.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "thor"
2
2
  require "fontist/repo_cli"
3
+ require "fontist/import_cli"
3
4
  require "fontist/google_cli"
4
5
 
5
6
  module Fontist
@@ -15,10 +16,12 @@ module Fontist
15
16
  STATUS_REPO_NOT_FOUND = 8
16
17
  STATUS_MAIN_REPO_NOT_FOUND = 9
17
18
  STATUS_REPO_COULD_NOT_BE_UPDATED = 10
19
+ STATUS_MANUAL_FONT_ERROR = 11
18
20
 
19
21
  ERROR_TO_STATUS = {
20
22
  Fontist::Errors::UnsupportedFontError => [STATUS_NON_SUPPORTED_FONT_ERROR],
21
23
  Fontist::Errors::MissingFontError => [STATUS_MISSING_FONT_ERROR],
24
+ Fontist::Errors::ManualFontError => [STATUS_MANUAL_FONT_ERROR],
22
25
  Fontist::Errors::LicensingError => [STATUS_LICENSING_ERROR],
23
26
  Fontist::Errors::ManifestCouldNotBeFoundError => [STATUS_MANIFEST_COULD_NOT_BE_FOUND_ERROR,
24
27
  "Manifest could not be found."],
@@ -167,6 +170,9 @@ module Fontist
167
170
  desc "repo SUBCOMMAND ...ARGS", "Manage custom repositories"
168
171
  subcommand "repo", Fontist::RepoCLI
169
172
 
173
+ desc "import SUBCOMMAND ...ARGS", "Manage imports"
174
+ subcommand "import", Fontist::ImportCLI
175
+
170
176
  desc "google SUBCOMMAND ...ARGS", "Manage Google formulas"
171
177
  subcommand "google", Fontist::GoogleCLI
172
178
 
@@ -205,10 +211,15 @@ module Fontist
205
211
  Fontist.ui.say(" #{font.name}")
206
212
 
207
213
  styles.each do |style, installed|
214
+ opts = []
215
+ opts << "manual" if formula.manual?
216
+ opts << (installed ? "installed" : "uninstalled")
217
+ msg = " #{style.type} (#{opts.join(', ')})"
218
+
208
219
  if installed
209
- Fontist.ui.success(" #{style.type} (installed)")
220
+ Fontist.ui.success(msg)
210
221
  else
211
- Fontist.ui.error(" #{style.type} (uninstalled)")
222
+ Fontist.ui.error(msg)
212
223
  end
213
224
  end
214
225
  end
@@ -72,6 +72,14 @@ module Fontist
72
72
  end
73
73
  end
74
74
 
75
+ class ManualFontError < FontError
76
+ def initialize(font, formula)
77
+ msg = "'#{font}' font is missing.\n\n#{formula.instructions}"
78
+
79
+ super(msg, font)
80
+ end
81
+ end
82
+
75
83
  class UnsupportedFontError < FontError
76
84
  def initialize(font)
77
85
  msg = <<~MSG.chomp
data/lib/fontist/font.rb CHANGED
@@ -38,21 +38,25 @@ module Fontist
38
38
  end
39
39
 
40
40
  def find
41
- find_system_font || downloadable_font || raise_non_supported_font
41
+ find_system_font || downloadable_font || manual_font ||
42
+ raise_non_supported_font
42
43
  end
43
44
 
44
45
  def install
45
- (find_system_font unless @force) || download_font || raise_non_supported_font
46
+ (find_system_font unless @force) || download_font || manual_font ||
47
+ raise_non_supported_font
46
48
  end
47
49
 
48
50
  def uninstall
49
- uninstall_font || downloadable_font || raise_non_supported_font
51
+ uninstall_font || downloadable_font || manual_font ||
52
+ raise_non_supported_font
50
53
  end
51
54
 
52
55
  def status
53
56
  return installed_paths unless @name
54
57
 
55
- find_system_font || downloadable_font || raise_non_supported_font
58
+ find_system_font || downloadable_font || manual_font ||
59
+ raise_non_supported_font
56
60
  end
57
61
 
58
62
  def list
@@ -62,7 +66,7 @@ module Fontist
62
66
  end
63
67
 
64
68
  def all
65
- Fontist::Formula.all.map(&:fonts).flatten
69
+ all_formulas.map(&:fonts).flatten
66
70
  end
67
71
 
68
72
  private
@@ -98,24 +102,37 @@ module Fontist
98
102
  FontInstaller.new(formula, no_progress: @no_progress)
99
103
  end
100
104
 
101
- def formula
102
- @formula ||= Fontist::Formula.find(name)
105
+ def downloadable_formulas
106
+ @downloadable_formulas ||= formulas.select(&:downloadable?)
107
+ end
108
+
109
+ def manual_formulas
110
+ @manual_formulas ||= formulas.reject(&:downloadable?)
103
111
  end
104
112
 
105
113
  def formulas
106
114
  @formulas ||= Fontist::Formula.find_many(name)
115
+ .select { |f| supported_formula?(f) }
107
116
  end
108
117
 
109
- def downloadable_font
110
- if formula
111
- raise Fontist::Errors::MissingFontError.new(name)
118
+ def supported_formula?(formula)
119
+ return true if formula.platforms.nil?
120
+
121
+ formula.platforms.any? do |platform|
122
+ Utils::System.match?(platform)
112
123
  end
113
124
  end
114
125
 
126
+ def downloadable_font
127
+ return if downloadable_formulas.empty?
128
+
129
+ raise Fontist::Errors::MissingFontError.new(name)
130
+ end
131
+
115
132
  def download_font
116
- return if formulas.empty?
133
+ return if downloadable_formulas.empty?
117
134
 
118
- formulas.flat_map do |formula|
135
+ downloadable_formulas.flat_map do |formula|
119
136
  confirmation = check_and_confirm_required_license(formula)
120
137
  paths = font_installer(formula).install(confirmation: confirmation)
121
138
 
@@ -165,6 +182,12 @@ module Fontist
165
182
  MSG
166
183
  end
167
184
 
185
+ def manual_font
186
+ return if manual_formulas.empty?
187
+
188
+ raise Fontist::Errors::ManualFontError.new(name, manual_formulas.first)
189
+ end
190
+
168
191
  def uninstall_font
169
192
  paths = find_fontist_paths
170
193
  return unless paths
@@ -190,7 +213,7 @@ module Fontist
190
213
  end
191
214
 
192
215
  def all_formulas
193
- Fontist::Formula.all
216
+ Fontist::Formula.all.select { |f| supported_formula?(f) }
194
217
  end
195
218
 
196
219
  def path(style)
@@ -215,7 +238,7 @@ module Fontist
215
238
 
216
239
  def list_styles(formulas)
217
240
  map_to_hash(formulas) do |formula|
218
- map_to_hash(formula.fonts) do |font|
241
+ map_to_hash(requested_fonts(formula.fonts)) do |font|
219
242
  map_to_hash(font.styles) do |style|
220
243
  installed(style)
221
244
  end
@@ -227,6 +250,14 @@ module Fontist
227
250
  elements.map { |e| [e, yield(e)] }.to_h
228
251
  end
229
252
 
253
+ def requested_fonts(fonts)
254
+ return fonts unless @name
255
+
256
+ fonts.select do |font|
257
+ font.name.casecmp?(name)
258
+ end
259
+ end
260
+
230
261
  def installed(style)
231
262
  path(style) ? true : false
232
263
  end
@@ -54,16 +54,30 @@ module Fontist
54
54
  end
55
55
 
56
56
  def download_file(source)
57
- request = source.urls.first
58
- url = request.respond_to?(:url) ? request.url : request
59
- Fontist.ui.say(%(Downloading font "#{@formula.key}" from #{url}))
57
+ errors = []
58
+ source.urls.each do |request|
59
+ url = request.respond_to?(:url) ? request.url : request
60
+ Fontist.ui.say(%(Downloading font "#{@formula.key}" from #{url}))
60
61
 
62
+ result = try_download_file(request, source)
63
+ return result unless result.is_a?(Errors::InvalidResourceError)
64
+
65
+ errors << result
66
+ end
67
+
68
+ raise Errors::InvalidResourceError, errors.join(" ")
69
+ end
70
+
71
+ def try_download_file(request, source)
61
72
  Fontist::Utils::Downloader.download(
62
73
  request,
63
74
  sha: source.sha256,
64
75
  file_size: source.file_size,
65
76
  progress_bar: !@no_progress
66
77
  )
78
+ rescue Errors::InvalidResourceError => e
79
+ Fontist.ui.say(e.message)
80
+ e
67
81
  end
68
82
 
69
83
  def font_file?(path)
@@ -59,6 +59,14 @@ module Fontist
59
59
  Indexes::IndexFormula.new(path)
60
60
  end
61
61
 
62
+ def manual?
63
+ !downloadable?
64
+ end
65
+
66
+ def downloadable?
67
+ @data.key?("resources")
68
+ end
69
+
62
70
  def path
63
71
  @path
64
72
  end
@@ -91,12 +99,20 @@ module Fontist
91
99
  @data["requires_license_agreement"] ? true : false
92
100
  end
93
101
 
102
+ def platforms
103
+ @data["platforms"]
104
+ end
105
+
94
106
  def extract
95
107
  Helpers.parse_to_object(@data["extract"])
96
108
  end
97
109
 
98
110
  def resources
99
- Helpers.parse_to_object(@data["resources"].values)
111
+ Helpers.parse_to_object(@data["resources"]&.values)
112
+ end
113
+
114
+ def instructions
115
+ @data["instructions"]
100
116
  end
101
117
 
102
118
  def fonts
@@ -1,7 +1,5 @@
1
1
  require "fontist/import"
2
2
  require_relative "recursive_extraction"
3
- require_relative "otf/font_file"
4
- require_relative "files/collection_file"
5
3
  require_relative "helpers/hash_helper"
6
4
  require_relative "formula_builder"
7
5
 
@@ -14,21 +12,29 @@ module Fontist
14
12
  end
15
13
 
16
14
  def call
17
- save(formula)
15
+ save(builder)
18
16
  end
19
17
 
20
18
  private
21
19
 
22
- def formula
20
+ def builder
23
21
  builder = FormulaBuilder.new
24
- builder.url = @url
22
+ setup_strings(builder, archive)
23
+ setup_files(builder)
24
+ builder
25
+ end
26
+
27
+ def setup_strings(builder, archive)
25
28
  builder.archive = archive
26
- builder.extractor = extractor
29
+ builder.url = @url
27
30
  builder.options = @options
31
+ end
32
+
33
+ def setup_files(builder)
34
+ builder.extractor = extractor
28
35
  builder.font_files = extractor.font_files
29
36
  builder.font_collection_files = extractor.font_collection_files
30
37
  builder.license_text = extractor.license_text
31
- builder.formula
32
38
  end
33
39
 
34
40
  def extractor
@@ -48,10 +54,10 @@ module Fontist
48
54
  Fontist::Utils::Downloader.download(url, progress_bar: true).path
49
55
  end
50
56
 
51
- def save(hash)
52
- filename = Import.name_to_filename(hash[:name])
57
+ def save(builder)
58
+ filename = Import.name_to_filename(builder.name)
53
59
  path = @options[:formula_dir] ? File.join(@options[:formula_dir], filename) : filename
54
- yaml = YAML.dump(Helpers::HashHelper.stringify_keys(hash))
60
+ yaml = YAML.dump(Helpers::HashHelper.stringify_keys(builder.formula))
55
61
  File.write(path, yaml)
56
62
  path
57
63
  end
@@ -9,11 +9,13 @@ module Fontist
9
9
  FONT_LABELS = ["OpenType font data",
10
10
  "TrueType Font data"].freeze
11
11
 
12
- COLLECTION_LABEL = "TrueType font collection data".freeze
12
+ COLLECTION_LABELS = ["OpenType font collection data",
13
+ "TrueType font collection data"].freeze
13
14
 
14
15
  FONT_EXTENSIONS = {
15
16
  "OpenType font data" => "otf",
16
17
  "TrueType Font data" => "ttf",
18
+ "OpenType font collection data" => "ttc",
17
19
  "TrueType font collection data" => "ttc",
18
20
  }.freeze
19
21
 
@@ -22,7 +24,7 @@ module Fontist
22
24
 
23
25
  if brief.start_with?(*FONT_LABELS)
24
26
  :font
25
- elsif brief.start_with?(COLLECTION_LABEL)
27
+ elsif brief.start_with?(*COLLECTION_LABELS)
26
28
  :collection
27
29
  else
28
30
  :other
@@ -4,36 +4,41 @@ require_relative "text_helper"
4
4
  module Fontist
5
5
  module Import
6
6
  class FormulaBuilder
7
- FORMULA_ATTRIBUTES = %i[name description homepage resources
7
+ FORMULA_ATTRIBUTES = %i[description homepage resources
8
8
  font_collections fonts extract copyright
9
9
  license_url open_license digest command].freeze
10
10
 
11
- attr_accessor :archive,
12
- :url,
13
- :extractor,
14
- :options,
15
- :font_files,
16
- :font_collection_files,
17
- :license_text
11
+ attr_writer :archive,
12
+ :url,
13
+ :extractor,
14
+ :options,
15
+ :font_files,
16
+ :font_collection_files,
17
+ :license_text,
18
+ :homepage
18
19
 
19
20
  def initialize
20
21
  @options = {}
21
22
  end
22
23
 
23
24
  def formula
24
- FORMULA_ATTRIBUTES.map { |name| [name, send(name)] }.to_h.compact
25
+ formula_attributes.map { |name| [name, send(name)] }.to_h.compact
25
26
  end
26
27
 
27
- private
28
-
29
28
  def name
30
- return options[:name] if options[:name]
29
+ return @options[:name] if @options[:name]
31
30
 
32
31
  unique_names = both_fonts.map(&:family_name).uniq
33
32
  TextHelper.longest_common_prefix(unique_names) ||
34
33
  both_fonts.first.family_name
35
34
  end
36
35
 
36
+ private
37
+
38
+ def formula_attributes
39
+ FORMULA_ATTRIBUTES
40
+ end
41
+
37
42
  def both_fonts
38
43
  @both_fonts ||= group_fonts
39
44
  end
@@ -50,7 +55,7 @@ module Fontist
50
55
  end
51
56
 
52
57
  def homepage
53
- both_fonts.map(&:homepage).compact.first
58
+ @options[:homepage] || both_fonts.map(&:homepage).compact.first
54
59
  end
55
60
 
56
61
  def resources
@@ -0,0 +1,148 @@
1
+ require "plist"
2
+ require "nokogiri"
3
+ require "fontist/import"
4
+ require_relative "recursive_extraction"
5
+ require_relative "helpers/hash_helper"
6
+ require_relative "manual_formula_builder"
7
+
8
+ module Fontist
9
+ module Import
10
+ class Macos
11
+ FONT_XML = "/System/Library/AssetsV2/com_apple_MobileAsset_Font6/com_apple_MobileAsset_Font6.xml".freeze # rubocop:disable Layout/LineLength
12
+ DESCRIPTION = "Fonts included with macOS %<name>s".freeze
13
+
14
+ INSTRUCTIONS = <<~INSTRUCTIONS.freeze
15
+ To download and enable any of these fonts:
16
+
17
+ 1. Open Font Book, which is in your Applications folder.
18
+ 2. Select All Fonts in the sidebar, or use the Search field to find the font that you want to download. Fonts that are not already downloaded appear dimmed in the list of fonts.
19
+ 3. Select the dimmed font and choose Edit > Download, or Control-click it and choose Download from the pop-up menu.
20
+ INSTRUCTIONS
21
+
22
+ def initialize(options = {})
23
+ @options = options
24
+ end
25
+
26
+ def call
27
+ downloadable_fonts = fetch_fonts_list
28
+ links = fetch_links(downloadable_fonts)
29
+ archives = download(links)
30
+ store_in_dir(archives) do |dir|
31
+ create_formula(dir)
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def fetch_fonts_list
38
+ html = Net::HTTP.get(URI.parse(@options[:fonts_link]))
39
+
40
+ document = Nokogiri::HTML.parse(html)
41
+ document.css("#sections div.grid2col:nth-of-type(3) div ul > li",
42
+ "#sections div.grid2col:nth-of-type(4) div ul > li")
43
+ .map(&:text)
44
+ end
45
+
46
+ def fetch_links(downloadable_fonts)
47
+ data = Plist.parse_xml(FONT_XML)
48
+ assets = downloadable_assets(data, downloadable_fonts)
49
+ assets_links(assets)
50
+ end
51
+
52
+ def downloadable_assets(data, downloadable_fonts)
53
+ data["Assets"].select do |x|
54
+ x["FontInfo4"].any? do |i|
55
+ downloadable_fonts.find do |d|
56
+ d.start_with?(i["FontFamilyName"])
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ def assets_links(assets)
63
+ assets.map do |x|
64
+ x.values_at("__BaseURL", "__RelativePath").join
65
+ end
66
+ end
67
+
68
+ def download(links)
69
+ links.map do |url|
70
+ Fontist::Utils::Downloader.download(url, progress_bar: true).path
71
+ end
72
+ end
73
+
74
+ def store_in_dir(archives)
75
+ Dir.mktmpdir do |dir|
76
+ archives.each do |archive|
77
+ FileUtils.ln(archive, dir)
78
+ end
79
+
80
+ yield dir
81
+ end
82
+ end
83
+
84
+ def create_formula(archives_dir)
85
+ extractor = RecursiveExtraction.new(archives_dir)
86
+ path = save(formula(archives_dir, extractor))
87
+ Fontist.ui.success("Formula has been successfully created: #{path}")
88
+
89
+ path
90
+ end
91
+
92
+ def formula(archive, extractor)
93
+ builder = ManualFormulaBuilder.new
94
+ setup_strings(builder, archive)
95
+ setup_files(builder, extractor)
96
+ builder.formula
97
+ end
98
+
99
+ def setup_strings(builder, archive)
100
+ builder.url = archive
101
+ builder.archive = archive
102
+ builder.platforms = platforms
103
+ builder.instructions = instructions
104
+ builder.description = description
105
+ builder.options = builder_options
106
+ end
107
+
108
+ def platforms
109
+ major_version = Sys::Uname.release.split(".").first
110
+
111
+ ["macos-#{major_version}"]
112
+ end
113
+
114
+ def instructions
115
+ INSTRUCTIONS.strip
116
+ end
117
+
118
+ def description
119
+ format(DESCRIPTION, name: @options[:name])
120
+ end
121
+
122
+ def builder_options
123
+ @options.merge(homepage: @options[:fonts_link])
124
+ end
125
+
126
+ def setup_files(builder, extractor)
127
+ builder.extractor = extractor
128
+ builder.font_files = extractor.font_files
129
+ builder.font_collection_files = extractor.font_collection_files
130
+ builder.license_text = extractor.license_text
131
+ end
132
+
133
+ def save(hash)
134
+ filename = Import.name_to_filename(@options[:name])
135
+ path = File.join(formula_dir, filename)
136
+ yaml = YAML.dump(Helpers::HashHelper.stringify_keys(hash))
137
+ File.write(path, yaml)
138
+ path
139
+ end
140
+
141
+ def formula_dir
142
+ @formula_dir ||= Fontist.formulas_path.join("macos").tap do |path|
143
+ FileUtils.mkdir_p(path) unless File.exist?(path)
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,24 @@
1
+ require_relative "formula_builder"
2
+
3
+ module Fontist
4
+ module Import
5
+ class ManualFormulaBuilder < FormulaBuilder
6
+ attr_accessor :description,
7
+ :platforms,
8
+ :instructions
9
+
10
+ private
11
+
12
+ def formula_attributes
13
+ @formula_attributes ||= super.dup.tap do |attrs|
14
+ attrs.delete(:resources)
15
+ attrs.delete(:open_license)
16
+ attrs.delete(:license_url)
17
+ attrs.delete(:copyright)
18
+
19
+ attrs.insert(attrs.index(:homepage) + 1, :platforms, :instructions)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,3 +1,5 @@
1
+ require_relative "otf/font_file"
2
+ require_relative "files/collection_file"
1
3
  require_relative "files/font_detector"
2
4
 
3
5
  module Fontist
@@ -0,0 +1,19 @@
1
+ module Fontist
2
+ class ImportCLI < Thor
3
+ desc "macos", "Create formula for on-demand macOS fonts"
4
+ option :name, desc: "Example: Big Sur", required: true
5
+ option :fonts_link,
6
+ desc: "A link to a list of available fonts in a current OS",
7
+ required: true
8
+ option :formulas_path, type: :string, desc: "Path to formulas"
9
+ def macos
10
+ if options[:formulas_path]
11
+ Fontist.formulas_path = Pathname.new(options[:formulas_path])
12
+ end
13
+
14
+ require_relative "import/macos"
15
+ Import::Macos.new(options).call
16
+ CLI::STATUS_SUCCESS
17
+ end
18
+ end
19
+ end
data/lib/fontist/repo.rb CHANGED
@@ -15,8 +15,20 @@ module Fontist
15
15
  raise(Errors::RepoNotFoundError, "No such repo '#{name}'.")
16
16
  end
17
17
 
18
- Git.open(path).pull
18
+ git = Git.open(path)
19
+ git.pull("origin", git.current_branch)
20
+
19
21
  Index.rebuild
22
+ rescue Git::GitExecuteError => e
23
+ raise Errors::RepoCouldNotBeUpdatedError.new(<<~MSG.chomp)
24
+ Formulas repo '#{name}' could not be updated.
25
+ Please consider reinitializing it with:
26
+ fontist remove #{name}
27
+ fontist setup #{name} REPO_URL
28
+
29
+ Git error:
30
+ #{e.message}
31
+ MSG
20
32
  end
21
33
 
22
34
  def remove(name)
@@ -14,6 +14,7 @@ system:
14
14
  - /System/Library/Fonts/**/**.{ttf,ttc}
15
15
  - /Users/{username}/Library/Fonts/**.{ttf,ttc}
16
16
  - /Applications/Microsoft**/Contents/Resources/**/**.{ttf,ttc}
17
+ - /System/Library/AssetsV2/com_apple_MobileAsset_Font6/**/**.{ttf,ttc}
17
18
 
18
19
  unix:
19
20
  paths:
@@ -21,7 +21,7 @@ module Fontist
21
21
  templates = YAML.load_file(config_path)["system"][os]["paths"]
22
22
  patterns = expand_paths(templates)
23
23
 
24
- Dir.glob(patterns)
24
+ Dir.glob(patterns, File::FNM_CASEFOLD)
25
25
  end
26
26
 
27
27
  def self.reset_system_font_paths_cache
@@ -1,9 +1,7 @@
1
1
  module Fontist
2
2
  class Update
3
- VERSION = "v2".freeze
4
-
5
3
  def self.call
6
- new(VERSION).call
4
+ new(Fontist.formulas_version).call
7
5
  end
8
6
 
9
7
  def initialize(branch = "main")
@@ -30,7 +28,14 @@ module Fontist
30
28
  depth: 1)
31
29
  end
32
30
 
33
- git = Git.open(Fontist.formulas_repo_path)
31
+ git = if Dir.exist?(Fontist.formulas_repo_path.join(".git"))
32
+ Git.open(Fontist.formulas_repo_path)
33
+ else
34
+ Git.init(Fontist.formulas_repo_path.to_s).tap do |g|
35
+ g.add_remote("origin", Fontist.formulas_repo_url)
36
+ end
37
+ end
38
+
34
39
  return git.pull("origin", @branch) if git.current_branch == @branch
35
40
 
36
41
  git.config("remote.origin.fetch",
@@ -41,36 +46,11 @@ module Fontist
41
46
  end
42
47
 
43
48
  def update_private_repos
44
- private_repos.each do |path|
45
- update_repo(path)
46
- end
47
- end
48
-
49
- def update_repo(path)
50
- Git.open(path).pull
51
- rescue Git::GitExecuteError => e
52
- name = repo_name(path)
53
- raise Errors::RepoCouldNotBeUpdatedError.new(<<~MSG.chomp)
54
- Formulas repo '#{name}' could not be updated.
55
- Please consider reinitializing it with:
56
- fontist remove #{name}
57
- fontist setup #{name} REPO_URL
58
-
59
- Git error:
60
- #{e.message}
61
- MSG
62
- end
63
-
64
- def private_repos
65
- Dir.glob(Fontist.private_formulas_path.join("*")).select do |path|
66
- File.directory?(path)
49
+ Repo.list.each do |name|
50
+ Repo.update(name)
67
51
  end
68
52
  end
69
53
 
70
- def repo_name(path)
71
- File.basename(path)
72
- end
73
-
74
54
  def rebuild_index
75
55
  Index.rebuild
76
56
  end
@@ -15,7 +15,7 @@ module Fontist
15
15
  @file = file
16
16
  @sha = [sha].flatten.compact
17
17
  @file_size = file_size.to_i if file_size
18
- @progress_bar = set_progress_bar(progress_bar)
18
+ @progress_bar = progress_bar
19
19
  @cache = Cache.new
20
20
  end
21
21
 
@@ -54,35 +54,48 @@ module Fontist
54
54
  options[:download_path] || Fontist.root_path.join("tmp")
55
55
  end
56
56
 
57
- def set_progress_bar(progress_bar)
58
- if progress_bar
57
+ def download_file
58
+ tries = tries ? tries + 1 : 1
59
+ do_download_file
60
+ rescue Down::Error => e
61
+ retry if tries < 3
62
+
63
+ raise Fontist::Errors::InvalidResourceError,
64
+ "Invalid URL: #{@file}. Error: #{e.inspect}."
65
+ end
66
+
67
+ def do_download_file
68
+ progress_bar = create_progress_bar
69
+ file = do_download_file_with_progress_bar(progress_bar)
70
+ progress_bar.finish
71
+ file
72
+ end
73
+
74
+ def create_progress_bar
75
+ if @progress_bar
59
76
  ProgressBar.new(@file_size)
60
77
  else
61
78
  NullProgressBar.new(@file_size)
62
79
  end
63
80
  end
64
81
 
65
- def download_file
66
- file = Down.download(
82
+ # rubocop:disable Metrics/MethodLength
83
+ def do_download_file_with_progress_bar(progress_bar)
84
+ Down.download(
67
85
  url,
68
86
  open_timeout: 10,
69
87
  read_timeout: 10,
70
88
  max_redirects: 10,
71
89
  headers: headers,
72
90
  content_length_proc: ->(content_length) {
73
- @progress_bar.total = content_length if content_length
91
+ progress_bar.total = content_length if content_length
74
92
  },
75
93
  progress_proc: -> (progress) {
76
- @progress_bar.increment(progress)
94
+ progress_bar.increment(progress)
77
95
  }
78
96
  )
79
-
80
- @progress_bar.finish
81
-
82
- file
83
- rescue Down::NotFound
84
- raise(Fontist::Errors::InvalidResourceError.new("Invalid URL: #{@file}"))
85
97
  end
98
+ # rubocop:enable Metrics/MethodLength
86
99
 
87
100
  def url
88
101
  @file.respond_to?(:url) ? @file.url : @file
@@ -1,3 +1,5 @@
1
+ require "sys/uname"
2
+
1
3
  module Fontist
2
4
  module Utils
3
5
  module System
@@ -18,6 +20,14 @@ module Fontist
18
20
  end
19
21
  end
20
22
  end
23
+
24
+ def self.user_os_with_version
25
+ "#{user_os}-#{Sys::Uname.release}"
26
+ end
27
+
28
+ def self.match?(platform)
29
+ user_os_with_version.start_with?(platform)
30
+ end
21
31
  end
22
32
  end
23
33
  end
@@ -1,3 +1,3 @@
1
1
  module Fontist
2
- VERSION = "1.11.3".freeze
2
+ VERSION = "1.12.0".freeze
3
3
  end
data/lib/fontist.rb CHANGED
@@ -44,7 +44,11 @@ module Fontist
44
44
  end
45
45
 
46
46
  def self.fontist_version_path
47
- Fontist.fontist_path.join("versions", Update::VERSION)
47
+ Fontist.fontist_path.join("versions", formulas_version)
48
+ end
49
+
50
+ def self.formulas_version
51
+ "v3"
48
52
  end
49
53
 
50
54
  def self.formulas_repo_url
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fontist
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.11.3
4
+ version: 1.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-17 00:00:00.000000000 Z
11
+ date: 2021-11-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: down
@@ -38,6 +38,34 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: sys-uname
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.2'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.2'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: thor
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +108,20 @@ dependencies:
80
108
  - - "~>"
81
109
  - !ruby/object:Gem::Version
82
110
  version: '1.6'
111
+ - !ruby/object:Gem::Dependency
112
+ name: plist
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '3.0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '3.0'
83
125
  - !ruby/object:Gem::Dependency
84
126
  name: excavate
85
127
  requirement: !ruby/object:Gem::Requirement
@@ -136,20 +178,6 @@ dependencies:
136
178
  - - ">="
137
179
  - !ruby/object:Gem::Version
138
180
  version: '0'
139
- - !ruby/object:Gem::Dependency
140
- name: nokogiri
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - "~>"
144
- - !ruby/object:Gem::Version
145
- version: '1.0'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - "~>"
151
- - !ruby/object:Gem::Version
152
- version: '1.0'
153
181
  - !ruby/object:Gem::Dependency
154
182
  name: rake
155
183
  requirement: !ruby/object:Gem::Requirement
@@ -293,6 +321,8 @@ files:
293
321
  - lib/fontist/import/google_import.rb
294
322
  - lib/fontist/import/helpers/hash_helper.rb
295
323
  - lib/fontist/import/helpers/system_helper.rb
324
+ - lib/fontist/import/macos.rb
325
+ - lib/fontist/import/manual_formula_builder.rb
296
326
  - lib/fontist/import/otf/font_file.rb
297
327
  - lib/fontist/import/otf_parser.rb
298
328
  - lib/fontist/import/otf_style.rb
@@ -303,6 +333,7 @@ files:
303
333
  - lib/fontist/import/sil_import.rb
304
334
  - lib/fontist/import/template_helper.rb
305
335
  - lib/fontist/import/text_helper.rb
336
+ - lib/fontist/import_cli.rb
306
337
  - lib/fontist/index.rb
307
338
  - lib/fontist/indexes/base_index.rb
308
339
  - lib/fontist/indexes/default_family_font_index.rb