minitar-cli 0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Contributing.md +71 -0
- data/History.md +25 -0
- data/Licence.md +15 -0
- data/Manifest.txt +22 -0
- data/README.rdoc +105 -0
- data/Rakefile +47 -0
- data/bin/minitar +11 -0
- data/docs/bsdl.txt +19 -0
- data/docs/ruby.txt +56 -0
- data/lib/minitar/cli.rb +64 -0
- data/lib/minitar/cli/command.rb +46 -0
- data/lib/minitar/cli/command/create.rb +144 -0
- data/lib/minitar/cli/command/extract.rb +174 -0
- data/lib/minitar/cli/command/help.rb +57 -0
- data/lib/minitar/cli/command/list.rb +162 -0
- data/lib/minitar/cli/commander.rb +64 -0
- data/test/fixtures/bad-dir.tar.gz +0 -0
- data/test/fixtures/spaces.tar.gz +0 -0
- data/test/minitest_helper.rb +11 -0
- data/test/support/minitar_cli_test_helper.rb +15 -0
- data/test/test_cli_help.rb +71 -0
- data/test/test_cli_list.rb +123 -0
- metadata +265 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The base for commands in Minitar::CLI. This will be replaced in a future
|
4
|
+
# version by one of the better-executed CLI application frameworks like GLI,
|
5
|
+
# after Ruby 1.8 and 1.9 support have been dropped.
|
6
|
+
class Minitar::CLI::Command
|
7
|
+
@children = []
|
8
|
+
|
9
|
+
attr_reader :commander
|
10
|
+
attr_reader :ioe
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_reader :children
|
14
|
+
|
15
|
+
def inherited(subclass)
|
16
|
+
children << subclass
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module CatchMinitarErrors # :nodoc:
|
21
|
+
def call(args, opts)
|
22
|
+
run(args, opts)
|
23
|
+
rescue Archive::Tar::Minitar::Error => error
|
24
|
+
ioe[:error] << "#{error}\n"
|
25
|
+
5
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(commander)
|
30
|
+
@commander = commander
|
31
|
+
@ioe = commander.ioe
|
32
|
+
end
|
33
|
+
|
34
|
+
def name
|
35
|
+
raise Minitar::CLI::AbstractCommandError
|
36
|
+
end
|
37
|
+
|
38
|
+
def call(_args, _opts = {})
|
39
|
+
raise Minitar::CLI::AbstractCommandError
|
40
|
+
end
|
41
|
+
alias [] call
|
42
|
+
|
43
|
+
def help
|
44
|
+
raise Minitar::CLI::AbstractCommandError
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Tarball creation command. This will be replaced in a future version by one of
|
4
|
+
# the better-executed CLI application frameworks like GLI, after Ruby 1.8 and
|
5
|
+
# 1.9 support have been dropped.
|
6
|
+
class Minitar::CLI::Command::Create < Minitar::CLI::Command
|
7
|
+
def name
|
8
|
+
'create'
|
9
|
+
end
|
10
|
+
|
11
|
+
def altname
|
12
|
+
'cr'
|
13
|
+
end
|
14
|
+
|
15
|
+
HELP = <<-EOH.freeze
|
16
|
+
minitar create [OPTIONS] <tarfile|-> <file|directory|-->+
|
17
|
+
|
18
|
+
Creates a new tarfile. If the tarfile is named .tar.gz or .tgz, then it
|
19
|
+
will be compressed automatically. If the tarfile is "-", then it will be
|
20
|
+
output to standard output (stdout) so that minitar may be piped.
|
21
|
+
|
22
|
+
The files or directories that will be packed into the tarfile are
|
23
|
+
specified after the name of the tarfile itself. Directories will be
|
24
|
+
processed recursively. If the token "--" is found in the list of files
|
25
|
+
to be packed, additional filenames will be read from standard input
|
26
|
+
(stdin). If any file is not found, the packaging will be halted.
|
27
|
+
|
28
|
+
create Options:
|
29
|
+
--compress, -z Compresses the tarfile with gzip.
|
30
|
+
|
31
|
+
EOH
|
32
|
+
|
33
|
+
include CatchMinitarErrors
|
34
|
+
|
35
|
+
def run(args, opts = {})
|
36
|
+
argv = []
|
37
|
+
|
38
|
+
while (arg = args.shift)
|
39
|
+
case arg
|
40
|
+
when '--compress', '-z'
|
41
|
+
opts[:compress] = true
|
42
|
+
else
|
43
|
+
argv << arg
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
if argv.size < 2
|
48
|
+
ioe[:output] << "Not enough arguments.\n\n"
|
49
|
+
commander.command('help').call(%w(create))
|
50
|
+
return 255
|
51
|
+
end
|
52
|
+
|
53
|
+
output = argv.shift
|
54
|
+
if '-' == output
|
55
|
+
opts[:name] = 'STDOUT'
|
56
|
+
output = ioe[:output]
|
57
|
+
opts[:output] = ioe[:error]
|
58
|
+
else
|
59
|
+
opts[:name] = output
|
60
|
+
output = File.open(output, 'wb')
|
61
|
+
opts[:output] = ioe[:output]
|
62
|
+
end
|
63
|
+
|
64
|
+
if opts[:name] =~ /\.tar\.gz$|\.tgz$/ or opts[:compress]
|
65
|
+
output = Zlib::GzipWriter.new(output)
|
66
|
+
end
|
67
|
+
|
68
|
+
files = []
|
69
|
+
if argv.include?('--')
|
70
|
+
# Read stdin for the list of files.
|
71
|
+
files = ''
|
72
|
+
files << ioe[:input].read until ioe[:input].eof?
|
73
|
+
files = files.split(/\r\n|\n|\r/)
|
74
|
+
args.delete('--')
|
75
|
+
end
|
76
|
+
|
77
|
+
files << argv.to_a
|
78
|
+
files.flatten!
|
79
|
+
|
80
|
+
watcher, finisher =
|
81
|
+
if opts[:verbose]
|
82
|
+
verbose
|
83
|
+
elsif opts[:progress]
|
84
|
+
progress
|
85
|
+
else
|
86
|
+
silent
|
87
|
+
end
|
88
|
+
|
89
|
+
Archive::Tar::Minitar.pack(files, output, &watcher)
|
90
|
+
finisher.call
|
91
|
+
0
|
92
|
+
ensure
|
93
|
+
output.close if output && !output.closed?
|
94
|
+
end
|
95
|
+
|
96
|
+
def help
|
97
|
+
HELP
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def verbose
|
103
|
+
[
|
104
|
+
lambda { |action, name, _stats|
|
105
|
+
opts[:output] << "#{name}\n" if action == :dir || action == :file_done
|
106
|
+
},
|
107
|
+
lambda { opts[:output] << "\n" }
|
108
|
+
]
|
109
|
+
end
|
110
|
+
|
111
|
+
def progress
|
112
|
+
require 'powerbar'
|
113
|
+
progress = PowerBar.new(:msg => opts[:name], :total => 1)
|
114
|
+
[
|
115
|
+
lambda { |action, name, stats|
|
116
|
+
progress_info = {}
|
117
|
+
|
118
|
+
case action
|
119
|
+
when :file_start, :dir
|
120
|
+
progress_info[:msg] = File.basename(name)
|
121
|
+
|
122
|
+
if action == :dir
|
123
|
+
progress_info[:total] = progress.total + 1
|
124
|
+
progress_info[:done] = progress.done + 1
|
125
|
+
else
|
126
|
+
progress_info[:total] = progress.total + stats[:size]
|
127
|
+
end
|
128
|
+
when :file_progress
|
129
|
+
progress_info[:done] = progress.done + stats[:currinc]
|
130
|
+
end
|
131
|
+
|
132
|
+
progress.show(progress_info)
|
133
|
+
},
|
134
|
+
lambda {
|
135
|
+
progress.show(:msg => opts[:name])
|
136
|
+
progress.close(true)
|
137
|
+
}
|
138
|
+
]
|
139
|
+
end
|
140
|
+
|
141
|
+
def silent
|
142
|
+
[ lambda { |_, _, _| }, lambda {} ]
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Tarball extraction command. This will be replaced in a future version by one
|
4
|
+
# of the better-executed CLI application frameworks like GLI, after Ruby 1.8
|
5
|
+
# and 1.9 support have been dropped.
|
6
|
+
class Minitar::CLI::Command::Extract < Minitar::CLI::Command
|
7
|
+
def name
|
8
|
+
'extract'
|
9
|
+
end
|
10
|
+
|
11
|
+
def altname
|
12
|
+
'ex'
|
13
|
+
end
|
14
|
+
|
15
|
+
HELP = <<-EOH.freeze
|
16
|
+
minitar extract [OPTIONS] <tarfile|-> [<file>+]
|
17
|
+
|
18
|
+
Extracts files from an existing tarfile. If the tarfile is named .tar.gz
|
19
|
+
or .tgz, then it will be uncompressed automatically. If the tarfile is
|
20
|
+
"-", then it will be read from standard input (stdin) so that minitar
|
21
|
+
may be piped.
|
22
|
+
|
23
|
+
The files or directories that will be extracted from the tarfile are
|
24
|
+
specified after the name of the tarfile itself. Directories will be
|
25
|
+
processed recursively. Files must be specified in full. A file
|
26
|
+
"foo/bar/baz.txt" cannot simply be specified by specifying "baz.txt".
|
27
|
+
Any file not found will simply be skipped and an error will be reported.
|
28
|
+
|
29
|
+
extract Options:
|
30
|
+
--uncompress, -z Uncompresses the tarfile with gzip.
|
31
|
+
--pipe Emits the extracted files to STDOUT for piping.
|
32
|
+
--output, -o Extracts the files to the specified directory.
|
33
|
+
|
34
|
+
EOH
|
35
|
+
|
36
|
+
include CatchMinitarErrors
|
37
|
+
|
38
|
+
def run(args, opts = {})
|
39
|
+
argv = []
|
40
|
+
output = nil
|
41
|
+
dest = '.'
|
42
|
+
files = []
|
43
|
+
|
44
|
+
while (arg = args.shift)
|
45
|
+
case arg
|
46
|
+
when '--uncompress', '-z'
|
47
|
+
opts[:uncompress] = true
|
48
|
+
when '--pipe'
|
49
|
+
output = ioe[:output]
|
50
|
+
ioe[:output] = ioe[:error]
|
51
|
+
when '--output', '-o'
|
52
|
+
dest = args.shift
|
53
|
+
else
|
54
|
+
argv << arg
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
if argv.empty?
|
59
|
+
ioe[:output] << "Not enough arguments.\n\n"
|
60
|
+
commander.command('help').call(%w(extract))
|
61
|
+
return 255
|
62
|
+
end
|
63
|
+
|
64
|
+
input = argv.shift
|
65
|
+
if '-' == input
|
66
|
+
opts[:name] = 'STDIN'
|
67
|
+
input = ioe[:input]
|
68
|
+
else
|
69
|
+
opts[:name] = input
|
70
|
+
input = File.open(input, 'rb')
|
71
|
+
end
|
72
|
+
|
73
|
+
if opts[:name] =~ /\.tar\.gz$|\.tgz$/ or opts[:uncompress]
|
74
|
+
input = Zlib::GzipReader.new(input)
|
75
|
+
end
|
76
|
+
|
77
|
+
files << argv.to_a
|
78
|
+
files.flatten!
|
79
|
+
|
80
|
+
watcher, finisher =
|
81
|
+
if opts[:verbose]
|
82
|
+
verbose
|
83
|
+
elsif opts[:progress]
|
84
|
+
progress
|
85
|
+
else
|
86
|
+
silent
|
87
|
+
end
|
88
|
+
|
89
|
+
if output.nil?
|
90
|
+
Archive::Tar::Minitar.unpack(input, dest, files, &watcher)
|
91
|
+
finisher.call
|
92
|
+
else
|
93
|
+
Archive::Tar::Minitar::Input.each_entry(input) do |entry|
|
94
|
+
next unless files.empty? || files.include?(entry.full_name)
|
95
|
+
|
96
|
+
stats = {
|
97
|
+
:mode => entry.mode,
|
98
|
+
:mtime => entry.mtime,
|
99
|
+
:size => entry.size,
|
100
|
+
:gid => entry.gid,
|
101
|
+
:uid => entry.uid,
|
102
|
+
:current => 0,
|
103
|
+
:currinc => 0,
|
104
|
+
:entry => entry
|
105
|
+
}
|
106
|
+
|
107
|
+
if entry.directory?
|
108
|
+
watcher.call(:dir, dest, stats)
|
109
|
+
else
|
110
|
+
watcher.call(:file_start, destfile, stats)
|
111
|
+
loop do
|
112
|
+
data = entry.read(4096)
|
113
|
+
break unless data
|
114
|
+
stats[:currinc] = output.write(data)
|
115
|
+
stats[:current] += stats[:currinc]
|
116
|
+
|
117
|
+
watcher.call(:file_progress, name, stats)
|
118
|
+
end
|
119
|
+
watcher.call(:file_done, name, stats)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
0
|
125
|
+
end
|
126
|
+
|
127
|
+
def help
|
128
|
+
HELP
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
def verbose
|
134
|
+
[
|
135
|
+
lambda { |action, name, _stats|
|
136
|
+
ioe[:output] << "#{name}\n" if action == :dir or action == :file_done
|
137
|
+
},
|
138
|
+
lambda { ioe[:output] << "\n" }
|
139
|
+
]
|
140
|
+
end
|
141
|
+
|
142
|
+
def progress
|
143
|
+
require 'powerbar'
|
144
|
+
progress = PowerBar.new(:msg => opts[:name], :total => 1)
|
145
|
+
[
|
146
|
+
lambda { |action, name, stats|
|
147
|
+
progress_info = {}
|
148
|
+
|
149
|
+
case action
|
150
|
+
when :file_start, :dir
|
151
|
+
progress_info[:msg] = File.basename(name)
|
152
|
+
if action == :dir
|
153
|
+
progress_info[:total] = progress.total + 1
|
154
|
+
progress_info[:done] = progress.done + 1
|
155
|
+
else
|
156
|
+
progress_info[:total] = progress.total + stats[:entry].size
|
157
|
+
end
|
158
|
+
when :file_progress
|
159
|
+
progress_info[:done] = progress.done + stats[:currinc]
|
160
|
+
end
|
161
|
+
|
162
|
+
progress.show(progress_info)
|
163
|
+
},
|
164
|
+
lambda {
|
165
|
+
progress.show(:msg => opts[:name])
|
166
|
+
progress.close(true)
|
167
|
+
}
|
168
|
+
]
|
169
|
+
end
|
170
|
+
|
171
|
+
def silent
|
172
|
+
[ lambda { |_, _, _| }, lambda {} ]
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Help command. This will be replaced in a future version by one of the
|
4
|
+
# better-executed CLI application frameworks like GLI, after Ruby 1.8 and 1.9
|
5
|
+
# support have been dropped.
|
6
|
+
class Minitar::CLI::Command::Help < Minitar::CLI::Command
|
7
|
+
def name
|
8
|
+
'help'
|
9
|
+
end
|
10
|
+
|
11
|
+
COMMANDS = <<-EOS.freeze
|
12
|
+
The commands known to minitar are:
|
13
|
+
|
14
|
+
minitar create Creates a new tarfile.
|
15
|
+
minitar extract Extracts files from a tarfile.
|
16
|
+
minitar list Lists files in the tarfile.
|
17
|
+
|
18
|
+
All commands accept the options --verbose and --progress, which are
|
19
|
+
mutually exclusive. In "minitar list", --progress means the same as
|
20
|
+
--verbose.
|
21
|
+
|
22
|
+
--verbose, -V Performs the requested command verbosely.
|
23
|
+
--progress, -P Shows a progress bar, if appropriate, for the action
|
24
|
+
being performed.
|
25
|
+
|
26
|
+
EOS
|
27
|
+
|
28
|
+
BASIC = <<-EOS.freeze
|
29
|
+
This is a basic help message containing pointers to more information on
|
30
|
+
how to use this command-line tool. Try:
|
31
|
+
|
32
|
+
minitar help commands list all 'minitar' commands
|
33
|
+
minitar help <COMMAND> show help on <COMMAND>
|
34
|
+
(e.g., 'minitar help create')
|
35
|
+
EOS
|
36
|
+
|
37
|
+
def call(args, _opts = {})
|
38
|
+
help_on = args.shift
|
39
|
+
|
40
|
+
if commander.command?(help_on)
|
41
|
+
ioe[:output] << commander[help_on].help
|
42
|
+
elsif help_on == 'commands'
|
43
|
+
ioe[:output] << COMMANDS
|
44
|
+
else
|
45
|
+
unless help_on.nil? or help_on.empty?
|
46
|
+
ioe[:output] << "Unknown command: #{help_on}\n"
|
47
|
+
end
|
48
|
+
ioe[:output] << help
|
49
|
+
end
|
50
|
+
|
51
|
+
0
|
52
|
+
end
|
53
|
+
|
54
|
+
def help
|
55
|
+
BASIC
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Tarball list command. This will be replaced in a future version by one of the
|
4
|
+
# better-executed CLI application frameworks like GLI, after Ruby 1.8 and 1.9
|
5
|
+
# support have been dropped.
|
6
|
+
class Minitar::CLI::Command::List < Minitar::CLI::Command
|
7
|
+
def name
|
8
|
+
'list'
|
9
|
+
end
|
10
|
+
|
11
|
+
def altname
|
12
|
+
'ls'
|
13
|
+
end
|
14
|
+
|
15
|
+
HELP = <<-EOH.freeze
|
16
|
+
minitar list [OPTIONS] <tarfile|-> [<file>+]
|
17
|
+
|
18
|
+
Lists files in an existing tarfile. If the tarfile is named .tar.gz or
|
19
|
+
.tgz, then it will be uncompressed automatically. If the tarfile is "-",
|
20
|
+
then it will be read from standard input (stdin) so that minitar may be
|
21
|
+
piped.
|
22
|
+
|
23
|
+
If --verbose or --progress is specified, then the file list will be
|
24
|
+
similar to that produced by the Unix command "ls -l".
|
25
|
+
|
26
|
+
list Options:
|
27
|
+
--uncompress, -z Uncompresses the tarfile with gzip.
|
28
|
+
--sort [<FIELD>], -S Sorts the list of files by the specified
|
29
|
+
field. The sort defaults to the filename.
|
30
|
+
--reverse, -R Reverses the sort.
|
31
|
+
-l Lists the files in detail.
|
32
|
+
|
33
|
+
Sort Fields:
|
34
|
+
name, mtime, size
|
35
|
+
|
36
|
+
EOH
|
37
|
+
|
38
|
+
def modestr(mode)
|
39
|
+
s = String.new('---')
|
40
|
+
s[0] = 'r' if (mode & 4) == 4
|
41
|
+
s[1] = 'w' if (mode & 2) == 2
|
42
|
+
s[2] = 'x' if (mode & 1) == 1
|
43
|
+
s
|
44
|
+
end
|
45
|
+
|
46
|
+
include CatchMinitarErrors
|
47
|
+
|
48
|
+
def run(args, opts = {})
|
49
|
+
argv = []
|
50
|
+
output = nil
|
51
|
+
files = []
|
52
|
+
opts[:field] = 'name'
|
53
|
+
|
54
|
+
while (arg = args.shift)
|
55
|
+
case arg
|
56
|
+
when '--sort', '-S'
|
57
|
+
opts[:sort] = true
|
58
|
+
opts[:field] = args.shift
|
59
|
+
when '--reverse', '-R'
|
60
|
+
opts[:reverse] = true
|
61
|
+
opts[:sort] = true
|
62
|
+
when '--uncompress', '-z'
|
63
|
+
opts[:uncompress] = true
|
64
|
+
when '-l'
|
65
|
+
opts[:verbose] = true
|
66
|
+
else
|
67
|
+
argv << arg
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
if argv.empty?
|
72
|
+
ioe[:output] << "Not enough arguments.\n\n"
|
73
|
+
commander.command('help').call(%w(list))
|
74
|
+
return 255
|
75
|
+
end
|
76
|
+
|
77
|
+
input = argv.shift
|
78
|
+
if '-' == input
|
79
|
+
opts[:name] = 'STDIN'
|
80
|
+
input = ioe[:input]
|
81
|
+
else
|
82
|
+
opts[:name] = input
|
83
|
+
input = File.open(input, 'rb')
|
84
|
+
end
|
85
|
+
|
86
|
+
if opts[:name] =~ /\.tar\.gz$|\.tgz$/ or opts[:uncompress]
|
87
|
+
input = Zlib::GzipReader.new(input)
|
88
|
+
end
|
89
|
+
|
90
|
+
files << argv.to_a
|
91
|
+
files.flatten!
|
92
|
+
|
93
|
+
if opts[:verbose] or opts[:progress]
|
94
|
+
format = '%10s %4d %8s %8s %8d %12s %s'
|
95
|
+
datefmt = '%b %d %Y'
|
96
|
+
timefmt = '%b %d %H:%M'
|
97
|
+
fields = %w(permissions inodes user group size date fullname)
|
98
|
+
else
|
99
|
+
format = '%s'
|
100
|
+
fields = %w(fullname)
|
101
|
+
end
|
102
|
+
|
103
|
+
opts[:field] = opts[:field].to_sym
|
104
|
+
opts[:field] = :full_name if opts[:field] == :name
|
105
|
+
|
106
|
+
output = []
|
107
|
+
|
108
|
+
today = Time.now
|
109
|
+
oneyear = Time.mktime(today.year - 1, today.month, today.day)
|
110
|
+
|
111
|
+
Archive::Tar::Minitar::Input.each_entry(input) do |entry|
|
112
|
+
next unless files.empty? || files.include?(entry.full_name)
|
113
|
+
|
114
|
+
value = format % fields.map { |ff|
|
115
|
+
case ff
|
116
|
+
when 'permissions'
|
117
|
+
s = String.new(entry.directory? ? 'd' : '-')
|
118
|
+
s << modestr(entry.mode / 0o100)
|
119
|
+
s << modestr(entry.mode / 0o010)
|
120
|
+
s << modestr(entry.mode)
|
121
|
+
when 'inodes'
|
122
|
+
entry.size / 512
|
123
|
+
when 'user'
|
124
|
+
entry.uname || entry.uid || 0
|
125
|
+
when 'group'
|
126
|
+
entry.gname || entry.gid || 0
|
127
|
+
when 'size'
|
128
|
+
entry.size
|
129
|
+
when 'date'
|
130
|
+
if Time.at(entry.mtime) > oneyear
|
131
|
+
Time.at(entry.mtime).strftime(timefmt)
|
132
|
+
else
|
133
|
+
Time.at(entry.mtime).strftime(datefmt)
|
134
|
+
end
|
135
|
+
when 'fullname'
|
136
|
+
entry.full_name
|
137
|
+
end
|
138
|
+
}
|
139
|
+
|
140
|
+
if opts[:sort]
|
141
|
+
output << [ entry.send(opts[:field]), value ]
|
142
|
+
else
|
143
|
+
ioe[:output] << value << "\n"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
if opts[:sort]
|
148
|
+
output = output.sort { |a, b| a[0] <=> b[0] }
|
149
|
+
if opts[:reverse]
|
150
|
+
output.reverse_each { |oo| ioe[:output] << oo[1] << "\n" }
|
151
|
+
else
|
152
|
+
output.each { |oo| ioe[:output] << oo[1] << "\n" }
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
0
|
157
|
+
end
|
158
|
+
|
159
|
+
def help
|
160
|
+
HELP
|
161
|
+
end
|
162
|
+
end
|