shu-san-scripts 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rvmrc +27 -0
- data/Gemfile +34 -0
- data/Gemfile.lock +32 -0
- data/HISTORY +29 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +55 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/bin/store +50 -0
- data/lib/SANStore.rb +24 -0
- data/lib/SANStore/cli.rb +29 -0
- data/lib/SANStore/cli/base.rb +102 -0
- data/lib/SANStore/cli/commands.rb +30 -0
- data/lib/SANStore/cli/commands/help.rb +106 -0
- data/lib/SANStore/cli/commands/list_vols.rb +87 -0
- data/lib/SANStore/cli/commands/new_vol.rb +103 -0
- data/lib/SANStore/cli/logger.rb +88 -0
- data/lib/SANStore/cri.rb +12 -0
- data/lib/SANStore/cri/base.rb +153 -0
- data/lib/SANStore/cri/command.rb +104 -0
- data/lib/SANStore/cri/core_ext.rb +8 -0
- data/lib/SANStore/cri/core_ext/string.rb +41 -0
- data/lib/SANStore/cri/option_parser.rb +186 -0
- data/shu-san-scripts.gemspec +85 -0
- data/test/helper.rb +18 -0
- data/test/test_shu-san-scripts.rb +7 -0
- metadata +199 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
# Copyright (c) 2009 Denis Defreyne, 2010-2011 David Love
|
2
|
+
#
|
3
|
+
# Permission to use, copy, modify, and/or distribute this software for
|
4
|
+
# any purpose with or without fee is hereby granted, provided that the
|
5
|
+
# above copyright notice and this permission notice appear in all copies.
|
6
|
+
#
|
7
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
|
+
|
15
|
+
# @author David Love
|
16
|
+
#
|
17
|
+
# The +Commands+ module acts as the gathering place for all the sub-commands
|
18
|
+
# which the +store+ command can deal with. Each sub-command defines both
|
19
|
+
# the command action, options, and associated help text.
|
20
|
+
#
|
21
|
+
# All commands should live under +lib/SANStore/cli/commands+, with the
|
22
|
+
# file-name named after the sub-command defined within it.
|
23
|
+
|
24
|
+
module SANStore::CLI::Commands
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'SANStore/cli/commands/help'
|
28
|
+
|
29
|
+
#require 'SANStore/cli/commands/new_vol'
|
30
|
+
#require 'SANStore/cli/commands/list_vols'
|
@@ -0,0 +1,106 @@
|
|
1
|
+
### Copyright (c) 2009 Denis Defreyne, 2010-2011 David Love
|
2
|
+
###
|
3
|
+
### Permission to use, copy, modify, and/or distribute this software for
|
4
|
+
### any purpose with or without fee is hereby granted, provided that the
|
5
|
+
### above copyright notice and this permission notice appear in all copies.
|
6
|
+
###
|
7
|
+
### THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
### WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
### MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
### ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
### WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
### ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
### OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
|
+
###
|
15
|
+
|
16
|
+
module SANStore::CLI::Commands
|
17
|
+
|
18
|
+
# @author Denis Defreyne
|
19
|
+
# @author David Love
|
20
|
+
#
|
21
|
+
# The +help+ command show the user a brief summary of the available
|
22
|
+
# sub-commands, and the short description of each of those commands.
|
23
|
+
#
|
24
|
+
# Further help is available to the user, if one of the sub-commands
|
25
|
+
# is named as an argument to this command. In that case, the longer
|
26
|
+
# help for the command is displayed.
|
27
|
+
#
|
28
|
+
# @note This class is merely a helper class: the actual text, options
|
29
|
+
# and other details are drawn directly from the source code of those
|
30
|
+
# commands. In the execution of this command, we rely on the +cri+
|
31
|
+
# and +cli+ libraries to do the hard work of actually processing the
|
32
|
+
# sub-commands.
|
33
|
+
class Help < Cri::Command
|
34
|
+
|
35
|
+
# The name of the sub-command (as it appears in the command line app)
|
36
|
+
def name
|
37
|
+
'help'
|
38
|
+
end
|
39
|
+
|
40
|
+
# The aliases this sub-command is known by
|
41
|
+
def aliases
|
42
|
+
[]
|
43
|
+
end
|
44
|
+
|
45
|
+
# A short help text describing the purpose of this command
|
46
|
+
def short_desc
|
47
|
+
'Show help for a command'
|
48
|
+
end
|
49
|
+
|
50
|
+
# A longer description, detailing both the purpose and the
|
51
|
+
# use of this command
|
52
|
+
def long_desc
|
53
|
+
'Show help for the given command, or show general help. When no ' +
|
54
|
+
'command is given, a list of available commands is displayed, as ' +
|
55
|
+
'well as a list of global command-line options. When a command is ' +
|
56
|
+
'given, a command description as well as command-specific ' +
|
57
|
+
'command-line options are shown.'
|
58
|
+
end
|
59
|
+
|
60
|
+
# Show the user the basic syntax of this command
|
61
|
+
def usage
|
62
|
+
"store help [command]"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Execute the command
|
66
|
+
def run(options, arguments)
|
67
|
+
# Check arguments
|
68
|
+
if arguments.size > 1
|
69
|
+
$stderr.puts "usage: #{usage}"
|
70
|
+
exit 1
|
71
|
+
end
|
72
|
+
|
73
|
+
if arguments.length == 0
|
74
|
+
# Build help text
|
75
|
+
text = ''
|
76
|
+
|
77
|
+
# Add title
|
78
|
+
text << "A command-line tool for managing iSCSI targets on OpenSolaris.\n"
|
79
|
+
|
80
|
+
# Add available commands
|
81
|
+
text << "\n"
|
82
|
+
text << "Available commands:\n"
|
83
|
+
text << "\n"
|
84
|
+
@base.commands.sort.each do |command|
|
85
|
+
text << sprintf(" %-20s %s\n", command.name, command.short_desc)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Add global options
|
89
|
+
text << "\n"
|
90
|
+
text << "Global options:\n"
|
91
|
+
text << "\n"
|
92
|
+
@base.global_option_definitions.sort { |x,y| x[:long] <=> y[:long] }.each do |opt_def|
|
93
|
+
text << sprintf(" -%1s --%-15s %s\n", opt_def[:short], opt_def[:long], opt_def[:desc])
|
94
|
+
end
|
95
|
+
|
96
|
+
# Display text
|
97
|
+
puts text
|
98
|
+
elsif arguments.length == 1
|
99
|
+
command = @base.command_named(arguments[0])
|
100
|
+
puts command.help
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# Copyright (c) 2011 David Love
|
2
|
+
#
|
3
|
+
# Permission to use, copy, modify, and/or distribute this software for
|
4
|
+
# any purpose with or without fee is hereby granted, provided that the
|
5
|
+
# above copyright notice and this permission notice appear in all copies.
|
6
|
+
#
|
7
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
|
+
#
|
15
|
+
#
|
16
|
+
# @author David Love
|
17
|
+
#
|
18
|
+
|
19
|
+
module WhiteCloth::CLI::Commands
|
20
|
+
|
21
|
+
# @author David Love
|
22
|
+
#
|
23
|
+
# Displays a summary of the realm data found in the configured WhiteCloth
|
24
|
+
# server.
|
25
|
+
class Show < Cri::Command
|
26
|
+
|
27
|
+
# The name of the sub-command (as it appears in the command line app)
|
28
|
+
def name
|
29
|
+
'show-status'
|
30
|
+
end
|
31
|
+
|
32
|
+
# The aliases this sub-command is known by
|
33
|
+
def aliases
|
34
|
+
[]
|
35
|
+
end
|
36
|
+
|
37
|
+
# A short help text describing the purpose of this command
|
38
|
+
def short_desc
|
39
|
+
'Create or update information from the network'
|
40
|
+
end
|
41
|
+
|
42
|
+
# A longer description, detailing both the purpose and the
|
43
|
+
# use of this command
|
44
|
+
def long_desc
|
45
|
+
"Displays the current state of the evironemnt " +
|
46
|
+
"to update the host files (held in the 'hosts' directory). Existing " +
|
47
|
+
"information will be updated, and missing information inserted.\n"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Show the user the basic syntax of this command
|
51
|
+
def usage
|
52
|
+
"bootstrap show-status"
|
53
|
+
end
|
54
|
+
|
55
|
+
# Define the options for this command
|
56
|
+
def option_definitions
|
57
|
+
[]
|
58
|
+
end
|
59
|
+
|
60
|
+
# Execute the command
|
61
|
+
def run(options, arguments)
|
62
|
+
|
63
|
+
# Load the list of groups
|
64
|
+
group_list = YAML::load( File.open("config/groups.yaml"))
|
65
|
+
|
66
|
+
# Load the list of networks
|
67
|
+
network_list = YAML::load( File.open("config/networks.yaml"))
|
68
|
+
|
69
|
+
# Update the information in each group-network directory
|
70
|
+
gn_name_list = Array.new
|
71
|
+
|
72
|
+
network_list.each{|network|
|
73
|
+
puts network[1]
|
74
|
+
|
75
|
+
net_block = network[1]['ip4-address-block'].to_s
|
76
|
+
|
77
|
+
# Scan this network
|
78
|
+
# parser = Nmap::Parser.parsescan("nmap", "-sVC " + net_block)
|
79
|
+
|
80
|
+
puts parser
|
81
|
+
}
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# Copyright (c) 2009 Denis Defreyne, 2010-2011 David Love
|
2
|
+
#
|
3
|
+
# Permission to use, copy, modify, and/or distribute this software for
|
4
|
+
# any purpose with or without fee is hereby granted, provided that the
|
5
|
+
# above copyright notice and this permission notice appear in all copies.
|
6
|
+
#
|
7
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
|
+
|
15
|
+
|
16
|
+
module WhiteCloth::CLI::Commands
|
17
|
+
|
18
|
+
# @author David Love
|
19
|
+
#
|
20
|
+
# The +bootstrap+ command prepared the basic WhiteCloth realms (if
|
21
|
+
# needed), and then links the current host to those realms. The basic
|
22
|
+
# realms consists of
|
23
|
+
#
|
24
|
+
# +Realm 0+: *Namespace*. All the named realms stored in this domain.
|
25
|
+
#
|
26
|
+
# +Realm 1+: *Realm Handlers*. The basic gateways needed to create/store/update
|
27
|
+
# other realms.
|
28
|
+
#
|
29
|
+
# +Realm 5+: *Realm Code*. Libraries and other code which the realm handlers
|
30
|
+
# should use by preference when conducting operations on the realms.
|
31
|
+
#
|
32
|
+
# If the IP address of a server (or a server name) is given to as an argument
|
33
|
+
# to this command, then we will use that IP address (name) for as the WhiteCloth
|
34
|
+
# realm server to contact. Otherwise we will look for the same data from the file
|
35
|
+
# +/etc/whitecloth.conf+: aborting if the file cannot be found.
|
36
|
+
#
|
37
|
+
# Once we have made contact with the server, we look at the basic realms listed
|
38
|
+
# above, and attempt to ensure they can be found. If not, an attempt is made to
|
39
|
+
# create the basic realms: aborting if this attempt fails.
|
40
|
+
#
|
41
|
+
# Finally, once everything has been set-up, we upload the core realm code (or
|
42
|
+
# update the existing code)
|
43
|
+
class Bootstrap < Cri::Command
|
44
|
+
|
45
|
+
# The name of the sub-command (as it appears in the command line app)
|
46
|
+
def name
|
47
|
+
'bootstrap'
|
48
|
+
end
|
49
|
+
|
50
|
+
# The aliases this sub-command is known by
|
51
|
+
def aliases
|
52
|
+
[]
|
53
|
+
end
|
54
|
+
|
55
|
+
# A short help text describing the purpose of this command
|
56
|
+
def short_desc
|
57
|
+
'Create a link between this host and the whitecloth servers.'
|
58
|
+
end
|
59
|
+
|
60
|
+
# A longer description, detailing both the purpose and the
|
61
|
+
# use of this command
|
62
|
+
def long_desc
|
63
|
+
'Look for the specified server, adding the data required to link the ' +
|
64
|
+
'current host to that server. If the found server has not been set-up ' +
|
65
|
+
'then this command also performs the setup of the base realms as well. '
|
66
|
+
end
|
67
|
+
|
68
|
+
# Show the user the basic syntax of this command
|
69
|
+
def usage
|
70
|
+
"whitecloth bootstrap [-s server]"
|
71
|
+
end
|
72
|
+
|
73
|
+
# Define the options for this command
|
74
|
+
def option_definitions
|
75
|
+
[
|
76
|
+
{ :short => 's', :long => 'server', :argument => :optional }
|
77
|
+
]
|
78
|
+
end
|
79
|
+
|
80
|
+
# Execute the command
|
81
|
+
def run(options, arguments)
|
82
|
+
|
83
|
+
# The first thing we need to do is to find the relevant server. So we
|
84
|
+
# check the options and see if they can help
|
85
|
+
unless options[:server].nil? or options[:server].empty? then
|
86
|
+
#
|
87
|
+
else
|
88
|
+
|
89
|
+
# The user has not specified a server, so we will attempt to get one
|
90
|
+
# from the system configuration
|
91
|
+
if File.exists?("/etc/whitecloth.conf") then
|
92
|
+
#
|
93
|
+
|
94
|
+
# Everything has failed, so we abort
|
95
|
+
else
|
96
|
+
WhiteCloth::CLI::Logger.instance.log_level(:high, :error, "Cannot locate a WhiteCloth server. Either specify the server to connect to using the 'server' option, or create an appropriate configuration file.")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# Copyright (c) 2009 Denis Defreyne, 2010-2011 David Love
|
2
|
+
#
|
3
|
+
# Permission to use, copy, modify, and/or distribute this software for
|
4
|
+
# any purpose with or without fee is hereby granted, provided that the
|
5
|
+
# above copyright notice and this permission notice appear in all copies.
|
6
|
+
#
|
7
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
|
+
#
|
15
|
+
|
16
|
+
require 'singleton'
|
17
|
+
require 'facets'
|
18
|
+
|
19
|
+
module SANStore::CLI
|
20
|
+
|
21
|
+
# SANStore::CLI::Logger is a singleton class responsible for generating
|
22
|
+
# feedback in the terminal.
|
23
|
+
class Logger
|
24
|
+
|
25
|
+
# ANSI console codes (escape sequences) for highlighting particular
|
26
|
+
# log outputs.
|
27
|
+
ACTION_COLORS = {
|
28
|
+
:error => "\e[1m" + "\e[31m", # bold + red
|
29
|
+
:warning => "\e[1m" + "\e[33m", # bold + yellow
|
30
|
+
:info => "\e[1m" + "\e[32m", # bold + green
|
31
|
+
}
|
32
|
+
|
33
|
+
include Singleton
|
34
|
+
|
35
|
+
# The log level, which can be :high, :low or :off (which will log all
|
36
|
+
# messages, only high-priority messages, or no messages at all,
|
37
|
+
# respectively).
|
38
|
+
attr_accessor :level
|
39
|
+
|
40
|
+
# Whether to use color in log messages or not
|
41
|
+
attr_accessor :color
|
42
|
+
alias_method :color?, :color
|
43
|
+
|
44
|
+
def initialize
|
45
|
+
@level = :high
|
46
|
+
@color = true
|
47
|
+
end
|
48
|
+
|
49
|
+
# Logs a messsage, using appropriate colours to highlight different
|
50
|
+
# levels.
|
51
|
+
#
|
52
|
+
# +level+:: The importance of this action. Can be :high or :low.
|
53
|
+
#
|
54
|
+
# +action+:: The kind of file action. Can be :create, :update or
|
55
|
+
# :identical.
|
56
|
+
#
|
57
|
+
# +message+:: The identifier of the item the action was performed on.
|
58
|
+
def log_level(level, action, message)
|
59
|
+
log(
|
60
|
+
level,
|
61
|
+
'%s%12s%s: %s' % [
|
62
|
+
color? ? ACTION_COLORS[action.to_sym] : '',
|
63
|
+
action.capitalize,
|
64
|
+
color? ? "\e[0m" : '',
|
65
|
+
message.word_wrap(60).indent(15).lstrip
|
66
|
+
]
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Logs a message.
|
71
|
+
#
|
72
|
+
# +level+:: The importance of this message. Can be :high or :low.
|
73
|
+
#
|
74
|
+
# +message+:: The message to be logged.
|
75
|
+
#
|
76
|
+
# +io+:: The IO instance to which the message will be written. Defaults to
|
77
|
+
# standard output.
|
78
|
+
def log(level, message, io=$stdout)
|
79
|
+
# Don't log when logging is disabled
|
80
|
+
return if @level == :off
|
81
|
+
|
82
|
+
# Log when level permits it
|
83
|
+
io.puts(message) if (@level == :low or @level == level)
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
data/lib/SANStore/cri.rb
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
module Cri
|
2
|
+
|
3
|
+
# Cri::Base is the central class representing a commandline tool. It has a
|
4
|
+
# list of commands.
|
5
|
+
class Base
|
6
|
+
|
7
|
+
# The CLI's list of commands (should also contain the help command)
|
8
|
+
attr_reader :commands
|
9
|
+
|
10
|
+
# The CLI's help command (required)
|
11
|
+
attr_accessor :help_command
|
12
|
+
|
13
|
+
# Creates a new instance of the commandline tool.
|
14
|
+
def initialize(tool_name)
|
15
|
+
@tool_name = tool_name
|
16
|
+
|
17
|
+
@commands = []
|
18
|
+
end
|
19
|
+
|
20
|
+
# Parses the given commandline arguments and executes the requested
|
21
|
+
# command.
|
22
|
+
def run(args)
|
23
|
+
# Check arguments
|
24
|
+
if args.length == 0
|
25
|
+
@help_command.run([], [])
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
|
29
|
+
# Partition options
|
30
|
+
opts_before_command = []
|
31
|
+
command_name = nil
|
32
|
+
opts_and_args_after_command = []
|
33
|
+
stage = 0
|
34
|
+
args.each do |arg|
|
35
|
+
# Update stage if necessary
|
36
|
+
stage = 1 if stage == 0 && !is_option?(arg)
|
37
|
+
|
38
|
+
# Add
|
39
|
+
opts_before_command << arg if stage == 0
|
40
|
+
command_name = arg if stage == 1
|
41
|
+
opts_and_args_after_command << arg if stage == 2
|
42
|
+
|
43
|
+
# Update stage if necessary
|
44
|
+
stage = 2 if stage == 1
|
45
|
+
end
|
46
|
+
|
47
|
+
# Handle options before command
|
48
|
+
begin
|
49
|
+
parsed_arguments = Cri::OptionParser.parse(opts_before_command, global_option_definitions)
|
50
|
+
rescue Cri::OptionParser::IllegalOptionError => e
|
51
|
+
$stderr.puts "illegal option -- #{e}"
|
52
|
+
exit 1
|
53
|
+
end
|
54
|
+
parsed_arguments[:options].keys.each do |option|
|
55
|
+
handle_option(option)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Get command
|
59
|
+
if command_name.nil?
|
60
|
+
$stderr.puts "no command given"
|
61
|
+
exit 1
|
62
|
+
end
|
63
|
+
command = command_named(command_name)
|
64
|
+
if command.nil?
|
65
|
+
$stderr.puts "no such command: #{command_name}"
|
66
|
+
exit 1
|
67
|
+
end
|
68
|
+
|
69
|
+
# Parse arguments
|
70
|
+
option_definitions = command.option_definitions + global_option_definitions
|
71
|
+
begin
|
72
|
+
parsed_arguments = Cri::OptionParser.parse(opts_and_args_after_command, option_definitions)
|
73
|
+
rescue Cri::OptionParser::IllegalOptionError => e
|
74
|
+
$stderr.puts "illegal option -- #{e}"
|
75
|
+
exit 1
|
76
|
+
rescue Cri::OptionParser::OptionRequiresAnArgumentError => e
|
77
|
+
$stderr.puts "option requires an argument -- #{e}"
|
78
|
+
exit 1
|
79
|
+
end
|
80
|
+
|
81
|
+
# Handle global options
|
82
|
+
global_options = global_option_definitions.map { |o| o[:long] }
|
83
|
+
global_options.delete_if { |o| !parsed_arguments[:options].keys.include?(o.to_sym) }
|
84
|
+
global_options.each { |o| handle_option(o.to_sym) }
|
85
|
+
|
86
|
+
if parsed_arguments[:options].has_key?(:help)
|
87
|
+
# Show help for this command
|
88
|
+
show_help(command)
|
89
|
+
else
|
90
|
+
# Run command
|
91
|
+
command.run(parsed_arguments[:options], parsed_arguments[:arguments])
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns the command with the given name.
|
96
|
+
def command_named(name)
|
97
|
+
# Find by exact name or alias
|
98
|
+
command = @commands.find { |c| c.name == name or c.aliases.include?(name) }
|
99
|
+
return command unless command.nil?
|
100
|
+
|
101
|
+
# Find by approximation
|
102
|
+
commands = @commands.select { |c| c.name[0, name.length] == name }
|
103
|
+
if commands.length > 1
|
104
|
+
$stderr.puts "#{@tool_name}: '#{name}' is ambiguous:"
|
105
|
+
$stderr.puts " #{commands.map { |c| c.name }.join(' ') }"
|
106
|
+
exit 1
|
107
|
+
elsif commands.length == 0
|
108
|
+
$stderr.puts "#{@tool_name}: unknown command '#{name}'\n"
|
109
|
+
show_help
|
110
|
+
exit 1
|
111
|
+
else
|
112
|
+
return commands[0]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Shows the help text for the given command, or shows the general help
|
117
|
+
# text if no command is given.
|
118
|
+
def show_help(command=nil)
|
119
|
+
if command.nil?
|
120
|
+
@help_command.run([], [])
|
121
|
+
else
|
122
|
+
@help_command.run([], [ command.name ])
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Returns the list of global option definitionss.
|
127
|
+
def global_option_definitions
|
128
|
+
[]
|
129
|
+
end
|
130
|
+
|
131
|
+
# Adds the given command to the list of commands. Adding a command will
|
132
|
+
# also cause the command's +base+ to be set to this instance.
|
133
|
+
def add_command(command)
|
134
|
+
@commands << command
|
135
|
+
command.base = self
|
136
|
+
end
|
137
|
+
|
138
|
+
# Handles the given optio
|
139
|
+
def handle_option(option)
|
140
|
+
false
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
# Returns true if the given string is an option (i.e. -foo or --foo),
|
146
|
+
# false otherwise.
|
147
|
+
def is_option?(string)
|
148
|
+
string =~ /^-/
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|