fontist 1.4.0 → 1.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -95,8 +95,10 @@ module Fontist
95
95
  styles = options.fetch(:extract_styles_from_collection, [])
96
96
 
97
97
  unless styles.empty?
98
- styles.map do |type, file|
99
- { type: type, collection: file, font: temp_resource[:filename] }
98
+ styles.map do |attributes|
99
+ filenames = temp_resource.slice(:filename, :source_filename)
100
+ Fontist::Utils::Dsl::CollectionFont.new(attributes.merge(filenames))
101
+ .attributes
100
102
  end
101
103
  end
102
104
  end
@@ -109,8 +111,11 @@ module Fontist
109
111
  end
110
112
 
111
113
  def download_file(source)
114
+ url = source[:urls].first
115
+ Fontist.ui.say(%(Downloading font "#{key}" from #{url}))
116
+
112
117
  downloaded_file = Fontist::Utils::Downloader.download(
113
- source[:urls].first,
118
+ url,
114
119
  sha: source[:sha256],
115
120
  file_size: source[:file_size],
116
121
  progress_bar: is_progress_bar_enabled
@@ -121,7 +126,33 @@ module Fontist
121
126
  end
122
127
 
123
128
  def is_progress_bar_enabled
124
- options.nil? ? false : options.fetch(:progress_bar, false)
129
+ options.nil? ? true : options.fetch(:progress_bar, true)
130
+ end
131
+
132
+ def font_file?(filename)
133
+ source_files.include?(filename)
134
+ end
135
+
136
+ def source_files
137
+ @source_files ||= fonts.flat_map do |font|
138
+ font[:styles].map do |style|
139
+ style[:source_font] || style[:font]
140
+ end
141
+ end
142
+ end
143
+
144
+ def target_filename(source_filename)
145
+ target_filenames[source_filename]
146
+ end
147
+
148
+ def target_filenames
149
+ @target_filenames ||= fonts.flat_map do |font|
150
+ font[:styles].map do |style|
151
+ source = style[:source_font] || style[:font]
152
+ target = style[:font]
153
+ [source, target]
154
+ end
155
+ end.to_h
125
156
  end
126
157
  end
127
158
  end
@@ -2,6 +2,7 @@ module Fontist
2
2
  class Formula
3
3
  def initialize(options = {})
4
4
  @font_name = options.fetch(:font_name, nil)
5
+ @style_name = options.fetch(:style_name, nil)
5
6
 
6
7
  check_and_register_font_formulas
7
8
  end
@@ -18,6 +19,10 @@ module Fontist
18
19
  new(font_name: name).find_fonts
19
20
  end
20
21
 
22
+ def self.find_styles(font, style)
23
+ new(font_name: font, style_name: style).find_styles
24
+ end
25
+
21
26
  def all
22
27
  @all ||= Fontist::Registry.instance.formulas
23
28
  end
@@ -32,9 +37,19 @@ module Fontist
32
37
  fonts.empty? ? nil : fonts
33
38
  end
34
39
 
40
+ def find_styles
41
+ formulas.values.flat_map do |formula|
42
+ formula.fonts.flat_map do |f|
43
+ f.styles.select do |s|
44
+ f.name.casecmp?(font_name) && s.type.casecmp?(style_name)
45
+ end
46
+ end
47
+ end
48
+ end
49
+
35
50
  private
36
51
 
37
- attr_reader :font_name
52
+ attr_reader :font_name, :style_name
38
53
 
39
54
  def find_formula
40
55
  find_by_key || find_by_font_name || find_by_font || []
@@ -2,9 +2,10 @@ module Fontist
2
2
  class FormulaTemplate
3
3
  def self.create_formula_class(formula)
4
4
  Class.new(FontFormula) do |klass|
5
- cleanname = formula.fonts.first.name.gsub(/ /, "")
5
+ first_font = (formula.fonts || formula.font_collections.first.fonts).first
6
+ cleanname = first_font.name.gsub(/ /, "")
6
7
  resource_name = formula.resources.to_h.keys.first
7
- font_filename = formula.fonts.first.styles.first.font
8
+ font_filename = first_font.styles.first.font
8
9
 
9
10
  key formula.key&.to_sym || formula.name.gsub(/ /, "_").downcase.to_sym
10
11
  display_progress_bar formula.display_progress_bar if formula.display_progress_bar
@@ -22,31 +23,47 @@ module Fontist
22
23
  formula.font_collections.each do |collection|
23
24
  provides_font_collection do
24
25
  filename collection.filename
26
+ source_filename collection.source_filename
25
27
 
26
28
  collection.fonts.each do |font|
27
- styles = font.styles.map { |s| [s.type, s.full_name] }.to_h
28
- provides_font font.name, extract_styles_from_collection: styles
29
+ provides_font(
30
+ font.name,
31
+ extract_styles_from_collection: font.styles.map do |style|
32
+ {
33
+ family_name: style.family_name,
34
+ style: style.type,
35
+ full_name: style.full_name,
36
+ post_script_name: style.post_script_name,
37
+ version: style.version,
38
+ description: style.description,
39
+ copyright: style.copyright,
40
+ }
41
+ end
42
+ )
29
43
  end
30
44
  end
31
45
  end
32
46
  end
33
47
 
34
- formula.fonts.each do |font|
35
- provides_font(
36
- font.name,
37
- match_styles_from_file: font.styles.map do |style|
38
- {
39
- family_name: style.family_name,
40
- style: style.type,
41
- full_name: style.full_name,
42
- post_script_name: style.post_script_name,
43
- version: style.version,
44
- description: style.description,
45
- filename: style.font,
46
- copyright: style.copyright,
47
- }
48
- end
49
- )
48
+ if formula.fonts
49
+ formula.fonts.each do |font|
50
+ provides_font(
51
+ font.name,
52
+ match_styles_from_file: font.styles.map do |style|
53
+ {
54
+ family_name: style.family_name,
55
+ style: style.type,
56
+ full_name: style.full_name,
57
+ post_script_name: style.post_script_name,
58
+ version: style.version,
59
+ description: style.description,
60
+ filename: style.font,
61
+ source_filename: style.source_font,
62
+ copyright: style.copyright,
63
+ }
64
+ end
65
+ )
66
+ end
50
67
  end
51
68
 
52
69
  klass.define_method :extract do
@@ -61,8 +78,10 @@ module Fontist
61
78
  end
62
79
  end
63
80
 
64
- formula.fonts.each do |font|
65
- match_fonts(resource, font.name)
81
+ if formula.fonts
82
+ formula.fonts.each do |font|
83
+ match_fonts(resource, font.name)
84
+ end
66
85
  end
67
86
 
68
87
  if formula.font_collections
@@ -8,10 +8,6 @@ require_relative "formula_builder"
8
8
  module Fontist
9
9
  module Import
10
10
  class CreateFormula
11
- FONT_PATTERN = /(\.ttf|\.otf)$/i.freeze
12
- FONT_COLLECTION_PATTERN = /\.ttc$/i.freeze
13
- LICENSE_PATTERN = /(OFL\.txt|UFL\.txt|LICENSE\.txt)$/i.freeze
14
-
15
11
  def initialize(url, options = {})
16
12
  @url = url
17
13
  @options = options
@@ -26,41 +22,30 @@ module Fontist
26
22
  def formula
27
23
  builder = FormulaBuilder.new
28
24
  builder.url = @url
29
- builder.archive = download(@url)
30
- builder.extractor = extractor(builder.archive)
25
+ builder.archive = archive
26
+ builder.extractor = extractor
31
27
  builder.options = @options
32
- builder.font_files = font_files(builder.extractor)
33
- builder.font_collection_files = font_collection_files(builder.extractor)
34
- builder.license_text = license_texts(builder.extractor).first
28
+ builder.font_files = extractor.font_files
29
+ builder.font_collection_files = extractor.font_collection_files
30
+ builder.license_text = extractor.license_text
35
31
  builder.formula
36
32
  end
37
33
 
38
- def download(url)
39
- return url if File.exist?(url)
40
-
41
- Fontist::Utils::Downloader.download(url, progress_bar: true).path
34
+ def extractor
35
+ @extractor ||=
36
+ RecursiveExtraction.new(archive,
37
+ subarchive: @options[:subarchive],
38
+ subdir: @options[:subdir])
42
39
  end
43
40
 
44
- def extractor(archive)
45
- RecursiveExtraction.new(archive)
41
+ def archive
42
+ @archive ||= download(@url)
46
43
  end
47
44
 
48
- def font_files(extractor)
49
- extractor.extract(FONT_PATTERN) do |path|
50
- Otf::FontFile.new(path)
51
- end
52
- end
53
-
54
- def font_collection_files(extractor)
55
- extractor.extract(FONT_COLLECTION_PATTERN) do |path|
56
- Files::CollectionFile.new(path)
57
- end
58
- end
45
+ def download(url)
46
+ return url if File.exist?(url)
59
47
 
60
- def license_texts(extractor)
61
- extractor.extract(LICENSE_PATTERN) do |path|
62
- File.read(path)
63
- end
48
+ Fontist::Utils::Downloader.download(url, progress_bar: true).path
64
49
  end
65
50
 
66
51
  def save(hash)
@@ -1,3 +1,4 @@
1
+ require "extract_ttc"
1
2
  require "fontist/import/helpers/system_helper"
2
3
  require_relative "../otf/font_file"
3
4
 
@@ -5,17 +6,20 @@ module Fontist
5
6
  module Import
6
7
  module Files
7
8
  class CollectionFile
8
- STRIP_TTC_BINARY = Fontist.root_path.join("bin", "stripttc")
9
-
10
9
  attr_reader :fonts
11
10
 
12
11
  def initialize(path)
13
12
  @path = path
14
13
  @fonts = read
14
+ @extension = "ttc"
15
15
  end
16
16
 
17
17
  def filename
18
- File.basename(@path)
18
+ File.basename(@path, ".*") + "." + @extension
19
+ end
20
+
21
+ def source_filename
22
+ File.basename(@path) unless filename == File.basename(@path)
19
23
  end
20
24
 
21
25
  private
@@ -37,10 +41,10 @@ module Fontist
37
41
  end
38
42
 
39
43
  def extract_ttfs(tmp_dir)
40
- Helpers::SystemHelper.run("#{STRIP_TTC_BINARY} #{@path}")
41
-
42
- basename = File.basename(@path, ".ttc")
43
- Dir.glob(File.join(tmp_dir, "#{basename}_[0-9][0-9].ttf"))
44
+ filenames = ExtractTtc.extract(@path)
45
+ filenames.map do |filename|
46
+ File.join(tmp_dir, filename)
47
+ end
44
48
  end
45
49
  end
46
50
  end
@@ -0,0 +1,17 @@
1
+ module Fontist
2
+ module Import
3
+ module Files
4
+ class FileRequirement
5
+ def initialize
6
+ `file -v`
7
+ rescue Errno::ENOENT
8
+ abort "`file` is not available. (Or is PATH not setup properly?)"
9
+ end
10
+
11
+ def call(path)
12
+ Helpers::SystemHelper.run("file --brief '#{path}'")
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,48 @@
1
+ require_relative "file_requirement"
2
+
3
+ module Fontist
4
+ module Import
5
+ module Files
6
+ class FontDetector
7
+ REQUIREMENTS = { file: FileRequirement.new }.freeze
8
+
9
+ FONT_LABELS = ["OpenType font data",
10
+ "TrueType Font data"].freeze
11
+
12
+ COLLECTION_LABEL = "TrueType font collection data".freeze
13
+
14
+ FONT_EXTENSIONS = {
15
+ "OpenType font data" => "otf",
16
+ "TrueType Font data" => "ttf",
17
+ "TrueType font collection data" => "ttc",
18
+ }.freeze
19
+
20
+ def self.detect(path)
21
+ brief = file_brief(path)
22
+
23
+ if brief.start_with?(*FONT_LABELS)
24
+ :font
25
+ elsif brief.start_with?(COLLECTION_LABEL)
26
+ :collection
27
+ else
28
+ :other
29
+ end
30
+ end
31
+
32
+ def self.standard_extension(path)
33
+ brief = file_brief(path)
34
+
35
+ FONT_EXTENSIONS.each do |label, extension|
36
+ return extension if brief.start_with?(label)
37
+ end
38
+
39
+ raise Errors::UnknownFontTypeError.new(path)
40
+ end
41
+
42
+ def self.file_brief(path)
43
+ REQUIREMENTS[:file].call(path)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -39,7 +39,7 @@ module Fontist
39
39
 
40
40
  def group_fonts
41
41
  files = (@font_files + @font_collection_files.map(&:fonts)).flatten
42
- raise FontNotFoundError, "No font found" if files.empty?
42
+ raise Errors::FontNotFoundError, "No font found" if files.empty?
43
43
 
44
44
  files
45
45
  end
@@ -55,10 +55,51 @@ module Fontist
55
55
  def resources
56
56
  filename = name.gsub(" ", "_") + "." + @extractor.extension
57
57
 
58
- options = { urls: [@url] + (@options[:mirror] || []),
59
- sha256: Digest::SHA256.file(@archive).to_s }
58
+ { filename => resource_options }
59
+ end
60
+
61
+ def resource_options
62
+ urls = []
63
+ sha = []
64
+ downloads do |url, path|
65
+ urls << url
66
+ sha << Digest::SHA256.file(path).to_s
67
+ end
68
+
69
+ sha = prepare_sha256(sha)
70
+
71
+ { urls: urls, sha256: sha }
72
+ end
73
+
74
+ def downloads
75
+ yield @url, @archive
76
+
77
+ mirrors.each do |url|
78
+ path = download(url)
79
+ next unless path
60
80
 
61
- { filename => options }
81
+ yield url, path
82
+ end
83
+ end
84
+
85
+ def mirrors
86
+ @options[:mirror] || []
87
+ end
88
+
89
+ def download(url)
90
+ Fontist::Utils::Downloader.download(url, progress_bar: true).path
91
+ rescue Errors::InvalidResourceError
92
+ Fontist.ui.error("WARN: a mirror is not found '#{url}'")
93
+ nil
94
+ end
95
+
96
+ def prepare_sha256(input)
97
+ output = input.uniq
98
+ return output.first if output.size == 1
99
+
100
+ checksums = output.join(", ")
101
+ Fontist.ui.error("WARN: SHA256 differs (#{checksums})")
102
+ output
62
103
  end
63
104
 
64
105
  def font_collections
@@ -66,7 +107,10 @@ module Fontist
66
107
 
67
108
  collections = @font_collection_files.map do |file|
68
109
  fonts = fonts_from_files(file.fonts, :to_collection_style)
69
- { filename: file.filename, fonts: fonts }
110
+
111
+ { filename: file.filename,
112
+ source_filename: file.source_filename,
113
+ fonts: fonts }.compact
70
114
  end
71
115
 
72
116
  collections.sort_by do |x|
@@ -106,7 +150,14 @@ module Fontist
106
150
  end
107
151
 
108
152
  def open_license
109
- return unless @license_text
153
+ unless @license_text
154
+ Fontist.ui.error("WARN: please add license manually")
155
+ return
156
+ end
157
+
158
+ Fontist.ui.error("WARN: ensure it's an open license, otherwise " \
159
+ "change the 'open_license' attribute to " \
160
+ "'requires_license_agreement'")
110
161
 
111
162
  TextHelper.cleanup(@license_text)
112
163
  end