nanoc 3.4.3 → 3.5.0b1
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.
- data/CONTRIBUTING.md +25 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +22 -13
- data/NEWS.md +27 -0
- data/README.md +3 -1
- data/lib/nanoc.rb +2 -2
- data/lib/nanoc/base/compilation/compiler_dsl.rb +19 -0
- data/lib/nanoc/base/core_ext/array.rb +18 -8
- data/lib/nanoc/base/core_ext/hash.rb +18 -8
- data/lib/nanoc/base/core_ext/pathname.rb +2 -8
- data/lib/nanoc/base/plugin_registry.rb +57 -19
- data/lib/nanoc/base/result_data/item_rep.rb +3 -15
- data/lib/nanoc/base/source_data/item.rb +1 -1
- data/lib/nanoc/base/source_data/layout.rb +1 -1
- data/lib/nanoc/base/source_data/site.rb +15 -19
- data/lib/nanoc/cli.rb +28 -23
- data/lib/nanoc/cli/command_runner.rb +4 -0
- data/lib/nanoc/cli/commands/autocompile.rb +15 -6
- data/lib/nanoc/cli/commands/check.rb +47 -0
- data/lib/nanoc/cli/commands/compile.rb +271 -195
- data/lib/nanoc/cli/commands/create-site.rb +5 -5
- data/lib/nanoc/cli/commands/deploy.rb +16 -4
- data/lib/nanoc/cli/commands/prune.rb +3 -3
- data/lib/nanoc/cli/commands/show-data.rb +73 -58
- data/lib/nanoc/cli/commands/show-rules.rb +1 -1
- data/lib/nanoc/cli/commands/validate-css.rb +2 -3
- data/lib/nanoc/cli/commands/validate-html.rb +2 -3
- data/lib/nanoc/cli/commands/validate-links.rb +5 -11
- data/lib/nanoc/cli/commands/view.rb +1 -1
- data/lib/nanoc/cli/commands/watch.rb +38 -20
- data/lib/nanoc/cli/error_handler.rb +122 -122
- data/lib/nanoc/data_sources.rb +2 -0
- data/lib/nanoc/data_sources/filesystem_unified.rb +1 -1
- data/lib/nanoc/data_sources/filesystem_verbose.rb +1 -1
- data/lib/nanoc/data_sources/static.rb +60 -0
- data/lib/nanoc/extra.rb +2 -0
- data/lib/nanoc/extra/checking.rb +16 -0
- data/lib/nanoc/extra/checking/check.rb +33 -0
- data/lib/nanoc/extra/checking/checks.rb +19 -0
- data/lib/nanoc/extra/checking/checks/css.rb +23 -0
- data/lib/nanoc/extra/checking/checks/external_links.rb +149 -0
- data/lib/nanoc/extra/checking/checks/html.rb +24 -0
- data/lib/nanoc/extra/checking/checks/internal_links.rb +57 -0
- data/lib/nanoc/extra/checking/checks/stale.rb +23 -0
- data/lib/nanoc/extra/checking/dsl.rb +31 -0
- data/lib/nanoc/extra/checking/issue.rb +19 -0
- data/lib/nanoc/extra/checking/runner.rb +130 -0
- data/lib/nanoc/extra/link_collector.rb +57 -0
- data/lib/nanoc/extra/pruner.rb +1 -1
- data/lib/nanoc/extra/validators/links.rb +5 -262
- data/lib/nanoc/extra/validators/w3c.rb +8 -76
- data/lib/nanoc/filters/colorize_syntax.rb +1 -1
- data/lib/nanoc/filters/handlebars.rb +2 -2
- data/lib/nanoc/filters/less.rb +1 -1
- data/lib/nanoc/filters/redcarpet.rb +1 -1
- data/lib/nanoc/filters/rubypants.rb +1 -1
- data/lib/nanoc/filters/slim.rb +1 -1
- data/lib/nanoc/helpers/blogging.rb +163 -104
- data/lib/nanoc/helpers/xml_sitemap.rb +9 -3
- data/tasks/doc.rake +2 -1
- data/test/base/core_ext/array_spec.rb +4 -4
- data/test/base/core_ext/hash_spec.rb +7 -7
- data/test/base/core_ext/pathname_spec.rb +12 -2
- data/test/base/test_compiler_dsl.rb +24 -0
- data/test/base/test_item_rep.rb +58 -26
- data/test/cli/commands/test_watch.rb +0 -8
- data/test/data_sources/test_static.rb +66 -0
- data/test/extra/checking/checks/test_css.rb +40 -0
- data/test/extra/checking/checks/test_external_links.rb +76 -0
- data/test/extra/checking/checks/test_html.rb +40 -0
- data/test/extra/checking/checks/test_internal_links.rb +46 -0
- data/test/extra/checking/checks/test_stale.rb +49 -0
- data/test/extra/checking/test_check.rb +16 -0
- data/test/extra/checking/test_dsl.rb +20 -0
- data/test/extra/checking/test_runner.rb +15 -0
- data/test/extra/test_link_collector.rb +93 -0
- data/test/extra/validators/test_links.rb +0 -64
- data/test/extra/validators/test_w3c.rb +20 -26
- data/test/filters/test_colorize_syntax.rb +15 -0
- data/test/filters/test_less.rb +14 -0
- data/test/filters/test_pandoc.rb +5 -1
- data/test/helpers/test_blogging.rb +52 -8
- data/test/helpers/test_xml_sitemap.rb +68 -0
- data/test/test_gem.rb +1 -1
- metadata +31 -6
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc::Extra::Checking
|
4
|
+
|
5
|
+
class DSL
|
6
|
+
|
7
|
+
attr_reader :deploy_checks
|
8
|
+
|
9
|
+
def self.from_file(filename)
|
10
|
+
dsl = self.new
|
11
|
+
dsl.instance_eval File.read(filename)
|
12
|
+
dsl
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@deploy_checks = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def check(identifier, &block)
|
20
|
+
klass = Class.new(::Nanoc::Extra::Checking::Check)
|
21
|
+
klass.send(:define_method, :run, &block)
|
22
|
+
klass.send(:identifier, identifier)
|
23
|
+
end
|
24
|
+
|
25
|
+
def deploy_check(*identifiers)
|
26
|
+
identifiers.each { |i| @deploy_checks << i }
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc::Extra::Checking
|
4
|
+
|
5
|
+
class Issue
|
6
|
+
|
7
|
+
attr_reader :description
|
8
|
+
attr_reader :subject
|
9
|
+
attr_reader :check_class
|
10
|
+
|
11
|
+
def initialize(desc, subject, check_class)
|
12
|
+
@description = desc
|
13
|
+
@subject = subject
|
14
|
+
@check_class = check_class
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc::Extra::Checking
|
4
|
+
|
5
|
+
# Runner is reponsible for running issue checks.
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class Runner
|
9
|
+
|
10
|
+
# @param [Nanoc::Site] site The nanoc site this runner is for
|
11
|
+
def initialize(site)
|
12
|
+
@site = site
|
13
|
+
end
|
14
|
+
|
15
|
+
# Ensures that there is a deployer DSL present.
|
16
|
+
#
|
17
|
+
# @return [void]
|
18
|
+
def require_dsl
|
19
|
+
if self.dsl.nil?
|
20
|
+
raise Nanoc::Errors::GenericTrivial, "No checks defined (no Checks file present)"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Lists all available checks on stdout.
|
25
|
+
#
|
26
|
+
# @return [void]
|
27
|
+
def list_checks
|
28
|
+
puts "Available checks:"
|
29
|
+
puts
|
30
|
+
puts all_check_classes.map { |i| " " + i.identifier.to_s }.sort.join("\n")
|
31
|
+
end
|
32
|
+
|
33
|
+
# Runs all checks.
|
34
|
+
#
|
35
|
+
# @return [Boolean] true if successful, false otherwise
|
36
|
+
def run_all
|
37
|
+
self.run_check_classes(self.all_check_classes)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Runs the checks marked for deployment.
|
41
|
+
#
|
42
|
+
# @return [Boolean] true if successful, false otherwise
|
43
|
+
def run_for_deploy
|
44
|
+
return true if self.dsl.nil?
|
45
|
+
self.run_check_classes(self.check_classes_named(self.dsl.deploy_checks))
|
46
|
+
end
|
47
|
+
|
48
|
+
# Runs the checks with the given names.
|
49
|
+
#
|
50
|
+
# @param [Array<Symbol>] check_class_names The names of the checks
|
51
|
+
#
|
52
|
+
# @return [Boolean] true if successful, false otherwise
|
53
|
+
def run_specific(check_class_names)
|
54
|
+
self.run_check_classes(self.check_classes_named(check_class_names))
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
|
59
|
+
def dsl
|
60
|
+
@dsl_loaded ||= false
|
61
|
+
if !@dsl_loaded
|
62
|
+
if File.exist?('Checks')
|
63
|
+
@dsl = Nanoc::Extra::Checking::DSL.from_file('Checks')
|
64
|
+
else
|
65
|
+
@dsl = nil
|
66
|
+
end
|
67
|
+
@dsl_loaded = true
|
68
|
+
end
|
69
|
+
@dsl
|
70
|
+
end
|
71
|
+
|
72
|
+
def run_check_classes(classes)
|
73
|
+
issues = self.run_checks(classes)
|
74
|
+
self.print_issues(issues)
|
75
|
+
issues.empty? ? true : false
|
76
|
+
end
|
77
|
+
|
78
|
+
def all_check_classes
|
79
|
+
Nanoc::Extra::Checking::Check.all.map { |p| p.last }.uniq
|
80
|
+
end
|
81
|
+
|
82
|
+
def check_classes_named(n)
|
83
|
+
classes = n.map do |a|
|
84
|
+
klass = Nanoc::Extra::Checking::Check.named(a)
|
85
|
+
raise Nanoc::Errors::GenericTrivial, "Unknown check: #{a}" if klass.nil?
|
86
|
+
klass
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def run_checks(classes)
|
91
|
+
return [] if classes.empty?
|
92
|
+
|
93
|
+
checks = []
|
94
|
+
issues = Set.new
|
95
|
+
length = classes.map { |c| c.identifier.to_s.length }.max + 18
|
96
|
+
classes.each do |klass|
|
97
|
+
print format(" %-#{length}s", "Running #{klass.identifier} check… ")
|
98
|
+
|
99
|
+
check = klass.new(@site)
|
100
|
+
check.run
|
101
|
+
|
102
|
+
checks << check
|
103
|
+
issues.merge(check.issues)
|
104
|
+
|
105
|
+
# TODO report progress
|
106
|
+
|
107
|
+
puts check.issues.empty? ? 'ok'.green : 'error'.red
|
108
|
+
end
|
109
|
+
issues
|
110
|
+
end
|
111
|
+
|
112
|
+
def print_issues(issues)
|
113
|
+
require 'colored'
|
114
|
+
|
115
|
+
return if issues.empty?
|
116
|
+
puts "Issues found!"
|
117
|
+
issues.group_by { |i| i.subject }.to_a.sort_by { |p| p.first }.each do |pair|
|
118
|
+
subject = pair.first
|
119
|
+
issues = pair.last
|
120
|
+
unless issues.empty?
|
121
|
+
puts " #{subject}:"
|
122
|
+
issues.each do |i|
|
123
|
+
puts " [ #{'ERROR'.red} ] #{i.check_class.identifier} - #{i.description}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
module ::Nanoc::Extra
|
6
|
+
|
7
|
+
class LinkCollector
|
8
|
+
|
9
|
+
def initialize(filenames, mode=nil)
|
10
|
+
@filenames = filenames
|
11
|
+
@filter = case mode
|
12
|
+
when nil
|
13
|
+
lambda { |h| true }
|
14
|
+
when :external
|
15
|
+
lambda { |h| external_href?(h) }
|
16
|
+
when :internal
|
17
|
+
lambda { |h| !external_href?(h) }
|
18
|
+
else
|
19
|
+
raise ArgumentError, 'Expected mode argument to be :internal, :external or nil'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def filenames_per_href
|
24
|
+
require 'nokogiri'
|
25
|
+
filenames_per_href = {}
|
26
|
+
@filenames.each do |filename|
|
27
|
+
hrefs_in_file(filename).each do |href|
|
28
|
+
filenames_per_href[href] ||= Set.new
|
29
|
+
filenames_per_href[href] << filename
|
30
|
+
end
|
31
|
+
end
|
32
|
+
filenames_per_href
|
33
|
+
end
|
34
|
+
|
35
|
+
def external_href?(href)
|
36
|
+
!!(href =~ %r{^(\/\/|[a-z\-]+:)})
|
37
|
+
end
|
38
|
+
|
39
|
+
def hrefs_in_file(filename)
|
40
|
+
hrefs_in_file = Set.new
|
41
|
+
doc = Nokogiri::HTML(::File.read(filename))
|
42
|
+
doc.css('a').each { |e| hrefs_in_file << e[:href] unless e[:href].nil? }
|
43
|
+
doc.css('img').each { |e| hrefs_in_file << e[:src] }
|
44
|
+
|
45
|
+
# Convert protocol-relative urls
|
46
|
+
# e.g. //example.com => http://example.com
|
47
|
+
hrefs_in_file.map! { |href| href.gsub /^\/\//, 'http://' }
|
48
|
+
|
49
|
+
# Strip fragment
|
50
|
+
hrefs_in_file.map! { |href| href.gsub(/#.*$/, '') }
|
51
|
+
|
52
|
+
hrefs_in_file.select(&@filter)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
data/lib/nanoc/extra/pruner.rb
CHANGED
@@ -49,7 +49,7 @@ module Nanoc::Extra
|
|
49
49
|
end
|
50
50
|
|
51
51
|
# Remove empty directories
|
52
|
-
present_dirs.
|
52
|
+
present_dirs.each do |dir|
|
53
53
|
next if Dir.foreach(dir) { |n| break true if n !~ /\A\.\.?\z/ }
|
54
54
|
next if filename_excluded?(dir)
|
55
55
|
self.delete_dir(dir)
|
@@ -2,276 +2,19 @@
|
|
2
2
|
|
3
3
|
module Nanoc::Extra::Validators
|
4
4
|
|
5
|
-
#
|
6
|
-
# location that exists.
|
5
|
+
# @deprecated Use the Checking API or the `check` command instead
|
7
6
|
class Links
|
8
7
|
|
9
|
-
# @param [String] dir The directory that will be searched for HTML files
|
10
|
-
# to validate
|
11
|
-
#
|
12
|
-
# @param [Array<String>] index_filenames An array of index filenames that
|
13
|
-
# will be appended to URLs by web servers if a directory is requested
|
14
|
-
# instead of a file
|
15
|
-
#
|
16
|
-
# @option params [Boolean] :internal (false) True if internal links should
|
17
|
-
# be checked; false if they should not
|
18
|
-
#
|
19
|
-
# @option params [Boolean] :external (false) True if external links should
|
20
|
-
# be checked; false if they should not
|
21
8
|
def initialize(dir, index_filenames, params={})
|
22
|
-
@dir = dir
|
23
|
-
@index_filenames = index_filenames
|
24
9
|
@include_internal = params.has_key?(:internal) && params[:internal]
|
25
10
|
@include_external = params.has_key?(:external) && params[:external]
|
26
11
|
end
|
27
12
|
|
28
|
-
# Starts the validator. The results will be printed to stdout.
|
29
|
-
#
|
30
|
-
# @return [void]
|
31
13
|
def run
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
if links.empty?
|
37
|
-
puts "No broken links found!"
|
38
|
-
else
|
39
|
-
links.each_pair do |href, origins|
|
40
|
-
puts "Broken link: #{href} -- referenced from:"
|
41
|
-
origins.each do |origin|
|
42
|
-
puts " #{origin}"
|
43
|
-
end
|
44
|
-
puts
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
# Enumerates all key-value pairs of a given hash in a thread-safe way.
|
52
|
-
#
|
53
|
-
# @api private
|
54
|
-
class ThreadsafeHashEnumerator
|
55
|
-
|
56
|
-
# Creates a new enumerator for the given hash.
|
57
|
-
#
|
58
|
-
# @param [Hash] hash The hash for which the enumerator should return
|
59
|
-
# key-value pairs
|
60
|
-
def initialize(hash)
|
61
|
-
@hash = hash
|
62
|
-
@unprocessed_keys = @hash.keys.dup
|
63
|
-
@mutex = Mutex.new
|
64
|
-
end
|
65
|
-
|
66
|
-
# Returns the next key-value pair in the hash.
|
67
|
-
#
|
68
|
-
# @return [Array] An array containing the key and the corresponding
|
69
|
-
# value of teh next key-value pair
|
70
|
-
def next_pair
|
71
|
-
@mutex.synchronize do
|
72
|
-
key = @unprocessed_keys.shift
|
73
|
-
return (key ? [ key, @hash[key] ] : nil)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
end
|
78
|
-
|
79
|
-
def all_broken_hrefs
|
80
|
-
broken_hrefs = {}
|
81
|
-
|
82
|
-
internal_hrefs = {}
|
83
|
-
external_hrefs = {}
|
84
|
-
|
85
|
-
# Split into internal and external hrefs
|
86
|
-
all_hrefs_per_filename.each_pair do |filename, hrefs|
|
87
|
-
hrefs.each do |href|
|
88
|
-
if is_external_href?(href)
|
89
|
-
external_hrefs[href] ||= []
|
90
|
-
external_hrefs[href] << filename
|
91
|
-
else
|
92
|
-
internal_hrefs[href] ||= []
|
93
|
-
internal_hrefs[href] << filename
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# Validate hrefs
|
99
|
-
validate_internal_hrefs(internal_hrefs, broken_hrefs) if @include_internal
|
100
|
-
validate_external_hrefs(external_hrefs, broken_hrefs) if @include_external
|
101
|
-
|
102
|
-
# Done
|
103
|
-
broken_hrefs
|
104
|
-
end
|
105
|
-
|
106
|
-
def all_files
|
107
|
-
Dir[@dir + '/**/*.html']
|
108
|
-
end
|
109
|
-
|
110
|
-
def all_hrefs_per_filename
|
111
|
-
hrefs = {}
|
112
|
-
all_files.each do |filename|
|
113
|
-
hrefs[filename] ||= all_hrefs_in_file(filename)
|
114
|
-
end
|
115
|
-
hrefs
|
116
|
-
end
|
117
|
-
|
118
|
-
def all_hrefs_in_file(filename)
|
119
|
-
doc = Nokogiri::HTML(::File.read(filename))
|
120
|
-
doc.css('a').map { |l| l[:href] }.compact
|
121
|
-
end
|
122
|
-
|
123
|
-
def is_external_href?(href)
|
124
|
-
!!(href =~ %r{^[a-z\-]+:})
|
125
|
-
end
|
126
|
-
|
127
|
-
def is_valid_internal_href?(href, origin)
|
128
|
-
# Skip hrefs that point to self
|
129
|
-
# FIXME this is ugly and won’t always be correct
|
130
|
-
return true if href == '.'
|
131
|
-
|
132
|
-
# Remove target
|
133
|
-
path = href.sub(/#.*$/, '')
|
134
|
-
return true if path.empty?
|
135
|
-
|
136
|
-
# Make absolute
|
137
|
-
if path[0, 1] == '/'
|
138
|
-
path = @dir + path
|
139
|
-
else
|
140
|
-
path = ::File.expand_path(path, ::File.dirname(origin))
|
141
|
-
end
|
142
|
-
|
143
|
-
# Check whether file exists
|
144
|
-
return true if File.file?(path)
|
145
|
-
|
146
|
-
# Check whether directory with index file exists
|
147
|
-
return true if File.directory?(path) && @index_filenames.any? { |fn| File.file?(File.join(path, fn)) }
|
148
|
-
|
149
|
-
# Nope :(
|
150
|
-
return false
|
151
|
-
end
|
152
|
-
|
153
|
-
def is_valid_external_href?(href)
|
154
|
-
require 'net/http'
|
155
|
-
require 'uri'
|
156
|
-
|
157
|
-
# Parse
|
158
|
-
uri = nil
|
159
|
-
begin
|
160
|
-
uri = URI.parse(href)
|
161
|
-
rescue URI::InvalidURIError
|
162
|
-
@delegate && @delegate.send(:external_href_validated, href, false)
|
163
|
-
return false
|
164
|
-
end
|
165
|
-
|
166
|
-
# Skip non-HTTP URLs
|
167
|
-
return true if uri.scheme !~ /^https?$/
|
168
|
-
|
169
|
-
# Get status
|
170
|
-
status = fetch_http_status_for(uri)
|
171
|
-
is_valid = !status.nil? && status == 200
|
172
|
-
|
173
|
-
# Notify
|
174
|
-
@delegate && @delegate.send(:external_href_validated, href, is_valid)
|
175
|
-
|
176
|
-
# Done
|
177
|
-
is_valid
|
178
|
-
end
|
179
|
-
|
180
|
-
def validate_internal_hrefs(hrefs, broken_hrefs)
|
181
|
-
hrefs.each_pair do |href, filenames|
|
182
|
-
filenames.each do |filename|
|
183
|
-
if !is_valid_internal_href?(href, filename)
|
184
|
-
broken_hrefs[href] = filenames
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
def validate_external_hrefs(hrefs, broken_hrefs)
|
191
|
-
@mutex = Mutex.new
|
192
|
-
|
193
|
-
enum = ThreadsafeHashEnumerator.new(hrefs)
|
194
|
-
|
195
|
-
threads = []
|
196
|
-
10.times do
|
197
|
-
threads << Thread.new do
|
198
|
-
loop do
|
199
|
-
# Get next pair
|
200
|
-
pair = enum.next_pair
|
201
|
-
break if pair.nil?
|
202
|
-
href, filenames = pair[0], pair[1]
|
203
|
-
|
204
|
-
# Validate
|
205
|
-
if !is_valid_external_href?(href)
|
206
|
-
@mutex.synchronize do
|
207
|
-
broken_hrefs[href] = filenames
|
208
|
-
end
|
209
|
-
end
|
210
|
-
end
|
211
|
-
end
|
212
|
-
end
|
213
|
-
threads.each { |t| t.join }
|
214
|
-
end
|
215
|
-
|
216
|
-
def fetch_http_status_for(url, params={})
|
217
|
-
5.times do |i|
|
218
|
-
begin
|
219
|
-
res = nil
|
220
|
-
Timeout::timeout(10) do
|
221
|
-
res = request_url_once(url)
|
222
|
-
end
|
223
|
-
|
224
|
-
if res.code =~ /^3..$/
|
225
|
-
return nil if i == 5
|
226
|
-
|
227
|
-
# Find proper location
|
228
|
-
location = res['Location']
|
229
|
-
if location !~ /^https?:\/\//
|
230
|
-
base_url = url.dup
|
231
|
-
base_url.path = (location =~ /^\// ? '' : '/')
|
232
|
-
base_url.query = nil
|
233
|
-
base_url.fragment = nil
|
234
|
-
location = base_url.to_s + location
|
235
|
-
end
|
236
|
-
|
237
|
-
url = URI.parse(location)
|
238
|
-
else
|
239
|
-
return res.code.to_i
|
240
|
-
end
|
241
|
-
rescue
|
242
|
-
return nil
|
243
|
-
end
|
244
|
-
end
|
245
|
-
end
|
246
|
-
|
247
|
-
def request_url_once(url)
|
248
|
-
require 'net/https'
|
249
|
-
|
250
|
-
path = (url.path.nil? || url.path.empty? ? '/' : url.path)
|
251
|
-
req = Net::HTTP::Head.new(path)
|
252
|
-
http = Net::HTTP.new(url.host, url.port)
|
253
|
-
if url.instance_of? URI::HTTPS
|
254
|
-
http.use_ssl = true
|
255
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
256
|
-
end
|
257
|
-
res = http.request(req)
|
258
|
-
end
|
259
|
-
|
260
|
-
def external_href_validated(href, is_valid)
|
261
|
-
texts = {
|
262
|
-
true => 'ok',
|
263
|
-
false => ' ERROR '
|
264
|
-
}
|
265
|
-
|
266
|
-
colors = {
|
267
|
-
true => "\e[32m",
|
268
|
-
false => "\e[41m\e[37m",
|
269
|
-
:off => "\033[0m"
|
270
|
-
}
|
271
|
-
|
272
|
-
@mutex.synchronize do
|
273
|
-
puts href + ': ' + colors[is_valid] + texts[is_valid] + colors[:off]
|
274
|
-
end
|
14
|
+
checks = []
|
15
|
+
checks << 'ilinks' if options[:internal]
|
16
|
+
checks << 'elinks' if options[:external]
|
17
|
+
Nanoc::CLI.run [ 'check', checks ].flatten
|
275
18
|
end
|
276
19
|
|
277
20
|
end
|