tpkg 1.16.2 → 1.18.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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