nanoc 4.11.14 → 4.11.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/NEWS.md +16 -0
  3. data/lib/nanoc.rb +4 -2
  4. data/lib/nanoc/data_sources/filesystem.rb +9 -3
  5. data/lib/nanoc/extra.rb +1 -0
  6. data/lib/nanoc/extra/core_ext.rb +0 -1
  7. data/lib/nanoc/extra/srcset_parser.rb +79 -0
  8. data/lib/nanoc/filters/erb.rb +1 -5
  9. data/lib/nanoc/filters/relativize_paths.rb +62 -10
  10. data/lib/nanoc/helpers/rendering.rb +5 -4
  11. data/lib/nanoc/orig_cli.rb +0 -5
  12. data/lib/nanoc/rule_dsl.rb +1 -0
  13. data/lib/nanoc/rule_dsl/action_provider.rb +1 -1
  14. data/lib/nanoc/rule_dsl/compiler_dsl.rb +1 -1
  15. data/lib/nanoc/rule_dsl/errors.rb +25 -0
  16. data/lib/nanoc/rule_dsl/rules_loader.rb +1 -1
  17. data/lib/nanoc/version.rb +1 -1
  18. metadata +37 -33
  19. data/lib/nanoc/base.rb +0 -13
  20. data/lib/nanoc/base/changes_stream.rb +0 -53
  21. data/lib/nanoc/base/errors.rb +0 -65
  22. data/lib/nanoc/checking.rb +0 -14
  23. data/lib/nanoc/checking/check.rb +0 -93
  24. data/lib/nanoc/checking/checks.rb +0 -14
  25. data/lib/nanoc/checking/checks/css.rb +0 -16
  26. data/lib/nanoc/checking/checks/external_links.rb +0 -151
  27. data/lib/nanoc/checking/checks/html.rb +0 -16
  28. data/lib/nanoc/checking/checks/internal_links.rb +0 -95
  29. data/lib/nanoc/checking/checks/mixed_content.rb +0 -37
  30. data/lib/nanoc/checking/checks/stale.rb +0 -41
  31. data/lib/nanoc/checking/checks/w3c_validator.rb +0 -31
  32. data/lib/nanoc/checking/dsl.rb +0 -27
  33. data/lib/nanoc/checking/issue.rb +0 -16
  34. data/lib/nanoc/checking/loader.rb +0 -50
  35. data/lib/nanoc/checking/runner.rb +0 -136
  36. data/lib/nanoc/deploying.rb +0 -10
  37. data/lib/nanoc/deploying/deployer.rb +0 -45
  38. data/lib/nanoc/deploying/deployers.rb +0 -11
  39. data/lib/nanoc/deploying/deployers/fog.rb +0 -220
  40. data/lib/nanoc/deploying/deployers/git.rb +0 -112
  41. data/lib/nanoc/deploying/deployers/rsync.rb +0 -68
  42. data/lib/nanoc/extra/core_ext/pathname.rb +0 -27
  43. data/lib/nanoc/orig_cli/commands/check.rb +0 -43
  44. 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
@@ -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
@@ -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
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Nanoc
4
- # @api private
5
- module Deploying
6
- end
7
- end
8
-
9
- require 'nanoc/deploying/deployer'
10
- require 'nanoc/deploying/deployers'