fontist 1.8.9 → 1.9.0

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: 0c34f4a52f1c0842347ebd17811c7550b4eb9e31048bab00077cea20dcd94985
4
- data.tar.gz: 9a5bad3ff72333d3b73673189510f0b739ef1160233235212e6b0c21f5152d2c
3
+ metadata.gz: 46371ff826db31f7fc1c4e5fefca2d6f237f0a874a896dbca6c4c2dbcb937255
4
+ data.tar.gz: dc6a20cb42ce6649791e256a4d6cb8376c29d196c795e2e1869279caa1df8b5a
5
5
  SHA512:
6
- metadata.gz: d8d58465500cd8417d3c164cb791215d6adcfeee358ac60b14d93492d5c6ef1b465cb26236e44ced38566995d61e741ffe1566ad482c491d474ccea9c10fa447
7
- data.tar.gz: f41298a94ffe8d6c2d6f33ff990f9e3c03b6271d580db2a86f48d94bc7dd4776a7c767f7d0d946097782ec00335c716053c90bd88aec4ba3dc274a6e863555bb
6
+ metadata.gz: 7ac9af8e04948c40b1b1fc488f6eeffebd7e598050d59224557f271b1deb328c639a67d153bad08b1a82e3869dda13525647db87e1b04269c0cf5e0b8c0ae295
7
+ data.tar.gz: 680fbde53bf5482ae3e36a720b6e6482cac5a62c29efa1b9962b18c1d51d7e7cafd2ce154c2c484cdfd6211002b413f1df45b909341df1d6ac864585aa590450
@@ -0,0 +1,35 @@
1
+ name: metanorma
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ name: Test on Ruby ${{ matrix.ruby }} ${{ matrix.os }}
11
+ runs-on: ${{ matrix.os }}
12
+ continue-on-error: ${{ matrix.experimental }}
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ ruby: [ '2.5', '2.6', '2.7', '3.0' ]
17
+ os: [ ubuntu-latest, windows-latest, macos-latest ]
18
+ experimental: [ true ]
19
+ steps:
20
+ - uses: actions/checkout@master
21
+ with:
22
+ repository: metanorma/metanorma
23
+
24
+ - uses: actions/checkout@master
25
+ with:
26
+ path: "fontist"
27
+
28
+ - run: 'echo ''gem "fontist", path: "./fontist"'' > Gemfile.devel'
29
+
30
+ - uses: ruby/setup-ruby@v1
31
+ with:
32
+ ruby-version: ${{ matrix.ruby }}
33
+ bundler-cache: true
34
+
35
+ - run: bundle exec rake
@@ -2,7 +2,7 @@ name: rspec
2
2
 
3
3
  on:
4
4
  push:
5
- branches: [ master ]
5
+ branches: [ main ]
6
6
  pull_request:
7
7
 
8
8
  jobs:
@@ -13,19 +13,9 @@ jobs:
13
13
  strategy:
14
14
  fail-fast: false
15
15
  matrix:
16
- ruby: [ '2.4', '2.5', '2.6', '2.7' ]
16
+ ruby: [ '2.4', '2.5', '2.6', '2.7', '3.0' ]
17
17
  os: [ ubuntu-latest, windows-latest, macos-latest ]
18
18
  experimental: [ false ]
19
- # include:
20
- # - ruby: '3.0'
21
- # os: 'ubuntu-latest'
22
- # experimental: true
23
- # - ruby: '3.0'
24
- # os: 'windows-latest'
25
- # experimental: true
26
- # - ruby: '3.0'
27
- # os: 'macos-latest'
28
- # experimental: true
29
19
 
30
20
  steps:
31
21
  - uses: actions/checkout@master
@@ -33,20 +23,11 @@ jobs:
33
23
  - uses: ruby/setup-ruby@v1
34
24
  with:
35
25
  ruby-version: ${{ matrix.ruby }}
36
-
37
- - uses: actions/cache@v1
38
- with:
39
- path: vendor/bundle
40
- key: bundle-v2-${{ matrix.os }}-${{ matrix.ruby }}-${{ hashFiles('**/*.gemspec') }}
41
- restore-keys: bundle-v2-${{ matrix.os }}-${{ matrix.ruby }}
26
+ bundler-cache: true
42
27
 
43
28
  - if: matrix.os == 'macos-latest'
44
29
  run: brew install lcdf-typetools
45
30
 
46
- - run: bundle config set path 'vendor/bundle'
47
-
48
- - run: bundle install --jobs 4 --retry 3
49
-
50
31
  - if: matrix.os == 'macos-latest'
51
32
  run: bundle exec rspec
52
33
  env:
data/.rubocop.yml CHANGED
@@ -9,14 +9,14 @@ AllCops:
9
9
  Rails:
10
10
  Enabled: false
11
11
 
12
- Metrics/LineLength:
12
+ Layout/LineLength:
13
13
  Exclude:
14
14
  - 'lib/fontist/formulas/**/*.rb'
15
15
 
16
- Layout/IndentFirstHashElement:
16
+ Layout/FirstHashElementIndentation:
17
17
  Exclude:
18
18
  - 'lib/fontist/formulas/**/*.rb'
19
19
 
20
- Layout/IndentHeredoc:
20
+ Layout/HeredocIndentation:
21
21
  Exclude:
22
22
  - 'lib/fontist/formulas/**/*.rb'
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Fontist
2
2
 
