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.10.0'
Class Method Summary
collapse
Class Method Details
.calculate_coverage ⇒ Object
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
124
|
# File 'lib/deadfinder.rb', line 89
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
35
36
37
|
# File 'lib/deadfinder.rb', line 35
def self.coverage_data
@coverage_data
end
|
.coverage_data=(val) ⇒ Object
39
40
41
|
# File 'lib/deadfinder.rb', line 39
def self.coverage_data=(val)
@coverage_data = val
end
|
.gen_output(options) ⇒ Object
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
# File 'lib/deadfinder.rb', line 126
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)
when 'toml'
output_with_coverage = coverage_info ? { 'dead_links' => output_data, 'coverage' => coverage_info } : output_data
TomlRB.dump(output_with_coverage)
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
|
# File 'lib/deadfinder.rb', line 154
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
26
27
28
|
# File 'lib/deadfinder.rb', line 26
def self.output
@output
end
|
.output=(val) ⇒ Object
30
31
32
|
# File 'lib/deadfinder.rb', line 30
def self.output=(val)
@output = val
end
|
.run_file(filename, options) ⇒ Object
47
48
49
|
# File 'lib/deadfinder.rb', line 47
def self.run_file(filename, options)
run_with_input(options) { File.foreach(filename).map(&:chomp) }
end
|
.run_pipe(options) ⇒ Object
43
44
45
|
# File 'lib/deadfinder.rb', line 43
def self.run_pipe(options)
run_with_input(options) { $stdin.gets&.chomp }
end
|
.run_sitemap(sitemap_url, options) ⇒ Object
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
# File 'lib/deadfinder.rb', line 57
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
51
52
53
54
55
|
# File 'lib/deadfinder.rb', line 51
def self.run_url(url, options)
DeadFinder::Logger.apply_options(options)
run_with_target(url, options)
gen_output(options)
end
|
72
73
74
75
76
77
78
79
80
81
82
|
# File 'lib/deadfinder.rb', line 72
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
84
85
86
87
|
# File 'lib/deadfinder.rb', line 84
def self.run_with_target(target, options, app = Runner.new)
DeadFinder::Logger.target "Fetching #{target}"
app.run(target, options)
end
|