fpm 1.3.3 → 1.4.0
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.
- checksums.yaml +4 -4
- data/CHANGELIST +32 -0
- data/CONTRIBUTORS +1 -1
- data/lib/fpm.rb +1 -0
- data/lib/fpm/command.rb +43 -18
- data/lib/fpm/package.rb +13 -13
- data/lib/fpm/package/cpan.rb +29 -17
- data/lib/fpm/package/deb.rb +59 -23
- data/lib/fpm/package/dir.rb +13 -26
- data/lib/fpm/package/empty.rb +6 -0
- data/lib/fpm/package/gem.rb +4 -4
- data/lib/fpm/package/npm.rb +2 -2
- data/lib/fpm/package/osxpkg.rb +3 -3
- data/lib/fpm/package/p5p.rb +124 -0
- data/lib/fpm/package/pyfpm/get_metadata.py +9 -1
- data/lib/fpm/package/python.rb +16 -9
- data/lib/fpm/package/rpm.rb +17 -10
- data/lib/fpm/package/sh.rb +1 -7
- data/lib/fpm/package/solaris.rb +1 -1
- data/lib/fpm/package/virtualenv.rb +136 -0
- data/lib/fpm/package/zip.rb +1 -1
- data/lib/fpm/util.rb +31 -5
- data/lib/fpm/version.rb +1 -1
- data/templates/deb/postinst_upgrade.sh.erb +14 -2
- data/templates/deb/postrm_upgrade.sh.erb +10 -1
- data/templates/deb/preinst_upgrade.sh.erb +11 -2
- data/templates/deb/prerm_upgrade.sh.erb +7 -2
- data/templates/p5p_metadata.erb +12 -0
- data/templates/rpm.erb +34 -5
- data/templates/sh.erb +22 -1
- metadata +8 -7
- data/lib/fpm/package/pyfpm/__init__.pyc +0 -0
- data/lib/fpm/package/pyfpm/get_metadata.pyc +0 -0
@@ -90,7 +90,15 @@ class get_metadata(Command):
|
|
90
90
|
|
91
91
|
output = open(self.output, "w")
|
92
92
|
if hasattr(json, 'dumps'):
|
93
|
-
|
93
|
+
def default_to_str(obj):
|
94
|
+
""" Fall back to using __str__ if possible """
|
95
|
+
# This checks if the class of obj defines __str__ itself,
|
96
|
+
# so we don't fall back to an inherited __str__ method.
|
97
|
+
if "__str__" in type(obj).__dict__:
|
98
|
+
return str(obj)
|
99
|
+
return json.JSONEncoder.default(self, obj)
|
100
|
+
|
101
|
+
output.write(json.dumps(data, indent=2, default=default_to_str))
|
94
102
|
else:
|
95
103
|
# For Python 2.5 and Debian's python-json
|
96
104
|
output.write(json.write(data))
|
data/lib/fpm/package/python.rb
CHANGED
@@ -7,7 +7,7 @@ require "fileutils"
|
|
7
7
|
require "tmpdir"
|
8
8
|
require "json"
|
9
9
|
|
10
|
-
# Support for python packages.
|
10
|
+
# Support for python packages.
|
11
11
|
#
|
12
12
|
# This supports input, but not output.
|
13
13
|
#
|
@@ -28,7 +28,7 @@ class FPM::Package::Python < FPM::Package
|
|
28
28
|
"is used instead", :default => nil
|
29
29
|
option "--pypi", "PYPI_URL",
|
30
30
|
"PyPi Server uri for retrieving packages.",
|
31
|
-
:default => "
|
31
|
+
:default => "https://pypi.python.org/simple"
|
32
32
|
option "--package-prefix", "NAMEPREFIX",
|
33
33
|
"(DEPRECATED, use --package-name-prefix) Name to prefix the package " \
|
34
34
|
"name with." do |value|
|
@@ -69,6 +69,10 @@ class FPM::Package::Python < FPM::Package
|
|
69
69
|
"current python interpreter (sys.executable). This option is equivalent " \
|
70
70
|
"to appending 'build_scripts --executable PYTHON_EXECUTABLE' arguments " \
|
71
71
|
"to 'setup.py install' command."
|
72
|
+
option "--disable-dependency", "python_package_name",
|
73
|
+
"The python package name to remove from dependency list",
|
74
|
+
:multivalued => true, :attribute_name => :python_disable_dependency,
|
75
|
+
:default => []
|
72
76
|
|
73
77
|
private
|
74
78
|
|
@@ -88,7 +92,7 @@ class FPM::Package::Python < FPM::Package
|
|
88
92
|
setup_py = path_to_package
|
89
93
|
end
|
90
94
|
|
91
|
-
if !File.
|
95
|
+
if !File.exist?(setup_py)
|
92
96
|
logger.error("Could not find 'setup.py'", :path => setup_py)
|
93
97
|
raise "Unable to find python package; tried #{setup_py}"
|
94
98
|
end
|
@@ -104,7 +108,7 @@ class FPM::Package::Python < FPM::Package
|
|
104
108
|
# part should go elsewhere.
|
105
109
|
path = package
|
106
110
|
# If it's a path, assume local build.
|
107
|
-
if File.directory?(path) or (File.
|
111
|
+
if File.directory?(path) or (File.exist?(path) and File.basename(path) == "setup.py")
|
108
112
|
return path
|
109
113
|
end
|
110
114
|
|
@@ -127,7 +131,7 @@ class FPM::Package::Python < FPM::Package
|
|
127
131
|
"--build-directory", target, want_pkg)
|
128
132
|
else
|
129
133
|
logger.debug("using pip", :pip => attributes[:python_pip])
|
130
|
-
safesystem(attributes[:python_pip], "install", "--no-deps", "--no-install", "-i", attributes[:python_pypi], "-U", "--build", target, want_pkg)
|
134
|
+
safesystem(attributes[:python_pip], "install", "--no-deps", "--no-install", "--no-use-wheel", "-i", attributes[:python_pypi], "-U", "--build", target, want_pkg)
|
131
135
|
end
|
132
136
|
|
133
137
|
# easy_install will put stuff in @tmpdir/packagename/, so find that:
|
@@ -145,7 +149,7 @@ class FPM::Package::Python < FPM::Package
|
|
145
149
|
attributes[:python_package_name_prefix] = attributes[:python_package_prefix]
|
146
150
|
end
|
147
151
|
|
148
|
-
begin
|
152
|
+
begin
|
149
153
|
json_test_code = [
|
150
154
|
"try:",
|
151
155
|
" import json",
|
@@ -219,7 +223,7 @@ class FPM::Package::Python < FPM::Package
|
|
219
223
|
self.name = self.name.downcase if attributes[:python_downcase_name?]
|
220
224
|
|
221
225
|
if !attributes[:no_auto_depends?] and attributes[:python_dependencies?]
|
222
|
-
|
226
|
+
metadata["dependencies"].each do |dep|
|
223
227
|
dep_re = /^([^<>!= ]+)\s*(?:([<>!=]{1,2})\s*(.*))?$/
|
224
228
|
match = dep_re.match(dep)
|
225
229
|
if match.nil?
|
@@ -228,6 +232,8 @@ class FPM::Package::Python < FPM::Package
|
|
228
232
|
end
|
229
233
|
name, cmp, version = match.captures
|
230
234
|
|
235
|
+
next if attributes[:python_disable_dependency].include?(name)
|
236
|
+
|
231
237
|
# convert == to =
|
232
238
|
if cmp == "=="
|
233
239
|
logger.info("Converting == dependency requirement to =", :dependency => dep )
|
@@ -241,7 +247,8 @@ class FPM::Package::Python < FPM::Package
|
|
241
247
|
|
242
248
|
# convert dependencies from python-Foo to python-foo
|
243
249
|
name = name.downcase if attributes[:python_downcase_dependencies?]
|
244
|
-
|
250
|
+
|
251
|
+
self.dependencies << "#{name} #{cmp} #{version}"
|
245
252
|
end
|
246
253
|
end # if attributes[:python_dependencies?]
|
247
254
|
end # def load_package_info
|
@@ -267,7 +274,7 @@ class FPM::Package::Python < FPM::Package
|
|
267
274
|
|
268
275
|
prefix = "/"
|
269
276
|
prefix = attributes[:prefix] unless attributes[:prefix].nil?
|
270
|
-
|
277
|
+
|
271
278
|
# Some setup.py's assume $PWD == current directory of setup.py, so let's
|
272
279
|
# chdir first.
|
273
280
|
::Dir.chdir(project_dir) do
|
data/lib/fpm/package/rpm.rb
CHANGED
@@ -29,7 +29,7 @@ class FPM::Package::RPM < FPM::Package
|
|
29
29
|
"bzip2" => "w9.bzdio"
|
30
30
|
} unless defined?(COMPRESSION_MAP)
|
31
31
|
|
32
|
-
option "--use-file-permissions", :flag,
|
32
|
+
option "--use-file-permissions", :flag,
|
33
33
|
"Use existing file permissions when defining ownership and modes."
|
34
34
|
|
35
35
|
option "--user", "USER", "Set the user to USER in the %files section. Overrides the user when used with use-file-permissions setting."
|
@@ -55,6 +55,8 @@ class FPM::Package::RPM < FPM::Package
|
|
55
55
|
next rpmbuild_define
|
56
56
|
end
|
57
57
|
|
58
|
+
option "--dist", "DIST-TAG", "Set the rpm distribution."
|
59
|
+
|
58
60
|
option "--digest", DIGEST_ALGORITHM_MAP.keys.join("|"),
|
59
61
|
"Select a digest algorithm. md5 works on the most platforms.",
|
60
62
|
:default => "md5" do |value|
|
@@ -98,7 +100,7 @@ class FPM::Package::RPM < FPM::Package
|
|
98
100
|
option "--attr", "ATTRFILE",
|
99
101
|
"Set the attribute for a file (%attr).",
|
100
102
|
:multivalued => true, :attribute_name => :attrs
|
101
|
-
|
103
|
+
|
102
104
|
option "--init", "FILEPATH", "Add FILEPATH as an init script",
|
103
105
|
:multivalued => true do |file|
|
104
106
|
next File.expand_path(file)
|
@@ -149,14 +151,14 @@ class FPM::Package::RPM < FPM::Package
|
|
149
151
|
match = trigger.match(/^(\[.*\]|)(.*): (.*)$/)
|
150
152
|
@logger.fatal("Trigger '#{trigger_type}' definition can't be parsed ('#{trigger}')") unless match
|
151
153
|
opt, pkg, file = match.captures
|
152
|
-
@logger.fatal("File given for --trigger-#{trigger_type} does not exist (#{file})") unless File.
|
154
|
+
@logger.fatal("File given for --trigger-#{trigger_type} does not exist (#{file})") unless File.exist?(file)
|
153
155
|
rpm_trigger << [pkg, File.read(file), opt.tr('[]','')]
|
154
156
|
next rpm_trigger
|
155
157
|
end
|
156
158
|
end
|
157
|
-
|
159
|
+
|
158
160
|
private
|
159
|
-
|
161
|
+
|
160
162
|
# Fix path name
|
161
163
|
# Replace [ with [\[] to make rpm not use globs
|
162
164
|
# Replace * with [*] to make rpm not use globs
|
@@ -289,7 +291,7 @@ class FPM::Package::RPM < FPM::Package
|
|
289
291
|
script_path = self.attributes[scriptname]
|
290
292
|
# Skip scripts not set
|
291
293
|
next if script_path.nil?
|
292
|
-
if !File.
|
294
|
+
if !File.exist?(script_path)
|
293
295
|
logger.error("No such file (for #{scriptname.to_s}): #{script_path.inspect}")
|
294
296
|
script_errors << script_path
|
295
297
|
end
|
@@ -303,7 +305,6 @@ class FPM::Package::RPM < FPM::Package
|
|
303
305
|
end # def converted
|
304
306
|
|
305
307
|
def rpm_get_trigger_type(flag)
|
306
|
-
puts "#{flag.to_s(2)}"
|
307
308
|
if (flag & (1 << 25)) == (1 << 25)
|
308
309
|
:rpm_trigger_before_install
|
309
310
|
elsif (flag & (1 << 16)) == (1 << 16)
|
@@ -375,13 +376,13 @@ class FPM::Package::RPM < FPM::Package
|
|
375
376
|
[name, operator, version].join(" ")
|
376
377
|
end
|
377
378
|
#input.replaces += replaces
|
378
|
-
|
379
|
+
|
379
380
|
self.config_files += rpm.config_files
|
380
381
|
|
381
382
|
# rpms support '%dir' things for specifying empty directories to package,
|
382
383
|
# but the rpm header itself doesn't actually record this information.
|
383
384
|
# so there's no 'directories' to copy, so don't try to merge in the
|
384
|
-
# 'directories' feature.
|
385
|
+
# 'directories' feature.
|
385
386
|
# TODO(sissel): If you want this feature, we'll have to find scan
|
386
387
|
# the extracted rpm for empty directories. I'll wait until someone asks for
|
387
388
|
# this feature
|
@@ -414,6 +415,9 @@ class FPM::Package::RPM < FPM::Package
|
|
414
415
|
args += ["--target", rpm_target]
|
415
416
|
end
|
416
417
|
|
418
|
+
# set the rpm dist tag
|
419
|
+
args += ["--define", "dist .#{attributes[:rpm_dist]}"] if attributes[:rpm_dist]
|
420
|
+
|
417
421
|
args += [
|
418
422
|
"--define", "buildroot #{build_path}/BUILD",
|
419
423
|
"--define", "_topdir #{build_path}",
|
@@ -531,7 +535,10 @@ class FPM::Package::RPM < FPM::Package
|
|
531
535
|
end # def epoch
|
532
536
|
|
533
537
|
def to_s(format=nil)
|
534
|
-
|
538
|
+
if format.nil?
|
539
|
+
return super("NAME-VERSION-ITERATION.DIST.ARCH.TYPE").gsub('DIST', attributes[:rpm_dist]) if attributes[:rpm_dist]
|
540
|
+
return super("NAME-VERSION-ITERATION.ARCH.TYPE")
|
541
|
+
end
|
535
542
|
return super(format)
|
536
543
|
end # def to_s
|
537
544
|
|
data/lib/fpm/package/sh.rb
CHANGED
@@ -11,7 +11,7 @@ require "digest"
|
|
11
11
|
#
|
12
12
|
# This class only supports output of packages.
|
13
13
|
#
|
14
|
-
# The sh package is a single sh file with a
|
14
|
+
# The sh package is a single sh file with a tar payload concatenated to the end.
|
15
15
|
# The script can unpack the tarball to install it and call optional post install scripts.
|
16
16
|
class FPM::Package::Sh < FPM::Package
|
17
17
|
|
@@ -24,12 +24,6 @@ class FPM::Package::Sh < FPM::Package
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def create_scripts
|
27
|
-
if script?(:before_install)
|
28
|
-
# the scripts are kept in the payload so what would before install be if we've already
|
29
|
-
# unpacked the payload?
|
30
|
-
raise "sh package does not support before install scripts."
|
31
|
-
end
|
32
|
-
|
33
27
|
if script?(:after_install)
|
34
28
|
File.write(File.join(fpm_meta_path, "after_install"), script(:after_install))
|
35
29
|
end
|
data/lib/fpm/package/solaris.rb
CHANGED
@@ -75,7 +75,7 @@ class FPM::Package::Solaris < FPM::Package
|
|
75
75
|
# Should create a package directory named by the package name.
|
76
76
|
safesystem("pkgmk", "-o", "-f", "#{build_path}/Prototype", "-d", build_path)
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
|
80
80
|
# Convert the 'package directory' built above to a real solaris package.
|
81
81
|
safesystem("pkgtrans", "-s", build_path, output_path, name)
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require "fpm/namespace"
|
2
|
+
require "fpm/package"
|
3
|
+
require "fpm/util"
|
4
|
+
|
5
|
+
# Support for python virtualenv packages.
|
6
|
+
#
|
7
|
+
# This supports input, but not output.
|
8
|
+
#
|
9
|
+
class FPM::Package::Virtualenv < FPM::Package
|
10
|
+
# Flags '--foo' will be accessable as attributes[:virtualenv_foo]
|
11
|
+
|
12
|
+
option "--pypi", "PYPI_URL",
|
13
|
+
"PyPi Server uri for retrieving packages.",
|
14
|
+
:default => "https://pypi.python.org/simple"
|
15
|
+
option "--package-name-prefix", "PREFIX", "Name to prefix the package " \
|
16
|
+
"name with.", :default => "virtualenv"
|
17
|
+
|
18
|
+
option "--install-location", "DIRECTORY", "Location to which to " \
|
19
|
+
"install the virtualenv by default.", :default => "/usr/share/python" do |path|
|
20
|
+
File.expand_path(path)
|
21
|
+
end
|
22
|
+
|
23
|
+
option "--fix-name", :flag, "Should the target package name be prefixed?",
|
24
|
+
:default => true
|
25
|
+
option "--other-files-dir", "DIRECTORY", "Optionally, the contents of the " \
|
26
|
+
"specified directory may be added to the package. This is useful if the " \
|
27
|
+
"virtualenv needs configuration files, etc.", :default => nil
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# Input a package.
|
32
|
+
#
|
33
|
+
# `package` can look like `psutil==2.2.1` or `psutil`.
|
34
|
+
def input(package)
|
35
|
+
installdir = attributes[:virtualenv_install_location]
|
36
|
+
m = /^([^=]+)==([^=]+)$/.match(package)
|
37
|
+
package_version = nil
|
38
|
+
|
39
|
+
if m
|
40
|
+
package_name = m[1]
|
41
|
+
package_version = m[2]
|
42
|
+
self.version ||= package_version
|
43
|
+
else
|
44
|
+
package_name = package
|
45
|
+
package_version = nil
|
46
|
+
end
|
47
|
+
|
48
|
+
virtualenv_name = package_name
|
49
|
+
|
50
|
+
self.name ||= package_name
|
51
|
+
|
52
|
+
if self.attributes[:virtualenv_fix_name?]
|
53
|
+
self.name = [self.attributes[:virtualenv_package_name_prefix],
|
54
|
+
self.name].join("-")
|
55
|
+
end
|
56
|
+
|
57
|
+
virtualenv_folder =
|
58
|
+
File.join(installdir,
|
59
|
+
virtualenv_name)
|
60
|
+
|
61
|
+
virtualenv_build_folder = build_path(virtualenv_folder)
|
62
|
+
|
63
|
+
::FileUtils.mkdir_p(virtualenv_build_folder)
|
64
|
+
|
65
|
+
safesystem("virtualenv", virtualenv_build_folder)
|
66
|
+
pip_exe = File.join(virtualenv_build_folder, "bin", "pip")
|
67
|
+
python_exe = File.join(virtualenv_build_folder, "bin", "python")
|
68
|
+
|
69
|
+
# Why is this hack here? It looks important, so I'll keep it in.
|
70
|
+
safesystem(pip_exe, "install", "-U", "-i",
|
71
|
+
attributes[:virtualenv_pypi],
|
72
|
+
"pip", "distribute")
|
73
|
+
safesystem(pip_exe, "uninstall", "-y", "distribute")
|
74
|
+
|
75
|
+
safesystem(pip_exe, "install", "-i",
|
76
|
+
attributes[:virtualenv_pypi],
|
77
|
+
package)
|
78
|
+
|
79
|
+
if package_version.nil?
|
80
|
+
frozen = safesystemout(pip_exe, "freeze")
|
81
|
+
package_version = frozen[/#{package}==[^=]+$/].split("==")[1].chomp!
|
82
|
+
self.version ||= package_version
|
83
|
+
end
|
84
|
+
|
85
|
+
::Dir[build_path + "/**/*"].each do |f|
|
86
|
+
if ! File.world_readable? f
|
87
|
+
File.lchmod(File.stat(f).mode | 444)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
::Dir.chdir(virtualenv_build_folder) do
|
92
|
+
safesystem("virtualenv-tools", "--update-path", virtualenv_folder)
|
93
|
+
end
|
94
|
+
|
95
|
+
if !attributes[:virtualenv_other_files_dir].nil?
|
96
|
+
# Copy all files from other dir to build_path
|
97
|
+
Find.find(attributes[:virtualenv_other_files_dir]) do |path|
|
98
|
+
src = path.gsub(/^#{attributes[:virtualenv_other_files_dir]}/, '')
|
99
|
+
dst = File.join(build_path, src)
|
100
|
+
copy_entry(path, dst, preserve=true, remove_destination=true)
|
101
|
+
copy_metadata(path, dst)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
remove_python_compiled_files virtualenv_build_folder
|
106
|
+
|
107
|
+
# use dir to set stuff up properly, mainly so I don't have to reimplement
|
108
|
+
# the chdir/prefix stuff special for tar.
|
109
|
+
dir = convert(FPM::Package::Dir)
|
110
|
+
|
111
|
+
if attributes[:chdir]
|
112
|
+
dir.attributes[:chdir] = File.join(build_path, attributes[:chdir])
|
113
|
+
else
|
114
|
+
dir.attributes[:chdir] = build_path
|
115
|
+
end
|
116
|
+
|
117
|
+
cleanup_staging
|
118
|
+
# Tell 'dir' to input "." and chdir/prefix will help it figure out the
|
119
|
+
# rest.
|
120
|
+
dir.input(".")
|
121
|
+
@staging_path = dir.staging_path
|
122
|
+
dir.cleanup_build
|
123
|
+
|
124
|
+
end # def input
|
125
|
+
|
126
|
+
# Delete python precompiled files found in a given folder.
|
127
|
+
def remove_python_compiled_files path
|
128
|
+
logger.debug("Now removing python object and compiled files from the virtualenv")
|
129
|
+
Find.find(path) do |path|
|
130
|
+
if path.end_with? '.pyc' or path.end_with? '.pyo'
|
131
|
+
FileUtils.rm path
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
public(:input)
|
136
|
+
end # class FPM::Package::Virtualenv
|
data/lib/fpm/package/zip.rb
CHANGED
data/lib/fpm/util.rb
CHANGED
@@ -24,6 +24,8 @@ module FPM::Util
|
|
24
24
|
|
25
25
|
# Is the given program in the system's PATH?
|
26
26
|
def program_in_path?(program)
|
27
|
+
# return false if path is not set
|
28
|
+
return false unless ENV['PATH']
|
27
29
|
# Scan path to find the executable
|
28
30
|
# Do this to help the user get a better error message.
|
29
31
|
envpath = ENV["PATH"].split(":")
|
@@ -33,12 +35,12 @@ module FPM::Util
|
|
33
35
|
def program_exists?(program)
|
34
36
|
# Scan path to find the executable
|
35
37
|
# Do this to help the user get a better error message.
|
36
|
-
return program_in_path?(program) if !program.include?("/")
|
38
|
+
return program_in_path?(program) if !program.include?("/")
|
37
39
|
return File.executable?(program)
|
38
40
|
end # def program_exists?
|
39
41
|
|
40
42
|
def default_shell
|
41
|
-
shell = ENV["SHELL"]
|
43
|
+
shell = ENV["SHELL"]
|
42
44
|
return "/bin/sh" if shell.nil? || shell.empty?
|
43
45
|
return shell
|
44
46
|
end
|
@@ -139,7 +141,7 @@ module FPM::Util
|
|
139
141
|
end # def tar_cmd
|
140
142
|
|
141
143
|
# Run a block with a value.
|
142
|
-
# Useful in lieu of assigning variables
|
144
|
+
# Useful in lieu of assigning variables
|
143
145
|
def with(value, &block)
|
144
146
|
block.call(value)
|
145
147
|
end # def with
|
@@ -157,7 +159,30 @@ module FPM::Util
|
|
157
159
|
rc
|
158
160
|
end
|
159
161
|
|
160
|
-
def
|
162
|
+
def copy_metadata(source, destination)
|
163
|
+
source_stat = File::lstat(source)
|
164
|
+
dest_stat = File::lstat(destination)
|
165
|
+
|
166
|
+
# If this is a hard-link, there's no metadata to copy.
|
167
|
+
# If this is a symlink, what it points to hasn't been copied yet.
|
168
|
+
return if source_stat.ino == dest_stat.ino || dest_stat.symlink?
|
169
|
+
|
170
|
+
File.utime(source_stat.atime, source_stat.mtime, destination)
|
171
|
+
mode = source_stat.mode
|
172
|
+
begin
|
173
|
+
File.lchown(source_stat.uid, source_stat.gid, destination)
|
174
|
+
rescue Errno::EPERM
|
175
|
+
# clear setuid/setgid
|
176
|
+
mode &= 01777
|
177
|
+
end
|
178
|
+
|
179
|
+
unless source_stat.symlink?
|
180
|
+
File.chmod(mode, destination)
|
181
|
+
end
|
182
|
+
end # def copy_metadata
|
183
|
+
|
184
|
+
|
185
|
+
def copy_entry(src, dst, preserve=false, remove_destination=false)
|
161
186
|
case File.ftype(src)
|
162
187
|
when 'fifo', 'characterSpecial', 'blockSpecial', 'socket'
|
163
188
|
st = File.stat(src)
|
@@ -173,7 +198,8 @@ module FPM::Util
|
|
173
198
|
if known_entry
|
174
199
|
FileUtils.ln(known_entry, dst)
|
175
200
|
else
|
176
|
-
FileUtils.copy_entry(src, dst
|
201
|
+
FileUtils.copy_entry(src, dst, preserve=preserve,
|
202
|
+
remove_destination=remove_destination)
|
177
203
|
copied_entries[[st.dev, st.ino]] = dst
|
178
204
|
end
|
179
205
|
end # else...
|