fontist 1.11.5 → 1.13.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -68,7 +73,7 @@ module Fontist
68
73
  end
69
74
 
70
75
  def resource_options_without_sha
71
- { urls: [@url] + mirrors }
76
+ { urls: [@url] + mirrors, file_size: file_size }
72
77
  end
73
78
 
74
79
  def resource_options_with_sha
@@ -81,7 +86,7 @@ module Fontist
81
86
 
82
87
  sha = prepare_sha256(sha)
83
88
 
84
- { urls: urls, sha256: sha }
89
+ { urls: urls, sha256: sha, file_size: file_size }
85
90
  end
86
91
 
87
92
  def downloads
@@ -115,6 +120,10 @@ module Fontist
115
120
  output
116
121
  end
117
122
 
123
+ def file_size
124
+ File.size(@archive)
125
+ end
126
+
118
127
  def font_collections
119
128
  return if @font_collection_files.empty?
120
129
 
@@ -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
@@ -9,7 +9,10 @@ module Fontist
9
9
 
10
10
  def add_formula(formula)
11
11
  formula.fonts.each do |font|
12
- add_index_formula(font.name, formula.to_index_formula)
12
+ font.styles.each do |style|
13
+ font_name = style.default_family_name || font.name
14
+ add_index_formula(font_name, formula.to_index_formula)
15
+ end
13
16
  end
14
17
  end
15
18
 
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)
@@ -0,0 +1,39 @@
1
+ module Fontist
2
+ class StyleVersion
3
+ def initialize(text)
4
+ @text = text
5
+ end
6
+
7
+ def value
8
+ @value ||= numbers || default_value
9
+ end
10
+
11
+ def numbers
12
+ string_version&.split(".")&.map(&:strip)
13
+ end
14
+
15
+ def string_version
16
+ @text&.split(";")&.first
17
+ end
18
+
19
+ def default_value
20
+ ["0"]
21
+ end
22
+
23
+ def <=>(other)
24
+ value <=> other.value
25
+ end
26
+
27
+ def ==(other)
28
+ value == other.value
29
+ end
30
+
31
+ def eql?(other)
32
+ value.eql?(other.value)
33
+ end
34
+
35
+ def hash
36
+ value.hash
37
+ end
38
+ end
39
+ end
@@ -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
@@ -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.5".freeze
2
+ VERSION = "1.13.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
@@ -103,6 +107,10 @@ module Fontist
103
107
  Fontist.fontist_version_path
104
108
  end
105
109
 
110
+ def self.formula_size_limit_in_megabytes
111
+ 300
112
+ end
113
+
106
114
  def self.preferred_family?
107
115
  !!@preferred_family
108
116
  end