fontist 1.8.2 → 1.8.3

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: 1fea467133e3e6a8a287dd36a2a03790fb63859f983b0398f0f558de519a0a64
4
- data.tar.gz: b8c717aef31834b5a9b3c3f903dacf0d267ddd85aa6f0a1eca34566a45b219bf
3
+ metadata.gz: 8b8f20509f7376c4f88906c9f5d95d02f965351433b2b9f47c46d7e9e5afbb1e
4
+ data.tar.gz: e4c71f47525f2c82f0d098eca47629bc808bd1bbff7c83b39f4ede42fd507c05
5
5
  SHA512:
6
- metadata.gz: 20d44b20267db6f15f1b36be660f91690cef7c6f4b0653341231b3f18658ec0f88ea8225884b7b2ac1d06f3e8aa5be79aea600fed5be91513f43031a10b5de5b
7
- data.tar.gz: 6138e6bed40c741f21c6d116f021aef9f6c7cca24506337fe681ba5e6c6e996c8e8e6a84e50103601231d6cab9f5cafc7b5527b418d65fbd6c1477c67ceda201
6
+ metadata.gz: 82f8dc79feec65cd9a1ec567f6168dd9ff06fb7ba4ac7d8fbc58e450dba52380ba98d1d9f559b102ab4c997321565e2ee7fe04ac1b34100b7ce3c66078367b20
7
+ data.tar.gz: 2c80173b5683ed435c609f40bdfae52a0be258a1f491228fba93f2feedea1f28141461708b5c2a84385b5dde84af52792465c21dcf709dfd0f9a4f42d142cf57
@@ -9,15 +9,17 @@ module Fontist
9
9
  STATUS_LICENSING_ERROR = 4
10
10
  STATUS_MANIFEST_COULD_NOT_BE_FOUND_ERROR = 5
11
11
  STATUS_MANIFEST_COULD_NOT_BE_READ_ERROR = 6
12
+ STATUS_FONT_INDEX_CORRUPTED = 7
12
13
 
13
14
  ERROR_TO_STATUS = {
14
- Fontist::Errors::NonSupportedFontError => [STATUS_NON_SUPPORTED_FONT_ERROR],
15
+ Fontist::Errors::UnsupportedFontError => [STATUS_NON_SUPPORTED_FONT_ERROR],
15
16
  Fontist::Errors::MissingFontError => [STATUS_MISSING_FONT_ERROR],
16
17
  Fontist::Errors::LicensingError => [STATUS_LICENSING_ERROR],
17
18
  Fontist::Errors::ManifestCouldNotBeFoundError => [STATUS_MANIFEST_COULD_NOT_BE_FOUND_ERROR,
18
19
  "Manifest could not be found."],
19
20
  Fontist::Errors::ManifestCouldNotBeReadError => [STATUS_MANIFEST_COULD_NOT_BE_READ_ERROR,
20
21
  "Manifest could not be read."],
22
+ Fontist::Errors::FontIndexCorrupted => [STATUS_FONT_INDEX_CORRUPTED],
21
23
  }.freeze
22
24
 
23
25
  def self.exit_on_failure?
@@ -105,7 +107,8 @@ module Fontist
105
107
  option :name, desc: "Example: Times New Roman"
106
108
  option :mirror, repeatable: true
107
109
  option :subarchive, desc: "Subarchive to choose when there are several ones"
108
- option :subdir, desc: "Subdirectory to take fonts from"
110
+ option :subdir, desc: "Subdirectory to take fonts from, starting with the " \
111
+ "root dir, e.g.: stixfonts-2.10/fonts/static_otf. May include `fnmatch` patterns."
109
112
  def create_formula(url)
110
113
  require "fontist/import/create_formula"
111
114
  name = Fontist::Import::CreateFormula.new(url, options).call
@@ -1,7 +1,9 @@
1
1
  module Fontist
2
2
  module Errors
3
3
  class GeneralError < StandardError; end
4
+
4
5
  class BinaryCallError < GeneralError; end
6
+ class FontIndexCorrupted < GeneralError; end
5
7
  class FontNotFoundError < GeneralError; end
6
8
  class FormulaIndexNotFoundError < GeneralError; end
7
9
  class InvalidResourceError < GeneralError; end
@@ -9,10 +11,56 @@ module Fontist
9
11
  class ManifestCouldNotBeFoundError < GeneralError; end
10
12
  class ManifestCouldNotBeReadError < GeneralError; end
11
13
  class MissingAttributeError < GeneralError; end
12
- class MissingFontError < GeneralError; end
13
- class NonSupportedFontError < GeneralError; end
14
14
  class TamperedFileError < GeneralError; end
15
15
  class TimeoutError < GeneralError; end
16
16
  class UnknownFontTypeError < GeneralError; end
17
+
18
+ class FontError < GeneralError
19
+ attr_reader :font, :style
20
+
21
+ def initialize(msg, font = nil, style = nil)
22
+ @font = font
23
+ @style = style
24
+
25
+ super(msg)
26
+ end
27
+
28
+ def name
29
+ messages = []
30
+ messages << "Font name: '#{@font}'"
31
+ messages << "Style: '#{@style}'" if @style
32
+ messages.join("; ")
33
+ end
34
+ end
35
+
36
+ class MissingFontError < FontError
37
+ def initialize(font, style = nil)
38
+ name = prepare_name(font, style)
39
+ msg = "#{name} font is missing, please run `fontist install '#{font}'` to download the font."
40
+
41
+ super(msg, font, style)
42
+ end
43
+
44
+ private
45
+
46
+ def prepare_name(font, style)
47
+ names = []
48
+ names << "'#{font}'"
49
+ names << "'#{style}'" if style
50
+ names.join(" ")
51
+ end
52
+ end
53
+
54
+ class UnsupportedFontError < FontError
55
+ def initialize(font)
56
+ msg = <<~MSG.chomp
57
+ Font '#{font}' not found locally nor available in the Fontist formula repository.
58
+ Perhaps it is available at the latest Fontist formula repository.
59
+ You can update the formula repository using the command `fontist update` and try again.
60
+ MSG
61
+
62
+ super(msg, font)
63
+ end
64
+ end
17
65
  end
18
66
  end
@@ -96,12 +96,7 @@ module Fontist
96
96
 
97
97
  def downloadable_font
98
98
  if formula
99
- raise(
100
- Fontist::Errors::MissingFontError,
101
- "#{name} fonts are missing, please run " \
102
- "`fontist install '#{name}'` to " \
103
- "download the font."
104
- )
99
+ raise Fontist::Errors::MissingFontError.new(name)
105
100
  end
106
101
  end
107
102
 
@@ -236,14 +231,7 @@ module Fontist
236
231
  end
237
232
 
238
233
  def raise_non_supported_font
239
- raise Fontist::Errors::NonSupportedFontError.new(
240
- "Font '#{@name}' not found locally nor available in the Fontist " \
241
- "formula repository.\n" \
242
- "Perhaps it is available at the latest Fontist formula " \
243
- "repository.\n" \
244
- "You can update the formula repository using the command " \
245
- "`fontist update` and try again."
246
- )
234
+ raise Fontist::Errors::UnsupportedFontError.new(@name)
247
235
  end
248
236
  end
249
237
  end
@@ -55,7 +55,7 @@ module Fontist
55
55
  def file_paths(font, style)
56
56
  find_font_with_name(font, style).tap do |x|
57
57
  if x["paths"].empty?
58
- raise Errors::MissingFontError.new("Could not find font #{font} #{style}.")
58
+ raise Errors::MissingFontError.new(font, style)
59
59
  end
60
60
  end
61
61
  end
@@ -9,6 +9,33 @@ module Fontist
9
9
  @user_sources = sources || []
10
10
  end
11
11
 
