rprogram 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,316 @@
1
+ require 'rprogram/exceptions/program_not_found'
2
+ require 'rprogram/rprogram'
3
+
4
+ require 'env/variables'
5
+
6
+ module RProgram
7
+ #
8
+ # @since 0.3.0
9
+ #
10
+ module System
11
+ extend Env::Variables
12
+
13
+ @arch, @platform = RUBY_PLATFORM.split('-',2)
14
+ @platform ||= @arch
15
+
16
+ #
17
+ # Determines the native architecture.
18
+ #
19
+ # @return [String]
20
+ # The native architecture.
21
+ #
22
+ # @example
23
+ # System.arch
24
+ # # => "x86-64"
25
+ #
26
+ # @since 0.3.0
27
+ #
28
+ def System.arch
29
+ @arch
30
+ end
31
+
32
+ #
33
+ # Determines the native platform.
34
+ #
35
+ # @return [String]
36
+ # The native platform.
37
+ #
38
+ # @example
39
+ # System.platform
40
+ # # => "linux"
41
+ #
42
+ def System.platform
43
+ @platform
44
+ end
45
+
46
+ #
47
+ # Determines if the platform is Windows.
48
+ #
49
+ # @return [Boolean]
50
+ # Specifies whether the platform is Windows.
51
+ #
52
+ # @since 0.3.0
53
+ #
54
+ def System.windows?
55
+ if @platform
56
+ @platform.include?('mingw') || @platform.include?('mswin')
57
+ else
58
+ false
59
+ end
60
+ end
61
+
62
+ #
63
+ # Determines if the current Ruby VM is from the 1.8.x family.
64
+ #
65
+ # @return [Boolean]
66
+ # Specifies if the current Ruby VM is from the 1.8.x family.
67
+ #
68
+ # @since 0.3.0
69
+ #
70
+ def System.ruby_1_8?
71
+ RUBY_VERSION[0,4] == '1.8.'
72
+ end
73
+
74
+ #
75
+ # Determines if the current Ruby VM is JRuby.
76
+ #
77
+ # @return [Boolean]
78
+ # Specifies whether the Ruby VM is JRuby.
79
+ #
80
+ # @since 0.3.0
81
+ #
82
+ def System.jruby?
83
+ Object.const_defined?(:RUBY_ENGINE) && \
84
+ Object.const_get(:RUBY_ENGINE) == 'jruby'
85
+ end
86
+
87
+ #
88
+ # Finds the full-path of the program with the matching name.
89
+ #
90
+ # @param [String] name
91
+ # The name of the program to find.
92
+ #
93
+ # @return [Pathname, nil]
94
+ # The full-path of the desired program.
95
+ #
96
+ # @example
97
+ # System.find_program('as')
98
+ # #=> #<Pathname:/usr/bin/as>
99
+ #
100
+ def System.find_program(name)
101
+ # add the `.exe` suffix to the name, if running on Windows
102
+ if windows?
103
+ name = "#{name}.exe"
104
+ end
105
+
106
+ paths.each do |dir|
107
+ full_path = dir.join(name).expand_path
108
+
109
+ return full_path if full_path.file?
110
+ end
111
+
112
+ return nil
113
+ end
114
+
115
+ #
116
+ # Finds the program matching one of the matching names.
117
+ #
118
+ # @param [Array] names
119
+ # The names of the program to use while searching for the program.
120
+ #
121
+ # @return [Pathname, nil]
122
+ # The first full-path for the program.
123
+ #
124
+ # @example
125
+ # System.find_program_by_names("gas","as")
126
+ # # => #<Pathname:/usr/bin/as>
127
+ #
128
+ def System.find_program_by_names(*names)
129
+ names.each do |name|
130
+ if (path = find_program(name))
131
+ return path
132
+ end
133
+ end
134
+
135
+ return nil
136
+ end
137
+
138
+ #
139
+ # Runs a program.
140
+ #
141
+ # @overload run(path,*arguments)
142
+ # Run the program with the given arguments.
143
+ #
144
+ # @param [Pathname, String] path
145
+ # The path of the program to run.
146
+ #
147
+ # @param [Array] arguments
148
+ # Additional arguments to run the program with.
149
+ #
150
+ # @overload run(path,*arguments,options)
151
+ # Run the program with the given arguments and options.
152
+ #
153
+ # @param [Pathname, String] path
154
+ # The path of the program to run.
155
+ #
156
+ # @param [Array] arguments
157
+ # Additional arguments to run the program with.
158
+ #
159
+ # @param [Hash] options
160
+ # Additional options to execute the program with.
161
+ #
162
+ # @option options [Hash{String => String}] :env
163
+ # Environment variables to execute the program with.
164
+ #
165
+ # @option options [String] :popen
166
+ # Specifies to run the program using `IO.popen` with the given
167
+ # IO mode.
168
+ #
169
+ # @return [Boolean]
170
+ # Specifies whether the program exited successfully.
171
+ #
172
+ # @raise [RuntimeError]
173
+ # Passing `:popen`, `:env` or exec options is not supported
174
+ # before Ruby 1.9.1.
175
+ #
176
+ # @see http://rubydoc.info/stdlib/core/1.9.2/Kernel#spawn-instance_method
177
+ # For acceptable options.
178
+ #
179
+ def System.run(*arguments)
180
+ # extra tailing options and ENV variables from arguments
181
+ if arguments.last.kind_of?(Hash)
182
+ options = arguments.pop
183
+ env = (options.delete(:env) || {})
184
+ popen = options.delete(:popen)
185
+ else
186
+ options = {}
187
+ env = {}
188
+ end
189
+
190
+ # all arguments must be Strings
191
+ arguments = arguments.map { |arg| arg.to_s }
192
+
193
+ # print debugging information
194
+ if RProgram.debug
195
+ command = ''
196
+
197
+ env.each do |name,value|
198
+ command << "#{name}=#{value} "
199
+ end
200
+
201
+ command << arguments.join(' ')
202
+ command << " #{options.inspect}" unless options.empty?
203
+
204
+ STDERR.puts ">>> #{command}"
205
+ end
206
+
207
+ # passing ENV variables or exec options is not supported before 1.9.1
208
+ if (!options.empty? && ruby_1_8?)
209
+ raise("cannot pass exec options to Kernel.system in #{RUBY_VERSION}")
210
+ end
211
+
212
+ if popen
213
+ # IO.popen does not accept multiple arguments on Ruby 1.8.x.
214
+ if ruby_1_8?
215
+ raise("cannot use :popen on #{RUBY_VERSION}, please use 1.9.x")
216
+ end
217
+
218
+ # :popen can only be used on Unix, or on Windows with JRuby
219
+ if (windows? && !jruby?)
220
+ raise("cannot use :popen on Windows, unless under JRuby")
221
+ end
222
+ end
223
+
224
+ # re-add ENV variables and exec options
225
+ arguments.unshift(env) unless env.empty?
226
+ arguments.push(options) unless options.empty?
227
+
228
+ if popen
229
+ IO.popen(arguments,popen)
230
+ else
231
+ Kernel.system(*arguments)
232
+ end
233
+ end
234
+
235
+ #
236
+ # The path to the `sudo` program.
237
+ #
238
+ # @return [Pathname, nil]
239
+ # The path to the `sudo` program.
240
+ #
241
+ # @since 0.3.0
242
+ #
243
+ def System.sudo_path
244
+ @sudo ||= find_program('sudo')
245
+ end
246
+
247
+ #
248
+ # Sets the path to the `sudo` program.
249
+ #
250
+ # @param [String, Pathname] path
251
+ # The new path to use.
252
+ #
253
+ # @return [Pathanme]
254
+ # The new path to the `sudo` program.
255
+ #
256
+ # @since 0.3.0
257
+ #
258
+ def System.sudo_path=(path)
259
+ @sudo = Pathname.new(path)
260
+ end
261
+
262
+ #
263
+ # Determines whether `sudo` is available on the system.
264
+ #
265
+ # @return [Boolean]
266
+ # Specifies whether the `sudo` program is installed on the system.
267
+ #
268
+ # @since 0.3.0
269
+ #
270
+ def System.sudo?
271
+ !sudo_path.nil?
272
+ end
273
+
274
+ #
275
+ # Runs a program under sudo.
276
+ #
277
+ # @overload run(path,*arguments)
278
+ # Run the program with the given arguments.
279
+ #
280
+ # @param [Pathname, String] path
281
+ # The path of the program to run.
282
+ #
283
+ # @param [Array] arguments
284
+ # Additional arguments to run the program with.
285
+ #
286
+ # @overload run(path,*arguments,options)
287
+ # Run the program with the given arguments and options.
288
+ #
289
+ # @param [Pathname, String] path
290
+ # The path of the program to run.
291
+ #
292
+ # @param [Array] arguments
293
+ # Additional arguments to run the program with.
294
+ #
295
+ # @param [Hash] options
296
+ # Additional options to execute the program with.
297
+ #
298
+ # @return [Boolean]
299
+ # Specifies whether the program exited successfully.
300
+ #
301
+ # @raise [ProgramNotFound]
302
+ # Indicates that the `sudo` program could not be located.
303
+ #
304
+ # @since 0.1.8
305
+ #
306
+ # @see run
307
+ #
308
+ def System.sudo(*arguments)
309
+ unless sudo?
310
+ raise(ProgramNotFound,'could not find the "sudo" program')
311
+ end
312
+
313
+ return run(sudo_path,*arguments)
314
+ end
315
+ end
316
+ end
data/lib/rprogram/task.rb CHANGED
@@ -1,14 +1,10 @@
1
- require 'rprogram/options'
1
+ require 'rprogram/option'
2
2
  require 'rprogram/option_list'
