tpkg 1.16.2

Sign up to get free protection for your applications and to get access to all the features.
data/bin/tpkg ADDED
@@ -0,0 +1,560 @@
1
+ #!/usr/bin/ruby -w
2
+ ##############################################################################
3
+ # tpkg package management and deployment tool
4
+ ##############################################################################
5
+
6
+ # Ensure we can find tpkg.rb
7
+ #$:.unshift File.dirname(__FILE__)
8
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
9
+
10
+ require 'optparse'
11
+ require 'tpkg'
12
+
13
+ #
14
+ # Parse the command line options
15
+ #
16
+
17
+ @action = nil
18
+ @action_value = nil
19
+ @debug = false
20
+ @prompt = true
21
+ @quiet = false
22
+ @sudo = true
23
+ @lockforce = false
24
+ @force = false
25
+ @deploy = false
26
+ @deploy_params = ARGV # hold parameters for how to invoke tpkg on the machines we're deploying to
27
+ @deploy_options = {} # options for how to run the deployer
28
+ @servers = nil
29
+ @worker_count = 10
30
+ @rerun_with_sudo = false
31
+ @tpkg_options = {}
32
+
33
+ def rerun_with_sudo_if_necessary
34
+ if Process.euid != 0 && @sudo
35
+ warn "Executing with sudo"
36
+ exec('sudo', $0, *ARGV)
37
+ end
38
+ end
39
+
40
+ opts = OptionParser.new(nil, 24, ' ')
41
+ opts.banner = 'Usage: tpkg [options]'
42
+ opts.on('--servers', '-s', '=SERVERS', Array, 'Servers to apply the actions to') do |opt|
43
+ @servers = opt
44
+ @deploy = true
45
+ @deploy_params = @deploy_params - ['--servers', '-s', @servers.join(","), "--servers=#{@servers.join(',')}"]
46
+ end
47
+ opts.on('--make', '-m', '=DIRECTORY', 'Make a package out of the contents of the directory') do |opt|
48
+ @action = :make
49
+ @action_value = opt
50
+ end
51
+ opts.on('--extract', '-x', '=DIRECTORY', 'Extract the metadata for a directory of packages') do |opt|
52
+ @action = :extract
53
+ @action_value = opt
54
+ end
55
+ opts.on('--install', '-i', '=PACKAGES', 'Install one or more packages', Array) do |opt|
56
+ @rerun_with_sudo = true
57
+ @action = :install
58
+ @action_value = opt
59
+ end
60
+ opts.on('--upgrade', '-u', '=PACKAGES', 'Upgrade one or more packages', Array) do |opt|
61
+ @rerun_with_sudo = true
62
+ @action = :upgrade
63
+ @action_value = opt
64
+ end
65
+ opts.on('--downgrade', '=PACKAGES', 'Downgrade one or more packages', Array) do |opt|
66
+ @rerun_with_sudo = true
67
+ @action = :downgrade
68
+ @action_value = opt
69
+ end
70
+ opts.on('--ua', 'Upgrade all packages') do |opt|
71
+ @rerun_with_sudo = true
72
+ @action = :upgrade
73
+ end
74
+ opts.on('--remove', '-r', '=PACKAGES', 'Remove one or more packages', Array) do |opt|
75
+ @rerun_with_sudo = true
76
+ @action = :remove
77
+ @action_value = opt
78
+ end
79
+ opts.on('--rd', '=PACKAGES', 'Similar to -r but also remove depending packages', Array) do |opt|
80
+ @rerun_with_sudo = true
81
+ @action = :remove_all_dep
82
+ @action_value = opt
83
+ end
84
+ opts.on('--rp', '=PACKAGES', 'Similar to -r but also remove prerequisites', Array) do |opt|
85
+ @rerun_with_sudo = true
86
+ @action = :remove_all_prereq
87
+ @action_value = opt
88
+ end
89
+ opts.on('--ra', 'Remove all packages') do |opt|
90
+ @rerun_with_sudo = true
91
+ @action = :remove
92
+ end
93
+ opts.on('--verify', '-V', '=NAME', 'Verify packages') do |opt|
94
+ @rerun_with_sudo = true
95
+ @action = :verify
96
+ @action_value = opt
97
+ end
98
+ opts.on('--start', '=NAME', 'Start the init script for the specified package', Array) do |opt|
99
+ @rerun_with_sudo = true
100
+ @action = :start_init
101
+ @action_value = opt
102
+ end
103
+ opts.on('--stop', '=NAME', 'Stop the init script for the specified package', Array) do |opt|
104
+ @rerun_with_sudo = true
105
+ @action = :stop_init
106
+ @action_value = opt
107
+ end
108
+ opts.on('--restart', '=NAME', 'Restart the init script for the specified package', Array) do |opt|
109
+ @rerun_with_sudo = true
110
+ @action = :restart_init
111
+ @action_value = opt
112
+ end
113
+ opts.on('--reload', '=NAME', 'Reload the init script for the specified package', Array) do |opt|
114
+ @rerun_with_sudo = true
115
+ @action = :reload_init
116
+ @action_value = opt
117
+ end
118
+ opts.on('--start-all', 'Start the init scripts for all packages') do |opt|
119
+ @rerun_with_sudo = true
120
+ @action = :start_init
121
+ end
122
+ opts.on('--stop-all', 'Stop the init script for all packages') do |opt|
123
+ @rerun_with_sudo = true
124
+ @action = :stop_init
125
+ end
126
+ opts.on('--restart-all', 'Restart the init script for all packages') do |opt|
127
+ @rerun_with_sudo = true
128
+ @action = :restart_init
129
+ end
130
+ opts.on('--reload-all', 'Reload the init script for all packages') do |opt|
131
+ @rerun_with_sudo = true
132
+ @action = :reload_init
133
+ end
134
+ opts.on('--query', '-q', '=NAMES', 'List installed packages', Array) do |opt|
135
+ # People mistype -qa instead of --qa frequently
136
+ if opt == ['a']
137
+ warn "NOTE: tpkg -qa queries for a pkg named 'a', you probably want --qa for all pkgs"
138
+ end
139
+ @action = :query_installed
140
+ @action_value = opt
141
+ end
142
+ opts.on('--qa', 'List all installed packages') do |opt|
143
+ @action = :query_installed
144
+ end
145
+ opts.on('--qi', '=NAME', 'Info for packages') do |opt|
146
+ @action = :query_info
147
+ @action_value = opt
148
+ end
149
+ opts.on('--ql', '=NAME', 'List files in installed packages') do |opt|
150
+ @action = :query_list_files
151
+ @action_value = opt
152
+ end
153
+ opts.on('--qf', '=FILE', 'List the package that owns a file') do |opt|
154
+ @action = :query_who_owns_file
155
+ @action_value = opt
156
+ end
157
+ opts.on('--qv', '=NAME', 'List available packages') do |opt|
158
+ @action = :query_available
159
+ @action_value = opt
160
+ end
161
+ opts.on('--qva', 'List all available packages') do |opt|
162
+ @action = :query_available
163
+ end
164
+ opts.on('--qr', '=NAME', 'List installed packages that require package') do |opt|
165
+ @action = :query_requires
166
+ @action_value = opt
167
+ end
168
+ opts.on('--qd', '=NAME', 'List the packages that package depends on') do |opt|
169
+ @action = :query_depends
170
+ @action_value = opt
171
+ end
172
+ opts.on('--qld', '=NAME', 'Similar to --qd, but only look at local packages') do |opt|
173
+ @action = :query_local_depends
174
+ @action_value = opt
175
+ end
176
+
177
+ opts.on('--dw', '=INTEGER', 'Number of workers for deploying') do |opt|
178
+ @worker_count = opt.to_i
179
+ @deploy_params = @deploy_params - ['--dw', @worker_count, "--dw=#{opt}"]
180
+ end
181
+ opts.on('--qX', '=FILENAME', 'Display tpkg.xml of the given package') do |opt|
182
+ @action = :query_tpkgxml
183
+ @action_value = opt
184
+ end
185
+ opts.on('--qenv', "Display machine's information") do |opt|
186
+ @action = :query_env
187
+ end
188
+ opts.on('--source', '=NAME', 'Sources where packages are located', Array) do |opt|
189
+ @tpkg_options["sources"] = opt
190
+ end
191
+ opts.on('-n', '--no-prompt', 'No confirmation prompts') do |opt|
192
+ @prompt = opt
193
+ Tpkg::set_prompt(@prompt)
194
+ end
195
+ opts.on('--quiet', 'Reduce informative but non-essential output') do |opt|
196
+ @quiet = opt
197
+ end
198
+ opts.on('--no-sudo', 'No calls to sudo for operations that might need root') do |opt|
199
+ @sudo = opt
200
+ end
201
+ opts.on('--lock-force', 'Force the removal of an existing lockfile') do |opt|
202
+ @lockforce = opt
203
+ end
204
+ opts.on('--force', 'Force the execution of a given task.') do |opt|
205
+ @force = opt
206
+ end
207
+ opts.on('--use-ssh-key', 'Use ssh key for deploying instead of password') do |opt|
208
+ @deploy_options["use-ssh-key"] = opt
209
+ @deploy_params = @deploy_params - ['--use-ssh-key']
210
+ end
211
+ opts.on('--deploy-as', '=USERNAME', 'What username to use for deploying to remote server') do |opt|
212
+ @deploy_options["deploy-as"] = opt
213
+ @deploy_params = @deploy_params - ['--deploy-as']
214
+ end
215
+ opts.on('--debug', 'Print lots of messages about what tpkg is doing') do |opt|
216
+ @debug = opt
217
+ Tpkg::set_debug(@debug)
218
+ end
219
+ opts.on('--version', 'Show tpkg version') do |opt|
220
+ puts Tpkg::VERSION
221
+ exit
222
+ end
223
+ opts.on_tail("-h", "--help", "Show this message") do
224
+ puts opts
225
+ exit
226
+ end
227
+
228
+ leftovers = opts.parse(ARGV)
229
+
230
+ # Rerun with sudo if necessary, unless it's a deploy, then
231
+ # we don't need to run with sudo on this machine. It will run with sudo
232
+ # on the remote machine
233
+ if @rerun_with_sudo && !@deploy
234
+ rerun_with_sudo_if_necessary
235
+ end
236
+
237
+ # Display a usage message if the user did not specify a valid action to perform.
238
+ if !@action
239
+ puts opts
240
+ exit
241
+ end
242
+
243
+ #
244
+ # Figure out base directory, sources and other configuration
245
+ #
246
+
247
+ def instantiate_tpkg(options = {})
248
+ base = Tpkg::DEFAULT_BASE
249
+ sources = options["sources"] || []
250
+ report_server = nil
251
+
252
+ [File.join(Tpkg::CONFIGDIR, 'tpkg.conf'), "#{ENV['HOME']}/.tpkg.conf"].each do |configfile|
253
+ if File.exist?(configfile)
254
+ IO.foreach(configfile) do |line|
255
+ line.chomp!
256
+ next if (line =~ /^\s*$/); # Skip blank lines
257
+ next if (line =~ /^\s*#/); # Skip comments
258
+ line.strip! # Remove leading/trailing whitespace
259
+ key, value = line.split(/\s*=\s*/, 2)
260
+ if key == 'base'
261
+ # Warn the user, as this could potentially be confusing
262
+ # if they don't realize there's a config file lying
263
+ # around
264
+ base = value
265
+ warn "Using base #{base} from #{configfile}"
266
+ elsif key == 'source'
267
+ sources << value
268
+ puts "Loaded source #{value} from #{configfile}" if (@debug)
269
+ elsif key == 'report_server'
270
+ report_server = value
271
+ puts "Loaded report server #{report_server} from #{configfile}" if (@debug)
272
+ end
273
+ end
274
+ end
275
+ end
276
+
277
+ if ENV['TPKG_HOME']
278
+ base = ENV['TPKG_HOME']
279
+ # Warn the user, as this could potentially be confusing
280
+ # if they don't realize there's an environment variable set.
281
+ warn "Using base '#{base}' base from $TPKG_HOME"
282
+ end
283
+
284
+ tpkg = Tpkg.new(:base => base, :sources => sources, :report_server => report_server, :lockforce => @lockforce, :force => @force)
285
+ end
286
+
287
+ passphrase_callback = lambda do | package |
288
+ # ask("Passphrase for #{package}: ", true)
289
+ begin
290
+ system 'stty -echo;'
291
+ print "Passphrase for #{package}: "
292
+ input = STDIN.gets.chomp
293
+ ensure
294
+ system 'stty echo; echo ""'
295
+ end
296
+ input
297
+ end
298
+
299
+ #
300
+ # Do stuff
301
+ #
302
+ if @deploy
303
+ # puts "Creating deployer with #{@worker_count} number of worker"
304
+ @deploy_options["max-worker"] = @worker_count
305
+ @deploy_options["abort-on-fail"] = false
306
+ Tpkg::deploy(@deploy_params, @deploy_options, @servers)
307
+ exit
308
+ end
309
+
310
+ ret_val = 0
311
+ case @action
312
+ when :make
313
+ pkgfile = Tpkg::make_package(@action_value, passphrase_callback)
314
+ if pkgfile
315
+ puts "Package is #{pkgfile}"
316
+ else
317
+ puts "Package build aborted or failed"
318
+ end
319
+ when :extract
320
+ Tpkg::extract_metadata(@action_value)
321
+ when :install
322
+ tpkg = instantiate_tpkg(@tpkg_options)
323
+ ret_val = tpkg.install(@action_value, passphrase_callback)
324
+ when :upgrade
325
+ tpkg = instantiate_tpkg(@tpkg_options)
326
+ ret_val = tpkg.upgrade(@action_value, passphrase_callback)
327
+ when :downgrade
328
+ downgrade = true
329
+ tpkg = instantiate_tpkg(@tpkg_options)
330
+ ret_val = tpkg.upgrade(@action_value, passphrase_callback, downgrade)
331
+ when :remove
332
+ tpkg = instantiate_tpkg(@tpkg_options)
333
+ ret_val = tpkg.remove(@action_value)
334
+ when :remove_all_dep
335
+ tpkg = instantiate_tpkg(@tpkg_options)
336
+ ret_val = tpkg.remove(@action_value, {:remove_all_dep => true})
337
+ when :remove_all_prereq
338
+ tpkg = instantiate_tpkg(@tpkg_options)
339
+ ret_val = tpkg.remove(@action_value, {:remove_all_prereq => true})
340
+ when :verify
341
+ result = nil
342
+ # Verify a given .tpkg file
343
+ if File.exist?(@action_value)
344
+ Tpkg::verify_package_checksum(@action_value)
345
+ # Verify an installed pkg
346
+ else
347
+ tpkg = instantiate_tpkg(@tpkg_options)
348
+ results = tpkg.verify_file_metadata(@action_value)
349
+ if results.length == 0
350
+ puts "No package found"
351
+ end
352
+ success = true
353
+ results.each do | file, errors |
354
+ if errors.length == 0
355
+ puts "#{file}: Passed"
356
+ else
357
+ puts "#{file}: Failed (Reasons: #{errors.join(", ")})"
358
+ success = false
359
+ end
360
+ end
361
+ puts "Package verification failed" unless success
362
+ end
363
+ when :start_init
364
+ tpkg = instantiate_tpkg(@tpkg_options)
365
+ ret_val = tpkg.execute_init(@action_value, "start")
366
+ when :stop_init
367
+ tpkg = instantiate_tpkg(@tpkg_options)
368
+ ret_val = tpkg.execute_init(@action_value, "stop")
369
+ when :restart_init
370
+ tpkg = instantiate_tpkg(@tpkg_options)
371
+ ret_val = tpkg.execute_init(@action_value, "restart")
372
+ when :reload_init
373
+ tpkg = instantiate_tpkg(@tpkg_options)
374
+ ret_val = tpkg.execute_init(@action_value, "reload")
375
+ when :query_installed
376
+ tpkg = instantiate_tpkg(@tpkg_options)
377
+ req = nil
378
+ matches = []
379
+ if @action_value
380
+ @action_value.each do | value |
381
+ req = Tpkg::parse_request(value, tpkg.installed_directory)
382
+ match = tpkg.installed_packages_that_meet_requirement(req)
383
+
384
+ # If the user requested specific packages and we found no matches
385
+ # then exit with a non-zero value to indicate failure. This allows
386
+ # command-line syntax like "tpkg -q foo || tpkg -i foo" to ensure
387
+ # that a package is installed.
388
+ ret_val = 1 if match.empty?
389
+ matches |= match
390
+ end
391
+ else
392
+ matches = tpkg.installed_packages_that_meet_requirement(req)
393
+ end
394
+
395
+ if !@quiet
396
+ matches.sort(&Tpkg::SORT_PACKAGES).each do |pkg|
397
+ puts pkg[:metadata][:filename]
398
+ end
399
+ end
400
+ when :query_info
401
+ metadatas = nil
402
+ if File.exist?(@action_value)
403
+ metadatas = [Tpkg::metadata_from_package(@action_value)]
404
+ else
405
+ tpkg = instantiate_tpkg(@tpkg_options)
406
+ metadatas = []
407
+ requirements = []
408
+ packages = {}
409
+ tpkg.parse_requests([@action_value], requirements, packages)
410
+ packages.each do | name, pkgs |
411
+ pkgs.each do | pkg |
412
+ metadatas << pkg[:metadata]
413
+ end
414
+ end
415
+ end
416
+ already_displayed = {}
417
+ metadatas.each do |metadata|
418
+ next if already_displayed[metadata[:filename]]
419
+ already_displayed[metadata[:filename]] = true
420
+ [:name, :version, :package_version, :operatingsystem, :architecture, :maintainer, :description, :bugreporting].each do |field|
421
+ if metadata[field]
422
+ if metadata[field].kind_of?(Array)
423
+ puts "#{field}: #{metadata[field].join(',')}"
424
+ else
425
+ puts "#{field}: #{metadata[field]}"
426
+ end
427
+ end
428
+ end
429
+ end
430
+ when :query_list_files
431
+ tpkg = instantiate_tpkg(@tpkg_options)
432
+ pkgfiles = nil
433
+ if File.exist?(@action_value)
434
+ fip = Tpkg::files_in_package(@action_value)
435
+ tpkg.normalize_paths(fip)
436
+ puts "#{pkgfile}:"
437
+ fip[:normalized].each { |file| puts file }
438
+ else
439
+ pkgfiles = []
440
+ metadatas = []
441
+ requirements = []
442
+ packages = {}
443
+
444
+ req = Tpkg::parse_request(@action_value)
445
+ pkgs = tpkg.installed_packages_that_meet_requirement(req)
446
+ if pkgs.nil? or pkgs.empty?
447
+ ret_val = 1
448
+ puts "Could not find any installed packages that meet the request \"#{@action_value}\""
449
+ end
450
+ pkgs.each do | pkg |
451
+ pkgfiles << pkg[:metadata][:filename]
452
+ end
453
+
454
+ files = tpkg.files_for_installed_packages(pkgfiles)
455
+ files.each do |pkgfile, fip|
456
+ puts "#{pkgfile}:"
457
+ fip[:normalized].each { |file| puts file }
458
+ end
459
+ end
460
+ when :query_who_owns_file
461
+ tpkg = instantiate_tpkg(@tpkg_options)
462
+ tpkg.files_for_installed_packages.each do |pkgfile, fip|
463
+ fip[:normalized].each do |file|
464
+ if file == @action_value
465
+ puts "#{file}: #{pkgfile}"
466
+ end
467
+ end
468
+ end
469
+ when :query_available
470
+ tpkg = instantiate_tpkg(@tpkg_options)
471
+ req = nil
472
+ if @action_value
473
+ req = Tpkg::parse_request(@action_value)
474
+ end
475
+ tpkg.available_packages_that_meet_requirement(req).each do |pkg|
476
+ next if pkg[:source] == :native_installed
477
+ next if pkg[:source] == :native_available
478
+ puts "#{pkg[:metadata][:filename]} (#{pkg[:source]})"
479
+ end
480
+ when :query_requires
481
+ tpkg = instantiate_tpkg(@tpkg_options)
482
+
483
+ # parse the request
484
+ requirements = []
485
+ packages = {}
486
+ tpkg.parse_requests([@action_value], requirements, packages)
487
+
488
+ # get dependencies of all installed packages
489
+ dependencies = {}
490
+ tpkg.metadata_for_installed_packages.each do |metadata|
491
+ dependencies[metadata[:filename]] = metadata[:dependencies]
492
+ end
493
+
494
+ # check to see if the any required dependencies match with what the
495
+ # user specified in the request
496
+ packages.each do |name, pkgs|
497
+ pkgs.each do |pkg|
498
+ next if pkg[:source] != :currently_installed
499
+ puts "The following package(s) require #{pkg[:metadata][:filename]}:"
500
+ dependencies.each do | requiree, deps |
501
+ deps.each do | dep |
502
+ if Tpkg::package_meets_requirement?(pkg, dep)
503
+ puts " #{requiree}"
504
+ end
505
+ end
506
+ end
507
+ end
508
+ end
509
+ when :query_local_depends
510
+ tpkg = instantiate_tpkg(@tpkg_options)
511
+ req = Tpkg::parse_request(@action_value)
512
+ pkgs = tpkg.installed_packages_that_meet_requirement(req)
513
+ pkgs.each do | pkg |
514
+ puts pkg[:metadata][:filename] + ':'
515
+ if pkg[:metadata][:dependencies]
516
+ pkg[:metadata][:dependencies].each do |req|
517
+ puts " Requires #{req[:name]}"
518
+ req.each do |field, value|
519
+ next if field == :name
520
+ puts " #{field}: #{value}"
521
+ end
522
+ end
523
+ end
524
+ end
525
+ when :query_depends
526
+ tpkg = instantiate_tpkg(@tpkg_options)
527
+ requirements = []
528
+ packages = {}
529
+ tpkg.parse_requests([@action_value], requirements, packages)
530
+ packages.each do |name, pkgs|
531
+ already_displayed = {}
532
+ pkgs.each do |pkg|
533
+ # parse_requests returns both installed and available packages.
534
+ # The same package may show up in both, skip any duplicates.
535
+ next if already_displayed[pkg[:filename]]
536
+ already_displayed[pkg[:metadata][:filename]] = true
537
+ puts pkg[:metadata][:filename] + ':'
538
+ if pkg[:metadata][:dependencies]
539
+ pkg[:metadata][:dependencies].each do |req|
540
+ puts " Requires #{req[:name]}"
541
+ req.each do |field, value|
542
+ next if field == :name
543
+ puts " #{field}: #{value}"
544
+ end
545
+ end
546
+ end
547
+ end
548
+ end
549
+ when :query_tpkgxml
550
+ tpkg = instantiate_tpkg(@tpkg_options)
551
+ if !File.exist?(@action_value)
552
+ puts "File #{@action_value} doesn't exist."
553
+ else
554
+ puts Tpkg::extract_tpkgxml(@action_value)
555
+ end
556
+ when :query_env
557
+ puts "Operating System: #{Tpkg::get_os}"
558
+ puts "Architecture: #{Tpkg::get_arch}"
559
+ end
560
+ exit ret_val