sla 0.3.0 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +61 -35
- data/lib/sla/checker.rb +22 -13
- data/lib/sla/formatters/base.rb +2 -3
- data/lib/sla/formatters/simple.rb +7 -1
- data/lib/sla/formatters/tty.rb +14 -9
- data/lib/sla/formatters/verbose.rb +24 -13
- data/lib/sla/page.rb +68 -63
- data/lib/sla/version.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b7ab0a2c8232984458067a9d9a501011c50c4e6e3c500631a516b2f495b02fa6
|
4
|
+
data.tar.gz: 3d1af9be056a2cabc8dbf39dc37d14795b549f4f4e19803be82663d761eb7e5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10d4a3dd2bcffcba10b4866ab5200dd9ded805c73bc196666efbe827005ea10620180d61667d02e9aa28c809dba07e4ca6d6dd7f2f6fd8668d3c741d526c332f
|
7
|
+
data.tar.gz: 9998c057a56599449bb8077c1fdfba755d70a4877d83a6cbe9d25b243248d6b588d08bdc2c8cb9db87b6ecbf90852a8efde1eb31871e13ed7705d220bbc2484c
|
data/README.md
CHANGED
@@ -1,8 +1,7 @@
|
|
1
|
-
Site Link Analyzer
|
2
|
-
==================================================
|
1
|
+
# Site Link Analyzer
|
3
2
|
|
4
3
|
[![Gem Version](https://badge.fury.io/rb/sla.svg)](https://badge.fury.io/rb/sla)
|
5
|
-
[![Build Status](https://
|
4
|
+
[![Build Status](https://github.com/DannyBen/sla/workflows/Test/badge.svg)](https://github.com/DannyBen/sla/actions?query=workflow%3ATest)
|
6
5
|
[![Maintainability](https://api.codeclimate.com/v1/badges/f78192aead8a74535a24/maintainability)](https://codeclimate.com/github/DannyBen/sla/maintainability)
|
7
6
|
|
8
7
|
---
|
@@ -11,45 +10,58 @@ SLA is a simple broken links checker, with built in caching.
|
|
11
10
|
|
12
11
|
![SLA Demo](demo/cast.svg "SLA Demo")
|
13
12
|
|
14
|
-
Install
|
15
|
-
--------------------------------------------------
|
13
|
+
## Install
|
16
14
|
|
17
|
-
|
15
|
+
### Install using Ruby
|
16
|
+
|
17
|
+
```shell
|
18
18
|
$ gem install sla
|
19
19
|
```
|
20
20
|
|
21
|
+
### Install using Docker
|
22
|
+
|
23
|
+
```shell
|
24
|
+
alias sla='docker run --rm -it --network host -v /tmp/sla_cache:/app/cache dannyben/sla'
|
25
|
+
```
|
26
|
+
|
27
|
+
The `--network host` flag is only necessary if you intend to check links on `localhost`.
|
21
28
|
|
22
|
-
Features
|
23
|
-
--------------------------------------------------
|
29
|
+
## Features
|
24
30
|
|
25
31
|
- Easy to use command line interface.
|
26
32
|
- Built in caching, to avoid overtaxing the server.
|
27
33
|
- Show and save list of broken links to a log file.
|
28
34
|
- Exits with non zero code on failure, for CI integration.
|
29
35
|
|
30
|
-
|
31
|
-
Usage
|
32
|
-
--------------------------------------------------
|
36
|
+
## Usage
|
33
37
|
|
34
38
|
```
|
35
39
|
$ sla --help
|
36
|
-
|
40
|
+
Site Link Analyzer
|
37
41
|
|
38
42
|
Usage:
|
39
|
-
sla
|
40
|
-
sla
|
43
|
+
sla URL [options]
|
44
|
+
sla --help | -h | --version
|
41
45
|
|
42
|
-
Commands:
|
43
|
-
check
|
44
|
-
Start checking for broken links on a given domain.
|
45
|
-
|
46
46
|
Options:
|
47
|
+
--verbose, -v
|
48
|
+
Show detailed output
|
49
|
+
|
50
|
+
--simple, -s
|
51
|
+
Show simple output of errors only
|
52
|
+
|
47
53
|
--depth, -d DEPTH
|
48
|
-
Set crawling depth [default: 5]
|
54
|
+
Set crawling depth [default: 5]
|
55
|
+
|
56
|
+
--external, -x
|
57
|
+
Also check external links
|
58
|
+
|
59
|
+
--ignore, -i URLS
|
60
|
+
Specify a list of space delimited patterns to skip
|
61
|
+
URLs that contain any of the strings in this list will be skipped
|
49
62
|
|
50
63
|
--cache, -c LIFE
|
51
|
-
Set cache life [default: 1d]. LIFE can be in any of the
|
52
|
-
following formats:
|
64
|
+
Set cache life [default: 1d]. LIFE can be in any of the following formats:
|
53
65
|
10 = 10 seconds
|
54
66
|
20s = 20 seconds
|
55
67
|
10m = 10 minutes
|
@@ -57,24 +69,38 @@ Options:
|
|
57
69
|
10d = 10 days
|
58
70
|
|
59
71
|
--cache-dir DIR
|
60
|
-
Set the cache directory
|
72
|
+
Set the cache directory
|
61
73
|
|
62
|
-
--
|
63
|
-
|
74
|
+
-h --help
|
75
|
+
Show this help
|
64
76
|
|
65
|
-
--
|
66
|
-
|
77
|
+
--version
|
78
|
+
Show version number
|
67
79
|
|
68
|
-
|
69
|
-
|
70
|
-
|
80
|
+
Parameters:
|
81
|
+
URL
|
82
|
+
URL to scan
|
83
|
+
|
84
|
+
Environment Variables:
|
85
|
+
SLA_SLEEP
|
86
|
+
Set number of seconds to sleep between calls (for debugging purposes)
|
71
87
|
|
72
88
|
Examples:
|
73
|
-
sla
|
74
|
-
sla
|
75
|
-
sla
|
76
|
-
sla
|
77
|
-
sla
|
78
|
-
sla
|
89
|
+
sla example.com
|
90
|
+
sla example.com -c10m -d10
|
91
|
+
sla example.com --cache-dir my_cache
|
92
|
+
sla example.com --depth 10
|
93
|
+
sla example.com --cache 30d --external
|
94
|
+
sla example.com --simple > out.log
|
95
|
+
sla example.com --ignore "/admin /customer/login"
|
79
96
|
|
80
97
|
```
|
98
|
+
|
99
|
+
## Contributing / Support
|
100
|
+
|
101
|
+
If you experience any issue, have a question or a suggestion, or if you wish
|
102
|
+
to contribute, feel free to [open an issue][issues].
|
103
|
+
|
104
|
+
---
|
105
|
+
|
106
|
+
[issues]: https://github.com/DannyBen/sla/issues
|
data/lib/sla/checker.rb
CHANGED
@@ -8,23 +8,12 @@ module SLA
|
|
8
8
|
@check_external = check_external
|
9
9
|
end
|
10
10
|
|
11
|
-
def deeply_checked
|
12
|
-
@deeply_checked ||= {}
|
13
|
-
end
|
14
|
-
|
15
|
-
def checked
|
16
|
-
@checked ||= {}
|
17
|
-
end
|
18
|
-
|
19
11
|
def check(page, &block)
|
20
|
-
return if
|
21
|
-
return if page.depth >= max_depth
|
22
|
-
return unless page.valid?
|
12
|
+
return if skip? page
|
23
13
|
|
24
14
|
yield [:source, page] if block_given?
|
25
15
|
|
26
|
-
pages = page
|
27
|
-
pages.reject! { |page| page.external? } if !check_external
|
16
|
+
pages = page_list page
|
28
17
|
|
29
18
|
pages.each do |page|
|
30
19
|
if checked.has_key? page.url or ignore? page
|
@@ -45,6 +34,18 @@ module SLA
|
|
45
34
|
|
46
35
|
private
|
47
36
|
|
37
|
+
def page_list(page)
|
38
|
+
if check_external
|
39
|
+
page.pages
|
40
|
+
else
|
41
|
+
page.pages.reject { |page| page.external? }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def skip?(page)
|
46
|
+
ignore?(page) or page.depth >= max_depth or !page.valid?
|
47
|
+
end
|
48
|
+
|
48
49
|
def ignore?(page)
|
49
50
|
return false unless ignore
|
50
51
|
|
@@ -55,6 +56,14 @@ module SLA
|
|
55
56
|
false
|
56
57
|
end
|
57
58
|
|
59
|
+
def deeply_checked
|
60
|
+
@deeply_checked ||= {}
|
61
|
+
end
|
62
|
+
|
63
|
+
def checked
|
64
|
+
@checked ||= {}
|
65
|
+
end
|
66
|
+
|
58
67
|
end
|
59
68
|
end
|
60
69
|
|
data/lib/sla/formatters/base.rb
CHANGED
@@ -10,15 +10,21 @@ module SLA
|
|
10
10
|
@count += 1
|
11
11
|
|
12
12
|
return if page.valid?
|
13
|
-
|
14
13
|
@failed += 1
|
15
14
|
|
15
|
+
show_status page
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def show_status(page)
|
16
21
|
if last_source
|
17
22
|
say "!txtpur!SOURCE #{last_source}"
|
18
23
|
@last_source = nil
|
19
24
|
end
|
20
25
|
|
21
26
|
say " !txtred!FAIL!txtrst! #{page.depth} #{page.url}"
|
27
|
+
say " !txtred!#{page.code}!txtrst! #{page.error}" unless page.code == 404
|
22
28
|
end
|
23
29
|
|
24
30
|
end
|
data/lib/sla/formatters/tty.rb
CHANGED
@@ -1,16 +1,25 @@
|
|
1
1
|
module SLA
|
2
2
|
module Formatters
|
3
3
|
class TTY < Base
|
4
|
-
attr_reader :last_source
|
4
|
+
attr_reader :last_source, :screen_width
|
5
5
|
|
6
6
|
def handle(action, page)
|
7
|
-
screen_width = terminal_width
|
8
|
-
|
7
|
+
@screen_width = terminal_width
|
9
8
|
@last_source = page.url if action == :source
|
10
9
|
|
11
10
|
return unless action == :check
|
12
11
|
@count += 1
|
13
12
|
|
13
|
+
show_status page
|
14
|
+
end
|
15
|
+
|
16
|
+
def footer_prefix
|
17
|
+
terminal? ? "\033[2K\n" : "\n"
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def show_status(page)
|
14
23
|
if page.valid?
|
15
24
|
status = "PASS"
|
16
25
|
color = "!txtgrn!"
|
@@ -25,6 +34,7 @@ module SLA
|
|
25
34
|
end
|
26
35
|
|
27
36
|
resay " !txtred!FAIL!txtrst! #{page.depth} #{page.url}"
|
37
|
+
resay " !txtred!#{page.code}!txtrst! #{page.error}" unless page.code == 404
|
28
38
|
end
|
29
39
|
|
30
40
|
message = "[#{failed}/#{count} @ #{page.depth}] #{status}"
|
@@ -33,11 +43,6 @@ module SLA
|
|
33
43
|
resay "[#{failed}/#{count} @ #{page.depth}] #{color}#{status}!txtrst! #{url} "
|
34
44
|
end
|
35
45
|
|
36
|
-
def footer_prefix
|
37
|
-
terminal? ? "\033[2K\n" : "\n"
|
38
|
-
end
|
39
|
-
|
40
|
-
|
41
46
|
end
|
42
47
|
end
|
43
|
-
end
|
48
|
+
end
|
@@ -5,26 +5,37 @@ module SLA
|
|
5
5
|
case action
|
6
6
|
when :source
|
7
7
|
say "\n!txtpur!SOURCE #{page.url}"
|
8
|
-
|
8
|
+
|
9
9
|
when :check
|
10
|
-
|
11
|
-
|
12
|
-
if page.valid?
|
13
|
-
status = "PASS"
|
14
|
-
color = "!txtgrn!"
|
15
|
-
else
|
16
|
-
@failed += 1
|
17
|
-
status = "FAIL"
|
18
|
-
color = "!txtred!"
|
19
|
-
end
|
20
|
-
|
21
|
-
say " #{color}#{status}!txtrst! #{page.depth} #{page.url}"
|
10
|
+
show_check_status page
|
22
11
|
|
23
12
|
when :skip
|
24
13
|
say " !txtblu!SKIP!txtrst! #{page.depth} #{page.url}"
|
25
14
|
|
26
15
|
end
|
27
16
|
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def show_check_status(page)
|
21
|
+
@count += 1
|
22
|
+
|
23
|
+
show_error = false
|
24
|
+
|
25
|
+
if page.valid?
|
26
|
+
status = "PASS"
|
27
|
+
color = "!txtgrn!"
|
28
|
+
else
|
29
|
+
@failed += 1
|
30
|
+
status = "FAIL"
|
31
|
+
color = "!txtred!"
|
32
|
+
show_error = page.code != 404
|
33
|
+
end
|
34
|
+
|
35
|
+
say " #{color}#{status}!txtrst! #{page.depth} #{page.url}"
|
36
|
+
say " !txtred!#{page.code}!txtrst! #{page.error}" if show_error
|
37
|
+
end
|
38
|
+
|
28
39
|
end
|
29
40
|
end
|
30
41
|
end
|
data/lib/sla/page.rb
CHANGED
@@ -1,83 +1,88 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
module SLA
|
2
|
+
class Page
|
3
|
+
attr_reader :uri, :parent, :depth
|
4
|
+
|
5
|
+
def initialize(uri, parent: nil, depth: 0)
|
6
|
+
if uri.is_a? String
|
7
|
+
uri = "http://#{uri}" unless uri.start_with? 'http'
|
8
|
+
uri = URI.parse uri
|
9
|
+
uri.fragment = false
|
10
|
+
end
|
11
|
+
|
12
|
+
@uri, @parent, @depth = uri, parent, depth
|
9
13
|
end
|
10
14
|
|
11
|
-
|
12
|
-
|
15
|
+
def error
|
16
|
+
response.error
|
17
|
+
end
|
13
18
|
|
14
|
-
|
15
|
-
|
16
|
-
|
19
|
+
def code
|
20
|
+
response.code || 'ERR'
|
21
|
+
end
|
17
22
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
23
|
+
def external?
|
24
|
+
parent ? (uri.host != parent.uri.host) : false
|
25
|
+
end
|
22
26
|
|
23
|
-
|
24
|
-
|
25
|
-
|
27
|
+
def inspect
|
28
|
+
"#<Page url: #{url}, depth: #{depth}>"
|
29
|
+
end
|
26
30
|
|
27
|
-
|
28
|
-
|
29
|
-
|
31
|
+
def pages
|
32
|
+
@pages ||= pages!
|
33
|
+
end
|
30
34
|
|
31
|
-
|
32
|
-
|
33
|
-
|
35
|
+
def url
|
36
|
+
uri.to_s
|
37
|
+
end
|
34
38
|
|
35
|
-
|
36
|
-
|
37
|
-
|
39
|
+
def valid?
|
40
|
+
!response.error
|
41
|
+
end
|
38
42
|
|
39
|
-
private
|
43
|
+
private
|
40
44
|
|
41
|
-
|
42
|
-
|
43
|
-
|
45
|
+
def anchors
|
46
|
+
@anchors ||= dom.css('a[href]')
|
47
|
+
end
|
44
48
|
|
45
|
-
|
46
|
-
|
47
|
-
|
49
|
+
def content
|
50
|
+
@content ||= response.content
|
51
|
+
end
|
48
52
|
|
49
|
-
|
50
|
-
|
51
|
-
|
53
|
+
def dom
|
54
|
+
@dom ||= Nokogiri::HTML content
|
55
|
+
end
|
52
56
|
|
53
|
-
|
54
|
-
|
55
|
-
|
57
|
+
def normalize_url(new_url)
|
58
|
+
new_url = URI.parse new_url
|
59
|
+
new_url.fragment = false
|
56
60
|
|
57
|
-
|
61
|
+
result = new_url.absolute? ? new_url : URI.join(url, new_url)
|
58
62
|
|
59
|
-
|
60
|
-
|
63
|
+
result.scheme =~ /^http/ ? result.to_s : nil
|
64
|
+
end
|
61
65
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
66
|
+
def pages!
|
67
|
+
result = {}
|
68
|
+
anchors.each do |a|
|
69
|
+
url = normalize_url a['href']
|
70
|
+
next unless url
|
71
|
+
page = Page.new url, parent: self, depth: depth+1
|
72
|
+
result[url] = page
|
73
|
+
end
|
74
|
+
result.values
|
69
75
|
end
|
70
|
-
result.values
|
71
|
-
end
|
72
76
|
|
73
|
-
|
74
|
-
|
75
|
-
|
77
|
+
def response
|
78
|
+
@response ||= response!
|
79
|
+
end
|
76
80
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
81
|
+
def response!
|
82
|
+
response = WebCache.get url
|
83
|
+
@uri = response.base_uri
|
84
|
+
response
|
85
|
+
end
|
82
86
|
|
83
|
-
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/sla/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sla
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Danny Ben Shitrit
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-07-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colsole
|
@@ -50,14 +50,14 @@ dependencies:
|
|
50
50
|
requirements:
|
51
51
|
- - "~>"
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: '0.
|
53
|
+
version: '0.7'
|
54
54
|
type: :runtime
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
58
|
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: '0.
|
60
|
+
version: '0.7'
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: nokogiri
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -110,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
110
110
|
- !ruby/object:Gem::Version
|
111
111
|
version: '0'
|
112
112
|
requirements: []
|
113
|
-
rubygems_version: 3.
|
113
|
+
rubygems_version: 3.2.16
|
114
114
|
signing_key:
|
115
115
|
specification_version: 4
|
116
116
|
summary: Command Line Site Link Analyzer
|