nanoc 4.11.14 → 4.11.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/NEWS.md +16 -0
- data/lib/nanoc.rb +4 -2
- data/lib/nanoc/data_sources/filesystem.rb +9 -3
- data/lib/nanoc/extra.rb +1 -0
- data/lib/nanoc/extra/core_ext.rb +0 -1
- data/lib/nanoc/extra/srcset_parser.rb +79 -0
- data/lib/nanoc/filters/erb.rb +1 -5
- data/lib/nanoc/filters/relativize_paths.rb +62 -10
- data/lib/nanoc/helpers/rendering.rb +5 -4
- data/lib/nanoc/orig_cli.rb +0 -5
- data/lib/nanoc/rule_dsl.rb +1 -0
- data/lib/nanoc/rule_dsl/action_provider.rb +1 -1
- data/lib/nanoc/rule_dsl/compiler_dsl.rb +1 -1
- data/lib/nanoc/rule_dsl/errors.rb +25 -0
- data/lib/nanoc/rule_dsl/rules_loader.rb +1 -1
- data/lib/nanoc/version.rb +1 -1
- metadata +37 -33
- data/lib/nanoc/base.rb +0 -13
- data/lib/nanoc/base/changes_stream.rb +0 -53
- data/lib/nanoc/base/errors.rb +0 -65
- data/lib/nanoc/checking.rb +0 -14
- data/lib/nanoc/checking/check.rb +0 -93
- data/lib/nanoc/checking/checks.rb +0 -14
- data/lib/nanoc/checking/checks/css.rb +0 -16
- data/lib/nanoc/checking/checks/external_links.rb +0 -151
- data/lib/nanoc/checking/checks/html.rb +0 -16
- data/lib/nanoc/checking/checks/internal_links.rb +0 -95
- data/lib/nanoc/checking/checks/mixed_content.rb +0 -37
- data/lib/nanoc/checking/checks/stale.rb +0 -41
- data/lib/nanoc/checking/checks/w3c_validator.rb +0 -31
- data/lib/nanoc/checking/dsl.rb +0 -27
- data/lib/nanoc/checking/issue.rb +0 -16
- data/lib/nanoc/checking/loader.rb +0 -50
- data/lib/nanoc/checking/runner.rb +0 -136
- data/lib/nanoc/deploying.rb +0 -10
- data/lib/nanoc/deploying/deployer.rb +0 -45
- data/lib/nanoc/deploying/deployers.rb +0 -11
- data/lib/nanoc/deploying/deployers/fog.rb +0 -220
- data/lib/nanoc/deploying/deployers/git.rb +0 -112
- data/lib/nanoc/deploying/deployers/rsync.rb +0 -68
- data/lib/nanoc/extra/core_ext/pathname.rb +0 -27
- data/lib/nanoc/orig_cli/commands/check.rb +0 -43
- data/lib/nanoc/orig_cli/commands/deploy.rb +0 -126
@@ -1,95 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Nanoc::Checking::Checks
|
4
|
-
# A check that verifies that all internal links point to a location that exists.
|
5
|
-
#
|
6
|
-
# @api private
|
7
|
-
class InternalLinks < ::Nanoc::Checking::Check
|
8
|
-
identifiers :internal_links, :ilinks
|
9
|
-
|
10
|
-
# Starts the validator. The results will be printed to stdout.
|
11
|
-
#
|
12
|
-
# Internal links that match a regexp pattern in `@config[:checks][:internal_links][:exclude]` will
|
13
|
-
# be skipped.
|
14
|
-
#
|
15
|
-
# @return [void]
|
16
|
-
def run
|
17
|
-
# TODO: de-duplicate this (duplicated in external links check)
|
18
|
-
filenames = output_html_filenames
|
19
|
-
uris = ::Nanoc::Extra::LinkCollector.new(filenames, :internal).filenames_per_href
|
20
|
-
|
21
|
-
uris.each_pair do |href, fns|
|
22
|
-
fns.each do |filename|
|
23
|
-
next if valid?(href, filename)
|
24
|
-
|
25
|
-
add_issue(
|
26
|
-
"broken reference to #{href}",
|
27
|
-
subject: filename,
|
28
|
-
)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
protected
|
34
|
-
|
35
|
-
def valid?(href, origin)
|
36
|
-
# Skip hrefs that point to self
|
37
|
-
# FIXME: this is ugly and won’t always be correct
|
38
|
-
return true if href == '.'
|
39
|
-
|
40
|
-
# Turn file: into output_dir-as-root relative paths
|
41
|
-
|
42
|
-
output_dir = @config.output_dir
|
43
|
-
output_dir += '/' unless output_dir.end_with?('/')
|
44
|
-
base_uri = URI("file://#{output_dir}")
|
45
|
-
path = href.sub(/#{base_uri}/, '').sub(/file:\/{1,3}/, '')
|
46
|
-
|
47
|
-
path = "/#{path}" unless path.start_with?('/')
|
48
|
-
|
49
|
-
# Skip hrefs that are specified in the exclude configuration
|
50
|
-
return true if excluded?(path, origin)
|
51
|
-
|
52
|
-
# Make an absolute path
|
53
|
-
path = ::File.join(output_dir, path[1..path.length])
|
54
|
-
|
55
|
-
# Remove fragment
|
56
|
-
path = path.sub(/#.*$/, '')
|
57
|
-
return true if path.empty?
|
58
|
-
|
59
|
-
# Remove query string
|
60
|
-
path = path.sub(/\?.*$/, '')
|
61
|
-
return true if path.empty?
|
62
|
-
|
63
|
-
# Decode URL (e.g. '%20' -> ' ')
|
64
|
-
path = CGI.unescape(path)
|
65
|
-
|
66
|
-
# Check whether file exists
|
67
|
-
return true if File.file?(path)
|
68
|
-
|
69
|
-
# Check whether directory with index file exists
|
70
|
-
return true if File.directory?(path) && @config[:index_filenames].any? { |fn| File.file?(File.join(path, fn)) }
|
71
|
-
|
72
|
-
# Nope :(
|
73
|
-
false
|
74
|
-
end
|
75
|
-
|
76
|
-
def excluded?(href, origin)
|
77
|
-
config = @config.fetch(:checks, {}).fetch(:internal_links, {})
|
78
|
-
excluded_target?(href, config) || excluded_origin?(origin, config)
|
79
|
-
end
|
80
|
-
|
81
|
-
def excluded_target?(href, config)
|
82
|
-
excludes = config.fetch(:exclude_targets, config.fetch(:exclude, []))
|
83
|
-
excludes.any? { |pattern| Regexp.new(pattern).match(href) }
|
84
|
-
end
|
85
|
-
|
86
|
-
def excluded_origin?(origin, config)
|
87
|
-
# FIXME: do not depend on current working directory
|
88
|
-
origin = File.absolute_path(origin)
|
89
|
-
|
90
|
-
relative_origin = origin[@config.output_dir.size..-1]
|
91
|
-
excludes = config.fetch(:exclude_origins, [])
|
92
|
-
excludes.any? { |pattern| Regexp.new(pattern).match(relative_origin) }
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Nanoc::Checking::Checks
|
4
|
-
# A check that verifies HTML files do not reference external resources with
|
5
|
-
# URLs that would trigger "mixed content" warnings.
|
6
|
-
#
|
7
|
-
# @api private
|
8
|
-
class MixedContent < ::Nanoc::Checking::Check
|
9
|
-
identifier :mixed_content
|
10
|
-
|
11
|
-
PROTOCOL_PATTERN = /^(\w+):\/\//.freeze
|
12
|
-
|
13
|
-
def run
|
14
|
-
filenames = output_html_filenames
|
15
|
-
resource_uris_with_filenames = ::Nanoc::Extra::LinkCollector.new(filenames).filenames_per_resource_uri
|
16
|
-
|
17
|
-
resource_uris_with_filenames.each_pair do |uri, fns|
|
18
|
-
next unless guaranteed_insecure?(uri)
|
19
|
-
|
20
|
-
fns.each do |filename|
|
21
|
-
add_issue(
|
22
|
-
"mixed content include: #{uri}",
|
23
|
-
subject: filename,
|
24
|
-
)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def guaranteed_insecure?(href)
|
32
|
-
protocol = PROTOCOL_PATTERN.match(href)
|
33
|
-
|
34
|
-
protocol && protocol[1].casecmp('http').zero?
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Nanoc::Checking::Checks
|
4
|
-
# @api private
|
5
|
-
class Stale < ::Nanoc::Checking::Check
|
6
|
-
identifier :stale
|
7
|
-
|
8
|
-
def run
|
9
|
-
output_filenames.each do |f|
|
10
|
-
next if pruner.filename_excluded?(f)
|
11
|
-
next if item_rep_paths.include?(f)
|
12
|
-
|
13
|
-
add_issue(
|
14
|
-
'file without matching item',
|
15
|
-
subject: f,
|
16
|
-
)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
protected
|
21
|
-
|
22
|
-
def item_rep_paths
|
23
|
-
@item_rep_paths ||=
|
24
|
-
Set.new(
|
25
|
-
@items
|
26
|
-
.flat_map(&:reps)
|
27
|
-
.map(&:_unwrap)
|
28
|
-
.flat_map(&:raw_paths)
|
29
|
-
.flat_map(&:values)
|
30
|
-
.flatten,
|
31
|
-
)
|
32
|
-
end
|
33
|
-
|
34
|
-
def pruner
|
35
|
-
exclude_config = @config.fetch(:prune, {}).fetch(:exclude, [])
|
36
|
-
# FIXME: specifying reps this way is icky
|
37
|
-
reps = Nanoc::Core::ItemRepRepo.new
|
38
|
-
@pruner ||= Nanoc::Core::Pruner.new(@config._unwrap, reps, exclude: exclude_config)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ::Nanoc::Checking::Checks
|
4
|
-
# @api private
|
5
|
-
class W3CValidator < ::Nanoc::Checking::Check
|
6
|
-
def run
|
7
|
-
require 'w3c_validators'
|
8
|
-
require 'resolv-replace'
|
9
|
-
|
10
|
-
Dir[@config.output_dir + '/**/*.' + extension].each do |filename|
|
11
|
-
results = validator_class.new.validate_file(filename)
|
12
|
-
lines = File.readlines(filename)
|
13
|
-
results.errors.each do |e|
|
14
|
-
line_num = e.line.to_i - 1
|
15
|
-
line = lines[line_num]
|
16
|
-
message = e.message.gsub(%r{\s+}, ' ').strip.sub(/\s+:$/, '')
|
17
|
-
desc = "line #{line_num + 1}: #{message}: #{line}"
|
18
|
-
add_issue(desc, subject: filename)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def extension
|
24
|
-
raise NotImplementedError
|
25
|
-
end
|
26
|
-
|
27
|
-
def validator_class
|
28
|
-
raise NotImplementedError
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
data/lib/nanoc/checking/dsl.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Nanoc::Checking
|
4
|
-
# @api private
|
5
|
-
class DSL
|
6
|
-
def self.from_file(filename, enabled_checks:)
|
7
|
-
dsl = new(enabled_checks: enabled_checks)
|
8
|
-
absolute_filename = File.expand_path(filename)
|
9
|
-
dsl.instance_eval(File.read(filename), absolute_filename)
|
10
|
-
dsl
|
11
|
-
end
|
12
|
-
|
13
|
-
def initialize(enabled_checks:)
|
14
|
-
@enabled_checks = enabled_checks
|
15
|
-
end
|
16
|
-
|
17
|
-
def check(identifier, &block)
|
18
|
-
klass = Class.new(::Nanoc::Checking::Check)
|
19
|
-
klass.send(:define_method, :run, &block)
|
20
|
-
klass.send(:identifier, identifier)
|
21
|
-
end
|
22
|
-
|
23
|
-
def deploy_check(*identifiers)
|
24
|
-
identifiers.each { |i| @enabled_checks << i }
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
data/lib/nanoc/checking/issue.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Nanoc::Checking
|
4
|
-
# @api private
|
5
|
-
class Issue
|
6
|
-
attr_reader :description
|
7
|
-
attr_reader :subject
|
8
|
-
attr_reader :check_class
|
9
|
-
|
10
|
-
def initialize(desc, subject, check_class)
|
11
|
-
@description = desc
|
12
|
-
@subject = subject
|
13
|
-
@check_class = check_class
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Nanoc::Checking
|
4
|
-
# @api private
|
5
|
-
class Loader
|
6
|
-
CHECKS_FILENAMES = ['Checks', 'Checks.rb', 'checks', 'checks.rb'].freeze
|
7
|
-
|
8
|
-
def initialize(config:)
|
9
|
-
@config = config
|
10
|
-
end
|
11
|
-
|
12
|
-
def run
|
13
|
-
dsl
|
14
|
-
end
|
15
|
-
|
16
|
-
def enabled_checks
|
17
|
-
(enabled_checks_from_dsl + enabled_checks_from_config).uniq
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def dsl_present?
|
23
|
-
checks_filename && File.file?(checks_filename)
|
24
|
-
end
|
25
|
-
|
26
|
-
def enabled_checks_from_dsl
|
27
|
-
dsl
|
28
|
-
@enabled_checks_from_dsl
|
29
|
-
end
|
30
|
-
|
31
|
-
def enabled_checks_from_config
|
32
|
-
@config.fetch(:checking, {}).fetch(:enabled_checks, []).map(&:to_sym)
|
33
|
-
end
|
34
|
-
|
35
|
-
def dsl
|
36
|
-
@enabled_checks_from_dsl ||= []
|
37
|
-
|
38
|
-
@dsl ||=
|
39
|
-
if dsl_present?
|
40
|
-
Nanoc::Checking::DSL.from_file(checks_filename, enabled_checks: @enabled_checks_from_dsl)
|
41
|
-
else
|
42
|
-
Nanoc::Checking::DSL.new(enabled_checks: @enabled_checks_from_dsl)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def checks_filename
|
47
|
-
@_checks_filename ||= CHECKS_FILENAMES.find { |f| File.file?(f) }
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,136 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Nanoc::Checking
|
4
|
-
# Runner is reponsible for running issue checks.
|
5
|
-
#
|
6
|
-
# @api private
|
7
|
-
class Runner
|
8
|
-
# @param [Nanoc::Core::Site] site The Nanoc site this runner is for
|
9
|
-
def initialize(site)
|
10
|
-
@site = site
|
11
|
-
end
|
12
|
-
|
13
|
-
def any_enabled_checks?
|
14
|
-
enabled_checks.any?
|
15
|
-
end
|
16
|
-
|
17
|
-
# Lists all available checks on stdout.
|
18
|
-
#
|
19
|
-
# @return [void]
|
20
|
-
def list_checks
|
21
|
-
load_all
|
22
|
-
|
23
|
-
puts 'Available checks:'
|
24
|
-
puts
|
25
|
-
puts all_check_classes.map { |i| ' ' + i.identifier.to_s }.sort.join("\n")
|
26
|
-
end
|
27
|
-
|
28
|
-
# Runs all checks.
|
29
|
-
#
|
30
|
-
# @return [Boolean] true if successful, false otherwise
|
31
|
-
def run_all
|
32
|
-
load_all
|
33
|
-
run_check_classes(all_check_classes)
|
34
|
-
end
|
35
|
-
|
36
|
-
# Runs the checks marked for deployment.
|
37
|
-
#
|
38
|
-
# @return [Boolean] true if successful, false otherwise
|
39
|
-
def run_for_deploy
|
40
|
-
# TODO: rename to #run_enabled
|
41
|
-
load_all
|
42
|
-
run_check_classes(check_classes_named(enabled_checks))
|
43
|
-
end
|
44
|
-
|
45
|
-
# Runs the checks with the given names.
|
46
|
-
#
|
47
|
-
# @param [Array<Symbol>] check_class_names The names of the checks
|
48
|
-
#
|
49
|
-
# @return [Boolean] true if successful, false otherwise
|
50
|
-
def run_specific(check_class_names)
|
51
|
-
load_all
|
52
|
-
run_check_classes(check_classes_named(check_class_names))
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
def loader
|
58
|
-
@loader ||= Nanoc::Checking::Loader.new(config: @site.config)
|
59
|
-
end
|
60
|
-
|
61
|
-
def load_all
|
62
|
-
loader.run
|
63
|
-
end
|
64
|
-
|
65
|
-
def enabled_checks
|
66
|
-
loader.enabled_checks
|
67
|
-
end
|
68
|
-
|
69
|
-
def run_check_classes(classes)
|
70
|
-
issues = run_checks(classes)
|
71
|
-
print_issues(issues)
|
72
|
-
issues.empty? ? true : false
|
73
|
-
end
|
74
|
-
|
75
|
-
def all_check_classes
|
76
|
-
Nanoc::Checking::Check.all
|
77
|
-
end
|
78
|
-
|
79
|
-
def check_classes_named(names)
|
80
|
-
names.map do |name|
|
81
|
-
name = name.to_s.tr('-', '_').to_sym
|
82
|
-
klass = Nanoc::Checking::Check.named(name)
|
83
|
-
raise Nanoc::Core::TrivialError, "Unknown check: #{name}" if klass.nil?
|
84
|
-
|
85
|
-
klass
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def run_checks(classes)
|
90
|
-
return [] if classes.empty?
|
91
|
-
|
92
|
-
# TODO: remove me
|
93
|
-
Nanoc::Core::Compiler.new_for(@site).run_until_reps_built
|
94
|
-
|
95
|
-
checks = []
|
96
|
-
issues = Set.new
|
97
|
-
length = classes.map { |c| c.identifier.to_s.length }.max + 18
|
98
|
-
classes.each do |klass|
|
99
|
-
print format(" %-#{length}s", "Running check #{klass.identifier}… ")
|
100
|
-
|
101
|
-
check = klass.create(@site)
|
102
|
-
check.run
|
103
|
-
|
104
|
-
checks << check
|
105
|
-
issues.merge(check.issues)
|
106
|
-
|
107
|
-
# TODO: report progress
|
108
|
-
|
109
|
-
puts check.issues.empty? ? 'ok'.green : 'error'.red
|
110
|
-
end
|
111
|
-
issues
|
112
|
-
end
|
113
|
-
|
114
|
-
def subject_to_s(str)
|
115
|
-
str || '(global)'
|
116
|
-
end
|
117
|
-
|
118
|
-
def print_issues(issues)
|
119
|
-
require 'colored'
|
120
|
-
|
121
|
-
return if issues.empty?
|
122
|
-
|
123
|
-
puts 'Issues found!'
|
124
|
-
issues.group_by(&:subject).to_a.sort_by { |s| subject_to_s(s.first) }.each do |pair|
|
125
|
-
subject = pair.first
|
126
|
-
issues = pair.last
|
127
|
-
next if issues.empty?
|
128
|
-
|
129
|
-
puts " #{subject_to_s(subject)}:"
|
130
|
-
issues.each do |i|
|
131
|
-
puts " [ #{'ERROR'.red} ] #{i.check_class.identifier} - #{i.description}"
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|