12
+ def self.font_paths
13
+ system_font_paths + fontist_font_paths
14
+ end
15
+
16
+ def self.system_font_paths
17
+ config_path = Fontist.system_file_path
18
+ os = Fontist::Utils::System.user_os.to_s
19
+ templates = YAML.load_file(config_path)["system"][os]["paths"]
20
+ patterns = expand_paths(templates)
21
+
22
+ Dir.glob(patterns)
23
+ end
24
+
25
+ def self.expand_paths(paths)
26
+ paths.map do |path|
27
+ require "etc"
28
+ passwd = Etc.getpwuid
29
+ username = passwd ? passwd.name : Etc.getlogin
30
+
31
+ username ? path.gsub("{username}", username) : path
32
+ end
33
+ end
34
+
35
+ def self.fontist_font_paths
36
+ Dir.glob(Fontist.fonts_path.join("**"))
37
+ end
38
+
12
39
  def self.find(font, sources: [])
13
40
  new(font: font, sources: sources).find
14
41
  end
@@ -36,50 +63,20 @@ module Fontist
36
63
 
37
64
  attr_reader :font, :style, :user_sources
38
65
 
39
- def normalize_default_paths
40
- @normalize_default_paths ||= default_sources["paths"].map do |path|
41
- require "etc"
42
- passwd = Etc.getpwuid
43
- username = passwd ? passwd.name : Etc.getlogin
44
-
45
- username ? path.gsub("{username}", username) : path
46
- end
47
- end
48
-
49
- def font_paths
50
- @font_paths ||= Dir.glob((
51
- user_sources +
52
- normalize_default_paths +
53
- [fontist_fonts_path.join("**")]
54
- ).flatten.uniq)
55
- end
56
-
57
- def fontist_fonts_path
58
- @fontist_fonts_path ||= Fontist.fonts_path
59
- end
60
-
61
- def user_os
62
- Fontist::Utils::System.user_os
63
- end
64
-
65
- def system_path_file
66
- File.open(Fontist.system_file_path)
67
- end
68
-
69
- def default_sources
70
- @default_sources ||= YAML.safe_load(system_path_file)["system"][user_os.to_s]
71
- end
72
-
73
66
  def find_styles
74
67
  find_by_index || find_by_formulas
75
68
  end
76
69
 
77
70
  def find_by_index
78
- SystemIndex.new(font_paths).find(font, style)
71
+ SystemIndex.new(all_paths).find(font, style)
79
72
  end
80
73
 
81
74
  def find_by_formulas
82
- FormulaPaths.new(font_paths).find(font, style)
75
+ FormulaPaths.new(all_paths).find(font, style)
76
+ end
77
+
78
+ def all_paths
79
+ @all_paths ||= Dir.glob(user_sources) + self.class.font_paths
83
80
  end
84
81
  end
85
82
  end
@@ -2,8 +2,18 @@ require "ttfunk"
2
2
 
3
3
  module Fontist
4
4
  class SystemIndex
5
+ include Utils::Locking
6
+
5
7
  attr_reader :font_paths
6
8
 
9
+ def self.find(font, style)
10
+ new(SystemFont.font_paths).find(font, style)
11
+ end
12
+
13
+ def self.rebuild
14
+ new(SystemFont.font_paths).rebuild
15
+ end
16
+
7
17
  def initialize(font_paths)
8
18
  @font_paths = font_paths
9
19
  end
@@ -17,6 +27,10 @@ module Fontist
17
27
  fonts.empty? ? nil : fonts
18
28
  end
19
29
 
30
+ def rebuild
31
+ build_system_index
32
+ end
33
+
20
34
  private
21
35
 
22
36
  def system_index
@@ -24,21 +38,49 @@ module Fontist
24
38
  end
25
39
 
26
40
  def build_system_index
41
+ lock(lock_path) do
42
+ do_build_system_index
43
+ end
44
+ end
45
+
46
+ def lock_path
47
+ Fontist.system_index_path.to_s + ".lock"
48
+ end
49
+
50
+ def do_build_system_index
27
51
  previous_index = load_system_index
28
52
  updated_index = detect_paths(font_paths, previous_index)
29
53
  updated_index.tap do |index|
