fontist 1.8.2 → 1.8.3

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