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 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.16.2'
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 $dashdep = $dep;
220
- $dashdep =~ s/::/-/g;
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{$dashdep}{minimum_version} = $prereqs{$dep};
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-$dashname</name>", "\n";
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 = :start_init
101
- @action_value = opt
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 = :stop_init
106
- @action_value = opt
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 = :restart_init
111
- @action_value = opt
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 = :reload_init
116
- @action_value = opt
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 = :start_init
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 = :stop_init
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 = :restart_init
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 = :reload_init
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 = :query_tpkgxml
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 :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
385
+ when :execute_init
370
386
  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")
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 :query_tpkgxml
572
+ when :query_tpkg_metadata
550
573
  tpkg = instantiate_tpkg(@tpkg_options)
551
- if !File.exist?(@action_value)
552
- puts "File #{@action_value} doesn't exist."
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 Tpkg::extract_tpkgxml(@action_value)
579
+ puts "File #{@action_value} doesn't exist."
555
580
  end
556
581
  when :query_env
557
582
  puts "Operating System: #{Tpkg::get_os}"
@@ -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.16.2'
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.hash, file)
245
- # YAML::dump(filemetadata.hash, file)
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
- raise "Extracting tpkg.xml from #{package_file} failed"
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
- metadata_contents = File.read(File.join(directory, 'metadata.yml'))
564
- Metadata::get_pkgs_metadata_from_yml_doc(metadata_contents, existing_metadata)
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.hash, metadata_tmpfile)
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 (!req[:type] || req[:type] == :tpkg) &&
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 should take package filenames
967
- # First, look inside installed dir to see if we can find the request package. This is to support
968
- # request that uses package filename rather than package name
969
- if installed_dir && File.exists?(File.join(installed_dir, request))
970
- metadata = Tpkg::metadata_from_package(File.join(installed_dir, request))
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.extract_tpkgxml(package_file)
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 !File.exist?(File.join(workdir,"tpkg", "tpkg.xml"))
1044
- raise "#{package_file} does not contain tpkg.xml"
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
- File.open(File.join(workdir,"tpkg", "tpkg.xml"), "r") do | f |
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 metadata
1279
- # hashes
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
- # metadata hashes] And thus m[1] is the array of
1282
- # metadata hashes. And metadata hashes are themselves
1283
- # a hash of XML metadata and source.
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 list #{yum[:arg]} #{pkgname}") do |stdin, stdout, stderr|
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
- name_and_arch, ver_and_release, repo = line.split
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.hash, file)
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
- # or all packages may be optionally pre-selected and specified via the
1783
- # packages parameter, otherwise packages are picked from the set of
1784
- # available packages. The packages parameter is in the form of a hash
1785
- # with package names as keys pointing to arrays of package specs (our
1786
- # standard hash of package metadata and source). The return value
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
- packages.each do |pkgname, pkgs|
1836
- pkgs.sort!(&SORT_PACKAGES)
1837
- # Only currently installed packages are allowed to score 0.
1838
- # Anything else can score 1 at best. This ensures
1839
- # that we prefer the solution which leaves the most
1840
- # currently installed packages alone.
1841
- if pkgs[0][:source] != :currently_installed &&
1842
- pkgs[0][:source] != :native_installed
1843
- pkgs.unshift(nil)
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 = packages.reject{|pkgname, pkgs| core_packages.include?(pkgname)}
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
- noncorepkgs.each do |ncpkgname, ncpkgs|
1952
- puts "resolvedeps noncorepkg #{ncpkgname}: #{ncpkgs.inspect}" if @@debug
1953
- new_solutions = []
1954
- solutions.each do |solution|
1955
- remaining_noncoredepth = solution[:remaining_noncoredepth]
1956
- puts "resolvedeps :remaining_noncoredepth: #{remaining_noncoredepth}" if @@debug
1957
- (0..[remaining_noncoredepth, ncpkgs.length-1].min).each do |ncpkgdepth|
1958
- puts "resolvedeps ncpkgdepth: #{ncpkgdepth}" if @@debug
1959
- # We insert a nil entry in some situations (see the sort
1960
- # step earlier), so skip nil entries in the pkgs array.
1961
- if ncpkgs[ncpkgdepth] != nil
1962
- sol = solution.dup
1963
- # Hash#dup doesn't dup each key/value, so we need to
1964
- # explicitly dup :pkgs so that each copy has an
1965
- # independent array that we can modify.
1966
- sol[:pkgs] = solution[:pkgs].dup
1967
- sol[:remaining_noncoredepth] -= ncpkgdepth
1968
- sol[:pkgs] << ncpkgs[ncpkgdepth]
1969
- new_solutions << sol
1970
- # If this is a complete combination of packages then
1971
- # proceed to the next step
1972
- puts "resolvedeps sol[:pkgs] #{sol[:pkgs].inspect}" if @@debug
1973
- if sol[:pkgs].length == packages.length
1974
- puts "resolvedeps complete pkg set: #{sol.inspect}" if @@debug
1975
- # Solutions with remaining depth are duplicates of
1976
- # solutions we already checked at lower depth levels
1977
- if sol[:remaining_noncoredepth] == 0
1978
- result = check_solution(sol, requirements, packages, core_packages, number_of_possible_solutions_checked)
1979
- if result[:solution]
1980
- return result
1981
- else
1982
- number_of_possible_solutions_checked = result[:number_of_possible_solutions_checked]
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
- levels.to_s.each do |level|
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
- IO.popen("#{externalpath} '#{pkgfile}' install", 'w') do |pipe|
2264
- pipe.write(data)
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
- IO.popen("#{externalpath} '#{pkgfile}' remove", 'w') do |pipe|
2268
- pipe.write(data)
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.hash, file)
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
- dep_satisfied = false
2906
+ good_package = false
2862
2907
  end
2863
2908
  end if metadata[:dependencies]
2864
- request_satisfied = true if dep_satisfied
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
- puts "Native #{name}=#{version}=#{package_version}"
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
- currently_installed_requirements.concat(
3015
- requirements_for_currently_installed_package(req[:name]))
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
- additional_requirements << metadata.hash
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 && req[:type] != :native_installed
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(requests, action)
3831
+
3832
+ def execute_init(options, *moreoptions)
3773
3833
  ret_val = 0
3774
3834
  packages_to_execute_on = []
3775
- if requests.nil?
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
- requests.each do |request|
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
- init_scripts << init
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.hash}
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 hash[key]
90
+ return to_hash[key]
90
91
  end
91
92
 
92
93
  def []=(key,value)
93
- hash[key]=value
94
+ to_hash[key]=value
94
95
  end
95
96
 
96
- def hash
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(hash, file)
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 = hash[:name]
119
- version = hash[:version]
131
+ name = to_hash[:name]
132
+ version = to_hash[:version]
120
133
  packageversion = nil
121
- if hash[:package_version] && !hash[:package_version].to_s.empty?
122
- packageversion = hash[:package_version]
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 hash[:operatingsystem] and !hash[:operatingsystem].empty?
131
- if hash[:operatingsystem].length == 1
132
- package_filename << "-#{Metadata::clean_for_filename(hash[:operatingsystem].first)}"
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 = hash[:operatingsystem].dup
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 hash[:architecture] and !hash[:architecture].empty?
158
- if hash[:architecture].length == 1
159
- package_filename << "-#{Metadata::clean_for_filename(hash[:architecture].first)}"
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 hash[reqfield].nil?
183
+ if to_hash[reqfield].nil?
171
184
  raise "Required field #{reqfield} not found"
172
- elsif hash[reqfield].to_s.empty?
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 hash
407
+ def to_hash
391
408
  if @hash
392
409
  return @hash
393
410
  end
394
411
 
395
412
  if @format == 'bin'
396
- @hash = Marshal::load(@metadata_text)
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.16.2
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: 2009-12-16 00:00:00 -08:00
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/gem2tpkg
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/versiontype.rb
55
+ - lib/tpkg/metadata.rb
54
56
  - lib/tpkg.rb
55
57
  - Rakefile
56
58
  has_rdoc: true