unix_utils 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.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
5
+ # development dependencies
6
+ gem 'minitest'
7
+ gem 'minitest-reporters'
data/History.txt ADDED
@@ -0,0 +1,9 @@
1
+ == 0.0.2 / 2012-02-16
2
+
3
+ * Bug fixes
4
+
5
+ * Fix use of splat internally so that it actually runs in MRI 1.8.7 and JRuby
6
+
7
+ == 0.0.1 / 2012-02-16 (yanked!)
8
+
9
+ * Birthday!
data/README.markdown ADDED
@@ -0,0 +1,77 @@
1
+ # unix_utils
2
+
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
+
5
+ Works in MRI 1.8.7+, MRI 1.9.2+, and JRuby 1.6.7+
6
+
7
+ ## What to expect
8
+
9
+ For commands like zip, untar, sed, head, cut, dos2unix, etc.:
10
+
11
+ 1. Just returns a path to the output, randomly named, located in the system tmp dir (`UnixUtils.unzip('kittens.zip)` → `'/tmp/unix_utils-129392301-kittens'`)
12
+ 2. Never touches the input
13
+ 3. Sticks a useful file extension on the output, if applicable (`UnixUtils.tar('puppies/')` → `'/tmp/unix_utils-99293192-puppies.tar'`)
14
+
15
+ For commands like du, md5sum, shasum, etc.:
16
+
17
+ 1. Just returns the good stuff (the checksum, for example, not the filename that is listed after it in the standard command output)
18
+ 2. Never touches the input
19
+
20
+ ## Philosophy
21
+
22
+ Use a subprocess to perform a big task and then get out of memory.
23
+
24
+ ## But I can just spawn these myself
25
+
26
+ This lib was created to ease the pain of remembering command options for Gentoo, deciding which spawning method to use, possibly handling pipes...
27
+
28
+ require 'tmpdir'
29
+ destdir = File.join(Dir.tmpdir, "kittens_#{Kernel.rand(1e11)}")
30
+ require 'open3'
31
+ Open3.popen3('unzip', '-q', '-n', 'kittens.zip, '-d', destdir) do |stdin, stdout, stderr|
32
+ stdin.close
33
+ @error_message = stderr.read
34
+ end
35
+
36
+ is replaced safely with
37
+
38
+ destdir = UnixUtils.unzip 'kittens.zip'
39
+
40
+ ## But I can just use `Digest::SHA256`
41
+
42
+ This will load an entire file into memory before it can be processed...
43
+
44
+ require 'digest'
45
+ str = Digest::SHA256.hexdigest File.read('kittens.zip')
46
+
47
+ ... so you're really replacing this ...
48
+
49
+ sha256 = Digest::SHA256.new
50
+ File.open('kittens.zip', 'r') do |f|
51
+ while chunk = f.read(4_194_304)
52
+ sha256 << chunk
53
+ end
54
+ end
55
+ str = sha256.hexdigest
56
+
57
+ You get the same low memory footprint with
58
+
59
+ str = UnixUtils.shasum('kittens.zip', 256)
60
+
61
+ ## Compatibility
62
+
63
+ Uses `open3` because it's in the Ruby stdlib and is consistent across MRI and JRuby.
64
+
65
+ ## Where it's used
66
+
67
+ * [Brighter Planet Reference Data web service](http://data.brighterplanet.com)
68
+ * [Brighter Planet Emission Estimate web service](http://impact.brighterplanet.com) aka CM1
69
+ * [`remote_table` library](https://github.com/seamusabshere/remote_table)
70
+
71
+ ## Authors
72
+
73
+ * Seamus Abshere <seamus@abshere.net>
74
+
75
+ ## Copyright
76
+
77
+ Copyright (c) 2012 Brighter Planet. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rake'
5
+ require 'rake/testtask'
6
+ Rake::TestTask.new(:test) do |test|
7
+ test.libs << 'lib' << 'test'
8
+ test.pattern = 'test/**/test_*.rb'
9
+ test.verbose = true
10
+ end
11
+
12
+ task :default => :test
data/lib/unix_utils.rb ADDED
@@ -0,0 +1,276 @@
1
+ require 'fileutils'
2
+ require 'tmpdir'
3
+ require 'uri'
4
+ require 'open3'
5
+
6
+ require "unix_utils/version"
7
+
8
+ module UnixUtils
9
+
10
+ def self.curl(url, form_data = nil)
11
+ outfile = tmp_path url
12
+ if url.start_with?('/') or url.start_with?('file://')
13
+ # deal with local files
14
+ ::FileUtils.cp url.delete('file://'), path
15
+ return outfile
16
+ end
17
+ uri = ::URI.parse url
18
+ argv = [ 'curl', '--location', '--show-error', '--silent', '--compressed', '--header', 'Expect: ' ]
19
+ if form_data
20
+ argv += [ '--data', form_data ]
21
+ end
22
+ argv += [ uri.to_s, '--output', outfile ]
23
+ spawn argv
24
+ outfile
25
+ end
26
+
27
+ #--
28
+ # most platforms
29
+ # $ openssl dgst -sha256 .bash_profile
30
+ # SHA256(.bash_profile)= ae12206aaa35dc96273ed421f4e85ca26a1707455e3cc9f054c7f5e2e9c53df6
31
+ # ubuntu 11.04
32
+ # $ shasum -a 256 --portable .mysql_history
33
+ # 856aa27deb0b80b41031c2ddf722af28ba2a8c4999ff9cf2d45f33bc67d992ba ?.mysql_history
34
+ # fedora 7
35
+ # $ sha256sum --binary .bash_profile
36
+ # 01b1210962b3d1e5e1ccba26f93d98efbb7b315b463f9f6bdb40ab496728d886 *.bash_profile
37
+ def self.shasum(infile, algorithm)
38
+ if available?('shasum')
39
+ argv = ['shasum', '--binary', '-a', algorithm.to_s, infile]
40
+ stdout = spawn argv
41
+ stdout.strip.split(' ').first
42
+ else
43
+ argv = ['openssl', 'dgst', "-sha#{algorithm}", infile]
44
+ stdout = spawn argv
45
+ stdout.strip.split(' ').last
46
+ end
47
+ end
48
+
49
+ #--
50
+ # os x 10.6.8; most platforms
51
+ # $ openssl dgst -md5 .bashrc
52
+ # MD5(.bashrc)= 88f464fb6d1d6fe9141135248bf7b265
53
+ # ubuntu 11.04; fedora 7; gentoo
54
+ # $ md5sum --binary .mysql_history
55
+ # 8d01e54ab8142d6786850e22d55a1b6c *.mysql_history
56
+ def self.md5sum(infile)
57
+ if available?('md5sum')
58
+ argv = ['md5sum', '--binary', infile]
59
+ stdout = spawn argv
60
+ stdout.strip.split(' ').first
61
+ else
62
+ argv = ['openssl', 'dgst', '-md5', infile]
63
+ stdout = spawn argv
64
+ stdout.strip.split(' ').last
65
+ end
66
+ end
67
+
68
+ def self.du(srcdir)
69
+ argv = ['du', srcdir]
70
+ stdout = spawn argv
71
+ stdout.strip.split(/\s+/).first.to_i
72
+ end
73
+
74
+ def self.wc(infile)
75
+ argv = ['wc', infile]
76
+ stdout = spawn argv
77
+ stdout.strip.split(/\s+/)[0..2].map { |s| s.to_i }
78
+ end
79
+
80
+ # --
81
+
82
+ def self.unzip(infile)
83
+ destdir = tmp_path infile
84
+ ::FileUtils.mkdir destdir
85
+ argv = ['unzip', '-qq', '-n', infile, '-d', destdir]
86
+ spawn argv
87
+ destdir
88
+ end
89
+
90
+ def self.untar(infile)
91
+ destdir = tmp_path infile
92
+ ::FileUtils.mkdir destdir
93
+ argv = ['tar', '-xf', infile, '-C', destdir]
94
+ spawn argv
95
+ destdir
96
+ end
97
+
98
+ def self.gunzip(infile)
99
+ outfile = tmp_path infile
100
+ argv = ['gunzip', '--stdout', infile]
101
+ spawn argv, :write_to => outfile
102
+ outfile
103
+ end
104
+
105
+ def self.bunzip2(infile)
106
+ outfile = tmp_path infile
107
+ argv = ['bunzip2', '--stdout', infile,]
108
+ spawn argv, :write_to => outfile
109
+ outfile
110
+ end
111
+
112
+ # --
113
+
114
+ def self.bzip2(infile)
115
+ outfile = tmp_path infile, '.bz2'
116
+ argv = ['bzip2', '--keep', '--stdout', infile]
117
+ spawn argv, :write_to => outfile
118
+ outfile
119
+ end
120
+
121
+ def self.tar(srcdir)
122
+ outfile = tmp_path srcdir, '.tar'
123
+ argv = ['tar', '-cf', outfile, '-C', srcdir, '.']
124
+ spawn argv
125
+ outfile
126
+ end
127
+
128
+ def self.zip(srcdir)
129
+ outfile = tmp_path srcdir, '.zip'
130
+ argv = ['zip', '-rq', outfile, '.']
131
+ spawn argv, :chdir => srcdir
132
+ outfile
133
+ end
134
+
135
+ def self.gzip(infile)
136
+ outfile = tmp_path infile, '.gz'
137
+ argv = ['gzip', '--stdout', infile]
138
+ spawn argv, :write_to => outfile
139
+ outfile
140
+ end
141
+
142
+ # --
143
+
144
+ def self.awk(infile, *expr)
145
+ outfile = tmp_path infile
146
+ bin = available?('gawk') ? 'gawk' : 'awk'
147
+ argv = [bin, expr, infile].flatten
148
+ spawn argv, :write_to => outfile
149
+ outfile
150
+ end
151
+
152
+ # Yes, this is a very limited use of perl.
153
+ def self.perl(infile, *expr)
154
+ outfile = tmp_path infile
155
+ argv = [ 'perl', expr.map { |e| ['-pe', e] } ].flatten
156
+ spawn argv, :read_from => infile, :write_to => outfile
157
+ outfile
158
+ end
159
+
160
+ def self.unix2dos(infile)
161
+ if available?('gawk') or available?('awk')
162
+ awk infile, '{ sub(/\r/, ""); printf("%s\r\n", $0) }'
163
+ else
164
+ perl infile, 's/\r\n|\n|\r/\r\n/g'
165
+ end
166
+ end
167
+
168
+ def self.dos2unix(infile)
169
+ if available?('gawk') or available?('awk')
170
+ awk infile, '{ sub(/\r/, ""); printf("%s\n", $0) }'
171
+ else
172
+ perl infile, 's/\r\n|\n|\r/\n/g'
173
+ end
174
+ end
175
+
176
+ def self.sed(infile, *expr)
177
+ outfile = tmp_path infile
178
+ bin = available?('gsed') ? 'gsed' : 'sed'
179
+ argv = [ bin, expr.map { |e| ['-e', e] } ].flatten
180
+ spawn argv, :read_from => infile, :write_to => outfile
181
+ outfile
182
+ end
183
+
184
+ def self.tail(infile, lines)
185
+ outfile = tmp_path infile
186
+ argv = ['tail', '-n', lines.to_s, infile]
187
+ spawn argv, :write_to => outfile
188
+ outfile
189
+ end
190
+
191
+ def self.head(infile, lines)
192
+ outfile = tmp_path infile
193
+ argv = ['head', '-n', lines.to_s, infile]
194
+ spawn argv, :write_to => outfile
195
+ outfile
196
+ end
197
+
198
+ # specify character_positions as a string like "3-5" or "3,9-10"
199
+ def self.cut(infile, character_positions)
200
+ outfile = tmp_path infile
201
+ argv = ['cut', '-c', character_positions, infile]
202
+ spawn argv, :write_to => outfile
203
+ outfile
204
+ end
205
+
206
+ def self.iconv(infile, to, from)
207
+ outfile = tmp_path infile
208
+ argv = ['iconv', '-t', to, '-f', from, infile]
209
+ spawn argv, :write_to => outfile
210
+ outfile
211
+ end
212
+
213
+ def self.available?(bin) # :nodoc:
214
+ bin = bin.to_s
215
+ return @@available_query[bin] if defined?(@@available_query) and @@available_query.is_a?(::Hash) and @@available_query.has_key?(bin)
216
+ @@available_query ||= {}
217
+ @@available_query[bin] = ::Kernel.system 'which', '-s', bin
218
+ end
219
+
220
+ def self.tmp_path(ancestor, extname = nil) # :nodoc:
221
+ extname ||= ::File.extname ancestor
222
+ basename = ::File.basename ancestor.sub(/^unix_utils-[0-9]+-/, '').gsub(/\W+/, '_')
223
+ name = basename + extname
224
+ ::Kernel.srand
225
+ ::File.join ::Dir.tmpdir, "unix_utils-#{::Kernel.rand(1e11)}-#{name}"
226
+ end
227
+
228
+ def self.spawn(argv, options = {}) # :nodoc:
229
+ if options[:chdir]
230
+ old_pwd = ::Dir.pwd
231
+ ::Dir.chdir options[:chdir]
232
+ end
233
+
234
+ whole_stdout = nil
235
+ whole_stderr = nil
236
+
237
+ ::Open3.popen3(*argv) do |stdin, stdout, stderr|
238
+ # deal with STDIN
239
+ if options[:read_from]
240
+ ::File.open(options[:read_from], 'r') do |in_f|
241
+ while chunk = in_f.read(4_194_304)
242
+ stdin.write chunk
243
+ end
244
+ end
245
+ end
246
+ stdin.close
247
+
248
+ # deal with STDOUT
249
+ if options[:write_to]
250
+ ::File.open(options[:write_to], 'wb') do |out_f|
251
+ while chunk = stdout.read(4_194_304)
252
+ out_f.write chunk
253
+ end
254
+ end
255
+ whole_stdout = "Redirected to #{options[:write_to]}"
256
+ else
257
+ whole_stdout = stdout.read
258
+ end
259
+
260
+ # deal with STDERR
261
+ whole_stderr = stderr.read
262
+ end
263
+
264
+ unless whole_stderr.empty?
265
+ $stderr.puts "[unix_utils] `#{argv.join(' ')}` STDERR:"
266
+ $stderr.puts whole_stderr
267
+ end
268
+
269
+ whole_stdout
270
+
271
+ ensure
272
+ if options[:chdir]
273
+ ::Dir.chdir old_pwd
274
+ end
275
+ end
276
+ end
@@ -0,0 +1,3 @@
1
+ module UnixUtils
2
+ VERSION = "0.0.2"
3
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,73 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'minitest/spec'
5
+ require 'minitest/autorun'
6
+ require 'minitest/reporters'
7
+ MiniTest::Unit.runner = MiniTest::SuiteRunner.new
8
+ MiniTest::Unit.runner.reporters << MiniTest::Reporters::SpecReporter.new
9
+
10
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
11
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
12
+ require 'unix_utils'
13
+
14
+ require 'fileutils'
15
+ require 'tmpdir'
16
+ require 'tempfile'
17
+
18
+ module TestHelper
19
+ def assert_does_not_touch(method_id, *args)
20
+ infile_or_srcdir = args.first
21
+ mtime = File.mtime infile_or_srcdir
22
+ kind = File.file?(infile_or_srcdir) ? :file : :directory
23
+ case kind
24
+ when :file
25
+ checksum = UnixUtils.shasum infile_or_srcdir, 256
26
+ when :directory
27
+ size = UnixUtils.du infile_or_srcdir
28
+ end
29
+ destdir = UnixUtils.send(*([method_id] + args))
30
+ safe_delete destdir
31
+ File.mtime(infile_or_srcdir).must_equal mtime
32
+ case kind
33
+ when :file
34
+ UnixUtils.shasum(infile_or_srcdir, 256).must_equal checksum
35
+ when :directory
36
+ UnixUtils.du(infile_or_srcdir).must_equal size
37
+ end
38
+ end
39
+
40
+ def assert_unpack_dir(method_id, infile)
41
+ destdir = UnixUtils.send method_id, infile
42
+ File.directory?(destdir).must_equal true
43
+ Dir.entries(destdir).must_equal %w{ . .. hello_world.txt hello_world.xml }
44
+ File.dirname(destdir).start_with?(Dir.tmpdir).must_equal true
45
+ safe_delete destdir
46
+ end
47
+
48
+ def assert_unpack_file(method_id, infile)
49
+ outfile = UnixUtils.send method_id, infile
50
+ File.file?(outfile).must_equal true
51
+ `file #{outfile}`.chomp.must_match %r{text}
52
+ File.dirname(outfile).start_with?(Dir.tmpdir).must_equal true
53
+ safe_delete outfile
54
+ end
55
+
56
+ def assert_pack(method_id, infile)
57
+ outfile = UnixUtils.send method_id, infile
58
+ File.file?(outfile).must_equal true
59
+ `file #{outfile}`.chomp.must_match %r{\b#{method_id.to_s.downcase}\b}
60
+ File.dirname(outfile).start_with?(Dir.tmpdir).must_equal true
61
+ safe_delete outfile
62
+ end
63
+
64
+ def safe_delete(path)
65
+ path = File.expand_path path
66
+ raise "Refusing to rm -rf #{path} because it's not in #{Dir.tmpdir}" unless File.dirname(path).start_with?(Dir.tmpdir)
67
+ FileUtils.rm_rf path
68
+ end
69
+ end
70
+
71
+ class MiniTest::Spec
72
+ include TestHelper
73
+ end
Binary file
Binary file
@@ -0,0 +1 @@
1
+ hello world
@@ -0,0 +1 @@
1
+ <b>hello world</b>
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1 @@
1
+ Hola, �c�mo est�s?
@@ -0,0 +1 @@
1
+ Hola, ¿cómo estás?
@@ -0,0 +1,383 @@
1
+ # encoding: UTF-8
2
+ require 'helper'
3
+
4
+ describe UnixUtils do
5
+ before do
6
+ @old_pwd = Dir.pwd
7
+ Dir.chdir File.expand_path('../target', __FILE__)
8
+ end
9
+
10
+ after do
11
+ Dir.chdir @old_pwd
12
+ end
13
+
14
+ describe :curl do
15
+ it "downloads to a temp file" do
16
+ outfile = UnixUtils.curl('http://brighterplanet.com')
17
+ File.read(outfile).must_match %r{sustain}i
18
+ safe_delete outfile
19
+ end
20
+ end
21
+
22
+ describe :shasum do
23
+ it "checksums a file with SHA-1" do
24
+ UnixUtils.shasum('directory.zip', 1).must_equal 'c0abb36c923ed7bf87ebb8d7097cb8e264e528d2'
25
+ end
26
+ it "checksums a file with SHA-256" do
27
+ UnixUtils.shasum('directory.zip', 256).must_equal '661af2b7b0993088263228b071b649a88d82a6a655562162c32307d1e127f27a'
28
+ end
29
+ end
30
+
31
+ describe :md5sum do
32
+ it "checksums a file" do
33
+ UnixUtils.md5sum('directory.zip').must_equal 'd6e15da798ae19551da6c49ec09afaef'
34
+ end
35
+ end
36
+
37
+ describe :du do
38
+ it "calculates the size of a directory in bytes" do
39
+ UnixUtils.du('directory').must_equal 16
40
+ end
41
+ end
42
+
43
+ describe :unzip do
44
+ before do
45
+ @infile = 'directory.zip'
46
+ @anonymous_infile = 'directory-really-a-z_i_p-shh'
47
+ end
48
+ it "unpacks a DIRECTORY located in the tmp directory" do
49
+ assert_unpack_dir :unzip, @infile
50
+ end
51
+ it "accepts unsemantic filenames" do
52
+ assert_unpack_dir :unzip, @anonymous_infile
53
+ end
54
+ it "does not touch the infile" do
55
+ assert_does_not_touch :unzip, @infile
56
+ end
57
+ end
58
+
59
+ describe :untar do
60
+ before do
61
+ @infile = 'directory.tar'
62
+ @anonymous_infile = 'directory-really-a-t_a_r-shh'
63
+ end
64
+ it "unpacks a DIRECTORY located in the tmp directory" do
65
+ assert_unpack_dir :untar, @infile
66
+ end
67
+ it "accepts unsemantic filenames" do
68
+ assert_unpack_dir :untar, @anonymous_infile
69
+ end
70
+ it "does not touch the infile" do
71
+ assert_does_not_touch :untar, @infile
72
+ end
73
+ end
74
+
75
+ describe :bunzip2 do
76
+ before do
77
+ @infile = 'file.bz2'
78
+ @anonymous_infile = 'file-really-a-b_z_2-shh'
79
+ end
80
+ it "unpacks a FILE located in the tmp directory" do
81
+ assert_unpack_file :bunzip2, @infile
82
+ end
83
+ it "accepts unsemantic filenames" do
84
+ assert_unpack_file :bunzip2, @anonymous_infile
85
+ end
86
+ it "does not touch the infile" do
87
+ assert_does_not_touch :bunzip2, @infile
88
+ end
89
+ end
90
+
91
+ describe :gunzip do
92
+ before do
93
+ @infile = 'file.gz'
94
+ @anonymous_infile = 'file-really-a-g_z-shh'
95
+ end
96
+ it "unpacks a FILE located in the tmp directory" do
97
+ assert_unpack_file :gunzip, @infile
98
+ end
99
+ it "accepts unsemantic filenames" do
100
+ assert_unpack_file :gunzip, @anonymous_infile
101
+ end
102
+ it "does not touch the infile" do
103
+ assert_does_not_touch :gunzip, @infile
104
+ end
105
+ end
106
+
107
+ describe :bzip2 do
108
+ before do
109
+ @infile = 'directory.tar'
110
+ end
111
+ it "packs a FILE to a FILE in the tmp directory" do
112
+ assert_pack :bzip2, @infile
113
+ end
114
+ it "does not touch the infile" do
115
+ assert_does_not_touch :bzip2, @infile
116
+ end
117
+ it "sticks on a useful extension" do
118
+ outfile = UnixUtils.bzip2 @infile
119
+ File.extname(outfile).must_equal '.bz2'
120
+ safe_delete outfile
121
+ end
122
+ end
123
+
124
+ describe :gzip do
125
+ before do
126
+ @infile = 'directory.tar'
127
+ end
128
+ it "packs a FILE to a FILE in the tmp directory" do
129
+ assert_pack :gzip, @infile
130
+ end
131
+ it "does not touch the infile" do
132
+ assert_does_not_touch :gzip, @infile
133
+ end
134
+ it "sticks on a useful extension" do
135
+ outfile = UnixUtils.gzip @infile
136
+ File.extname(outfile).must_equal '.gz'
137
+ safe_delete outfile
138
+ end
139
+ end
140
+
141
+ describe :zip do
142
+ before do
143
+ @srcdir = 'directory'
144
+ end
145
+ it "packs a DIRECTORY to a FILE in the tmp directory" do
146
+ assert_pack :zip, @srcdir
147
+ end
148
+ it "does not touch the infile" do
149
+ assert_does_not_touch :zip, @srcdir
150
+ end
151
+ it "sticks on a useful extension" do
152
+ outfile = UnixUtils.zip @srcdir
153
+ File.extname(outfile).must_equal '.zip'
154
+ safe_delete outfile
155
+ end
156
+ end
157
+
158
+ describe :tar do
159
+ before do
160
+ @srcdir = 'directory'
161
+ end
162
+ it "packs a DIRECTORY to a FILE in the tmp directory" do
163
+ assert_pack :tar, @srcdir
164
+ end
165
+ it "does not touch the infile" do
166
+ assert_does_not_touch :tar, @srcdir
167
+ end
168
+ it "sticks on a useful extension" do
169
+ outfile = UnixUtils.tar @srcdir
170
+ File.extname(outfile).must_equal '.tar'
171
+ safe_delete outfile
172
+ end
173
+ end
174
+
175
+ describe :perl do
176
+ before do
177
+ @f = Tempfile.new('perl.txt')
178
+ @f.write "bad\n"*10
179
+ @f.flush
180
+ @infile = @f.path
181
+ end
182
+ after do
183
+ @f.close
184
+ end
185
+ it "processes a file" do
186
+ outfile = UnixUtils.perl(@infile, 's/bad/good/g')
187
+ File.read(outfile).must_equal "good\n"*10
188
+ safe_delete outfile
189
+ end
190
+ it "does not touch the infile" do
191
+ assert_does_not_touch :perl, @infile, 's/bad/good/g'
192
+ end
193
+ it "keeps the original extname" do
194
+ outfile = UnixUtils.perl(@infile, 's/bad/good/g')
195
+ File.extname(outfile).must_equal File.extname(@infile)
196
+ safe_delete outfile
197
+ end
198
+ end
199
+
200
+ describe :awk do
201
+ before do
202
+ @f = Tempfile.new('awk.txt')
203
+ @f.write "bad\n"*10
204
+ @f.flush
205
+ @infile = @f.path
206
+ end
207
+ after do
208
+ @f.close
209
+ end
210
+ it "processes a file" do
211
+ outfile = UnixUtils.awk(@infile, '{gsub(/bad/, "good"); print}')
212
+ File.read(outfile).must_equal "good\n"*10
213
+ safe_delete outfile
214
+ end
215
+ it "does not touch the infile" do
216
+ assert_does_not_touch :awk, @infile, '{gsub(/bad/, "good"); print}'
217
+ end
218
+ it "keeps the original extname" do
219
+ outfile = UnixUtils.awk(@infile, '{gsub(/bad/, "good"); print}')
220
+ File.extname(outfile).must_equal File.extname(@infile)
221
+ safe_delete outfile
222
+ end
223
+ end
224
+
225
+ describe :unix2dos do
226
+ before do
227
+ @f = Tempfile.new('unix2dos.txt')
228
+ @f.write "unix\n"*5
229
+ @f.write "dos\r\n"*5
230
+ @f.flush
231
+ @infile = @f.path
232
+ end
233
+ after do
234
+ @f.close
235
+ end
236
+ it 'converts newlines' do
237
+ outfile = UnixUtils.unix2dos @infile
238
+ File.read(outfile).must_equal("unix\r\n"*5 + "dos\r\n"*5)
239
+ safe_delete outfile
240
+ end
241
+ end
242
+
243
+ describe :dos2unix do
244
+ before do
245
+ @f = Tempfile.new('dos2unix.txt')
246
+ @f.write "dos\r\n"*5
247
+ @f.write "unix\n"*5
248
+ @f.flush
249
+ @infile = @f.path
250
+ end
251
+ after do
252
+ @f.close
253
+ end
254
+ it 'converts newlines' do
255
+ outfile = UnixUtils.dos2unix @infile
256
+ File.read(outfile).must_equal("dos\n"*5 + "unix\n"*5)
257
+ safe_delete outfile
258
+ end
259
+ end
260
+
261
+ describe :wc do
262
+ before do
263
+ @f = Tempfile.new('wc.txt')
264
+ @f.write "dos line\r\n"*5
265
+ @f.write "unix line\n"*5
266
+ @f.flush
267
+ @infile = @f.path
268
+ end
269
+ after do
270
+ @f.close
271
+ end
272
+ it 'counts lines, words, and bytes' do
273
+ UnixUtils.wc(@infile).must_equal [5+5, 10+10, 50+50]
274
+ end
275
+ end
276
+
277
+ describe :sed do
278
+ before do
279
+ @f = Tempfile.new('sed.txt')
280
+ @f.write "bad\n"*10
281
+ @f.flush
282
+ @infile = @f.path
283
+ end
284
+ after do
285
+ @f.close
286
+ end
287
+ it "processes a file" do
288
+ outfile = UnixUtils.sed(@infile, 's/bad/good/g')
289
+ File.read(outfile).must_equal "good\n"*10
290
+ safe_delete outfile
291
+ end
292
+ it "does not touch the infile" do
293
+ assert_does_not_touch :sed, @infile, 's/bad/good/g'
294
+ end
295
+ it "keeps the original extname" do
296
+ outfile = UnixUtils.sed(@infile, 's/bad/good/g')
297
+ File.extname(outfile).must_equal File.extname(@infile)
298
+ safe_delete outfile
299
+ end
300
+
301
+ end
302
+
303
+ describe :tail do
304
+ before do
305
+ @a2z = ('a'..'z').to_a
306
+ @f = Tempfile.new('tail.txt')
307
+ @f.write @a2z.join("\n")
308
+ @f.flush
309
+ @infile = @f.path
310
+ end
311
+ after do
312
+ @f.close
313
+ end
314
+ it 'gets last three lines' do
315
+ outfile = UnixUtils.tail(@infile, 3)
316
+ File.read(outfile).must_equal @a2z.last(3).join("\n")
317
+ safe_delete outfile
318
+ end
319
+ it 'gets trailing lines starting with the third line (inclusive)' do
320
+ outfile = UnixUtils.tail(@infile, '+3')
321
+ File.read(outfile).must_equal @a2z[2..-1].join("\n")
322
+ safe_delete outfile
323
+ end
324
+ end
325
+
326
+ describe :head do
327
+ before do
328
+ @a2z = ('a'..'z').to_a
329
+ @f = Tempfile.new('head.txt')
330
+ @f.write @a2z.join("\n")
331
+ @f.flush
332
+ @infile = @f.path
333
+ end
334
+ after do
335
+ @f.close
336
+ end
337
+ it 'gets first three lines' do
338
+ outfile = UnixUtils.head(@infile, 3)
339
+ File.read(outfile).must_equal(@a2z.first(3).join("\n") + "\n")
340
+ safe_delete outfile
341
+ end
342
+ end
343
+
344
+ describe :cut do
345
+ before do
346
+ @a2z = ('a'..'z').to_a
347
+ @f = Tempfile.new('cut.txt')
348
+ 10.times do
349
+ @f.write(@a2z.join + "\n")
350
+ end
351
+ @f.flush
352
+ @infile = @f.path
353
+ end
354
+ after do
355
+ @f.close
356
+ end
357
+ it 'cuts out character positions' do
358
+ outfile = UnixUtils.cut(@infile, '1,12,13,15,19,20')
359
+ almosts = (0..9).map { |i| 'almost' }.join("\n") + "\n"
360
+ File.read(outfile).must_equal almosts
361
+ safe_delete outfile
362
+ end
363
+ it 'cuts out character ranges (inclusive)' do
364
+ outfile = UnixUtils.cut(@infile, '3-6')
365
+ cdefs = (0..9).map { |i| 'cdef' }.join("\n") + "\n"
366
+ File.read(outfile).must_equal cdefs
367
+ safe_delete outfile
368
+ end
369
+ end
370
+
371
+ describe :iconv do
372
+ it 'converts files from utf-8 to latin1' do
373
+ outfile = UnixUtils.iconv('utf8.txt', 'ISO-8859-1', 'UTF-8')
374
+ UnixUtils.md5sum(outfile).must_equal UnixUtils.md5sum('iso-8859-1.txt')
375
+ safe_delete outfile
376
+ end
377
+ it 'converts files from latin1 to utf-8' do
378
+ outfile = UnixUtils.iconv('iso-8859-1.txt', 'UTF-8', 'ISO-8859-1')
379
+ UnixUtils.md5sum(outfile).must_equal UnixUtils.md5sum('utf8.txt')
380
+ safe_delete outfile
381
+ end
382
+ end
383
+ end
@@ -0,0 +1,18 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/unix_utils/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Seamus Abshere"]
6
+ gem.email = ["seamus@abshere.net"]
7
+ desc = %q{Like FileUtils, but provides zip, unzip, bzip2, bunzip2, tar, untar, sed, du, md5sum, shasum, cut, head, tail, wc, unix2dos, dos2unix, iconv, curl, perl, etc.}
8
+ gem.description = desc
9
+ gem.summary = desc
10
+ gem.homepage = "https://github.com/seamusabshere/unix_utils"
11
+
12
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
13
+ gem.files = `git ls-files`.split("\n")
14
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ gem.name = "unix_utils"
16
+ gem.require_paths = ["lib"]
17
+ gem.version = UnixUtils::VERSION
18
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: unix_utils
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Seamus Abshere
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-17 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Like FileUtils, but provides zip, unzip, bzip2, bunzip2, tar, untar,
15
+ sed, du, md5sum, shasum, cut, head, tail, wc, unix2dos, dos2unix, iconv, curl, perl,
16
+ etc.
17
+ email:
18
+ - seamus@abshere.net
19
+ executables: []
20
+ extensions: []
21
+ extra_rdoc_files: []
22
+ files:
23
+ - .gitignore
24
+ - Gemfile
25
+ - History.txt
26
+ - README.markdown
27
+ - Rakefile
28
+ - lib/unix_utils.rb
29
+ - lib/unix_utils/version.rb
30
+ - test/helper.rb
31
+ - test/target/directory-really-a-t_a_r-shh
32
+ - test/target/directory-really-a-z_i_p-shh
33
+ - test/target/directory.tar
34
+ - test/target/directory.zip
35
+ - test/target/directory/hello_world.txt
36
+ - test/target/directory/hello_world.xml
37
+ - test/target/file-really-a-b_z_2-shh
38
+ - test/target/file-really-a-g_z-shh
39
+ - test/target/file.bz2
40
+ - test/target/file.gz
41
+ - test/target/iso-8859-1.txt
42
+ - test/target/utf8.txt
43
+ - test/test_unix_utils.rb
44
+ - unix_utils.gemspec
45
+ homepage: https://github.com/seamusabshere/unix_utils
46
+ licenses: []
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ requirements: []
64
+ rubyforge_project:
65
+ rubygems_version: 1.8.15
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: Like FileUtils, but provides zip, unzip, bzip2, bunzip2, tar, untar, sed,
69
+ du, md5sum, shasum, cut, head, tail, wc, unix2dos, dos2unix, iconv, curl, perl,
70
+ etc.
71
+ test_files:
72
+ - test/helper.rb
73
+ - test/target/directory-really-a-t_a_r-shh
74
+ - test/target/directory-really-a-z_i_p-shh
75
+ - test/target/directory.tar
76
+ - test/target/directory.zip
77
+ - test/target/directory/hello_world.txt
78
+ - test/target/directory/hello_world.xml
79
+ - test/target/file-really-a-b_z_2-shh
80
+ - test/target/file-really-a-g_z-shh
81
+ - test/target/file.bz2
82
+ - test/target/file.gz
83
+ - test/target/iso-8859-1.txt
84
+ - test/target/utf8.txt
85
+ - test/test_unix_utils.rb
86
+ has_rdoc: