fpm-aeppert 1.6.2 → 1.11.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 +5 -5
- data/CHANGELOG.rst +617 -0
- data/CONTRIBUTORS +1 -0
- data/LICENSE +1 -1
- data/bin/fpm +0 -1
- data/lib/fpm.rb +1 -0
- data/lib/fpm/command.rb +26 -12
- data/lib/fpm/package.rb +24 -4
- data/lib/fpm/package/apk.rb +6 -6
- data/lib/fpm/package/cpan.rb +57 -29
- data/lib/fpm/package/deb.rb +177 -40
- data/lib/fpm/package/dir.rb +12 -17
- data/lib/fpm/package/empty.rb +1 -1
- data/lib/fpm/package/freebsd.rb +25 -14
- data/lib/fpm/package/gem.rb +148 -13
- data/lib/fpm/package/pacman.rb +1 -1
- data/lib/fpm/package/pleaserun.rb +13 -1
- data/lib/fpm/package/pyfpm/get_metadata.py +5 -0
- data/lib/fpm/package/python.rb +13 -2
- data/lib/fpm/package/rpm.rb +43 -7
- data/lib/fpm/package/sh.rb +1 -1
- data/lib/fpm/package/snap.rb +130 -0
- data/lib/fpm/package/tar.rb +2 -10
- data/lib/fpm/package/virtualenv.rb +53 -12
- data/lib/fpm/package/zip.rb +6 -22
- data/lib/fpm/util.rb +88 -18
- data/lib/fpm/util/tar_writer.rb +2 -0
- data/lib/fpm/version.rb +1 -1
- data/templates/deb.erb +1 -1
- data/templates/deb/changelog.erb +1 -1
- data/templates/deb/deb.changes.erb +30 -0
- data/templates/deb/postinst_upgrade.sh.erb +24 -8
- data/templates/deb/postrm_upgrade.sh.erb +12 -5
- data/templates/deb/prerm_upgrade.sh.erb +7 -4
- data/templates/rpm.erb +12 -9
- metadata +84 -76
- data/CHANGELIST +0 -661
data/lib/fpm/package/rpm.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require "fpm/package"
|
2
|
-
require "backports"
|
2
|
+
require "backports/latest"
|
3
3
|
require "fileutils"
|
4
4
|
require "find"
|
5
5
|
require "arr-pm/file" # gem 'arr-pm'
|
@@ -24,9 +24,10 @@ class FPM::Package::RPM < FPM::Package
|
|
24
24
|
|
25
25
|
COMPRESSION_MAP = {
|
26
26
|
"none" => "w0.gzdio",
|
27
|
-
"xz" => "
|
28
|
-
"
|
29
|
-
"
|
27
|
+
"xz" => ".xzdio",
|
28
|
+
"xzmt" => "T.xzdio",
|
29
|
+
"gzip" => ".gzdio",
|
30
|
+
"bzip2" => ".bzdio"
|
30
31
|
} unless defined?(COMPRESSION_MAP)
|
31
32
|
|
32
33
|
option "--use-file-permissions", :flag,
|
@@ -67,6 +68,15 @@ class FPM::Package::RPM < FPM::Package
|
|
67
68
|
value.downcase
|
68
69
|
end
|
69
70
|
|
71
|
+
option "--compression-level", "[0-9]", "Select a compression level. 0 is store-only. 9 is max compression.",
|
72
|
+
:default => "9" do |value|
|
73
|
+
valint = value.to_i
|
74
|
+
unless value =~ /^\d$/ && valint >= 0 && valint <= 9
|
75
|
+
raise "Invalid compression level '#{value}'. Valid values are integers between 0 and 9 inclusive."
|
76
|
+
end
|
77
|
+
valint
|
78
|
+
end
|
79
|
+
|
70
80
|
option "--compression", COMPRESSION_MAP.keys.join("|"),
|
71
81
|
"Select a compression method. gzip works on the most platforms.",
|
72
82
|
:default => "gzip" do |value|
|
@@ -141,6 +151,10 @@ class FPM::Package::RPM < FPM::Package
|
|
141
151
|
"names in rpm requires instead of the redhat style " \
|
142
152
|
"rubygem(foo).", :default => false
|
143
153
|
|
154
|
+
option "--macro-expansion", :flag,
|
155
|
+
"install-time macro expansion in %pre %post %preun %postun scripts " \
|
156
|
+
"(see: https://rpm.org/user_doc/scriptlet_expansion.html)", :default => false
|
157
|
+
|
144
158
|
option "--verifyscript", "FILE",
|
145
159
|
"a script to be run on verification" do |val|
|
146
160
|
File.expand_path(val) # Get the full path to the script
|
@@ -472,6 +486,22 @@ class FPM::Package::RPM < FPM::Package
|
|
472
486
|
self.directories = alldirs
|
473
487
|
end
|
474
488
|
|
489
|
+
# include external config files
|
490
|
+
(attributes[:config_files] or []).each do |conf|
|
491
|
+
dest_conf = File.join(staging_path, conf)
|
492
|
+
|
493
|
+
if File.exist?(dest_conf)
|
494
|
+
logger.debug("Using --config-file from staging area", :path => conf)
|
495
|
+
elsif File.exist?(conf)
|
496
|
+
logger.info("Copying --config-file from local path", :path => conf)
|
497
|
+
FileUtils.mkdir_p(File.dirname(dest_conf))
|
498
|
+
FileUtils.cp_r conf, dest_conf
|
499
|
+
else
|
500
|
+
logger.error("Failed to find given --config-file", :path => conf)
|
501
|
+
raise "Could not find config file '#{conf}' in staging area or on host. This can happen if you specify `--config-file '#{conf}'` but this file does not exist in the source package and also does not exist in filesystem."
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
475
505
|
# scan all conf file paths for files and add them
|
476
506
|
allconfigs = []
|
477
507
|
self.config_files.each do |path|
|
@@ -499,10 +529,11 @@ class FPM::Package::RPM < FPM::Package
|
|
499
529
|
end
|
500
530
|
|
501
531
|
# copy all files from staging to BUILD dir
|
532
|
+
# [#1538] Be sure to preserve the original timestamps.
|
502
533
|
Find.find(staging_path) do |path|
|
503
534
|
src = path.gsub(/^#{staging_path}/, '')
|
504
535
|
dst = File.join(build_path, build_sub_dir, src)
|
505
|
-
copy_entry(path, dst)
|
536
|
+
copy_entry(path, dst, preserve=true)
|
506
537
|
end
|
507
538
|
|
508
539
|
rpmspec = template("rpm.erb").result(binding)
|
@@ -537,7 +568,7 @@ class FPM::Package::RPM < FPM::Package
|
|
537
568
|
|
538
569
|
def summary
|
539
570
|
if !attributes[:rpm_summary]
|
540
|
-
return @description.split("\n").
|
571
|
+
return @description.split("\n").find { |line| !line.strip.empty? } || "_"
|
541
572
|
end
|
542
573
|
|
543
574
|
return attributes[:rpm_summary]
|
@@ -580,7 +611,12 @@ class FPM::Package::RPM < FPM::Package
|
|
580
611
|
end # def to_s
|
581
612
|
|
582
613
|
def payload_compression
|
583
|
-
|
614
|
+
if attributes[:rpm_compression] == 'none'
|
615
|
+
# when 'none' ignore any compression level and return w0.gzdio
|
616
|
+
return COMPRESSION_MAP[attributes[:rpm_compression]]
|
617
|
+
else
|
618
|
+
return "w#{attributes[:rpm_compression_level]}" + COMPRESSION_MAP[attributes[:rpm_compression]]
|
619
|
+
end
|
584
620
|
end # def payload_compression
|
585
621
|
|
586
622
|
def digest_algorithm
|
data/lib/fpm/package/sh.rb
CHANGED
@@ -0,0 +1,130 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
3
|
+
require "fpm/package"
|
4
|
+
require "fpm/util"
|
5
|
+
require "fileutils"
|
6
|
+
require "fpm/package/dir"
|
7
|
+
|
8
|
+
# Support for snaps (.snap files).
|
9
|
+
#
|
10
|
+
# This supports the input and output of snaps.
|
11
|
+
class FPM::Package::Snap < FPM::Package
|
12
|
+
|
13
|
+
option "--yaml", "FILEPATH",
|
14
|
+
"Custom version of the snap.yaml file." do | snap_yaml |
|
15
|
+
File.expand_path(snap_yaml)
|
16
|
+
end
|
17
|
+
|
18
|
+
option "--confinement", "CONFINEMENT",
|
19
|
+
"Type of confinement to use for this snap.",
|
20
|
+
default: "devmode" do | confinement |
|
21
|
+
if ['strict', 'devmode', 'classic'].include? confinement
|
22
|
+
confinement
|
23
|
+
else
|
24
|
+
raise "Unsupported confinement type '#{confinement}'"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
option "--grade", "GRADE", "Grade of this snap.",
|
29
|
+
default: "devel" do | grade |
|
30
|
+
if ['stable', 'devel'].include? grade
|
31
|
+
grade
|
32
|
+
else
|
33
|
+
raise "Unsupported grade type '#{grade}'"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Input a snap
|
38
|
+
def input(input_snap)
|
39
|
+
extract_snap_to_staging input_snap
|
40
|
+
extract_snap_metadata_from_staging
|
41
|
+
end # def input
|
42
|
+
|
43
|
+
# Output a snap.
|
44
|
+
def output(output_snap)
|
45
|
+
output_check(output_snap)
|
46
|
+
|
47
|
+
write_snap_yaml
|
48
|
+
|
49
|
+
# Create the snap from the staging path
|
50
|
+
safesystem("mksquashfs", staging_path, output_snap, "-noappend", "-comp",
|
51
|
+
"xz", "-no-xattrs", "-no-fragments", "-all-root")
|
52
|
+
end # def output
|
53
|
+
|
54
|
+
def to_s(format=nil)
|
55
|
+
# Default format if nil
|
56
|
+
# name_version_arch.snap
|
57
|
+
return super(format.nil? ? "NAME_FULLVERSION_ARCH.EXTENSION" : format)
|
58
|
+
end # def to_s
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def extract_snap_to_staging(snap_path)
|
63
|
+
safesystem("unsquashfs", "-f", "-d", staging_path, snap_path)
|
64
|
+
end
|
65
|
+
|
66
|
+
def extract_snap_metadata_from_staging
|
67
|
+
metadata = YAML.safe_load(File.read(
|
68
|
+
staging_path(File.join("meta", "snap.yaml"))))
|
69
|
+
|
70
|
+
self.name = metadata["name"]
|
71
|
+
self.version = metadata["version"]
|
72
|
+
self.description = metadata["summary"] + "\n" + metadata["description"]
|
73
|
+
self.architecture = metadata["architectures"][0]
|
74
|
+
self.attributes[:snap_confinement] = metadata["confinement"]
|
75
|
+
self.attributes[:snap_grade] = metadata["grade"]
|
76
|
+
|
77
|
+
if metadata["apps"].nil?
|
78
|
+
attributes[:snap_apps] = []
|
79
|
+
else
|
80
|
+
attributes[:snap_apps] = metadata["apps"]
|
81
|
+
end
|
82
|
+
|
83
|
+
if metadata["hooks"].nil?
|
84
|
+
attributes[:snap_hooks] = []
|
85
|
+
else
|
86
|
+
attributes[:snap_hooks] = metadata["hooks"]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def write_snap_yaml
|
91
|
+
# Write the snap.yaml
|
92
|
+
if attributes[:snap_yaml]
|
93
|
+
logger.debug("Using '#{attributes[:snap_yaml]}' as the snap.yaml")
|
94
|
+
yaml_data = File.read(attributes[:snap_yaml])
|
95
|
+
else
|
96
|
+
summary, *remainder = (self.description or "no summary given").split("\n")
|
97
|
+
description = "no description given"
|
98
|
+
if remainder.any?
|
99
|
+
description = remainder.join("\n")
|
100
|
+
end
|
101
|
+
|
102
|
+
yaml_data = {
|
103
|
+
"name" => self.name,
|
104
|
+
"version" => self.version,
|
105
|
+
"summary" => summary,
|
106
|
+
"description" => description,
|
107
|
+
"architectures" => [self.architecture],
|
108
|
+
"confinement" => self.attributes[:snap_confinement],
|
109
|
+
"grade" => self.attributes[:snap_grade],
|
110
|
+
}
|
111
|
+
|
112
|
+
unless attributes[:snap_apps].nil? or attributes[:snap_apps].empty?
|
113
|
+
yaml_data["apps"] = attributes[:snap_apps]
|
114
|
+
end
|
115
|
+
|
116
|
+
unless attributes[:snap_hooks].nil? or attributes[:snap_hooks].empty?
|
117
|
+
yaml_data["hooks"] = attributes[:snap_hooks]
|
118
|
+
end
|
119
|
+
|
120
|
+
yaml_data = yaml_data.to_yaml
|
121
|
+
end
|
122
|
+
|
123
|
+
FileUtils.mkdir_p(staging_path("meta"))
|
124
|
+
snap_yaml_path = staging_path(File.join("meta", "snap.yaml"))
|
125
|
+
logger.debug("Writing snap.yaml", :path => snap_yaml_path)
|
126
|
+
File.write(snap_yaml_path, yaml_data)
|
127
|
+
File.chmod(0644, snap_yaml_path)
|
128
|
+
edit_file(snap_yaml_path) if attributes[:edit?]
|
129
|
+
end # def write_snap_yaml
|
130
|
+
end # class FPM::Package::Snap
|
data/lib/fpm/package/tar.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require "backports" # gem backports
|
1
|
+
require "backports/latest" # gem backports
|
2
2
|
require "fpm/package"
|
3
3
|
require "fpm/util"
|
4
4
|
require "fileutils"
|
@@ -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
|
|
@@ -30,6 +33,19 @@ class FPM::Package::Virtualenv < FPM::Package
|
|
30
33
|
:multivalued => true, :attribute_name => :virtualenv_pypi_extra_index_urls,
|
31
34
|
:default => nil
|
32
35
|
|
36
|
+
option "--setup-install", :flag, "After building virtualenv run setup.py install "\
|
37
|
+
"useful when building a virtualenv for packages and including their requirements from "
|
38
|
+
"requirements.txt"
|
39
|
+
|
40
|
+
option "--system-site-packages", :flag, "Give the virtual environment access to the "\
|
41
|
+
"global site-packages"
|
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
|
+
|
33
49
|
private
|
34
50
|
|
35
51
|
# Input a package.
|
@@ -69,23 +85,33 @@ class FPM::Package::Virtualenv < FPM::Package
|
|
69
85
|
self.name].join("-")
|
70
86
|
end
|
71
87
|
|
88
|
+
# prefix wins over previous virtual_install_location behaviour
|
72
89
|
virtualenv_folder =
|
73
|
-
|
74
|
-
|
90
|
+
if self.attributes[:prefix]
|
91
|
+
self.attributes[:prefix]
|
92
|
+
else
|
93
|
+
File.join(installdir,
|
94
|
+
virtualenv_name)
|
95
|
+
end
|
75
96
|
|
76
97
|
virtualenv_build_folder = build_path(virtualenv_folder)
|
77
98
|
|
78
99
|
::FileUtils.mkdir_p(virtualenv_build_folder)
|
79
100
|
|
80
|
-
|
101
|
+
if self.attributes[:virtualenv_system_site_packages?]
|
102
|
+
logger.info("Creating virtualenv with --system-site-packages")
|
103
|
+
safesystem("virtualenv", "--system-site-packages", virtualenv_build_folder)
|
104
|
+
else
|
105
|
+
safesystem("virtualenv", virtualenv_build_folder)
|
106
|
+
end
|
107
|
+
|
81
108
|
pip_exe = File.join(virtualenv_build_folder, "bin", "pip")
|
82
109
|
python_exe = File.join(virtualenv_build_folder, "bin", "python")
|
83
110
|
|
84
111
|
# Why is this hack here? It looks important, so I'll keep it in.
|
85
|
-
safesystem(pip_exe, "install", "-U", "-i",
|
112
|
+
safesystem(python_exe, pip_exe, "install", "-U", "-i",
|
86
113
|
attributes[:virtualenv_pypi],
|
87
|
-
"pip"
|
88
|
-
safesystem(pip_exe, "uninstall", "-y", "distribute")
|
114
|
+
"pip")
|
89
115
|
|
90
116
|
extra_index_url_args = []
|
91
117
|
if attributes[:virtualenv_pypi_extra_index_urls]
|
@@ -94,6 +120,13 @@ class FPM::Package::Virtualenv < FPM::Package
|
|
94
120
|
end
|
95
121
|
end
|
96
122
|
|
123
|
+
find_links_url_args = []
|
124
|
+
if attributes[:virtualenv_find_links_urls]
|
125
|
+
attributes[:virtualenv_find_links_urls].each do |links_url|
|
126
|
+
find_links_url_args << "--find-links" << links_url
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
97
130
|
target_args = []
|
98
131
|
if is_requirements_file
|
99
132
|
target_args << "-r" << package
|
@@ -101,12 +134,19 @@ class FPM::Package::Virtualenv < FPM::Package
|
|
101
134
|
target_args << package
|
102
135
|
end
|
103
136
|
|
104
|
-
pip_args = [pip_exe, "install", "-i", attributes[:virtualenv_pypi]] << extra_index_url_args << target_args
|
137
|
+
pip_args = [python_exe, pip_exe, "install", "-i", attributes[:virtualenv_pypi]] << extra_index_url_args << find_links_url_args << target_args
|
105
138
|
safesystem(*pip_args.flatten)
|
106
139
|
|
140
|
+
if attributes[:virtualenv_setup_install?]
|
141
|
+
logger.info("Running PACKAGE setup.py")
|
142
|
+
setup_args = [python_exe, "setup.py", "install"]
|
143
|
+
safesystem(*setup_args.flatten)
|
144
|
+
end
|
145
|
+
|
107
146
|
if ! is_requirements_file && package_version.nil?
|
108
|
-
frozen = safesystemout(pip_exe, "freeze")
|
109
|
-
|
147
|
+
frozen = safesystemout(python_exe, pip_exe, "freeze")
|
148
|
+
frozen_version = frozen[/#{package}==[^=]+$/]
|
149
|
+
package_version = frozen_version && frozen_version.split("==")[1].chomp!
|
110
150
|
self.version ||= package_version
|
111
151
|
end
|
112
152
|
|
@@ -135,7 +175,8 @@ class FPM::Package::Virtualenv < FPM::Package
|
|
135
175
|
# use dir to set stuff up properly, mainly so I don't have to reimplement
|
136
176
|
# the chdir/prefix stuff special for tar.
|
137
177
|
dir = convert(FPM::Package::Dir)
|
138
|
-
|
178
|
+
# don't double prefix the files
|
179
|
+
dir.attributes[:prefix] = nil
|
139
180
|
if attributes[:chdir]
|
140
181
|
dir.attributes[:chdir] = File.join(build_path, attributes[:chdir])
|
141
182
|
else
|
data/lib/fpm/package/zip.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require "backports" # gem backports
|
1
|
+
require "backports/latest" # gem backports
|
2
2
|
require "fpm/package"
|
3
3
|
require "fpm/util"
|
4
4
|
require "fileutils"
|
@@ -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...
|