fontist 1.17.1 → 1.18.2

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: 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