unix_utils 0.0.14 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,13 @@
1
+ 0.0.15 / 2012-11-09
2
+
3
+ * Enhancements
4
+
5
+ * Back to stdlib open3 because C extension support is not enabled by default in JRuby 1.7+
6
+
7
+ * Known issues
8
+
9
+ * stderr is not captured in JRuby 1.7.0 because of https://jira.codehaus.org/browse/JRUBY-6986
10
+
1
11
  0.0.14 / 2012-07-06
2
12
 
3
13
  * Breaking changes
data/Gemfile CHANGED
@@ -1,9 +1,3 @@
1
1
  source :rubygems
2
2
 
3
3
  gemspec
4
-
5
- # development dependencies
6
- gem 'minitest'
7
- gem 'minitest-reporters'
8
- gem 'yard'
9
- # gem 'ruby-prof'
@@ -2,7 +2,9 @@
2
2
 
3
3
  Like FileUtils, but provides zip, unzip, bzip2, bunzip2, tar, untar, sed, du, md5sum, shasum, cut, head, tail, wc, unix2dos, dos2unix, iconv, curl, perl, etc.
4
4
 
5
- Works in MRI 1.8.7+, MRI 1.9.2+, and JRuby 1.6.7+
5
+ You must have these binaries in your `PATH`. _Not_ a pure-ruby implementation of all these UNIX greats!
6
+
7
+ Works in MRI 1.8.7+, MRI 1.9.2+, and JRuby 1.6.7+. No gem dependencies; uses stdlib
6
8
 
7
9
  ## Real-world usage
8
10
 
@@ -79,13 +81,18 @@ This will load an entire file into memory before it can be processed...
79
81
 
80
82
  You get the same low memory footprint with
81
83
 
82
- str = UnixUtils.shasum('kittens.zip', 256)
84
+ str = UnixUtils.shasum 'kittens.zip', 256
83
85
 
84
86
  ## Compatibility
85
87
 