30
- save_index(index)
54
+ save_index(index) if changed?(updated_index, previous_index)
31
55
  end
32
56
  end
33
57
 
58
+ def changed?(this, other)
59
+ this.map { |x| x[:path] }.uniq.sort != other.map { |x| x[:path] }.uniq.sort
60
+ end
61
+
34
62
  def load_system_index
35
63
  index = File.exist?(Fontist.system_index_path) ? YAML.load_file(Fontist.system_index_path) : []
36
- index.group_by { |x| x[:path] }
64
+
65
+ index.each do |item|
66
+ missing_keys = %i[path full_name family_name type] - item.keys
67
+ unless missing_keys.empty?
68
+ raise(Errors::FontIndexCorrupted, <<~MSG.chomp)
69
+ Font index is corrupted.
70
+ Item #{item.inspect} misses required attributes: #{missing_keys.join(', ')}.
71
+ You can remove the index file (#{Fontist.system_index_path}) and try again.
72
+ MSG
73
+ end
74
+ end
75
+
76
+ index
37
77
  end
38
78
 
39
- def detect_paths(paths, indexed)
79
+ def detect_paths(paths, index)
80
+ by_path = index.group_by { |x| x[:path] }
81
+
40
82
  paths.flat_map do |path|
41
- next indexed[path] if indexed[path]
83
+ next by_path[path] if by_path[path]
42
84
 
43
85
  detect_fonts(path)
44
86
  end
@@ -1,4 +1,5 @@
1
1
  require "fontist/utils/ui"
2
+ require "fontist/utils/locking"
2
3
  require "fontist/utils/system"
3
4
  require "fontist/utils/dsl"
4
5
  require "fontist/utils/dsl/font"
@@ -1,6 +1,8 @@
1
1
  module Fontist
2
2
  module Utils
3
3
  class Cache
4
+ include Locking
5
+
4
6
  def fetch(key, bar: nil)
5
7
  map = load_cache
6
8
  if cache_exist?(map[key])
@@ -48,13 +50,19 @@ module Fontist
48
50
  def save_cache(generated_file, key)
49
51
  path = move_to_downloads(generated_file)
50
52
 
51
- map = load_cache
52
- map[key] = path
53
- File.write(cache_map_path, YAML.dump(map))
53
+ lock(lock_path) do
54
+ map = load_cache
55
+ map[key] = path
56
+ File.write(cache_map_path, YAML.dump(map))
57
+ end
54
58
 
55
59
  path
56
60
  end
57
61
 
62
+ def lock_path
63
+ cache_map_path.to_s + ".lock"
64
+ end
65
+
58
66
  def move_to_downloads(source)
59
67
  create_downloads_directory
60
68
  path = generate_file_path(source)
@@ -0,0 +1,17 @@
1
+ module Fontist
2
+ module Utils
3
+ module Locking
4
+ def lock(lock_path)
5
+ File.dirname(lock_path).tap do |dir|
6
+ FileUtils.mkdir_p(dir) unless File.exist?(dir)
7
+ end
8
+
9
+ f = File.open(lock_path, File::CREAT)
10
+ f.flock(File::LOCK_EX)
11
+ yield
12
+ ensure
13
+ f.flock(File::LOCK_UN)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,3 +1,3 @@
1
1
  module Fontist
2
- VERSION = "1.8.2".freeze
2
+ VERSION = "1.8.3".freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fontist
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.2
4
+ version: 1.8.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2020-12-30 00:00:00.000000000 Z
12
+ date: 2021-01-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: down
@@ -357,6 +357,7 @@ files:
357
357
  - lib/fontist/utils/dsl/collection_font.rb
358
358
  - lib/fontist/utils/dsl/font.rb
359
359
  - lib/fontist/utils/exe_extractor.rb
360
+ - lib/fontist/utils/locking.rb
360
361
  - lib/fontist/utils/msi_extractor.rb
361
362
  - lib/fontist/utils/seven_zip_extractor.rb
362
363
  - lib/fontist/utils/system.rb