3
+ require 'rprogram/non_option'
3
4
 
4
5
  module RProgram
5
6
  class Task
6
7
 
7
- include Options
8
-
9
- # Specifies whether the task will be run under sudo
10
- attr_accessor :sudo
11
-
12
8
  #
13
9
  # Creates a new Task object.
14
10
  #
@@ -30,13 +26,119 @@ module RProgram
30
26
  # end
31
27
  #
32
28
  def initialize(options={},&block)
33
- @sudo = (options.delete(:sudo) || false)
34
29
  @subtasks = {}
35
30
  @options = options
36
31
 
37
32
  block.call(self) if block
38
33
  end
39
34
 
35
+ #
36
+ # @return [Hash]
37
+ # All defined non-options of the class.
38
+ #
39
+ def self.non_options
40
+ @non_options ||= {}
41
+ end
42
+
43
+ #
44
+ # Searches for the non-option with the matching name in the class
45
+ # and it's ancestors.
46
+ #
47
+ # @param [Symbol, String] name
48
+ # The name to search for.
49
+ #
50
+ # @return [true, false]
51
+ # Specifies whether the non-option with the matching name was
52
+ # defined.
53
+ #
54
+ def self.has_non_option?(name)
55
+ name = name.to_sym
56
+
57
+ ancestors.each do |base|
58
+ if base < RProgram::Task
59
+ return true if base.non_options.include?(name)
60
+ end
61
+ end
62
+
63
+ return false
64
+ end
65
+
66
+ #
67
+ # Searches for the non-option with the matching name in the class
68
+ # and it's ancestors.
69
+ #
70
+ # @param [Symbol, String] name
71
+ # The name to search for.
72
+ #
73
+ # @return [NonOption]
74
+ # The non-option with the matching name.
75
+ #
76
+ def self.get_non_option(name)
77
+ name = name.to_sym
78
+
79
+ ancestors.each do |base|
80
+ if base < RProgram::Task
81
+ if base.non_options.has_key?(name)
82
+ return base.non_options[name]
83
+ end
84
+ end
85
+ end
86
+
87
+ return nil
88
+ end
89
+
90
+ #
91
+ # @return [Hash]
92
+ # All defined options for the class.
93
+ #
94
+ def self.options
95
+ @options ||= {}
96
+ end
97
+
98
+ #
99
+ # Searches for the option with the matching name in the class and
100
+ # it's ancestors.
101
+ #
102
+ # @param [Symbol, String] name
103
+ # The name to search for.
104
+ #
105
+ # @return [true, false]
106
+ # Specifies whether the option with the matching name was defined.
107
+ #
108
+ def self.has_option?(name)
109
+ name = name.to_sym
110
+
111
+ ancestors.each do |base|
112
+ if base < RProgram::Task
113
+ return true if base.options.has_key?(name)
114
+ end
115
+ end
116
+
117
+ return false
118
+ end
119
+
120
+ #
121
+ # Searches for the option with the matching name in the class and
122
+ # it's ancestors.
123
+ #
124
+ # @param [Symbol, String] name
125
+ # The name to search for.
126
+ #
127
+ # @return [Option]
128
+ # The option with the matching name.
129
+ #
130
+ def self.get_option(name)
131
+ name = name.to_sym
132
+
133
+ ancestors.each do |base|
134
+ if base < RProgram::Task
135
+ return base.options[name] if base.options.has_key?(name)
136
+ end
137
+ end
138
+
139
+ return nil
140
+ end
141
+
40
142
  #
41
143
  # Creates a new Task object, then formats command-line arguments
42
144
  # using the Task object.
@@ -69,15 +171,31 @@ module RProgram
69
171
  end
70
172
 
71
173
  #
72
- # Specifies whether the task will be ran under sudo.
174
+ # @see has_non_option?
175
+ #
176
+ def has_non_option?(name)
177
+ self.class.has_non_option?(name)
178
+ end
179
+
180
+ #
181
+ # @see get_non_option
182
+ #
183
+ def get_non_option(name)
184
+ self.class.get_non_option(name)
185
+ end
186
+
187
+ #
188
+ # @see has_option?
73
189
  #
74
- # @return [Boolean]
75
- # Returns `true` if sudo is enabled, returns `false` otherwise.
190
+ def has_option?(name)
191
+ self.class.has_option?(name)
192
+ end
193
+
76
194
  #
77
- # @since 0.1.8
195
+ # @see get_option
78
196
  #
79
- def sudo?
80
- @sudo == true
197
+ def get_option(name)
198
+ self.class.get_option(name)
81
199
  end
82
200
 
83
201
  #
@@ -166,9 +284,17 @@ module RProgram
166
284
  # options and tailing non-options of the task and it's sub-tasks.
167
285
  #
168
286
  def arguments
169
- leading_non_options + options + tailing_non_options
287
+ tailing_args = tailing_non_options
288
+
289
+ if tailing_args.any? { |arg| arg[0,1] == '-' }
290
+ tailing_args.unshift('--')
291
+ end
292
+
293
+ return leading_non_options + options + tailing_args
170
294
  end
171
295
 
296
+ alias to_a arguments
297
+
172
298
  protected
173
299
 
174
300
  #
@@ -185,20 +311,22 @@ module RProgram
185
311
  #
186
312
  def self.subtask(name,task)
187
313
  name = name.to_s
314
+ file = __FILE__
315
+ line = __LINE__ + 3
188
316
 
189
317
  class_eval %{
190
318
  def #{name}(options={},&block)
191
319
  if @subtasks[#{name.dump}]
192
320
  @subtasks[#{name.dump}].options.merge!(options)
193
321
 
194
- block.call(@subtasks[#{name.dump}]) if block
322
+ yield(@subtasks[#{name.dump}]) if block_given?
195
323
  else
196
324
  @subtasks[#{name.dump}] = #{task}.new(options,&block)
197
325
  end
198
326
 
199
327
  return @subtasks[#{name.dump}]
200
328
  end
201
- }
329
+ }, file, line
202
330
  end
203
331
 
204
332
  #