shu-san-scripts 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,104 @@
1
+ module Cri
2
+
3
+ # Cri::Command represents a command that can be executed on the commandline.
4
+ # It is an abstract superclass for all commands.
5
+ class Command
6
+
7
+ attr_accessor :base
8
+
9
+ # Returns a string containing the name of thi command. Subclasses must
10
+ # implement this method.
11
+ def name
12
+ raise NotImplementedError.new("Command subclasses should override #name")
13
+ end
14
+
15
+ # Returns an array of strings containing the aliases for this command.
16
+ # Subclasses must implement this method.
17
+ def aliases
18
+ raise NotImplementedError.new("Command subclasses should override #aliases")
19
+ end
20
+
21
+ # Returns a string containing this command's short description, which
22
+ # should not be longer than 50 characters. Subclasses must implement this
23
+ # method.
24
+ def short_desc
25
+ raise NotImplementedError.new("Command subclasses should override #short_desc")
26
+ end
27
+
28
+ # Returns a string containing this command's complete description, which
29
+ # should explain what this command does and how it works in detail.
30
+ # Subclasses must implement this method.
31
+ def long_desc
32
+ raise NotImplementedError.new("Command subclasses should override #long_desc")
33
+ end
34
+
35
+ # Returns a string containing this command's usage. Subclasses must
36
+ # implement this method.
37
+ def usage
38
+ raise NotImplementedError.new("Command subclasses should override #usage")
39
+ end
40
+
41
+ # Returns an array containing this command's option definitions. See the
42
+ # documentation for Cri::OptionParser for details on what option
43
+ # definitions look like. Subclasses may implement this method if the
44
+ # command has options.
45
+ def option_definitions
46
+ []
47
+ end
48
+
49
+ # Executes the command. Subclasses must implement this method
50
+ # (obviously... what's the point of a command that can't be run?).
51
+ #
52
+ # +options+:: A hash containing the parsed commandline options. For
53
+ # example, '--foo=bar' will be converted into { :foo => 'bar'
54
+ # }. See the Cri::OptionParser documentation for details.
55
+ #
56
+ # +arguments+:: An array of strings representing the commandline arguments
57
+ # given to this command.
58
+ def run(options, arguments)
59
+ raise NotImplementedError.new("Command subclasses should override #run")
60
+ end
61
+
62
+ # Returns the help text for this command.
63
+ def help
64
+ text = ''
65
+
66
+ # Append usage
67
+ text << usage + "\n"
68
+
69
+ # Append aliases
70
+ unless aliases.empty?
71
+ text << "\n"
72
+ text << "aliases: #{aliases.join(' ')}\n"
73
+ end
74
+
75
+ # Append short description
76
+ text << "\n"
77
+ text << short_desc + "\n"
78
+
79
+ # Append long description
80
+ text << "\n"
81
+ text << long_desc.wrap_and_indent(78, 4) + "\n"
82
+
83
+ # Append options
84
+ unless option_definitions.empty?
85
+ text << "\n"
86
+ text << "options:\n"
87
+ text << "\n"
88
+ option_definitions.sort { |x,y| x[:long] <=> y[:long] }.each do |opt_def|
89
+ text << sprintf(" -%1s --%-10s %s\n", opt_def[:short], opt_def[:long], opt_def[:desc])
90
+ end
91
+ end
92
+
93
+ # Return text
94
+ text
95
+ end
96
+
97
+ # Compares this command's name to the other given command's name.
98
+ def <=>(other)
99
+ self.name <=> other.name
100
+ end
101
+
102
+ end
103
+
104
+ end
@@ -0,0 +1,8 @@
1
+ module Cri::CoreExtensions
2
+ end
3
+
4
+ require 'SANStore/cri/core_ext/string'
5
+
6
+ class String
7
+ include Cri::CoreExtensions::String
8
+ end
@@ -0,0 +1,41 @@
1
+ module Cri::CoreExtensions
2
+
3
+ module String
4
+
5
+ # Word-wraps and indents the string.
6
+ #
7
+ # +width+:: The maximal width of each line. This also includes indentation,
8
+ # i.e. the actual maximal width of the text is width-indentation.
9
+ #
10
+ # +indentation+:: The number of spaces to indent each wrapped line.
11
+ def wrap_and_indent(width, indentation)
12
+ # Split into paragraphs
13
+ paragraphs = self.split("\n").map { |p| p.strip }.reject { |p| p == '' }
14
+
15
+ # Wrap and indent each paragraph
16
+ paragraphs.map do |paragraph|
17
+ # Initialize
18
+ lines = []
19
+ line = ''
20
+
21
+ # Split into words
22
+ paragraph.split(/\s/).each do |word|
23
+ # Begin new line if it's too long
24
+ if (line + ' ' + word).length >= width
25
+ lines << line
26
+ line = ''
27
+ end
28
+
29
+ # Add word to line
30
+ line += (line == '' ? '' : ' ' ) + word
31
+ end
32
+ lines << line
33
+
34
+ # Join lines
35
+ lines.map { |l| ' '*indentation + l }.join("\n")
36
+ end.join("\n\n")
37
+ end
38
+
39
+ end
40
+
41
+ end
@@ -0,0 +1,186 @@
1
+ module Cri
2
+
3
+ # Cri::OptionParser is used for parsing commandline options.
4
+ class OptionParser
5
+
6
+ # Error that will be raised when an unknown option is encountered.
7
+ class IllegalOptionError < RuntimeError ; end
8
+
9
+ # Error that will be raised when an option without argument is
10
+ # encountered.
11
+ class OptionRequiresAnArgumentError < RuntimeError ; end
12
+
13
+ # Parses the commandline arguments in +arguments_and_options+, using the
14
+ # commandline option definitions in +definitions+.
15
+ #
16
+ # +arguments_and_options+ is an array of commandline arguments and
17
+ # options. This will usually be +ARGV+.
18
+ #
19
+ # +definitions+ contains a list of hashes defining which options are
20
+ # allowed and how they will be handled. Such a hash has three keys:
21
+ #
22
+ # :short:: The short name of the option, e.g. +a+. Do not include the '-'
23
+ # prefix.
24
+ #
25
+ # :long:: The long name of the option, e.g. +all+. Do not include the '--'
26
+ # prefix.
27
+ #
28
+ # :argument:: Whether this option's argument is required (:required),
29
+ # optional (:optional) or forbidden (:forbidden).
30
+ #
31
+ # A sample array of definition hashes could look like this:
32
+ #
33
+ # [
34
+ # { :short => 'a', :long => 'all', :argument => :forbidden },
35
+ # { :short => 'p', :long => 'port', :argument => :required },
36
+ # ]
37
+ #
38
+ # During parsing, two errors can be raised:
39
+ #
40
+ # IllegalOptionError:: An unrecognised option was encountered, i.e. an
41
+ # option that is not present in the list of option
42
+ # definitions.
43
+ #
44
+ # OptionRequiresAnArgumentError:: An option was found that did not have a
45
+ # value, even though this value was
46
+ # required.
47
+ #
48
+ # What will be returned, is a hash with two keys, :arguments and :options.
49
+ # The :arguments value contains a list of arguments, and the :options
50
+ # value contains a hash with key-value pairs for each option. Options
51
+ # without values will have a +nil+ value instead.
52
+ #
53
+ # For example, the following commandline options (which should not be
54
+ # passed as a string, but as an array of strings):
55
+ #
56
+ # foo -xyz -a hiss -s -m please --level 50 --father=ani -n luke squeak
57
+ #
58
+ # with the following option definitions:
59
+ #
60
+ # [
61
+ # { :short => 'x', :long => 'xxx', :argument => :forbidden },
62
+ # { :short => 'y', :long => 'yyy', :argument => :forbidden },
63
+ # { :short => 'z', :long => 'zzz', :argument => :forbidden },
64
+ # { :short => 'a', :long => 'all', :argument => :forbidden },
65
+ # { :short => 's', :long => 'stuff', :argument => :optional },
66
+ # { :short => 'm', :long => 'more', :argument => :optional },
67
+ # { :short => 'l', :long => 'level', :argument => :required },
68
+ # { :short => 'f', :long => 'father', :argument => :required },
69
+ # { :short => 'n', :long => 'name', :argument => :required }
70
+ # ]
71
+ #
72
+ # will be translated into:
73
+ #
74
+ # {
75
+ # :arguments => [ 'foo', 'hiss', 'squeak' ],
76
+ # :options => {
77
+ # :xxx => true,
78
+ # :yyy => true,
79
+ # :zzz => true,
80
+ # :all => true,
81
+ # :stuff => true,
82
+ # :more => 'please',
83
+ # :level => '50',
84
+ # :father => 'ani',
85
+ # :name => 'luke'
86
+ # }
87
+ # }
88
+ def self.parse(arguments_and_options, definitions)
89
+ # Don't touch original argument
90
+ unprocessed_arguments_and_options = arguments_and_options.dup
91
+
92
+ # Initialize
93
+ arguments = []
94
+ options = {}
95
+
96
+ # Determines whether we've passed the '--' marker or not
97
+ no_more_options = false
98
+
99
+ loop do
100
+ # Get next item
101
+ e = unprocessed_arguments_and_options.shift
102
+ break if e.nil?
103
+
104
+ # Handle end-of-options marker
105
+ if e == '--'
106
+ no_more_options = true
107
+ # Handle incomplete options
108
+ elsif e =~ /^--./ and !no_more_options
109
+ # Get option key, and option value if included
110
+ if e =~ /^--([^=]+)=(.+)$/
111
+ option_key = $1
112
+ option_value = $2
113
+ else
114
+ option_key = e[2..-1]
115
+ option_value = nil
116
+ end
117
+
118
+ # Find definition
119
+ definition = definitions.find { |d| d[:long] == option_key }
120
+ raise IllegalOptionError.new(option_key) if definition.nil?
121
+
122
+ if [ :required, :optional ].include?(definition[:argument])
123
+ # Get option value if necessary
124
+ if option_value.nil?
125
+ option_value = unprocessed_arguments_and_options.shift
126
+ if option_value.nil? || option_value =~ /^-/
127
+ if definition[:argument] == :required
128
+ raise OptionRequiresAnArgumentError.new(option_key)
129
+ else
130
+ unprocessed_arguments_and_options.unshift(option_value)
131
+ option_value = true
132
+ end
133
+ end
134
+ end
135
+
136
+ # Store option
137
+ options[definition[:long].to_sym] = option_value
138
+ else
139
+ # Store option
140
+ options[definition[:long].to_sym] = true
141
+ end
142
+ # Handle -xyz options
143
+ elsif e =~ /^-./ and !no_more_options
144
+ # Get option keys
145
+ option_keys = e[1..-1].scan(/./)
146
+
147
+ # For each key
148
+ option_keys.each do |option_key|
149
+ # Find definition
150
+ definition = definitions.find { |d| d[:short] == option_key }
151
+ raise IllegalOptionError.new(option_key) if definition.nil?
152
+
153
+ if option_keys.length > 1 and definition[:argument] == :required
154
+ # This is a combined option and it requires an argument, so complain
155
+ raise OptionRequiresAnArgumentError.new(option_key)
156
+ elsif [ :required, :optional ].include?(definition[:argument])
157
+ # Get option value
158
+ option_value = unprocessed_arguments_and_options.shift
159
+ if option_value.nil? || option_value =~ /^-/
160
+ if definition[:argument] == :required
161
+ raise OptionRequiresAnArgumentError.new(option_key)
162
+ else
163
+ unprocessed_arguments_and_options.unshift(option_value)
164
+ option_value = true
165
+ end
166
+ end
167
+
168
+ # Store option
169
+ options[definition[:long].to_sym] = option_value
170
+ else
171
+ # Store option
172
+ options[definition[:long].to_sym] = true
173
+ end
174
+ end
175
+ # Handle normal arguments
176
+ else
177
+ arguments << e
178
+ end
179
+ end
180
+
181
+ { :options => options, :arguments => arguments }
182
+ end
183
+
184
+ end
185
+
186
+ end
@@ -0,0 +1,85 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{shu-san-scripts}
8
+ s.version = "0.0.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = [%q{David Love}]
12
+ s.date = %q{2011-09-23}
13
+ s.description = %q{See the README file.}
14
+ s.email = %q{david@homeunix.org.uk}
15
+ s.executables = [%q{store}]
16
+ s.extra_rdoc_files = [
17
+ "LICENSE.txt",
18
+ "README.rdoc"
19
+ ]
20
+ s.files = [
21
+ ".document",
22
+ ".rvmrc",
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "HISTORY",
26
+ "LICENSE.txt",
27
+ "README.rdoc",
28
+ "Rakefile",
29
+ "VERSION",
30
+ "bin/store",
31
+ "lib/SANStore.rb",
32
+ "lib/SANStore/cli.rb",
33
+ "lib/SANStore/cli/base.rb",
34
+ "lib/SANStore/cli/commands.rb",
35
+ "lib/SANStore/cli/commands/help.rb",
36
+ "lib/SANStore/cli/commands/list_vols.rb",
37
+ "lib/SANStore/cli/commands/new_vol.rb",
38
+ "lib/SANStore/cli/logger.rb",
39
+ "lib/SANStore/cri.rb",
40
+ "lib/SANStore/cri/base.rb",
41
+ "lib/SANStore/cri/command.rb",
42
+ "lib/SANStore/cri/core_ext.rb",
43
+ "lib/SANStore/cri/core_ext/string.rb",
44
+ "lib/SANStore/cri/option_parser.rb",
45
+ "shu-san-scripts.gemspec",
46
+ "test/helper.rb",
47
+ "test/test_shu-san-scripts.rb"
48
+ ]
49
+ s.homepage = %q{http://github.com/dlove24/shu-san-scripts}
50
+ s.licenses = [%q{ISC}]
51
+ s.require_paths = [%q{lib}]
52
+ s.rubygems_version = %q{1.8.6}
53
+ s.summary = %q{Scripts used to set-up and manage iSCSI targets on OpenSolaris (ZFS) systems.}
54
+
55
+ if s.respond_to? :specification_version then
56
+ s.specification_version = 3
57
+
58
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
59
+ s.add_runtime_dependency(%q<cri>, ["~> 2.0.2"])
60
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
61
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.0"])
62
+ s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
63
+ s.add_development_dependency(%q<vclog>, ["~> 1.8.1"])
64
+ s.add_development_dependency(%q<minitest>, [">= 0"])
65
+ s.add_development_dependency(%q<riot>, [">= 0"])
66
+ else
67
+ s.add_dependency(%q<cri>, ["~> 2.0.2"])
68
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
69
+ s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
70
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
71
+ s.add_dependency(%q<vclog>, ["~> 1.8.1"])
72
+ s.add_dependency(%q<minitest>, [">= 0"])
73
+ s.add_dependency(%q<riot>, [">= 0"])
74
+ end
75
+ else
76
+ s.add_dependency(%q<cri>, ["~> 2.0.2"])
77
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
78
+ s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
79
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
80
+ s.add_dependency(%q<vclog>, ["~> 1.8.1"])
81
+ s.add_dependency(%q<minitest>, [">= 0"])
82
+ s.add_dependency(%q<riot>, [">= 0"])
83
+ end
84
+ end
85
+
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'shu-san-scripts'
16
+
17
+ class Test::Unit::TestCase
18
+ end