3
- ![windows](https://github.com/fontist/fontist/workflows/windows/badge.svg)
4
- ![macos](https://github.com/fontist/fontist/workflows/macos/badge.svg)
5
- ![ubuntu](https://github.com/fontist/fontist/workflows/ubuntu/badge.svg)
3
+ [![Build Status](https://github.com/fontist/fontist/actions/workflows/rspec.yml/badge.svg)](https://github.com/fontist/fontist/actions/workflows/rspec.yml)
4
+ [![Gem Version](https://img.shields.io/gem/v/fontist.svg)](https://rubygems.org/gems/fontist)
5
+ [![Pull Requests](https://img.shields.io/github/issues-pr-raw/fontist/fontist.svg)](https://github.com/fontist/fontist/pulls)
6
6
 
7
7
  A simple library to find and download fonts for Windows, Linux and Mac.
8
8
 
@@ -34,6 +34,18 @@ After installation please fetch formulas to your system:
34
34
  fontist update
35
35
  ```
36
36
 
37
+ ### Dependencies
38
+
39
+ Depends on
40
+ [ffi-libarchive-binary](https://github.com/fontist/ffi-libarchive-binary) which
41
+ has the following requirements:
42
+
43
+ * zlib
44
+ * Expat
45
+ * OpenSSL (for Linux only)
46
+
47
+ These dependencies are generally present on all systems.
48
+
37
49
  ## Usage
38
50
 
39
51
  ### Font
@@ -387,6 +399,57 @@ bin/rspec
387
399
  All formulas are kept in the [formulas][fontist-formulas] repository. If you'd
388
400
  like to add a new one or change any existing, please refer to its documentation.
389
401
 
402
+ ### Privare repos
403
+
404
+ There is an ability to use private fonts via private fontist repo. Fontist repo
405
+ is a git repo which contains YAML formula files. Formulas can be created
406
+ manually (see [examples](https://github.com/fontist/formulas/tree/master/Formulas)),
407
+ or [auto-generated from an archive](#auto-generate-a-formula).
408
+
409
+ A corresponding SSH key should be setup with ssh-agent in order to access this private repo.
410
+
411
+ Private fontist repo can be set up with:
412
+
413
+ ```sh
414
+ fontist repo setup NAME URL
415
+ ```
416
+
417
+ E.g.
418
+
419
+ ```sh
420
+ fontist repo setup acme https://example.com/acme/formulas.git
421
+ ```
422
+
423
+ Later, to fetch changes the following command can be used:
424
+
425
+ ```sh
426
+ fontist repo update acme
427
+ ```
428
+
429
+ If there is a need to avoid using these formulas, the repo can be removed with:
430
+
431
+ ```sh
432
+ fontist repo remove acme
433
+ ```
434
+
435
+ ### Private formulas
436
+
437
+ Authorization of private archives in private formulas can be implemented with
438
+ headers. Here is an example which works with Github releases:
439
+
440
+ ```yaml
441
+ resources:
442
+ fonts.zip:
443
+ urls:
444
+ - url: https://example.com/repos/acme/formulas/releases/assets/38777461
445
+ headers:
446
+ Accept: application/octet-stream
447
+ Authorization: token ghp_1234567890abcdefghi
448
+ ```
449
+
450
+ A token can be obtained on [this page](https://github.com/settings/tokens).
451
+ It should have at least the `repo` scope.
452
+
390
453
  ### Auto-generate a formula
391
454
 
392
455
  A formula could be generated from a fonts archive. Just specify a URL to the
@@ -397,20 +460,21 @@ fontist create-formula https://www.latofonts.com/download/lato2ofl-zip/
397
460
  cp lato.yml ~/.fontist/formulas/Formulas/
398
461
  ```
399
462
 
463
+ Though indexes are auto-generated now, maintainers should rebuild indexes
464
+ in the main repo for backward compatibility with fontist prior to 1.9.x versions.
400
465
  A formula index should be rebuild, when a new formula is generated or an
401
466
  existing one changed:
402
467
 
403
468
  ```sh
404
- fontist rebuild-index
469
+ fontist rebuild-index --main-repo
405
470
  ```
406
471
 
407
- Then, both the formula and the updated index should be commited and pushed to
472
+ Then, both the formula and the updated indexes should be commited and pushed to
408
473
  the formula repository:
409
474
 
410
475
  ```sh
411
476
  cd ~/.fontist/formulas
412
- git add Formulas/lato.yml
413
- git add index.yml
477
+ git add Formulas/lato.yml index.yml filename_index.yml
414
478
  git commit -m "Add Lato formula"
415
479
  ```
416
480
 
@@ -429,7 +493,7 @@ repository [formulas][fontist-formulas]:
429
493
 
430
494
  ```
431
495
  cd ~/.fontist/formulas
432
- git add Formulas/google
496
+ git add Formulas/google index.yml filename_index.yml
433
497
  git commit -m "Google Fonts update"
434
498
  git push
435
499
  ```
@@ -442,8 +506,7 @@ can be updated with:
442
506
  ```sh
443
507
  fontist import-sil
444
508
  cd ~/.fontist/formulas
445
- git add Formulas/sil
446
- git add index.yml
509
+ git add Formulas/sil index.yml filename_index.yml
447
510
  git commit -m "SIL fonts update"
448
511
  git push
449
512
  ```
data/fontist.gemspec CHANGED
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.add_runtime_dependency "down", "~> 5.0"
31
31
  spec.add_runtime_dependency "thor", "~> 1.0.1"
32
32
  spec.add_runtime_dependency "git", "~> 1.0"
33
- spec.add_runtime_dependency "ttfunk", "~> 1.6.2"
33
+ spec.add_runtime_dependency "ttfunk", "~> 1.6"
34
34
  spec.add_runtime_dependency "excavate", "~> 0.1"
35
35
 
36
36
  spec.add_development_dependency "extract_ttc", "~> 0.1"
@@ -40,7 +40,7 @@ Gem::Specification.new do |spec|
40
40
  spec.add_development_dependency "nokogiri", "~> 1.0"
41
41
  spec.add_development_dependency "rake", "~> 13"
42
42
  spec.add_development_dependency "rspec", "~> 3.0"
43
- spec.add_development_dependency "rubocop", "0.75.0"
43
+ spec.add_development_dependency "rubocop", "1.5.2"
44
44
  spec.add_development_dependency "rubocop-rails"
45
45
  spec.add_development_dependency "rubocop-performance"
46
46
  spec.add_development_dependency "ruby-protocol-buffers", "~> 1.0"
data/lib/fontist.rb CHANGED
@@ -7,6 +7,7 @@ require "singleton"
7
7
  require "fontist/errors"
8
8
  require "fontist/version"
9
9
 
10
+ require "fontist/repo"
10
11
  require "fontist/font"
11
12
  require "fontist/formula"
12
13
  require "fontist/system_font"
@@ -28,7 +29,11 @@ module Fontist
28
29
  end
29
30
 
30
31
  def self.fontist_path
31
- Pathname.new(ENV["FONTIST_PATH"] || File.join(Dir.home, ".fontist"))
32
+ Pathname.new(ENV["FONTIST_PATH"] || default_fontist_path)
33
+ end
34
+
35
+ def self.default_fontist_path
36
+ Pathname.new(File.join(Dir.home, ".fontist"))
32
37
  end
33
38
 
34
39
  def self.fonts_path
@@ -47,6 +52,10 @@ module Fontist
47
52
  Fontist.formulas_repo_path.join("Formulas")
48
53
  end
49
54
 
55
+ def self.private_formulas_path
56
+ Fontist.formulas_path.join("private")
57
+ end
58
+
50
59
  def self.downloads_path
51
60
  Fontist.fontist_path.join("downloads")
52
61
  end
@@ -60,10 +69,23 @@ module Fontist
60
69
  end
61
70
 
62
71
  def self.formula_index_path
63
- Fontist.formulas_repo_path.join("index.yml")
72
+ @formula_index_path || Fontist.formula_index_dir.join("formula_index.yml")
73
+ end
74
+
75
+ def self.formula_index_path=(path)
76
+ @formula_index_path = path
64
77
  end
65
78
 
66
79
  def self.formula_filename_index_path
67
- Fontist.formulas_repo_path.join("filename_index.yml")
80
+ @formula_filename_index_path ||
81
+ Fontist.formula_index_dir.join("filename_index.yml")
82
+ end
83
+
84
+ def self.formula_filename_index_path=(path)
85
+ @formula_filename_index_path = path
86
+ end
87
+
88
+ def self.formula_index_dir
89
+ Fontist.fontist_path
68
90
  end
69
91
  end
data/lib/fontist/cli.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "thor"
2
+ require "fontist/repo_cli"
2
3
 
3
4
  module Fontist
4
5
  class CLI < Thor
@@ -10,6 +11,8 @@ module Fontist
10
11
  STATUS_MANIFEST_COULD_NOT_BE_FOUND_ERROR = 5
11
12
  STATUS_MANIFEST_COULD_NOT_BE_READ_ERROR = 6
12
13
  STATUS_FONT_INDEX_CORRUPTED = 7
14
+ STATUS_REPO_NOT_FOUND = 8
15
+ STATUS_MAIN_REPO_NOT_FOUND = 9
13
16
 
14
17
  ERROR_TO_STATUS = {
15
18
  Fontist::Errors::UnsupportedFontError => [STATUS_NON_SUPPORTED_FONT_ERROR],
@@ -20,6 +23,8 @@ module Fontist
20
23
  Fontist::Errors::ManifestCouldNotBeReadError => [STATUS_MANIFEST_COULD_NOT_BE_READ_ERROR,
21
24
  "Manifest could not be read."],
22
25
  Fontist::Errors::FontIndexCorrupted => [STATUS_FONT_INDEX_CORRUPTED],
26
+ Fontist::Errors::RepoNotFoundError => [STATUS_REPO_NOT_FOUND],
27
+ Fontist::Errors::MainRepoNotFoundError => [STATUS_MAIN_REPO_NOT_FOUND],
23
28
  }.freeze
24
29
 
25
30
  def self.exit_on_failure?
@@ -31,12 +36,14 @@ module Fontist
31
36
  desc: "Install even if it's already installed in system"
32
37
  option :accept_all_licenses, type: :boolean, aliases: "--confirm-license", desc: "Accept all license agreements"
33
38
  option :hide_licenses, type: :boolean, desc: "Hide license texts"
39
+ option :no_progress, type: :boolean, desc: "Hide download progress"
34
40
  def install(font)
35
41
  Fontist::Font.install(
36
42
  font,
37
43
  force: options[:force],
38
44
  confirmation: options[:accept_all_licenses] ? "yes" : "no",
39
- hide_licenses: options[:hide_licenses]
45
+ hide_licenses: options[:hide_licenses],
46
+ no_progress: options[:no_progress]
40
47
  )
41
48
  success
42
49
  rescue Fontist::Errors::GeneralError => e
@@ -121,11 +128,21 @@ module Fontist
121
128
 
122
129
  desc "rebuild-index", "Rebuild formula index (used by formulas maintainers)"
123
130
  long_desc <<-LONGDESC
124
- This index is pre-built and served with formulas, so there is no need
125
- update it unless something changes in the formulas repo.
131
+ Index should be rebuilt when any formula changes.
132
+
133
+ It is done automatically when formulas are updated, or private formulas
134
+ are set up.
126
135
  LONGDESC
136
+ option :main_repo, type: :boolean,
137
+ desc: "Updates indexes in the main repo (for backward " \
138
+ "compatibility with versions prior to 1.9)"
127
139
  def rebuild_index
128
- Fontist::Index.rebuild
140
+ if options[:main_repo]
141
+ Fontist::Index.rebuild_for_main_repo
142
+ else
143
+ Fontist::Index.rebuild
144
+ end
145
+
129
146
  Fontist.ui.say("Formula index has been rebuilt.")
130
147
  STATUS_SUCCESS
131
148
  end
@@ -136,6 +153,9 @@ module Fontist
136
153
  Fontist::Import::SilImport.new.call
137
154
  end
138
155
 
156
+ desc "repo SUBCOMMAND ...ARGS", "Manage custom repositories"
157
+ subcommand "repo", Fontist::RepoCLI
158
+
139
159
  private
140
160
 
141
161
  def success
@@ -3,17 +3,35 @@ module Fontist
3
3
  class GeneralError < StandardError; end
4
4
 
5
5
  class BinaryCallError < GeneralError; end
6
+
6
7
  class FontIndexCorrupted < GeneralError; end
8
+
7
9
  class FontNotFoundError < GeneralError; end
10
+
11
+ # for backward compatibility with metanorma,
12
+ # it depends on this exception to automatically download formulas
8
13
  class FormulaIndexNotFoundError < GeneralError; end
14
+
15
+ class MainRepoNotFoundError < FormulaIndexNotFoundError; end
16
+
9
17
  class InvalidResourceError < GeneralError; end
18
+
10
19
  class LicensingError < GeneralError; end
20
+
11
21
  class ManifestCouldNotBeFoundError < GeneralError; end
22
+
12
23
  class ManifestCouldNotBeReadError < GeneralError; end
24
+
13
25
  class MissingAttributeError < GeneralError; end
26
+
27
+ class RepoNotFoundError < GeneralError; end
28
+
14
29
  class TamperedFileError < GeneralError; end
30
+
15
31
  class TimeoutError < GeneralError; end
32
+
16
33
  class UnknownFontTypeError < GeneralError; end
34
+
17
35
  class UnknownArchiveError < GeneralError; end
18
36
 
19
37
  class FontError < GeneralError
data/lib/fontist/font.rb CHANGED
@@ -7,6 +7,7 @@ module Fontist
7
7
  @name = options[:name]
8
8
  @confirmation = options[:confirmation] || "no"
9
9
  @hide_licenses = options[:hide_licenses]
10
+ @no_progress = options[:no_progress] || false
10
11
  @force = options[:force] || false
11
12
 
12
13
  check_or_create_fontist_path!
@@ -94,7 +95,7 @@ module Fontist
94
95
  end
95
96
 
96
97
  def font_installer(formula)
97
- FontInstaller.new(formula)
98
+ FontInstaller.new(formula, no_progress: @no_progress)
98
99
  end
99
100
 
100
101
  def formula
@@ -202,9 +203,9 @@ module Fontist
202
203
  end
203
204
 
204
205
  def font_list
205
- return unless formula
206
+ return if formulas.empty?
206
207
 
207
- list_styles([formula])
208
+ list_styles(formulas)
208
209
  end
209
210
 
210
211
  def list_styles(formulas)
@@ -3,8 +3,9 @@ require "excavate"
3
3
 
4
4
  module Fontist
5
5
  class FontInstaller
6
- def initialize(formula)
6
+ def initialize(formula, no_progress: false)
7
7
  @formula = formula
8
+ @no_progress = no_progress
8
9
  end
9
10
 
10
11
  def install(confirmation:)
@@ -53,14 +54,15 @@ module Fontist
53
54
  end
54
55
 
55
56
  def download_file(source)
56
- url = source.urls.first
57
+ request = source.urls.first
58
+ url = request.respond_to?(:url) ? request.url : request
57
59
  Fontist.ui.say(%(Downloading font "#{@formula.key}" from #{url}))
58
60
 
59
61
  Fontist::Utils::Downloader.download(
60
- url,
62
+ request,
61
63
  sha: source.sha256,
62
64
  file_size: source.file_size,
63
- progress_bar: true
65
+ progress_bar: !@no_progress
64
66
  )
65
67
  end
66
68
 
@@ -5,6 +5,9 @@ require "git"
5
5
  module Fontist
6
6
  class Formula
7
7
  def self.update_formulas_repo
8
+ dir = File.dirname(Fontist.formulas_repo_path)
9
+ FileUtils.mkdir_p(dir) unless File.exist?(dir)
10
+
8
11
  if Dir.exist?(Fontist.formulas_repo_path)
9
12
  Git.open(Fontist.formulas_repo_path).pull
10
13
  else
@@ -12,6 +15,8 @@ module Fontist
12
15
  Fontist.formulas_repo_path,
13
16
  depth: 1)
14
17
  end
18
+
19
+ Index.rebuild
15
20
  end
16
21
 
17
22
  def self.all
@@ -14,6 +14,7 @@ module Fontist
14
14
  paths = search_font_paths(s["font"])
15
15
  paths.map do |path|
16
16
  { full_name: s["full_name"],
17
+ type: s["type"],
17
18
  path: path }
18
19
  end
19
20
  end
@@ -4,9 +4,7 @@ module Fontist
4
4
  module SystemHelper
5
5
  class << self
6
6
  def run(command)
7
- unless ENV.fetch("TEST_ENV", "") === "CI"
8
- Fontist.ui.say("Run `#{command}`")
9
- end
7
+ Fontist.ui.say("Run `#{command}`")
10
8
 
11
9
  result = `#{command}`
12
10
  unless $CHILD_STATUS.to_i.zero?
data/lib/fontist/index.rb CHANGED
@@ -3,9 +3,42 @@ require_relative "indexes/filename_index"
3
3
 
4
4
  module Fontist
5
5
  class Index
6
+ def self.rebuild_for_main_repo
7
+ unless Dir.exist?(Fontist.private_formulas_path)
8
+ return do_rebuild_for_main_repo_with
9
+ end
10
+
11
+ Dir.mktmpdir do |dir|
12
+ tmp_private_path = File.join(dir, "private")
13
+ FileUtils.mv(Fontist.private_formulas_path, tmp_private_path)
14
+
15
+ do_rebuild_for_main_repo_with
16
+
17
+ FileUtils.mv(tmp_private_path, Fontist.private_formulas_path)
18
+ end
19
+ end
20
+
21
+ def self.do_rebuild_for_main_repo_with
22
+ Fontist.formula_index_path = Fontist.formulas_repo_path.join("index.yml")
23
+ Fontist.formula_filename_index_path =
24
+ Fontist.formulas_repo_path.join("filename_index.yml")
25
+
26
+ rebuild
27
+
28
+ Fontist.formula_index_path = nil
29
+ Fontist.formula_filename_index_path = nil
30
+ end
31
+
6
32
  def self.rebuild
7
33
  Fontist::Indexes::FontIndex.rebuild
8
34
  Fontist::Indexes::FilenameIndex.rebuild
35
+
36
+ reset_cache
37
+ end
38
+
39
+ def self.reset_cache
40
+ Fontist::Indexes::FontIndex.reset_cache
41
+ Fontist::Indexes::FilenameIndex.reset_cache
9
42
  end
10
43
  end
11
44
  end
@@ -5,10 +5,14 @@ module Fontist
5
5
  class BaseIndex
6
6
  def self.from_yaml
7
7
  @from_yaml ||= begin
8
- unless File.exist?(path)
9
- raise Errors::FormulaIndexNotFoundError.new("Please fetch `#{path}` index with `fontist update`.")
8
+ unless Dir.exist?(Fontist.formulas_repo_path)
9
+ raise Errors::MainRepoNotFoundError.new(
10
+ "Please fetch formulas with `fontist update`.",
11
+ )
10
12
  end
11
13
 
14
+ rebuild unless File.exist?(path)
15
+
12
16
  data = YAML.load_file(path)
13
17
  new(data)
14
18
  end
@@ -18,6 +22,10 @@ module Fontist
18
22
  raise NotImplementedError, "Please define path of an index"
19
23
  end
20
24
 
25
+ def self.reset_cache
26
+ @from_yaml = nil
27
+ end
28
+
21
29
  def self.rebuild
22
30
  index = new
23
31
  index.build
@@ -59,6 +67,8 @@ module Fontist
59
67
  end
60
68
 
61
69
  def to_yaml
70
+ dir = File.dirname(self.class.path)
71
+ FileUtils.mkdir_p(dir) unless File.exist?(dir)
62
72
  File.write(self.class.path, YAML.dump(to_h))
63
73
  end
64
74
 
@@ -3,17 +3,18 @@ require_relative "locations"
3
3
  module Fontist
4
4
  module Manifest
5
5
  class Install < Locations
6
- def initialize(manifest, confirmation: "no", hide_licenses: false)
7
- @manifest = manifest
6
+ def initialize(manifest, confirmation: "no", hide_licenses: false, no_progress: false)
7
+ super(manifest)
8
8
  @confirmation = confirmation
9
9
  @hide_licenses = hide_licenses
10
+ @no_progress = no_progress
10
11
  end
11
12
 
12
13
  private
13
14
 
14
15
  def file_paths(font, style)
15
16
  paths = find_font_with_name(font, style)
16
- return paths unless paths["paths"].empty?
17
+ return paths unless paths.nil?
17
18
 
18
19
  install_font(font)
19
20
 
@@ -21,7 +22,13 @@ module Fontist
21
22
  end
22
23
 
23
24
  def install_font(font)
24
- Fontist::Font.install(font, force: true, confirmation: @confirmation, hide_licenses: @hide_licenses)
25
+ Fontist::Font.install(
26
+ font,
27
+ force: true,
28
+ confirmation: @confirmation,
29
+ hide_licenses: @hide_licenses,
30
+ no_progress: @no_progress
31
+ )
25
32
  end
26
33
  end
27
34
  end
@@ -42,26 +42,40 @@ module Fontist
42
42
  end
43
43
 
44
44
  def style_paths_map(font, names)
45
- paths = style_paths(font, names)
46
- names.zip(paths).to_h
45
+ styles = style_paths(font, names)
46
+ group_paths(styles)
47
47
  end
48
48
 
49
49
  def style_paths(font, names)
50
- names.map do |style|
51
- file_paths(font, style)
50
+ names.flat_map do |style|
51
+ file_paths(font, style) || empty_paths(style)
52
52
  end
53
53
  end
54
54
 
55
+ def group_paths(styles)
56
+ styles.group_by { |s| s[:type] }
57
+ .transform_values { |group| style(group) }
58
+ end
59
+
60
+ def style(styles)
61
+ { "full_name" => styles.first[:full_name],
62
+ "paths" => styles.map { |x| x[:path] } }.compact
63
+ end
64
+
55
65
  def file_paths(font, style)
56
66
  find_font_with_name(font, style).tap do |x|
57
- if x["paths"].empty?
67
+ if x.nil?
58
68
  raise Errors::MissingFontError.new(font, style)
59
69
  end
60
70
  end
61
71
  end
62
72
 
63
73
  def find_font_with_name(font, style)
64
- Fontist::SystemFont.find_with_name(font, style).map { |k, v| [k.to_s, v] }.to_h
74
+ Fontist::SystemFont.find_styles(font, style)
75
+ end
76
+
77
+ def empty_paths(style)
78
+ [{ "full_name" => nil, "type" => style, "path" => nil }]
65
79
  end
66
80
  end
67
81
  end
@@ -0,0 +1,54 @@
1
+ require "git"
2
+
3
+ module Fontist
4
+ class Repo
5
+ class << self
6
+ def setup(name, url)
7
+ ensure_private_formulas_path_exists
8
+ fetch_repo(name, url)
9
+ Index.rebuild
10
+ end
11
+
12
+ def update(name)
13
+ path = repo_path(name)
14
+ unless Dir.exist?(path)
15
+ raise(Errors::RepoNotFoundError, "No such repo '#{name}'.")
16
+ end
17
+
18
+ Git.open(path).pull
19
+ Index.rebuild
20
+ end
21
+
22
+ def remove(name)
23
+ path = repo_path(name)
24
+ unless Dir.exist?(path)
25
+ raise(Errors::RepoNotFoundError, "No such repo '#{name}'.")
26
+ end
27
+
28
+ FileUtils.rm_r(path)
29
+ Index.rebuild
30
+ end
31
+
32
+ private
33
+
34
+ def ensure_private_formulas_path_exists
35
+ Fontist.private_formulas_path.tap do |path|
36
+ FileUtils.mkdir_p(path) unless Dir.exist?(path)
37
+ end
38
+ end
39
+
40
+ def fetch_repo(name, url)
41
+ path = repo_path(name)
42
+ if Dir.exist?(path)
43
+ Git.open(path).pull
44
+ else
45
+ Git.clone(url, path, depth: 1)
46
+ end
47
+ end
48
+
49
+ def repo_path(name)
50
+ Fontist.private_formulas_path.join(name)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,42 @@
1
+ module Fontist
2
+ class RepoCLI < Thor
3
+ desc "setup NAME URL",
4
+ "Setup a custom fontist repo named NAME for the repository at URL"
5
+ def setup(name, url)
6
+ Repo.setup(name, url)
7
+ Fontist.ui.success(
8
+ "Fontist repo '#{name}' from '#{url}' has been successfully set up.",
9
+ )
10
+ CLI::STATUS_SUCCESS
11
+ end
12
+
13
+ desc "update NAME", "Update formulas in a fontist repo named NAME"
14
+ def update(name)
15
+ Repo.update(name)
16
+ Fontist.ui.success(
17
+ "Fontist repo '#{name}' has been successfully updated.",
18
+ )
19
+ CLI::STATUS_SUCCESS
20
+ rescue Errors::RepoNotFoundError
21
+ handle_repo_not_found(name)
22
+ end
23
+
24
+ desc "remove NAME", "Remove fontist repo named NAME"
25
+ def remove(name)
26
+ Repo.remove(name)
27
+ Fontist.ui.success(
28
+ "Fontist repo '#{name}' has been successfully removed.",
29
+ )
30
+ CLI::STATUS_SUCCESS
31
+ rescue Errors::RepoNotFoundError
32
+ handle_repo_not_found(name)
33
+ end
34
+
35
+ private
36
+
37
+ def handle_repo_not_found(name)
38
+ Fontist.ui.error("Fontist repo '#{name}' is not found.")
39
+ CLI::STATUS_REPO_NOT_FOUND
40
+ end
41
+ end
42
+ end
@@ -40,8 +40,8 @@ module Fontist
40
40
  new(font: font, sources: sources).find
41
41
  end
42
42
 
43
- def self.find_with_name(font, style)
44
- new(font: font, style: style).find_with_name
43
+ def self.find_styles(font, style)
44
+ new(font: font, style: style).find_styles
45
45
  end
46
46
 
47
47
  def find
@@ -51,22 +51,14 @@ module Fontist
51
51
  styles.map { |x| x[:path] }
52
52
  end
53
53
 
54
- def find_with_name
55
- styles = find_styles
56
- return { full_name: nil, paths: [] } unless styles
57
-
58
- { full_name: styles.first[:full_name],
59
- paths: styles.map { |x| x[:path] } }
54
+ def find_styles
55
+ find_by_index || find_by_formulas
60
56
  end
61
57
 
62
58
  private
63
59
 
64
60
  attr_reader :font, :style, :user_sources
65
61
 
66
- def find_styles
67
- find_by_index || find_by_formulas
68
- end
69
-
70
62
  def find_by_index
71
63
  SystemIndex.new(all_paths).find(font, style)
72
64
  end
@@ -83,7 +83,7 @@ module Fontist
83
83
  next by_path[path] if by_path[path]
84
84
 
85
85
  detect_fonts(path)
86
- end
86
+ end.compact
87
87
  end
88
88
 
89
89
  def detect_fonts(path)
@@ -100,6 +100,9 @@ module Fontist
100
100
  def detect_file_font(path)
101
101
  file = TTFunk::File.open(path)
102
102
  parse_font(file, path)
103
+ rescue StandardError
104
+ warn $!.message
105
+ warn "Warning: File at #{path} not recognized as a font file."
103
106
  end
104
107
 
105
108
  def detect_collection_fonts(path)
@@ -3,10 +3,10 @@ module Fontist
3
3
  class Cache
4
4
  include Locking
5
5
 
6
- def fetch(key, bar: nil)
6
+ def fetch(key)
7
7
  map = load_cache
8
8
  if cache_exist?(map[key])
9
- print_bar(bar, map[key]) if bar
9
+ print(map[key])
10
10
 
11
11
  return downloaded_file(map[key])
12
12
  end
@@ -17,6 +17,25 @@ module Fontist
17
17
  downloaded_file(path)
18
18
  end
19
19
 
20
+ def delete(key)
21
+ lock(lock_path) do
22
+ map = load_cache
23
+ return unless map[key]
24
+
25
+ value = map.delete(key)
26
+ File.write(cache_map_path, YAML.dump(map))
27
+ value
28
+ end
29
+ end
30
+
31
+ def set(key, value)
32
+ lock(lock_path) do
33
+ map = load_cache
34
+ map[key] = value
35
+ File.write(cache_map_path, YAML.dump(map))
36
+ end
37
+ end
38
+
20
39
  private
21
40
 
22
41
  def cache_map_path
@@ -39,12 +58,12 @@ module Fontist
39
58
  Fontist.downloads_path.join(path)
40
59
  end
41
60
 
42
- def print_bar(bar, path)
43
- File.size(downloaded_path(path)).tap do |size|
44
- bar.total = size
45
- bar.increment(size)
46
- bar.finish("cache")
47
- end
61
+ def print(path)
62
+ Fontist.ui.say("Fetched from cache: #{size(path)} MiB.")
63
+ end
64
+
65
+ def size(path)
66
+ File.size(downloaded_path(path)) / (1024 * 1024)
48
67
  end
49
68
 
50
69
  def save_cache(generated_file, key)
@@ -14,13 +14,13 @@ module Fontist
14
14
  # TODO: If the first mirror fails, try the second one
15
15
  @file = file
16
16
  @sha = [sha].flatten.compact
17
- @file_size = (file_size || default_file_size).to_i
17
+ @file_size = file_size.to_i if file_size
18
18
  @progress_bar = set_progress_bar(progress_bar)
19
19
  @cache = Cache.new
20
20
  end
21
21
 
22
22
  def download
23
- file = @cache.fetch(@file, bar: @progress_bar) do
23
+ file = @cache.fetch(url) do
24
24
  download_file
25
25
  end
26
26
 
@@ -38,10 +38,6 @@ module Fontist
38
38
 
39
39
  attr_reader :file, :sha, :file_size
40
40
 
41
- def default_file_size
42
- 5 * byte_to_megabyte
43
- end
44
-
45
41
  def byte_to_megabyte
46
42
  @byte_to_megabyte ||= 1024 * 1024
47
43
  end
@@ -51,18 +47,19 @@ module Fontist
51
47
  end
52
48
 
53
49
  def set_progress_bar(progress_bar)
54
- if ENV.fetch("TEST_ENV", "") === "CI" || progress_bar
50
+ if progress_bar
55
51
  ProgressBar.new(@file_size)
56
52
  else
57
- NullProgressBar.new
53
+ NullProgressBar.new(@file_size)
58
54
  end
59
55
  end
60
56
 
61
57
  def download_file
62
58
  file = Down.download(
63
- @file,
59
+ url,
64
60
  open_timeout: 10,
65
61
  read_timeout: 10,
62
+ headers: headers,
66
63
  content_length_proc: ->(content_length) {
67
64
  @progress_bar.total = content_length if content_length
68
65
  },
@@ -77,26 +74,26 @@ module Fontist
77
74
  rescue Down::NotFound
78
75
  raise(Fontist::Errors::InvalidResourceError.new("Invalid URL: #{@file}"))
79
76
  end
80
- end
81
-
82
- class NullProgressBar
83
- def total=(_)
84
- # do nothing
85
- end
86
77
 
87
- def increment(_)
88
- # do nothing
78
+ def url
79
+ @file.respond_to?(:url) ? @file.url : @file
89
80
  end
90
81
 
91
- def finish(_ = nil)
92
- # do nothing
82
+ def headers
83
+ @file.respond_to?(:headers) &&
84
+ @file.headers &&
85
+ @file.headers.to_h.map { |k, v| [k.to_s, v] }.to_h || # rubocop:disable Style/HashTransformKeys, Metrics/LineLength
86
+ {}
93
87
  end
94
88
  end
95
89
 
96
90
  class ProgressBar
97
91
  def initialize(total)
98
- @counter = 1
92
+ @counter = 0
99
93
  @total = total
94
+ @printed_percent = -1
95
+ @printed_size = -1
96
+ @start = Time.now
100
97
  end
101
98
 
102
99
  def total=(total)
@@ -105,22 +102,57 @@ module Fontist
105
102
 
106
103
  def increment(progress)
107
104
  @counter = progress
108
- Fontist.ui.print "\r\e[0KDownloads: #{counter_mb}MB/#{total_mb}MB " \
109
- "(#{completeness})"
105
+
106
+ print_incrementally
110
107
  end
111
108
 
112
- def finish(message = nil)
113
- if message
114
- Fontist.ui.print " (#{message})\n"
109
+ def finish
110
+ print
111
+
112
+ Fontist.ui.print(format(", %<mb_per_second>.2f MiB/s, done.\n", mb_per_second: mb_per_second))
113
+ end
114
+
115
+ private
116
+
117
+ def print_incrementally
118
+ if total?
119
+ print_percent_incrementally
115
120
  else
116
- Fontist.ui.print "\n"
121
+ print_size_incrementally
117
122
  end
118
123
  end
119
124
 
120
- private
125
+ def print
126
+ if total?
127
+ print_percent
128
+ else
129
+ print_size
130
+ end
131
+ end
132
+
133
+ def total?
134
+ !!@total
135
+ end
136
+
137
+ def print_percent_incrementally
138
+ return unless percent > @printed_percent
139
+
140
+ print_percent
141
+
142
+ @printed_percent = percent
143
+ end
121
144
 
122
- def completeness
123
- sprintf("%#.2f%%", (@counter.fdiv(@total) * 100)) # rubocop:disable Style/FormatStringToken, Metrics/LineLength
145
+ def print_percent
146
+ # rubocop:disable Style/FormatStringToken
147
+ Fontist.ui.print(format("\r\e[0KDownloading: %<completeness>3d%% (%<counter_mb>d/%<total_mb>d MiB)",
148
+ completeness: percent,
149
+ counter_mb: counter_mb,
150
+ total_mb: total_mb))
151
+ # rubocop:enable Style/FormatStringToken
152
+ end
153
+
154
+ def percent
155
+ (@counter.fdiv(@total) * 100).to_i
124
156
  end
125
157
 
126
158
  def counter_mb
@@ -134,6 +166,28 @@ module Fontist
134
166
  def byte_to_megabyte
135
167
  @byte_to_megabyte ||= 1024 * 1024
136
168
  end
169
+
170
+ def print_size_incrementally
171
+ return unless counter_mb > @printed_size
172
+
173
+ print_size
174
+
175
+ @printed_size = counter_mb
176
+ end
177
+
178
+ def print_size
179
+ Fontist.ui.print(format("\r\e[0KDownloading: %<downloaded>4d MiB", downloaded: counter_mb))
180
+ end
181
+
182
+ def mb_per_second
183
+ @counter / (Time.now - @start) / byte_to_megabyte
184
+ end
185
+ end
186
+
187
+ class NullProgressBar < ProgressBar
188
+ def print_incrementally
189
+ # do nothing
190
+ end
137
191
  end
138
192
  end
139
193
  end
@@ -11,6 +11,7 @@ module Fontist
11
11
  yield
12
12
  ensure
13
13
  f.flock(File::LOCK_UN)
14
+ f.close
14
15
  end
15
16
  end
16
17
  end
@@ -1,3 +1,3 @@
1
1
  module Fontist
2
- VERSION = "1.8.9".freeze
2
+ VERSION = "1.9.0".freeze
3
3
  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.8.9
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-10 00:00:00.000000000 Z
11
+ date: 2021-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: down
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 1.6.2
61
+ version: '1.6'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 1.6.2
68
+ version: '1.6'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: excavate
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -184,14 +184,14 @@ dependencies:
184
184
  requirements:
185
185
  - - '='
186
186
  - !ruby/object:Gem::Version
187
- version: 0.75.0
187
+ version: 1.5.2
188
188
  type: :development
189
189
  prerelease: false
190
190
  version_requirements: !ruby/object:Gem::Requirement
191
191
  requirements:
192
192
  - - '='
193
193
  - !ruby/object:Gem::Version
194
- version: 0.75.0
194
+ version: 1.5.2
195
195
  - !ruby/object:Gem::Dependency
196
196
  name: rubocop-rails
197
197
  requirement: !ruby/object:Gem::Requirement
@@ -243,6 +243,7 @@ extensions: []
243
243
  extra_rdoc_files: []
244
244
  files:
245
245
  - ".github/workflows/check_google.yml"
246
+ - ".github/workflows/metanorma.yml"
246
247
  - ".github/workflows/release.yml"
247
248
  - ".github/workflows/rspec.yml"
248
249
  - ".gitignore"
@@ -301,6 +302,8 @@ files:
301
302
  - lib/fontist/manifest.rb
302
303
  - lib/fontist/manifest/install.rb
303
304
  - lib/fontist/manifest/locations.rb
305
+ - lib/fontist/repo.rb
306
+ - lib/fontist/repo_cli.rb
304
307
  - lib/fontist/system.yml
305
308
  - lib/fontist/system_font.rb
306
309
  - lib/fontist/system_index.rb
@@ -336,7 +339,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
336
339
  - !ruby/object:Gem::Version
337
340
  version: '0'
338
341
  requirements: []
339
- rubygems_version: 3.0.3
342
+ rubygems_version: 3.0.3.1
340
343
  signing_key:
341
344
  specification_version: 4
342
345
  summary: Install openly-licensed fonts on Windows, Linux and Mac!