unix_utils 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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: