fontist 1.8.9 → 1.9.0

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 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!