nasl-pedant 0.0.3 → 0.0.4
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/Rakefile +38 -0
- data/bin/pedant +1 -1
- data/lib/pedant.rb +3 -1
- data/lib/pedant/check.rb +20 -12
- data/lib/pedant/checks/conditional_or_loop_is_empty.rb +1 -1
- data/lib/pedant/checks/contains_ip_address_literals.rb +1 -1
- data/lib/pedant/checks/contains_no_carriage_returns.rb +1 -1
- data/lib/pedant/checks/contains_no_tabs.rb +1 -1
- data/lib/pedant/checks/contains_registration_section.rb +10 -4
- data/lib/pedant/checks/contains_unreachable_code.rb +2 -2
- data/lib/pedant/checks/ends_with_newline.rb +1 -1
- data/lib/pedant/checks/{files_parse_without_error.rb → files_parse_without_errors.rb} +1 -1
- data/lib/pedant/checks/local_variable_unused.rb +51 -0
- data/lib/pedant/checks/parse_test_code.rb +1 -1
- data/lib/pedant/checks/plugin_type_not_specified.rb +4 -3
- data/lib/pedant/checks/script_category.rb +111 -0
- data/lib/pedant/checks/script_family_not_specified.rb +53 -16
- data/lib/pedant/checks/script_id.rb +115 -0
- data/lib/pedant/checks/script_name.rb +133 -0
- data/lib/pedant/checks/script_summary.rb +142 -0
- data/lib/pedant/cli.rb +41 -31
- data/lib/pedant/command.rb +16 -29
- data/lib/pedant/commands/check.rb +105 -6
- data/lib/pedant/commands/test.rb +24 -2
- data/lib/pedant/knowledge_base.rb +1 -1
- data/lib/pedant/test.rb +5 -5
- data/lib/pedant/version.rb +1 -1
- data/pedant.gemspec +33 -6
- data/test/test_helper.rb +26 -0
- data/test/unit/checks/test_conditional_or_loop_is_empty.rb +1 -1
- data/test/unit/checks/test_contains_ip_address_literals.rb +1 -1
- data/test/unit/checks/test_contains_no_carriage_returns.rb +1 -1
- data/test/unit/checks/test_contains_no_tabs.rb +1 -1
- data/test/unit/checks/test_contains_registration_section.rb +17 -1
- data/test/unit/checks/test_contains_unreachable_code.rb +11 -1
- data/test/unit/checks/test_ends_with_newline.rb +1 -1
- data/test/unit/checks/test_plugin_type_not_specified.rb +9 -1
- data/test/unit/checks/test_script_family_not_specified.rb +54 -13
- metadata +30 -20
@@ -0,0 +1,115 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Copyright (c) 2012, Mak Kolybabi
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
9
|
+
# list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
16
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
17
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
18
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
19
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
20
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
21
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
22
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
23
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
24
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
25
|
+
################################################################################
|
26
|
+
|
27
|
+
module Pedant
|
28
|
+
class CheckScriptId < Check
|
29
|
+
def self.requires
|
30
|
+
super + [:main, :trees]
|
31
|
+
end
|
32
|
+
|
33
|
+
def run
|
34
|
+
# This check only applies to plugins.
|
35
|
+
return skip unless @kb[:main].extname == '.nasl'
|
36
|
+
|
37
|
+
si_nodes = []
|
38
|
+
tree = @kb[:trees][@kb[:main]]
|
39
|
+
|
40
|
+
tree.all(:Call).each do |node|
|
41
|
+
next unless node.name.ident.name == 'script_id'
|
42
|
+
next unless node.name.indexes == []
|
43
|
+
si_nodes << node
|
44
|
+
end
|
45
|
+
|
46
|
+
if si_nodes.length == 0
|
47
|
+
report(:error, "Plugin does not call script_id() in the description.")
|
48
|
+
return fail
|
49
|
+
elsif si_nodes.length > 1
|
50
|
+
report(:error, "Plugin specifies multiple script IDs:")
|
51
|
+
si_nodes.each { |call| report(:error, call.context()) }
|
52
|
+
return fail
|
53
|
+
end
|
54
|
+
|
55
|
+
si_node = si_nodes.first
|
56
|
+
|
57
|
+
if si_node.args.empty?
|
58
|
+
report(:error, "script_id() was called with no arguments:\n#{si_node.context()}")
|
59
|
+
return fail
|
60
|
+
end
|
61
|
+
|
62
|
+
if si_node.args.length > 1
|
63
|
+
report(:error, "script_id() was called with too many arguments:\n#{si_node.context()}")
|
64
|
+
return fail
|
65
|
+
end
|
66
|
+
|
67
|
+
# Pull out argument
|
68
|
+
type = si_node.args.first.type
|
69
|
+
arg = si_node.args.first.expr
|
70
|
+
|
71
|
+
if type != :anonymous
|
72
|
+
report(
|
73
|
+
:error,
|
74
|
+
"script_id() was called using a named parameter. It requires using one positional parameter.\n" +
|
75
|
+
arg.context(si_node)
|
76
|
+
)
|
77
|
+
return fail
|
78
|
+
end
|
79
|
+
|
80
|
+
unless arg.is_a? Nasl::Integer
|
81
|
+
report(
|
82
|
+
:error,
|
83
|
+
"script_id() was called with the wrong type of argument.\n" +
|
84
|
+
"An integer literal between 10001 and 999999 inclusive is required:\n" +
|
85
|
+
arg.context(si_node)
|
86
|
+
)
|
87
|
+
return fail
|
88
|
+
end
|
89
|
+
|
90
|
+
# Ensure that the script id is valid.
|
91
|
+
if arg.value < 10001 or arg.value > 999999
|
92
|
+
report(
|
93
|
+
:error,
|
94
|
+
"script_id() was called with an invalid argument.\n" +
|
95
|
+
"An integer literal between 10001 and 999999 inclusive is required:\n" +
|
96
|
+
arg.context(si_node)
|
97
|
+
)
|
98
|
+
return fail
|
99
|
+
end
|
100
|
+
|
101
|
+
# Ensure that the script id is valid.
|
102
|
+
if arg.value >= 900001 and arg.value <= 999999
|
103
|
+
report(
|
104
|
+
:warn,
|
105
|
+
"Uses a script id reserved for custom plugins / plugins in development.\n" +
|
106
|
+
arg.context(si_node)
|
107
|
+
)
|
108
|
+
return warn
|
109
|
+
end
|
110
|
+
|
111
|
+
report(:info, "Plugin has script id #{arg.value}:\n#{arg.context(si_node)}")
|
112
|
+
pass
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Copyright (c) 2012, Mak Kolybabi
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
9
|
+
# list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
16
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
17
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
18
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
19
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
20
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
21
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
22
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
23
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
24
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
25
|
+
################################################################################
|
26
|
+
|
27
|
+
module Pedant
|
28
|
+
class CheckScriptName < Check
|
29
|
+
def self.requires
|
30
|
+
super + [:main, :trees]
|
31
|
+
end
|
32
|
+
|
33
|
+
def run
|
34
|
+
# This check only applies to plugins.
|
35
|
+
return skip unless @kb[:main].extname == '.nasl'
|
36
|
+
|
37
|
+
sn_nodes = []
|
38
|
+
tree = @kb[:trees][@kb[:main]]
|
39
|
+
|
40
|
+
tree.all(:Call).each do |node|
|
41
|
+
next unless node.name.ident.name == 'script_name'
|
42
|
+
next unless node.name.indexes == []
|
43
|
+
sn_nodes << node
|
44
|
+
end
|
45
|
+
|
46
|
+
if sn_nodes.length == 0
|
47
|
+
report(:error, "Plugin does not call script_name() in the description.")
|
48
|
+
return fail
|
49
|
+
elsif sn_nodes.length > 1
|
50
|
+
report(:error, "Plugin calls script_name() multiple times:")
|
51
|
+
sn_nodes.each { |call| report(:error, call.context()) }
|
52
|
+
return fail
|
53
|
+
end
|
54
|
+
|
55
|
+
sn_node = sn_nodes.first
|
56
|
+
|
57
|
+
if sn_node.args.empty?
|
58
|
+
report(:error, "script_name() was called with no arguments:\n#{sn_node.context()}")
|
59
|
+
return fail
|
60
|
+
end
|
61
|
+
|
62
|
+
if sn_node.args.length > 1
|
63
|
+
report(:error, "script_name() was called with too many arguments:\n#{sn_node.context()}")
|
64
|
+
return fail
|
65
|
+
end
|
66
|
+
|
67
|
+
# Pull out argument
|
68
|
+
type = sn_node.args.first.type
|
69
|
+
param = sn_node.args.first.name
|
70
|
+
arg = sn_node.args.first.expr
|
71
|
+
|
72
|
+
if type == :anonymous
|
73
|
+
report(
|
74
|
+
:error,
|
75
|
+
"script_name() was called using a positional parameter.\n" +
|
76
|
+
"It requires using an argument to the 'english' named parameter.\n" +
|
77
|
+
arg.context(sn_node)
|
78
|
+
)
|
79
|
+
return fail
|
80
|
+
end
|
81
|
+
|
82
|
+
if param.name != "english"
|
83
|
+
report(
|
84
|
+
:error,
|
85
|
+
"script_name() was called using an invalid named parameter.\n" +
|
86
|
+
"The 'english' named parameter must be used.\n" +
|
87
|
+
param.context(sn_node)
|
88
|
+
)
|
89
|
+
return fail
|
90
|
+
end
|
91
|
+
|
92
|
+
unless arg.is_a? Nasl::String
|
93
|
+
report(
|
94
|
+
:error,
|
95
|
+
"script_name() was called with the wrong type of argument. A string is required.\n" +
|
96
|
+
arg.context(sn_node)
|
97
|
+
)
|
98
|
+
return fail
|
99
|
+
end
|
100
|
+
|
101
|
+
if arg.text.length == 0
|
102
|
+
report(
|
103
|
+
:error,
|
104
|
+
"script_name() was called with an empty string.\n" +
|
105
|
+
arg.context(sn_node)
|
106
|
+
)
|
107
|
+
return fail
|
108
|
+
end
|
109
|
+
|
110
|
+
if arg.text.slice(0) == " " && arg.text.slice(-1) == " "
|
111
|
+
ws_error = "Script name has leading and trailing whitespace:\n"
|
112
|
+
elsif arg.text.slice(0) == " "
|
113
|
+
ws_error = "Script name has leading whitespace:\n"
|
114
|
+
elsif arg.text.slice(-1) == " "
|
115
|
+
ws_error = "Script name has trailing whitespace:\n"
|
116
|
+
else
|
117
|
+
ws_error = nil
|
118
|
+
end
|
119
|
+
|
120
|
+
unless ws_error.nil?
|
121
|
+
report(
|
122
|
+
:error,
|
123
|
+
ws_error +
|
124
|
+
arg.context(sn_node)
|
125
|
+
)
|
126
|
+
return fail
|
127
|
+
end
|
128
|
+
|
129
|
+
report(:info, "Plugin has a script name of '#{arg.text}':\n#{arg.context(sn_node)}")
|
130
|
+
pass
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Copyright (c) 2012, Mak Kolybabi
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
9
|
+
# list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
16
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
17
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
18
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
19
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
20
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
21
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
22
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
23
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
24
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
25
|
+
################################################################################
|
26
|
+
|
27
|
+
module Pedant
|
28
|
+
class CheckScriptSummary < Check
|
29
|
+
def self.requires
|
30
|
+
super + [:main, :trees]
|
31
|
+
end
|
32
|
+
|
33
|
+
def run
|
34
|
+
# This check only applies to plugins.
|
35
|
+
return skip unless @kb[:main].extname == '.nasl'
|
36
|
+
|
37
|
+
ss_nodes = []
|
38
|
+
tree = @kb[:trees][@kb[:main]]
|
39
|
+
|
40
|
+
tree.all(:Call).each do |node|
|
41
|
+
next unless node.name.ident.name == 'script_summary'
|
42
|
+
next unless node.name.indexes == []
|
43
|
+
ss_nodes << node
|
44
|
+
end
|
45
|
+
|
46
|
+
if ss_nodes.length == 0
|
47
|
+
report(:error, "Plugin does not call script_summary() in the description.")
|
48
|
+
return fail
|
49
|
+
elsif ss_nodes.length > 1
|
50
|
+
report(:error, "Plugin calls script_summary() multiple times:")
|
51
|
+
ss_nodes.each { |call| report(:error, call.context()) }
|
52
|
+
return fail
|
53
|
+
end
|
54
|
+
|
55
|
+
ss_node = ss_nodes.first
|
56
|
+
|
57
|
+
if ss_node.args.empty?
|
58
|
+
report(:error, "script_summary() was called with no arguments:\n#{ss_node.context()}")
|
59
|
+
return fail
|
60
|
+
end
|
61
|
+
|
62
|
+
if ss_node.args.length > 1
|
63
|
+
report(:error, "script_summary() was called with too many arguments:\n#{ss_node.context()}")
|
64
|
+
return fail
|
65
|
+
end
|
66
|
+
|
67
|
+
# Pull out argument
|
68
|
+
type = ss_node.args.first.type
|
69
|
+
param = ss_node.args.first.name
|
70
|
+
arg = ss_node.args.first.expr
|
71
|
+
|
72
|
+
if type == :anonymous
|
73
|
+
report(
|
74
|
+
:error,
|
75
|
+
"script_summary() was called using a positional parameter.\n" +
|
76
|
+
"It requires using an argument to the 'english' named parameter.\n" +
|
77
|
+
arg.context(ss_node)
|
78
|
+
)
|
79
|
+
return fail
|
80
|
+
end
|
81
|
+
|
82
|
+
if param.name != "english"
|
83
|
+
report(
|
84
|
+
:error,
|
85
|
+
"script_summary() was called using an invalid named parameter.\n" +
|
86
|
+
"The 'english' named parameter must be used.\n" +
|
87
|
+
param.context(ss_node)
|
88
|
+
)
|
89
|
+
return fail
|
90
|
+
end
|
91
|
+
|
92
|
+
unless arg.is_a? Nasl::String
|
93
|
+
report(
|
94
|
+
:error,
|
95
|
+
"script_summary() was called with the wrong type of argument. A string is required.\n" +
|
96
|
+
arg.context(ss_node)
|
97
|
+
)
|
98
|
+
return fail
|
99
|
+
end
|
100
|
+
|
101
|
+
if arg.text.length == 0
|
102
|
+
report(
|
103
|
+
:error,
|
104
|
+
"script_summary() was called with an empty string.\n" +
|
105
|
+
arg.context(ss_node)
|
106
|
+
)
|
107
|
+
return fail
|
108
|
+
end
|
109
|
+
|
110
|
+
if arg.text.slice(0) == " " && arg.text.slice(-1) == " "
|
111
|
+
ws_error = "Script summary has leading and trailing whitespace:\n"
|
112
|
+
elsif arg.text.slice(0) == " "
|
113
|
+
ws_error = "Script summary has leading whitespace:\n"
|
114
|
+
elsif arg.text.slice(-1) == " "
|
115
|
+
ws_error = "Script summary has trailing whitespace:\n"
|
116
|
+
else
|
117
|
+
ws_error = nil
|
118
|
+
end
|
119
|
+
|
120
|
+
unless ws_error.nil?
|
121
|
+
report(
|
122
|
+
:error,
|
123
|
+
ws_error +
|
124
|
+
arg.context(ss_node)
|
125
|
+
)
|
126
|
+
return fail
|
127
|
+
end
|
128
|
+
|
129
|
+
if arg.text.include? "\n"
|
130
|
+
report(
|
131
|
+
:error,
|
132
|
+
"Script summary includes newline characters:\n" +
|
133
|
+
arg.context(ss_node)
|
134
|
+
)
|
135
|
+
return fail
|
136
|
+
end
|
137
|
+
|
138
|
+
report(:info, "Plugin has a script summary of '#{arg.text}':\n#{arg.context(ss_node)}")
|
139
|
+
pass
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
data/lib/pedant/cli.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
################################################################################
|
2
|
-
# Copyright (c) 2011,
|
2
|
+
# Copyright (c) 2011-2014, Tenable Network Security
|
3
3
|
# All rights reserved.
|
4
4
|
#
|
5
5
|
# Redistribution and use in source and binary forms, with or without
|
@@ -28,53 +28,63 @@ require 'optparse'
|
|
28
28
|
|
29
29
|
module Pedant
|
30
30
|
class Cli
|
31
|
+
@@optparse = nil
|
32
|
+
|
31
33
|
def self.run
|
32
|
-
|
34
|
+
options = {
|
35
|
+
input_mode: :filesystem,
|
36
|
+
output_mode: :terminal,
|
37
|
+
verbosity: 0
|
38
|
+
}
|
33
39
|
|
34
40
|
Command.initialize!
|
35
41
|
|
36
|
-
optparse = OptionParser.new do |opts|
|
37
|
-
opts.banner = "Usage: pedant [options] [command [args]]"
|
42
|
+
@@optparse = OptionParser.new do |opts|
|
43
|
+
opts.banner = "Usage: pedant [global-options] [command [command-options] [args]]"
|
44
|
+
|
45
|
+
opts.separator ""
|
46
|
+
opts.separator "Global settings:"
|
38
47
|
|
39
|
-
|
40
|
-
|
41
|
-
cfg[:verbose] += 1
|
48
|
+
opts.on('-v', '--verbose', 'Output more information, use multiple time to increase verbosity.') do
|
49
|
+
options[:verbosity] += 1
|
42
50
|
end
|
43
|
-
end
|
44
51
|
|
45
|
-
|
52
|
+
opts.separator ""
|
53
|
+
opts.separator "Common operations:"
|
46
54
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
55
|
+
opts.on('-h', '--help', 'Display this help screen.') do
|
56
|
+
puts opts
|
57
|
+
exit 1
|
58
|
+
end
|
59
|
+
|
60
|
+
opts.on('-l', '--list', 'Display the list of available commands.') do
|
61
|
+
puts Command.list
|
62
|
+
exit 1
|
63
|
+
end
|
64
|
+
|
65
|
+
opts.on('-V', '--version', 'Display the version of Pedant.') do
|
66
|
+
puts "#{Pedant::VERSION}"
|
67
|
+
exit
|
68
|
+
end
|
53
69
|
end
|
54
70
|
|
71
|
+
@@optparse.order!
|
72
|
+
|
73
|
+
# Sanity check the command.
|
74
|
+
usage("No command was specified.") if ARGV.empty?
|
55
75
|
cmd = ARGV.shift
|
56
76
|
cls = Command.find(cmd)
|
57
|
-
if cls.nil?
|
58
|
-
puts "Command '#{cmd}' not supported."
|
59
|
-
puts
|
60
|
-
usage
|
61
|
-
exit 1
|
62
|
-
end
|
77
|
+
usage("Command '#{cmd}' not supported.") if cls.nil?
|
63
78
|
|
64
79
|
# Run the command.
|
65
|
-
cls.run(
|
80
|
+
cls.run(options, ARGV)
|
66
81
|
end
|
67
82
|
|
68
|
-
def self.usage
|
69
|
-
puts
|
70
|
-
puts
|
71
|
-
puts "Flags:"
|
72
|
-
puts " -v Display more verbose (warning) messages. "
|
73
|
-
puts " -vv Display more verbose (informational) messages. "
|
83
|
+
def self.usage(msg)
|
84
|
+
puts Rainbow(msg).color(:red)
|
74
85
|
puts
|
75
|
-
puts
|
76
|
-
|
77
|
-
puts " test Runs the specified unit tests, all are selected by default."
|
86
|
+
puts @@optparse
|
87
|
+
exit 1
|
78
88
|
end
|
79
89
|
end
|
80
90
|
end
|