fontist 1.17.1 → 1.18.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 91726c53a66563f2b0a32417d45d246617b85586cc7c9573b24c5b83533c5444
4
- data.tar.gz: de8e1aba5de04fb720c85a6c98e708dcbae944bf439c15f4dc29c3f27e4d0831
3
+ metadata.gz: 7df8791fd4754d729546380e67e6c29866f12e4d85bb917b427284c1be610dff
4
+ data.tar.gz: be7991cacf763d3abc89aeea2841d02b4cc58b7e3a24c99551ee48639b07a3f8
5
5
  SHA512:
6
- metadata.gz: d05de7120339d223fc716ad1f99a60c80ec54deb37bbe77692cff0295d3ccc4b7263ae5bc2ed2beae3dc82f18f0684d85b47f01ca4c5730e04ec4cb82357be2c
7
- data.tar.gz: 381a74039161a1e9d5ea9b560afbc9c551083c67462002f9c590da83fe69283fd8d0506983554c19d9f0ded9fba33a3b71a5d7db11a82d3689ebd7b885a9cfc2
6
+ metadata.gz: 5ec6f6dfa9169caddd99e3641d05864d49bb1bfa2f59ae4887dd72b703c18c599628711fa5f414cb5863832f14751fddc7536cea549358eebbb926231eaf7651
7
+ data.tar.gz: a87e924b0741861b59114ae75ea93a09ba86eb43510787501f20980a488ec3a181bba20ea0307e6b7f51f83d989c0edaf7db7ea1c74680534eec3280dc1a8d47
@@ -45,6 +45,7 @@ jobs:
45
45
  bundler-cache: true
46
46
 
47
47
  - if: matrix.os == 'macos-latest'
48
+ name: Run tests including dev ones
48
49
  run: |
49
50
  brew install lcdf-typetools
50
51
  bundle exec rspec
data/README.adoc CHANGED
@@ -78,6 +78,9 @@ NOTE: See <<preferred-family-change>> for the differences between
78
78
  `-v, --verbose`:: Set the log level to debug. It prints formulas excluded
79
79
  during installation and information for developers of fontist.
80
80
 
81
+ `-c, --no-cache`:: Prefer direct download even when a file is already cached in
82
+ a system.
83
+
81
84
  === Install fonts: `fontist install`
82
85
 
83
86
  Fontist checks whether this font is already installed, and if not, then installs
@@ -299,6 +302,39 @@ Roboto Mono:
299
302
  - "/Users/user/.fontist/fonts/RobotoMono-VariableFont_wght.ttf"
300
303
  ----
301
304
 
305
+ === Work with fontist config: `fontist config`
306
+
307
+ Fontist supports system-wide settings for the following parameters:
308
+
309
+ `open_timeout`:: Sets timeout for opening a connection during download
310
+ (default: 10)
311
+
312
+ `read_timeout`:: Sets timeout for reading the opened connection during download
313
+ (default: 10)
314
+
315
+ Show current attributes in the config:
316
+
317
+ [source,sh]
318
+ ----
319
+ $ fontist config show
320
+ Current config:
321
+ read_timeout: 5
322
+ ----
323
+
324
+ Assign a value to an attribute:
325
+
326
+ [source,sh]
327
+ ----
328
+ $ fontist config set read_timeout 60
329
+ ----
330
+
331
+ Restore a default value of an attribute:
332
+
333
+ [source,sh]
334
+ ----
335
+ $ fontist config delete read_timeout
336
+ ----
337
+
302
338
  === Work with Fontconfig: `fontist fontconfig`
303
339
 
304
340
  Fontconfig is a software designed to provide fonts to other programs. It is
@@ -621,6 +657,15 @@ Apple Support site:
621
657
  WARNING: Fontist does not allow installing macOS-specific fonts on non-macOS
622
658
  platforms due to font license restrictions of those fonts.
623
659
 
660
+ === Known problematic fonts
661
+
662
+ * NISC18030.ttf (GB18030 Bitmap) - macOS, more info in
663
+ https://github.com/fontist/fontist/issues/344[the NISC18030 issue]
664
+
665
+ The full list of known problematic fonts:
666
+
667
+ * https://github.com/fontist/fontist/blob/main/lib/fontist/exclude.yml[List of fonts excluded from usage]
668
+
624
669
 
625
670
  == Advanced usage
626
671
 
@@ -826,7 +871,7 @@ For file paths, specify the file path as argument:
826
871
 
827
872
  [source,sh]
828
873
  ----
829
- wget https://www.latofonts.com/download/lato2ofl-zip/
874
+ wget https://www.latofonts.com/files/Lato2OFL.zip
830
875
  fontist create-formula lato.zip
831
876
  ----
832
877
 
@@ -834,7 +879,7 @@ For URLs, simply specify the URL as the argument:
834
879
 
835
880
  [source,sh]
836
881
  ----
837
- fontist create-formula https://www.latofonts.com/download/lato2ofl-zip/
882
+ fontist create-formula https://www.latofonts.com/files/Lato2OFL.zip
838
883
  # > file created at lato.yml because the file downloaded is lato.zip
839
884
  ----
840
885
 
@@ -843,7 +888,7 @@ private formula repository location.
843
888
 
844
889
  [source,sh]
845
890
  ----
846
- fontist create-formula https://www.latofonts.com/download/lato2ofl-zip/
891
+ fontist create-formula https://www.latofonts.com/files/Lato2OFL.zip
847
892
  cp lato.yml ~/.fontist/formulas/Formulas/
848
893
  ----
849
894
 
data/fontist.gemspec CHANGED
@@ -31,6 +31,7 @@ Gem::Specification.new do |spec|
31
31
 
32
32
  spec.add_runtime_dependency "down", "~> 5.0"
33
33
  spec.add_runtime_dependency "extract_ttc", "~> 0.1"
34
+ spec.add_runtime_dependency "json", "~> 2.0"
34
35
  spec.add_runtime_dependency "nokogiri", "~> 1.0"
35
36
  spec.add_runtime_dependency "mime-types", "~> 3.0"
36
37
  spec.add_runtime_dependency "sys-uname", "~> 1.2"
@@ -1,9 +1,37 @@
1
1
  module Fontist
2
2
  class CLI < Thor
3
3
  module ClassOptions
4
+ # rubocop:disable Metrics/MethodLength
5
+ def self.included(base)
6
+ base.class_option :preferred_family,
7
+ type: :boolean,
8
+ desc: "Use Preferred Family when available"
9
+
10
+ base.class_option :quiet,
11
+ aliases: :q,
12
+ type: :boolean,
13
+ desc: "Hide all messages"
14
+
15
+ base.class_option :verbose,
16
+ aliases: :v,
17
+ type: :boolean,
18
+ desc: "Print debug messages"
19
+
20
+ base.class_option :no_cache,
21
+ aliases: :c,
22
+ type: :boolean,
23
+ desc: "Avoid using cache during download"
24
+
25
+ base.class_option :formulas_path,
26
+ type: :string,
27
+ desc: "Path to formulas"
28
+ end
29
+ # rubocop:enable Metrics/MethodLength
30
+
4
31
  def handle_class_options(options)
5
32
  Fontist.preferred_family = options[:preferred_family]
6
33
  Fontist.log_level = log_level(options)
34
+ Fontist.use_cache = !options[:no_cache]
7
35
 
8
36
  if options[:formulas_path]
9
37
  Fontist.formulas_path = Pathname.new(options[:formulas_path])
data/lib/fontist/cli.rb CHANGED
@@ -4,6 +4,7 @@ require "fontist/repo_cli"
4
4
  require "fontist/cache_cli"
5
5
  require "fontist/import_cli"
6
6
  require "fontist/fontconfig_cli"
7
+ require "fontist/config_cli"
7
8
 
8
9
  module Fontist
9
10
  class CLI < Thor
@@ -58,22 +59,6 @@ module Fontist
58
59
  false
59
60
  end
60
61
 
61
- class_option :preferred_family,
62
- type: :boolean,
63
- desc: "Use Preferred Family when available"
64
-
65
- class_option :quiet,
66
- aliases: :q,
67
- type: :boolean,
68
- desc: "Hide all messages"
69
-
70
- class_option :verbose,
71
- aliases: :v,
72
- type: :boolean,
73
- desc: "Print debug messages"
74
-
75
- class_option :formulas_path, type: :string, desc: "Path to formulas"
76
-
77
62
  desc "install FONT", "Install font"
78
63
  option :force, type: :boolean, aliases: :f,
79
64
  desc: "Install even if already installed in system"
@@ -221,6 +206,9 @@ module Fontist
221
206
  desc "fontconfig SUBCOMMAND ...ARGS", "Manage fontconfig"
222
207
  subcommand "fontconfig", Fontist::FontconfigCLI
223
208
 
209
+ desc "config SUBCOMMAND ...ARGS", "Manage fontist config"
210
+ subcommand "config", Fontist::ConfigCLI
211
+
224
212
  desc "cache SUBCOMMAND ...ARGS", "Manage fontist cache"
225
213
  subcommand "cache", Fontist::CacheCLI
226
214
 
@@ -0,0 +1,62 @@
1
+ module Fontist
2
+ class Config
3
+ include Singleton
4
+
5
+ def initialize
6
+ @custom_values = load_config_file
7
+ end
8
+
9
+ def values
10
+ default_values.merge(@custom_values)
11
+ end
12
+
13
+ def custom_values
14
+ @custom_values
15
+ end
16
+
17
+ def set(key, value)
18
+ v = normalize_value(value)
19
+ @custom_values[key.to_s] = v
20
+
21
+ persist
22
+ end
23
+
24
+ def delete(key)
25
+ @custom_values.delete(key.to_s)
26
+
27
+ persist
28
+ end
29
+
30
+ def default_value(key)
31
+ default_values[key.to_s]
32
+ end
33
+
34
+ def default_values
35
+ { open_timeout: 10,
36
+ read_timeout: 10 }.transform_keys(&:to_s)
37
+ end
38
+
39
+ def persist
40
+ FileUtils.mkdir_p(File.dirname(Fontist.config_path))
41
+ File.write(Fontist.config_path, YAML.dump(@custom_values))
42
+ end
43
+
44
+ def load
45
+ @custom_values = load_config_file
46
+ end
47
+
48
+ private
49
+
50
+ def load_config_file
51
+ return {} unless File.exist?(Fontist.config_path)
52
+
53
+ YAML.load_file(Fontist.config_path)
54
+ end
55
+
56
+ def normalize_value(value)
57
+ return value.to_i if value.to_i.to_s == value # detect integer
58
+
59
+ value
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,40 @@
1
+ module Fontist
2
+ class ConfigCLI < Thor
3
+ include CLI::ClassOptions
4
+
5
+ STATUS_SUCCESS = 0
6
+
7
+ desc "show", "Show values of the current config"
8
+ def show
9
+ handle_class_options(options)
10
+ values = Config.instance.custom_values
11
+ Fontist.ui.success("Current config:")
12
+ Fontist.ui.success(format_hash(values))
13
+ STATUS_SUCCESS
14
+ end
15
+
16
+ desc "set KEY VALUE", "Set the KEY attribute to VALUE in the current config"
17
+ def set(key, value)
18
+ handle_class_options(options)
19
+ Config.instance.set(key, value)
20
+ Fontist.ui.success("'#{key}' set to '#{value}'.")
21
+ STATUS_SUCCESS
22
+ end
23
+
24
+ desc "delete KEY", "Delete the KEY attribute from the current config"
25
+ def delete(key)
26
+ handle_class_options(options)
27
+ Config.instance.delete(key)
28
+ Fontist.ui.success(
29
+ "'#{key}' reset to default ('#{Config.instance.default_value(key)}').",
30
+ )
31
+ STATUS_SUCCESS
32
+ end
33
+
34
+ private
35
+
36
+ def format_hash(hash)
37
+ YAML.dump(hash).gsub(/^---.*$/, "").strip
38
+ end
39
+ end
40
+ end
@@ -0,0 +1 @@
1
+ - NISC18030.ttf
@@ -9,8 +9,9 @@ module Fontist
9
9
  REPO_URL = "https://github.com/google/fonts.git".freeze
10
10
  SKIPLIST_PATH = File.expand_path("skiplist.yml", __dir__)
11
11
 
12
- def initialize(logging: false)
12
+ def initialize(logging: false, limit: nil)
13
13
  @logging = logging
14
+ @limit = limit
14
15
  end
15
16
 
16
17
  def call
@@ -30,11 +31,20 @@ module Fontist
30
31
  end
31
32
 
32
33
  def fetch_new_paths
33
- fetch_fonts_paths.select do |path|
34
- log_font(path) do
34
+ new_paths = []
35
+
36
+ fetch_fonts_paths.each do |path|
37
+ new = log_font(path) do
35
38
  new?(path)
36
39
  end
40
+
41
+ next unless new
42
+
43
+ new_paths << path
44
+ return new_paths if @limit && new_paths.size >= @limit
37
45
  end
46
+
47
+ new_paths
38
48
  end
39
49
 
40
50
  def fetch_fonts_paths
@@ -1,6 +1,8 @@
1
1
  module Fontist
2
2
  module Import
3
3
  module Google
4
+ DEFAULT_MAX_COUNT = 100
5
+
4
6
  def self.metadata_name(path)
5
7
  metadata_path = File.join(path, "METADATA.pb")
6
8
  return unless File.exist?(metadata_path)
@@ -6,16 +6,21 @@ require_relative "create_formula"
6
6
  module Fontist
7
7
  module Import
8
8
  class GoogleImport
9
+ def initialize(options)
10
+ @max_count = options[:max_count] || Google::DEFAULT_MAX_COUNT
11
+ end
12
+
9
13
  def call
10
14
  fonts = new_fonts
11
15
  create_formulas(fonts)
12
- rebuild_index
16
+ rebuild_index unless fonts.empty?
13
17
  end
14
18
 
15
19
  private
16
20
 
17
21
  def new_fonts
18
- Fontist::Import::Google::NewFontsFetcher.new(logging: true).call
22
+ Fontist::Import::Google::NewFontsFetcher.new(logging: true,
23
+ limit: @max_count).call
19
24
  end
20
25
 
21
26
  def create_formulas(fonts)
@@ -8,6 +8,10 @@ module Fontist
8
8
  FONT_XML = "/System/Library/AssetsV2/com_apple_MobileAsset_Font6/com_apple_MobileAsset_Font6.xml".freeze # rubocop:disable Layout/LineLength
9
9
  HOMEPAGE = "https://support.apple.com/en-om/HT211240#document".freeze
10
10
 
11
+ def initialize(font_xml = FONT_XML)
12
+ @font_xml = font_xml
13
+ end
14
+
11
15
  def call
12
16
  links.each do |link|
13
17
  create_formula(link)
@@ -21,7 +25,7 @@ module Fontist
21
25
  private
22
26
 
23
27
  def links
24
- data = Plist.parse_xml(FONT_XML)
28
+ data = Plist.parse_xml(@font_xml)
25
29
  data["Assets"].map do |x|
26
30
  x.values_at("__BaseURL", "__RelativePath").join
27
31
  end
@@ -1,12 +1,19 @@
1
+ require_relative "import/google"
2
+
1
3
  module Fontist
2
4
  class ImportCLI < Thor
3
5
  include CLI::ClassOptions
4
6
 
5
7
  desc "google", "Import Google fonts"
8
+ option :max_count,
9
+ type: :numeric, aliases: :n,
10
+ desc: "Limit the number of formulas to import " \
11
+ "(default is #{Fontist::Import::Google::DEFAULT_MAX_COUNT})."
12
+
6
13
  def google
7
14
  handle_class_options(options)
8
15
  require "fontist/import/google_import"
9
- Fontist::Import::GoogleImport.new.call
16
+ Fontist::Import::GoogleImport.new(options).call
10
17
  CLI::STATUS_SUCCESS
11
18
  end
12
19
 
@@ -16,9 +16,8 @@ module Fontist
16
16
  end
17
17
 
18
18
  def self.load_system_font_paths
19
- config_path = Fontist.system_file_path
20
19
  os = Fontist::Utils::System.user_os.to_s
21
- templates = YAML.load_file(config_path)["system"][os]["paths"]
20
+ templates = system_config["system"][os]["paths"]
22
21
  patterns = expand_paths(templates)
23
22
 
24
23
  Dir.glob(patterns)
@@ -26,6 +25,10 @@ module Fontist
26
25
  # "Case sensitivity depends on your system"
27
26
  end
28
27
 
28
+ def self.system_config
29
+ YAML.load_file(Fontist.system_file_path)
30
+ end
31
+
29
32
  def self.reset_system_font_paths_cache
30
33
  @system_font_paths = nil
31
34
  end
@@ -66,6 +66,10 @@ module Fontist
66
66
  Fontist.preferred_family? ? PreferredFamily.new : DefaultFamily.new
67
67
  end
68
68
 
69
+ def excluded_fonts
70
+ @excluded_fonts ||= YAML.load_file(Fontist.excluded_fonts_path)
71
+ end
72
+
69
73
  def initialize(index_path, font_paths_fetcher, family)
70
74
  @index_path = index_path
71
75
  @font_paths_fetcher = font_paths_fetcher
@@ -154,16 +158,26 @@ module Fontist
154
158
  end
155
159
 
156
160
  def detect_fonts(path)
161
+ return if excluded?(path)
162
+
163
+ gather_fonts(path)
164
+ rescue Errors::FontFileError => e
165
+ print_recognition_error(e, path)
166
+ end
167
+
168
+ def excluded?(path)
169
+ excluded_fonts.include?(File.basename(path))
170
+ end
171
+
172
+ def gather_fonts(path)
157
173
  case File.extname(path).gsub(/^\./, "").downcase
158
174
  when "ttf", "otf"
159
175
  detect_file_font(path)
160
176
  when "ttc"
161
177
  detect_collection_fonts(path)
162
178
  else
163
- raise Errors::UnknownFontTypeError.new(path)
179
+ print_recognition_error(Errors::UnknownFontTypeError.new(path), path)
164
180
  end
165
- rescue Errors::FontFileError => e
166
- print_recognition_error(e, path)
167
181
  end
168
182
 
169
183
  def print_recognition_error(exception, path)
@@ -9,7 +9,7 @@ module Fontist
9
9
 
10
10
  def fetch(key)
11
11
  map = load_cache
12
- if cache_exist?(map[key])
12
+ if Fontist.use_cache? && cache_exist?(map[key])
13
13
  print(map[key])
14
14
 
15
15
  return downloaded_file(map[key])
@@ -80,8 +80,8 @@ module Fontist
80
80
  def do_download_file_with_progress_bar(progress_bar)
81
81
  Down.download(
82
82
  url,
83
- open_timeout: 10,
84
- read_timeout: 10,
83
+ open_timeout: Fontist.open_timeout,
84
+ read_timeout: Fontist.read_timeout,
85
85
  max_redirects: 10,
86
86
  headers: headers,
87
87
  content_length_proc: ->(content_length) {
@@ -0,0 +1,35 @@
1
+ module Fontist
2
+ module Utils
3
+ class FileMagic
4
+ MAP_MAGIC_TO_TYPE = {
5
+ "\x00\x01\x00\x00\x00" => :ttf,
6
+ "\x4f\x54\x54\x4f" => :otf,
7
+ "\x74\x74\x63\x66" => :ttc,
8
+ }.freeze
9
+
10
+ def self.detect(path)
11
+ new(path).detect
12
+ end
13
+
14
+ def self.max_magic
15
+ @max_magic ||= MAP_MAGIC_TO_TYPE.keys.map(&:bytesize).max
16
+ end
17
+
18
+ def initialize(path)
19
+ @path = path
20
+ end
21
+
22
+ def detect
23
+ beginning = File.binread(@path, self.class.max_magic)
24
+
25
+ MAP_MAGIC_TO_TYPE.each do |magic, type|
26
+ slice = beginning.byteslice(0, magic.bytesize)
27
+
28
+ return type if slice == magic
29
+ end
30
+
31
+ nil
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,3 +1,3 @@
1
1
  module Fontist
2
- VERSION = "1.17.1".freeze
2
+ VERSION = "1.18.2".freeze
3
3
  end
data/lib/fontist.rb CHANGED
@@ -13,6 +13,7 @@ require "fontist/formula"
13
13
  require "fontist/system_font"
14
14
  require "fontist/manifest"
15
15
  require "fontist/helpers"
16
+ require "fontist/config"
16
17
 
17
18
  module Fontist
18
19
  def self.ui
@@ -75,6 +76,10 @@ module Fontist
75
76
  Fontist.lib_path.join("fontist", "system.yml")
76
77
  end
77
78
 
79
+ def self.excluded_fonts_path
80
+ Fontist.lib_path.join("fontist", "exclude.yml")
81
+ end
82
+
78
83
  def self.system_index_path
79
84
  Fontist.fontist_path.join("system_index.default_family.yml")
80
85
  end
@@ -119,6 +124,30 @@ module Fontist
119
124
  @preferred_family = bool
120
125
  end
121
126
 
127
+ def self.open_timeout
128
+ config[:open_timeout]
129
+ end
130
+
131
+ def self.read_timeout
132
+ config[:read_timeout]
133
+ end
134
+
135
+ def self.config
136
+ Fontist::Config.instance.values
137
+ end
138
+
139
+ def self.config_path
140
+ Fontist.fontist_path.join("config.yml")
141
+ end
142
+
143
+ def self.use_cache?
144
+ instance_variable_defined?("@use_cache") ? @use_cache : true
145
+ end
146
+
147
+ def self.use_cache=(bool)
148
+ @use_cache = bool
149
+ end
150
+
122
151
  def self.log_level=(level)
123
152
  Fontist.ui.level = level
124
153
  end
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.17.1
4
+ version: 1.18.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-09-11 00:00:00.000000000 Z
11
+ date: 2024-01-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: down
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: nokogiri
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -306,7 +320,10 @@ files:
306
320
  - lib/fontist/cli.rb
307
321
  - lib/fontist/cli/class_options.rb
308
322
  - lib/fontist/collection_file.rb
323
+ - lib/fontist/config.rb
324
+ - lib/fontist/config_cli.rb
309
325
  - lib/fontist/errors.rb
326
+ - lib/fontist/exclude.yml
310
327
  - lib/fontist/font.rb
311
328
  - lib/fontist/font_file.rb
312
329
  - lib/fontist/font_installer.rb
@@ -365,6 +382,7 @@ files:
365
382
  - lib/fontist/utils.rb
366
383
  - lib/fontist/utils/cache.rb
367
384
  - lib/fontist/utils/downloader.rb
385
+ - lib/fontist/utils/file_magic.rb
368
386
  - lib/fontist/utils/locking.rb
369
387
  - lib/fontist/utils/system.rb
370
388
  - lib/fontist/utils/ui.rb