minvee 0.0.1
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.
- checksums.yaml +7 -0
- data/README.md +23 -0
- data/lib/minvee/serverbox.rb +2038 -0
- data/lib/minvee.rb +885 -0
- metadata +46 -0
data/lib/minvee.rb
ADDED
@@ -0,0 +1,885 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
require 'json'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
# requires
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
|
9
|
+
#===============================================================================
|
10
|
+
# Minvee
|
11
|
+
# This module is just to initialize the namespace. It doesn't do anything.
|
12
|
+
#
|
13
|
+
module Minvee
|
14
|
+
# Version
|
15
|
+
VERSION = '0.0.1'
|
16
|
+
end
|
17
|
+
#
|
18
|
+
# Minvee
|
19
|
+
#===============================================================================
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
#===============================================================================
|
24
|
+
# Minvee::Client
|
25
|
+
#
|
26
|
+
module Minvee::Client
|
27
|
+
#---------------------------------------------------------------------------
|
28
|
+
# tmp dir
|
29
|
+
#
|
30
|
+
@@tmp_dir = '/tmp'
|
31
|
+
|
32
|
+
def self.tmp_dir
|
33
|
+
return @@tmp_dir
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.tmp_dir=(p_dir)
|
37
|
+
@@tmp_dir = p_dir
|
38
|
+
end
|
39
|
+
#
|
40
|
+
# tmp dir
|
41
|
+
#---------------------------------------------------------------------------
|
42
|
+
|
43
|
+
|
44
|
+
#---------------------------------------------------------------------------
|
45
|
+
# process_command_line
|
46
|
+
#
|
47
|
+
def self.process_command_line(params)
|
48
|
+
# $tm.hrm
|
49
|
+
|
50
|
+
# action
|
51
|
+
command = params.shift
|
52
|
+
|
53
|
+
# must have action
|
54
|
+
if not command
|
55
|
+
puts 'syntax: ' + script_name() + ' command [command options]'
|
56
|
+
exit 1
|
57
|
+
end
|
58
|
+
|
59
|
+
# normalize command
|
60
|
+
command = command.downcase
|
61
|
+
command = command.gsub(/\s+/mu, '')
|
62
|
+
|
63
|
+
# run command
|
64
|
+
if cmd = @@COMMANDS[command]
|
65
|
+
puts cmd
|
66
|
+
else
|
67
|
+
puts 'unknown command: ' + command
|
68
|
+
end
|
69
|
+
end
|
70
|
+
#
|
71
|
+
# process_command_line
|
72
|
+
#---------------------------------------------------------------------------
|
73
|
+
|
74
|
+
|
75
|
+
# commands
|
76
|
+
@@COMMANDS = {}
|
77
|
+
|
78
|
+
#---------------------------------------------------------------------------
|
79
|
+
# prep
|
80
|
+
#
|
81
|
+
@@COMMANDS['prep'] = {}
|
82
|
+
|
83
|
+
@@COMMANDS['prep']['sub'] = Proc.new do
|
84
|
+
puts 'hello world'
|
85
|
+
end
|
86
|
+
#
|
87
|
+
# prep
|
88
|
+
#---------------------------------------------------------------------------
|
89
|
+
|
90
|
+
|
91
|
+
#---------------------------------------------------------------------------
|
92
|
+
# help
|
93
|
+
#
|
94
|
+
def self.help
|
95
|
+
|
96
|
+
|
97
|
+
puts 'syntax: ' + script_name() + ' command [command options]'
|
98
|
+
|
99
|
+
end
|
100
|
+
#
|
101
|
+
# help
|
102
|
+
#---------------------------------------------------------------------------
|
103
|
+
|
104
|
+
|
105
|
+
#---------------------------------------------------------------------------
|
106
|
+
# script_name
|
107
|
+
#
|
108
|
+
def self.script_name
|
109
|
+
return File.basename(__FILE__)
|
110
|
+
end
|
111
|
+
#
|
112
|
+
# script_name
|
113
|
+
#---------------------------------------------------------------------------
|
114
|
+
|
115
|
+
|
116
|
+
#---------------------------------------------------------------------------
|
117
|
+
# zip
|
118
|
+
#
|
119
|
+
def self.zip(root, opts={})
|
120
|
+
# $tm.hrm
|
121
|
+
|
122
|
+
# default options
|
123
|
+
opts = {'auto_delete'=>true}.merge(opts)
|
124
|
+
|
125
|
+
# get temp path to zip file
|
126
|
+
tgt_path = Minvee::Utils::TempPath.new(self.tmp_dir, 'ext'=>'tgz')
|
127
|
+
|
128
|
+
# build command
|
129
|
+
cmd = [
|
130
|
+
'tar',
|
131
|
+
'-czf',
|
132
|
+
tgt_path.to_s,
|
133
|
+
'./',
|
134
|
+
]
|
135
|
+
|
136
|
+
# go to working copy and zip there
|
137
|
+
Dir.chdir(root) do
|
138
|
+
system(*cmd)
|
139
|
+
end
|
140
|
+
|
141
|
+
# return path
|
142
|
+
return tgt_path
|
143
|
+
end
|
144
|
+
#
|
145
|
+
# zip
|
146
|
+
#---------------------------------------------------------------------------
|
147
|
+
|
148
|
+
|
149
|
+
#---------------------------------------------------------------------------
|
150
|
+
# find_working_copy_dir
|
151
|
+
# TODO: Allow for possibility that effective user does not own the
|
152
|
+
# working copy.
|
153
|
+
#
|
154
|
+
def self.find_working_copy_dir(opts={})
|
155
|
+
# $tm.hrm
|
156
|
+
|
157
|
+
# use explicit or current directory
|
158
|
+
if current_dir = opts['dir']
|
159
|
+
current_dir = File.expand_path(current_dir, Dir::pwd)
|
160
|
+
else
|
161
|
+
current_dir = Dir::pwd
|
162
|
+
end
|
163
|
+
|
164
|
+
# loop while the current dir is owned by the effective user
|
165
|
+
while File.stat(current_dir).writable?
|
166
|
+
# check for minvee.json
|
167
|
+
if File.exist?(current_dir + '/minvee.json')
|
168
|
+
return current_dir
|
169
|
+
end
|
170
|
+
|
171
|
+
# go to parent directory
|
172
|
+
current_dir = File.expand_path('..', current_dir)
|
173
|
+
end
|
174
|
+
|
175
|
+
# didn't find working copy
|
176
|
+
return nil
|
177
|
+
end
|
178
|
+
#
|
179
|
+
# find_working_copy_dir
|
180
|
+
#---------------------------------------------------------------------------
|
181
|
+
|
182
|
+
|
183
|
+
#---------------------------------------------------------------------------
|
184
|
+
# find_working_copy
|
185
|
+
#
|
186
|
+
def self.find_working_copy(opts={})
|
187
|
+
# $tm.hrm
|
188
|
+
|
189
|
+
# get working copy directory
|
190
|
+
root = find_working_copy_dir(opts)
|
191
|
+
root or return nil
|
192
|
+
|
193
|
+
# instantiate working copy object
|
194
|
+
wc = Minvee::Client::WorkingCopy.new(root, opts)
|
195
|
+
|
196
|
+
# return
|
197
|
+
return wc
|
198
|
+
end
|
199
|
+
#
|
200
|
+
# find_working_copy
|
201
|
+
#---------------------------------------------------------------------------
|
202
|
+
end
|
203
|
+
#
|
204
|
+
# Minvee::Client
|
205
|
+
#===============================================================================
|
206
|
+
|
207
|
+
|
208
|
+
#===============================================================================
|
209
|
+
# Minvee::Utils
|
210
|
+
#
|
211
|
+
module Minvee::Utils
|
212
|
+
#---------------------------------------------------------------------------
|
213
|
+
# rand_pk
|
214
|
+
#
|
215
|
+
@@rnd_chars = 'a'.upto('z').to_a + '0'.upto('9').to_a
|
216
|
+
@@rnd_chars_max = @@rnd_chars.length - 1
|
217
|
+
|
218
|
+
def self.rand_pk()
|
219
|
+
# intialize rv
|
220
|
+
rv = ''
|
221
|
+
|
222
|
+
# build return string
|
223
|
+
10.times do
|
224
|
+
rv += @@rnd_chars[rand 0 .. @@rnd_chars_max]
|
225
|
+
end
|
226
|
+
|
227
|
+
# freeze return value
|
228
|
+
rv.freeze
|
229
|
+
|
230
|
+
# return
|
231
|
+
return rv
|
232
|
+
end
|
233
|
+
#
|
234
|
+
# rand_pk
|
235
|
+
#---------------------------------------------------------------------------
|
236
|
+
|
237
|
+
|
238
|
+
#---------------------------------------------------------------------------
|
239
|
+
# atomic_write
|
240
|
+
#
|
241
|
+
def self.atomic_write(tgt_path)
|
242
|
+
# $tm.hrm
|
243
|
+
|
244
|
+
# get temp path
|
245
|
+
tmp_path = Minvee::Utils::TempPath.new(Minvee::Client.tmp_dir)
|
246
|
+
|
247
|
+
# ensure the tmp path gets deleted
|
248
|
+
begin
|
249
|
+
# provide write handle
|
250
|
+
File.open(tmp_path, 'w') do |tmp_file|
|
251
|
+
yield(tmp_file)
|
252
|
+
end
|
253
|
+
|
254
|
+
# move the temp file to the permanent location
|
255
|
+
FileUtils.mv(tmp_path, tgt_path)
|
256
|
+
ensure
|
257
|
+
# delete the tmp path
|
258
|
+
tmp_path.close
|
259
|
+
end
|
260
|
+
end
|
261
|
+
#
|
262
|
+
# atomic_write
|
263
|
+
#---------------------------------------------------------------------------
|
264
|
+
end
|
265
|
+
#
|
266
|
+
# Minvee::Utils
|
267
|
+
#===============================================================================
|
268
|
+
|
269
|
+
|
270
|
+
#===============================================================================
|
271
|
+
# Minvee::Client::Message
|
272
|
+
#
|
273
|
+
class Minvee::Client::Message
|
274
|
+
attr_reader :languages
|
275
|
+
attr_reader :params
|
276
|
+
attr_reader :path
|
277
|
+
|
278
|
+
#---------------------------------------------------------------------------
|
279
|
+
# initialize
|
280
|
+
#
|
281
|
+
def initialize(p_path)
|
282
|
+
# initialize params
|
283
|
+
@params = {}
|
284
|
+
|
285
|
+
# initialize languages
|
286
|
+
@languages = ['general']
|
287
|
+
|
288
|
+
# clone path
|
289
|
+
@path = p_path.clone
|
290
|
+
end
|
291
|
+
#
|
292
|
+
# initialize
|
293
|
+
#---------------------------------------------------------------------------
|
294
|
+
|
295
|
+
|
296
|
+
#---------------------------------------------------------------------------
|
297
|
+
# src
|
298
|
+
#
|
299
|
+
def src
|
300
|
+
# intialize search
|
301
|
+
search = @path.clone
|
302
|
+
|
303
|
+
# initialize rv
|
304
|
+
rv = Minvee::Client::Message::Sources.srcs['general']
|
305
|
+
|
306
|
+
# get message source
|
307
|
+
while search.length > 0
|
308
|
+
rv = rv[search.shift()]
|
309
|
+
end
|
310
|
+
|
311
|
+
# return
|
312
|
+
return rv
|
313
|
+
end
|
314
|
+
#
|
315
|
+
# src
|
316
|
+
#---------------------------------------------------------------------------
|
317
|
+
|
318
|
+
|
319
|
+
#---------------------------------------------------------------------------
|
320
|
+
# expand
|
321
|
+
#
|
322
|
+
def expand
|
323
|
+
# $tm.hrm
|
324
|
+
|
325
|
+
# initialize return value
|
326
|
+
rv = []
|
327
|
+
|
328
|
+
# split src
|
329
|
+
tokens = src.split(/(\[\[[a-z0-9\-\_]+?\]\])/imu)
|
330
|
+
tokens = tokens.grep(/\S/imu)
|
331
|
+
|
332
|
+
# build return value
|
333
|
+
tokens.each do |token|
|
334
|
+
if token.match(/\A\[\[[a-z0-9\-\_]+?\]\]\z/imu)
|
335
|
+
token.sub!(/\A\[\[\s*/imu, '')
|
336
|
+
token.sub!(/\s*\]\]\z/imu, '')
|
337
|
+
|
338
|
+
if @params.has_key?(token)
|
339
|
+
rv.push @params[token].to_s
|
340
|
+
end
|
341
|
+
else
|
342
|
+
rv.push token
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
# return
|
347
|
+
return rv.join('')
|
348
|
+
end
|
349
|
+
#
|
350
|
+
# expand
|
351
|
+
#---------------------------------------------------------------------------
|
352
|
+
end
|
353
|
+
#
|
354
|
+
# Minvee::Client::Message
|
355
|
+
#===============================================================================
|
356
|
+
|
357
|
+
|
358
|
+
#===============================================================================
|
359
|
+
# Minvee::Client::Message::Sources
|
360
|
+
#
|
361
|
+
module Minvee::Client::Message::Sources
|
362
|
+
@@srcs = {}
|
363
|
+
def self.srcs; return @@srcs; end;
|
364
|
+
|
365
|
+
# general
|
366
|
+
@@srcs['general'] = {
|
367
|
+
'test' => {
|
368
|
+
'a' => 'test message a',
|
369
|
+
'b' => 'test [[[[my-param]] b',
|
370
|
+
},
|
371
|
+
|
372
|
+
'questions' => {
|
373
|
+
'yes' => {
|
374
|
+
'letter' => 'y',
|
375
|
+
'word' => 'yes',
|
376
|
+
},
|
377
|
+
'no' => {
|
378
|
+
'letter' => 'n',
|
379
|
+
'word' => 'no',
|
380
|
+
},
|
381
|
+
}
|
382
|
+
}
|
383
|
+
end
|
384
|
+
#
|
385
|
+
# Minvee::Client::Message::Sources
|
386
|
+
#===============================================================================
|
387
|
+
|
388
|
+
|
389
|
+
#===============================================================================
|
390
|
+
# Minvee::Client::WorkingCopy
|
391
|
+
#
|
392
|
+
class Minvee::Client::WorkingCopy
|
393
|
+
attr_accessor :root
|
394
|
+
attr_reader :settings
|
395
|
+
|
396
|
+
|
397
|
+
#---------------------------------------------------------------------------
|
398
|
+
# initialize
|
399
|
+
#
|
400
|
+
def initialize(p_root, opts={})
|
401
|
+
# $tm.hrm
|
402
|
+
|
403
|
+
# p_root must be defined
|
404
|
+
if p_root.nil?
|
405
|
+
raise 'root-not-defined: did not get a defined root for working copy'
|
406
|
+
end
|
407
|
+
|
408
|
+
# hold on to root
|
409
|
+
@root = p_root.to_s.dup
|
410
|
+
|
411
|
+
# normalize and freeze root
|
412
|
+
@root.sub!(/\/+\z/imu, '')
|
413
|
+
@root.freeze
|
414
|
+
|
415
|
+
# if directory doesn't exist
|
416
|
+
if not File.exist?(@root)
|
417
|
+
raise 'root-not-exists: do not find a directory at ' + @root
|
418
|
+
end
|
419
|
+
|
420
|
+
# if settings file doesn't exist
|
421
|
+
if not File.exist?(self.settings_path)
|
422
|
+
raise 'no-settings-file: do not find minvee.json at ' + settings_path
|
423
|
+
end
|
424
|
+
|
425
|
+
# slurp in file
|
426
|
+
# KLUDGE: File or JSON will throw errors at this point if there are any.
|
427
|
+
# We'll just let those bubble up to the script that is calling this
|
428
|
+
# method instead of catching the exceptions here.
|
429
|
+
@settings = JSON.parse(File.read(self.settings_path))
|
430
|
+
|
431
|
+
# check settings
|
432
|
+
check_settings(opts)
|
433
|
+
end
|
434
|
+
#
|
435
|
+
# initialize
|
436
|
+
#---------------------------------------------------------------------------
|
437
|
+
|
438
|
+
|
439
|
+
#---------------------------------------------------------------------------
|
440
|
+
# zip
|
441
|
+
#
|
442
|
+
def zip(opts={})
|
443
|
+
return Minvee::Client.zip(@root, opts)
|
444
|
+
end
|
445
|
+
#
|
446
|
+
# zip
|
447
|
+
#---------------------------------------------------------------------------
|
448
|
+
|
449
|
+
|
450
|
+
#---------------------------------------------------------------------------
|
451
|
+
# settings_path
|
452
|
+
#
|
453
|
+
def settings_path
|
454
|
+
return @root + '/minvee.json'
|
455
|
+
end
|
456
|
+
#
|
457
|
+
# settings_path
|
458
|
+
#---------------------------------------------------------------------------
|
459
|
+
|
460
|
+
|
461
|
+
#---------------------------------------------------------------------------
|
462
|
+
# save_settings
|
463
|
+
#
|
464
|
+
def save_settings
|
465
|
+
Minvee::Utils.atomic_write(self.settings_path) do |file|
|
466
|
+
file.print JSON.pretty_generate(@settings)
|
467
|
+
end
|
468
|
+
end
|
469
|
+
#
|
470
|
+
# save_settings
|
471
|
+
#---------------------------------------------------------------------------
|
472
|
+
|
473
|
+
|
474
|
+
# private from here on
|
475
|
+
private
|
476
|
+
|
477
|
+
|
478
|
+
#---------------------------------------------------------------------------
|
479
|
+
# check_settings
|
480
|
+
# settings must have a project element, which is a hash, and that hash
|
481
|
+
# must have a url.
|
482
|
+
#
|
483
|
+
def check_settings(opts={})
|
484
|
+
# $tm.hrm
|
485
|
+
|
486
|
+
# default options
|
487
|
+
opts = {'check_url'=>true}.merge(opts)
|
488
|
+
|
489
|
+
# must be hash
|
490
|
+
if not @settings.is_a?(Hash)
|
491
|
+
raise "settings-not-hash: the settings for #{@root} are not a hash"
|
492
|
+
end
|
493
|
+
|
494
|
+
# convenience
|
495
|
+
project = @settings['project']
|
496
|
+
|
497
|
+
# must have project element
|
498
|
+
if not project
|
499
|
+
raise "settings-no-project: there are no project settings for #{@root}"
|
500
|
+
end
|
501
|
+
|
502
|
+
# project element must be a hash
|
503
|
+
if not project.is_a?(Hash)
|
504
|
+
raise "settings-project-not-hash: the project element for #{@root} is not a hash"
|
505
|
+
end
|
506
|
+
|
507
|
+
# must have project url
|
508
|
+
if not project['url']
|
509
|
+
raise "settings-project-no-url: the settings for #{@root} do not have a project url"
|
510
|
+
end
|
511
|
+
|
512
|
+
# must be an HTTPS url
|
513
|
+
# TODO: We'll probably need to expand what types of URLs are allowed.
|
514
|
+
# For example, we should probably allow http on localhost.
|
515
|
+
if opts['check_url']
|
516
|
+
if not URI(project['url']).is_a?(URI::HTTPS)
|
517
|
+
raise "settings-project-invalid-url: the project url for #{@root} is not an HTTPS url: " + project['url']
|
518
|
+
end
|
519
|
+
end
|
520
|
+
end
|
521
|
+
#
|
522
|
+
# check_settings
|
523
|
+
#---------------------------------------------------------------------------
|
524
|
+
end
|
525
|
+
#
|
526
|
+
# Minvee::Client::WorkingCopy
|
527
|
+
#===============================================================================
|
528
|
+
|
529
|
+
|
530
|
+
#===============================================================================
|
531
|
+
# Minvee::Utils::TempPath
|
532
|
+
#
|
533
|
+
class Minvee::Utils::TempPath
|
534
|
+
attr_reader :path
|
535
|
+
attr_accessor :auto_delete
|
536
|
+
|
537
|
+
#---------------------------------------------------------------------------
|
538
|
+
# initialize
|
539
|
+
#
|
540
|
+
def initialize(base, opts={})
|
541
|
+
# default options
|
542
|
+
opts = {'auto_delete'=>true}.merge(opts)
|
543
|
+
|
544
|
+
# if explicit path sent
|
545
|
+
if opts['explicit']
|
546
|
+
@path = base
|
547
|
+
|
548
|
+
# else build random path
|
549
|
+
else
|
550
|
+
# if path is a directory, add /
|
551
|
+
if File.directory?(base)
|
552
|
+
base = base.sub(/\/*\z/imu, '/')
|
553
|
+
end
|
554
|
+
|
555
|
+
# initialize path
|
556
|
+
@path = base + Minvee::Utils.rand_pk
|
557
|
+
|
558
|
+
# add suffix
|
559
|
+
if opts['suffix']
|
560
|
+
@path += '.' + opts['suffix']
|
561
|
+
end
|
562
|
+
|
563
|
+
# add ext if sent
|
564
|
+
if opts['ext']
|
565
|
+
ext = opts['ext'].dup
|
566
|
+
ext.sub!(/\A\.*/imu, '.')
|
567
|
+
@path += ext
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
# set finalizer for this object
|
572
|
+
ObjectSpace.define_finalizer(self, proc { self.class.finalize(self.object_id) })
|
573
|
+
|
574
|
+
# set auto delete
|
575
|
+
@auto_delete = opts['auto_delete']
|
576
|
+
end
|
577
|
+
#
|
578
|
+
# initialize
|
579
|
+
#---------------------------------------------------------------------------
|
580
|
+
|
581
|
+
|
582
|
+
#---------------------------------------------------------------------------
|
583
|
+
# to_s. and to_str
|
584
|
+
#
|
585
|
+
def to_str
|
586
|
+
return @path
|
587
|
+
end
|
588
|
+
|
589
|
+
def to_s
|
590
|
+
return @path
|
591
|
+
end
|
592
|
+
|
593
|
+
def +(str)
|
594
|
+
return @path.to_s + str
|
595
|
+
end
|
596
|
+
#
|
597
|
+
# to_s. and to_str
|
598
|
+
#---------------------------------------------------------------------------
|
599
|
+
|
600
|
+
|
601
|
+
#---------------------------------------------------------------------------
|
602
|
+
# close
|
603
|
+
#
|
604
|
+
def close
|
605
|
+
# if file exists, delete it
|
606
|
+
if self.auto_delete
|
607
|
+
if File.directory?(self.path)
|
608
|
+
FileUtils.rm_rf(self.path)
|
609
|
+
elsif File.exist?(self.path)
|
610
|
+
File.delete(self.path)
|
611
|
+
end
|
612
|
+
end
|
613
|
+
end
|
614
|
+
#
|
615
|
+
# close
|
616
|
+
#---------------------------------------------------------------------------
|
617
|
+
|
618
|
+
|
619
|
+
#---------------------------------------------------------------------------
|
620
|
+
# finalize method
|
621
|
+
#
|
622
|
+
def self.finalize(id)
|
623
|
+
# $tm.hrm
|
624
|
+
|
625
|
+
# get object from id
|
626
|
+
myself = ObjectSpace._id2ref(id)
|
627
|
+
|
628
|
+
# close
|
629
|
+
myself.close()
|
630
|
+
end
|
631
|
+
#
|
632
|
+
# finalize method
|
633
|
+
#---------------------------------------------------------------------------
|
634
|
+
end
|
635
|
+
#
|
636
|
+
# Minvee::Utils::TempPath
|
637
|
+
#===============================================================================
|
638
|
+
|
639
|
+
|
640
|
+
#===============================================================================
|
641
|
+
# Minvee::Utils::TempDir
|
642
|
+
#
|
643
|
+
class Minvee::Utils::TempDir < Minvee::Utils::TempPath
|
644
|
+
#---------------------------------------------------------------------------
|
645
|
+
# initialize
|
646
|
+
#
|
647
|
+
def initialize(base, opts={})
|
648
|
+
# call super method
|
649
|
+
super(base, opts)
|
650
|
+
|
651
|
+
# create directory
|
652
|
+
FileUtils::mkdir_p(@path)
|
653
|
+
end
|
654
|
+
#
|
655
|
+
# initialize
|
656
|
+
#---------------------------------------------------------------------------
|
657
|
+
end
|
658
|
+
#
|
659
|
+
# Minvee::Utils::TempDir
|
660
|
+
#===============================================================================
|
661
|
+
|
662
|
+
|
663
|
+
#===============================================================================
|
664
|
+
# Minvee::Client::Questions
|
665
|
+
#
|
666
|
+
module Minvee::Client::Questions
|
667
|
+
#---------------------------------------------------------------------------
|
668
|
+
# ask
|
669
|
+
#
|
670
|
+
def self.ask(type, opts)
|
671
|
+
# $tm.hrm
|
672
|
+
|
673
|
+
# select
|
674
|
+
if type == 'select'
|
675
|
+
return self.select(opts)
|
676
|
+
|
677
|
+
# short
|
678
|
+
elsif type == 'short'
|
679
|
+
return self.short(opts)
|
680
|
+
|
681
|
+
# boolean
|
682
|
+
elsif type == 'boolean'
|
683
|
+
return self.boolean(opts)
|
684
|
+
|
685
|
+
# else unknown
|
686
|
+
else
|
687
|
+
raise 'unknown question type: ' + type
|
688
|
+
end
|
689
|
+
end
|
690
|
+
#
|
691
|
+
# ask
|
692
|
+
#---------------------------------------------------------------------------
|
693
|
+
|
694
|
+
|
695
|
+
#---------------------------------------------------------------------------
|
696
|
+
# select
|
697
|
+
#
|
698
|
+
def self.select(opts)
|
699
|
+
# $tm.hrm
|
700
|
+
|
701
|
+
# initialize choice
|
702
|
+
choice = ''
|
703
|
+
|
704
|
+
# initialize choices hash
|
705
|
+
choices = {}
|
706
|
+
|
707
|
+
# initialize return hash
|
708
|
+
rv = {}
|
709
|
+
|
710
|
+
# normalized choices
|
711
|
+
opts['choices'].each do |k, v|
|
712
|
+
choices[k.downcase] = v
|
713
|
+
end
|
714
|
+
|
715
|
+
# prompt user until they make a choice
|
716
|
+
while not choices[choice]
|
717
|
+
# empty line
|
718
|
+
puts
|
719
|
+
|
720
|
+
# output question
|
721
|
+
puts opts['question']
|
722
|
+
|
723
|
+
# output choices
|
724
|
+
choices.each do |k, v|
|
725
|
+
puts k + ': ' + v['text']
|
726
|
+
end
|
727
|
+
|
728
|
+
# empty line
|
729
|
+
puts
|
730
|
+
|
731
|
+
# prompt
|
732
|
+
print opts['prompt'] + ': '
|
733
|
+
|
734
|
+
# get input from user
|
735
|
+
choice = gets
|
736
|
+
choice.sub!(/\s+\z/imu, '')
|
737
|
+
choice.sub!(/\A\s+/imu, '')
|
738
|
+
choice.downcase!
|
739
|
+
end
|
740
|
+
|
741
|
+
# store choice
|
742
|
+
rv['choice'] = choice
|
743
|
+
|
744
|
+
# if "other"
|
745
|
+
if choices[choice]['other']
|
746
|
+
while not rv['other']
|
747
|
+
# get other choice
|
748
|
+
print choices[choice]['other'] + ': '
|
749
|
+
response = gets
|
750
|
+
|
751
|
+
# normalize response
|
752
|
+
response.sub!(/\s+\z/imu, '')
|
753
|
+
response.sub!(/\A\s+/imu, '')
|
754
|
+
|
755
|
+
# if response has content, we're done with this loop
|
756
|
+
if response.length > 0
|
757
|
+
rv['other'] = response
|
758
|
+
end
|
759
|
+
end
|
760
|
+
end
|
761
|
+
|
762
|
+
# return
|
763
|
+
return rv
|
764
|
+
end
|
765
|
+
#
|
766
|
+
# select
|
767
|
+
#---------------------------------------------------------------------------
|
768
|
+
|
769
|
+
|
770
|
+
#---------------------------------------------------------------------------
|
771
|
+
# short
|
772
|
+
#
|
773
|
+
def self.short(opts)
|
774
|
+
# $tm.hrm
|
775
|
+
|
776
|
+
# initialize return hash
|
777
|
+
rv = {}
|
778
|
+
|
779
|
+
# loop until we get an answer
|
780
|
+
while not rv['response']
|
781
|
+
# get other choice
|
782
|
+
print opts['prompt'] + ': '
|
783
|
+
response = gets
|
784
|
+
|
785
|
+
# normalize response
|
786
|
+
response.sub!(/\s+\z/imu, '')
|
787
|
+
response.sub!(/\A\s+/imu, '')
|
788
|
+
|
789
|
+
# if response has content, or response is not required, we're done
|
790
|
+
if (response.length > 0) or (not opts['required'])
|
791
|
+
rv['response'] = response
|
792
|
+
end
|
793
|
+
end
|
794
|
+
|
795
|
+
# return
|
796
|
+
return rv
|
797
|
+
end
|
798
|
+
#
|
799
|
+
# short
|
800
|
+
#---------------------------------------------------------------------------
|
801
|
+
|
802
|
+
|
803
|
+
#---------------------------------------------------------------------------
|
804
|
+
# boolean
|
805
|
+
#
|
806
|
+
def self.boolean(opts)
|
807
|
+
# $tm.hrm
|
808
|
+
|
809
|
+
# initialize return hash
|
810
|
+
rv = {}
|
811
|
+
|
812
|
+
# output prompt
|
813
|
+
puts opts['prompt']
|
814
|
+
|
815
|
+
# boolean options
|
816
|
+
bools = {
|
817
|
+
Minvee::Client::Message.new(%w{questions yes letter}).expand => true,
|
818
|
+
Minvee::Client::Message.new(%w{questions no letter}).expand => false,
|
819
|
+
}
|
820
|
+
|
821
|
+
# initialize choices
|
822
|
+
choices = []
|
823
|
+
|
824
|
+
# yes
|
825
|
+
choices.push 'y'
|
826
|
+
choices.push 'n'
|
827
|
+
|
828
|
+
# default
|
829
|
+
if opts.has_key?('default')
|
830
|
+
has_default = true
|
831
|
+
|
832
|
+
if opts['default']
|
833
|
+
choices[0].upcase!
|
834
|
+
else
|
835
|
+
choices[1].upcase!
|
836
|
+
end
|
837
|
+
end
|
838
|
+
|
839
|
+
# ask until we get an answer
|
840
|
+
while rv['response'].nil?
|
841
|
+
# prompt
|
842
|
+
print choices.join('/'), ': '
|
843
|
+
|
844
|
+
# get response
|
845
|
+
response = gets
|
846
|
+
|
847
|
+
# normalize response
|
848
|
+
response.sub!(/\s+\z/imu, '')
|
849
|
+
response.sub!(/\A\s+/imu, '')
|
850
|
+
response.downcase!()
|
851
|
+
|
852
|
+
# if anything left in the string, get the first character
|
853
|
+
if response.length > 0
|
854
|
+
response = response[0]
|
855
|
+
end
|
856
|
+
|
857
|
+
# if we got an acceptable answer
|
858
|
+
if bools.has_key?(response)
|
859
|
+
rv['response'] = bools[response]
|
860
|
+
elsif has_default and (response == '')
|
861
|
+
rv['response'] = opts['default']
|
862
|
+
end
|
863
|
+
end
|
864
|
+
|
865
|
+
# return
|
866
|
+
return rv
|
867
|
+
end
|
868
|
+
#
|
869
|
+
# boolean
|
870
|
+
#---------------------------------------------------------------------------
|
871
|
+
end
|
872
|
+
#
|
873
|
+
# Minvee::Client::Questions
|
874
|
+
#===============================================================================
|
875
|
+
|
876
|
+
|
877
|
+
#===============================================================================
|
878
|
+
# run if the script was not loaded by another script
|
879
|
+
#
|
880
|
+
if caller().length <= 0
|
881
|
+
Minvee::Client.process_command_line ARGV
|
882
|
+
end
|
883
|
+
#
|
884
|
+
# run if the script was not loaded by another script
|
885
|
+
#===============================================================================
|