fontist 1.6.0 → 1.8.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 +5 -5
- data/.github/workflows/release.yml +38 -0
- data/.github/workflows/rspec.yml +58 -0
- data/README.md +109 -32
- data/{bin → exe}/fontist +0 -0
- data/fontist.gemspec +4 -2
- data/lib/fontist.rb +10 -3
- data/lib/fontist/cli.rb +63 -42
- data/lib/fontist/errors.rb +14 -11
- data/lib/fontist/font.rb +25 -27
- data/lib/fontist/font_installer.rb +114 -0
- data/lib/fontist/fontist_font.rb +3 -49
- data/lib/fontist/formula.rb +89 -63
- data/lib/fontist/formula_paths.rb +43 -0
- data/lib/fontist/helpers.rb +7 -0
- data/lib/fontist/import/create_formula.rb +15 -30
- data/lib/fontist/import/files/collection_file.rb +6 -1
- data/lib/fontist/import/files/file_requirement.rb +17 -0
- data/lib/fontist/import/files/font_detector.rb +48 -0
- data/lib/fontist/import/formula_builder.rb +7 -3
- data/lib/fontist/import/google_check.rb +1 -1
- data/lib/fontist/import/google_import.rb +3 -4
- data/lib/fontist/import/otf/font_file.rb +17 -3
- data/lib/fontist/import/otfinfo_generate.rb +1 -1
- data/lib/fontist/import/recursive_extraction.rb +74 -13
- data/lib/fontist/index.rb +72 -0
- data/lib/fontist/index_formula.rb +30 -0
- data/lib/fontist/manifest/install.rb +6 -15
- data/lib/fontist/manifest/locations.rb +59 -4
- data/lib/fontist/system_font.rb +22 -49
- data/lib/fontist/system_index.rb +92 -0
- data/lib/fontist/utils.rb +1 -0
- data/lib/fontist/utils/dsl.rb +4 -0
- data/lib/fontist/utils/dsl/collection_font.rb +36 -0
- data/lib/fontist/utils/dsl/font.rb +2 -1
- data/lib/fontist/utils/exe_extractor.rb +6 -5
- data/lib/fontist/utils/zip_extractor.rb +20 -12
- data/lib/fontist/version.rb +1 -1
- metadata +45 -20
- data/.github/workflows/macosx.yml +0 -33
- data/.github/workflows/ubuntu.yml +0 -30
- data/.github/workflows/windows.yml +0 -32
- data/bin/check_google +0 -8
- data/bin/console +0 -11
- data/bin/convert_formulas +0 -8
- data/bin/generate_otfinfo +0 -8
- data/bin/import_google +0 -8
- data/bin/rspec +0 -29
- data/bin/setup +0 -7
- data/lib/fontist/font_formula.rb +0 -130
- data/lib/fontist/formula_template.rb +0 -108
- data/lib/fontist/formulas.rb +0 -56
- data/lib/fontist/manifest/common.rb +0 -60
- data/lib/fontist/registry.rb +0 -43
@@ -0,0 +1,30 @@
|
|
1
|
+
module Fontist
|
2
|
+
class IndexFormula
|
3
|
+
def initialize(path)
|
4
|
+
@path = path
|
5
|
+
end
|
6
|
+
|
7
|
+
def to_s
|
8
|
+
normalized
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_full
|
12
|
+
Formula.new_from_file(full_path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def ==(other)
|
16
|
+
to_s == other.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def normalized
|
22
|
+
escaped = Regexp.escape(Fontist.formulas_path.to_s + "/")
|
23
|
+
@path.sub(Regexp.new("^" + escaped), "")
|
24
|
+
end
|
25
|
+
|
26
|
+
def full_path
|
27
|
+
Fontist.formulas_path.join(normalized).to_s
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,35 +1,26 @@
|
|
1
|
-
require_relative "
|
1
|
+
require_relative "locations"
|
2
2
|
|
3
3
|
module Fontist
|
4
4
|
module Manifest
|
5
|
-
class Install <
|
5
|
+
class Install < Locations
|
6
6
|
def initialize(manifest, confirmation: "no")
|
7
7
|
@manifest = manifest
|
8
8
|
@confirmation = confirmation
|
9
9
|
end
|
10
10
|
|
11
|
-
def self.call(manifest, confirmation: "no")
|
12
|
-
new(manifest, confirmation: confirmation).call
|
13
|
-
end
|
14
|
-
|
15
11
|
private
|
16
12
|
|
17
13
|
def file_paths(font, style)
|
18
|
-
paths =
|
19
|
-
return paths unless paths.empty?
|
14
|
+
paths = find_font_with_name(font, style)
|
15
|
+
return paths unless paths["paths"].empty?
|
20
16
|
|
21
17
|
install_font(font)
|
22
|
-
find_installed_font(font, style)
|
23
|
-
end
|
24
18
|
|
25
|
-
|
26
|
-
Fontist::SystemFont.find_with_style(font, style)
|
19
|
+
find_font_with_name(font, style)
|
27
20
|
end
|
28
21
|
|
29
22
|
def install_font(font)
|
30
|
-
Fontist::Font.
|
31
|
-
rescue Fontist::Errors::LicensingError
|
32
|
-
[] # try to install other fonts
|
23
|
+
Fontist::Font.install(font, force: true, confirmation: @confirmation)
|
33
24
|
end
|
34
25
|
end
|
35
26
|
end
|
@@ -1,12 +1,67 @@
|
|
1
|
-
require_relative "common"
|
2
|
-
|
3
1
|
module Fontist
|
4
2
|
module Manifest
|
5
|
-
class Locations
|
3
|
+
class Locations
|
4
|
+
def initialize(manifest)
|
5
|
+
@manifest = manifest
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.from_file(file, **keywords)
|
9
|
+
raise Fontist::Errors::ManifestCouldNotBeFoundError unless File.exist?(file)
|
10
|
+
|
11
|
+
manifest = YAML.load_file(file)
|
12
|
+
raise Fontist::Errors::ManifestCouldNotBeReadError unless manifest.is_a?(Hash)
|
13
|
+
|
14
|
+
from_hash(manifest, **keywords)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.from_hash(manifest, **keywords)
|
18
|
+
if keywords.empty?
|
19
|
+
new(manifest).call
|
20
|
+
else
|
21
|
+
new(manifest, **keywords).call
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def call
|
26
|
+
font_names.zip(font_paths).to_h
|
27
|
+
end
|
28
|
+
|
6
29
|
private
|
7
30
|
|
31
|
+
attr_reader :manifest
|
32
|
+
|
33
|
+
def font_names
|
34
|
+
manifest.keys
|
35
|
+
end
|
36
|
+
|
37
|
+
def font_paths
|
38
|
+
manifest.map do |font, styles|
|
39
|
+
styles_to_ary = [styles].flatten
|
40
|
+
style_paths_map(font, styles_to_ary)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def style_paths_map(font, names)
|
45
|
+
paths = style_paths(font, names)
|
46
|
+
names.zip(paths).to_h
|
47
|
+
end
|
48
|
+
|
49
|
+
def style_paths(font, names)
|
50
|
+
names.map do |style|
|
51
|
+
file_paths(font, style)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
8
55
|
def file_paths(font, style)
|
9
|
-
|
56
|
+
find_font_with_name(font, style).tap do |x|
|
57
|
+
if x["paths"].empty?
|
58
|
+
raise Errors::MissingFontError.new("Could not find font #{font} #{style}.")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def find_font_with_name(font, style)
|
64
|
+
Fontist::SystemFont.find_with_name(font, style).map { |k, v| [k.to_s, v] }.to_h
|
10
65
|
end
|
11
66
|
end
|
12
67
|
end
|
data/lib/fontist/system_font.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require_relative "system_index"
|
2
|
+
require_relative "formula_paths"
|
3
|
+
|
1
4
|
module Fontist
|
2
5
|
class SystemFont
|
3
6
|
def initialize(font:, style: nil, sources: nil)
|
@@ -10,22 +13,23 @@ module Fontist
|
|
10
13
|
new(font: font, sources: sources).find
|
11
14
|
end
|
12
15
|
|
13
|
-
def self.
|
14
|
-
new(font: font, style: style).
|
16
|
+
def self.find_with_name(font, style)
|
17
|
+
new(font: font, style: style).find_with_name
|
15
18
|
end
|
16
19
|
|
17
20
|
def find
|
18
|
-
|
19
|
-
|
21
|
+
styles = find_styles
|
22
|
+
return unless styles
|
20
23
|
|
21
|
-
|
24
|
+
styles.map { |x| x[:path] }
|
22
25
|
end
|
23
26
|
|
24
|
-
def
|
25
|
-
|
26
|
-
return paths unless
|
27
|
+
def find_with_name
|
28
|
+
styles = find_styles
|
29
|
+
return { full_name: nil, paths: [] } unless styles
|
27
30
|
|
28
|
-
|
31
|
+
{ full_name: styles.first[:full_name],
|
32
|
+
paths: styles.map { |x| x[:path] } }
|
29
33
|
end
|
30
34
|
|
31
35
|
private
|
@@ -42,25 +46,6 @@ module Fontist
|
|
42
46
|
end
|
43
47
|
end
|
44
48
|
|
45
|
-
def grep_font_paths(font, style = nil)
|
46
|
-
pattern = prepare_pattern(font, style)
|
47
|
-
|
48
|
-
paths = font_paths.map { |path| [File.basename(path), path] }.to_h
|
49
|
-
files = paths.keys
|
50
|
-
matched = files.grep(pattern)
|
51
|
-
paths.values_at(*matched).compact
|
52
|
-
end
|
53
|
-
|
54
|
-
def prepare_pattern(font, style = nil)
|
55
|
-
style = nil if style&.casecmp?("regular")
|
56
|
-
|
57
|
-
s = [font, style].compact.map { |x| Regexp.quote(x) }
|
58
|
-
.join(".*")
|
59
|
-
.gsub("\\ ", "\s?") # space independent
|
60
|
-
|
61
|
-
Regexp.new(s, Regexp::IGNORECASE)
|
62
|
-
end
|
63
|
-
|
64
49
|
def font_paths
|
65
50
|
@font_paths ||= Dir.glob((
|
66
51
|
user_sources +
|
@@ -69,11 +54,6 @@ module Fontist
|
|
69
54
|
).flatten.uniq)
|
70
55
|
end
|
71
56
|
|
72
|
-
def lookup_using_font_name
|
73
|
-
font_names = map_name_to_valid_font_names || []
|
74
|
-
font_paths.grep(/#{font_names.join("|")}/i) unless font_names.empty?
|
75
|
-
end
|
76
|
-
|
77
57
|
def fontist_fonts_path
|
78
58
|
@fontist_fonts_path ||= Fontist.fonts_path
|
79
59
|
end
|
@@ -82,31 +62,24 @@ module Fontist
|
|
82
62
|
Fontist::Utils::System.user_os
|
83
63
|
end
|
84
64
|
|
85
|
-
def map_name_to_valid_font_names
|
86
|
-
fonts = Formula.find_fonts(font)
|
87
|
-
fonts.map { |font| font.styles.map(&:font) }.flatten if fonts
|
88
|
-
end
|
89
|
-
|
90
65
|
def system_path_file
|
91
66
|
File.open(Fontist.system_file_path)
|
92
67
|
end
|
93
68
|
|
94
69
|
def default_sources
|
95
|
-
@default_sources ||= YAML.
|
70
|
+
@default_sources ||= YAML.safe_load(system_path_file)["system"][user_os.to_s]
|
96
71
|
end
|
97
72
|
|
98
|
-
def
|
99
|
-
|
100
|
-
filenames = styles.map(&:font)
|
101
|
-
filenames.flat_map do |filename|
|
102
|
-
search_font_paths(filename)
|
103
|
-
end
|
73
|
+
def find_styles
|
74
|
+
find_by_index || find_by_formulas
|
104
75
|
end
|
105
76
|
|
106
|
-
def
|
107
|
-
font_paths.
|
108
|
-
|
109
|
-
|
77
|
+
def find_by_index
|
78
|
+
SystemIndex.new(font_paths).find(font, style)
|
79
|
+
end
|
80
|
+
|
81
|
+
def find_by_formulas
|
82
|
+
FormulaPaths.new(font_paths).find(font, style)
|
110
83
|
end
|
111
84
|
end
|
112
85
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require "ttfunk"
|
2
|
+
|
3
|
+
module Fontist
|
4
|
+
class SystemIndex
|
5
|
+
attr_reader :font_paths
|
6
|
+
|
7
|
+
def initialize(font_paths)
|
8
|
+
@font_paths = font_paths
|
9
|
+
end
|
10
|
+
|
11
|
+
def find(font, style)
|
12
|
+
fonts = system_index.select do |file|
|
13
|
+
file[:family_name].casecmp?(font) &&
|
14
|
+
(style.nil? || file[:type].casecmp?(style))
|
15
|
+
end
|
16
|
+
|
17
|
+
fonts.empty? ? nil : fonts
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def system_index
|
23
|
+
@system_index ||= build_system_index
|
24
|
+
end
|
25
|
+
|
26
|
+
def build_system_index
|
27
|
+
previous_index = load_system_index
|
28
|
+
updated_index = detect_paths(font_paths, previous_index)
|
29
|
+
updated_index.tap do |index|
|
30
|
+
save_index(index)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def load_system_index
|
35
|
+
index = File.exist?(Fontist.system_index_path) ? YAML.load_file(Fontist.system_index_path) : []
|
36
|
+
index.group_by { |x| x[:path] }
|
37
|
+
end
|
38
|
+
|
39
|
+
def detect_paths(paths, indexed)
|
40
|
+
paths.flat_map do |path|
|
41
|
+
next indexed[path] if indexed[path]
|
42
|
+
|
43
|
+
detect_fonts(path)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def detect_fonts(path)
|
48
|
+
case File.extname(path).gsub(/^\./, "").downcase
|
49
|
+
when "ttf", "otf"
|
50
|
+
detect_file_font(path)
|
51
|
+
when "ttc"
|
52
|
+
detect_collection_fonts(path)
|
53
|
+
else
|
54
|
+
raise Errors::UnknownFontTypeError.new(path)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def detect_file_font(path)
|
59
|
+
file = TTFunk::File.open(path)
|
60
|
+
parse_font(file, path)
|
61
|
+
end
|
62
|
+
|
63
|
+
def detect_collection_fonts(path)
|
64
|
+
TTFunk::Collection.open(path) do |collection|
|
65
|
+
collection.map do |file|
|
66
|
+
parse_font(file, path)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def parse_font(file, path)
|
72
|
+
x = file.name
|
73
|
+
|
74
|
+
{
|
75
|
+
path: path,
|
76
|
+
full_name: parse_text(x.font_name.first),
|
77
|
+
family_name: parse_text(x.preferred_family.first || x.font_family.first),
|
78
|
+
type: parse_text(x.preferred_subfamily.first || x.font_subfamily.first),
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
def parse_text(text)
|
83
|
+
text.gsub(/[^[:print:]]/, "").to_s
|
84
|
+
end
|
85
|
+
|
86
|
+
def save_index(index)
|
87
|
+
dir = File.dirname(Fontist.system_index_path)
|
88
|
+
FileUtils.mkdir_p(dir) unless File.exist?(dir)
|
89
|
+
File.write(Fontist.system_index_path, YAML.dump(index))
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/fontist/utils.rb
CHANGED
@@ -2,6 +2,7 @@ require "fontist/utils/ui"
|
|
2
2
|
require "fontist/utils/system"
|
3
3
|
require "fontist/utils/dsl"
|
4
4
|
require "fontist/utils/dsl/font"
|
5
|
+
require "fontist/utils/dsl/collection_font"
|
5
6
|
require "fontist/utils/downloader"
|
6
7
|
require "fontist/utils/zip_extractor"
|
7
8
|
require "fontist/utils/exe_extractor"
|
data/lib/fontist/utils/dsl.rb
CHANGED
@@ -47,6 +47,10 @@ module Fontist
|
|
47
47
|
instance.temp_resource.merge!(filename: name)
|
48
48
|
end
|
49
49
|
|
50
|
+
def source_filename(name)
|
51
|
+
instance.temp_resource.merge!(source_filename: name)
|
52
|
+
end
|
53
|
+
|
50
54
|
def provides_font(font, options = {})
|
51
55
|
font_styles = instance.extract_font_styles(options)
|
52
56
|
instance.font_list.push(name: font, styles: font_styles)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Fontist
|
2
|
+
module Utils
|
3
|
+
module Dsl
|
4
|
+
class CollectionFont
|
5
|
+
REQUIRED_ATTRIBUTES = %i[style].freeze
|
6
|
+
|
7
|
+
attr_reader :attributes
|
8
|
+
|
9
|
+
def initialize(attributes)
|
10
|
+
REQUIRED_ATTRIBUTES.each do |required_attribute|
|
11
|
+
unless attributes[required_attribute]
|
12
|
+
raise(Fontist::Errors::MissingAttributeError.new(
|
13
|
+
"Missing attribute: #{required_attribute}"
|
14
|
+
))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
self.attributes = attributes
|
19
|
+
end
|
20
|
+
|
21
|
+
def attributes=(attrs)
|
22
|
+
@attributes = { family_name: attrs[:family_name],
|
23
|
+
type: attrs[:style],
|
24
|
+
collection: attrs[:full_name],
|
25
|
+
full_name: attrs[:full_name],
|
26
|
+
post_script_name: attrs[:post_script_name],
|
27
|
+
version: attrs[:version],
|
28
|
+
description: attrs[:description],
|
29
|
+
copyright: attrs[:copyright],
|
30
|
+
font: attrs[:filename],
|
31
|
+
source_font: attrs[:source_filename] }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -6,9 +6,9 @@ module Fontist
|
|
6
6
|
|
7
7
|
exe_file = download_file(exe_file).path if download
|
8
8
|
|
9
|
-
Fontist.ui.say(%(Installing font "#{key}".))
|
9
|
+
Fontist.ui.say(%(Installing font "#{formula.key}".))
|
10
10
|
cab_file = decompressor.search(exe_file)
|
11
|
-
cabbed_fonts = grep_fonts(cab_file.files
|
11
|
+
cabbed_fonts = grep_fonts(cab_file.files) || []
|
12
12
|
fonts_paths = extract_cabbed_fonts_to_assets(cabbed_fonts)
|
13
13
|
|
14
14
|
block_given? ? yield(fonts_paths) : fonts_paths
|
@@ -29,10 +29,10 @@ module Fontist
|
|
29
29
|
)
|
30
30
|
end
|
31
31
|
|
32
|
-
def grep_fonts(file
|
32
|
+
def grep_fonts(file)
|
33
33
|
Array.new.tap do |fonts|
|
34
34
|
while file
|
35
|
-
fonts.push(file) if file.filename
|
35
|
+
fonts.push(file) if font_file?(file.filename)
|
36
36
|
file = file.next
|
37
37
|
end
|
38
38
|
end
|
@@ -41,7 +41,8 @@ module Fontist
|
|
41
41
|
def extract_cabbed_fonts_to_assets(cabbed_fonts)
|
42
42
|
Array.new.tap do |fonts|
|
43
43
|
cabbed_fonts.each do |font|
|
44
|
-
|
44
|
+
target_filename = target_filename(font.filename)
|
45
|
+
font_path = fonts_path.join(target_filename).to_s
|
45
46
|
decompressor.extract(font, font_path)
|
46
47
|
|
47
48
|
fonts.push(font_path)
|