fpm 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELIST +32 -1
- data/lib/fpm.rb +1 -0
- data/lib/fpm/command.rb +49 -30
- data/lib/fpm/package.rb +4 -4
- data/lib/fpm/package/cpan.rb +20 -7
- data/lib/fpm/package/deb.rb +160 -32
- data/lib/fpm/package/dir.rb +2 -2
- data/lib/fpm/package/freebsd.rb +165 -0
- data/lib/fpm/package/osxpkg.rb +2 -2
- data/lib/fpm/package/pacman.rb +398 -0
- data/lib/fpm/package/pyfpm/__init__.pyc +0 -0
- data/lib/fpm/package/pyfpm/get_metadata.pyc +0 -0
- data/lib/fpm/package/rpm.rb +33 -7
- data/lib/fpm/package/tar.rb +2 -2
- data/lib/fpm/package/virtualenv.rb +12 -3
- data/lib/fpm/rake_task.rb +59 -0
- data/lib/fpm/util.rb +3 -6
- data/lib/fpm/version.rb +1 -1
- data/templates/deb/postinst_upgrade.sh.erb +19 -0
- data/templates/deb/prerm_upgrade.sh.erb +7 -0
- data/templates/pacman.erb +47 -0
- data/templates/pacman/INSTALL.erb +41 -0
- data/templates/rpm.erb +4 -1
- data/templates/sh.erb +16 -2
- metadata +67 -4
data/lib/fpm/package/dir.rb
CHANGED
@@ -128,7 +128,7 @@ class FPM::Package::Dir < FPM::Package
|
|
128
128
|
"to stage files during packaging, so this setting would have " \
|
129
129
|
"caused fpm to loop creating staging directories and copying " \
|
130
130
|
"them into your package! Oops! If you are confused, maybe you could " \
|
131
|
-
"check your TMPDIR or
|
131
|
+
"check your TMPDIR, TMP, or TEMP environment variables?"
|
132
132
|
end
|
133
133
|
|
134
134
|
# For single file copies, permit file destinations
|
@@ -160,7 +160,7 @@ class FPM::Package::Dir < FPM::Package
|
|
160
160
|
# lstat to follow symlinks
|
161
161
|
dstat = File.stat(directory) rescue nil
|
162
162
|
if dstat.nil?
|
163
|
-
FileUtils.mkdir_p(directory)
|
163
|
+
FileUtils.mkdir_p(directory, :mode => 0755)
|
164
164
|
elsif dstat.directory?
|
165
165
|
# do nothing, it's already a directory!
|
166
166
|
else
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require "backports" # gem backports
|
2
|
+
require "fpm/package"
|
3
|
+
require "fpm/util"
|
4
|
+
require "digest"
|
5
|
+
require "fileutils"
|
6
|
+
require "rubygems/package"
|
7
|
+
require "xz"
|
8
|
+
require "corefines"
|
9
|
+
|
10
|
+
class FPM::Package::FreeBSD < FPM::Package
|
11
|
+
SCRIPT_MAP = {
|
12
|
+
:before_install => "pre-install",
|
13
|
+
:after_install => "post-install",
|
14
|
+
:before_remove => "pre-deinstall",
|
15
|
+
:after_remove => "post-deinstall",
|
16
|
+
} unless defined?(SCRIPT_MAP)
|
17
|
+
|
18
|
+
def self.default_abi
|
19
|
+
abi_name = %x{uname -s}.chomp
|
20
|
+
abi_version = %x{uname -r}.chomp.split(".")[0]
|
21
|
+
abi_arch = %x{uname -m}.chomp
|
22
|
+
|
23
|
+
[abi_name, abi_version, abi_arch].join(":")
|
24
|
+
end
|
25
|
+
|
26
|
+
option "--abi", "ABI",
|
27
|
+
"Sets the FreeBSD abi pkg field to specify binary compatibility.",
|
28
|
+
:default => default_abi
|
29
|
+
|
30
|
+
option "--origin", "ABI",
|
31
|
+
"Sets the FreeBSD 'origin' pkg field",
|
32
|
+
:default => "fpm/<name>"
|
33
|
+
|
34
|
+
def output(output_path)
|
35
|
+
output_check(output_path)
|
36
|
+
|
37
|
+
# Build the packaging metadata files.
|
38
|
+
checksums = {}
|
39
|
+
self.files.each do |f|
|
40
|
+
path = staging_path(f)
|
41
|
+
if File.symlink?(path)
|
42
|
+
checksums[f] = "-"
|
43
|
+
elsif File.file?(path)
|
44
|
+
checksums[f] = Digest::SHA256.file(path).hexdigest
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
pkg_origin = attributes[:freebsd_origin]
|
49
|
+
if pkg_origin == "fpm/<name>" # fill in default
|
50
|
+
pkg_origin = "fpm/#{name}"
|
51
|
+
end
|
52
|
+
|
53
|
+
pkg_version = "#{version}-#{iteration || 1}"
|
54
|
+
|
55
|
+
pkgdata = {
|
56
|
+
"abi" => attributes[:freebsd_abi],
|
57
|
+
"name" => name,
|
58
|
+
"version" => pkg_version,
|
59
|
+
"comment" => description,
|
60
|
+
"desc" => description,
|
61
|
+
"origin" => pkg_origin,
|
62
|
+
"maintainer" => maintainer,
|
63
|
+
"www" => url,
|
64
|
+
# prefix is required, but it doesn't seem to matter
|
65
|
+
"prefix" => "/",
|
66
|
+
}
|
67
|
+
|
68
|
+
# Write +COMPACT_MANIFEST, without the "files" section.
|
69
|
+
File.open(staging_path("+COMPACT_MANIFEST"), "w+") do |file|
|
70
|
+
file.write(pkgdata.to_json + "\n")
|
71
|
+
end
|
72
|
+
|
73
|
+
# Populate files + checksums, then write +MANIFEST.
|
74
|
+
pkgdata["files"] = {}
|
75
|
+
checksums.each do |f, shasum|
|
76
|
+
# pkg expands % URL-style escapes, so make sure to escape % as %25
|
77
|
+
pkgdata["files"]["/" + f.gsub("%", "%25")] = shasum
|
78
|
+
end
|
79
|
+
|
80
|
+
# Populate scripts
|
81
|
+
pkgdata["scripts"] = {}
|
82
|
+
scripts.each do |name, data|
|
83
|
+
pkgdata["scripts"][SCRIPT_MAP[name]] = data
|
84
|
+
end
|
85
|
+
|
86
|
+
File.open(staging_path("+MANIFEST"), "w+") do |file|
|
87
|
+
file.write(pkgdata.to_json + "\n")
|
88
|
+
end
|
89
|
+
|
90
|
+
# Create the .txz package archive from the files in staging_path.
|
91
|
+
File.open(output_path, "wb") do |file|
|
92
|
+
XZ::StreamWriter.new(file) do |xz|
|
93
|
+
::Gem::Package::TarWriter.new(xz) do |tar|
|
94
|
+
# The manifests must come first for pkg.
|
95
|
+
add_path(tar, "+COMPACT_MANIFEST",
|
96
|
+
File.join(staging_path, "+COMPACT_MANIFEST"))
|
97
|
+
add_path(tar, "+MANIFEST",
|
98
|
+
File.join(staging_path, "+MANIFEST"))
|
99
|
+
|
100
|
+
checksums.keys.each do |path|
|
101
|
+
add_path(tar, "/" + path, File.join(staging_path, path))
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end # def output
|
107
|
+
|
108
|
+
def add_path(tar, tar_path, path)
|
109
|
+
stat = File.lstat(path)
|
110
|
+
if stat.directory?
|
111
|
+
tar.mkdir(tar_path, stat.mode)
|
112
|
+
elsif stat.symlink?
|
113
|
+
tar.add_symlink(tar_path, File.readlink(path), stat.mode)
|
114
|
+
else
|
115
|
+
tar.add_file_simple(tar_path, stat.mode, stat.size) do |io|
|
116
|
+
File.open(path) do |fd|
|
117
|
+
chunk = nil
|
118
|
+
size = 0
|
119
|
+
while chunk = fd.read(16384) do
|
120
|
+
size += io.write(chunk)
|
121
|
+
end
|
122
|
+
if size != stat.size
|
123
|
+
raise "Failed to add #{path} to the archive; expected to " +
|
124
|
+
"write #{stat.size} bytes, only wrote #{size}"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end # tar.tar.add_file_simple
|
128
|
+
end
|
129
|
+
end # def add_path
|
130
|
+
|
131
|
+
def to_s(format=nil)
|
132
|
+
return "#{name}-#{version}_#{iteration || 1}.txz"
|
133
|
+
return super(format)
|
134
|
+
end # def to_s
|
135
|
+
end # class FPM::Package::FreeBSD
|
136
|
+
|
137
|
+
# Backport Symlink Support to TarWriter
|
138
|
+
# https://github.com/rubygems/rubygems/blob/4a778c9c2489745e37bcc2d0a8f12c601a9c517f/lib/rubygems/package/tar_writer.rb#L239-L253
|
139
|
+
module TarWriterAddSymlink
|
140
|
+
refine Gem::Package::TarWriter do
|
141
|
+
def add_symlink(name, target, mode)
|
142
|
+
check_closed
|
143
|
+
|
144
|
+
name, prefix = split_name name
|
145
|
+
|
146
|
+
header = Gem::Package::TarHeader.new(:name => name, :mode => mode,
|
147
|
+
:size => 0, :typeflag => "2",
|
148
|
+
:linkname => target,
|
149
|
+
:prefix => prefix,
|
150
|
+
:mtime => Time.now).to_s
|
151
|
+
|
152
|
+
@io.write header
|
153
|
+
|
154
|
+
self
|
155
|
+
end # def add_symlink
|
156
|
+
end # refine Gem::Package::TarWriter
|
157
|
+
end # module TarWriterAddSymlink
|
158
|
+
|
159
|
+
module Util
|
160
|
+
module Tar
|
161
|
+
unless Gem::Package::TarWriter.public_instance_methods.include? :add_symlink
|
162
|
+
using TarWriterAddSymlink
|
163
|
+
end
|
164
|
+
end # module Tar
|
165
|
+
end # module Util
|
data/lib/fpm/package/osxpkg.rb
CHANGED
@@ -81,7 +81,7 @@ class FPM::Package::OSXpkg < FPM::Package
|
|
81
81
|
SCRIPT_MAP.each do |scriptname, filename|
|
82
82
|
next unless script?(scriptname)
|
83
83
|
|
84
|
-
|
84
|
+
scripts_path(filename).tap do |pkgscript|
|
85
85
|
logger.info("Writing pkg script", :source => filename, :target => pkgscript)
|
86
86
|
File.write(pkgscript, script(scriptname))
|
87
87
|
# scripts are required to be executable
|
@@ -103,7 +103,7 @@ class FPM::Package::OSXpkg < FPM::Package
|
|
103
103
|
|
104
104
|
# Extract name and version from PackageInfo XML
|
105
105
|
def extract_info(package)
|
106
|
-
|
106
|
+
build_path("expand").tap do |path|
|
107
107
|
doc = REXML::Document.new File.open(File.join(path, "PackageInfo"))
|
108
108
|
pkginfo_elem = doc.elements["pkg-info"]
|
109
109
|
identifier = pkginfo_elem.attribute("identifier").value
|
@@ -0,0 +1,398 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require "fpm/package"
|
3
|
+
require "fpm/util"
|
4
|
+
require "backports"
|
5
|
+
require "fileutils"
|
6
|
+
require "find"
|
7
|
+
|
8
|
+
class FPM::Package::Pacman < FPM::Package
|
9
|
+
|
10
|
+
option "--optional-depends", "PACKAGE",
|
11
|
+
"Add an optional dependency to the pacman package.", :multivalued => true
|
12
|
+
|
13
|
+
option "--use-file-permissions", :flag,
|
14
|
+
"Use existing file permissions when defining ownership and modes"
|
15
|
+
|
16
|
+
option "--user", "USER", "The owner of files in this package", :default => 'root'
|
17
|
+
|
18
|
+
option "--group", "GROUP", "The group owner of files in this package", :default => 'root'
|
19
|
+
|
20
|
+
# The list of supported compression types. Default is xz (LZMA2)
|
21
|
+
COMPRESSION_TYPES = [ "gz", "bzip2", "xz", "none" ]
|
22
|
+
|
23
|
+
option "--compression", "COMPRESSION", "The compression type to use, must " \
|
24
|
+
"be one of #{COMPRESSION_TYPES.join(", ")}.", :default => "xz" do |value|
|
25
|
+
if !COMPRESSION_TYPES.include?(value)
|
26
|
+
raise ArgumentError, "Pacman compression value of '#{value}' is invalid. " \
|
27
|
+
"Must be one of #{COMPRESSION_TYPES.join(", ")}"
|
28
|
+
end
|
29
|
+
value
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(*args)
|
33
|
+
super(*args)
|
34
|
+
attributes[:pacman_optional_depends] = []
|
35
|
+
end # def initialize
|
36
|
+
|
37
|
+
def architecture
|
38
|
+
case @architecture
|
39
|
+
when nil
|
40
|
+
return %x{uname -m}.chomp # default to current arch
|
41
|
+
when "amd64" # debian and pacman disagree on architecture names
|
42
|
+
return "x86_64"
|
43
|
+
when "native"
|
44
|
+
return %x{uname -m}.chomp # 'native' is current arch
|
45
|
+
when "all", "any", "noarch"
|
46
|
+
return "any"
|
47
|
+
else
|
48
|
+
return @architecture
|
49
|
+
end
|
50
|
+
end # def architecture
|
51
|
+
|
52
|
+
def iteration
|
53
|
+
return @iteration || 1
|
54
|
+
end # def iteration
|
55
|
+
|
56
|
+
def config_files
|
57
|
+
return @config_files || []
|
58
|
+
end # def config_files
|
59
|
+
|
60
|
+
def dependencies
|
61
|
+
bogus_regex = /[^\sA-Za-z0-9><=-]/
|
62
|
+
# Actually modifies depencies if they are not right
|
63
|
+
bogus_dependencies = @dependencies.grep bogus_regex
|
64
|
+
if bogus_dependencies.any?
|
65
|
+
@dependencies.reject! { |a| a =~ bogus_regex }
|
66
|
+
logger.warn("Some of the dependencies looked like they weren't package " \
|
67
|
+
"names. Such dependency entries only serve to confuse arch. " \
|
68
|
+
"I am removing them.",
|
69
|
+
:removed_dependencies => bogus_dependencies,
|
70
|
+
:fixed_dependencies => @dependencies)
|
71
|
+
end
|
72
|
+
return @dependencies
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# This method is invoked on a package when it has been converted to a new
|
77
|
+
# package format. The purpose of this method is to do any extra conversion
|
78
|
+
# steps, like translating dependency conditions, etc.
|
79
|
+
#def converted_from(origin)
|
80
|
+
# nothing to do by default. Subclasses may implement this.
|
81
|
+
# See the RPM package class for an example.
|
82
|
+
#end # def converted_from
|
83
|
+
|
84
|
+
# Add a new source to this package.
|
85
|
+
# The exact behavior depends on the kind of package being managed.
|
86
|
+
#
|
87
|
+
# For instance:
|
88
|
+
#
|
89
|
+
# * for FPM::Package::Dir, << expects a path to a directory or files.
|
90
|
+
# * for FPM::Package::RPM, << expects a path to an rpm.
|
91
|
+
#
|
92
|
+
# The idea is that you can keep pumping in new things to a package
|
93
|
+
# for later conversion or output.
|
94
|
+
#
|
95
|
+
# Implementations are expected to put files relevant to the 'input' in the
|
96
|
+
# staging_path
|
97
|
+
def input(pacman_pkg_path)
|
98
|
+
control = {}
|
99
|
+
# Unpack the control tarball
|
100
|
+
safesystem(tar_cmd, "-C", staging_path, "-xf", pacman_pkg_path)
|
101
|
+
pkginfo = staging_path(".PKGINFO")
|
102
|
+
mtree = staging_path(".MTREE")
|
103
|
+
install = staging_path(".INSTALL")
|
104
|
+
|
105
|
+
control_contents = File.read(pkginfo)
|
106
|
+
FileUtils.rm(pkginfo)
|
107
|
+
FileUtils.rm(mtree)
|
108
|
+
|
109
|
+
|
110
|
+
control_lines = control_contents.split("\n")
|
111
|
+
control_lines.each do |line|
|
112
|
+
key, val = line.split(/ += +/, 2)
|
113
|
+
if control.has_key? key
|
114
|
+
control[key].push(val)
|
115
|
+
else
|
116
|
+
control[key] = [val]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
self.name = control["pkgname"][0]
|
121
|
+
|
122
|
+
# Parse 'epoch:version-iteration' in the version string
|
123
|
+
version_re = /^(?:([0-9]+):)?(.+?)(?:-(.*))?$/
|
124
|
+
m = version_re.match(control["pkgver"][0])
|
125
|
+
if !m
|
126
|
+
raise "Unsupported version string '#{control["pkgver"][0]}'"
|
127
|
+
end
|
128
|
+
self.epoch, self.version, self.iteration = m.captures
|
129
|
+
|
130
|
+
self.maintainer = control["packager"][0]
|
131
|
+
|
132
|
+
# Arch has no notion of vendor, so...
|
133
|
+
#self.vendor =
|
134
|
+
|
135
|
+
self.url = control["url"][0]
|
136
|
+
# Groups could include more than one.
|
137
|
+
# Speaking of just taking the first entry of the field:
|
138
|
+
# A crude thing to do, but I suppose it's better than nothing.
|
139
|
+
# -- Daniel Haskin, 3/24/2015
|
140
|
+
self.category = control["group"][0] || self.category
|
141
|
+
|
142
|
+
# Licenses could include more than one.
|
143
|
+
# Speaking of just taking the first entry of the field:
|
144
|
+
# A crude thing to do, but I suppose it's better than nothing.
|
145
|
+
# -- Daniel Haskin, 3/24/2015
|
146
|
+
self.license = control["license"][0] || self.license
|
147
|
+
|
148
|
+
self.architecture = control["arch"][0]
|
149
|
+
|
150
|
+
self.dependencies = control["depend"] || self.dependencies
|
151
|
+
|
152
|
+
self.provides = control["provides"] || self.provides
|
153
|
+
|
154
|
+
self.conflicts = control["conflict"] || self.conflicts
|
155
|
+
|
156
|
+
self.replaces = control["replaces"] || self.replaces
|
157
|
+
|
158
|
+
self.description = control["pkgdesc"][0]
|
159
|
+
|
160
|
+
if control.include? "backup"
|
161
|
+
self.config_files = control["backup"].map{|file| "/" + file}
|
162
|
+
else
|
163
|
+
self.config_files = []
|
164
|
+
end
|
165
|
+
|
166
|
+
self.dependencies = control["depend"] || self.dependencies
|
167
|
+
|
168
|
+
self.attributes[:pacman_optional_depends] = control["optdepend"] || []
|
169
|
+
# There are other available attributes, but I didn't include them because:
|
170
|
+
# - makedepend: deps needed to make the arch package. But it's already
|
171
|
+
# made. It just needs to be converted at this point
|
172
|
+
# - checkdepend: See above
|
173
|
+
# - makepkgopt: See above
|
174
|
+
# - size: can be dynamically generated
|
175
|
+
# - builddate: Should be changed to time of package conversion in the new
|
176
|
+
# package, so this value should be thrown away.
|
177
|
+
|
178
|
+
if File.exist?(install)
|
179
|
+
functions = parse_install_script(install)
|
180
|
+
if functions.include?("pre_install")
|
181
|
+
self.scripts[:before_install] = functions["pre_install"].join("\n")
|
182
|
+
end
|
183
|
+
if functions.include?("post_install")
|
184
|
+
self.scripts[:after_install] = functions["post_install"].join("\n")
|
185
|
+
end
|
186
|
+
if functions.include?("pre_upgrade")
|
187
|
+
self.scripts[:before_upgrade] = functions["pre_upgrade"].join("\n")
|
188
|
+
end
|
189
|
+
if functions.include?("post_upgrade")
|
190
|
+
self.scripts[:after_upgrade] = functions["post_upgrade"].join("\n")
|
191
|
+
end
|
192
|
+
if functions.include?("pre_remove")
|
193
|
+
self.scripts[:before_remove] = functions["pre_remove"].join("\n")
|
194
|
+
end
|
195
|
+
if functions.include?("post_remove")
|
196
|
+
self.scripts[:after_remove] = functions["post_remove"].join("\n")
|
197
|
+
end
|
198
|
+
FileUtils.rm(install)
|
199
|
+
end
|
200
|
+
|
201
|
+
# Note: didn't use `self.directories`.
|
202
|
+
# Pacman doesn't really record that information, to my knowledge.
|
203
|
+
|
204
|
+
end # def input
|
205
|
+
|
206
|
+
def compression_option
|
207
|
+
case self.attributes[:pacman_compression]
|
208
|
+
when nil, "xz"
|
209
|
+
return "--xz"
|
210
|
+
when "none"
|
211
|
+
return ""
|
212
|
+
when "gz"
|
213
|
+
return "-z"
|
214
|
+
when "bzip2"
|
215
|
+
return "-j"
|
216
|
+
else
|
217
|
+
return "--xz"
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def compression_ending
|
222
|
+
case self.attributes[:pacman_compression]
|
223
|
+
when nil, "xz"
|
224
|
+
return ".xz"
|
225
|
+
when "none"
|
226
|
+
return ""
|
227
|
+
when "gz"
|
228
|
+
return ".gz"
|
229
|
+
when "bzip2"
|
230
|
+
return ".bz2"
|
231
|
+
else
|
232
|
+
return ".xz"
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# Output this package to the given path.
|
237
|
+
def output(output_path)
|
238
|
+
output_check(output_path)
|
239
|
+
|
240
|
+
# Copy all files from staging to BUILD dir
|
241
|
+
Find.find(staging_path) do |path|
|
242
|
+
src = path.gsub(/^#{staging_path}/, '')
|
243
|
+
dst = build_path(src)
|
244
|
+
copy_entry(path, dst, preserve=true, remove_destination=true)
|
245
|
+
copy_metadata(path, dst)
|
246
|
+
end
|
247
|
+
|
248
|
+
# This value is used later in the template for PKGINFO
|
249
|
+
size = safesystemout("du", "-sk", build_path).split(/\s+/)[0].to_i * 1024
|
250
|
+
builddate = Time.new.to_i
|
251
|
+
|
252
|
+
pkginfo = template("pacman.erb").result(binding)
|
253
|
+
pkginfo_file = build_path(".PKGINFO")
|
254
|
+
File.write(pkginfo_file, pkginfo)
|
255
|
+
|
256
|
+
if script?(:before_install) or script?(:after_install) or \
|
257
|
+
script?(:before_upgrade) or script?(:after_upgrade) or \
|
258
|
+
script?(:before_remove) or script?(:after_remove)
|
259
|
+
install_script = template("pacman/INSTALL.erb").result(binding)
|
260
|
+
install_script_file = build_path(".INSTALL")
|
261
|
+
File.write(install_script_file, install_script)
|
262
|
+
end
|
263
|
+
|
264
|
+
generate_mtree
|
265
|
+
|
266
|
+
File.expand_path(output_path).tap do |path|
|
267
|
+
::Dir.chdir(build_path) do
|
268
|
+
safesystem(*([tar_cmd,
|
269
|
+
compression_option,
|
270
|
+
"-cf",
|
271
|
+
path] + data_tar_flags + \
|
272
|
+
::Dir.entries(".").reject{|entry| entry =~ /^\.{1,2}$/ }))
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end # def output
|
276
|
+
|
277
|
+
def data_tar_flags
|
278
|
+
data_tar_flags = []
|
279
|
+
if attributes[:pacman_use_file_permissions?].nil?
|
280
|
+
if !attributes[:pacman_user].nil?
|
281
|
+
if attributes[:pacman_user] == 'root'
|
282
|
+
data_tar_flags += [ "--numeric-owner", "--owner", "0" ]
|
283
|
+
else
|
284
|
+
data_tar_flags += [ "--owner", attributes[:deb_user] ]
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
if !attributes[:pacman_group].nil?
|
289
|
+
if attributes[:pacman_group] == 'root'
|
290
|
+
data_tar_flags += [ "--numeric-owner", "--group", "0" ]
|
291
|
+
else
|
292
|
+
data_tar_flags += [ "--group", attributes[:deb_group] ]
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
return data_tar_flags
|
297
|
+
end # def data_tar_flags
|
298
|
+
|
299
|
+
def default_output
|
300
|
+
v = version
|
301
|
+
v = "#{epoch}:#{v}" if epoch
|
302
|
+
if iteration
|
303
|
+
"#{name}_#{v}-#{iteration}_#{architecture}.#{type}"
|
304
|
+
else
|
305
|
+
"#{name}_#{v}_#{architecture}.#{type}"
|
306
|
+
end
|
307
|
+
end # def default_output
|
308
|
+
|
309
|
+
def to_s(format=nil)
|
310
|
+
# Default format if nil
|
311
|
+
# git_1.7.9.3-1_amd64.deb
|
312
|
+
return super("NAME-FULLVERSION-ARCH.pkg.tar#{compression_ending}") if format.nil?
|
313
|
+
return super(format)
|
314
|
+
end # def to_s
|
315
|
+
|
316
|
+
private
|
317
|
+
|
318
|
+
def generate_mtree
|
319
|
+
::Dir.chdir(build_path) do
|
320
|
+
cmd = "LANG=C bsdtar "
|
321
|
+
cmd += "-czf .MTREE "
|
322
|
+
cmd += "--format=mtree "
|
323
|
+
cmd += "--options='!all,use-set,type,uid,gid,mode,time,size,md5,sha256,link' "
|
324
|
+
cmd += ::Dir.entries(".").reject{|entry| entry =~ /^\.{1,2}$/ }.join(" ")
|
325
|
+
safesystem(cmd)
|
326
|
+
end
|
327
|
+
end # def generate_mtree
|
328
|
+
|
329
|
+
# KNOWN ISSUE:
|
330
|
+
# If an un-matched bracket is used in valid bash, as in
|
331
|
+
# `echo "{"`, this function will choke.
|
332
|
+
# However, to cover this case basically
|
333
|
+
# requires writing almost half a bash parser,
|
334
|
+
# and it is a very small corner case.
|
335
|
+
# Otherwise, this approach is very robust.
|
336
|
+
def gobble_function(cons,prod)
|
337
|
+
level = 1
|
338
|
+
while level > 0
|
339
|
+
line = cons.next
|
340
|
+
# Not the best, but pretty good
|
341
|
+
# short of writing an *actual* sh
|
342
|
+
# parser
|
343
|
+
level += line.count "{"
|
344
|
+
level -= line.count "}"
|
345
|
+
if level > 0
|
346
|
+
prod.push(line.rstrip())
|
347
|
+
else
|
348
|
+
fine = line.sub(/\s*[}]\s*$/, "")
|
349
|
+
if !(fine =~ /^\s*$/)
|
350
|
+
prod.push(fine.rstrip())
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end # def gobble_function
|
355
|
+
|
356
|
+
FIND_SCRIPT_FUNCTION_LINE =
|
357
|
+
/^\s*(\w+)\s*\(\s*\)\s*\{\s*([^}]+?)?\s*(\})?\s*$/
|
358
|
+
|
359
|
+
def parse_install_script(path)
|
360
|
+
global_lines = []
|
361
|
+
look_for = Set.new(["pre_install", "post_install",
|
362
|
+
"pre_upgrade", "post_upgrade",
|
363
|
+
"pre_remove", "post_remove"])
|
364
|
+
functions = {}
|
365
|
+
look_for.each do |fname|
|
366
|
+
functions[fname] = []
|
367
|
+
end
|
368
|
+
|
369
|
+
open(path, "r") do |iscript|
|
370
|
+
lines = iscript.each
|
371
|
+
begin
|
372
|
+
while true
|
373
|
+
line = lines.next
|
374
|
+
# This regex picks up beginning names of posix shell
|
375
|
+
# functions
|
376
|
+
# Examples:
|
377
|
+
# fname() {
|
378
|
+
# fname() { echo hi }
|
379
|
+
m = FIND_SCRIPT_FUNCTION_LINE.match(line)
|
380
|
+
if not m.nil? and look_for.include? m[1]
|
381
|
+
if not m[2].nil?
|
382
|
+
functions[m[1]].push(m[2].rstrip())
|
383
|
+
end
|
384
|
+
gobble_function(lines, functions[m[1]])
|
385
|
+
else
|
386
|
+
global_lines.push(line.rstrip())
|
387
|
+
end
|
388
|
+
end
|
389
|
+
rescue StopIteration
|
390
|
+
end
|
391
|
+
end
|
392
|
+
look_for.each do |name|
|
393
|
+
# Add global lines to each function to preserve global variables, etc.
|
394
|
+
functions[name] = global_lines + functions[name]
|
395
|
+
end
|
396
|
+
return functions
|
397
|
+
end # def parse_install_script
|
398
|
+
end # class FPM::Package::Pacman
|