86
- Now using [`posix-spawn`](https://github.com/rtomayko/posix-spawn) for speed. Thanks for the suggestion [jjb](https://github.com/jjb)!
88
+ Uses `open3` because it's in the Ruby stdlib and is consistent across MRI and JRuby.
89
+
90
+ ## Wishlist
87
91
 
88
- Previously used `open3` because it's in the Ruby stdlib and is consistent across MRI and JRuby.
92
+ * cheat sheet based on [GNU Coreutils cheat sheet](www.catonmat.net/download/gnu-coreutils-cheat-sheet.pdf)
93
+ * yarddocs
94
+ * properly use Dir.tmpdir(name), etc.
95
+ * smarter tmp file name generation - don't include url params for curl, etc.
89
96
 
90
97
  ## Authors
91
98
 
@@ -93,4 +100,4 @@ Previously used `open3` because it's in the Ruby stdlib and is consistent across
93
100
 
94
101
  ## Copyright
95
102
 
96
- Copyright (c) 2012 Brighter Planet. See LICENSE for details.
103
+ Copyright (c) 2012 Seamus Abshere
@@ -2,7 +2,7 @@ require 'fileutils'
2
2
  require 'tmpdir'
3
3
  require 'uri'
4
4
  require 'stringio'
5
- require 'posix/spawn'
5
+ require 'open3'
6
6
  require 'securerandom'
7
7
  require "unix_utils/version"
8
8
 
@@ -14,14 +14,14 @@ module UnixUtils
14
14
  outfile = tmp_path url
15
15
  if url.start_with?('file://') or not url.include?('://')
16
16
  # deal with local files
17
- infile = ::File.expand_path url.sub('file://', '')
17
+ infile = File.expand_path url.sub('file://', '')
18
18
  unless File.readable?(infile)
19
19
  raise "[unix_utils] #{url.inspect} does not exist or is not readable on the local filesystem."
20
20
  end
21
- ::FileUtils.cp infile, outfile
21
+ FileUtils.cp infile, outfile
22
22
  return outfile
23
23
  end
24
- uri = ::URI.parse url
24
+ uri = URI.parse url
25
25
  argv = [ 'curl', '--location', '--show-error', '--silent', '--compressed', '--header', 'Expect: ' ]
26
26
  if form_data
27
27
  argv += [ '--data', form_data ]
@@ -42,7 +42,7 @@ module UnixUtils
42
42
  # $ sha256sum --binary .bash_profile
43
43
  # 01b1210962b3d1e5e1ccba26f93d98efbb7b315b463f9f6bdb40ab496728d886 *.bash_profile
44
44
  def self.shasum(infile, algorithm)
45
- infile = ::File.expand_path infile
45
+ infile = File.expand_path infile
46
46
  if available?('shasum')
47
47
  argv = ['shasum', '--binary', '-a', algorithm.to_s, infile]
48
48
  stdout = spawn argv
@@ -62,7 +62,7 @@ module UnixUtils
62
62
  # $ md5sum --binary .mysql_history
63
63
  # 8d01e54ab8142d6786850e22d55a1b6c *.mysql_history
64
64
  def self.md5sum(infile)
65
- infile = ::File.expand_path infile
65
+ infile = File.expand_path infile
66
66
  if available?('md5sum')
67
67
  argv = ['md5sum', '--binary', infile]
68
68
  stdout = spawn argv
@@ -75,14 +75,14 @@ module UnixUtils
75
75
  end
76
76
 
77
77
  def self.du(srcdir)
78
- srcdir = ::File.expand_path srcdir
78
+ srcdir = File.expand_path srcdir
79
79
  argv = ['du', '-sk', srcdir]
80
80
  stdout = spawn argv
81
81
  stdout.strip.split(/\s+/).first.to_i
82
82
  end
83
83
 
84
84
  def self.wc(infile)
85
- infile = ::File.expand_path infile
85
+ infile = File.expand_path infile
86
86
  argv = ['wc', infile]
87
87
  stdout = spawn argv
88
88
  stdout.strip.split(/\s+/)[0..2].map { |s| s.to_i }
@@ -91,25 +91,25 @@ module UnixUtils
91
91
  # --
92
92
 
93
93
  def self.unzip(infile)
94
- infile = ::File.expand_path infile
94
+ infile = File.expand_path infile
95
95
  destdir = tmp_path infile
96
- ::FileUtils.mkdir destdir
96
+ FileUtils.mkdir destdir
97
97
  argv = ['unzip', '-qq', '-n', infile, '-d', destdir]
98
98
  spawn argv
99
99
  destdir
100
100
  end
101
101
 
102
102
  def self.untar(infile)
103
- infile = ::File.expand_path infile
103
+ infile = File.expand_path infile
104
104
  destdir = tmp_path infile
105
- ::FileUtils.mkdir destdir
105
+ FileUtils.mkdir destdir
106
106
  argv = ['tar', '-xf', infile, '-C', destdir]
107
107
  spawn argv
108
108
  destdir
109
109
  end
110
110
 
111
111
  def self.gunzip(infile)
112
- infile = ::File.expand_path infile
112
+ infile = File.expand_path infile
113
113
  outfile = tmp_path infile
114
114
  argv = ['gunzip', '--stdout', infile]
115
115
  spawn argv, :write_to => outfile
@@ -117,7 +117,7 @@ module UnixUtils
117
117
  end
118
118
 
119
119
  def self.bunzip2(infile)
120
- infile = ::File.expand_path infile
120
+ infile = File.expand_path infile
121
121
  outfile = tmp_path infile
122
122
  argv = ['bunzip2', '--stdout', infile]
123
123
  spawn argv, :write_to => outfile
@@ -127,7 +127,7 @@ module UnixUtils
127
127
  # --
128
128
 
129
129
  def self.bzip2(infile)
130
- infile = ::File.expand_path infile
130
+ infile = File.expand_path infile
131
131
  outfile = tmp_path infile, '.bz2'
132
132
  argv = ['bzip2', '--keep', '--stdout', infile]
133
133
  spawn argv, :write_to => outfile
@@ -135,7 +135,7 @@ module UnixUtils
135
135
  end
136
136
 
137
137
  def self.tar(srcdir)
138
- srcdir = ::File.expand_path srcdir
138
+ srcdir = File.expand_path srcdir
139
139
  outfile = tmp_path srcdir, '.tar'
140
140
  argv = ['tar', '-cf', outfile, '-C', srcdir, '.']
141
141
  spawn argv
@@ -143,7 +143,7 @@ module UnixUtils
143
143
  end
144
144
 
145
145
  def self.zip(srcdir)
146
- srcdir = ::File.expand_path srcdir
146
+ srcdir = File.expand_path srcdir
147
147
  outfile = tmp_path srcdir, '.zip'
148
148
  argv = ['zip', '-rq', outfile, '.']
149
149
  spawn argv, :chdir => srcdir
@@ -151,7 +151,7 @@ module UnixUtils
151
151
  end
152
152
 
153
153
  def self.gzip(infile)
154
- infile = ::File.expand_path infile
154
+ infile = File.expand_path infile
155
155
  outfile = tmp_path infile, '.gz'
156
156
  argv = ['gzip', '--stdout', infile]
157
157
  spawn argv, :write_to => outfile
@@ -161,7 +161,7 @@ module UnixUtils
161
161
  # --
162
162
 
163
163
  def self.awk(infile, *expr)
164
- infile = ::File.expand_path infile
164
+ infile = File.expand_path infile
165
165
  outfile = tmp_path infile
166
166
  bin = available?('gawk') ? 'gawk' : 'awk'
167
167
  argv = [bin, expr, infile].flatten
@@ -171,7 +171,7 @@ module UnixUtils
171
171
 
172
172
  # Yes, this is a very limited use of perl.
173
173
  def self.perl(infile, *expr)
174
- infile = ::File.expand_path infile
174
+ infile = File.expand_path infile
175
175
  outfile = tmp_path infile
176
176
  argv = [ 'perl', expr.map { |e| ['-pe', e] }, infile ].flatten
177
177
  spawn argv, :write_to => outfile
@@ -179,7 +179,7 @@ module UnixUtils
179
179
  end
180
180
 
181
181
  def self.unix2dos(infile)
182
- infile = ::File.expand_path infile
182
+ infile = File.expand_path infile
183
183
  if available?('gawk') or available?('awk')
184
184
  awk infile, '{ sub(/\r/, ""); printf("%s\r\n", $0) }'
185
185
  else
@@ -188,7 +188,7 @@ module UnixUtils
188
188
  end
189
189
 
190
190
  def self.dos2unix(infile)
191
- infile = ::File.expand_path infile
191
+ infile = File.expand_path infile
192
192
  if available?('gawk') or available?('awk')
193
193
  awk infile, '{ sub(/\r/, ""); printf("%s\n", $0) }'
194
194
  else
@@ -198,7 +198,7 @@ module UnixUtils
198
198
 
199
199
  # POSIX sed, whether it's provided by sed or gsed
200
200
  def self.sed(infile, *expr)
201
- infile = ::File.expand_path infile
201
+ infile = File.expand_path infile
202
202
  outfile = tmp_path infile
203
203
  bin = available?('sed') ? 'sed' : ['gsed', '--posix']
204
204
  argv = [ bin, expr.map { |e| ['-e', e] }, infile ].flatten
@@ -207,7 +207,7 @@ module UnixUtils
207
207
  end
208
208
 
209
209
  def self.tail(infile, lines)
210
- infile = ::File.expand_path infile
210
+ infile = File.expand_path infile
211
211
  outfile = tmp_path infile
212
212
  argv = ['tail', '-n', lines.to_s, infile]
213
213
  spawn argv, :write_to => outfile
@@ -215,7 +215,7 @@ module UnixUtils
215
215
  end
216
216
 
217
217
  def self.head(infile, lines)
218
- infile = ::File.expand_path infile
218
+ infile = File.expand_path infile
219
219
  outfile = tmp_path infile
220
220
  argv = ['head', '-n', lines.to_s, infile]
221
221
  spawn argv, :write_to => outfile
@@ -224,7 +224,7 @@ module UnixUtils
224
224
 
225
225
  # specify character_positions as a string like "3-5" or "3,9-10"
226
226
  def self.cut(infile, character_positions)
227
- infile = ::File.expand_path infile
227
+ infile = File.expand_path infile
228
228
  outfile = tmp_path infile
229
229
  argv = ['cut', '-c', character_positions, infile]
230
230
  spawn argv, :write_to => outfile
@@ -232,7 +232,7 @@ module UnixUtils
232
232
  end
233
233
 
234
234
  def self.iconv(infile, to, from)
235
- infile = ::File.expand_path infile
235
+ infile = File.expand_path infile
236
236
  outfile = tmp_path infile
237
237
  argv = ['iconv', '-c', '-t', to, '-f', from, infile]
238
238
  spawn argv, :write_to => outfile
@@ -241,7 +241,7 @@ module UnixUtils
241
241
 
242
242
  def self.available?(bin) # :nodoc:
243
243
  bin = bin.to_s
244
- return @@available_query[bin] if defined?(@@available_query) and @@available_query.is_a?(::Hash) and @@available_query.has_key?(bin)
244
+ return @@available_query[bin] if defined?(@@available_query) and @@available_query.is_a?(Hash) and @@available_query.has_key?(bin)
245
245
  @@available_query ||= {}
246
246
  `which #{bin}`
247
247
  @@available_query[bin] = $?.success?
@@ -249,84 +249,93 @@ module UnixUtils
249
249
 
250
250
  def self.tmp_path(ancestor, extname = nil) # :nodoc:
251
251
  ancestor = ancestor.to_s
252
- extname ||= ::File.extname ancestor
253
- basename = ::File.basename ancestor.gsub(/unix_utils_[a-f0-9]{8,}_/, '')
252
+ extname ||= File.extname ancestor
253
+ basename = File.basename ancestor.gsub(/unix_utils_[a-f0-9]{8,}_/, '')
254
254
  basename.gsub! /\W+/, '_'
255
- ::File.join ::Dir.tmpdir, "unix_utils_#{::SecureRandom.hex(4)}_#{basename[0..(234-extname.length)]}#{extname}"
255
+ File.join Dir.tmpdir, "unix_utils_#{SecureRandom.hex(4)}_#{basename[0..(234-extname.length)]}#{extname}"
256
256
  end
257
257
 
258
258
  def self.spawn(argv, options = {}) # :nodoc:
259
- options = options.dup
260
-
261
- input = if (read_from = options.delete(:read_from))
262
- ::File.open(read_from, 'r')
259
+ input = if (read_from = options[:read_from])
260
+ if RUBY_DESCRIPTION =~ /jruby 1.7.0/
261
+ raise "[unix_utils] Can't use `#{argv.first}` since JRuby 1.7.0 has a broken IO implementation!"
262
+ end
263
+ File.open(read_from, 'r')
263
264
  end
264
-
265
- output = if (write_to = options.delete(:write_to))
265
+ output = if (write_to = options[:write_to])
266
266
  output_redirected = true
267
- ::File.open(write_to, 'wb')
267
+ File.open(write_to, 'wb')
268
268
  else
269
269
  output_redirected = false
270
- ::StringIO.new
271
- end
272
-
273
- error = ::StringIO.new
274
-
275
- pid, stdin, stdout, stderr = ::POSIX::Spawn.popen4(*(argv+[options]))
276
-
277
- # lifted from posix-spawn
278
- # https://github.com/rtomayko/posix-spawn/blob/master/lib/posix/spawn/child.rb
279
- readers = [stdout, stderr]
280
- writers = if input
281
- [stdin]
282
- else
283
- stdin.close
284
- []
270
+ StringIO.new
285
271
  end
286
- while readers.any? or writers.any?
287
- ready = ::IO.select(readers, writers, readers + writers)
288
- # write to stdin stream
289
- ready[1].each do |fd|
290
- begin
291
- boom = nil
292
- size = fd.write(input.read(BUFSIZE))
293
- rescue ::Errno::EPIPE => boom
294
- rescue ::Errno::EAGAIN, ::Errno::EINTR
295
- end
296
- if boom || size < BUFSIZE
297
- stdin.close
298
- input.close
299
- writers.delete(stdin)
300
- end
301
- end
302
- # read from stdout and stderr streams
303
- ready[0].each do |fd|
304
- buf = (fd == stdout) ? output : error
305
- begin
306
- buf << fd.readpartial(BUFSIZE)
307
- rescue ::Errno::EAGAIN, ::Errno::EINTR
308
- rescue ::EOFError
309
- readers.delete(fd)
310
- fd.close
311
- end
272
+ error = StringIO.new
273
+ if (chdir = options[:chdir])
274
+ Dir.chdir(chdir) do
275
+ _spawn argv, input, output, error
312
276
  end
277
+ else
278
+ _spawn argv, input, output, error
313
279
  end
314
- # thanks @tmm1 and @rtomayko for showing how it's done!
315
-
316
- ::Process.waitpid pid
317
-
318
280
  error.rewind
319
281
  unless (whole_error = error.read).empty?
320
282
  $stderr.puts "[unix_utils] `#{argv.join(' ')}` STDERR:"
321
283
  $stderr.puts whole_error
322
284
  end
323
-
324
285
  unless output_redirected
325
286
  output.rewind
326
287
  output.read
327
288
  end
328
289
  ensure
329
- [stdin, stdout, stderr, input, output, error].each { |io| io.close if io and not io.closed? }
290
+ [input, output, error].each { |io| io.close if io and not io.closed? }
291
+ end
292
+
293
+ def self._spawn(argv, input, output, error)
294
+ # lifted from posix-spawn
295
+ # https://github.com/rtomayko/posix-spawn/blob/master/lib/posix/spawn/child.rb
296
+ Open3.popen3(*argv) do |stdin, stdout, stderr|
297
+ readers = [stdout, stderr]
298
+ if RUBY_DESCRIPTION =~ /jruby 1.7.0/
299
+ readers.delete stderr
300
+ end
301
+ writers = if input
302
+ [stdin]
303
+ else
304
+ stdin.close
305
+ []
306
+ end
307
+ while readers.any? or writers.any?
308
+ ready = IO.select(readers, writers, readers + writers)
309
+ # write to stdin stream
310
+ ready[1].each do |fd|
311
+ begin
312
+ boom = nil
313
+ size = fd.write input.read(BUFSIZE)
314
+ rescue Errno::EPIPE => boom
315
+ rescue Errno::EAGAIN, Errno::EINTR
316
+ end
317
+ if boom || size < BUFSIZE
318
+ stdin.close
319
+ input.close
320
+ writers.delete stdin
321
+ end
322
+ end
323
+ # read from stdout and stderr streams
324
+ ready[0].each do |fd|
325
+ buf = (fd == stdout) ? output : error
326
+ if fd.eof?
327
+ readers.delete fd
328
+ fd.close
329
+ else
330
+ begin
331
+ buf << fd.readpartial(BUFSIZE)
332
+ rescue Errno::EAGAIN, Errno::EINTR
333
+ end
334
+ end
335
+ end
336
+ end
337
+ # thanks @tmm1 and @rtomayko for showing how it's done!
338
+ end
330
339
  end
331
340
 
332
341
  def self.method_missing(method_id, *args)
@@ -334,9 +343,9 @@ module UnixUtils
334
343
  if respond_to?(base_method_id)
335
344
  begin
336
345
  outfile = send(*([base_method_id]+args))
337
- ::File.read outfile
346
+ File.read outfile
338
347
  ensure
339
- ::FileUtils.rm_f outfile
348
+ FileUtils.rm_f outfile
340
349
  end
341
350
  else
342
351
  super
@@ -1,3 +1,3 @@
1
1
  module UnixUtils
2
- VERSION = "0.0.14"
2
+ VERSION = "0.0.15"
3
3
  end
@@ -1,11 +1,13 @@
1
1
  require 'rubygems'
2
2
  require 'bundler/setup'
3
+ require 'pry'
3
4
 
4
5
  require 'minitest/spec'
5
6
  require 'minitest/autorun'
6
- require 'minitest/reporters'
7
- MiniTest::Unit.runner = MiniTest::SuiteRunner.new
8
- MiniTest::Unit.runner.reporters << MiniTest::Reporters::SpecReporter.new
7
+ if RUBY_VERSION >= '1.9'
8
+ require 'minitest/reporters'
9
+ MiniTest::Reporters.use! MiniTest::Reporters::SpecReporter.new
10
+ end
9
11
 
10
12
  require 'unix_utils'
11
13
 
@@ -17,5 +17,10 @@ Gem::Specification.new do |gem|
17
17
  gem.version = UnixUtils::VERSION
18
18
  gem.license = 'MIT'
19
19
 
20
- gem.add_runtime_dependency 'posix-spawn'
20
+ gem.add_development_dependency 'minitest'
21
+ if RUBY_VERSION >= '1.9'
22
+ gem.add_development_dependency 'minitest-reporters'
23
+ end
24
+ gem.add_development_dependency 'yard'
25
+ gem.add_development_dependency 'pry'
21
26
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unix_utils
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.14
4
+ version: 0.0.15
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,17 +9,65 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-06 00:00:00.000000000 Z
12
+ date: 2012-11-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: posix-spawn
15
+ name: minitest
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
20
20
  - !ruby/object:Gem::Version
21
21
  version: '0'
22
- type: :runtime
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: minitest-reporters
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: yard
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: pry
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
23
71
  prerelease: false
24
72
  version_requirements: !ruby/object:Gem::Requirement
25
73
  none: false