sys_cmd 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 307b77667d06748740cea3b10c0b0112475dac60
4
- data.tar.gz: d584ecfcfb2cbbdce499adede7c68bf59014cd24
3
+ metadata.gz: 1699ccea4cb7b0bc8248c247383683ba89dfa43a
4
+ data.tar.gz: eeb6ffc30f8bfc9a9cec6ad680adcd0c7b33fed8
5
5
  SHA512:
6
- metadata.gz: 24290cf375b93fb4414d85f6534535285fd528b11be30f37fa5662226382df7eaae663006ce6c01133dff20fd1e1ab13c4878ec0df1ab04079e1af41e0a961fe
7
- data.tar.gz: 85b2d3089a50c50e30d25bd70b9a0ea3ce19c0661d8d486a8d2d10759a988eecd224ca4d1a4f8cb15c4c5b0c699389ad9bea53b7aaa630e7891dcef8b4e05dfc
6
+ metadata.gz: 316a8757c455ecd7ae0cb136a5b444e70c33fcee0263277dd287421d1360bef5e4922f31fc29877f34b92d9a2c197838f68dd45ffe6b6be3eab462ec29f360c1
7
+ data.tar.gz: 480aaa5ec37aad47601d8890be1a164e1eda342d688bb88c0a7c70d8d1d86c23a3d0272b66c1e512f6e761608dc386975e30de216ac6956511d0f970a77009f8
data/.travis.yml CHANGED
@@ -1,3 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.2.1
3
+ - 2.2.2
4
+ - 2.1.6
5
+ - 1.9.3
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # SysCmd
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/sys_cmd.svg)](http://badge.fury.io/rb/sys_cmd)
4
+ [![Build Status](https://travis-ci.org/jgoizueta/sys_cmd.svg)](https://travis-ci.org/jgoizueta/sys_cmd)
5
+
3
6
  SysCmd is a DSL to define commands to be executed by the system.
4
7
 
5
8
  The command arguments will we escaped properly for bash or
@@ -25,19 +28,82 @@ Or install it yourself as:
25
28
 
26
29
  ## Usage
27
30
 
28
- Example:
31
+ A command can be defined with a simple DSL (passing a block that defines
32
+ the command arguments to the SysCmd.command method):
29
33
 
30
34
  cmd = SysCmd.command 'ffmpeg' do
31
35
  option '-i', file: 'input video file.mkv'
32
36
  option '-vcodec', 'mjpeg'
33
37
  file 'output.mkv'
34
38
  end
39
+
40
+ The block is executed with +instance_eval+ inside the command definition
41
+ (an instance of SysCmd::Definicion), so +self+ and instance variables refer
42
+ to the definition. If this is not desirable an argument can be passed to
43
+ the block with the +Definition+ object:
44
+
45
+ cmd = SysCmd.command 'ffmpeg' do |cmd|
46
+ cmd.option '-i', file: 'input video file.mkv'
47
+ cmd.option '-vcodec', 'mjpeg'
48
+ cmd.file 'output.mkv'
49
+ end
50
+
51
+ The command can be converted to a String which represents it with
52
+ arguments quoted for the target OS/shell (here we assume a UN*X system)
53
+
35
54
  puts cmd.to_s # ffmpeg -i input\ video\ file.mkv -vcodec mjpeg output.mkv
55
+
56
+ A command can be generated for a system different from the current host
57
+ by passing the +:os+ option:
58
+
59
+ wcmd = SysCmd.command 'ffmpeg', os: :windows do |cmd|
60
+ cmd.option '-i', file: 'input video file.mkv'
61
+ cmd.option '-vcodec', 'mjpeg'
62
+ cmd.file 'output.mkv'
63
+ end
64
+ puts cmd.to_s # ffmpeg -i "input video file.mkv" -vcodec mjpeg "output.mkv"
65
+
66
+ Currently only +:windows+ (for CMD.EXE syntax) and +:unix+ (for bash syntax) are
67
+ accepted for the +:os+ parameter. +:unix+ represent any UN*X-like system
68
+ (including linux, OSX, etc.)
69
+
70
+ A Command can also be executed:
71
+
36
72
  cmd.run
37
73
  if cmd.success?
38
74
  puts cmd.output
39
75
  end
40
76
 
77
+ By default execution is done by launching a shell to interpret the command.
78
+ Unquoted arguments will be interpreted by the shell in that case:
79
+
80
+ cmd = SysCmd.command 'echo' do
81
+ argument '$BASH'
82
+ end
83
+ cmd.run
84
+ puts cmd.output # /bin/bash
85
+
86
+ Shell execution can be avoided by passing the +:direct+ option with value
87
+ +true+ to the +run+ method. In that case the command is executed directly,
88
+ and no shell interpretation takes place, so:
89
+
90
+ cmd.run direct: true
91
+ puts cmd.output # $BASH
92
+
93
+ If the command options include
94
+ an option with the name of the command being defined it is used to
95
+ replace the command name. This can be handy to pass user configuration
96
+ to define the location/name of commands in a particular system:
97
+
98
+ options = {
99
+ curl: "/usr/local/bin/curl"
100
+ }
101
+ cmd = SysCmd.command 'curl', options do
102
+ file 'http://jsonip.com'
103
+ end
104
+ puts cmd.to_s # /usr/local/bin/curl http://jsonip.com
105
+
106
+
41
107
  ## Development
42
108
 
43
109
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
data/lib/sys_cmd.rb CHANGED
@@ -26,7 +26,7 @@ module SysCmd
26
26
  @last_arg = :command
27
27
  end
28
28
 
29
- attr_reader :command
29
+ attr_reader :command, :shell
30
30
 
31
31
  def to_s
32
32
  command
@@ -124,14 +124,13 @@ module SysCmd
124
124
  @last_arg = :file
125
125
  end
126
126
 
127
- # Add the value of an option.
127
+ # Add the value of an option (or a quoted argument)
128
128
  #
129
129
  # option '-x'
130
130
  # join_value 123 # -x 123
131
131
  #
132
132
  def value(value, options = {})
133
133
  return unless @shell.applicable?(options)
134
- raise "An option is required for value" unless @last_arg == :option
135
134
  @command << ' ' << @shell.escape_filename(value.to_s)
136
135
  @last_arg = :value
137
136
  end
@@ -162,10 +161,12 @@ module SysCmd
162
161
  @last_arg = :value
163
162
  end
164
163
 
165
- # Add a generic argument to the command.
164
+ # Add an unquoted argument to the command.
165
+ # This is not useful for commands executed directly, since the arguments
166
+ # are note interpreted by a shell in that case.
166
167
  def argument(value, options = {})
167
168
  return unless @shell.applicable?(options)
168
- @command << ' ' << @shell.escape_value(value)
169
+ @command << ' ' << value.to_s
169
170
  @last_arg = :argument
170
171
  end
171
172
 
@@ -173,8 +174,14 @@ module SysCmd
173
174
 
174
175
  # An executable system command
175
176
  class Command
176
- def initialize(command)
177
- @command = command
177
+ def initialize(command, options = {})
178
+ if command.respond_to?(:shell)
179
+ @command = command.command
180
+ @shell = command.shell
181
+ else
182
+ @command = command
183
+ @shell = Shell.new(options)
184
+ end
178
185
  @output = nil
179
186
  @status = nil
180
187
  @error_output = nil
@@ -185,6 +192,17 @@ module SysCmd
185
192
 
186
193
  # Execute the command.
187
194
  #
195
+ # By default the command is executed by a shell. In this case,
196
+ # unquoted arguments are interpreted by the shell, e.g.
197
+ #
198
+ # SysCmd.command('echo $BASH').run # /bin/bash
199
+ #
200
+ # When the +:direct+ option is set to true, no shell is used and
201
+ # the command is directly executed; in this case unquoted arguments
202
+ # are not interpreted:
203
+ #
204
+ # SysCmd.command('echo $BASH').run # $BASH
205
+ #
188
206
  # The exit status of the command is retained in the +status+ attribute
189
207
  # (and its numeric value in the +status_value+ attribute).
190
208
  #
@@ -213,14 +231,19 @@ module SysCmd
213
231
  #
214
232
  def run(options = {})
215
233
  @output = @status = @error_output = @error = nil
234
+ if options[:direct]
235
+ command = @shell.split(@command)
236
+ else
237
+ command = [@command]
238
+ end
216
239
  begin
217
240
  case options[:error_output]
218
241
  when :mix # mix stderr with stdout
219
- @output, @status = Open3.capture2e(@command)
242
+ @output, @status = Open3.capture2e(*command)
220
243
  when :separate
221
- @output, @error_output, @status = Open3.capture3(@command)
244
+ @output, @error_output, @status = Open3.capture3(*command)
222
245
  else # :console (do not capture stderr output)
223
- @output, @status = Open3.capture2(@command)
246
+ @output, @status = Open3.capture2(*command)
224
247
  end
225
248
  rescue => error
226
249
  @error = error.dup
@@ -265,8 +288,14 @@ module SysCmd
265
288
  #
266
289
  def self.command(command, options = {}, &block)
267
290
  definition = Definition.new(command, options)
268
- definition.instance_eval &block if block
269
- Command.new definition.command
291
+ if block
292
+ if block.arity == 1
293
+ block.call definition
294
+ else
295
+ definition.instance_eval &block
296
+ end
297
+ end
298
+ Command.new definition
270
299
  end
271
300
 
272
301
  # Build and run a command
@@ -305,6 +334,26 @@ module SysCmd
305
334
  end
306
335
  end
307
336
 
337
+ def self.split(text, options = {})
338
+ case os_type(options)
339
+ when :windows
340
+ words = []
341
+ field = ''
342
+ line.scan(/\G\s*(?>([^\s\^\'\"]+)|'([^\']*)'|"((?:[^\"\^]|\\.)*)"|(\^.?)|(\S))(\s|\z)?/m) do
343
+ |word, sq, dq, esc, garbage, sep|
344
+ raise ArgumentError, "Unmatched double quote: #{line.inspect}" if garbage
345
+ field << (word || sq || (dq || esc).gsub(/\^(.)/, '\\1'))
346
+ if sep
347
+ words << field
348
+ field = ''
349
+ end
350
+ end
351
+ words
352
+ else
353
+ Shellwords.shellsplit(text)
354
+ end
355
+ end
356
+
308
357
  def self.line_separator(options = {})
309
358
  case os_type(options)
310
359
  when :windows
@@ -335,6 +384,10 @@ module SysCmd
335
384
  SysCmd.escape(text, os: @type)
336
385
  end
337
386
 
387
+ def split(text)
388
+ SysCmd.split(text, os: @type)
389
+ end
390
+
338
391
  def escape_filename(name)
339
392
  escape name
340
393
  end
@@ -1,3 +1,3 @@
1
1
  module SysCmd
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/sys_cmd.gemspec CHANGED
@@ -24,4 +24,6 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency "bundler", "~> 1.9"
25
25
  spec.add_development_dependency "rake", "~> 10.0"
26
26
  spec.add_development_dependency "minitest", "~> 5.4"
27
+
28
+ spec.required_ruby_version = '>= 1.9.3'
27
29
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sys_cmd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Javier Goizueta
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-04-26 00:00:00.000000000 Z
11
+ date: 2015-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: os
@@ -96,7 +96,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
96
96
  requirements:
97
97
  - - ">="
98
98
  - !ruby/object:Gem::Version
99
- version: '0'
99
+ version: 1.9.3
100
100
  required_rubygems_version: !ruby/object:Gem::Requirement
101
101
  requirements:
102
102
  - - ">="
@@ -104,8 +104,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
104
  version: '0'
105
105
  requirements: []
106
106
  rubyforge_project:
107
- rubygems_version: 2.4.6
107
+ rubygems_version: 2.2.2
108
108
  signing_key:
109
109
  specification_version: 4
110
110
  summary: Execute shell commands.
111
111
  test_files: []
112
+ has_rdoc: