Module: DeadFinder
- Defined in:
- lib/deadfinder.rb,
lib/deadfinder/cli.rb,
lib/deadfinder/logger.rb,
lib/deadfinder/runner.rb,
lib/deadfinder/version.rb,
lib/deadfinder/completion.rb,
lib/deadfinder/visualizer.rb,
lib/deadfinder/http_client.rb,
lib/deadfinder/url_pattern_matcher.rb
Defined Under Namespace
Modules: Completion, HttpClient, UrlPatternMatcher, Visualizer
Classes: CLI, Logger, Runner
Constant Summary
collapse
- Channel =
Concurrent::Channel
- CACHE_SET =
Concurrent::Map.new
- CACHE_QUE =
Concurrent::Map.new
- VERSION =
'1.9.1'
Class Method Summary
collapse
Class Method Details
.calculate_coverage ⇒ Object
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
# File 'lib/deadfinder.rb', line 88
def self.calculate_coverage
coverage_summary = {}
total_all_tested = 0
total_all_dead = 0
overall_status_counts = Hash.new(0)
coverage_data.each do |target, data|
total = data[:total]
dead = data[:dead]
status_counts = data[:status_counts] || {}
coverage_percentage = total.positive? ? ((dead.to_f / total) * 100).round(2) : 0.0
coverage_summary[target] = {
total_tested: total,
dead_links: dead,
coverage_percentage: coverage_percentage,
status_counts: status_counts
}
total_all_tested += total
total_all_dead += dead
status_counts.each { |code, count| overall_status_counts[code] += count }
end
overall_coverage = total_all_tested.positive? ? ((total_all_dead.to_f / total_all_tested) * 100).round(2) : 0.0
{
targets: coverage_summary,
summary: {
total_tested: total_all_tested,
total_dead: total_all_dead,
overall_coverage_percentage: overall_coverage,
overall_status_counts: overall_status_counts
}
}
end
|
.coverage_data ⇒ Object
34
35
36
|
# File 'lib/deadfinder.rb', line 34
def self.coverage_data
@coverage_data
end
|
.coverage_data=(val) ⇒ Object
38
39
40
|
# File 'lib/deadfinder.rb', line 38
def self.coverage_data=(val)
@coverage_data = val
end
|
.gen_output(options) ⇒ Object
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
# File 'lib/deadfinder.rb', line 125
def self.gen_output(options)
output_data = DeadFinder.output.to_h
format = options['output_format'].to_s.downcase
coverage_info = calculate_coverage if options['coverage'] && coverage_data.any? && coverage_data.values.any? { |v| v[:total].positive? }
unless options['output'].to_s.empty?
content = case format
when 'yaml', 'yml'
output_with_coverage = coverage_info ? { 'dead_links' => output_data, 'coverage' => coverage_info } : output_data
output_with_coverage.to_yaml
when 'csv'
generate_csv(output_data, coverage_info)
else
output_with_coverage = coverage_info ? { 'dead_links' => output_data, 'coverage' => coverage_info } : output_data
JSON.pretty_generate(output_with_coverage)
end
File.write(options['output'], content)
end
return unless options['visualize'] && !options['visualize'].empty? && coverage_info
DeadFinder::Visualizer.generate(coverage_info, options['visualize'])
end
|
.generate_csv(output_data, coverage_info = nil) ⇒ Object
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
# File 'lib/deadfinder.rb', line 150
def self.generate_csv(output_data, coverage_info = nil)
CSV.generate do |csv|
csv << %w[target url]
output_data.each do |target, urls|
Array(urls).each { |url| csv << [target, url] }
end
if coverage_info
csv << [] csv << ['Coverage Report']
csv << %w[target total_tested dead_links coverage_percentage]
coverage_info[:targets].each do |target, data|
csv << [target, data[:total_tested], data[:dead_links], "#{data[:coverage_percentage]}%"]
end
csv << [] csv << ['Overall Summary']
csv << %w[total_tested total_dead overall_coverage_percentage]
summary = coverage_info[:summary]
csv << [summary[:total_tested], summary[:total_dead], "#{summary[:overall_coverage_percentage]}%"]
end
end
end
|
.output ⇒ Object
25
26
27
|
# File 'lib/deadfinder.rb', line 25
def self.output
@output
end
|
.output=(val) ⇒ Object
29
30
31
|
# File 'lib/deadfinder.rb', line 29
def self.output=(val)
@output = val
end
|
.run_file(filename, options) ⇒ Object
46
47
48
|
# File 'lib/deadfinder.rb', line 46
def self.run_file(filename, options)
run_with_input(options) { File.foreach(filename).map(&:chomp) }
end
|
.run_pipe(options) ⇒ Object
42
43
44
|
# File 'lib/deadfinder.rb', line 42
def self.run_pipe(options)
run_with_input(options) { $stdin.gets&.chomp }
end
|
.run_sitemap(sitemap_url, options) ⇒ Object
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
# File 'lib/deadfinder.rb', line 56
def self.run_sitemap(sitemap_url, options)
DeadFinder::Logger.apply_options(options)
app = Runner.new
base_uri = URI(sitemap_url)
sitemap = SitemapParser.new(sitemap_url, recurse: true)
urls = sitemap.to_a
urls = urls.first(options['limit']) if options['limit'].positive?
DeadFinder::Logger.info "Found #{urls.size} URLs from #{sitemap_url}"
urls.each do |url|
turl = generate_url(url, base_uri)
run_with_target(turl, options, app)
end
gen_output(options)
end
|
.run_url(url, options) ⇒ Object
50
51
52
53
54
|
# File 'lib/deadfinder.rb', line 50
def self.run_url(url, options)
DeadFinder::Logger.apply_options(options)
run_with_target(url, options)
gen_output(options)
end
|
71
72
73
74
75
76
77
78
79
80
81
|
# File 'lib/deadfinder.rb', line 71
def self.run_with_input(options)
DeadFinder::Logger.apply_options(options)
DeadFinder::Logger.info 'Reading input'
app = Runner.new
targets = Array(yield)
targets = targets.first(options['limit']) if options['limit'].positive?
targets.each do |target|
run_with_target(target, options, app)
end
gen_output(options)
end
|
.run_with_target(target, options, app = Runner.new) ⇒ Object
83
84
85
86
|
# File 'lib/deadfinder.rb', line 83
def self.run_with_target(target, options, app = Runner.new)
DeadFinder::Logger.target "Fetching #{target}"
app.run(target, options)
end
|