shu-san-scripts 0.0.2
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/.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
|