fontist 1.20.0 → 1.21.1
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 +4 -4
- data/.github/workflows/test-and-release.yml +2 -1
- data/README.adoc +1 -1
- data/exe/fontist +1 -2
- data/lib/fontist/cli/thor_ext.rb +79 -0
- data/lib/fontist/cli.rb +2 -0
- data/lib/fontist/config.rb +2 -1
- data/lib/fontist/font.rb +5 -0
- data/lib/fontist/font_installer.rb +22 -51
- data/lib/fontist/formula.rb +6 -0
- data/lib/fontist/helpers.rb +2 -0
- data/lib/fontist/import/create_formula.rb +77 -35
- data/lib/fontist/import/formula_builder.rb +63 -81
- data/lib/fontist/import/google/api.rb +25 -0
- data/lib/fontist/import/google/create_google_formula.rb +89 -0
- data/lib/fontist/import/google_import.rb +63 -32
- data/lib/fontist/import/recursive_extraction.rb +0 -16
- data/lib/fontist/manifest/locations.rb +2 -0
- data/lib/fontist/resources/archive_resource.rb +55 -0
- data/lib/fontist/resources/google_resource.rb +64 -0
- data/lib/fontist/style_version.rb +4 -0
- data/lib/fontist/utils/cache.rb +16 -0
- data/lib/fontist/utils/downloader.rb +9 -2
- data/lib/fontist/utils/ui.rb +10 -2
- data/lib/fontist/version.rb +1 -1
- data/lib/fontist.rb +5 -1
- metadata +8 -6
- data/lib/fontist/import/google/new_fonts_fetcher.rb +0 -146
- data/lib/fontist/import/google/skiplist.yml +0 -12
- data/lib/fontist/import/google_check.rb +0 -27
@@ -0,0 +1,89 @@
|
|
1
|
+
require "fontist/import"
|
2
|
+
require "fontist/import/formula_builder"
|
3
|
+
require "fontist/import/otf/font_file"
|
4
|
+
|
5
|
+
module Fontist
|
6
|
+
module Import
|
7
|
+
module Google
|
8
|
+
class CreateGoogleFormula
|
9
|
+
REPO_PATH = Fontist.fontist_path.join("google", "fonts")
|
10
|
+
POSSIBLE_LICENSE_FILES = ["LICENSE.txt",
|
11
|
+
"LICENCE.txt",
|
12
|
+
"OFL.txt",
|
13
|
+
"UFL.txt"].freeze
|
14
|
+
|
15
|
+
def initialize(item, options = {})
|
16
|
+
@item = item
|
17
|
+
@options = options
|
18
|
+
end
|
19
|
+
|
20
|
+
def call
|
21
|
+
builder = FormulaBuilder.new
|
22
|
+
builder.options = options
|
23
|
+
builder.resources = resources
|
24
|
+
builder.font_files = font_files
|
25
|
+
builder.license_text = license_text
|
26
|
+
builder.save
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def options
|
32
|
+
@options.merge(name: formula_name, open_license: true)
|
33
|
+
end
|
34
|
+
|
35
|
+
def formula_name
|
36
|
+
@item["family"]
|
37
|
+
end
|
38
|
+
|
39
|
+
def resources
|
40
|
+
{
|
41
|
+
@item["family"] => {
|
42
|
+
source: "google",
|
43
|
+
family: @item["family"],
|
44
|
+
files: @item["files"].values,
|
45
|
+
},
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
def font_files
|
50
|
+
@font_files ||= @item["files"].map do |_key, url|
|
51
|
+
font_file(url)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def license_text
|
56
|
+
@license_text ||= find_license_text
|
57
|
+
end
|
58
|
+
|
59
|
+
def font_file(url)
|
60
|
+
path = Utils::Downloader.download(url, use_content_length: false).path
|
61
|
+
Otf::FontFile.new(path)
|
62
|
+
end
|
63
|
+
|
64
|
+
def find_license_text
|
65
|
+
file = license_file
|
66
|
+
return unless file
|
67
|
+
|
68
|
+
File.read(file)
|
69
|
+
end
|
70
|
+
|
71
|
+
def license_file
|
72
|
+
dir = @item["family"].gsub(" ", "").downcase
|
73
|
+
path = repo_paths(dir).first
|
74
|
+
return unless path
|
75
|
+
|
76
|
+
full_paths = POSSIBLE_LICENSE_FILES.map { |f| File.join(path, f) }
|
77
|
+
|
78
|
+
Dir[*full_paths].first
|
79
|
+
end
|
80
|
+
|
81
|
+
def repo_paths(dir)
|
82
|
+
Dir[File.join(REPO_PATH, "apache", dir),
|
83
|
+
File.join(REPO_PATH, "ofl", dir),
|
84
|
+
File.join(REPO_PATH, "ufl", dir)]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -1,54 +1,92 @@
|
|
1
|
-
require "erb"
|
2
1
|
require_relative "google"
|
3
|
-
require_relative "google/
|
4
|
-
require_relative "
|
2
|
+
require_relative "google/api"
|
3
|
+
require_relative "google/create_google_formula"
|
5
4
|
|
6
5
|
module Fontist
|
7
6
|
module Import
|
8
7
|
class GoogleImport
|
8
|
+
REPO_PATH = Fontist.fontist_path.join("google", "fonts")
|
9
|
+
REPO_URL = "https://github.com/google/fonts.git".freeze
|
10
|
+
|
9
11
|
def initialize(options)
|
10
12
|
@max_count = options[:max_count] || Google::DEFAULT_MAX_COUNT
|
11
13
|
end
|
12
14
|
|
13
15
|
def call
|
14
|
-
|
15
|
-
|
16
|
-
rebuild_index
|
16
|
+
update_repo
|
17
|
+
count = update_formulas
|
18
|
+
rebuild_index if count.positive?
|
17
19
|
end
|
18
20
|
|
19
21
|
private
|
20
22
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
23
|
+
def update_repo
|
24
|
+
if Dir.exist?(REPO_PATH)
|
25
|
+
`cd #{REPO_PATH} && git pull`
|
26
|
+
else
|
27
|
+
FileUtils.mkdir_p(File.dirname(REPO_PATH))
|
28
|
+
`git clone --depth 1 #{REPO_URL} #{REPO_PATH}`
|
29
|
+
end
|
24
30
|
end
|
25
31
|
|
26
|
-
def
|
27
|
-
|
32
|
+
def update_formulas
|
33
|
+
Fontist.ui.say "Updating formulas..."
|
34
|
+
|
35
|
+
items = api_items
|
28
36
|
|
29
|
-
|
30
|
-
|
31
|
-
|
37
|
+
count = 0
|
38
|
+
items.each do |item|
|
39
|
+
break if count >= @max_count
|
40
|
+
|
41
|
+
path = update_formula(item)
|
42
|
+
count += 1 if path
|
32
43
|
end
|
44
|
+
|
45
|
+
count
|
46
|
+
end
|
47
|
+
|
48
|
+
def api_items
|
49
|
+
Google::Api.items
|
50
|
+
end
|
51
|
+
|
52
|
+
def update_formula(item)
|
53
|
+
family = item["family"]
|
54
|
+
Fontist.ui.say "Checking #{family}"
|
55
|
+
unless new_changes?(item)
|
56
|
+
Fontist.ui.say "Skip, no changes"
|
57
|
+
return
|
58
|
+
end
|
59
|
+
|
60
|
+
create_formula(item)
|
33
61
|
end
|
34
62
|
|
35
|
-
def
|
36
|
-
|
63
|
+
def new_changes?(item)
|
64
|
+
formula = formula(item["family"])
|
65
|
+
return true unless formula
|
37
66
|
|
38
|
-
|
39
|
-
|
40
|
-
|
67
|
+
item["files"].values != formula.resources.first.files
|
68
|
+
end
|
69
|
+
|
70
|
+
def formula(font_name)
|
71
|
+
path = formula_path(font_name)
|
72
|
+
Formula.new_from_file(path) if File.exist?(path)
|
73
|
+
end
|
74
|
+
|
75
|
+
def formula_path(name)
|
76
|
+
snake_case = name.downcase.gsub(" ", "_")
|
77
|
+
filename = "#{snake_case}.yml"
|
78
|
+
Fontist.formulas_path.join("google", filename)
|
79
|
+
end
|
80
|
+
|
81
|
+
def create_formula(item)
|
82
|
+
path = Google::CreateGoogleFormula.new(
|
83
|
+
item,
|
41
84
|
formula_dir: formula_dir,
|
42
|
-
skip_sha: variable_style?(font_path),
|
43
|
-
digest: Google.digest(font_path),
|
44
85
|
).call
|
45
86
|
|
46
87
|
Fontist.ui.success("Formula has been successfully created: #{path}")
|
47
|
-
end
|
48
88
|
|
49
|
-
|
50
|
-
name = Google.metadata_name(path)
|
51
|
-
"https://fonts.google.com/download?family=#{ERB::Util.url_encode(name)}"
|
89
|
+
path
|
52
90
|
end
|
53
91
|
|
54
92
|
def formula_dir
|
@@ -57,13 +95,6 @@ module Fontist
|
|
57
95
|
end
|
58
96
|
end
|
59
97
|
|
60
|
-
def variable_style?(path)
|
61
|
-
fonts = Dir.glob(File.join(path, "*.{ttf,otf}"))
|
62
|
-
fonts.any? do |font|
|
63
|
-
File.basename(font).match?(/\[(.+,)?(wght|opsz)\]/)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
98
|
def rebuild_index
|
68
99
|
Fontist::Index.rebuild
|
69
100
|
end
|
@@ -19,10 +19,6 @@ module Fontist
|
|
19
19
|
save_operation_subdir
|
20
20
|
end
|
21
21
|
|
22
|
-
def extension
|
23
|
-
fetch_extension(@archive)
|
24
|
-
end
|
25
|
-
|
26
22
|
def font_files
|
27
23
|
ensure_extracted
|
28
24
|
@font_files
|
@@ -52,18 +48,6 @@ module Fontist
|
|
52
48
|
@operations[:options][:fonts_sub_dir] = @subdir
|
53
49
|
end
|
54
50
|
|
55
|
-
def fetch_extension(file)
|
56
|
-
File.extname(filename(file)).sub(/^\./, "")
|
57
|
-
end
|
58
|
-
|
59
|
-
def filename(file)
|
60
|
-
if file.respond_to?(:original_filename)
|
61
|
-
file.original_filename
|
62
|
-
else
|
63
|
-
File.basename(file)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
51
|
def ensure_extracted
|
68
52
|
return if @extracted
|
69
53
|
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Fontist
|
2
|
+
module Resources
|
3
|
+
class ArchiveResource
|
4
|
+
def initialize(resource, options = {})
|
5
|
+
@resource = resource
|
6
|
+
@options = options
|
7
|
+
end
|
8
|
+
|
9
|
+
def files(_source_names, &block)
|
10
|
+
excavate.files(recursive_packages: true, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def excavate
|
16
|
+
Excavate::Archive.new(archive.path)
|
17
|
+
end
|
18
|
+
|
19
|
+
def archive
|
20
|
+
download_file(@resource)
|
21
|
+
end
|
22
|
+
|
23
|
+
def download_file(source)
|
24
|
+
errors = []
|
25
|
+
source.urls.each do |request|
|
26
|
+
result = try_download_file(request, source)
|
27
|
+
return result unless result.is_a?(Errors::InvalidResourceError)
|
28
|
+
|
29
|
+
errors << result
|
30
|
+
end
|
31
|
+
|
32
|
+
raise Errors::InvalidResourceError, errors.join(" ")
|
33
|
+
end
|
34
|
+
|
35
|
+
def try_download_file(request, source)
|
36
|
+
info_log(request)
|
37
|
+
|
38
|
+
Fontist::Utils::Downloader.download(
|
39
|
+
request,
|
40
|
+
sha: source.sha256,
|
41
|
+
file_size: source.file_size,
|
42
|
+
progress_bar: !@options[:no_progress],
|
43
|
+
)
|
44
|
+
rescue Errors::InvalidResourceError => e
|
45
|
+
Fontist.ui.say(e.message)
|
46
|
+
e
|
47
|
+
end
|
48
|
+
|
49
|
+
def info_log(request)
|
50
|
+
url = request.respond_to?(:url) ? request.url : request
|
51
|
+
Fontist.ui.say(%(Downloading from #{url}))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Fontist
|
2
|
+
module Resources
|
3
|
+
class GoogleResource
|
4
|
+
def initialize(resource, options = {})
|
5
|
+
@resource = resource
|
6
|
+
@options = options
|
7
|
+
end
|
8
|
+
|
9
|
+
def files(source_names)
|
10
|
+
cached_paths = download_fonts(source_names)
|
11
|
+
|
12
|
+
cached_paths.map do |path|
|
13
|
+
Dir.mktmpdir do |dir|
|
14
|
+
FileUtils.cp(path, dir)
|
15
|
+
|
16
|
+
yield File.join(dir, File.basename(path))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def download_fonts(source_names)
|
24
|
+
urls = font_urls(source_names)
|
25
|
+
|
26
|
+
urls.map do |url|
|
27
|
+
download(url)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def font_urls(source_names)
|
32
|
+
@resource.files.select do |url|
|
33
|
+
source_names.include?(path_to_source_file(url))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def path_to_source_file(path)
|
38
|
+
format_filename(File.basename(path))
|
39
|
+
end
|
40
|
+
|
41
|
+
# TODO: remove duplication, another in Cache
|
42
|
+
def format_filename(filename)
|
43
|
+
return filename unless filename.length > 255
|
44
|
+
|
45
|
+
ext = File.extname(filename)
|
46
|
+
target_size = 255 - ext.length
|
47
|
+
cut_filename = filename.slice(0, target_size)
|
48
|
+
"#{cut_filename}#{ext}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def download(url)
|
52
|
+
Fontist.ui.say(%(Downloading from #{url}))
|
53
|
+
|
54
|
+
file = Utils::Downloader.download(
|
55
|
+
url,
|
56
|
+
use_content_length: false,
|
57
|
+
progress_bar: !@options[:no_progress],
|
58
|
+
)
|
59
|
+
|
60
|
+
file.path
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/fontist/utils/cache.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module Fontist
|
2
2
|
module Utils
|
3
3
|
class Cache
|
4
|
+
MAX_FILENAME_SIZE = 255
|
5
|
+
|
4
6
|
include Locking
|
5
7
|
|
6
8
|
def self.lock_path(path)
|
@@ -110,6 +112,11 @@ module Fontist
|
|
110
112
|
end
|
111
113
|
|
112
114
|
def filename(source)
|
115
|
+
filename = response_to_filename(source)
|
116
|
+
format_filename(filename)
|
117
|
+
end
|
118
|
+
|
119
|
+
def response_to_filename(source)
|
113
120
|
if File.extname(source.original_filename).empty? && source.content_type
|
114
121
|
require "mime/types"
|
115
122
|
ext = MIME::Types[source.content_type].first&.preferred_extension
|
@@ -119,6 +126,15 @@ module Fontist
|
|
119
126
|
source.original_filename
|
120
127
|
end
|
121
128
|
|
129
|
+
def format_filename(filename)
|
130
|
+
return filename unless filename.length > MAX_FILENAME_SIZE
|
131
|
+
|
132
|
+
ext = File.extname(filename)
|
133
|
+
target_size = MAX_FILENAME_SIZE - ext.length
|
134
|
+
cut_filename = filename.slice(0, target_size)
|
135
|
+
"#{cut_filename}#{ext}"
|
136
|
+
end
|
137
|
+
|
122
138
|
def move(source_file, target_path)
|
123
139
|
# Windows requires file descriptors to be closed before files are moved
|
124
140
|
source_file.close
|
@@ -10,12 +10,17 @@ module Fontist
|
|
10
10
|
ruby2_keywords :download if respond_to?(:ruby2_keywords, true)
|
11
11
|
end
|
12
12
|
|
13
|
-
def initialize(file,
|
13
|
+
def initialize(file,
|
14
|
+
file_size: nil,
|
15
|
+
sha: nil,
|
16
|
+
progress_bar: nil,
|
17
|
+
use_content_length: true)
|
14
18
|
# TODO: If the first mirror fails, try the second one
|
15
19
|
@file = file
|
16
20
|
@sha = [sha].flatten.compact
|
17
21
|
@file_size = file_size.to_i if file_size
|
18
22
|
@progress_bar = progress_bar
|
23
|
+
@use_content_length = use_content_length
|
19
24
|
@cache = Cache.new
|
20
25
|
end
|
21
26
|
|
@@ -85,7 +90,9 @@ module Fontist
|
|
85
90
|
max_redirects: 10,
|
86
91
|
headers: headers,
|
87
92
|
content_length_proc: ->(content_length) {
|
88
|
-
|
93
|
+
if @use_content_length && content_length
|
94
|
+
progress_bar.total = content_length
|
95
|
+
end
|
89
96
|
},
|
90
97
|
progress_proc: -> (progress) {
|
91
98
|
progress_bar.increment(progress)
|
data/lib/fontist/utils/ui.rb
CHANGED
@@ -16,7 +16,15 @@ module Fontist
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def self.level
|
19
|
-
@level || default_level
|
19
|
+
@level ||= env_level || default_level
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.env_level
|
23
|
+
ENV["FONTIST_LOG"]&.to_sym
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.debug?
|
27
|
+
log_levels.include?(:debug)
|
20
28
|
end
|
21
29
|
|
22
30
|
def self.default_level
|
@@ -50,7 +58,7 @@ module Fontist
|
|
50
58
|
end
|
51
59
|
|
52
60
|
def self.debug(message)
|
53
|
-
new.say(message) if
|
61
|
+
new.say(message) if debug?
|
54
62
|
end
|
55
63
|
|
56
64
|
def self.log_levels
|
data/lib/fontist/version.rb
CHANGED
data/lib/fontist.rb
CHANGED
@@ -49,7 +49,7 @@ module Fontist
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def self.formulas_version
|
52
|
-
"
|
52
|
+
"v4"
|
53
53
|
end
|
54
54
|
|
55
55
|
def self.formulas_repo_url
|
@@ -159,4 +159,8 @@ module Fontist
|
|
159
159
|
def self.interactive=(bool)
|
160
160
|
@interactive = bool
|
161
161
|
end
|
162
|
+
|
163
|
+
def self.google_fonts_key
|
164
|
+
ENV["GOOGLE_FONTS_API_KEY"] || config[:google_fonts_key]
|
165
|
+
end
|
162
166
|
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.
|
4
|
+
version: 1.21.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ribose Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-05-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: down
|
@@ -377,6 +377,7 @@ files:
|
|
377
377
|
- lib/fontist/cache_cli.rb
|
378
378
|
- lib/fontist/cli.rb
|
379
379
|
- lib/fontist/cli/class_options.rb
|
380
|
+
- lib/fontist/cli/thor_ext.rb
|
380
381
|
- lib/fontist/collection_file.rb
|
381
382
|
- lib/fontist/config.rb
|
382
383
|
- lib/fontist/config_cli.rb
|
@@ -401,9 +402,8 @@ files:
|
|
401
402
|
- lib/fontist/import/formula_builder.rb
|
402
403
|
- lib/fontist/import/formula_serializer.rb
|
403
404
|
- lib/fontist/import/google.rb
|
404
|
-
- lib/fontist/import/google/
|
405
|
-
- lib/fontist/import/google/
|
406
|
-
- lib/fontist/import/google_check.rb
|
405
|
+
- lib/fontist/import/google/api.rb
|
406
|
+
- lib/fontist/import/google/create_google_formula.rb
|
407
407
|
- lib/fontist/import/google_import.rb
|
408
408
|
- lib/fontist/import/helpers/hash_helper.rb
|
409
409
|
- lib/fontist/import/helpers/system_helper.rb
|
@@ -433,6 +433,8 @@ files:
|
|
433
433
|
- lib/fontist/manifest/locations.rb
|
434
434
|
- lib/fontist/repo.rb
|
435
435
|
- lib/fontist/repo_cli.rb
|
436
|
+
- lib/fontist/resources/archive_resource.rb
|
437
|
+
- lib/fontist/resources/google_resource.rb
|
436
438
|
- lib/fontist/style_version.rb
|
437
439
|
- lib/fontist/system.yml
|
438
440
|
- lib/fontist/system_font.rb
|
@@ -468,7 +470,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
468
470
|
- !ruby/object:Gem::Version
|
469
471
|
version: '0'
|
470
472
|
requirements: []
|
471
|
-
rubygems_version: 3.3.
|
473
|
+
rubygems_version: 3.3.27
|
472
474
|
signing_key:
|
473
475
|
specification_version: 4
|
474
476
|
summary: Install openly-licensed fonts on Windows, Linux and Mac!
|