fogbugz 1.0.3 → 1.0.4
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/bin/fogbugz +24 -76
- data/bin/fogbugz-areas +3 -49
- data/bin/fogbugz-assign +3 -54
- data/bin/fogbugz-categories +4 -50
- data/bin/fogbugz-close +1 -1
- data/bin/fogbugz-edit +46 -285
- data/bin/fogbugz-filter +2 -1
- data/bin/fogbugz-filters +6 -60
- data/bin/fogbugz-list +39 -42
- data/bin/fogbugz-login +3 -34
- data/bin/fogbugz-logoff +3 -47
- data/bin/fogbugz-milestones +6 -52
- data/bin/fogbugz-open +39 -0
- data/bin/fogbugz-people +5 -51
- data/bin/fogbugz-priorities +4 -51
- data/bin/fogbugz-projects +5 -51
- data/bin/fogbugz-reactivate +2 -1
- data/bin/fogbugz-reopen +2 -1
- data/bin/fogbugz-resolve +5 -72
- data/bin/fogbugz-show +22 -138
- data/bin/fogbugz-start +3 -52
- data/bin/fogbugz-statuses +5 -38
- data/bin/fogbugz-stop +3 -47
- data/lib/fogbugz/common.rb +370 -0
- metadata +19 -7
- data/bin/fogbugz-new +0 -175
- data/lib/dummy.rb +0 -1
data/bin/fogbugz-statuses
CHANGED
|
@@ -1,22 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
require 'rubygems'
|
|
4
|
-
require 'net/https'
|
|
5
|
-
require 'uri'
|
|
6
|
-
require 'rexml/document'
|
|
7
|
-
require 'optparse'
|
|
8
|
-
|
|
9
|
-
api_url = ENV['FOGBUGZ_API_URL']
|
|
10
|
-
unless api_url
|
|
11
|
-
puts "Environment variable FOGBUGZ_API_URL must be set."
|
|
12
|
-
exit 1
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
api_token = ENV['FOGBUGZ_API_TOKEN']
|
|
16
|
-
unless api_token
|
|
17
|
-
puts "Environment variable FOGBUGZ_API_TOKEN must be set."
|
|
18
|
-
exit 1
|
|
19
|
-
end
|
|
2
|
+
require 'fogbugz/common'
|
|
20
3
|
|
|
21
4
|
options = {}
|
|
22
5
|
optparse = OptionParser.new do |opts|
|
|
@@ -28,33 +11,17 @@ optparse = OptionParser.new do |opts|
|
|
|
28
11
|
end
|
|
29
12
|
|
|
30
13
|
options[:resolved] = false
|
|
31
|
-
opts.on('
|
|
14
|
+
opts.on('--resolved', 'Only show resolved statuses.') do
|
|
32
15
|
options[:resolved] = true
|
|
33
16
|
end
|
|
34
17
|
end
|
|
35
18
|
optparse.parse!
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
URI.escape(api_token),
|
|
39
|
-
options[:resolved] ? '&fResolved=1' : '')
|
|
40
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
|
41
|
-
if uri.scheme == 'https'
|
|
42
|
-
http.use_ssl = true
|
|
43
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
44
|
-
end
|
|
45
|
-
response = http.start { |h| h.request Net::HTTP::Get.new(uri.request_uri) }
|
|
46
|
-
if response.code != '200'
|
|
47
|
-
puts "HTTP request to #{api_url} failed with code #{response.code}."
|
|
48
|
-
exit 1
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
result = REXML::Document.new(response.body)
|
|
52
|
-
error = result.elements['/response/error']
|
|
53
|
-
if error
|
|
54
|
-
puts "Failed with error: #{error.text}."
|
|
19
|
+
unless ARGV.length == 0
|
|
20
|
+
puts optparse.help
|
|
55
21
|
exit 1
|
|
56
22
|
end
|
|
57
23
|
|
|
24
|
+
result = do_api 'listStatuses', options[:resolved] ? { :fResolved => '1' } : {}
|
|
58
25
|
result.elements.to_a('/response/statuses/status').map { |s|
|
|
59
26
|
s.elements['sStatus'].text
|
|
60
27
|
}.uniq!.sort!.each { |s| puts s }
|
data/bin/fogbugz-stop
CHANGED
|
@@ -1,49 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
require 'fogbugz/common'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
require 'uri'
|
|
6
|
-
require 'rexml/document'
|
|
7
|
-
require 'optparse'
|
|
8
|
-
|
|
9
|
-
api_url = ENV['FOGBUGZ_API_URL']
|
|
10
|
-
unless api_url
|
|
11
|
-
puts "Environment variable FOGBUGZ_API_URL must be set."
|
|
12
|
-
exit 1
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
api_token = ENV['FOGBUGZ_API_TOKEN']
|
|
16
|
-
unless api_token
|
|
17
|
-
puts "Environment variable FOGBUGZ_API_TOKEN must be set."
|
|
18
|
-
exit 1
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
options = {}
|
|
22
|
-
optparse = OptionParser.new do |opts|
|
|
23
|
-
opts.banner = "usage: #{File::basename(__FILE__)} [options]"
|
|
24
|
-
|
|
25
|
-
opts.on_tail('-h', '--help') do
|
|
26
|
-
puts optparse.help
|
|
27
|
-
exit 1
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
optparse.parse!
|
|
31
|
-
|
|
32
|
-
uri = URI format("#{api_url}?cmd=stopWork&token=%s", URI.escape(api_token))
|
|
33
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
|
34
|
-
if uri.scheme == 'https'
|
|
35
|
-
http.use_ssl = true
|
|
36
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
37
|
-
end
|
|
38
|
-
response = http.start { |h| h.request Net::HTTP::Get.new(uri.request_uri) }
|
|
39
|
-
if response.code != '200'
|
|
40
|
-
puts "HTTP request to #{api_url} failed with code #{response.code}."
|
|
41
|
-
exit 1
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
result = REXML::Document.new(response.body)
|
|
45
|
-
error = result.elements['/response/error']
|
|
46
|
-
if error
|
|
47
|
-
puts "Failed with error: #{error.text}."
|
|
48
|
-
exit 1
|
|
49
|
-
end
|
|
4
|
+
parse_opts "usage: #{File::basename(__FILE__)} [options]", 0
|
|
5
|
+
do_api 'stopWork'
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
require 'net/https'
|
|
2
|
+
require 'uri'
|
|
3
|
+
require 'rexml/document'
|
|
4
|
+
require 'optparse'
|
|
5
|
+
require 'highline'
|
|
6
|
+
require 'tempfile'
|
|
7
|
+
require 'yaml'
|
|
8
|
+
require 'English'
|
|
9
|
+
require 'time'
|
|
10
|
+
require 'chronic'
|
|
11
|
+
|
|
12
|
+
HighLine.use_color = STDOUT.isatty
|
|
13
|
+
begin
|
|
14
|
+
require 'win32console' if RUBY_PLATFORM =~ /mingw/
|
|
15
|
+
rescue LoadError
|
|
16
|
+
HighLine.use_color = false
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def r; HighLine.use_color? ? HighLine::RED : ''; end
|
|
20
|
+
def b; HighLine.use_color? ? HighLine::BLUE : ''; end
|
|
21
|
+
def g; HighLine.use_color? ? HighLine::GREEN : ''; end
|
|
22
|
+
def y; HighLine.use_color? ? HighLine::YELLOW : ''; end
|
|
23
|
+
def m; HighLine.use_color? ? HighLine::MAGENTA : ''; end
|
|
24
|
+
def c; HighLine.use_color? ? HighLine::CLEAR : ''; end
|
|
25
|
+
|
|
26
|
+
unless ENV['FOGBUGZ_API_URL']
|
|
27
|
+
puts "Environment variable FOGBUGZ_API_URL must be set."
|
|
28
|
+
exit 1
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
unless ENV['FOGBUGZ_API_TOKEN']
|
|
32
|
+
puts "Environment variable FOGBUGZ_API_TOKEN must be set."
|
|
33
|
+
exit 1
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def parse_opts(usage, num_args)
|
|
37
|
+
options = {}
|
|
38
|
+
optparse = OptionParser.new do |opts|
|
|
39
|
+
opts.banner = usage
|
|
40
|
+
|
|
41
|
+
opts.on_tail('-h', '--help') do
|
|
42
|
+
puts optparse.help
|
|
43
|
+
exit 1
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
optparse.parse!
|
|
47
|
+
|
|
48
|
+
unless ARGV.length == num_args
|
|
49
|
+
puts optparse.help
|
|
50
|
+
exit 1
|
|
51
|
+
end
|
|
52
|
+
options
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def parse_stdin_opts(usage, num_args)
|
|
56
|
+
options = {}
|
|
57
|
+
optparse = OptionParser.new do |opts|
|
|
58
|
+
opts.banner = usage
|
|
59
|
+
|
|
60
|
+
opts.on_tail('-h', '--help') do
|
|
61
|
+
puts optparse.help
|
|
62
|
+
exit 1
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
options[:file] = nil
|
|
66
|
+
opts.on('--file=<file>',
|
|
67
|
+
'Take the case content from the given file. Use - to read from STDIN.') do |file|
|
|
68
|
+
options[:file] = file
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
options[:template] = nil
|
|
72
|
+
opts.on('--template=<template>',
|
|
73
|
+
'Use the file content or - for STDIN as the initial case content.') do |template|
|
|
74
|
+
options[:template] = template
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
optparse.parse!
|
|
78
|
+
|
|
79
|
+
unless ARGV.length == num_args or
|
|
80
|
+
(ARGV.length == num_args + 1 and ARGV.last == '-')
|
|
81
|
+
puts optparse.help
|
|
82
|
+
exit 1
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
if ARGV.length == num_args + 1
|
|
86
|
+
ARGV.pop
|
|
87
|
+
options[:file] = '-'
|
|
88
|
+
end
|
|
89
|
+
options
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def get_editor_content(options, template)
|
|
93
|
+
editor = ENV['EDITOR'] || 'vim'
|
|
94
|
+
invoke_editor = true
|
|
95
|
+
old_argv = ARGV.clone
|
|
96
|
+
if options[:file]
|
|
97
|
+
if options[:file] == '-'
|
|
98
|
+
ARGV.replace []
|
|
99
|
+
else
|
|
100
|
+
ARGV.replace [options[:file]]
|
|
101
|
+
end
|
|
102
|
+
template = ARGF.read
|
|
103
|
+
invoke_editor = false
|
|
104
|
+
elsif options[:template]
|
|
105
|
+
if options[:template] == '-'
|
|
106
|
+
ARGV.replace []
|
|
107
|
+
else
|
|
108
|
+
ARGV.replace [options[:template]]
|
|
109
|
+
end
|
|
110
|
+
template = ARGF.read
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
content = template
|
|
114
|
+
if invoke_editor
|
|
115
|
+
tempfile = Tempfile.new ['case', '.md']
|
|
116
|
+
tempfile.write template
|
|
117
|
+
tempfile.close
|
|
118
|
+
rc = system "#{editor} #{tempfile.path}"
|
|
119
|
+
unless rc
|
|
120
|
+
puts "Editor exited with non-zero status. Aborting."
|
|
121
|
+
exit 1
|
|
122
|
+
end
|
|
123
|
+
tempfile.open
|
|
124
|
+
content = tempfile.read
|
|
125
|
+
tempfile.close
|
|
126
|
+
tempfile.delete
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
data = {}
|
|
130
|
+
if content =~ /(.*?\n?)^(---\s*$\n?)/m
|
|
131
|
+
# Combined YAML front matter with text content.
|
|
132
|
+
begin
|
|
133
|
+
data = YAML.load($1) || {}
|
|
134
|
+
data['body'] = $POSTMATCH if $POSTMATCH and not $POSTMATCH.empty?
|
|
135
|
+
rescue => e
|
|
136
|
+
puts "Exception reading YAML front matter. #{e.inspect}"
|
|
137
|
+
exit 1
|
|
138
|
+
end
|
|
139
|
+
else
|
|
140
|
+
begin
|
|
141
|
+
# YAML only content.
|
|
142
|
+
data = YAML.load(content)
|
|
143
|
+
if data.instance_of? String
|
|
144
|
+
# Text only content.
|
|
145
|
+
data = { 'body' => content }
|
|
146
|
+
end
|
|
147
|
+
rescue => e
|
|
148
|
+
data = {}
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
if not data or data.empty?
|
|
153
|
+
puts "No new content for case. Aborting."
|
|
154
|
+
exit 1
|
|
155
|
+
end
|
|
156
|
+
ARGV.replace old_argv
|
|
157
|
+
data
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def maybe_show(key, xml)
|
|
161
|
+
if xml and xml.text and not xml.text.empty?
|
|
162
|
+
format "#{b}%-11.11s#{c}#{xml.text}\n", "#{key}:"
|
|
163
|
+
else
|
|
164
|
+
''
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def maybe_show_array(key, xml)
|
|
169
|
+
if xml and not xml.empty?
|
|
170
|
+
format "#{b}%-11.11s#{c}#{xml.join(', ')}\n", "#{key}:"
|
|
171
|
+
else
|
|
172
|
+
''
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def maybe_show_literal(color, xml)
|
|
177
|
+
if xml and xml.text and not xml.text.empty?
|
|
178
|
+
"#{color}#{xml.text}#{c}\n"
|
|
179
|
+
else
|
|
180
|
+
''
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def maybe_show_time(key, xml)
|
|
185
|
+
if xml and xml.text and not xml.text.empty?
|
|
186
|
+
format "#{b}%-11.11s#{c}#{time_string(xml.text)}\n", "#{key}:"
|
|
187
|
+
else
|
|
188
|
+
''
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def maybe_show_event(color, xml, time_xml)
|
|
193
|
+
if xml and xml.text and not xml.text.empty?
|
|
194
|
+
if time_xml and time_xml.text and not time_xml.text.empty?
|
|
195
|
+
format("#{color}%s at %s.#{c}\n", xml.text, time_string(time_xml.text))
|
|
196
|
+
else
|
|
197
|
+
"#{color}#{xml.text}#{c}\n"
|
|
198
|
+
end
|
|
199
|
+
else
|
|
200
|
+
''
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def maybe_append(key, xml)
|
|
205
|
+
if xml and xml.text and not xml.text.empty?
|
|
206
|
+
"# #{key}: #{xml.text}\n"
|
|
207
|
+
else
|
|
208
|
+
"# #{key}: <#{key}>\n"
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def maybe_array(key, xml)
|
|
213
|
+
if xml and not xml.empty?
|
|
214
|
+
"# #{key}: [#{xml.join(', ')}]\n"
|
|
215
|
+
else
|
|
216
|
+
"# #{key}: [<#{key}>]\n"
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def time_short_string(text)
|
|
221
|
+
if text
|
|
222
|
+
Time.parse(text).localtime.strftime('%D')
|
|
223
|
+
else
|
|
224
|
+
''
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def time_string(text)
|
|
229
|
+
if text
|
|
230
|
+
time = Time.parse(text).localtime
|
|
231
|
+
format("%s on %s", time.strftime('%-l:%M %p'),
|
|
232
|
+
time.strftime('%A, %B %e %Y'))
|
|
233
|
+
else
|
|
234
|
+
''
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def parse_time(text)
|
|
239
|
+
return nil unless text
|
|
240
|
+
begin
|
|
241
|
+
time = Time.parse(text)
|
|
242
|
+
# Ruby 1.8.7 returns the current time on bad parses.
|
|
243
|
+
raise ArgumentError if Time.now.to_s == time.to_s
|
|
244
|
+
rescue ArgumentError
|
|
245
|
+
begin
|
|
246
|
+
time = Chronic.parse(text).utc.iso8601
|
|
247
|
+
rescue
|
|
248
|
+
puts "Unable to parse date #{text}."
|
|
249
|
+
exit 1
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
unless time
|
|
253
|
+
puts "Unable to parse date #{text}."
|
|
254
|
+
exit 1
|
|
255
|
+
end
|
|
256
|
+
time
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def maybe_time(key, xml)
|
|
260
|
+
if xml and xml.text and not xml.text.empty?
|
|
261
|
+
"# #{key}: #{time_string(xml.text)}\n"
|
|
262
|
+
else
|
|
263
|
+
"# #{key}: <#{key}>\n"
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def maybe_event(xml, time_xml)
|
|
268
|
+
if xml and xml.text and not xml.text.empty?
|
|
269
|
+
if time_xml and time_xml.text and not time_xml.text.empty?
|
|
270
|
+
format("# %s at %s.\n", xml.text, time_string(time_xml.text))
|
|
271
|
+
else
|
|
272
|
+
commented = xml.text.gsub(/\n/, "\n# ")
|
|
273
|
+
"# #{commented}"
|
|
274
|
+
end
|
|
275
|
+
else
|
|
276
|
+
''
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def maybe_literal(xml)
|
|
281
|
+
if xml and xml.text and not xml.text.empty?
|
|
282
|
+
commented = xml.text.gsub(/\n/, "\n# ")
|
|
283
|
+
"# #{commented}\n"
|
|
284
|
+
else
|
|
285
|
+
''
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def do_api(cmd, params={})
|
|
290
|
+
api_url = ENV['FOGBUGZ_API_URL']
|
|
291
|
+
api_token = ENV['FOGBUGZ_API_TOKEN']
|
|
292
|
+
|
|
293
|
+
query = ''
|
|
294
|
+
params.each_pair do |k,v|
|
|
295
|
+
query << format("&%s=%s", URI.escape(k.to_s), URI.escape(v.to_s)) if v
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
uri = URI "#{api_url}?cmd=#{cmd}&token=#{api_token}#{query}"
|
|
299
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
300
|
+
if uri.scheme == 'https'
|
|
301
|
+
http.use_ssl = true
|
|
302
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
303
|
+
end
|
|
304
|
+
response = http.start do |h|
|
|
305
|
+
h.request Net::HTTP::Get.new(uri.request_uri)
|
|
306
|
+
end
|
|
307
|
+
if response.code != '200'
|
|
308
|
+
puts "HTTP request to #{api_url} failed with code #{response.code}."
|
|
309
|
+
exit 1
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
result = REXML::Document.new(response.body)
|
|
313
|
+
error = result.elements['/response/error']
|
|
314
|
+
if error
|
|
315
|
+
puts "Failed with error: #{error.text}."
|
|
316
|
+
exit 1
|
|
317
|
+
end
|
|
318
|
+
result
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def which(cmd)
|
|
322
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
|
323
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
|
324
|
+
exts.each { |ext|
|
|
325
|
+
exe = "#{path}/#{cmd}#{ext}"
|
|
326
|
+
return exe if File.executable? exe
|
|
327
|
+
}
|
|
328
|
+
end
|
|
329
|
+
return nil
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def dispatch_subcommand(file, commands = {})
|
|
333
|
+
basename = File.basename(file)
|
|
334
|
+
absolute = File.expand_path(file)
|
|
335
|
+
|
|
336
|
+
usage = <<HERE
|
|
337
|
+
usage: #{basename} <subcommands> [options]
|
|
338
|
+
|
|
339
|
+
The subcommands are:
|
|
340
|
+
HERE
|
|
341
|
+
commands.keys.sort { |a,b| a.to_s <=> b.to_s }.each do |k|
|
|
342
|
+
usage << format(" %-16.16s%s\n", k, commands[k])
|
|
343
|
+
end
|
|
344
|
+
usage << <<HERE
|
|
345
|
+
|
|
346
|
+
See '#{basename} help <commands>' for more information on a specific command.
|
|
347
|
+
HERE
|
|
348
|
+
|
|
349
|
+
if ARGV[0] == 'help'
|
|
350
|
+
if ARGV[1] and commands[ARGV[1].to_sym]
|
|
351
|
+
subcommand = ARGV[1]
|
|
352
|
+
ARGV.replace ['--help']
|
|
353
|
+
load "#{absolute}-#{subcommand}"
|
|
354
|
+
elsif ARGV[1] and which("#{basename}-#{ARGV[1]}")
|
|
355
|
+
command = which("#{basename}-#{ARGV[1]}")
|
|
356
|
+
system "#{command} --help"
|
|
357
|
+
else
|
|
358
|
+
puts usage
|
|
359
|
+
exit 1
|
|
360
|
+
end
|
|
361
|
+
elsif ARGV[0] and commands[ARGV[0].to_sym]
|
|
362
|
+
load "#{absolute}-#{ARGV.shift}"
|
|
363
|
+
elsif ARGV[0] and which("#{basename}-#{ARGV[0]}")
|
|
364
|
+
command = which("#{basename}-#{ARGV.shift}")
|
|
365
|
+
Process.wait(Process.fork { Process.exec(command, *ARGV) })
|
|
366
|
+
else
|
|
367
|
+
puts usage
|
|
368
|
+
exit 1
|
|
369
|
+
end
|
|
370
|
+
end
|