tpkg 1.16.2 → 1.18.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +2 -2
- data/bin/cpan2tpkg +82 -14
- data/bin/tpkg +54 -29
- data/bin/tpkg_xml_to_yml +19 -0
- data/lib/tpkg.rb +225 -145
- data/lib/tpkg/metadata.rb +37 -20
- metadata +7 -5
data/Rakefile
CHANGED
@@ -4,7 +4,7 @@ spec = Gem::Specification.new do |s|
|
|
4
4
|
s.summary = 'tpkg Application Packaging & Deployment'
|
5
5
|
s.add_dependency('facter')
|
6
6
|
s.add_dependency('net-ssh')
|
7
|
-
s.version = '1.
|
7
|
+
s.version = '1.18.2'
|
8
8
|
s.authors = ['Darren Dao', 'Jason Heiss']
|
9
9
|
s.email = 'tpkg-users@lists.sourceforge.net'
|
10
10
|
s.homepage = 'http://tpkg.sourceforge.net'
|
@@ -12,7 +12,7 @@ spec = Gem::Specification.new do |s|
|
|
12
12
|
s.platform = Gem::Platform::RUBY
|
13
13
|
s.required_ruby_version = '>=1.8'
|
14
14
|
s.files = Dir['**/**']
|
15
|
-
s.executables = [ 'tpkg', 'cpan2tpkg', 'gem2tpkg' ]
|
15
|
+
s.executables = [ 'tpkg', 'cpan2tpkg', 'gem2tpkg', 'tpkg_xml_to_yml' ]
|
16
16
|
end
|
17
17
|
Rake::GemPackageTask.new(spec).define
|
18
18
|
|
data/bin/cpan2tpkg
CHANGED
@@ -36,7 +36,6 @@ All options can be shortened to anything that's unique.
|
|
36
36
|
EOF
|
37
37
|
}
|
38
38
|
|
39
|
-
# FIXME: we're not actually using $modver, we're just letting CPAN installed the latest available version
|
40
39
|
my $modver;
|
41
40
|
my $pkgver = 1;
|
42
41
|
my %extradeps = ();
|
@@ -58,6 +57,13 @@ usage() if (!$getopt);
|
|
58
57
|
usage() if ($help);
|
59
58
|
usage() if (!$module);
|
60
59
|
|
60
|
+
# FIXME: we're not actually using $modver, we're just letting CPAN install
|
61
|
+
# the latest available version
|
62
|
+
if ($modver)
|
63
|
+
{
|
64
|
+
die "--version not implemented\n";
|
65
|
+
}
|
66
|
+
|
61
67
|
my @extradepsopts = split(/,/, $extradepsopts);
|
62
68
|
while (scalar @extradepsopts)
|
63
69
|
{
|
@@ -161,16 +167,51 @@ print "Installed modules to be packaged (except Perl):\n";
|
|
161
167
|
print join(', ', $extinst->modules), "\n";
|
162
168
|
|
163
169
|
# Inspect temp directory and package each installed module
|
164
|
-
foreach my $name ($extinst->modules)
|
170
|
+
MODULE: foreach my $name ($extinst->modules)
|
165
171
|
{
|
166
|
-
next if ($name eq 'Perl');
|
172
|
+
next MODULE if ($name eq 'Perl');
|
167
173
|
print "Packaging $name\n";
|
168
|
-
my $dashname = $name;
|
169
|
-
$dashname =~ s/::/-/g;
|
170
|
-
my $ver = $extinst->version($name);
|
171
|
-
print "Module version is $ver\n";
|
172
174
|
my %deps = ();
|
173
175
|
my $mod = CPAN::Shell->expand('Module', $name);
|
176
|
+
# Sometimes calling expand on a result from EU::I->modules doesn't
|
177
|
+
# work. For example, if the user requests Date::Parse that module
|
178
|
+
# is part of the TimeDate distribution. EU::I->modules will return
|
179
|
+
# ['Perl', 'TimeDate'], but calling expand on TimeDate fails. It
|
180
|
+
# seems like we should find an alternative to EU::I->modules,
|
181
|
+
# something that returns the distributions installed rather than the
|
182
|
+
# modules.
|
183
|
+
if (!$mod)
|
184
|
+
{
|
185
|
+
# If EU::I->modules only returned two results we can safely
|
186
|
+
# assume the !Perl one is whatever the user asked to have
|
187
|
+
# installed and use its expansion instead. Continue the example
|
188
|
+
# mentioned above, calling expand on TimeDate fails but calling
|
189
|
+
# expand on Date::Parse works, for whatever reason.
|
190
|
+
if (scalar($extinst->modules) == 2)
|
191
|
+
{
|
192
|
+
# We've already called expand on the user's request, so we
|
193
|
+
# can reuse that result.
|
194
|
+
$mod = $modobj;
|
195
|
+
warn "Failed to expand $name the usual way, secondary efforts ",
|
196
|
+
"successful\n";
|
197
|
+
}
|
198
|
+
else
|
199
|
+
{
|
200
|
+
warn "Failed to expand $name, secondary efforts failed, skipping\n";
|
201
|
+
next MODULE;
|
202
|
+
}
|
203
|
+
}
|
204
|
+
# Note that this won't work if we ever implement letting the user
|
205
|
+
# select a specific version (via the --version CLI option), as
|
206
|
+
# expand presumably returns the info for the latest available
|
207
|
+
# version of the distribution. Note that EU::I->version returns the
|
208
|
+
# version of the module, not the version of the distribution, and
|
209
|
+
# those can differ. We're packaging the distribution, which may
|
210
|
+
# include multiple modules with their own, differing versions.
|
211
|
+
my $ver = module_to_dist_ver($mod);
|
212
|
+
print "Module version is $ver\n";
|
213
|
+
my $pkgname = module_to_pkg_name($mod);
|
214
|
+
print "Package name, based on distribution, is $pkgname\n";
|
174
215
|
# Looks like newer versions of CPAN.pm have a CPAN::Module::distribution()
|
175
216
|
# method. What I'm using here is a little hacky but works, so I
|
176
217
|
# don't think it is worth forcing users to use a newer version.
|
@@ -199,7 +240,7 @@ foreach my $name ($extinst->modules)
|
|
199
240
|
%prereqs = ();
|
200
241
|
}
|
201
242
|
}
|
202
|
-
foreach my $dep (keys %prereqs)
|
243
|
+
PREREQ: foreach my $dep (keys %prereqs)
|
203
244
|
{
|
204
245
|
# Skip dependencies on core modules
|
205
246
|
my $depmod = CPAN::Shell->expand('Module', $dep);
|
@@ -213,15 +254,14 @@ foreach my $name ($extinst->modules)
|
|
213
254
|
if ($depmod->inst_file =~ m,/home/t/perl,)
|
214
255
|
{
|
215
256
|
print "Prereq $dep is a core module, skipping\n";
|
216
|
-
next;
|
257
|
+
next PREREQ;
|
217
258
|
}
|
218
259
|
|
219
|
-
my $
|
220
|
-
$
|
221
|
-
$deps{$dashdep} = {};
|
260
|
+
my $deppkgname = module_to_pkg_name($depmod);
|
261
|
+
$deps{$deppkgname} = {};
|
222
262
|
if ($prereqs{$dep} ne '0')
|
223
263
|
{
|
224
|
-
$deps{$
|
264
|
+
$deps{$deppkgname}{minimum_version} = $prereqs{$dep};
|
225
265
|
}
|
226
266
|
}
|
227
267
|
}
|
@@ -248,7 +288,7 @@ foreach my $name ($extinst->modules)
|
|
248
288
|
print $xmlfh '<?xml version="1.0" encoding="UTF-8"?>', "\n";
|
249
289
|
print $xmlfh '<!DOCTYPE tpkg SYSTEM "http://tpkg.sourceforge.net/tpkg-1.0.dtd">', "\n";
|
250
290
|
print $xmlfh '<tpkg>', "\n";
|
251
|
-
print $xmlfh " <name>cpan-perl$majorminor-$
|
291
|
+
print $xmlfh " <name>cpan-perl$majorminor-$pkgname</name>", "\n";
|
252
292
|
print $xmlfh " <version>$ver</version>", "\n";
|
253
293
|
print $xmlfh " <package_version>$pkgver</package_version>", "\n";
|
254
294
|
print $xmlfh ' <maintainer>cpan2tpkg</maintainer>', "\n";
|
@@ -346,3 +386,31 @@ foreach my $name ($extinst->modules)
|
|
346
386
|
system("tpkg --make $tpkgdir");
|
347
387
|
}
|
348
388
|
|
389
|
+
# Pass in an expanded module (CPAN::Shell->expand), get back a name
|
390
|
+
# suitable for use in packaging.
|
391
|
+
# The package name is based on the distribution that contains the
|
392
|
+
# module, as sometimes multiple modules are packaged into a single
|
393
|
+
# distribution file.
|
394
|
+
sub module_to_pkg_name
|
395
|
+
{
|
396
|
+
my $mod = shift;
|
397
|
+
my $distfilename = basename($mod->{RO}{CPAN_FILE});
|
398
|
+
my $pkgname = $distfilename;
|
399
|
+
# Cut off the version and suffix
|
400
|
+
# I.e. TimeDate-1.20.tar.gz -> TimeDate
|
401
|
+
$pkgname =~ s/-\d.*//;
|
402
|
+
return $pkgname;
|
403
|
+
}
|
404
|
+
# Pass in an expanded module (CPAN::Shell->expand), get back the version
|
405
|
+
# of the associated distribution.
|
406
|
+
sub module_to_dist_ver
|
407
|
+
{
|
408
|
+
my $mod = shift;
|
409
|
+
my $distfilename = basename($mod->{RO}{CPAN_FILE});
|
410
|
+
# Cut off the distribution name and suffix
|
411
|
+
# I.e. TimeDate-1.20.tar.gz -> 1.20
|
412
|
+
$distfilename =~ /-(\d.*?)\.\D/;
|
413
|
+
my $distver = $1;
|
414
|
+
return $distver;
|
415
|
+
}
|
416
|
+
|
data/bin/tpkg
CHANGED
@@ -29,6 +29,7 @@ require 'tpkg'
|
|
29
29
|
@worker_count = 10
|
30
30
|
@rerun_with_sudo = false
|
31
31
|
@tpkg_options = {}
|
32
|
+
@init_options = {}
|
32
33
|
|
33
34
|
def rerun_with_sudo_if_necessary
|
34
35
|
if Process.euid != 0 && @sudo
|
@@ -97,39 +98,60 @@ opts.on('--verify', '-V', '=NAME', 'Verify packages') do |opt|
|
|
97
98
|
end
|
98
99
|
opts.on('--start', '=NAME', 'Start the init script for the specified package', Array) do |opt|
|
99
100
|
@rerun_with_sudo = true
|
100
|
-
@action = :
|
101
|
-
@
|
101
|
+
@action = :execute_init
|
102
|
+
@init_options[:packages] = opt
|
103
|
+
@init_options[:cmd] = 'start'
|
102
104
|
end
|
103
105
|
opts.on('--stop', '=NAME', 'Stop the init script for the specified package', Array) do |opt|
|
104
106
|
@rerun_with_sudo = true
|
105
|
-
@action = :
|
106
|
-
@
|
107
|
+
@action = :execute_init
|
108
|
+
@init_options[:packages] = opt
|
109
|
+
@init_options[:cmd] = 'stop'
|
107
110
|
end
|
108
111
|
opts.on('--restart', '=NAME', 'Restart the init script for the specified package', Array) do |opt|
|
109
112
|
@rerun_with_sudo = true
|
110
|
-
@action = :
|
111
|
-
@
|
113
|
+
@action = :execute_init
|
114
|
+
@init_options[:packages] = opt
|
115
|
+
@init_options[:cmd] = 'restart'
|
112
116
|
end
|
113
117
|
opts.on('--reload', '=NAME', 'Reload the init script for the specified package', Array) do |opt|
|
114
118
|
@rerun_with_sudo = true
|
115
|
-
@action = :
|
116
|
-
@
|
119
|
+
@action = :execute_init
|
120
|
+
@init_options[:packages] = opt
|
121
|
+
@init_options[:cmd] = 'reload'
|
117
122
|
end
|
118
123
|
opts.on('--start-all', 'Start the init scripts for all packages') do |opt|
|
119
124
|
@rerun_with_sudo = true
|
120
|
-
@action = :
|
125
|
+
@action = :execute_init
|
126
|
+
@init_options[:cmd] = 'start'
|
121
127
|
end
|
122
128
|
opts.on('--stop-all', 'Stop the init script for all packages') do |opt|
|
123
129
|
@rerun_with_sudo = true
|
124
|
-
@action = :
|
130
|
+
@action = :execute_init
|
131
|
+
@init_options[:cmd] = 'stop'
|
125
132
|
end
|
126
133
|
opts.on('--restart-all', 'Restart the init script for all packages') do |opt|
|
127
134
|
@rerun_with_sudo = true
|
128
|
-
@action = :
|
135
|
+
@action = :execute_init
|
136
|
+
@init_options[:cmd] = 'restart'
|
129
137
|
end
|
130
138
|
opts.on('--reload-all', 'Reload the init script for all packages') do |opt|
|
131
139
|
@rerun_with_sudo = true
|
132
|
-
@action = :
|
140
|
+
@action = :execute_init
|
141
|
+
@init_options[:cmd] = 'reload'
|
142
|
+
end
|
143
|
+
opts.on('--exec-init', '=NAME', 'Execute init scripts for the specified packages', Array) do |opt|
|
144
|
+
@rerun_with_sudo = true
|
145
|
+
@init_options[:packages] = opt
|
146
|
+
@action = :execute_init
|
147
|
+
end
|
148
|
+
opts.on('--init-script', '=NAME', 'What init scripts to execute', Array) do |opt|
|
149
|
+
@rerun_with_sudo = true
|
150
|
+
@init_options[:scripts] = opt
|
151
|
+
end
|
152
|
+
opts.on('--init-cmd', '=CMD', 'Invoke the specified init script command') do |opt|
|
153
|
+
@rerun_with_sudo = true
|
154
|
+
@init_options[:cmd] = opt
|
133
155
|
end
|
134
156
|
opts.on('--query', '-q', '=NAMES', 'List installed packages', Array) do |opt|
|
135
157
|
# People mistype -qa instead of --qa frequently
|
@@ -178,8 +200,8 @@ opts.on('--dw', '=INTEGER', 'Number of workers for deploying') do |opt|
|
|
178
200
|
@worker_count = opt.to_i
|
179
201
|
@deploy_params = @deploy_params - ['--dw', @worker_count, "--dw=#{opt}"]
|
180
202
|
end
|
181
|
-
opts.on('--qX', '=FILENAME', 'Display tpkg.xml of the given package') do |opt|
|
182
|
-
@action = :
|
203
|
+
opts.on('--qX', '=FILENAME', 'Display tpkg.xml or tpkg.yml of the given package') do |opt|
|
204
|
+
@action = :query_tpkg_metadata
|
183
205
|
@action_value = opt
|
184
206
|
end
|
185
207
|
opts.on('--qenv', "Display machine's information") do |opt|
|
@@ -360,18 +382,12 @@ when :verify
|
|
360
382
|
end
|
361
383
|
puts "Package verification failed" unless success
|
362
384
|
end
|
363
|
-
when :
|
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
|
385
|
+
when :execute_init
|
370
386
|
tpkg = instantiate_tpkg(@tpkg_options)
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
ret_val = tpkg.execute_init(@
|
387
|
+
if @init_options[:cmd].nil?
|
388
|
+
raise "You didn't specify what init command to run"
|
389
|
+
end
|
390
|
+
ret_val = tpkg.execute_init(@init_options)
|
375
391
|
when :query_installed
|
376
392
|
tpkg = instantiate_tpkg(@tpkg_options)
|
377
393
|
req = nil
|
@@ -418,6 +434,8 @@ when :query_info
|
|
418
434
|
next if already_displayed[metadata[:filename]]
|
419
435
|
already_displayed[metadata[:filename]] = true
|
420
436
|
[:name, :version, :package_version, :operatingsystem, :architecture, :maintainer, :description, :bugreporting].each do |field|
|
437
|
+
metadata[field] = 'any' if field == :operatingsystem && metadata[field].nil?
|
438
|
+
metadata[field] = 'any' if field == :architecture && metadata[field].nil?
|
421
439
|
if metadata[field]
|
422
440
|
if metadata[field].kind_of?(Array)
|
423
441
|
puts "#{field}: #{metadata[field].join(',')}"
|
@@ -426,6 +444,10 @@ when :query_info
|
|
426
444
|
end
|
427
445
|
end
|
428
446
|
end
|
447
|
+
if metadata[:dependencies]
|
448
|
+
puts "This package depends on other packages, use --qd/--qld to view the dependencies."
|
449
|
+
end
|
450
|
+
puts "================================================================================"
|
429
451
|
end
|
430
452
|
when :query_list_files
|
431
453
|
tpkg = instantiate_tpkg(@tpkg_options)
|
@@ -498,6 +520,7 @@ when :query_requires
|
|
498
520
|
next if pkg[:source] != :currently_installed
|
499
521
|
puts "The following package(s) require #{pkg[:metadata][:filename]}:"
|
500
522
|
dependencies.each do | requiree, deps |
|
523
|
+
next if deps.nil?
|
501
524
|
deps.each do | dep |
|
502
525
|
if Tpkg::package_meets_requirement?(pkg, dep)
|
503
526
|
puts " #{requiree}"
|
@@ -546,12 +569,14 @@ when :query_depends
|
|
546
569
|
end
|
547
570
|
end
|
548
571
|
end
|
549
|
-
when :
|
572
|
+
when :query_tpkg_metadata
|
550
573
|
tpkg = instantiate_tpkg(@tpkg_options)
|
551
|
-
if
|
552
|
-
puts
|
574
|
+
if File.exist?(@action_value)
|
575
|
+
puts Tpkg::extract_tpkg_metadata_file(@action_value)
|
576
|
+
elsif File.exists?(File.join(tpkg.installed_directory, @action_value))
|
577
|
+
puts Tpkg::extract_tpkg_metadata_file(File.join(tpkg.installed_directory, @action_value))
|
553
578
|
else
|
554
|
-
puts
|
579
|
+
puts "File #{@action_value} doesn't exist."
|
555
580
|
end
|
556
581
|
when :query_env
|
557
582
|
puts "Operating System: #{Tpkg::get_os}"
|
data/bin/tpkg_xml_to_yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
|
3
|
+
# This script expects one argument, which is the tpkg.xml file
|
4
|
+
# that you want to convert to yml format.
|
5
|
+
# The resulting data is output to stdout
|
6
|
+
require 'tpkg'
|
7
|
+
|
8
|
+
if ARGV.size < 1
|
9
|
+
raise "You didn't specify a file"
|
10
|
+
end
|
11
|
+
|
12
|
+
xmlfile = ARGV[0]
|
13
|
+
if !File.exist?(xmlfile)
|
14
|
+
raise "File doesn't exist"
|
15
|
+
end
|
16
|
+
|
17
|
+
metadata_text = File.read(xmlfile)
|
18
|
+
metadata = Metadata.new(metadata_text, 'xml')
|
19
|
+
metadata.write($stdout)
|
data/lib/tpkg.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
##############################################################################
|
2
2
|
# tpkg package management system library
|
3
|
-
# Copyright 2009, AT&T Interactive
|
3
|
+
# Copyright 2009, 2010 AT&T Interactive
|
4
4
|
# License: MIT (http://www.opensource.org/licenses/mit-license.php)
|
5
5
|
##############################################################################
|
6
6
|
|
@@ -48,7 +48,7 @@ require 'metadata'
|
|
48
48
|
|
49
49
|
class Tpkg
|
50
50
|
|
51
|
-
VERSION = '1.
|
51
|
+
VERSION = '1.18.2'
|
52
52
|
CONFIGDIR = '/etc'
|
53
53
|
|
54
54
|
POSTINSTALL_ERR = 2
|
@@ -241,8 +241,8 @@ class Tpkg
|
|
241
241
|
# by the package. For example, checksum, path, relocatable or not, etc.
|
242
242
|
File.open(File.join(tpkgdir, "file_metadata.bin"), "w") do |file|
|
243
243
|
filemetadata = get_filemetadata_from_directory(tpkgdir)
|
244
|
-
Marshal::dump(filemetadata.
|
245
|
-
# YAML::dump(filemetadata.
|
244
|
+
Marshal::dump(filemetadata.to_hash, file)
|
245
|
+
# YAML::dump(filemetadata.to_hash, file)
|
246
246
|
end
|
247
247
|
|
248
248
|
# Check all the files are there as specified in the metadata config file
|
@@ -510,7 +510,8 @@ class Tpkg
|
|
510
510
|
tpkg_xml = REXML::Document.new(pipe.read)
|
511
511
|
end
|
512
512
|
if !$?.success?
|
513
|
-
|
513
|
+
warn "Warning: Extracting tpkg.xml from #{package_file} failed"
|
514
|
+
return nil
|
514
515
|
end
|
515
516
|
|
516
517
|
# Insert an attribute on the root element with the package filename
|
@@ -543,7 +544,7 @@ class Tpkg
|
|
543
544
|
metadata << existing_metadata[File.basename(pkg)]
|
544
545
|
else
|
545
546
|
xml = xml_metadata_from_package(pkg)
|
546
|
-
metadata << xml.root
|
547
|
+
metadata << xml.root if xml
|
547
548
|
end
|
548
549
|
end
|
549
550
|
|
@@ -560,8 +561,13 @@ class Tpkg
|
|
560
561
|
existing_metadata = {}
|
561
562
|
|
562
563
|
if File.exists?(existing_metadata_file)
|
563
|
-
|
564
|
-
|
564
|
+
metadata_lists = File.read(File.join(directory, 'metadata.yml')).split("---")
|
565
|
+
metadata_lists.each do | metadata_text |
|
566
|
+
if metadata_text =~ /^:?filename:(.+)/
|
567
|
+
filename = $1.strip
|
568
|
+
existing_metadata[filename] = Metadata.new(metadata_text,'yml')
|
569
|
+
end
|
570
|
+
end
|
565
571
|
end
|
566
572
|
|
567
573
|
# Populate the metadata array with metadata for all of the packages
|
@@ -577,7 +583,7 @@ class Tpkg
|
|
577
583
|
|
578
584
|
return metadata
|
579
585
|
end
|
580
|
-
|
586
|
+
|
581
587
|
# Extracts the metadata from a directory of package files and saves it
|
582
588
|
# to metadata.xml in that directory
|
583
589
|
def self.extract_metadata(directory, dest=nil)
|
@@ -605,7 +611,7 @@ class Tpkg
|
|
605
611
|
# And write that out to metadata.yml
|
606
612
|
metadata_tmpfile = Tempfile.new('metadata.yml', dest)
|
607
613
|
metadata.each do | metadata |
|
608
|
-
YAML::dump(metadata.
|
614
|
+
YAML::dump(metadata.to_hash, metadata_tmpfile)
|
609
615
|
end
|
610
616
|
metadata_tmpfile.close
|
611
617
|
File.chmod(0644, metadata_tmpfile.path)
|
@@ -698,7 +704,9 @@ class Tpkg
|
|
698
704
|
# A req for a native package must be satisfied by a native package
|
699
705
|
puts "Package fails native requirement" if @@debug
|
700
706
|
result = false
|
701
|
-
elsif
|
707
|
+
elsif req[:filename]
|
708
|
+
result = false if req[:filename] != metadata[:filename]
|
709
|
+
elsif req[:type] == :tpkg &&
|
702
710
|
(pkg[:source] == :native_installed || pkg[:source] == :native_available)
|
703
711
|
# Likewise a req for a tpkg must be satisfied by a tpkg
|
704
712
|
puts "Package fails non-native requirement" if @@debug
|
@@ -771,6 +779,9 @@ class Tpkg
|
|
771
779
|
puts "Package fails name" if @@debug
|
772
780
|
result = false
|
773
781
|
end
|
782
|
+
if result
|
783
|
+
puts "Package matches" if @@debug
|
784
|
+
end
|
774
785
|
result
|
775
786
|
end
|
776
787
|
|
@@ -963,18 +974,11 @@ class Tpkg
|
|
963
974
|
req = {}
|
964
975
|
parts = request.split('=')
|
965
976
|
|
966
|
-
# upgrade/remove/query options
|
967
|
-
#
|
968
|
-
#
|
969
|
-
if
|
970
|
-
|
971
|
-
req[:name] = metadata[:name]
|
972
|
-
req[:minimum_version] = metadata[:version].to_s
|
973
|
-
req[:maximum_version] = metadata[:version].to_s
|
974
|
-
if metadata[:package_version] && !metadata[:package_version].to_s.empty?
|
975
|
-
req[:minimum_package_version] = metadata[:package_version].to_s
|
976
|
-
req[:maximum_package_version] = metadata[:package_version].to_s
|
977
|
-
end
|
977
|
+
# upgrade/remove/query options could take package filenames
|
978
|
+
# assuming that the filename is of the correct format, such as
|
979
|
+
# foo-1.0.tpkg or foo-1.0-1.tpkg
|
980
|
+
if request =~ /\.tpkg$/
|
981
|
+
req = {:filename => request, :name => request.split("-")[0]}
|
978
982
|
elsif parts.length > 2 && parts[-2] =~ /^[\d\.]/ && parts[-1] =~ /^[\d\.]/
|
979
983
|
package_version = parts.pop
|
980
984
|
version = parts.pop
|
@@ -991,6 +995,7 @@ class Tpkg
|
|
991
995
|
else
|
992
996
|
req[:name] = parts.join('-')
|
993
997
|
end
|
998
|
+
req[:type] = :tpkg
|
994
999
|
req
|
995
1000
|
end
|
996
1001
|
|
@@ -1032,21 +1037,22 @@ class Tpkg
|
|
1032
1037
|
end
|
1033
1038
|
end
|
1034
1039
|
|
1035
|
-
def self.
|
1040
|
+
def self.extract_tpkg_metadata_file(package_file)
|
1036
1041
|
result = ""
|
1037
1042
|
workdir = ""
|
1038
1043
|
begin
|
1039
1044
|
topleveldir = Tpkg::package_toplevel_directory(package_file)
|
1040
1045
|
workdir = Tpkg::tempdir(topleveldir)
|
1041
1046
|
system("#{find_tar} -xf #{package_file} -O #{File.join(topleveldir, 'tpkg.tar')} | #{find_tar} -C #{workdir} -xpf -")
|
1042
|
-
|
1043
|
-
if
|
1044
|
-
|
1047
|
+
|
1048
|
+
if File.exist?(File.join(workdir,"tpkg", "tpkg.yml"))
|
1049
|
+
metadata_file = File.join(workdir,"tpkg", "tpkg.yml")
|
1050
|
+
elsif File.exist?(File.join(workdir,"tpkg", "tpkg.xml"))
|
1051
|
+
metadata_file = File.join(workdir,"tpkg", "tpkg.xml")
|
1045
1052
|
else
|
1046
|
-
|
1047
|
-
result = f.read
|
1048
|
-
end
|
1053
|
+
raise "#{package_file} does not contain metadata configuration file."
|
1049
1054
|
end
|
1055
|
+
result = File.read(metadata_file)
|
1050
1056
|
rescue
|
1051
1057
|
puts "Failed to extract package."
|
1052
1058
|
ensure
|
@@ -1275,13 +1281,12 @@ class Tpkg
|
|
1275
1281
|
if @@debug
|
1276
1282
|
@sources.each do |source|
|
1277
1283
|
count = metadata.inject(0) do |memo,m|
|
1278
|
-
# metadata is a hash of pkgname => array of
|
1279
|
-
#
|
1284
|
+
# metadata is a hash of pkgname => array of Metadata
|
1285
|
+
# objects.
|
1280
1286
|
# Thus m is a 2 element array of [pkgname, array of
|
1281
|
-
#
|
1282
|
-
#
|
1283
|
-
|
1284
|
-
memo + m[1].select{|mh| mh[:source] == source}.length
|
1287
|
+
# Metadata objects] And thus m[1] is the array of
|
1288
|
+
# Metadata objects.
|
1289
|
+
memo + m[1].select{|mo| mo.source == source}.length
|
1285
1290
|
end
|
1286
1291
|
puts "Found #{count} packages from #{source}"
|
1287
1292
|
end
|
@@ -1346,34 +1351,35 @@ class Tpkg
|
|
1346
1351
|
{:arg => 'available', :header => 'Available', :source => :native_available} ].each do |yum|
|
1347
1352
|
puts "available_native_packages running 'yum list #{yum[:arg]} #{pkgname}'" if @@debug
|
1348
1353
|
stderr_first_line = nil
|
1349
|
-
Open3.popen3("yum
|
1354
|
+
Open3.popen3("yum info #{yum[:arg]} #{pkgname}") do |stdin, stdout, stderr|
|
1350
1355
|
stdin.close
|
1351
1356
|
read_packages = false
|
1357
|
+
name = version = package_version = nil
|
1352
1358
|
stdout.each_line do |line|
|
1353
1359
|
if line =~ /#{yum[:header]} Packages/
|
1354
1360
|
# Skip the header lines until we get to this line
|
1355
1361
|
read_packages = true
|
1356
1362
|
elsif read_packages
|
1357
|
-
|
1363
|
+
if line =~ /^Name\s*:\s*(.+)/
|
1364
|
+
name = $1.strip
|
1365
|
+
elsif line =~ /^Arch\s*:\s*(.+)/
|
1366
|
+
arch = $1.strip
|
1367
|
+
elsif line =~ /^Version\s*:\s*(.+)/
|
1368
|
+
version = $1.strip.to_s
|
1369
|
+
elsif line =~ /^Release\s*:\s*(.+)/
|
1370
|
+
package_version = $1.strip.to_s
|
1371
|
+
elsif line =~ /^Repo\s*:\s*(.+)/
|
1372
|
+
repo = $1.strip
|
1373
|
+
elsif line =~ /^\s*$/
|
1374
|
+
pkg = pkg_for_native_package(name, version, package_version, yum[:source])
|
1375
|
+
native_packages << pkg
|
1376
|
+
name = version = package_version = nil
|
1377
|
+
end
|
1358
1378
|
# In the end we ignore the architecture. Anything that
|
1359
1379
|
# shows up in yum should be installable on this box, and
|
1360
1380
|
# the chance of a mismatch between facter's idea of the
|
1361
1381
|
# architecture and RPM's idea is high. I.e. i386 vs i686
|
1362
1382
|
# or i32e vs x86_64 or whatever.
|
1363
|
-
name, arch = name_and_arch.split('.')
|
1364
|
-
# This is prone to error, as both the version and release
|
1365
|
-
# (what we call package version) could contain '-', so
|
1366
|
-
# there's no reliable way to parse the combined value.
|
1367
|
-
# RPM can show them separately, but seemingly not yum.
|
1368
|
-
# We could use rpm to list installed packages, but we
|
1369
|
-
# have to use yum to get available packages so we're
|
1370
|
-
# stuck with the problem.
|
1371
|
-
verparts = ver_and_release.split('-')
|
1372
|
-
package_version = verparts.pop
|
1373
|
-
version = verparts.join('-')
|
1374
|
-
# Create the pkg structure
|
1375
|
-
pkg = pkg_for_native_package(name, version, package_version, yum[:source])
|
1376
|
-
native_packages << pkg
|
1377
1383
|
end
|
1378
1384
|
end
|
1379
1385
|
stderr_first_line = stderr.gets
|
@@ -1629,7 +1635,7 @@ class Tpkg
|
|
1629
1635
|
begin
|
1630
1636
|
FileUtils.mkdir_p(package_metadata_dir)
|
1631
1637
|
File.open(metadata_file, "w") do |file|
|
1632
|
-
YAML::dump(m.
|
1638
|
+
YAML::dump(m.to_hash, file)
|
1633
1639
|
end
|
1634
1640
|
rescue Errno::EACCES
|
1635
1641
|
raise if Process.euid == 0
|
@@ -1778,18 +1784,21 @@ class Tpkg
|
|
1778
1784
|
files
|
1779
1785
|
end
|
1780
1786
|
|
1781
|
-
# Returns the best solution that meets the given requirements. Some
|
1782
|
-
#
|
1783
|
-
#
|
1784
|
-
#
|
1785
|
-
#
|
1786
|
-
#
|
1787
|
+
# Returns the best solution that meets the given requirements. Some or all
|
1788
|
+
# packages may be optionally pre-selected and specified via the packages
|
1789
|
+
# parameter, otherwise packages are picked from the set of available
|
1790
|
+
# packages. The requirements parameter is an array of package requirements.
|
1791
|
+
# The packages parameter is in the form of a hash with package names as keys
|
1792
|
+
# pointing to arrays of package specs (our standard hash of package metadata
|
1793
|
+
# and source). The core_packages parameter is an array of the names of
|
1794
|
+
# packages that should be considered core requirements, i.e. the user
|
1795
|
+
# specifically requested they be installed or upgraded. The return value
|
1787
1796
|
# will be an array of package specs.
|
1788
1797
|
MAX_POSSIBLE_SOLUTIONS_TO_CHECK = 10000
|
1789
1798
|
def best_solution(requirements, packages, core_packages)
|
1790
1799
|
# Dup objects passed to us so that resolve_dependencies is free to
|
1791
1800
|
# change them without potentially messing up our caller
|
1792
|
-
result = resolve_dependencies(requirements.dup, packages.dup, core_packages.dup)
|
1801
|
+
result = resolve_dependencies(requirements.dup, {:tpkg => packages.dup, :native => {}}, core_packages.dup)
|
1793
1802
|
if @@debug
|
1794
1803
|
if result[:solution]
|
1795
1804
|
puts "bestsol picks: #{result[:solution].inspect}" if @@debug
|
@@ -1801,21 +1810,30 @@ class Tpkg
|
|
1801
1810
|
end
|
1802
1811
|
|
1803
1812
|
# Recursive method used by best_solution
|
1813
|
+
# Parameters mostly map from best_solution, but packages turns into a hash
|
1814
|
+
# with two possible keys, :tpkg and :native. The value for the :tpkg key
|
1815
|
+
# would be the packages parameter from best_solution. Native packages are
|
1816
|
+
# only installed due to dependencies, we don't let the user request them
|
1817
|
+
# directly, so callers of best_solution never need to pass in a package list
|
1818
|
+
# for native packages. Separating the two sets of packages allows us to
|
1819
|
+
# calculate a solution that contains both a tpkg and a native package with
|
1820
|
+
# the same name. This may be necessary if different dependencies of the
|
1821
|
+
# core packages end up needing both.
|
1804
1822
|
def resolve_dependencies(requirements, packages, core_packages, number_of_possible_solutions_checked=0)
|
1805
1823
|
# Make sure we have populated package lists for all requirements.
|
1806
1824
|
# Filter the package lists against the requirements and
|
1807
1825
|
# ensure we can at least satisfy the initial requirements.
|
1808
1826
|
requirements.each do |req|
|
1809
|
-
if !packages[req[:name]]
|
1827
|
+
if !packages[req[:type]][req[:name]]
|
1810
1828
|
puts "resolvedeps initializing packages for #{req.inspect}" if @@debug
|
1811
|
-
packages[req[:name]] =
|
1829
|
+
packages[req[:type]][req[:name]] =
|
1812
1830
|
available_packages_that_meet_requirement(req)
|
1813
1831
|
else
|
1814
1832
|
# Loop over packages and eliminate ones that don't work for
|
1815
1833
|
# this requirement
|
1816
1834
|
puts "resolvedeps filtering packages for #{req.inspect}" if @@debug
|
1817
|
-
packages[req[:name]] =
|
1818
|
-
packages[req[:name]].select do |pkg|
|
1835
|
+
packages[req[:type]][req[:name]] =
|
1836
|
+
packages[req[:type]][req[:name]].select do |pkg|
|
1819
1837
|
# When this method is called recursively there might be a
|
1820
1838
|
# nil entry inserted into packages by the sorting code
|
1821
1839
|
# below. We need to skip those.
|
@@ -1824,7 +1842,7 @@ class Tpkg
|
|
1824
1842
|
end
|
1825
1843
|
end
|
1826
1844
|
end
|
1827
|
-
if packages[req[:name]].empty?
|
1845
|
+
if packages[req[:type]][req[:name]].empty?
|
1828
1846
|
if @@debug
|
1829
1847
|
puts "No packages matching #{req.inspect}"
|
1830
1848
|
end
|
@@ -1832,15 +1850,17 @@ class Tpkg
|
|
1832
1850
|
end
|
1833
1851
|
end
|
1834
1852
|
# Sort the packages
|
1835
|
-
|
1836
|
-
pkgs
|
1837
|
-
|
1838
|
-
|
1839
|
-
|
1840
|
-
|
1841
|
-
|
1842
|
-
|
1843
|
-
|
1853
|
+
[:tpkg, :native].each do |type|
|
1854
|
+
packages[type].each do |pkgname, pkgs|
|
1855
|
+
pkgs.sort!(&SORT_PACKAGES)
|
1856
|
+
# Only currently installed packages are allowed to score 0.
|
1857
|
+
# Anything else can score 1 at best. This ensures
|
1858
|
+
# that we prefer the solution which leaves the most
|
1859
|
+
# currently installed packages alone.
|
1860
|
+
if pkgs[0][:source] != :currently_installed &&
|
1861
|
+
pkgs[0][:source] != :native_installed
|
1862
|
+
pkgs.unshift(nil)
|
1863
|
+
end
|
1844
1864
|
end
|
1845
1865
|
end
|
1846
1866
|
|
@@ -1885,13 +1905,16 @@ class Tpkg
|
|
1885
1905
|
# [a2, b2, c2] (avg 2)
|
1886
1906
|
|
1887
1907
|
# Divide packages into core and non-core packages
|
1888
|
-
corepkgs = packages.reject{|pkgname, pkgs| !core_packages.include?(pkgname)}
|
1889
|
-
noncorepkgs =
|
1908
|
+
corepkgs = packages[:tpkg].reject{|pkgname, pkgs| !core_packages.include?(pkgname)}
|
1909
|
+
noncorepkgs = {}
|
1910
|
+
noncorepkgs[:tpkg] = packages[:tpkg].reject{|pkgname, pkgs| core_packages.include?(pkgname)}
|
1911
|
+
noncorepkgs[:native] = packages[:native]
|
1890
1912
|
|
1891
1913
|
# Calculate total package depth, the sum of the lengths (or rather
|
1892
1914
|
# the max array index) of each array of packages.
|
1893
1915
|
coretotaldepth = corepkgs.inject(0) {|memo, pkgs| memo + pkgs[1].length - 1}
|
1894
|
-
noncoretotaldepth = noncorepkgs.inject(0) {|memo, pkgs| memo + pkgs[1].length - 1}
|
1916
|
+
noncoretotaldepth = noncorepkgs[:tpkg].inject(0) {|memo, pkgs| memo + pkgs[1].length - 1} +
|
1917
|
+
noncorepkgs[:native].inject(0) {|memo, pkgs| memo + pkgs[1].length - 1}
|
1895
1918
|
if @@debug
|
1896
1919
|
puts "resolvedeps coretotaldepth #{coretotaldepth}"
|
1897
1920
|
puts "resolvedeps noncoretotaldepth #{noncoretotaldepth}"
|
@@ -1935,7 +1958,7 @@ class Tpkg
|
|
1935
1958
|
# {:pkgs=>{a1,b0}, :remaining_coredepth=0}
|
1936
1959
|
if coresol[:remaining_coredepth] == 0
|
1937
1960
|
# Second pass, add combinations of non-core packages
|
1938
|
-
if noncorepkgs.empty?
|
1961
|
+
if noncorepkgs[:tpkg].empty? && noncorepkgs[:native].empty?
|
1939
1962
|
puts "resolvedeps noncorepkgs empty, checking solution" if @@debug
|
1940
1963
|
result = check_solution(coresol, requirements, packages, core_packages, number_of_possible_solutions_checked)
|
1941
1964
|
if result[:solution]
|
@@ -1948,45 +1971,47 @@ class Tpkg
|
|
1948
1971
|
puts "resolvedeps noncoredepth: #{noncoredepth}" if @@debug
|
1949
1972
|
coresol[:remaining_noncoredepth] = noncoredepth
|
1950
1973
|
solutions = [coresol]
|
1951
|
-
|
1952
|
-
|
1953
|
-
|
1954
|
-
|
1955
|
-
|
1956
|
-
|
1957
|
-
|
1958
|
-
|
1959
|
-
|
1960
|
-
|
1961
|
-
|
1962
|
-
|
1963
|
-
|
1964
|
-
|
1965
|
-
|
1966
|
-
|
1967
|
-
|
1968
|
-
|
1969
|
-
|
1970
|
-
|
1971
|
-
|
1972
|
-
|
1973
|
-
|
1974
|
-
|
1975
|
-
|
1976
|
-
|
1977
|
-
|
1978
|
-
|
1979
|
-
|
1980
|
-
|
1981
|
-
|
1982
|
-
|
1974
|
+
[:tpkg, :native].each do |nctype|
|
1975
|
+
noncorepkgs[nctype].each do |ncpkgname, ncpkgs|
|
1976
|
+
puts "resolvedeps noncorepkg #{nctype} #{ncpkgname}: #{ncpkgs.inspect}" if @@debug
|
1977
|
+
new_solutions = []
|
1978
|
+
solutions.each do |solution|
|
1979
|
+
remaining_noncoredepth = solution[:remaining_noncoredepth]
|
1980
|
+
puts "resolvedeps :remaining_noncoredepth: #{remaining_noncoredepth}" if @@debug
|
1981
|
+
(0..[remaining_noncoredepth, ncpkgs.length-1].min).each do |ncpkgdepth|
|
1982
|
+
puts "resolvedeps ncpkgdepth: #{ncpkgdepth}" if @@debug
|
1983
|
+
# We insert a nil entry in some situations (see the sort
|
1984
|
+
# step earlier), so skip nil entries in the pkgs array.
|
1985
|
+
if ncpkgs[ncpkgdepth] != nil
|
1986
|
+
sol = solution.dup
|
1987
|
+
# Hash#dup doesn't dup each key/value, so we need to
|
1988
|
+
# explicitly dup :pkgs so that each copy has an
|
1989
|
+
# independent array that we can modify.
|
1990
|
+
sol[:pkgs] = solution[:pkgs].dup
|
1991
|
+
sol[:remaining_noncoredepth] -= ncpkgdepth
|
1992
|
+
sol[:pkgs] << ncpkgs[ncpkgdepth]
|
1993
|
+
new_solutions << sol
|
1994
|
+
# If this is a complete combination of packages then
|
1995
|
+
# proceed to the next step
|
1996
|
+
puts "resolvedeps sol[:pkgs] #{sol[:pkgs].inspect}" if @@debug
|
1997
|
+
if sol[:pkgs].length == packages[:tpkg].length + packages[:native].length
|
1998
|
+
puts "resolvedeps complete pkg set: #{sol.inspect}" if @@debug
|
1999
|
+
# Solutions with remaining depth are duplicates of
|
2000
|
+
# solutions we already checked at lower depth levels
|
2001
|
+
if sol[:remaining_noncoredepth] == 0
|
2002
|
+
result = check_solution(sol, requirements, packages, core_packages, number_of_possible_solutions_checked)
|
2003
|
+
if result[:solution]
|
2004
|
+
return result
|
2005
|
+
else
|
2006
|
+
number_of_possible_solutions_checked = result[:number_of_possible_solutions_checked]
|
2007
|
+
end
|
1983
2008
|
end
|
1984
2009
|
end
|
1985
2010
|
end
|
1986
2011
|
end
|
1987
2012
|
end
|
2013
|
+
solutions = new_solutions
|
1988
2014
|
end
|
1989
|
-
solutions = new_solutions
|
1990
2015
|
end
|
1991
2016
|
end
|
1992
2017
|
end
|
@@ -2036,7 +2061,7 @@ class Tpkg
|
|
2036
2061
|
newreqs_that_need_packages = []
|
2037
2062
|
newreqs.each do |newreq|
|
2038
2063
|
puts "checksol checking newreq: #{newreq.inspect}" if @@debug
|
2039
|
-
if packages[newreq[:name]]
|
2064
|
+
if packages[newreq[:type]][newreq[:name]]
|
2040
2065
|
pkg = solution[:pkgs].find{|solpkg| solpkg[:metadata][:name] == newreq[:name]}
|
2041
2066
|
puts "checksol newreq pkg: #{pkg.inspect}" if @@debug
|
2042
2067
|
if Tpkg::package_meets_requirement?(pkg, newreq)
|
@@ -2171,7 +2196,13 @@ class Tpkg
|
|
2171
2196
|
Tpkg::get_os =~ /Solaris/
|
2172
2197
|
init_directory = File.join(@file_system_root, 'etc')
|
2173
2198
|
end
|
2174
|
-
|
2199
|
+
|
2200
|
+
# in case user specify levels in yaml as string/integer instead of array
|
2201
|
+
if !levels.kind_of?(Array)
|
2202
|
+
levels = levels.to_s.split(//)
|
2203
|
+
end
|
2204
|
+
|
2205
|
+
levels.each do |level|
|
2175
2206
|
links[File.join(init_directory, "rc#{level}.d", 'S' + start.to_s + File.basename(installed_path))] = installed_path
|
2176
2207
|
end
|
2177
2208
|
elsif Tpkg::get_os =~ /FreeBSD/
|
@@ -2260,12 +2291,22 @@ class Tpkg
|
|
2260
2291
|
end
|
2261
2292
|
case operation
|
2262
2293
|
when :install
|
2263
|
-
|
2264
|
-
|
2294
|
+
begin
|
2295
|
+
IO.popen("#{externalpath} '#{pkgfile}' install", 'w') do |pipe|
|
2296
|
+
pipe.write(data)
|
2297
|
+
end
|
2298
|
+
rescue => e
|
2299
|
+
# Tell the user which external and package were involved, otherwise
|
2300
|
+
# failures in externals are very hard to debug
|
2301
|
+
raise e.exception("External #{name} #{operation} for #{File.basename(pkgfile)}: " + e.message)
|
2265
2302
|
end
|
2266
2303
|
when :remove
|
2267
|
-
|
2268
|
-
|
2304
|
+
begin
|
2305
|
+
IO.popen("#{externalpath} '#{pkgfile}' remove", 'w') do |pipe|
|
2306
|
+
pipe.write(data)
|
2307
|
+
end
|
2308
|
+
rescue => e
|
2309
|
+
raise e.exception("External #{name} #{operation} for #{File.basename(pkgfile)}: " + e.message)
|
2269
2310
|
end
|
2270
2311
|
else
|
2271
2312
|
raise "Bug, unknown external operation #{operation}"
|
@@ -2718,7 +2759,7 @@ class Tpkg
|
|
2718
2759
|
end
|
2719
2760
|
|
2720
2761
|
file = File.open(File.join(package_metadata_dir, "file_metadata.bin"), "w")
|
2721
|
-
Marshal.dump(file_metadata.
|
2762
|
+
Marshal.dump(file_metadata.to_hash, file)
|
2722
2763
|
file.close
|
2723
2764
|
else
|
2724
2765
|
warn "Warning: package #{File.basename(package_file)} does not include file_metadata information."
|
@@ -2737,7 +2778,8 @@ class Tpkg
|
|
2737
2778
|
metadata_for_installed_packages.each do |metadata|
|
2738
2779
|
if !pkgname || pkgname == metadata[:name]
|
2739
2780
|
req = { :name => metadata[:name],
|
2740
|
-
:minimum_version => metadata[:version]
|
2781
|
+
:minimum_version => metadata[:version],
|
2782
|
+
:type => :tpkg }
|
2741
2783
|
if metadata[:package_version]
|
2742
2784
|
req[:minimum_package_version] = metadata[:package_version]
|
2743
2785
|
end
|
@@ -2756,7 +2798,7 @@ class Tpkg
|
|
2756
2798
|
version = installed_xml[:version]
|
2757
2799
|
# For each currently installed package we insert a requirement for
|
2758
2800
|
# at least that version of the package
|
2759
|
-
req = { :name => name, :minimum_version => version }
|
2801
|
+
req = { :name => name, :minimum_version => version, :type => :tpkg }
|
2760
2802
|
requirements << req
|
2761
2803
|
# Initialize the list of possible packages for this req
|
2762
2804
|
if !packages[name]
|
@@ -2782,6 +2824,7 @@ class Tpkg
|
|
2782
2824
|
|
2783
2825
|
requests.each do |request|
|
2784
2826
|
puts "parse_requests processing #{request.inspect}" if @@debug
|
2827
|
+
|
2785
2828
|
if request =~ /^[-\w=<>\d\.]+$/ && !File.file?(request) # basic package specs ('foo' or 'foo=1.0')
|
2786
2829
|
puts "parse_requests request looks like package spec" if @@debug
|
2787
2830
|
|
@@ -2816,6 +2859,7 @@ class Tpkg
|
|
2816
2859
|
FileUtils.rm_rf(localpath)
|
2817
2860
|
end
|
2818
2861
|
req[:name] = metadata[:name]
|
2862
|
+
req[:type] = :tpkg
|
2819
2863
|
pkg = { :metadata => metadata, :source => source }
|
2820
2864
|
|
2821
2865
|
newreqs << req
|
@@ -2824,7 +2868,7 @@ class Tpkg
|
|
2824
2868
|
packages[req[:name]] = [pkg]
|
2825
2869
|
end
|
2826
2870
|
end
|
2827
|
-
|
2871
|
+
|
2828
2872
|
requirements.concat(newreqs)
|
2829
2873
|
newreqs
|
2830
2874
|
end
|
@@ -2845,23 +2889,24 @@ class Tpkg
|
|
2845
2889
|
request_satisfied = false # whether or not this request can be satisfied
|
2846
2890
|
possible_errors = []
|
2847
2891
|
pkgs.each do |pkg|
|
2892
|
+
good_package = true
|
2848
2893
|
metadata = pkg[:metadata]
|
2849
|
-
req = { :name => metadata[:name] }
|
2894
|
+
req = { :name => metadata[:name], :type => :tpkg }
|
2850
2895
|
# Quick sanity check that the package can be installed on this machine.
|
2851
2896
|
if !Tpkg::package_meets_requirement?(pkg, req)
|
2852
2897
|
possible_errors << " Requested package #{metadata[:filename]} doesn't match this machine's OS or architecture"
|
2898
|
+
good_package = false
|
2853
2899
|
next
|
2854
2900
|
end
|
2855
2901
|
# a sanity check that there is at least one package
|
2856
2902
|
# available for each dependency of this package
|
2857
|
-
dep_satisfied = true
|
2858
2903
|
metadata[:dependencies].each do |depreq|
|
2859
2904
|
if available_packages_that_meet_requirement(depreq).empty? && !Tpkg::packages_meet_requirement?(packages.values.flatten, depreq)
|
2860
2905
|
possible_errors << " Requested package #{metadata[:filename]} depends on #{depreq.inspect}, no packages that satisfy that dependency are available"
|
2861
|
-
|
2906
|
+
good_package = false
|
2862
2907
|
end
|
2863
2908
|
end if metadata[:dependencies]
|
2864
|
-
request_satisfied = true if
|
2909
|
+
request_satisfied = true if good_package
|
2865
2910
|
end
|
2866
2911
|
if !request_satisfied
|
2867
2912
|
errors << ["Unable to find any packages which satisfy #{name}. Possible error(s):"]
|
@@ -2987,7 +3032,11 @@ class Tpkg
|
|
2987
3032
|
name = pkg[:metadata][:name]
|
2988
3033
|
version = pkg[:metadata][:version]
|
2989
3034
|
package_version = pkg[:metadata][:package_version]
|
2990
|
-
|
3035
|
+
pkgname = "#{name}-#{version}"
|
3036
|
+
if package_version
|
3037
|
+
pkgname << "-#{package_version}"
|
3038
|
+
end
|
3039
|
+
puts "Native #{pkgname}"
|
2991
3040
|
else
|
2992
3041
|
puts pkg[:metadata][:filename]
|
2993
3042
|
end
|
@@ -3008,13 +3057,20 @@ class Tpkg
|
|
3008
3057
|
parse_requests(requests, requirements, packages)
|
3009
3058
|
check_requests(packages)
|
3010
3059
|
core_packages = []
|
3011
|
-
currently_installed_requirements = []
|
3060
|
+
#currently_installed_requirements = []
|
3012
3061
|
requirements.each do |req|
|
3013
3062
|
core_packages << req[:name] if !core_packages.include?(req[:name])
|
3014
|
-
|
3015
|
-
|
3063
|
+
|
3064
|
+
# This was here to ensure that nothing went backwards. But I guess in the
|
3065
|
+
# install case (as opposed to upgrade) going backwards can't really happen,
|
3066
|
+
# we may just install an older version alongside a newer version, which is
|
3067
|
+
# perfectly fine.
|
3068
|
+
# currently_installed_requirements.concat(
|
3069
|
+
# requirements_for_currently_installed_package(req[:name]))
|
3016
3070
|
end
|
3017
|
-
requirements.concat(currently_installed_requirements).uniq!
|
3071
|
+
#requirements.concat(currently_installed_requirements).uniq!
|
3072
|
+
|
3073
|
+
|
3018
3074
|
|
3019
3075
|
puts "install calling best_solution" if @@debug
|
3020
3076
|
puts "install requirements: #{requirements.inspect}" if @@debug
|
@@ -3192,7 +3248,11 @@ class Tpkg
|
|
3192
3248
|
metadata_for_installed_packages.each do | metadata |
|
3193
3249
|
metadata[:dependencies].each do | dep |
|
3194
3250
|
if dep[:name] == req[:name]
|
3195
|
-
|
3251
|
+
# Package metadata is almost usable as-is as a req, just need to
|
3252
|
+
# set :type
|
3253
|
+
addreq = metadata.to_hash
|
3254
|
+
addreq[:type] = :tpkg
|
3255
|
+
additional_requirements << addreq
|
3196
3256
|
end
|
3197
3257
|
end if metadata[:dependencies]
|
3198
3258
|
end
|
@@ -3330,10 +3390,10 @@ class Tpkg
|
|
3330
3390
|
# If the old and new packages have overlapping externals flag them
|
3331
3391
|
# to be skipped so that the external isn't removed and then
|
3332
3392
|
# immediately re-added
|
3333
|
-
oldpkgs = installed_packages_that_meet_requirement({:name => pkg[:metadata][:name]})
|
3393
|
+
oldpkgs = installed_packages_that_meet_requirement({:name => pkg[:metadata][:name], :type => :tpkg})
|
3334
3394
|
externals_to_skip = []
|
3335
3395
|
pkg[:metadata][:externals].each do |external|
|
3336
|
-
if oldpkgs.all? {|oldpkg| oldpkg[:metadata][:externals].include?(external)}
|
3396
|
+
if oldpkgs.all? {|oldpkg| oldpkg[:metadata][:externals] && oldpkg[:metadata][:externals].include?(external)}
|
3337
3397
|
externals_to_skip << external
|
3338
3398
|
end
|
3339
3399
|
end if pkg[:metadata][:externals]
|
@@ -3416,7 +3476,7 @@ class Tpkg
|
|
3416
3476
|
# We ignore native dependencies because there is no way a removal
|
3417
3477
|
# can break a native dependency, we don't support removing native
|
3418
3478
|
# packages.
|
3419
|
-
if req[:type] != :native
|
3479
|
+
if req[:type] != :native
|
3420
3480
|
iptmr = installed_packages_that_meet_requirement(req)
|
3421
3481
|
if iptmr.all? { |pkg| pkg_files_to_remove.include?(pkg[:metadata][:filename]) }
|
3422
3482
|
non_removable_pkg_files |= iptmr.map{ |pkg| pkg[:metadata][:filename]}
|
@@ -3768,32 +3828,43 @@ class Tpkg
|
|
3768
3828
|
end
|
3769
3829
|
return results
|
3770
3830
|
end
|
3771
|
-
|
3772
|
-
def execute_init(
|
3831
|
+
|
3832
|
+
def execute_init(options, *moreoptions)
|
3773
3833
|
ret_val = 0
|
3774
3834
|
packages_to_execute_on = []
|
3775
|
-
if
|
3835
|
+
if options.is_a?(Hash)
|
3836
|
+
action = options[:cmd]
|
3837
|
+
requested_packages = options[:packages]
|
3838
|
+
requested_init_scripts = options[:scripts]
|
3839
|
+
else # for backward compatibility
|
3840
|
+
action = moreoptions[0]
|
3841
|
+
requested_packages = options
|
3842
|
+
end
|
3843
|
+
|
3844
|
+
# if user specified no packages, then assume all
|
3845
|
+
if requested_packages.nil?
|
3776
3846
|
packages_to_execute_on = installed_packages_that_meet_requirement(nil)
|
3777
3847
|
else
|
3778
|
-
|
3848
|
+
requested_packages.each do |request|
|
3779
3849
|
req = Tpkg::parse_request(request)
|
3780
3850
|
packages_to_execute_on.concat(installed_packages_that_meet_requirement(req))
|
3781
3851
|
end
|
3782
3852
|
end
|
3783
3853
|
|
3784
3854
|
packages_to_execute_on.each do |pkg|
|
3785
|
-
ret_val |= execute_init_for_package(pkg, action)
|
3855
|
+
ret_val |= execute_init_for_package(pkg, action, requested_init_scripts)
|
3786
3856
|
end
|
3787
3857
|
return ret_val
|
3788
3858
|
end
|
3789
|
-
|
3790
|
-
def execute_init_for_package(pkg, action)
|
3859
|
+
|
3860
|
+
def execute_init_for_package(pkg, action, requested_init_scripts = nil)
|
3791
3861
|
ret_val = 0
|
3792
|
-
init_scripts_metadata = init_scripts(pkg[:metadata])
|
3793
3862
|
|
3863
|
+
# Get init scripts metadata for the given package
|
3864
|
+
init_scripts_metadata = init_scripts(pkg[:metadata])
|
3794
3865
|
# warn if there's no init script and then return
|
3795
3866
|
if init_scripts_metadata.nil? || init_scripts_metadata.empty?
|
3796
|
-
warn "Warning: There is no init script for #{pkg[:metadata][:name]}"
|
3867
|
+
warn "Warning: There is no init script for #{pkg[:metadata][:name]}."
|
3797
3868
|
return 1
|
3798
3869
|
end
|
3799
3870
|
|
@@ -3805,9 +3876,18 @@ class Tpkg
|
|
3805
3876
|
init = {}
|
3806
3877
|
init[:path] = installed_path
|
3807
3878
|
init[:start] = init_info[:init][:start] || 0
|
3808
|
-
|
3879
|
+
|
3880
|
+
# if user requests specific init scripts, then only include those
|
3881
|
+
if requested_init_scripts.nil? or
|
3882
|
+
requested_init_scripts && requested_init_scripts.include?(File.basename(installed_path))
|
3883
|
+
init_scripts << init
|
3884
|
+
end
|
3809
3885
|
end
|
3810
3886
|
|
3887
|
+
if requested_init_scripts && init_scripts.empty?
|
3888
|
+
warn "Warning: There are no init scripts that satisfy your request: #{requested_init_scripts.inspect} for package #{pkg[:metadata][:name]}."
|
3889
|
+
end
|
3890
|
+
|
3811
3891
|
# Reverse order if doing stop.
|
3812
3892
|
if action == "stop"
|
3813
3893
|
ordered_init_scripts = init_scripts.sort{ |a,b| b[:start] <=> a[:start] }
|
@@ -3880,7 +3960,7 @@ class Tpkg
|
|
3880
3960
|
|
3881
3961
|
# TODO: update server side to accept yaml data
|
3882
3962
|
def send_update_to_server
|
3883
|
-
metadata = metadata_for_installed_packages.collect{|metadata| metadata.
|
3963
|
+
metadata = metadata_for_installed_packages.collect{|metadata| metadata.to_hash}
|
3884
3964
|
yml = YAML.dump(metadata)
|
3885
3965
|
begin
|
3886
3966
|
update_uri = URI.parse("#{@report_server}")
|
data/lib/tpkg/metadata.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'yaml'
|
2
|
+
require 'rexml/document'
|
2
3
|
|
3
4
|
module SymbolizeKeys
|
4
5
|
|
@@ -86,14 +87,14 @@ class Metadata
|
|
86
87
|
end
|
87
88
|
|
88
89
|
def [](key)
|
89
|
-
return
|
90
|
+
return to_hash[key]
|
90
91
|
end
|
91
92
|
|
92
93
|
def []=(key,value)
|
93
|
-
|
94
|
+
to_hash[key]=value
|
94
95
|
end
|
95
96
|
|
96
|
-
def
|
97
|
+
def to_hash
|
97
98
|
if @hash
|
98
99
|
return @hash
|
99
100
|
end
|
@@ -101,6 +102,18 @@ class Metadata
|
|
101
102
|
if @format == 'yml'
|
102
103
|
hash = YAML::load(@metadata_text)
|
103
104
|
@hash = hash.extend(SymbolizeKeys)
|
105
|
+
|
106
|
+
# We need this for backward compatibility. With xml, we specify
|
107
|
+
# native dependency as type: :native rather then native: true
|
108
|
+
@hash[:dependencies].each do | dep |
|
109
|
+
if !dep[:type]
|
110
|
+
if dep[:native]
|
111
|
+
dep[:type] = :native
|
112
|
+
else
|
113
|
+
dep[:type] = :tpkg
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end if @hash[:dependencies]
|
104
117
|
else
|
105
118
|
@hash = metadata_xml_to_hash
|
106
119
|
end
|
@@ -108,18 +121,18 @@ class Metadata
|
|
108
121
|
end
|
109
122
|
|
110
123
|
def write(file)
|
111
|
-
YAML::dump(
|
124
|
+
YAML::dump(to_hash, file)
|
112
125
|
end
|
113
126
|
|
114
127
|
def get_files_list
|
115
128
|
end
|
116
129
|
|
117
130
|
def generate_package_filename
|
118
|
-
name =
|
119
|
-
version =
|
131
|
+
name = to_hash[:name]
|
132
|
+
version = to_hash[:version]
|
120
133
|
packageversion = nil
|
121
|
-
if
|
122
|
-
packageversion =
|
134
|
+
if to_hash[:package_version] && !to_hash[:package_version].to_s.empty?
|
135
|
+
packageversion = to_hash[:package_version]
|
123
136
|
end
|
124
137
|
package_filename = "#{name}-#{version}"
|
125
138
|
if packageversion
|
@@ -127,11 +140,11 @@ class Metadata
|
|
127
140
|
end
|
128
141
|
|
129
142
|
|
130
|
-
if
|
131
|
-
if
|
132
|
-
package_filename << "-#{Metadata::clean_for_filename(
|
143
|
+
if to_hash[:operatingsystem] and !to_hash[:operatingsystem].empty?
|
144
|
+
if to_hash[:operatingsystem].length == 1
|
145
|
+
package_filename << "-#{Metadata::clean_for_filename(to_hash[:operatingsystem].first)}"
|
133
146
|
else
|
134
|
-
operatingsystems =
|
147
|
+
operatingsystems = to_hash[:operatingsystem].dup
|
135
148
|
# Genericize any equivalent operating systems
|
136
149
|
# FIXME: more generic handling of equivalent OSs is probably called for
|
137
150
|
operatingsystems.each do |os|
|
@@ -154,9 +167,9 @@ class Metadata
|
|
154
167
|
end
|
155
168
|
end
|
156
169
|
end
|
157
|
-
if
|
158
|
-
if
|
159
|
-
package_filename << "-#{Metadata::clean_for_filename(
|
170
|
+
if to_hash[:architecture] and !to_hash[:architecture].empty?
|
171
|
+
if to_hash[:architecture].length == 1
|
172
|
+
package_filename << "-#{Metadata::clean_for_filename(to_hash[:architecture].first)}"
|
160
173
|
else
|
161
174
|
package_filename << "-multiarch"
|
162
175
|
end
|
@@ -167,16 +180,16 @@ class Metadata
|
|
167
180
|
|
168
181
|
def verify_required_fields
|
169
182
|
REQUIRED_FIELDS.each do |reqfield|
|
170
|
-
if
|
183
|
+
if to_hash[reqfield].nil?
|
171
184
|
raise "Required field #{reqfield} not found"
|
172
|
-
elsif
|
185
|
+
elsif to_hash[reqfield].to_s.empty?
|
173
186
|
raise "Required field #{reqfield} is empty"
|
174
187
|
end
|
175
188
|
end
|
176
189
|
end
|
177
190
|
|
178
191
|
def metadata_xml_to_hash
|
179
|
-
# Don't do anything if metadata is from xml file
|
192
|
+
# Don't do anything if metadata is not from xml file
|
180
193
|
return if @format != "xml"
|
181
194
|
|
182
195
|
metadata_hash = {}
|
@@ -230,6 +243,8 @@ class Metadata
|
|
230
243
|
end
|
231
244
|
if depxml.elements['native']
|
232
245
|
dep[:type] = :native
|
246
|
+
else
|
247
|
+
dep[:type] = :tpkg
|
233
248
|
end
|
234
249
|
deps << dep
|
235
250
|
end
|
@@ -247,6 +262,8 @@ class Metadata
|
|
247
262
|
end
|
248
263
|
if conflictxml.elements['native']
|
249
264
|
conflict[:type] = :native
|
265
|
+
else
|
266
|
+
conflict[:type] = :tpkg
|
250
267
|
end
|
251
268
|
conflicts << conflict
|
252
269
|
end
|
@@ -387,13 +404,13 @@ class Metadata
|
|
387
404
|
end
|
388
405
|
|
389
406
|
class FileMetadata < Metadata
|
390
|
-
def
|
407
|
+
def to_hash
|
391
408
|
if @hash
|
392
409
|
return @hash
|
393
410
|
end
|
394
411
|
|
395
412
|
if @format == 'bin'
|
396
|
-
|
413
|
+
hash = Marshal::load(@metadata_text)
|
397
414
|
@hash = hash.extend(SymbolizeKeys)
|
398
415
|
elsif @format == 'yml'
|
399
416
|
hash = YAML::load(@metadata_text)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tpkg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.18.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Darren Dao
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date:
|
13
|
+
date: 2010-01-28 00:00:00 -08:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -39,18 +39,20 @@ executables:
|
|
39
39
|
- tpkg
|
40
40
|
- cpan2tpkg
|
41
41
|
- gem2tpkg
|
42
|
+
- tpkg_xml_to_yml
|
42
43
|
extensions: []
|
43
44
|
|
44
45
|
extra_rdoc_files: []
|
45
46
|
|
46
47
|
files:
|
47
48
|
- bin/cpan2tpkg
|
48
|
-
- bin/
|
49
|
+
- bin/tpkg_xml_to_yml
|
49
50
|
- bin/tpkg
|
51
|
+
- bin/gem2tpkg
|
52
|
+
- lib/tpkg/versiontype.rb
|
50
53
|
- lib/tpkg/deployer.rb
|
51
|
-
- lib/tpkg/metadata.rb
|
52
54
|
- lib/tpkg/thread_pool.rb
|
53
|
-
- lib/tpkg/
|
55
|
+
- lib/tpkg/metadata.rb
|
54
56
|
- lib/tpkg.rb
|
55
57
|
- Rakefile
|
56
58
|
has_rdoc: true
|