tpkg 1.18.2 → 1.19.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 +2 -1
- data/bin/cpan2tpkg +12 -1
- data/bin/gem2tpkg +89 -46
- data/bin/tpkg +5 -1
- data/bin/tpkg_xml_to_yml +3 -0
- data/lib/tpkg.rb +458 -241
- data/lib/tpkg/metadata.rb +253 -47
- data/schema/schema-1.0.yml +84 -0
- data/schema/schema.yml +84 -0
- data/schema/tpkg-1.0.0.dtd +34 -0
- data/schema/tpkg-1.0.1.dtd +35 -0
- data/schema/tpkg-1.0.2.dtd +39 -0
- data/schema/tpkg-1.0.3.dtd +40 -0
- data/schema/tpkg-1.0.4.dtd +40 -0
- data/schema/tpkg-1.0.5.dtd +41 -0
- data/schema/tpkg.dtd +41 -0
- metadata +21 -2
data/Rakefile
CHANGED
@@ -4,7 +4,8 @@ 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.
|
7
|
+
s.add_dependency('kwalify')
|
8
|
+
s.version = '1.19.2'
|
8
9
|
s.authors = ['Darren Dao', 'Jason Heiss']
|
9
10
|
s.email = 'tpkg-users@lists.sourceforge.net'
|
10
11
|
s.homepage = 'http://tpkg.sourceforge.net'
|
data/bin/cpan2tpkg
CHANGED
@@ -29,6 +29,8 @@ Usage: cpan2tpkg
|
|
29
29
|
Extra dependencies to add to the package
|
30
30
|
[--native-deps foo,1.0,1.9999,bar,4.5,4.5,blah,,,]
|
31
31
|
Native dependencies to add to the package
|
32
|
+
[--force]
|
33
|
+
Force the install and packaging even if tests fail
|
32
34
|
[--help]
|
33
35
|
Show this message
|
34
36
|
|
@@ -42,6 +44,7 @@ my %extradeps = ();
|
|
42
44
|
my $extradepsopts = '';
|
43
45
|
my %nativedeps = ();
|
44
46
|
my $nativedepsopts = '';
|
47
|
+
my $force;
|
45
48
|
my $help;
|
46
49
|
|
47
50
|
my $getopt = GetOptions(
|
@@ -49,6 +52,7 @@ my $getopt = GetOptions(
|
|
49
52
|
'package-version=s' => \$pkgver,
|
50
53
|
'extra-deps=s' => \$extradepsopts,
|
51
54
|
'native-deps=s' => \$nativedepsopts,
|
55
|
+
'force' => \$force,
|
52
56
|
'help' => \$help);
|
53
57
|
|
54
58
|
my $module = shift @ARGV;
|
@@ -131,7 +135,14 @@ CPAN::Shell->o('conf', 'mbuildpl_arg', "--destdir=$workdir");
|
|
131
135
|
#CPAN::Shell->o('conf', 'prerequisites_policy', "ask");
|
132
136
|
|
133
137
|
# Install the module
|
134
|
-
$
|
138
|
+
if ($force)
|
139
|
+
{
|
140
|
+
CPAN::Shell->force('install', $module);
|
141
|
+
}
|
142
|
+
else
|
143
|
+
{
|
144
|
+
$modobj->install;
|
145
|
+
}
|
135
146
|
|
136
147
|
# It is not nearly as straightforward as one might wish to get
|
137
148
|
# ExtUtils::Installed to inspect only a specified directory structure and not
|
data/bin/gem2tpkg
CHANGED
@@ -10,20 +10,9 @@ require 'shellwords'
|
|
10
10
|
require 'tpkg'
|
11
11
|
require 'facter'
|
12
12
|
|
13
|
-
#
|
14
|
-
#
|
15
|
-
|
16
|
-
RUBYDEPS = ['ruby']
|
17
|
-
# T_RUBY_BASE = "/home/t/ruby"
|
18
|
-
T_RUBY_BASE = "#{Tpkg::DEFAULT_BASE}/#{RUBYDEPS.first}".freeze
|
19
|
-
DEFAULT_GEM_COMMAND = "#{T_RUBY_BASE}/bin/gem"
|
20
|
-
|
21
|
-
# Figure out rubygems library from ruby.
|
22
|
-
# There might be several versions so get the latest one. We're assuming that
|
23
|
-
# the version directories are named appropriately under lib/ruby/site_ruby.
|
24
|
-
versions = Dir.glob(File.join("#{T_RUBY_BASE}", "lib", "ruby", "site_ruby", "*"))
|
25
|
-
versions.sort!
|
26
|
-
DEFAULT_RUBYGEMS_PATH = versions[-1]
|
13
|
+
# We don't want to just use the first gem command in the user's PATH by
|
14
|
+
# default, as that may not be a tpkg gem. I.e. /usr/bin/gem on Mac OS X.
|
15
|
+
DEFAULT_GEM_COMMAND = "#{Tpkg::DEFAULT_BASE}/ruby-1.8/bin/gem"
|
27
16
|
|
28
17
|
# Haven't found a Ruby method for creating temporary directories,
|
29
18
|
# so create a temporary file and replace it with a directory.
|
@@ -45,6 +34,7 @@ end
|
|
45
34
|
@buildopts = []
|
46
35
|
@gemcmd = DEFAULT_GEM_COMMAND
|
47
36
|
@rubygemspath = nil
|
37
|
+
@extrapkgname = nil
|
48
38
|
|
49
39
|
opts = OptionParser.new
|
50
40
|
opts.banner = 'Usage: gem2tpkg [options] GEMNAME1 GEMNAME2 ...'
|
@@ -92,33 +82,91 @@ end
|
|
92
82
|
opts.on('--rubygems-path', '=PATH', 'Path to rubygems library') do |opt|
|
93
83
|
@rubygemspath = opt
|
94
84
|
end
|
85
|
+
opts.on('--extra-name', '=EXTRANAME', 'Extra string to add to package name') do |opt|
|
86
|
+
@extrapkgname = opt
|
87
|
+
end
|
95
88
|
opts.on_tail("-h", "--help", "Show this message") do
|
96
89
|
puts opts
|
97
90
|
exit
|
98
91
|
end
|
99
92
|
|
100
|
-
#
|
93
|
+
# Allow user to specify multiple gems at the end of the command line
|
94
|
+
# arguments
|
101
95
|
leftover = opts.parse(ARGV)
|
102
96
|
@gems = leftover
|
103
|
-
#if leftover.length == 1
|
104
|
-
# @gem = leftover.shift
|
105
|
-
#else
|
106
|
-
# puts opts
|
107
|
-
# exit
|
108
|
-
#end
|
109
97
|
|
110
|
-
#
|
111
|
-
@
|
98
|
+
# Extract a few paths from gem
|
99
|
+
@geminstallpath = nil
|
100
|
+
@gembinpath = nil
|
101
|
+
@rubypath = nil
|
102
|
+
IO.popen("#{@gemcmd} environment") do |pipe|
|
103
|
+
pipe.each_line do |line|
|
104
|
+
if line =~ /INSTALLATION DIRECTORY:\s+(\S+)/
|
105
|
+
@geminstallpath = $1
|
106
|
+
end
|
107
|
+
if line =~ /EXECUTABLE DIRECTORY:\s+(\S+)/
|
108
|
+
@gembinpath = $1
|
109
|
+
end
|
110
|
+
if line =~ /RUBY EXECUTABLE:\s+(\S+)/
|
111
|
+
@rubypath = $1
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
if !$?.success?
|
116
|
+
abort 'gem environment failed'
|
117
|
+
end
|
118
|
+
|
119
|
+
# Find the right rubygems library if the user didn't request a specific
|
120
|
+
# one
|
121
|
+
if !@rubygemspath
|
122
|
+
cmd = "#{@rubypath} -e 'puts $:'"
|
123
|
+
IO.popen(cmd) do |pipe|
|
124
|
+
pipe.each_line do |line|
|
125
|
+
line.chomp!
|
126
|
+
if File.exist?(File.join(line, 'rubygems.rb'))
|
127
|
+
@rubygemspath = line
|
128
|
+
break
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
if !$?.success?
|
133
|
+
abort "#{cmd} failed"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Require the correct rubygems based on what the user specifies
|
112
138
|
$:.unshift @rubygemspath unless @rubygemspath.nil?
|
113
139
|
require 'rubygems'
|
114
140
|
|
141
|
+
# Ask tpkg what package owns the gem executable that we're using so that
|
142
|
+
# we can add a dependency on that package to any packages we build.
|
143
|
+
@gemdep = []
|
144
|
+
# FIXME: Currently the reading of config files and whatnot is done in
|
145
|
+
# the tpkg executable. We should probably move that into the library so
|
146
|
+
# that other utilities like this one use an alternate base if the user
|
147
|
+
# has configured one, etc.
|
148
|
+
tpkg = Tpkg.new(:base => Tpkg::DEFAULT_BASE)
|
149
|
+
tpkg.files_for_installed_packages.each do |pkgfile, fip|
|
150
|
+
fip[:normalized].each do |file|
|
151
|
+
if file == @gemcmd
|
152
|
+
metadata = nil
|
153
|
+
# FIXME: Should add a metadata_for_installed_package method to the
|
154
|
+
# library
|
155
|
+
tpkg.metadata_for_installed_packages.each do |metadata|
|
156
|
+
if metadata[:filename] == pkgfile
|
157
|
+
@gemdep << metadata[:name]
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
115
164
|
# Create the directory we want gem to install into
|
116
165
|
@gemdir = tempdir('gem2tpkg')
|
117
166
|
ENV['GEM_HOME'] = @gemdir
|
118
167
|
ENV['GEM_PATH'] = @gemdir
|
119
168
|
|
120
169
|
# Install the gem
|
121
|
-
#geminst = [@gemcmd, 'install', @gems.join(" "), '--no-rdoc', '--no-ri']
|
122
170
|
geminst = [@gemcmd, 'install', '--no-rdoc', '--no-ri'] | @gems
|
123
171
|
if @gemver
|
124
172
|
geminst << @gemver
|
@@ -147,7 +195,6 @@ def package(gem)
|
|
147
195
|
puts "Packaging #{gem}"
|
148
196
|
|
149
197
|
gemsdir = nil
|
150
|
-
#globdirs = Dir.glob(File.join(@gemdir, 'gems', "#{gem}-*"))
|
151
198
|
globdirs = Dir.glob(File.join(@gemdir, 'gems', "#{gem}-[0-9]*"))
|
152
199
|
if globdirs.length == 1
|
153
200
|
gemsdir = globdirs[0]
|
@@ -286,7 +333,7 @@ def package(gem)
|
|
286
333
|
|
287
334
|
# The directory where we make our package
|
288
335
|
pkgdir = tempdir('gem2tpkg')
|
289
|
-
pkgbasedir = File.join(pkgdir, "/root/#{
|
336
|
+
pkgbasedir = File.join(pkgdir, "/root/#{@geminstallpath}")
|
290
337
|
FileUtils.mkdir_p(pkgbasedir)
|
291
338
|
pkggemdir = File.join(pkgbasedir, 'gems')
|
292
339
|
FileUtils.mkdir_p(pkggemdir)
|
@@ -305,7 +352,7 @@ def package(gem)
|
|
305
352
|
binfiles << File.join(@gemdir, 'bin', exec)
|
306
353
|
end
|
307
354
|
if !binfiles.empty?
|
308
|
-
bindir = "#{pkgdir}/root/#{
|
355
|
+
bindir = "#{pkgdir}/root/#{@gembinpath}"
|
309
356
|
FileUtils.mkdir_p(bindir)
|
310
357
|
binfiles.each do |binfile|
|
311
358
|
FileUtils.cp(binfile, bindir, :preserve => true)
|
@@ -315,6 +362,15 @@ def package(gem)
|
|
315
362
|
# Copy over the gemspec file
|
316
363
|
FileUtils.cp(gemspecfile, pkgspecdir, :preserve => true)
|
317
364
|
|
365
|
+
pkgnamesuffix = ''
|
366
|
+
if @extrapkgname
|
367
|
+
pkgnamesuffix = '-' + @extrapkgname
|
368
|
+
elsif @gemcmd != DEFAULT_GEM_COMMAND
|
369
|
+
# If we're not using the default gem try to name the package in a way
|
370
|
+
# that indicates the alternate ruby/gem used
|
371
|
+
pkgnamesuffix = '-' + @gemdep.first.sub(/\W/, '')
|
372
|
+
end
|
373
|
+
|
318
374
|
# Add tpkg.xml
|
319
375
|
os = nil
|
320
376
|
arch = nil
|
@@ -322,7 +378,7 @@ def package(gem)
|
|
322
378
|
file.puts '<?xml version="1.0" encoding="UTF-8"?>'
|
323
379
|
file.puts '<!DOCTYPE tpkg SYSTEM "http://tpkg.sourceforge.net/tpkg-1.0.dtd">'
|
324
380
|
file.puts '<tpkg>'
|
325
|
-
file.puts " <name>gem-#{gem}</name>"
|
381
|
+
file.puts " <name>gem-#{gem}#{pkgnamesuffix}</name>"
|
326
382
|
file.puts " <version>#{gemspec.version.to_s}</version>"
|
327
383
|
file.puts " <package_version>#{@pkgver}</package_version>"
|
328
384
|
file.puts ' <maintainer>gem2tpkg</maintainer>'
|
@@ -341,11 +397,11 @@ def package(gem)
|
|
341
397
|
end
|
342
398
|
if !deps.empty? ||
|
343
399
|
!@extradeps.empty? || !@nativedeps.empty? ||
|
344
|
-
|
400
|
+
!@gemdep.empty?
|
345
401
|
file.puts ' <dependencies>'
|
346
402
|
deps.each do |depgem, depvers|
|
347
403
|
file.puts ' <dependency>'
|
348
|
-
file.puts " <name>gem-#{depgem}</name>"
|
404
|
+
file.puts " <name>gem-#{depgem}#{pkgnamesuffix}</name>"
|
349
405
|
if depvers[:minimum_version]
|
350
406
|
file.puts " <minimum_version>#{depvers[:minimum_version]}</minimum_version>"
|
351
407
|
end
|
@@ -377,9 +433,9 @@ def package(gem)
|
|
377
433
|
file.puts ' <native/>'
|
378
434
|
file.puts ' </dependency>'
|
379
435
|
end
|
380
|
-
|
436
|
+
@gemdep.each do |gemdep|
|
381
437
|
file.puts ' <dependency>'
|
382
|
-
file.puts " <name>#{
|
438
|
+
file.puts " <name>#{gemdep}</name>"
|
383
439
|
file.puts ' </dependency>'
|
384
440
|
end
|
385
441
|
file.puts ' </dependencies>'
|
@@ -389,24 +445,11 @@ def package(gem)
|
|
389
445
|
|
390
446
|
# Make package
|
391
447
|
pkgfile = Tpkg::make_package(pkgdir)
|
392
|
-
# If the package is OS-specific then rename the file to reflect that
|
393
|
-
if os
|
394
|
-
# Examples:
|
395
|
-
# FreeBSD-7 -> freebsd7
|
396
|
-
# RedHat-5 -> redhat5
|
397
|
-
# CentOS-5 -> redhat5
|
398
|
-
fileos = Tpkg::get_os.sub('CentOS', 'RedHat').downcase.sub('-', '')
|
399
|
-
newpkgfile = File.join(
|
400
|
-
File.dirname(pkgfile),
|
401
|
-
"#{File.basename(pkgfile, '.tpkg')}-#{fileos}-#{arch}.tpkg")
|
402
|
-
File.rename(pkgfile, newpkgfile)
|
403
|
-
pkgfile = newpkgfile
|
404
|
-
end
|
405
448
|
pkgfiles << pkgfile
|
406
449
|
|
407
450
|
# Cleanup
|
408
451
|
FileUtils.rm_rf(pkgdir)
|
409
|
-
|
452
|
+
|
410
453
|
@already_packaged << gem
|
411
454
|
pkgfiles
|
412
455
|
end
|
data/bin/tpkg
CHANGED
@@ -329,10 +329,14 @@ if @deploy
|
|
329
329
|
exit
|
330
330
|
end
|
331
331
|
|
332
|
+
if @action_value.is_a?(Array)
|
333
|
+
@action_value.uniq!
|
334
|
+
end
|
335
|
+
|
332
336
|
ret_val = 0
|
333
337
|
case @action
|
334
338
|
when :make
|
335
|
-
pkgfile = Tpkg::make_package(@action_value, passphrase_callback)
|
339
|
+
pkgfile = Tpkg::make_package(@action_value, passphrase_callback, {:force => @force})
|
336
340
|
if pkgfile
|
337
341
|
puts "Package is #{pkgfile}"
|
338
342
|
else
|
data/bin/tpkg_xml_to_yml
CHANGED
data/lib/tpkg.rb
CHANGED
@@ -21,6 +21,13 @@ if File.directory?(tpkglibdir)
|
|
21
21
|
$:.unshift(tpkglibdir)
|
22
22
|
end
|
23
23
|
|
24
|
+
# We store this gem in our thirdparty directory. So we need to add it
|
25
|
+
# it to the search path
|
26
|
+
# This one is for when everything is installed
|
27
|
+
$:.unshift(File.join(File.dirname(__FILE__), 'thirdparty/kwalify-0.7.1/lib'))
|
28
|
+
# And this one for when we're in the svn directory structure
|
29
|
+
$:.unshift(File.join(File.dirname(File.dirname(__FILE__)), 'thirdparty/kwalify-0.7.1/lib'))
|
30
|
+
|
24
31
|
begin
|
25
32
|
# Try loading facter w/o gems first so that we don't introduce a
|
26
33
|
# dependency on gems if it is not needed.
|
@@ -45,16 +52,20 @@ require 'versiontype' # Version
|
|
45
52
|
require 'deployer'
|
46
53
|
require 'set'
|
47
54
|
require 'metadata'
|
55
|
+
require 'kwalify' # for validating yaml
|
48
56
|
|
49
57
|
class Tpkg
|
50
58
|
|
51
|
-
VERSION = '1.
|
59
|
+
VERSION = '1.19.2'
|
52
60
|
CONFIGDIR = '/etc'
|
53
|
-
|
61
|
+
|
62
|
+
GENERIC_ERR = 1
|
54
63
|
POSTINSTALL_ERR = 2
|
55
64
|
POSTREMOVE_ERR = 3
|
56
65
|
INITSCRIPT_ERR = 4
|
57
66
|
|
67
|
+
CONNECTION_TIMEOUT = 10
|
68
|
+
|
58
69
|
attr_reader :installed_directory
|
59
70
|
|
60
71
|
#
|
@@ -74,6 +85,8 @@ class Tpkg
|
|
74
85
|
# Find GNU tar or bsdtar in ENV['PATH']
|
75
86
|
# Raises an exception if a suitable tar cannot be found
|
76
87
|
@@tar = nil
|
88
|
+
@@taroptions = ""
|
89
|
+
@@tartype = nil
|
77
90
|
TARNAMES = ['tar', 'gtar', 'gnutar', 'bsdtar']
|
78
91
|
def self.find_tar
|
79
92
|
if !@@tar
|
@@ -83,7 +96,12 @@ class Tpkg
|
|
83
96
|
if File.executable?(File.join(path, tarname))
|
84
97
|
IO.popen("#{File.join(path, tarname)} --version 2>/dev/null") do |pipe|
|
85
98
|
pipe.each_line do |line|
|
86
|
-
if line.include?('GNU tar')
|
99
|
+
if line.include?('GNU tar')
|
100
|
+
@@tartype = 'gnu'
|
101
|
+
@@tar = File.join(path, tarname)
|
102
|
+
throw :tar_found
|
103
|
+
elsif line.include?('bsdtar')
|
104
|
+
@@tartype = 'bsd'
|
87
105
|
@@tar = File.join(path, tarname)
|
88
106
|
throw :tar_found
|
89
107
|
end
|
@@ -96,6 +114,15 @@ class Tpkg
|
|
96
114
|
raise "Unable to find GNU tar or bsdtar in PATH"
|
97
115
|
end
|
98
116
|
end
|
117
|
+
# bsdtar uses pax format by default. This format allows for vendor extensions, such
|
118
|
+
# as the SCHILY.* extensions which were introduced by star). bsdtar actually uses
|
119
|
+
# these extensions. These extension headers includde useful, but not vital information.
|
120
|
+
# gnu tar should just ignore them and gives a warning. This is what the latest gnu tar
|
121
|
+
# will do. However, on older gnu tar, it only threw an error at the end. The work
|
122
|
+
# around is to explicitly tell gnu tar to ignore those extensions.
|
123
|
+
if @@tartype == 'gnu'
|
124
|
+
@@taroptions = "--pax-option='delete=SCHILY.*'"
|
125
|
+
end
|
99
126
|
@@tar.dup
|
100
127
|
end
|
101
128
|
def self.clear_cached_tar
|
@@ -190,8 +217,7 @@ class Tpkg
|
|
190
217
|
end
|
191
218
|
|
192
219
|
# Makes a package from a directory containing the files to put into the package
|
193
|
-
|
194
|
-
def self.make_package(pkgsrcdir, passphrase=nil)
|
220
|
+
def self.make_package(pkgsrcdir, passphrase=nil, options = {})
|
195
221
|
pkgfile = nil
|
196
222
|
|
197
223
|
# Make a working directory
|
@@ -225,23 +251,40 @@ class Tpkg
|
|
225
251
|
# code (tar) ever touch the user's files.
|
226
252
|
system("#{find_tar} -C #{pkgsrcdir} -cf - . | #{find_tar} -C #{tpkgdir} -xpf -") || raise("Package content copy failed")
|
227
253
|
|
254
|
+
# check metadata file
|
255
|
+
errors = []
|
228
256
|
if File.exists?(File.join(tpkgdir, 'tpkg.yml'))
|
229
|
-
|
230
|
-
|
257
|
+
metadata_file = File.join(tpkgdir, 'tpkg.yml')
|
258
|
+
metadata_format = 'yml'
|
231
259
|
elsif File.exists?(File.join(tpkgdir, 'tpkg.xml'))
|
232
|
-
|
233
|
-
|
260
|
+
metadata_file = File.join(tpkgdir, 'tpkg.xml')
|
261
|
+
metadata_format = 'xml'
|
234
262
|
else
|
235
263
|
raise 'Your source directory does not contain the metadata configuration file.'
|
236
264
|
end
|
265
|
+
metadata_text = File.read(metadata_file)
|
266
|
+
metadata = Metadata.new(metadata_text, metadata_format)
|
237
267
|
|
238
|
-
|
268
|
+
# This is the directory where we put our dtd/schema for validating
|
269
|
+
# the metadata file
|
270
|
+
if File.exist?(File.join(CONFIGDIR, 'tpkg', 'schema'))
|
271
|
+
schema_dir = File.join(CONFIGDIR, 'tpkg', 'schema')
|
272
|
+
else # This is for when we're in developement mode or when installed as gem
|
273
|
+
schema_dir = File.join(File.dirname(File.dirname(__FILE__)), "schema")
|
274
|
+
end
|
275
|
+
errors = metadata.validate(schema_dir)
|
276
|
+
if errors && !errors.empty?
|
277
|
+
puts "Bad metadata file. Possible error(s):"
|
278
|
+
errors.each {|e| puts e }
|
279
|
+
raise "Failed to create package." unless options[:force]
|
280
|
+
end
|
239
281
|
|
240
282
|
# file_metadata.yml hold information for files that are installed
|
241
283
|
# by the package. For example, checksum, path, relocatable or not, etc.
|
242
284
|
File.open(File.join(tpkgdir, "file_metadata.bin"), "w") do |file|
|
243
285
|
filemetadata = get_filemetadata_from_directory(tpkgdir)
|
244
|
-
|
286
|
+
data = filemetadata.to_hash.recursively{|h| h.stringify_keys }
|
287
|
+
Marshal::dump(data, file)
|
245
288
|
# YAML::dump(filemetadata.to_hash, file)
|
246
289
|
end
|
247
290
|
|
@@ -259,6 +302,19 @@ class Tpkg
|
|
259
302
|
raise "File #{tpkg_path} referenced in tpkg.yml but not found"
|
260
303
|
end
|
261
304
|
|
305
|
+
# check permission/ownership of crontab files
|
306
|
+
if tpkgfile[:crontab]
|
307
|
+
data = {:actual_file => working_path, :metadata => metadata, :file_metadata => tpkgfile}
|
308
|
+
perms, uid, gid = predict_file_perms_and_ownership(data)
|
309
|
+
# crontab needs to be owned by root, and is not writable by group or others
|
310
|
+
if uid != 0
|
311
|
+
warn "Warning: Your cron jobs in \"#{tpkgfile[:path]}\" might fail to run because the file is not owned by root."
|
312
|
+
end
|
313
|
+
if (perms & 0022) != 0
|
314
|
+
warn "Warning: Your cron jobs in \"#{tpkgfile[:path]}\" might fail to run because the file is writable by group and/or others."
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
262
318
|
# Encrypt any files marked for encryption
|
263
319
|
if tpkgfile[:encrypt]
|
264
320
|
if tpkgfile[:encrypt] == 'precrypt'
|
@@ -323,8 +379,12 @@ class Tpkg
|
|
323
379
|
toplevel = nil
|
324
380
|
# FIXME: This is so lame, to read the whole package to get the
|
325
381
|
# first filename. Blech.
|
326
|
-
IO.popen("#{find_tar} -tf #{package_file}") do |pipe|
|
327
|
-
toplevel = pipe.gets
|
382
|
+
IO.popen("#{find_tar} -tf #{package_file} #{@@taroptions}") do |pipe|
|
383
|
+
toplevel = pipe.gets
|
384
|
+
if toplevel.nil?
|
385
|
+
raise "Package directory structure of #{package_file} unexpected. Unable to get top level."
|
386
|
+
end
|
387
|
+
toplevel.chomp!
|
328
388
|
# Avoid SIGPIPE, if we don't sink the rest of the output from tar
|
329
389
|
# then tar ends up getting SIGPIPE when it tries to write to the
|
330
390
|
# closed pipe and exits with error, which causes us to throw an
|
@@ -423,7 +483,7 @@ class Tpkg
|
|
423
483
|
topleveldir = package_toplevel_directory(package_file)
|
424
484
|
# Extract checksum.xml from the package
|
425
485
|
checksum_xml = nil
|
426
|
-
IO.popen("#{find_tar} -xf #{package_file} -O #{File.join(topleveldir, 'checksum.xml')}") do |pipe|
|
486
|
+
IO.popen("#{find_tar} -xf #{package_file} -O #{File.join(topleveldir, 'checksum.xml')} #{@@taroptions}") do |pipe|
|
427
487
|
checksum_xml = REXML::Document.new(pipe.read)
|
428
488
|
end
|
429
489
|
if !$?.success?
|
@@ -448,7 +508,7 @@ class Tpkg
|
|
448
508
|
raise("Unrecognized checksum algorithm #{checksum.elements['algorithm']}")
|
449
509
|
end
|
450
510
|
# Extract tpkg.tar from the package and digest it
|
451
|
-
IO.popen("#{find_tar} -xf #{package_file} -O #{File.join(topleveldir, 'tpkg.tar')}") do |pipe|
|
511
|
+
IO.popen("#{find_tar} -xf #{package_file} -O #{File.join(topleveldir, 'tpkg.tar')} #{@@taroptions}") do |pipe|
|
452
512
|
# Package files can be quite large, so we digest the package in
|
453
513
|
# chunks. A survey of the Internet turns up someone who tested
|
454
514
|
# various chunk sizes on various platforms and found 4k to be
|
@@ -880,7 +940,7 @@ class Tpkg
|
|
880
940
|
files[:root] = []
|
881
941
|
files[:reloc] = []
|
882
942
|
topleveldir = package_toplevel_directory(package_file)
|
883
|
-
IO.popen("#{find_tar} -xf #{package_file} -O #{File.join(topleveldir, 'tpkg.tar')} | #{find_tar} -tf -") do |pipe|
|
943
|
+
IO.popen("#{find_tar} -xf #{package_file} -O #{File.join(topleveldir, 'tpkg.tar')} #{@@taroptions}| #{find_tar} #{@@taroptions} -tf -") do |pipe|
|
884
944
|
pipe.each do |file|
|
885
945
|
file.chomp!
|
886
946
|
if file =~ Regexp.new(File.join('tpkg', 'root'))
|
@@ -1007,6 +1067,7 @@ class Tpkg
|
|
1007
1067
|
#
|
1008
1068
|
# servers is an array or a callback that list the remote servers where we want to deploy to
|
1009
1069
|
def self.deploy(deploy_params, deploy_options, servers)
|
1070
|
+
servers.uniq!
|
1010
1071
|
deployer = Deployer.new(deploy_options)
|
1011
1072
|
deployer.deploy(deploy_params, servers)
|
1012
1073
|
end
|
@@ -1043,7 +1104,7 @@ class Tpkg
|
|
1043
1104
|
begin
|
1044
1105
|
topleveldir = Tpkg::package_toplevel_directory(package_file)
|
1045
1106
|
workdir = Tpkg::tempdir(topleveldir)
|
1046
|
-
system("#{find_tar} -xf #{package_file} -O #{File.join(topleveldir, 'tpkg.tar')} | #{find_tar} -C #{workdir} -xpf -")
|
1107
|
+
system("#{find_tar} -xf #{package_file} -O #{File.join(topleveldir, 'tpkg.tar')} #{@@taroptions}| #{find_tar} #{@@taroptions} -C #{workdir} -xpf -")
|
1047
1108
|
|
1048
1109
|
if File.exist?(File.join(workdir,"tpkg", "tpkg.yml"))
|
1049
1110
|
metadata_file = File.join(workdir,"tpkg", "tpkg.yml")
|
@@ -1060,6 +1121,47 @@ class Tpkg
|
|
1060
1121
|
end
|
1061
1122
|
return result
|
1062
1123
|
end
|
1124
|
+
|
1125
|
+
# The only restriction right now is that the file doesn't begin with "."
|
1126
|
+
def self.valid_pkg_filename?(filename)
|
1127
|
+
return File.basename(filename) !~ /^\./
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
# helper method for predicting the permissions and ownership of a file that
|
1131
|
+
# will be installed by tpkg. This is done by looking at:
|
1132
|
+
# 1) its current perms & ownership
|
1133
|
+
# 2) the file_defaults settings of the metadata file
|
1134
|
+
# 3) the explicitly defined settings in the corresponding file section of the metadata file
|
1135
|
+
def self.predict_file_perms_and_ownership(data)
|
1136
|
+
perms = nil
|
1137
|
+
uid = nil
|
1138
|
+
gid = nil
|
1139
|
+
|
1140
|
+
# get current permission and ownership
|
1141
|
+
if data[:actual_file]
|
1142
|
+
stat = File.stat(data[:actual_file])
|
1143
|
+
perms = stat.mode
|
1144
|
+
uid = stat.uid
|
1145
|
+
gid = stat.gid
|
1146
|
+
end
|
1147
|
+
|
1148
|
+
# get default permission and ownership
|
1149
|
+
metadata = data[:metadata]
|
1150
|
+
if (metadata && metadata[:files] && metadata[:files][:file_defaults] && metadata[:files][:file_defaults][:posix])
|
1151
|
+
uid = Tpkg::lookup_uid(metadata[:files][:file_defaults][:posix][:owner]) if metadata[:files][:file_defaults][:posix][:owner]
|
1152
|
+
gid = Tpkg::lookup_uid(metadata[:files][:file_defaults][:posix][:group]) if metadata[:files][:file_defaults][:posix][:group]
|
1153
|
+
perms = metadata[:files][:file_defaults][:posix][:perms] if metadata[:files][:file_defaults][:posix][:perms]
|
1154
|
+
end
|
1155
|
+
|
1156
|
+
# get explicitly defined permission and ownership
|
1157
|
+
file_metadata = data[:file_metadata]
|
1158
|
+
if file_metadata && file_metadata[:posix]
|
1159
|
+
uid = Tpkg::lookup_uid(file_metadata[:posix][:owner]) if file_metadata[:posix][:owner]
|
1160
|
+
gid = Tpkg::lookup_uid(file_metadata[:posix][:group]) if file_metadata[:posix][:group]
|
1161
|
+
perms = file_metadata[:posix][:perms] if file_metadata[:posix][:perms]
|
1162
|
+
end
|
1163
|
+
return perms, uid, gid
|
1164
|
+
end
|
1063
1165
|
|
1064
1166
|
#
|
1065
1167
|
# Instance methods
|
@@ -1598,7 +1700,7 @@ class Tpkg
|
|
1598
1700
|
metadata = {}
|
1599
1701
|
if File.directory?(@installed_directory)
|
1600
1702
|
Dir.foreach(@installed_directory) do |entry|
|
1601
|
-
next if entry == '.' || entry == '..' || entry == 'metadata'
|
1703
|
+
next if entry == '.' || entry == '..' || entry == 'metadata' || !Tpkg::valid_pkg_filename?(entry)
|
1602
1704
|
# Check the timestamp on the file to see if it is new or has
|
1603
1705
|
# changed since we last loaded data
|
1604
1706
|
timestamp = File.mtime(File.join(@installed_directory, entry))
|
@@ -1642,7 +1744,7 @@ class Tpkg
|
|
1642
1744
|
end
|
1643
1745
|
end
|
1644
1746
|
metadata[entry] = { :timestamp => timestamp,
|
1645
|
-
:metadata => m }
|
1747
|
+
:metadata => m } unless m.nil?
|
1646
1748
|
end
|
1647
1749
|
end
|
1648
1750
|
end
|
@@ -1652,13 +1754,15 @@ class Tpkg
|
|
1652
1754
|
end
|
1653
1755
|
|
1654
1756
|
# Convert metadata_for_installed_packages into pkg hashes
|
1655
|
-
def installed_packages
|
1757
|
+
def installed_packages(pkgname=nil)
|
1656
1758
|
instpkgs = []
|
1657
1759
|
metadata_for_installed_packages.each do |metadata|
|
1658
|
-
|
1659
|
-
|
1660
|
-
|
1661
|
-
|
1760
|
+
if !pkgname || metadata[:name] == pkgname
|
1761
|
+
instpkgs << { :metadata => metadata,
|
1762
|
+
:source => :currently_installed,
|
1763
|
+
# It seems reasonable for this to default to true
|
1764
|
+
:prefer => true }
|
1765
|
+
end
|
1662
1766
|
end
|
1663
1767
|
instpkgs
|
1664
1768
|
end
|
@@ -1740,7 +1844,29 @@ class Tpkg
|
|
1740
1844
|
end
|
1741
1845
|
end
|
1742
1846
|
else
|
1743
|
-
|
1847
|
+
pkgname = nil
|
1848
|
+
if req && req[:name]
|
1849
|
+
pkgname = req[:name]
|
1850
|
+
end
|
1851
|
+
# Passing a package name if we have one to installed_packages serves
|
1852
|
+
# primarily to make following the debugging output of dependency
|
1853
|
+
# resolution easier. The dependency resolution process makes frequent
|
1854
|
+
# calls to available_packages_that_meet_requirement, which in turn calls
|
1855
|
+
# this method. For available packages we're able to pre-filter based on
|
1856
|
+
# package name before calling package_meets_requirement? because we
|
1857
|
+
# store available packages hashed based on package name.
|
1858
|
+
# package_meets_requirement? is fairly verbose in its debugging output,
|
1859
|
+
# so the user sees each package it checks against a given requirement.
|
1860
|
+
# It is therefore a bit disconcerting when trying to follow the
|
1861
|
+
# debugging output to see the fairly clean process of checking available
|
1862
|
+
# packages which have already been filtered to match the desired name,
|
1863
|
+
# and then available_packages_that_meet_requirement calls this method,
|
1864
|
+
# and the user starts to see every installed package checked against the
|
1865
|
+
# same requirement. It is not obvious to the someone why all of a
|
1866
|
+
# sudden packages that aren't even remotely close to the requirement
|
1867
|
+
# start getting checked. Doing a pre-filter based on package name here
|
1868
|
+
# makes the process more consistent and easier to follow.
|
1869
|
+
installed_packages(pkgname).each do |pkg|
|
1744
1870
|
if req
|
1745
1871
|
if Tpkg::package_meets_requirement?(pkg, req)
|
1746
1872
|
pkgs << pkg
|
@@ -1796,9 +1922,7 @@ class Tpkg
|
|
1796
1922
|
# will be an array of package specs.
|
1797
1923
|
MAX_POSSIBLE_SOLUTIONS_TO_CHECK = 10000
|
1798
1924
|
def best_solution(requirements, packages, core_packages)
|
1799
|
-
|
1800
|
-
# change them without potentially messing up our caller
|
1801
|
-
result = resolve_dependencies(requirements.dup, {:tpkg => packages.dup, :native => {}}, core_packages.dup)
|
1925
|
+
result = resolve_dependencies(requirements, {:tpkg => packages, :native => {}}, core_packages)
|
1802
1926
|
if @@debug
|
1803
1927
|
if result[:solution]
|
1804
1928
|
puts "bestsol picks: #{result[:solution].inspect}" if @@debug
|
@@ -1820,6 +1944,10 @@ class Tpkg
|
|
1820
1944
|
# the same name. This may be necessary if different dependencies of the
|
1821
1945
|
# core packages end up needing both.
|
1822
1946
|
def resolve_dependencies(requirements, packages, core_packages, number_of_possible_solutions_checked=0)
|
1947
|
+
# We're probably going to make changes to packages, dup it now so
|
1948
|
+
# that we don't mess up the caller's state.
|
1949
|
+
packages = {:tpkg => packages[:tpkg].dup, :native => packages[:native].dup}
|
1950
|
+
|
1823
1951
|
# Make sure we have populated package lists for all requirements.
|
1824
1952
|
# Filter the package lists against the requirements and
|
1825
1953
|
# ensure we can at least satisfy the initial requirements.
|
@@ -1849,6 +1977,13 @@ class Tpkg
|
|
1849
1977
|
return {:number_of_possible_solutions_checked => number_of_possible_solutions_checked}
|
1850
1978
|
end
|
1851
1979
|
end
|
1980
|
+
|
1981
|
+
# FIXME: Should we weed out any entries in packages that don't correspond
|
1982
|
+
# to something in requirements? We operate later on the assumption that
|
1983
|
+
# there are no such entries. Because we dup packages at the right points
|
1984
|
+
# I believe we'll never accidently end up with orphaned entries, but maybe
|
1985
|
+
# it would be worth the compute cycles to make sure?
|
1986
|
+
|
1852
1987
|
# Sort the packages
|
1853
1988
|
[:tpkg, :native].each do |type|
|
1854
1989
|
packages[type].each do |pkgname, pkgs|
|
@@ -1857,7 +1992,8 @@ class Tpkg
|
|
1857
1992
|
# Anything else can score 1 at best. This ensures
|
1858
1993
|
# that we prefer the solution which leaves the most
|
1859
1994
|
# currently installed packages alone.
|
1860
|
-
if pkgs[0]
|
1995
|
+
if pkgs[0] &&
|
1996
|
+
pkgs[0][:source] != :currently_installed &&
|
1861
1997
|
pkgs[0][:source] != :native_installed
|
1862
1998
|
pkgs.unshift(nil)
|
1863
1999
|
end
|
@@ -2001,6 +2137,7 @@ class Tpkg
|
|
2001
2137
|
if sol[:remaining_noncoredepth] == 0
|
2002
2138
|
result = check_solution(sol, requirements, packages, core_packages, number_of_possible_solutions_checked)
|
2003
2139
|
if result[:solution]
|
2140
|
+
puts "resolvdeps returning successful solution" if @@debug
|
2004
2141
|
return result
|
2005
2142
|
else
|
2006
2143
|
number_of_possible_solutions_checked = result[:number_of_possible_solutions_checked]
|
@@ -2024,6 +2161,7 @@ class Tpkg
|
|
2024
2161
|
end
|
2025
2162
|
end
|
2026
2163
|
# No solutions found
|
2164
|
+
puts "resolvedeps returning failure" if @@debug
|
2027
2165
|
return {:number_of_possible_solutions_checked => number_of_possible_solutions_checked}
|
2028
2166
|
end
|
2029
2167
|
|
@@ -2036,7 +2174,7 @@ class Tpkg
|
|
2036
2174
|
end
|
2037
2175
|
|
2038
2176
|
if @@debug
|
2039
|
-
puts "checksol checking #{solution.inspect}"
|
2177
|
+
puts "checksol checking sol #{solution.inspect}"
|
2040
2178
|
end
|
2041
2179
|
|
2042
2180
|
# Extract dependencies from each package in the solution
|
@@ -2064,7 +2202,7 @@ class Tpkg
|
|
2064
2202
|
if packages[newreq[:type]][newreq[:name]]
|
2065
2203
|
pkg = solution[:pkgs].find{|solpkg| solpkg[:metadata][:name] == newreq[:name]}
|
2066
2204
|
puts "checksol newreq pkg: #{pkg.inspect}" if @@debug
|
2067
|
-
if Tpkg::package_meets_requirement?(pkg, newreq)
|
2205
|
+
if pkg && Tpkg::package_meets_requirement?(pkg, newreq)
|
2068
2206
|
# No change to solution needed
|
2069
2207
|
else
|
2070
2208
|
# Solution no longer works
|
@@ -2082,14 +2220,16 @@ class Tpkg
|
|
2082
2220
|
return {:solution => solution[:pkgs]}
|
2083
2221
|
else
|
2084
2222
|
puts "checksol newreqs need packages, calling resolvedeps" if @@debug
|
2085
|
-
result = resolve_dependencies(requirements+newreqs_that_need_packages, packages
|
2223
|
+
result = resolve_dependencies(requirements+newreqs_that_need_packages, packages, core_packages, number_of_possible_solutions_checked)
|
2086
2224
|
if result[:solution]
|
2225
|
+
puts "checksol returning successful solution" if @@debug
|
2087
2226
|
return result
|
2088
2227
|
else
|
2089
2228
|
number_of_possible_solutions_checked = result[:number_of_possible_solutions_checked]
|
2090
2229
|
end
|
2091
2230
|
end
|
2092
2231
|
end
|
2232
|
+
puts "checksol returning failure" if @@debug
|
2093
2233
|
return {:number_of_possible_solutions_checked => number_of_possible_solutions_checked}
|
2094
2234
|
end
|
2095
2235
|
|
@@ -2320,7 +2460,7 @@ class Tpkg
|
|
2320
2460
|
def unpack(package_file, passphrase=nil, options={})
|
2321
2461
|
ret_val = 0
|
2322
2462
|
metadata = Tpkg::metadata_from_package(package_file)
|
2323
|
-
|
2463
|
+
|
2324
2464
|
# Unpack files in a temporary directory
|
2325
2465
|
# I'd prefer to unpack on the fly so that the user doesn't need to
|
2326
2466
|
# have disk space to hold three copies of the package (the package
|
@@ -2330,7 +2470,7 @@ class Tpkg
|
|
2330
2470
|
# directory structure in the package.
|
2331
2471
|
topleveldir = Tpkg::package_toplevel_directory(package_file)
|
2332
2472
|
workdir = Tpkg::tempdir(topleveldir, @tmp_directory)
|
2333
|
-
system("#{@tar} -xf #{package_file} -O #{File.join(topleveldir, 'tpkg.tar')} | #{@tar} -C #{workdir} -xpf -")
|
2473
|
+
system("#{@tar} -xf #{package_file} -O #{File.join(topleveldir, 'tpkg.tar')} #{@@taroptions} | #{@tar} #{@@taroptions} -C #{workdir} -xpf -")
|
2334
2474
|
files_info = {} # store perms, uid, gid, etc. for files
|
2335
2475
|
checksums_of_decrypted_files = {}
|
2336
2476
|
root_dir = File.join(workdir, 'tpkg', 'root')
|
@@ -2341,7 +2481,7 @@ class Tpkg
|
|
2341
2481
|
# Get list of conflicting files/directories & store their perm/ownership. That way, we can
|
2342
2482
|
# set them to the correct values later on in order to preserve them.
|
2343
2483
|
# TODO: verify this command works on all platforms
|
2344
|
-
files = `#{@tar} -xf #{package_file} -O #{File.join(topleveldir, 'tpkg.tar')} | #{@tar} -tf -`
|
2484
|
+
files = `#{@tar} -xf #{package_file} -O #{File.join(topleveldir, 'tpkg.tar')} #{@@taroptions} | #{@tar} #{@@taroptions} -tf -`
|
2345
2485
|
files = files.split("\n")
|
2346
2486
|
conflicting_files = {}
|
2347
2487
|
files.each do | file |
|
@@ -2590,119 +2730,8 @@ class Tpkg
|
|
2590
2730
|
system("#{@tar} -C #{File.join(workdir, 'tpkg', 'reloc')} -cf - . | #{@tar} -C #{@base} -xpf -")
|
2591
2731
|
end
|
2592
2732
|
|
2593
|
-
|
2594
|
-
|
2595
|
-
# We don't have to any anything if there's already symlink to our init script.
|
2596
|
-
# This can happen if user removes pkg manually without removing
|
2597
|
-
# init symlink
|
2598
|
-
next if File.symlink?(link) && File.readlink(link) == init_script
|
2599
|
-
begin
|
2600
|
-
if !File.exist?(File.dirname(link))
|
2601
|
-
FileUtils.mkdir_p(File.dirname(link))
|
2602
|
-
end
|
2603
|
-
begin
|
2604
|
-
File.symlink(init_script, link)
|
2605
|
-
rescue Errno::EEXIST
|
2606
|
-
# The link name that init_links provides is not guaranteed to
|
2607
|
-
# be unique. It might collide with a base system init script
|
2608
|
-
# or an init script from another tpkg. If the link name
|
2609
|
-
# supplied by init_links results in EEXIST then try appending
|
2610
|
-
# a number to the end of the link name.
|
2611
|
-
catch :init_link_done do
|
2612
|
-
1.upto(9) do |i|
|
2613
|
-
begin
|
2614
|
-
File.symlink(init_script, link + i.to_s)
|
2615
|
-
throw :init_link_done
|
2616
|
-
rescue Errno::EEXIST
|
2617
|
-
end
|
2618
|
-
end
|
2619
|
-
# If we get here (i.e. we never reached the throw) then we
|
2620
|
-
# failed to create any of the possible link names.
|
2621
|
-
raise "Failed to install init script #{init_script} -> #{link} for #{File.basename(package_file)}"
|
2622
|
-
end
|
2623
|
-
end
|
2624
|
-
rescue Errno::EPERM
|
2625
|
-
# If creating the link fails due to permission problems and
|
2626
|
-
# we're not running as root just warn the user, allowing folks
|
2627
|
-
# to run tpkg as a non-root user with reduced functionality.
|
2628
|
-
if Process.euid == 0
|
2629
|
-
raise
|
2630
|
-
else
|
2631
|
-
warn "Failed to install init script for #{File.basename(package_file)}, probably due to lack of root privileges"
|
2632
|
-
end
|
2633
|
-
end
|
2634
|
-
end
|
2635
|
-
|
2636
|
-
# Install any crontabs
|
2637
|
-
crontab_destinations(metadata).each do |crontab, destination|
|
2638
|
-
begin
|
2639
|
-
if destination[:link]
|
2640
|
-
next if File.symlink?(destination[:link]) && File.readlink(destination[:link]) == crontab
|
2641
|
-
if !File.exist?(File.dirname(destination[:link]))
|
2642
|
-
FileUtils.mkdir_p(File.dirname(destination[:link]))
|
2643
|
-
end
|
2644
|
-
begin
|
2645
|
-
File.symlink(crontab, destination[:link])
|
2646
|
-
rescue Errno::EEXIST
|
2647
|
-
# The link name that crontab_destinations provides is not
|
2648
|
-
# guaranteed to be unique. It might collide with a base
|
2649
|
-
# system crontab or a crontab from another tpkg. If the
|
2650
|
-
# link name supplied by crontab_destinations results in
|
2651
|
-
# EEXIST then try appending a number to the end of the link
|
2652
|
-
# name.
|
2653
|
-
catch :crontab_link_done do
|
2654
|
-
1.upto(9) do |i|
|
2655
|
-
begin
|
2656
|
-
File.symlink(crontab, destination[:link] + i.to_s)
|
2657
|
-
throw :crontab_link_done
|
2658
|
-
rescue Errno::EEXIST
|
2659
|
-
end
|
2660
|
-
end
|
2661
|
-
# If we get here (i.e. we never reached the throw) then we
|
2662
|
-
# failed to create any of the possible link names.
|
2663
|
-
raise "Failed to install crontab #{crontab} -> #{destination[:link]} for #{File.basename(package_file)}"
|
2664
|
-
end
|
2665
|
-
end
|
2666
|
-
elsif destination[:file]
|
2667
|
-
if !File.exist?(File.dirname(destination[:file]))
|
2668
|
-
FileUtils.mkdir_p(File.dirname(destination[:file]))
|
2669
|
-
end
|
2670
|
-
tmpfile = Tempfile.new(File.basename(destination[:file]), File.dirname(destination[:file]))
|
2671
|
-
if File.exist?(destination[:file])
|
2672
|
-
# Match permissions and ownership of current crontab
|
2673
|
-
st = File.stat(destination[:file])
|
2674
|
-
File.chmod(st.mode & 07777, tmpfile.path)
|
2675
|
-
File.chown(st.uid, st.gid, tmpfile.path)
|
2676
|
-
# Insert the contents of the current crontab file
|
2677
|
-
File.open(destination[:file]) { |file| tmpfile.write(file.read) }
|
2678
|
-
end
|
2679
|
-
# Insert a header line so we can find this section to remove later
|
2680
|
-
tmpfile.puts "### TPKG START - #{@base} - #{File.basename(package_file)}"
|
2681
|
-
# Insert the package crontab contents
|
2682
|
-
crontab_contents = IO.read(crontab)
|
2683
|
-
tmpfile.write(crontab_contents)
|
2684
|
-
# Insert a newline if the crontab doesn't end with one
|
2685
|
-
if crontab_contents.chomp == crontab_contents
|
2686
|
-
tmpfile.puts
|
2687
|
-
end
|
2688
|
-
# Insert a footer line
|
2689
|
-
tmpfile.puts "### TPKG END - #{@base} - #{File.basename(package_file)}"
|
2690
|
-
tmpfile.close
|
2691
|
-
File.rename(tmpfile.path, destination[:file])
|
2692
|
-
# FIXME: On Solaris we should bounce cron or use the crontab
|
2693
|
-
# command, otherwise cron won't pick up the changes
|
2694
|
-
end
|
2695
|
-
rescue Errno::EPERM
|
2696
|
-
# If installing the crontab fails due to permission problems and
|
2697
|
-
# we're not running as root just warn the user, allowing folks
|
2698
|
-
# to run tpkg as a non-root user with reduced functionality.
|
2699
|
-
if Process.euid == 0
|
2700
|
-
raise
|
2701
|
-
else
|
2702
|
-
warn "Failed to install crontab for #{File.basename(package_file)}, probably due to lack of root privileges"
|
2703
|
-
end
|
2704
|
-
end
|
2705
|
-
end
|
2733
|
+
install_init_scripts(metadata)
|
2734
|
+
install_crontabs(metadata)
|
2706
2735
|
|
2707
2736
|
# Run postinstall script
|
2708
2737
|
if File.exist?(File.join(workdir, 'tpkg', 'postinstall'))
|
@@ -2773,6 +2802,243 @@ class Tpkg
|
|
2773
2802
|
return ret_val
|
2774
2803
|
end
|
2775
2804
|
|
2805
|
+
def install_init_scripts(metadata)
|
2806
|
+
init_links(metadata).each do |link, init_script|
|
2807
|
+
# We don't have to do anything if there's already symlink to our init
|
2808
|
+
# script. This can happen if the user removes a package manually without
|
2809
|
+
# removing the init symlink
|
2810
|
+
next if File.symlink?(link) && File.readlink(link) == init_script
|
2811
|
+
begin
|
2812
|
+
if !File.exist?(File.dirname(link))
|
2813
|
+
FileUtils.mkdir_p(File.dirname(link))
|
2814
|
+
end
|
2815
|
+
begin
|
2816
|
+
File.symlink(init_script, link)
|
2817
|
+
rescue Errno::EEXIST
|
2818
|
+
# The link name that init_links provides is not guaranteed to
|
2819
|
+
# be unique. It might collide with a base system init script
|
2820
|
+
# or an init script from another tpkg. If the link name
|
2821
|
+
# supplied by init_links results in EEXIST then try appending
|
2822
|
+
# a number to the end of the link name.
|
2823
|
+
catch :init_link_done do
|
2824
|
+
1.upto(9) do |i|
|
2825
|
+
begin
|
2826
|
+
File.symlink(init_script, link + i.to_s)
|
2827
|
+
throw :init_link_done
|
2828
|
+
rescue Errno::EEXIST
|
2829
|
+
end
|
2830
|
+
end
|
2831
|
+
# If we get here (i.e. we never reached the throw) then we
|
2832
|
+
# failed to create any of the possible link names.
|
2833
|
+
raise "Failed to install init script #{init_script} -> #{link} for #{File.basename(metadata[:filename].to_s)}, too many overlapping filenames"
|
2834
|
+
end
|
2835
|
+
end
|
2836
|
+
# EACCES for file/directory permissions issues
|
2837
|
+
rescue Errno::EACCES => e
|
2838
|
+
# If creating the link fails due to permission problems and
|
2839
|
+
# we're not running as root just warn the user, allowing folks
|
2840
|
+
# to run tpkg as a non-root user with reduced functionality.
|
2841
|
+
if Process.euid != 0
|
2842
|
+
warn "Failed to install init script for #{File.basename(metadata[:filename].to_s)}, probably due to lack of root privileges: #{e.message}"
|
2843
|
+
else
|
2844
|
+
raise e
|
2845
|
+
end
|
2846
|
+
end
|
2847
|
+
end
|
2848
|
+
end
|
2849
|
+
def remove_init_scripts(metadata)
|
2850
|
+
init_links(metadata).each do |link, init_script|
|
2851
|
+
# The link we ended up making when we unpacked the package could be any
|
2852
|
+
# of a series (see the code in install_init_scripts for the reasoning),
|
2853
|
+
# we need to check them all.
|
2854
|
+
links = [link]
|
2855
|
+
links.concat((1..9).to_a.map { |i| link + i.to_s })
|
2856
|
+
links.each do |l|
|
2857
|
+
if File.symlink?(l) && File.readlink(l) == init_script
|
2858
|
+
begin
|
2859
|
+
File.delete(l)
|
2860
|
+
# EACCES for file/directory permissions issues
|
2861
|
+
rescue Errno::EACCES => e
|
2862
|
+
# If removing the link fails due to permission problems and
|
2863
|
+
# we're not running as root just warn the user, allowing folks
|
2864
|
+
# to run tpkg as a non-root user with reduced functionality.
|
2865
|
+
if Process.euid != 0
|
2866
|
+
warn "Failed to remove init script for #{File.basename(metadata[:filename].to_s)}, probably due to lack of root privileges: #{e.message}"
|
2867
|
+
else
|
2868
|
+
raise e
|
2869
|
+
end
|
2870
|
+
end
|
2871
|
+
end
|
2872
|
+
end
|
2873
|
+
end
|
2874
|
+
end
|
2875
|
+
|
2876
|
+
def install_crontabs(metadata)
|
2877
|
+
crontab_destinations(metadata).each do |crontab, destination|
|
2878
|
+
begin
|
2879
|
+
if destination[:link]
|
2880
|
+
install_crontab_link(metadata, crontab, destination)
|
2881
|
+
elsif destination[:file]
|
2882
|
+
install_crontab_file(metadata, crontab, destination)
|
2883
|
+
end
|
2884
|
+
# EACCES for file/directory permissions issues
|
2885
|
+
rescue Errno::EACCES => e
|
2886
|
+
# If installing the crontab fails due to permission problems and
|
2887
|
+
# we're not running as root just warn the user, allowing folks
|
2888
|
+
# to run tpkg as a non-root user with reduced functionality.
|
2889
|
+
if Process.euid != 0
|
2890
|
+
warn "Failed to install crontab for #{File.basename(metadata[:filename].to_s)}, probably due to lack of root privileges: #{e.message}"
|
2891
|
+
else
|
2892
|
+
raise e
|
2893
|
+
end
|
2894
|
+
rescue RuntimeError => e
|
2895
|
+
if e.message.include?('cannot generate tempfile') && Process.euid != 0
|
2896
|
+
warn "Failed to install crontab for #{File.basename(metadata[:filename].to_s)}, probably due to lack of root privileges: #{e.message}"
|
2897
|
+
else
|
2898
|
+
raise e
|
2899
|
+
end
|
2900
|
+
end
|
2901
|
+
end
|
2902
|
+
end
|
2903
|
+
def install_crontab_link(metadata, crontab, destination)
|
2904
|
+
return if File.symlink?(destination[:link]) && File.readlink(destination[:link]) == crontab
|
2905
|
+
if !File.exist?(File.dirname(destination[:link]))
|
2906
|
+
FileUtils.mkdir_p(File.dirname(destination[:link]))
|
2907
|
+
end
|
2908
|
+
begin
|
2909
|
+
File.symlink(crontab, destination[:link])
|
2910
|
+
rescue Errno::EEXIST
|
2911
|
+
# The link name that crontab_destinations provides is not
|
2912
|
+
# guaranteed to be unique. It might collide with a base
|
2913
|
+
# system crontab or a crontab from another tpkg. If the
|
2914
|
+
# link name supplied by crontab_destinations results in
|
2915
|
+
# EEXIST then try appending a number to the end of the link
|
2916
|
+
# name.
|
2917
|
+
catch :crontab_link_done do
|
2918
|
+
1.upto(9) do |i|
|
2919
|
+
begin
|
2920
|
+
File.symlink(crontab, destination[:link] + i.to_s)
|
2921
|
+
throw :crontab_link_done
|
2922
|
+
rescue Errno::EEXIST
|
2923
|
+
end
|
2924
|
+
end
|
2925
|
+
# If we get here (i.e. we never reached the throw) then we
|
2926
|
+
# failed to create any of the possible link names.
|
2927
|
+
raise "Failed to install crontab #{crontab} -> #{destination[:link]} for #{File.basename(metadata[:filename].to_s)}, too many overlapping filenames"
|
2928
|
+
end
|
2929
|
+
end
|
2930
|
+
end
|
2931
|
+
def install_crontab_file(metadata, crontab, destination)
|
2932
|
+
if !File.exist?(File.dirname(destination[:file]))
|
2933
|
+
FileUtils.mkdir_p(File.dirname(destination[:file]))
|
2934
|
+
end
|
2935
|
+
tmpfile = Tempfile.new(File.basename(destination[:file]), File.dirname(destination[:file]))
|
2936
|
+
if File.exist?(destination[:file])
|
2937
|
+
# Match permissions and ownership of current crontab
|
2938
|
+
st = File.stat(destination[:file])
|
2939
|
+
begin
|
2940
|
+
File.chmod(st.mode & 07777, tmpfile.path)
|
2941
|
+
File.chown(st.uid, st.gid, tmpfile.path)
|
2942
|
+
# EPERM for attempts to chown/chmod as non-root user
|
2943
|
+
rescue Errno::EPERM => e
|
2944
|
+
# If installing the crontab fails due to permission problems and
|
2945
|
+
# we're not running as root just warn the user, allowing folks
|
2946
|
+
# to run tpkg as a non-root user with reduced functionality.
|
2947
|
+
if Process.euid != 0
|
2948
|
+
warn "Failed to install crontab for #{File.basename(metadata[:filename].to_s)}, probably due to lack of root privileges: #{e.message}"
|
2949
|
+
else
|
2950
|
+
raise e
|
2951
|
+
end
|
2952
|
+
end
|
2953
|
+
# Insert the contents of the current crontab file
|
2954
|
+
File.open(destination[:file]) { |file| tmpfile.write(file.read) }
|
2955
|
+
end
|
2956
|
+
# Insert a header line so we can find this section to remove later
|
2957
|
+
tmpfile.puts "### TPKG START - #{@base} - #{File.basename(metadata[:filename].to_s)}"
|
2958
|
+
# Insert the package crontab contents
|
2959
|
+
crontab_contents = IO.read(crontab)
|
2960
|
+
tmpfile.write(crontab_contents)
|
2961
|
+
# Insert a newline if the crontab doesn't end with one
|
2962
|
+
if crontab_contents.chomp == crontab_contents
|
2963
|
+
tmpfile.puts
|
2964
|
+
end
|
2965
|
+
# Insert a footer line
|
2966
|
+
tmpfile.puts "### TPKG END - #{@base} - #{File.basename(metadata[:filename].to_s)}"
|
2967
|
+
tmpfile.close
|
2968
|
+
File.rename(tmpfile.path, destination[:file])
|
2969
|
+
# FIXME: On Solaris we should bounce cron or use the crontab
|
2970
|
+
# command, otherwise cron won't pick up the changes
|
2971
|
+
end
|
2972
|
+
def remove_crontabs(metadata)
|
2973
|
+
crontab_destinations(metadata).each do |crontab, destination|
|
2974
|
+
begin
|
2975
|
+
if destination[:link]
|
2976
|
+
remove_crontab_link(metadata, crontab, destination)
|
2977
|
+
elsif destination[:file]
|
2978
|
+
remove_crontab_file(metadata, crontab, destination)
|
2979
|
+
end
|
2980
|
+
# EACCES for file/directory permissions issues
|
2981
|
+
rescue Errno::EACCES => e
|
2982
|
+
# If removing the crontab fails due to permission problems and
|
2983
|
+
# we're not running as root just warn the user, allowing folks
|
2984
|
+
# to run tpkg as a non-root user with reduced functionality.
|
2985
|
+
if Process.euid != 0
|
2986
|
+
warn "Failed to remove crontab for #{File.basename(metadata[:filename].to_s)}, probably due to lack of root privileges: #{e.message}"
|
2987
|
+
else
|
2988
|
+
raise e
|
2989
|
+
end
|
2990
|
+
end
|
2991
|
+
end
|
2992
|
+
end
|
2993
|
+
def remove_crontab_link(metadata, crontab, destination)
|
2994
|
+
# The link we ended up making when we unpacked the package could
|
2995
|
+
# be any of a series (see the code in unpack for the reasoning),
|
2996
|
+
# we need to check them all.
|
2997
|
+
links = [destination[:link]]
|
2998
|
+
links.concat((1..9).to_a.map { |i| destination[:link] + i.to_s })
|
2999
|
+
links.each do |l|
|
3000
|
+
if File.symlink?(l) && File.readlink(l) == crontab
|
3001
|
+
File.delete(l)
|
3002
|
+
end
|
3003
|
+
end
|
3004
|
+
end
|
3005
|
+
def remove_crontab_file(metadata, crontab, destination)
|
3006
|
+
if File.exist?(destination[:file])
|
3007
|
+
tmpfile = Tempfile.new(File.basename(destination[:file]), File.dirname(destination[:file]))
|
3008
|
+
# Match permissions and ownership of current crontab
|
3009
|
+
st = File.stat(destination[:file])
|
3010
|
+
begin
|
3011
|
+
File.chmod(st.mode & 07777, tmpfile.path)
|
3012
|
+
File.chown(st.uid, st.gid, tmpfile.path)
|
3013
|
+
# EPERM for attempts to chown/chmod as non-root user
|
3014
|
+
rescue Errno::EPERM => e
|
3015
|
+
# If installing the crontab fails due to permission problems and
|
3016
|
+
# we're not running as root just warn the user, allowing folks
|
3017
|
+
# to run tpkg as a non-root user with reduced functionality.
|
3018
|
+
if Process.euid != 0
|
3019
|
+
warn "Failed to install crontab for #{File.basename(metadata[:filename].to_s)}, probably due to lack of root privileges: #{e.message}"
|
3020
|
+
else
|
3021
|
+
raise
|
3022
|
+
end
|
3023
|
+
end
|
3024
|
+
# Remove section associated with this package
|
3025
|
+
skip = false
|
3026
|
+
IO.foreach(destination[:file]) do |line|
|
3027
|
+
if line == "### TPKG START - #{@base} - #{File.basename(metadata[:filename].to_s)}\n"
|
3028
|
+
skip = true
|
3029
|
+
elsif line == "### TPKG END - #{@base} - #{File.basename(metadata[:filename].to_s)}\n"
|
3030
|
+
skip = false
|
3031
|
+
elsif !skip
|
3032
|
+
tmpfile.write(line)
|
3033
|
+
end
|
3034
|
+
end
|
3035
|
+
tmpfile.close
|
3036
|
+
File.rename(tmpfile.path, destination[:file])
|
3037
|
+
# FIXME: On Solaris we should bounce cron or use the crontab
|
3038
|
+
# command, otherwise cron won't pick up the changes
|
3039
|
+
end
|
3040
|
+
end
|
3041
|
+
|
2776
3042
|
def requirements_for_currently_installed_package(pkgname=nil)
|
2777
3043
|
requirements = []
|
2778
3044
|
metadata_for_installed_packages.each do |metadata|
|
@@ -2833,7 +3099,7 @@ class Tpkg
|
|
2833
3099
|
req = Tpkg::parse_request(request, @installed_directory)
|
2834
3100
|
newreqs << req
|
2835
3101
|
|
2836
|
-
|
3102
|
+
puts "Initializing the list of possible packages for this req" if @@debug
|
2837
3103
|
if !packages[req[:name]]
|
2838
3104
|
packages[req[:name]] = available_packages_that_meet_requirement(req)
|
2839
3105
|
end
|
@@ -2843,7 +3109,14 @@ class Tpkg
|
|
2843
3109
|
source = nil
|
2844
3110
|
localpath = nil
|
2845
3111
|
if File.file?(request)
|
3112
|
+
raise "Invalid package filename #{request}" if !Tpkg::valid_pkg_filename?(request)
|
3113
|
+
|
2846
3114
|
puts "parse_requests treating request as a file" if @@debug
|
3115
|
+
|
3116
|
+
if request !~ /\.tpkg$/
|
3117
|
+
warn "Warning: Attempting to perform the request on #{File.expand_path(request)}. This might not be a valid package file."
|
3118
|
+
end
|
3119
|
+
|
2847
3120
|
localpath = request
|
2848
3121
|
metadata = Tpkg::metadata_from_package(request)
|
2849
3122
|
source = request
|
@@ -2892,7 +3165,8 @@ class Tpkg
|
|
2892
3165
|
good_package = true
|
2893
3166
|
metadata = pkg[:metadata]
|
2894
3167
|
req = { :name => metadata[:name], :type => :tpkg }
|
2895
|
-
# Quick sanity check that the package can be installed on this machine.
|
3168
|
+
# Quick sanity check that the package can be installed on this machine.
|
3169
|
+
puts "check_requests checking that available package for request works on this machine: #{pkg.inspect}" if @@debug
|
2896
3170
|
if !Tpkg::package_meets_requirement?(pkg, req)
|
2897
3171
|
possible_errors << " Requested package #{metadata[:filename]} doesn't match this machine's OS or architecture"
|
2898
3172
|
good_package = false
|
@@ -2901,6 +3175,7 @@ class Tpkg
|
|
2901
3175
|
# a sanity check that there is at least one package
|
2902
3176
|
# available for each dependency of this package
|
2903
3177
|
metadata[:dependencies].each do |depreq|
|
3178
|
+
puts "check_requests checking for available packages to satisfy dependency: #{depreq.inspect}" if @@debug
|
2904
3179
|
if available_packages_that_meet_requirement(depreq).empty? && !Tpkg::packages_meet_requirement?(packages.values.flatten, depreq)
|
2905
3180
|
possible_errors << " Requested package #{metadata[:filename]} depends on #{depreq.inspect}, no packages that satisfy that dependency are available"
|
2906
3181
|
good_package = false
|
@@ -3386,6 +3661,11 @@ class Tpkg
|
|
3386
3661
|
else
|
3387
3662
|
pkgfile = download(pkg[:source], pkg[:metadata][:filename])
|
3388
3663
|
end
|
3664
|
+
|
3665
|
+
if !Tpkg::valid_pkg_filename?(pkgfile)
|
3666
|
+
raise "Invalid package filename: #{pkgfile}"
|
3667
|
+
end
|
3668
|
+
|
3389
3669
|
if prompt_for_conflicting_files(pkgfile, CHECK_UPGRADE)
|
3390
3670
|
# If the old and new packages have overlapping externals flag them
|
3391
3671
|
# to be skipped so that the external isn't removed and then
|
@@ -3399,7 +3679,7 @@ class Tpkg
|
|
3399
3679
|
end if pkg[:metadata][:externals]
|
3400
3680
|
|
3401
3681
|
# Remove the old package if we haven't done so
|
3402
|
-
unless removed_pkgs.include?(pkg[:metadata][:name])
|
3682
|
+
unless oldpkgs.nil? or oldpkgs.empty? or removed_pkgs.include?(pkg[:metadata][:name])
|
3403
3683
|
remove([pkg[:metadata][:name]], :upgrade => true, :externals_to_skip => externals_to_skip)
|
3404
3684
|
removed_pkgs << pkg[:metadata][:name]
|
3405
3685
|
end
|
@@ -3441,6 +3721,7 @@ class Tpkg
|
|
3441
3721
|
|
3442
3722
|
packages_to_remove = nil
|
3443
3723
|
if requests
|
3724
|
+
requests.uniq! if requests.is_a?(Array)
|
3444
3725
|
packages_to_remove = []
|
3445
3726
|
requests.each do |request|
|
3446
3727
|
req = Tpkg::parse_request(request, @installed_directory)
|
@@ -3548,7 +3829,7 @@ class Tpkg
|
|
3548
3829
|
|
3549
3830
|
topleveldir = Tpkg::package_toplevel_directory(package_file)
|
3550
3831
|
workdir = Tpkg::tempdir(topleveldir, @tmp_directory)
|
3551
|
-
system("#{@tar} -xf #{package_file} -O #{File.join(topleveldir, 'tpkg.tar')} | #{@tar} -C #{workdir} -xpf -")
|
3832
|
+
system("#{@tar} -xf #{package_file} -O #{File.join(topleveldir, 'tpkg.tar')} #{@@taroptions} | #{@tar} #{@@taroptions} -C #{workdir} -xpf -")
|
3552
3833
|
|
3553
3834
|
# Run preremove script
|
3554
3835
|
if File.exist?(File.join(workdir, 'tpkg', 'preremove'))
|
@@ -3571,86 +3852,9 @@ class Tpkg
|
|
3571
3852
|
# Switch back to our previous directory
|
3572
3853
|
Dir.chdir(pwd)
|
3573
3854
|
end
|
3574
|
-
|
3575
|
-
|
3576
|
-
|
3577
|
-
# The link we ended up making when we unpacked the package could
|
3578
|
-
# be any of a series (see the code in unpack for the reasoning),
|
3579
|
-
# we need to check them all.
|
3580
|
-
links = [link]
|
3581
|
-
links.concat((1..9).to_a.map { |i| link + i.to_s })
|
3582
|
-
links.each do |l|
|
3583
|
-
if File.symlink?(l) && File.readlink(l) == init_script
|
3584
|
-
begin
|
3585
|
-
File.delete(l)
|
3586
|
-
rescue Errno::EPERM
|
3587
|
-
if Process.euid == 0
|
3588
|
-
raise
|
3589
|
-
else
|
3590
|
-
warn "Failed to remove init script for #{File.basename(package_file)}, probably due to lack of root privileges"
|
3591
|
-
end
|
3592
|
-
end
|
3593
|
-
end
|
3594
|
-
end
|
3595
|
-
end
|
3596
|
-
|
3597
|
-
# Remove any crontabs
|
3598
|
-
crontab_destinations(pkg[:metadata]).each do |crontab, destination|
|
3599
|
-
begin
|
3600
|
-
if destination[:link]
|
3601
|
-
# The link we ended up making when we unpacked the package could
|
3602
|
-
# be any of a series (see the code in unpack for the reasoning),
|
3603
|
-
# we need to check them all.
|
3604
|
-
links = [destination[:link]]
|
3605
|
-
links.concat((1..9).to_a.map { |i| destination[:link] + i.to_s })
|
3606
|
-
links.each do |l|
|
3607
|
-
if File.symlink?(l) && File.readlink(l) == crontab
|
3608
|
-
begin
|
3609
|
-
File.delete(l)
|
3610
|
-
rescue Errno::EPERM
|
3611
|
-
if Process.euid == 0
|
3612
|
-
raise
|
3613
|
-
else
|
3614
|
-
warn "Failed to remove crontab for #{File.basename(package_file)}, probably due to lack of root privileges"
|
3615
|
-
end
|
3616
|
-
end
|
3617
|
-
end
|
3618
|
-
end
|
3619
|
-
elsif destination[:file]
|
3620
|
-
if File.exist?(destination[:file])
|
3621
|
-
tmpfile = Tempfile.new(File.basename(destination[:file]), File.dirname(destination[:file]))
|
3622
|
-
# Match permissions and ownership of current crontab
|
3623
|
-
st = File.stat(destination[:file])
|
3624
|
-
File.chmod(st.mode & 07777, tmpfile.path)
|
3625
|
-
File.chown(st.uid, st.gid, tmpfile.path)
|
3626
|
-
# Remove section associated with this package
|
3627
|
-
skip = false
|
3628
|
-
IO.foreach(destination[:file]) do |line|
|
3629
|
-
if line == "### TPKG START - #{@base} - #{File.basename(package_file)}\n"
|
3630
|
-
skip = true
|
3631
|
-
elsif line == "### TPKG END - #{@base} - #{File.basename(package_file)}\n"
|
3632
|
-
skip = false
|
3633
|
-
elsif !skip
|
3634
|
-
tmpfile.write(line)
|
3635
|
-
end
|
3636
|
-
end
|
3637
|
-
tmpfile.close
|
3638
|
-
File.rename(tmpfile.path, destination[:file])
|
3639
|
-
# FIXME: On Solaris we should bounce cron or use the crontab
|
3640
|
-
# command, otherwise cron won't pick up the changes
|
3641
|
-
end
|
3642
|
-
end
|
3643
|
-
rescue Errno::EPERM
|
3644
|
-
# If removing the crontab fails due to permission problems and
|
3645
|
-
# we're not running as root just warn the user, allowing folks
|
3646
|
-
# to run tpkg as a non-root user with reduced functionality.
|
3647
|
-
if Process.euid == 0
|
3648
|
-
raise
|
3649
|
-
else
|
3650
|
-
warn "Failed to remove crontab for #{File.basename(package_file)}, probably due to lack of root privileges"
|
3651
|
-
end
|
3652
|
-
end
|
3653
|
-
end
|
3855
|
+
|
3856
|
+
remove_init_scripts(pkg[:metadata])
|
3857
|
+
remove_crontabs(pkg[:metadata])
|
3654
3858
|
|
3655
3859
|
# Run any externals
|
3656
3860
|
pkg[:metadata][:externals].each do |external|
|
@@ -3678,6 +3882,12 @@ class Tpkg
|
|
3678
3882
|
end
|
3679
3883
|
rescue Errno::ENOENT
|
3680
3884
|
warn "File #{file} from package #{File.basename(package_file)} missing during remove"
|
3885
|
+
# I know it's bad to have a generic rescue for all exceptions, but in this case, there
|
3886
|
+
# can be many things that might go wrong when removing a file. We don't want tpkg
|
3887
|
+
# to crash and leave the packages in a bad state. It's better to catch
|
3888
|
+
# all exceptions and give the user some warnings.
|
3889
|
+
rescue
|
3890
|
+
warn "Failed to remove file #{file}."
|
3681
3891
|
end
|
3682
3892
|
end
|
3683
3893
|
|
@@ -3845,6 +4055,7 @@ class Tpkg
|
|
3845
4055
|
if requested_packages.nil?
|
3846
4056
|
packages_to_execute_on = installed_packages_that_meet_requirement(nil)
|
3847
4057
|
else
|
4058
|
+
requested_packages.uniq!
|
3848
4059
|
requested_packages.each do |request|
|
3849
4060
|
req = Tpkg::parse_request(request)
|
3850
4061
|
packages_to_execute_on.concat(installed_packages_that_meet_requirement(req))
|
@@ -3958,21 +4169,25 @@ class Tpkg
|
|
3958
4169
|
end
|
3959
4170
|
end
|
3960
4171
|
|
3961
|
-
# TODO: update server side to accept yaml data
|
3962
4172
|
def send_update_to_server
|
3963
4173
|
metadata = metadata_for_installed_packages.collect{|metadata| metadata.to_hash}
|
3964
4174
|
yml = YAML.dump(metadata)
|
3965
4175
|
begin
|
3966
|
-
|
3967
|
-
|
3968
|
-
|
3969
|
-
|
3970
|
-
|
3971
|
-
|
4176
|
+
response = nil
|
4177
|
+
# Need to set timeout otherwise tpkg can hang for a long time when having
|
4178
|
+
# problem talking to the reporter server.
|
4179
|
+
# I can't seem get net-ssh timeout to work so we'll just handle the timeout ourselves
|
4180
|
+
timeout(CONNECTION_TIMEOUT) do
|
4181
|
+
update_uri = URI.parse("#{@report_server}")
|
4182
|
+
http = Tpkg::gethttp(update_uri)
|
4183
|
+
request = {"yml"=>URI.escape(yml), "client"=>Facter['fqdn'].value}
|
4184
|
+
post = Net::HTTP::Post.new(update_uri.path)
|
4185
|
+
post.set_form_data(request)
|
4186
|
+
response = http.request(post)
|
4187
|
+
end
|
3972
4188
|
|
3973
4189
|
case response
|
3974
4190
|
when Net::HTTPSuccess
|
3975
|
-
# puts "Response from server:\n'#{response.body}'"
|
3976
4191
|
puts "Successfully send update to reporter server"
|
3977
4192
|
else
|
3978
4193
|
$stderr.puts response.body
|
@@ -3980,10 +4195,12 @@ class Tpkg
|
|
3980
4195
|
# just ignore error and give user warning
|
3981
4196
|
puts "Failed to send update to reporter server"
|
3982
4197
|
end
|
4198
|
+
rescue Timeout::Error
|
4199
|
+
puts "Timed out when trying to send update to reporter server"
|
3983
4200
|
rescue
|
3984
4201
|
puts "Failed to send update to reporter server"
|
3985
4202
|
end
|
3986
|
-
end
|
4203
|
+
end
|
3987
4204
|
|
3988
4205
|
# Build a dependency map of currently installed packages
|
3989
4206
|
# For example, if we have pkgB and pkgC which depends on pkgA, then
|