nanoc 3.4.3 → 3.5.0b1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|