fpm 1.8.1 → 1.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.rst +39 -0
- data/lib/fpm/command.rb +14 -0
- data/lib/fpm/package.rb +17 -1
- data/lib/fpm/package/apk.rb +1 -1
- data/lib/fpm/package/cpan.rb +26 -15
- data/lib/fpm/package/deb.rb +65 -24
- data/lib/fpm/package/dir.rb +8 -14
- data/lib/fpm/package/gem.rb +110 -2
- data/lib/fpm/package/pleaserun.rb +12 -2
- data/lib/fpm/package/python.rb +11 -0
- data/lib/fpm/package/rpm.rb +9 -0
- data/lib/fpm/package/tar.rb +1 -9
- data/lib/fpm/package/virtualenv.rb +28 -6
- data/lib/fpm/package/zip.rb +5 -21
- data/lib/fpm/util.rb +88 -18
- data/lib/fpm/version.rb +1 -1
- data/templates/deb/changelog.erb +1 -1
- data/templates/deb/postrm_upgrade.sh.erb +12 -5
- metadata +49 -62
data/lib/fpm/package/gem.rb
CHANGED
@@ -44,9 +44,27 @@ class FPM::Package::Gem < FPM::Package
|
|
44
44
|
option "--disable-dependency", "gem_name",
|
45
45
|
"The gem name to remove from dependency list",
|
46
46
|
:multivalued => true, :attribute_name => :gem_disable_dependencies
|
47
|
+
option "--embed-dependencies", :flag, "Should the gem dependencies " \
|
48
|
+
"be installed?", :default => false
|
47
49
|
|
48
50
|
option "--version-bins", :flag, "Append the version to the bins", :default => false
|
49
51
|
|
52
|
+
option "--stagingdir", "STAGINGDIR",
|
53
|
+
"The directory where fpm installs the gem temporarily before conversion. " \
|
54
|
+
"Normally a random subdirectory of workdir."
|
55
|
+
|
56
|
+
# Override parent method
|
57
|
+
def staging_path(path=nil)
|
58
|
+
@gem_staging_path ||= attributes[:gem_stagingdir] || Stud::Temporary.directory("package-#{type}-staging")
|
59
|
+
@staging_path = @gem_staging_path
|
60
|
+
|
61
|
+
if path.nil?
|
62
|
+
return @staging_path
|
63
|
+
else
|
64
|
+
return File.join(@staging_path, path)
|
65
|
+
end
|
66
|
+
end # def staging_path
|
67
|
+
|
50
68
|
def input(gem)
|
51
69
|
# 'arg' is the name of the rubygem we should unpack.
|
52
70
|
path_to_gem = download_if_necessary(gem, version)
|
@@ -144,7 +162,7 @@ class FPM::Package::Gem < FPM::Package
|
|
144
162
|
# composing multiple packages, it's best to explicitly include it in the provides list.
|
145
163
|
self.provides << "#{self.name} = #{self.version}"
|
146
164
|
|
147
|
-
if !attributes[:no_auto_depends?]
|
165
|
+
if !attributes[:no_auto_depends?] && !attributes[:gem_embed_dependencies?]
|
148
166
|
spec.runtime_dependencies.map do |dep|
|
149
167
|
# rubygems 1.3.5 doesn't have 'Gem::Dependency#requirement'
|
150
168
|
if dep.respond_to?(:requirement)
|
@@ -181,7 +199,12 @@ class FPM::Package::Gem < FPM::Package
|
|
181
199
|
::FileUtils.mkdir_p(installdir)
|
182
200
|
# TODO(sissel): Allow setting gem tool path
|
183
201
|
args = [attributes[:gem_gem], "install", "--quiet", "--no-ri", "--no-rdoc",
|
184
|
-
"--no-user-install", "--install-dir", installdir
|
202
|
+
"--no-user-install", "--install-dir", installdir]
|
203
|
+
|
204
|
+
if !attributes[:gem_embed_dependencies?]
|
205
|
+
args += ["--ignore-dependencies"]
|
206
|
+
end
|
207
|
+
|
185
208
|
if attributes[:gem_env_shebang?]
|
186
209
|
args += ["-E"]
|
187
210
|
end
|
@@ -231,6 +254,21 @@ class FPM::Package::Gem < FPM::Package
|
|
231
254
|
FileUtils.mv("#{bin_path}/#{bin}", "#{bin_path}/#{bin}-#{self.version}")
|
232
255
|
end
|
233
256
|
end
|
257
|
+
|
258
|
+
if attributes[:source_date_epoch_from_changelog?]
|
259
|
+
detect_source_date_from_changelog(installdir)
|
260
|
+
end
|
261
|
+
|
262
|
+
# Remove generated Makefile and gem_make.out files, if any; they
|
263
|
+
# are not needed, and may contain generated paths that cause
|
264
|
+
# different output on successive runs.
|
265
|
+
Find.find(installdir) do |path|
|
266
|
+
if path =~ /.*(gem_make.out|Makefile|mkmf.log)$/
|
267
|
+
logger.info("Removing no longer needed file %s to reduce nondeterminism" % path)
|
268
|
+
File.unlink(path)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
234
272
|
end # def install_to_staging
|
235
273
|
|
236
274
|
# Sanitize package name.
|
@@ -239,5 +277,75 @@ class FPM::Package::Gem < FPM::Package
|
|
239
277
|
def fix_name(name)
|
240
278
|
return [attributes[:gem_package_name_prefix], name].join("-")
|
241
279
|
end # def fix_name
|
280
|
+
|
281
|
+
# Regular expression to accept a gem changelog line, and store date & version, if any, in named capture groups.
|
282
|
+
# Supports formats suggested by http://keepachangelog.com and https://github.com/tech-angels/vandamme
|
283
|
+
# as well as other similar formats that actually occur in the wild.
|
284
|
+
# Build it in pieces for readability, and allow version and date in either order.
|
285
|
+
# Whenever you change this, add a row to the test case in spec/fpm/package/gem_spec.rb.
|
286
|
+
# Don't even try to handle dates that lack four-digit years.
|
287
|
+
# Building blocks:
|
288
|
+
P_RE_LEADIN = '^[#=]{0,3}\s?'
|
289
|
+
P_RE_VERSION_ = '[\w\.-]+\.[\w\.-]+[a-zA-Z0-9]'
|
290
|
+
P_RE_SEPARATOR = '\s[-=/(]?\s?'
|
291
|
+
P_RE_DATE1 = '\d{4}-\d{2}-\d{2}'
|
292
|
+
P_RE_DATE2 = '\w+ \d{1,2}(?:st|nd|rd|th)?,\s\d{4}'
|
293
|
+
P_RE_DATE3 = '\w+\s+\w+\s+\d{1,2},\s\d{4}'
|
294
|
+
P_RE_DATE = "(?<date>#{P_RE_DATE1}|#{P_RE_DATE2}|#{P_RE_DATE3})"
|
295
|
+
P_RE_URL = '\(https?:[-\w/.%]*\)' # In parens, per markdown
|
296
|
+
P_RE_GTMAGIC = '\[\]' # github magic version diff, per chandler
|
297
|
+
P_RE_VERSION = "\\[?(?:Version |v)?(?<version>#{P_RE_VERSION_})\\]?(?:#{P_RE_URL}|#{P_RE_GTMAGIC})?"
|
298
|
+
# The final RE's:
|
299
|
+
P_RE_VERSION_DATE = "#{P_RE_LEADIN}#{P_RE_VERSION}#{P_RE_SEPARATOR}#{P_RE_DATE}"
|
300
|
+
P_RE_DATE_VERSION = "#{P_RE_LEADIN}#{P_RE_DATE}#{P_RE_SEPARATOR}#{P_RE_VERSION}"
|
301
|
+
|
302
|
+
# Detect release date, if found, store in attributes[:source_date_epoch]
|
303
|
+
def detect_source_date_from_changelog(installdir)
|
304
|
+
name = self.name.sub("rubygem-", "") + "-" + self.version
|
305
|
+
changelog = nil
|
306
|
+
datestr = nil
|
307
|
+
r1 = Regexp.new(P_RE_VERSION_DATE)
|
308
|
+
r2 = Regexp.new(P_RE_DATE_VERSION)
|
309
|
+
|
310
|
+
# Changelog doesn't have a standard name, so check all common variations
|
311
|
+
# Sort this list using LANG=C, i.e. caps first
|
312
|
+
[
|
313
|
+
"CHANGELIST",
|
314
|
+
"CHANGELOG", "CHANGELOG.asciidoc", "CHANGELOG.md", "CHANGELOG.rdoc", "CHANGELOG.rst", "CHANGELOG.txt",
|
315
|
+
"CHANGES", "CHANGES.md", "CHANGES.txt",
|
316
|
+
"ChangeLog", "ChangeLog.md", "ChangeLog.txt",
|
317
|
+
"Changelog", "Changelog.md", "Changelog.txt",
|
318
|
+
"changelog", "changelog.md", "changelog.txt",
|
319
|
+
].each do |changelogname|
|
320
|
+
path = File.join(installdir, "gems", name, changelogname)
|
321
|
+
if File.exist?(path)
|
322
|
+
changelog = path
|
323
|
+
File.open path do |file|
|
324
|
+
file.each_line do |line|
|
325
|
+
if line =~ /#{self.version}/
|
326
|
+
[r1, r2].each do |r|
|
327
|
+
if r.match(line)
|
328
|
+
datestr = $~[:date]
|
329
|
+
break
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
if datestr
|
338
|
+
date = Date.parse(datestr)
|
339
|
+
sec = date.strftime("%s")
|
340
|
+
attributes[:source_date_epoch] = sec
|
341
|
+
logger.debug("Gem %s has changelog date %s, setting source_date_epoch to %s" % [name, datestr, sec])
|
342
|
+
elsif changelog
|
343
|
+
logger.debug("Gem %s changelog %s did not have recognizable date for release %s" % [name, changelog, self.version])
|
344
|
+
else
|
345
|
+
logger.debug("Gem %s did not have changelog with recognized name" % [name])
|
346
|
+
# FIXME: check rubygems.org?
|
347
|
+
end
|
348
|
+
end # detect_source_date_from_changelog
|
349
|
+
|
242
350
|
public(:input, :output)
|
243
351
|
end # class FPM::Package::Gem
|
@@ -10,7 +10,7 @@ require "pleaserun/cli"
|
|
10
10
|
# This does not currently support 'output'
|
11
11
|
class FPM::Package::PleaseRun < FPM::Package
|
12
12
|
# TODO(sissel): Implement flags.
|
13
|
-
|
13
|
+
|
14
14
|
require "pleaserun/platform/systemd"
|
15
15
|
require "pleaserun/platform/upstart"
|
16
16
|
require "pleaserun/platform/launchd"
|
@@ -28,6 +28,10 @@ class FPM::Package::PleaseRun < FPM::Package
|
|
28
28
|
::PleaseRun::Platform::Launchd.new("10.9"), # OS X
|
29
29
|
::PleaseRun::Platform::SYSV.new("lsb-3.1") # Ancient stuff
|
30
30
|
]
|
31
|
+
pleaserun_attributes = [ "chdir", "user", "group", "umask", "chroot", "nice", "limit_coredump",
|
32
|
+
"limit_cputime", "limit_data", "limit_file_size", "limit_locked_memory",
|
33
|
+
"limit_open_files", "limit_user_processes", "limit_physical_memory", "limit_stack_size",
|
34
|
+
"log_directory", "log_file_stderr", "log_file_stdout"]
|
31
35
|
|
32
36
|
attributes[:pleaserun_name] ||= File.basename(command.first)
|
33
37
|
attributes[:prefix] ||= "/usr/share/pleaserun/#{attributes[:pleaserun_name]}"
|
@@ -37,12 +41,18 @@ class FPM::Package::PleaseRun < FPM::Package
|
|
37
41
|
platform.program = command.first
|
38
42
|
platform.name = attributes[:pleaserun_name]
|
39
43
|
platform.args = command[1..-1]
|
40
|
-
platform.chdir = attributes[:pleaserun_chdir] if attributes[:pleaserun_chdir]
|
41
44
|
platform.description = if attributes[:description_given?]
|
42
45
|
attributes[:description]
|
43
46
|
else
|
44
47
|
platform.name
|
45
48
|
end
|
49
|
+
pleaserun_attributes.each do |attribute_name|
|
50
|
+
attribute = "pleaserun_#{attribute_name}".to_sym
|
51
|
+
if attributes.has_key?(attribute) and not attributes[attribute].nil?
|
52
|
+
platform.send("#{attribute_name}=", attributes[attribute])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
46
56
|
base = staging_path(File.join(attributes[:prefix], "#{platform.platform}/#{platform.target_version || "default"}"))
|
47
57
|
target = File.join(base, "files")
|
48
58
|
actions_script = File.join(base, "install_actions.sh")
|
data/lib/fpm/package/python.rb
CHANGED
@@ -73,6 +73,10 @@ class FPM::Package::Python < FPM::Package
|
|
73
73
|
"The python package name to remove from dependency list",
|
74
74
|
:multivalued => true, :attribute_name => :python_disable_dependency,
|
75
75
|
:default => []
|
76
|
+
option "--setup-py-arguments", "setup_py_argument",
|
77
|
+
"Arbitrary argument(s) to be passed to setup.py",
|
78
|
+
:multivalued => true, :attribute_name => :python_setup_py_arguments,
|
79
|
+
:default => []
|
76
80
|
|
77
81
|
private
|
78
82
|
|
@@ -310,6 +314,13 @@ class FPM::Package::Python < FPM::Package
|
|
310
314
|
flags += [ "build_scripts", "--executable", attributes[:python_scripts_executable] ]
|
311
315
|
end
|
312
316
|
|
317
|
+
if !attributes[:python_setup_py_arguments].nil? and !attributes[:python_setup_py_arguments].empty?
|
318
|
+
# Add optional setup.py arguments
|
319
|
+
attributes[:python_setup_py_arguments].each do |a|
|
320
|
+
flags += [ a ]
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
313
324
|
safesystem(attributes[:python_bin], "setup.py", "install", *flags)
|
314
325
|
end
|
315
326
|
end # def install_to_staging
|
data/lib/fpm/package/rpm.rb
CHANGED
@@ -472,6 +472,15 @@ class FPM::Package::RPM < FPM::Package
|
|
472
472
|
self.directories = alldirs
|
473
473
|
end
|
474
474
|
|
475
|
+
# include external config files
|
476
|
+
(attributes[:config_files] or []).each do |conf|
|
477
|
+
path = conf
|
478
|
+
dest_conf = File.join(staging_path, path)
|
479
|
+
FileUtils.mkdir_p(File.dirname(dest_conf))
|
480
|
+
FileUtils.cp_r conf, dest_conf
|
481
|
+
File.chmod(0755, dest_conf)
|
482
|
+
end
|
483
|
+
|
475
484
|
# scan all conf file paths for files and add them
|
476
485
|
allconfigs = []
|
477
486
|
self.config_files.each do |path|
|
data/lib/fpm/package/tar.rb
CHANGED
@@ -50,15 +50,7 @@ class FPM::Package::Tar < FPM::Package
|
|
50
50
|
output_check(output_path)
|
51
51
|
|
52
52
|
# Write the scripts, too.
|
53
|
-
|
54
|
-
::Dir.mkdir(scripts_path)
|
55
|
-
[:before_install, :after_install, :before_remove, :after_remove].each do |name|
|
56
|
-
next unless script?(name)
|
57
|
-
out = File.join(scripts_path, name.to_s)
|
58
|
-
logger.debug("Writing script", :source => name, :target => out)
|
59
|
-
File.write(out, script(name))
|
60
|
-
File.chmod(0755, out)
|
61
|
-
end
|
53
|
+
write_scripts
|
62
54
|
|
63
55
|
# Unpack the tarball to the staging path
|
64
56
|
args = ["-cf", output_path, "-C", staging_path]
|
@@ -15,8 +15,11 @@ class FPM::Package::Virtualenv < FPM::Package
|
|
15
15
|
option "--package-name-prefix", "PREFIX", "Name to prefix the package " \
|
16
16
|
"name with.", :default => "virtualenv"
|
17
17
|
|
18
|
-
option "--install-location", "DIRECTORY", "
|
19
|
-
|
18
|
+
option "--install-location", "DIRECTORY", "DEPRECATED: Use --prefix instead." \
|
19
|
+
" Location to which to install the virtualenv by default.",
|
20
|
+
:default => "/usr/share/python" do |path|
|
21
|
+
logger.warn("Using deprecated flag: --install-location. Please use " \
|
22
|
+
"--prefix instead.")
|
20
23
|
File.expand_path(path)
|
21
24
|
end
|
22
25
|
|
@@ -37,6 +40,12 @@ class FPM::Package::Virtualenv < FPM::Package
|
|
37
40
|
option "--system-site-packages", :flag, "Give the virtual environment access to the "\
|
38
41
|
"global site-packages"
|
39
42
|
|
43
|
+
option "--find-links", "PIP_FIND_LINKS", "If a url or path to an html file, then parse for "\
|
44
|
+
"links to archives. If a local path or file:// url that's a directory, then look "\
|
45
|
+
"for archives in the directory listing.",
|
46
|
+
:multivalued => true, :attribute_name => :virtualenv_find_links_urls,
|
47
|
+
:default => nil
|
48
|
+
|
40
49
|
private
|
41
50
|
|
42
51
|
# Input a package.
|
@@ -76,9 +85,14 @@ class FPM::Package::Virtualenv < FPM::Package
|
|
76
85
|
self.name].join("-")
|
77
86
|
end
|
78
87
|
|
88
|
+
# prefix wins over previous virtual_install_location behaviour
|
79
89
|
virtualenv_folder =
|
80
|
-
|
81
|
-
|
90
|
+
if self.attributes[:prefix]
|
91
|
+
self.attributes[:prefix]
|
92
|
+
else
|
93
|
+
File.join(installdir,
|
94
|
+
virtualenv_name)
|
95
|
+
end
|
82
96
|
|
83
97
|
virtualenv_build_folder = build_path(virtualenv_folder)
|
84
98
|
|
@@ -107,6 +121,13 @@ class FPM::Package::Virtualenv < FPM::Package
|
|
107
121
|
end
|
108
122
|
end
|
109
123
|
|
124
|
+
find_links_url_args = []
|
125
|
+
if attributes[:virtualenv_find_links_urls]
|
126
|
+
attributes[:virtualenv_find_links_urls].each do |links_url|
|
127
|
+
find_links_url_args << "--find-links" << links_url
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
110
131
|
target_args = []
|
111
132
|
if is_requirements_file
|
112
133
|
target_args << "-r" << package
|
@@ -114,7 +135,7 @@ class FPM::Package::Virtualenv < FPM::Package
|
|
114
135
|
target_args << package
|
115
136
|
end
|
116
137
|
|
117
|
-
pip_args = [python_exe, pip_exe, "install", "-i", attributes[:virtualenv_pypi]] << extra_index_url_args << target_args
|
138
|
+
pip_args = [python_exe, pip_exe, "install", "-i", attributes[:virtualenv_pypi]] << extra_index_url_args << find_links_url_args << target_args
|
118
139
|
safesystem(*pip_args.flatten)
|
119
140
|
|
120
141
|
if attributes[:virtualenv_setup_install?]
|
@@ -155,7 +176,8 @@ class FPM::Package::Virtualenv < FPM::Package
|
|
155
176
|
# use dir to set stuff up properly, mainly so I don't have to reimplement
|
156
177
|
# the chdir/prefix stuff special for tar.
|
157
178
|
dir = convert(FPM::Package::Dir)
|
158
|
-
|
179
|
+
# don't double prefix the files
|
180
|
+
dir.attributes[:prefix] = nil
|
159
181
|
if attributes[:chdir]
|
160
182
|
dir.attributes[:chdir] = File.join(build_path, attributes[:chdir])
|
161
183
|
else
|
data/lib/fpm/package/zip.rb
CHANGED
@@ -36,28 +36,12 @@ class FPM::Package::Zip < FPM::Package
|
|
36
36
|
dir.cleanup_build
|
37
37
|
end # def input
|
38
38
|
|
39
|
-
# Output a
|
40
|
-
#
|
41
|
-
# If the output path ends predictably (like in .tar.gz) it will try to obey
|
42
|
-
# the compression type.
|
39
|
+
# Output a zipfile.
|
43
40
|
def output(output_path)
|
44
41
|
output_check(output_path)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end # def output
|
49
|
-
|
50
|
-
# Generate the proper tar flags based on the path name.
|
51
|
-
def tar_compression_flag(path)
|
52
|
-
case path
|
53
|
-
when /\.tar\.bz2$/
|
54
|
-
return "-j"
|
55
|
-
when /\.tar\.gz$|\.tgz$/
|
56
|
-
return "-z"
|
57
|
-
when /\.tar\.xz$/
|
58
|
-
return "-J"
|
59
|
-
else
|
60
|
-
return nil
|
42
|
+
realpath = Pathname.new(output_path).realdirpath.to_s
|
43
|
+
::Dir.chdir(staging_path) do
|
44
|
+
safesystem("zip", "-9r", realpath, ".")
|
61
45
|
end
|
62
|
-
end # def
|
46
|
+
end # def output
|
63
47
|
end # class FPM::Package::Tar
|
data/lib/fpm/util.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require "fpm/namespace"
|
2
2
|
require "childprocess"
|
3
3
|
require "ffi"
|
4
|
+
require "fileutils"
|
4
5
|
|
5
6
|
# Some utility functions
|
6
7
|
module FPM::Util
|
@@ -190,9 +191,14 @@ module FPM::Util
|
|
190
191
|
if args.size == 1
|
191
192
|
args = [ default_shell, "-c", args[0] ]
|
192
193
|
end
|
193
|
-
program = args[0]
|
194
194
|
|
195
|
-
|
195
|
+
if args[0].kind_of?(Hash)
|
196
|
+
env = args.shift()
|
197
|
+
exit_code = execmd(env, args)
|
198
|
+
else
|
199
|
+
exit_code = execmd(args)
|
200
|
+
end
|
201
|
+
program = args[0]
|
196
202
|
success = (exit_code == 0)
|
197
203
|
|
198
204
|
if !success
|
@@ -226,26 +232,90 @@ module FPM::Util
|
|
226
232
|
return stdout_r_str
|
227
233
|
end # def safesystemout
|
228
234
|
|
235
|
+
# Get an array containing the recommended 'ar' command for this platform
|
236
|
+
# and the recommended options to quickly create/append to an archive
|
237
|
+
# without timestamps or uids (if possible).
|
238
|
+
def ar_cmd
|
239
|
+
return @@ar_cmd if defined? @@ar_cmd
|
240
|
+
|
241
|
+
@@ar_cmd_deterministic = false
|
242
|
+
|
243
|
+
# FIXME: don't assume current directory writeable
|
244
|
+
FileUtils.touch(["fpm-dummy.tmp"])
|
245
|
+
["ar", "gar"].each do |ar|
|
246
|
+
["-qc", "-qcD"].each do |ar_create_opts|
|
247
|
+
FileUtils.rm_f(["fpm-dummy.ar.tmp"])
|
248
|
+
# Return this combination if it creates archives without uids or timestamps.
|
249
|
+
# Exitstatus will be nonzero if the archive can't be created,
|
250
|
+
# or its table of contents doesn't match the regular expression.
|
251
|
+
# Be extra-careful about locale and timezone when matching output.
|
252
|
+
system("#{ar} #{ar_create_opts} fpm-dummy.ar.tmp fpm-dummy.tmp 2>/dev/null && env TZ=UTC LANG=C LC_TIME=C #{ar} -tv fpm-dummy.ar.tmp | grep '0/0.*1970' > /dev/null 2>&1")
|
253
|
+
if $?.exitstatus == 0
|
254
|
+
@@ar_cmd = [ar, ar_create_opts]
|
255
|
+
@@ar_cmd_deterministic = true
|
256
|
+
return @@ar_cmd
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
# If no combination of ar and options omits timestamps, fall back to default.
|
261
|
+
@@ar_cmd = ["ar", "-qc"]
|
262
|
+
return @@ar_cmd
|
263
|
+
ensure
|
264
|
+
# Clean up
|
265
|
+
FileUtils.rm_f(["fpm-dummy.ar.tmp", "fpm-dummy.tmp"])
|
266
|
+
end # def ar_cmd
|
267
|
+
|
268
|
+
# Return whether the command returned by ar_cmd can create deterministic archives
|
269
|
+
def ar_cmd_deterministic?
|
270
|
+
ar_cmd if not defined? @@ar_cmd_deterministic
|
271
|
+
return @@ar_cmd_deterministic
|
272
|
+
end
|
273
|
+
|
229
274
|
# Get the recommended 'tar' command for this platform.
|
230
275
|
def tar_cmd
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
276
|
+
return @@tar_cmd if defined? @@tar_cmd
|
277
|
+
|
278
|
+
# FIXME: don't assume current directory writeable
|
279
|
+
FileUtils.touch(["fpm-dummy.tmp"])
|
280
|
+
|
281
|
+
# Prefer tar that supports more of the features we want, stop if we find tar of our dreams
|
282
|
+
best="tar"
|
283
|
+
bestscore=0
|
284
|
+
@@tar_cmd_deterministic = false
|
285
|
+
# GNU Tar, if not the default, is usually on the path as gtar, but
|
286
|
+
# Mac OS X 10.8 and earlier shipped it as /usr/bin/gnutar
|
287
|
+
["tar", "gtar", "gnutar"].each do |tar|
|
288
|
+
opts=[]
|
289
|
+
score=0
|
290
|
+
["--sort=name", "--mtime=@0"].each do |opt|
|
291
|
+
system("#{tar} #{opt} -cf fpm-dummy.tar.tmp fpm-dummy.tmp > /dev/null 2>&1")
|
292
|
+
if $?.exitstatus == 0
|
293
|
+
opts << opt
|
294
|
+
score += 1
|
295
|
+
end
|
296
|
+
end
|
297
|
+
if score > bestscore
|
298
|
+
best=tar
|
299
|
+
bestscore=score
|
300
|
+
if score == 2
|
301
|
+
@@tar_cmd_deterministic = true
|
302
|
+
break
|
303
|
+
end
|
240
304
|
end
|
241
|
-
when "FreeBSD"
|
242
|
-
# use gnutar instead
|
243
|
-
return "gtar"
|
244
|
-
else
|
245
|
-
return "tar"
|
246
305
|
end
|
306
|
+
@@tar_cmd = best
|
307
|
+
return @@tar_cmd
|
308
|
+
ensure
|
309
|
+
# Clean up
|
310
|
+
FileUtils.rm_f(["fpm-dummy.tar.tmp", "fpm-dummy.tmp"])
|
247
311
|
end # def tar_cmd
|
248
312
|
|
313
|
+
# Return whether the command returned by tar_cmd can create deterministic archives
|
314
|
+
def tar_cmd_supports_sort_names_and_set_mtime?
|
315
|
+
tar_cmd if not defined? @@tar_cmd_deterministic
|
316
|
+
return @@tar_cmd_deterministic
|
317
|
+
end
|
318
|
+
|
249
319
|
# wrapper around mknod ffi calls
|
250
320
|
def mknod_w(path, mode, dev)
|
251
321
|
rc = -1
|
@@ -298,8 +368,8 @@ module FPM::Util
|
|
298
368
|
if known_entry
|
299
369
|
FileUtils.ln(known_entry, dst)
|
300
370
|
else
|
301
|
-
FileUtils.copy_entry(src, dst, preserve
|
302
|
-
remove_destination
|
371
|
+
FileUtils.copy_entry(src, dst, preserve, false,
|
372
|
+
remove_destination)
|
303
373
|
copied_entries[[st.dev, st.ino]] = dst
|
304
374
|
end
|
305
375
|
end # else...
|