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.
@@ -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