nanoc-checking 1.0.4 → 1.0.6

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: b380e10a13a38c13d712399af8308a0cb67b533094287649eb30283fceba9be3
4
- data.tar.gz: bd6715348e5527f23bedf1812b56bc49d75e5827b5bb318a5165bf5cf689077f
3
+ metadata.gz: 8ab6cbdc1bae780d9287e543d5462a6a6683141c0b0d79ec1d5f1f26e4ed228a
4
+ data.tar.gz: bb4437776e9720dc53935e96d920d2c74cd46b37c6aa020d10203fb64d59212f
5
5
  SHA512:
6
- metadata.gz: 61e31cc485a14e7a75199c65df33d172dd69caad7d00be40725ec55ca5203f052213846b974dd842be2a33d021d10be184a1266810f9fdcddf89db1a7def572d
7
- data.tar.gz: 2472f804af1d3facea1b840d89280070042b27fc03d91475b91db5e41a6783261a84ac62f83d6ea25811112ee85ff045e5a9110bc8ca398f08b4650dcfbc65ae
6
+ metadata.gz: 3efba36b203db266dec8769472a02dd8c8a08922f003cc1a408ae7d9799f2bf61f2a64c5b278507b36cbe70b13018b5a221ac91f3d31ef9b06485bfca65befc7
7
+ data.tar.gz: 894aebf4ae02cfccff5a0b37795781f8ffb1c0a0e46d3f4fb3afc46632717279b8a22691da702040000bc4df6c91c3ce12d1a5660058abcfa9063fe04bcfe7af
data/NEWS.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # nanoc-checking news
2
2
 
3
+ ## 1.0.6 (2025-04-20)
4
+
5
+ Enhancements:
6
+
7
+ - Made checks be run in parallel (#1735) [Jan M. Faber]
8
+
9
+ Fixes:
10
+
11
+ - Restored compatibility with Nanoc 4.13.4
12
+
13
+ ## 1.0.5 (2024-04-21)
14
+
15
+ Fixes:
16
+
17
+ - Fixed support for paths with spaces in internal_links check (#1702)
18
+
3
19
  ## 1.0.4 (2024-04-19)
4
20
 
5
21
  Enhancements:
@@ -39,21 +39,21 @@ module Nanoc
39
39
  view_context =
40
40
  Nanoc::Core::ViewContextForShell.new(
41
41
  items: site.items,
42
- reps: reps,
42
+ reps:,
43
43
  )
44
44
 
45
45
  context = {
46
46
  items: Nanoc::Core::PostCompileItemCollectionView.new(site.items, view_context),
47
47
  layouts: Nanoc::Core::LayoutCollectionView.new(site.layouts, view_context),
48
48
  config: Nanoc::Core::ConfigView.new(site.config, view_context),
49
- output_filenames: output_filenames,
49
+ output_filenames:,
50
50
  }
51
51
 
52
52
  new(context)
53
53
  end
54
54
 
55
55
  def initialize(context)
56
- super(context)
56
+ super
57
57
 
58
58
  @issues = Set.new
59
59
  end
@@ -143,7 +143,7 @@ module Nanoc
143
143
 
144
144
  def request_url_once(url)
145
145
  req = Net::HTTP::Get.new(path_for_url(url))
146
- req['User-Agent'] = "Mozilla/5.0 Nanoc/#{Nanoc::VERSION} (link rot checker)"
146
+ req['User-Agent'] = user_agent
147
147
  http = Net::HTTP.new(url.host, url.port)
148
148
  if url.instance_of? URI::HTTPS
149
149
  http.use_ssl = true
@@ -161,6 +161,20 @@ module Nanoc
161
161
  excludes = @config.fetch(:checks, {}).fetch(:external_links, {}).fetch(:exclude_files, [])
162
162
  excludes.any? { |pattern| Regexp.new(pattern).match(file) }
163
163
  end
164
+
165
+ def user_agent
166
+ @_user_agent ||= custom_user_agent || default_user_agent
167
+ end
168
+
169
+ private
170
+
171
+ def custom_user_agent
172
+ @config.dig(:checks, :external_links, :user_agent)
173
+ end
174
+
175
+ def default_user_agent
176
+ "Mozilla/5.0 Nanoc/#{Nanoc::VERSION} (link rot checker)"
177
+ end
164
178
  end
165
179
  end
166
180
  end
@@ -43,7 +43,8 @@ module Nanoc
43
43
 
44
44
  output_dir = @config.output_dir
45
45
  output_dir += '/' unless output_dir.end_with?('/')
46
- base_uri = URI("file://#{output_dir}")
46
+ # FIXME: escape is hacky
47
+ base_uri = URI("file://#{output_dir.gsub(' ', '%20')}")
47
48
  path = href.sub(/#{base_uri}/, '').sub(/file:\/{1,3}/, '')
48
49
 
49
50
  path = "/#{path}" unless path.start_with?('/')
@@ -10,7 +10,7 @@ module Nanoc
10
10
  class MixedContent < ::Nanoc::Checking::Check
11
11
  identifier :mixed_content
12
12
 
13
- PROTOCOL_PATTERN = /^(\w+):\/\//.freeze
13
+ PROTOCOL_PATTERN = /^(\w+):\/\//
14
14
 
15
15
  def run
16
16
  filenames = output_html_filenames
@@ -22,7 +22,7 @@ module Nanoc
22
22
  protected
23
23
 
24
24
  def item_rep_paths
25
- @item_rep_paths ||=
25
+ @_item_rep_paths ||=
26
26
  Set.new(
27
27
  @items
28
28
  .flat_map(&:reps)
@@ -34,10 +34,12 @@ module Nanoc
34
34
  end
35
35
 
36
36
  def pruner
37
- exclude_config = @config.fetch(:prune, {}).fetch(:exclude, [])
38
- # FIXME: specifying reps this way is icky
39
- reps = Nanoc::Core::ItemRepRepo.new
40
- @pruner ||= Nanoc::Core::Pruner.new(@config._unwrap, reps, exclude: exclude_config)
37
+ @_pruner ||= begin
38
+ exclude_config = @config.fetch(:prune, {}).fetch(:exclude, [])
39
+ # FIXME: specifying reps this way is icky
40
+ reps = Nanoc::Core::ItemRepRepo.new
41
+ Nanoc::Core::Pruner.new(@config._unwrap, reps, exclude: exclude_config)
42
+ end
41
43
  end
42
44
  end
43
45
  end
@@ -7,7 +7,6 @@ module Nanoc
7
7
  class W3CValidator < ::Nanoc::Checking::Check
8
8
  def run
9
9
  require 'w3c_validators'
10
- require 'resolv-replace'
11
10
 
12
11
  Dir[@config.output_dir + '/**/*.' + extension].each do |filename|
13
12
  results = validator_class.new.validate_file(filename)
@@ -19,7 +19,7 @@ module Nanoc
19
19
  runner.run_all
20
20
  elsif options[:deploy]
21
21
  runner.run_for_deploy
22
- elsif arguments.any?
22
+ elsif !arguments.empty?
23
23
  runner.run_specific(arguments)
24
24
  else
25
25
  runner.run_for_deploy
@@ -5,7 +5,7 @@ module Nanoc
5
5
  # @api private
6
6
  class DSL
7
7
  def self.from_file(filename, enabled_checks:)
8
- dsl = new(enabled_checks: enabled_checks)
8
+ dsl = new(enabled_checks:)
9
9
  absolute_filename = File.expand_path(filename)
10
10
  dsl.instance_eval(File.read(filename), absolute_filename)
11
11
  dsl
@@ -15,9 +15,9 @@ module Nanoc
15
15
  @enabled_checks = enabled_checks
16
16
  end
17
17
 
18
- def check(identifier, &block)
18
+ def check(identifier, &)
19
19
  klass = Class.new(::Nanoc::Checking::Check)
20
- klass.send(:define_method, :run, &block)
20
+ klass.send(:define_method, :run, &)
21
21
  klass.send(:identifier, identifier)
22
22
  end
23
23
 
@@ -83,7 +83,8 @@ module ::Nanoc
83
83
 
84
84
  def uris_in_file(filename, tag_names)
85
85
  uris = Set.new
86
- base_uri = URI("file://#{filename}")
86
+ # FIXME: escape is hacky
87
+ base_uri = URI("file://#{filename.gsub(' ', '%20')}")
87
88
  doc = Nokogiri::HTML(::File.read(filename))
88
89
  doc.traverse do |tag|
89
90
  next unless tag_names.nil? || tag_names.include?(tag.name)
@@ -116,7 +117,8 @@ module ::Nanoc
116
117
  uri
117
118
  else
118
119
  begin
119
- URI.join(base_uri, uri).to_s
120
+ # FIXME: escape is hacky
121
+ URI.join(base_uri, uri.gsub(' ', '%20')).to_s
120
122
  rescue
121
123
  uri
122
124
  end
@@ -36,7 +36,7 @@ module Nanoc
36
36
  def dsl
37
37
  @enabled_checks_from_dsl ||= []
38
38
 
39
- @dsl ||=
39
+ @_dsl ||=
40
40
  if dsl_present?
41
41
  Nanoc::Checking::DSL.from_file(checks_filename, enabled_checks: @enabled_checks_from_dsl)
42
42
  else
@@ -6,13 +6,18 @@ module Nanoc
6
6
  #
7
7
  # @api private
8
8
  class Runner
9
+ # Number of threads to use for running checks.
10
+ NUM_THREADS = 5
11
+
9
12
  # @param [Nanoc::Core::Site] site The Nanoc site this runner is for
10
13
  def initialize(site)
11
14
  @site = site
15
+
16
+ @log_mutex = Thread::Mutex.new
12
17
  end
13
18
 
14
19
  def any_enabled_checks?
15
- enabled_checks.any?
20
+ !enabled_checks.empty?
16
21
  end
17
22
 
18
23
  # Lists all available checks on stdout.
@@ -56,7 +61,7 @@ module Nanoc
56
61
  private
57
62
 
58
63
  def loader
59
- @loader ||= Nanoc::Checking::Loader.new(config: @site.config)
64
+ @_loader ||= Nanoc::Checking::Loader.new(config: @site.config)
60
65
  end
61
66
 
62
67
  def load_all
@@ -93,32 +98,83 @@ module Nanoc
93
98
  # TODO: remove me
94
99
  Nanoc::Core::Compiler.new_for(@site).run_until_reps_built
95
100
 
96
- checks = []
97
- issues = Set.new
98
- length = classes.map { |c| c.identifier.to_s.length }.max + 18
99
- classes.each do |klass|
100
- print format(" %-#{length}s", "Running check #{klass.identifier}… ")
101
+ checks = classes.map { _1.create(@site) }
102
+ length = classes.map { _1.identifier.to_s.length }.max
103
+
104
+ puts 'Running checks…'
105
+
106
+ # Create space in terminal to print status of all checks
107
+ classes.count.times { puts }
108
+ cursor_up($stdout, classes.count)
109
+
110
+ # Print all checks (all “pending” for now)
111
+ checks.each_with_index do |check, index|
112
+ log_check(index:, topic: format(" %-#{length}s", check.class.identifier.to_s), state: 'pending')
113
+ end
114
+
115
+ # Run checks in parallel
116
+ Parallel.each_with_index(checks, in_threads: NUM_THREADS) do |check, index|
117
+ log_check(index:, topic: format(" %-#{length}s", check.class.identifier.to_s), state: colorizer.c('running', :blue))
101
118
 
102
- check = klass.create(@site)
103
119
  check.run
104
120
 
105
- checks << check
106
- issues.merge(check.issues)
121
+ state = check.issues.empty? ? colorizer.c('ok', :green) : colorizer.c('error', :red)
122
+ log_check(index:, topic: format(" %-#{length}s", check.class.identifier.to_s), state:)
123
+ end
107
124
 
108
- # TODO: report progress
125
+ # Move cursor to below list
126
+ cursor_down($stdout, checks.count)
109
127
 
110
- puts check.issues.empty? ? 'ok'.green : 'error'.red
128
+ # Collect issues
129
+ issues = Set.new
130
+ checks.each do |check|
131
+ issues.merge(check.issues)
111
132
  end
133
+
112
134
  issues
113
135
  end
114
136
 
137
+ def log_check(index:, topic:, state:)
138
+ @log_mutex.synchronize do
139
+ cursor_down($stdout, index)
140
+
141
+ $stdout << "#{topic} #{state}"
142
+ erase_rest_of_line($stdout)
143
+
144
+ cursor_up($stdout, index)
145
+ go_to_start_of_line($stdout)
146
+ end
147
+ end
148
+
149
+ def cursor_up(io, count)
150
+ return if count.zero?
151
+
152
+ io << "\e[#{count}A"
153
+ end
154
+
155
+ def cursor_down(io, count)
156
+ return if count.zero?
157
+
158
+ io << "\e[#{count}B"
159
+ end
160
+
161
+ def go_to_start_of_line(io)
162
+ io << "\r"
163
+ end
164
+
165
+ def erase_rest_of_line(io)
166
+ io << "\e[K"
167
+ end
168
+
115
169
  def subject_to_s(str)
116
170
  str || '(global)'
117
171
  end
118
172
 
119
- def print_issues(issues)
120
- require 'colored'
173
+ def colorizer
174
+ @_colorizer ||= Nanoc::CLI::ANSIStringColorizer.new($stdout)
175
+ end
121
176
 
177
+ def print_issues(issues)
122
178
  return if issues.empty?
123
179
 
124
180
  puts 'Issues found!'
@@ -129,7 +185,7 @@ module Nanoc
129
185
 
130
186
  puts " #{subject_to_s(subject)}:"
131
187
  issues.each do |i|
132
- puts " [ #{'ERROR'.red} ] #{i.check_class.identifier} - #{i.description}"
188
+ puts " [ #{colorizer.c('ERROR', :red)} ] #{i.check_class.identifier} - #{i.description}"
133
189
  end
134
190
  end
135
191
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Nanoc
4
4
  module Checking
5
- VERSION = '1.0.4'
5
+ VERSION = '1.0.6'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nanoc-checking
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Defreyne
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-04-19 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: nanoc-cli
@@ -83,8 +82,7 @@ licenses:
83
82
  - MIT
84
83
  metadata:
85
84
  rubygems_mfa_required: 'true'
86
- source_code_uri: https://github.com/nanoc/nanoc/tree/nanoc-checking-v1.0.4/nanoc-checking
87
- post_install_message:
85
+ source_code_uri: https://github.com/nanoc/nanoc/tree/nanoc-checking-v1.0.6/nanoc-checking
88
86
  rdoc_options: []
89
87
  require_paths:
90
88
  - lib
@@ -92,15 +90,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
92
90
  requirements:
93
91
  - - ">="
94
92
  - !ruby/object:Gem::Version
95
- version: '2.7'
93
+ version: '3.1'
96
94
  required_rubygems_version: !ruby/object:Gem::Requirement
97
95
  requirements:
98
96
  - - ">="
99
97
  - !ruby/object:Gem::Version
100
98
  version: '0'
101
99
  requirements: []
102
- rubygems_version: 3.5.9
103
- signing_key:
100
+ rubygems_version: 3.6.7
104
101
  specification_version: 4
105
102
  summary: Checking support for Nanoc
106
103
  test_files: []