fpm 1.8.1 → 1.9.1
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/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...
|