fpm-itchio 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELIST +629 -0
- data/CONTRIBUTORS +26 -0
- data/LICENSE +21 -0
- data/bin/fpm +8 -0
- data/lib/fpm.rb +18 -0
- data/lib/fpm/command.rb +642 -0
- data/lib/fpm/errors.rb +4 -0
- data/lib/fpm/namespace.rb +4 -0
- data/lib/fpm/package.rb +524 -0
- data/lib/fpm/package/cpan.rb +378 -0
- data/lib/fpm/package/deb.rb +887 -0
- data/lib/fpm/package/dir.rb +207 -0
- data/lib/fpm/package/empty.rb +13 -0
- data/lib/fpm/package/gem.rb +224 -0
- data/lib/fpm/package/npm.rb +120 -0
- data/lib/fpm/package/osxpkg.rb +164 -0
- data/lib/fpm/package/p5p.rb +124 -0
- data/lib/fpm/package/pacman.rb +397 -0
- data/lib/fpm/package/pear.rb +117 -0
- data/lib/fpm/package/pkgin.rb +35 -0
- data/lib/fpm/package/puppet.rb +120 -0
- data/lib/fpm/package/pyfpm/__init__.py +1 -0
- data/lib/fpm/package/pyfpm/get_metadata.py +104 -0
- data/lib/fpm/package/python.rb +317 -0
- data/lib/fpm/package/rpm.rb +583 -0
- data/lib/fpm/package/sh.rb +69 -0
- data/lib/fpm/package/solaris.rb +95 -0
- data/lib/fpm/package/tar.rb +74 -0
- data/lib/fpm/package/virtualenv.rb +145 -0
- data/lib/fpm/package/zip.rb +63 -0
- data/lib/fpm/rake_task.rb +59 -0
- data/lib/fpm/util.rb +253 -0
- data/lib/fpm/version.rb +3 -0
- data/templates/deb.erb +52 -0
- data/templates/deb/changelog.erb +5 -0
- data/templates/deb/ldconfig.sh.erb +13 -0
- data/templates/deb/postinst_upgrade.sh.erb +62 -0
- data/templates/deb/postrm_upgrade.sh.erb +46 -0
- data/templates/deb/preinst_upgrade.sh.erb +41 -0
- data/templates/deb/prerm_upgrade.sh.erb +39 -0
- data/templates/osxpkg.erb +11 -0
- data/templates/p5p_metadata.erb +12 -0
- data/templates/pacman.erb +47 -0
- data/templates/pacman/INSTALL.erb +41 -0
- data/templates/puppet/package.pp.erb +34 -0
- data/templates/puppet/package/remove.pp.erb +13 -0
- data/templates/rpm.erb +261 -0
- data/templates/rpm/filesystem_list +14514 -0
- data/templates/sh.erb +367 -0
- data/templates/solaris.erb +15 -0
- metadata +265 -0
@@ -0,0 +1,164 @@
|
|
1
|
+
require "fpm/package"
|
2
|
+
require "fpm/util"
|
3
|
+
require "fileutils"
|
4
|
+
require "fpm/package/dir"
|
5
|
+
require 'tempfile' # stdlib
|
6
|
+
require 'pathname' # stdlib
|
7
|
+
require 'rexml/document' # stdlib
|
8
|
+
|
9
|
+
# Use an OS X pkg built with pkgbuild.
|
10
|
+
#
|
11
|
+
# Supports input and output. Requires pkgbuild and (for input) pkgutil, part of a
|
12
|
+
# standard OS X install in 10.7 and higher.
|
13
|
+
class FPM::Package::OSXpkg < FPM::Package
|
14
|
+
|
15
|
+
# Map of what scripts are named.
|
16
|
+
SCRIPT_MAP = {
|
17
|
+
:before_install => "preinstall",
|
18
|
+
:after_install => "postinstall",
|
19
|
+
} unless defined?(SCRIPT_MAP)
|
20
|
+
|
21
|
+
POSTINSTALL_ACTIONS = [ "logout", "restart", "shutdown" ]
|
22
|
+
OWNERSHIP_OPTIONS = ["recommended", "preserve", "preserve-other"]
|
23
|
+
|
24
|
+
option "--identifier-prefix", "IDENTIFIER_PREFIX",
|
25
|
+
"Reverse domain prefix prepended to package identifier, " \
|
26
|
+
"ie. 'org.great.my'. If this is omitted, the identifer " \
|
27
|
+
"will be the package name."
|
28
|
+
option "--payload-free", :flag, "Define no payload, assumes use of script options.",
|
29
|
+
:default => false
|
30
|
+
option "--ownership", "OWNERSHIP",
|
31
|
+
"--ownership option passed to pkgbuild. Defaults to 'recommended'. " \
|
32
|
+
"See pkgbuild(1).", :default => 'recommended' do |value|
|
33
|
+
if !OWNERSHIP_OPTIONS.include?(value)
|
34
|
+
raise ArgumentError, "osxpkg-ownership value of '#{value}' is invalid. " \
|
35
|
+
"Must be one of #{OWNERSHIP_OPTIONS.join(", ")}"
|
36
|
+
end
|
37
|
+
value
|
38
|
+
end
|
39
|
+
|
40
|
+
option "--postinstall-action", "POSTINSTALL_ACTION",
|
41
|
+
"Post-install action provided in package metadata. " \
|
42
|
+
"Optionally one of '#{POSTINSTALL_ACTIONS.join("', '")}'." do |value|
|
43
|
+
if !POSTINSTALL_ACTIONS.include?(value)
|
44
|
+
raise ArgumentError, "osxpkg-postinstall-action value of '#{value}' is invalid. " \
|
45
|
+
"Must be one of #{POSTINSTALL_ACTIONS.join(", ")}"
|
46
|
+
end
|
47
|
+
value
|
48
|
+
end
|
49
|
+
|
50
|
+
dont_obsolete_paths = []
|
51
|
+
option "--dont-obsolete", "DONT_OBSOLETE_PATH",
|
52
|
+
"A file path for which to 'dont-obsolete' in the built PackageInfo. " \
|
53
|
+
"Can be specified multiple times." do |path|
|
54
|
+
dont_obsolete_paths << path
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
# return the identifier by prepending the reverse-domain prefix
|
59
|
+
# to the package name, else return just the name
|
60
|
+
def identifier
|
61
|
+
identifier = name.dup
|
62
|
+
if self.attributes[:osxpkg_identifier_prefix]
|
63
|
+
identifier.insert(0, "#{self.attributes[:osxpkg_identifier_prefix]}.")
|
64
|
+
end
|
65
|
+
identifier
|
66
|
+
end # def identifier
|
67
|
+
|
68
|
+
# scripts_path and write_scripts cribbed from deb.rb
|
69
|
+
def scripts_path(path=nil)
|
70
|
+
@scripts_path ||= build_path("Scripts")
|
71
|
+
FileUtils.mkdir(@scripts_path) if !File.directory?(@scripts_path)
|
72
|
+
|
73
|
+
if path.nil?
|
74
|
+
return @scripts_path
|
75
|
+
else
|
76
|
+
return File.join(@scripts_path, path)
|
77
|
+
end
|
78
|
+
end # def scripts_path
|
79
|
+
|
80
|
+
def write_scripts
|
81
|
+
SCRIPT_MAP.each do |scriptname, filename|
|
82
|
+
next unless script?(scriptname)
|
83
|
+
|
84
|
+
scripts_path(filename).tap do |pkgscript|
|
85
|
+
logger.info("Writing pkg script", :source => filename, :target => pkgscript)
|
86
|
+
File.write(pkgscript, script(scriptname))
|
87
|
+
# scripts are required to be executable
|
88
|
+
File.chmod(0755, pkgscript)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end # def write_scripts
|
92
|
+
|
93
|
+
# Returns path of a processed template PackageInfo given to 'pkgbuild --info'
|
94
|
+
# note: '--info' is undocumented:
|
95
|
+
# http://managingosx.wordpress.com/2012/07/05/stupid-tricks-with-pkgbuild
|
96
|
+
def pkginfo_template_path
|
97
|
+
pkginfo_template = Tempfile.open("fpm-PackageInfo")
|
98
|
+
pkginfo_data = template("osxpkg.erb").result(binding)
|
99
|
+
pkginfo_template.write(pkginfo_data)
|
100
|
+
pkginfo_template.close
|
101
|
+
pkginfo_template.path
|
102
|
+
end # def write_pkginfo_template
|
103
|
+
|
104
|
+
# Extract name and version from PackageInfo XML
|
105
|
+
def extract_info(package)
|
106
|
+
build_path("expand").tap do |path|
|
107
|
+
doc = REXML::Document.new File.open(File.join(path, "PackageInfo"))
|
108
|
+
pkginfo_elem = doc.elements["pkg-info"]
|
109
|
+
identifier = pkginfo_elem.attribute("identifier").value
|
110
|
+
self.version = pkginfo_elem.attribute("version").value
|
111
|
+
# set name to the last dot element of the identifier
|
112
|
+
self.name = identifier.split(".").last
|
113
|
+
logger.info("inferring name #{self.name} from pkg-id #{identifier}")
|
114
|
+
end
|
115
|
+
end # def extract_info
|
116
|
+
|
117
|
+
# Take a flat package as input
|
118
|
+
def input(input_path)
|
119
|
+
# TODO: Fail if it's a Distribution pkg or old-fashioned
|
120
|
+
expand_dir = File.join(build_path, "expand")
|
121
|
+
# expand_dir must not already exist for pkgutil --expand
|
122
|
+
safesystem("pkgutil --expand #{input_path} #{expand_dir}")
|
123
|
+
|
124
|
+
extract_info(input_path)
|
125
|
+
|
126
|
+
# extract Payload
|
127
|
+
safesystem("tar -xz -f #{expand_dir}/Payload -C #{staging_path}")
|
128
|
+
end # def input
|
129
|
+
|
130
|
+
# Output a pkgbuild pkg.
|
131
|
+
def output(output_path)
|
132
|
+
output_check(output_path)
|
133
|
+
|
134
|
+
temp_info = pkginfo_template_path
|
135
|
+
|
136
|
+
args = ["--identifier", identifier,
|
137
|
+
"--info", temp_info,
|
138
|
+
"--version", version.to_s,
|
139
|
+
"--ownership", attributes[:osxpkg_ownership]]
|
140
|
+
|
141
|
+
if self.attributes[:osxpkg_payload_free?]
|
142
|
+
args << "--nopayload"
|
143
|
+
else
|
144
|
+
args += ["--root", staging_path]
|
145
|
+
end
|
146
|
+
|
147
|
+
if attributes[:before_install_given?] or attributes[:after_install_given?]
|
148
|
+
write_scripts
|
149
|
+
args += ["--scripts", scripts_path]
|
150
|
+
end
|
151
|
+
args << output_path
|
152
|
+
|
153
|
+
safesystem("pkgbuild", *args)
|
154
|
+
FileUtils.remove_file(temp_info)
|
155
|
+
end # def output
|
156
|
+
|
157
|
+
def to_s(format=nil)
|
158
|
+
return super("NAME-VERSION.pkg") if format.nil?
|
159
|
+
return super(format)
|
160
|
+
end # def to_s
|
161
|
+
|
162
|
+
public(:input, :output, :identifier, :to_s)
|
163
|
+
|
164
|
+
end # class FPM::Package::OSXpkg
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require "erb"
|
2
|
+
require "fpm/namespace"
|
3
|
+
require "fpm/package"
|
4
|
+
require "fpm/errors"
|
5
|
+
require "fpm/util"
|
6
|
+
|
7
|
+
class FPM::Package::P5P < FPM::Package
|
8
|
+
|
9
|
+
option "--user", "USER",
|
10
|
+
"Set the user to USER in the prototype files.",
|
11
|
+
:default => 'root'
|
12
|
+
|
13
|
+
option "--group", "GROUP",
|
14
|
+
"Set the group to GROUP in the prototype file.",
|
15
|
+
:default => 'root'
|
16
|
+
|
17
|
+
option "--zonetype", "ZONETYPE",
|
18
|
+
"Set the allowed zone types (global, nonglobal, both)",
|
19
|
+
:default => 'value=global value=nonglobal' do |value|
|
20
|
+
case @value
|
21
|
+
when "both"
|
22
|
+
value = "value=global value=nonglobal"
|
23
|
+
else
|
24
|
+
value = "value=#{value}"
|
25
|
+
end
|
26
|
+
end # value
|
27
|
+
|
28
|
+
option "--publisher", "PUBLISHER",
|
29
|
+
"Set the publisher name for the repository",
|
30
|
+
:default => 'FPM'
|
31
|
+
|
32
|
+
option "--lint" , :flag, "Check manifest with pkglint",
|
33
|
+
:default => true
|
34
|
+
|
35
|
+
option "--validate", :flag, "Validate with pkg install",
|
36
|
+
:default => true
|
37
|
+
|
38
|
+
def architecture
|
39
|
+
case @architecture
|
40
|
+
when nil, "native"
|
41
|
+
@architecture = %x{uname -p}.chomp
|
42
|
+
when "all"
|
43
|
+
@architecture = 'i386 value=sparc'
|
44
|
+
end
|
45
|
+
|
46
|
+
return @architecture
|
47
|
+
end # def architecture
|
48
|
+
|
49
|
+
def output(output_path)
|
50
|
+
|
51
|
+
# Fixup the category to an acceptable solaris category
|
52
|
+
case @category
|
53
|
+
when nil, "default"
|
54
|
+
@category = 'Applications/System Utilities'
|
55
|
+
end
|
56
|
+
|
57
|
+
# Manifest Filename
|
58
|
+
manifest_fn = build_path("#{name}.p5m")
|
59
|
+
|
60
|
+
# Generate a package manifest.
|
61
|
+
pkg_generate = safesystemout("pkgsend", "generate", "#{staging_path}")
|
62
|
+
File.write(build_path("#{name}.p5m.1"), pkg_generate)
|
63
|
+
|
64
|
+
# Add necessary metadata to the generated manifest.
|
65
|
+
metadata_template = template("p5p_metadata.erb").result(binding)
|
66
|
+
File.write(build_path("#{name}.mog"), metadata_template)
|
67
|
+
|
68
|
+
# Combine template and filelist; allow user to edit before proceeding
|
69
|
+
File.open(manifest_fn, "w") do |manifest|
|
70
|
+
manifest.write metadata_template
|
71
|
+
manifest.write pkg_generate
|
72
|
+
end
|
73
|
+
edit_file(manifest_fn) if attributes[:edit?]
|
74
|
+
|
75
|
+
# Execute the transmogrification on the manifest
|
76
|
+
pkg_mogrify = safesystemout("pkgmogrify", manifest_fn)
|
77
|
+
File.write(build_path("#{name}.p5m.2"), pkg_mogrify)
|
78
|
+
safesystem("cp", build_path("#{name}.p5m.2"), manifest_fn)
|
79
|
+
|
80
|
+
# Evaluate dependencies.
|
81
|
+
if !attributes[:no_auto_depends?]
|
82
|
+
pkgdepend_gen = safesystemout("pkgdepend", "generate", "-md", "#{staging_path}", manifest_fn)
|
83
|
+
File.write(build_path("#{name}.p5m.3"), pkgdepend_gen)
|
84
|
+
|
85
|
+
# Allow user to review added dependencies
|
86
|
+
edit_file(build_path("#{name}.p5m.3")) if attributes[:edit?]
|
87
|
+
|
88
|
+
safesystem("pkgdepend", "resolve", "-m", build_path("#{name}.p5m.3"))
|
89
|
+
safesystem("cp", build_path("#{name}.p5m.3.res"), manifest_fn)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Final format of manifest
|
93
|
+
safesystem("pkgfmt", manifest_fn)
|
94
|
+
|
95
|
+
# Final edit for lint check and packaging
|
96
|
+
edit_file(manifest_fn) if attributes[:edit?]
|
97
|
+
|
98
|
+
# Add any facets or actuators that are needed.
|
99
|
+
# TODO(jcraig): add manpage actuator to enable install wo/ man pages
|
100
|
+
|
101
|
+
# Verify the package.
|
102
|
+
if attributes[:p5p_lint] then
|
103
|
+
safesystem("pkglint", manifest_fn)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Publish the package.
|
107
|
+
repo_path = build_path("#{name}_repo")
|
108
|
+
safesystem("pkgrepo", "create", repo_path)
|
109
|
+
safesystem("pkgrepo", "set", "-s", repo_path, "publisher/prefix=#{attributes[:p5p_publisher]}")
|
110
|
+
safesystem("pkgsend", "-s", repo_path,
|
111
|
+
"publish", "-d", "#{staging_path}", "#{build_path}/#{name}.p5m")
|
112
|
+
safesystem("pkgrecv", "-s", repo_path, "-a",
|
113
|
+
"-d", build_path("#{name}.p5p"), name)
|
114
|
+
|
115
|
+
# Test the package
|
116
|
+
if attributes[:p5p_validate] then
|
117
|
+
safesystem("pkg", "install", "-nvg", build_path("#{name}.p5p"), name)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Cleanup
|
121
|
+
safesystem("mv", build_path("#{name}.p5p"), output_path)
|
122
|
+
|
123
|
+
end # def output
|
124
|
+
end # class FPM::Package::IPS
|
@@ -0,0 +1,397 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require "fpm/package"
|
3
|
+
require "backports"
|
4
|
+
require "fileutils"
|
5
|
+
require "find"
|
6
|
+
|
7
|
+
class FPM::Package::Pacman < FPM::Package
|
8
|
+
|
9
|
+
option "--optional-depends", "PACKAGE",
|
10
|
+
"Add an optional dependency to the pacman package.", :multivalued => true
|
11
|
+
|
12
|
+
option "--use-file-permissions", :flag,
|
13
|
+
"Use existing file permissions when defining ownership and modes"
|
14
|
+
|
15
|
+
option "--user", "USER", "The owner of files in this package", :default => 'root'
|
16
|
+
|
17
|
+
option "--group", "GROUP", "The group owner of files in this package", :default => 'root'
|
18
|
+
|
19
|
+
# The list of supported compression types. Default is xz (LZMA2)
|
20
|
+
COMPRESSION_TYPES = [ "gz", "bzip2", "xz", "none" ]
|
21
|
+
|
22
|
+
option "--compression", "COMPRESSION", "The compression type to use, must " \
|
23
|
+
"be one of #{COMPRESSION_TYPES.join(", ")}.", :default => "xz" do |value|
|
24
|
+
if !COMPRESSION_TYPES.include?(value)
|
25
|
+
raise ArgumentError, "Pacman compression value of '#{value}' is invalid. " \
|
26
|
+
"Must be one of #{COMPRESSION_TYPES.join(", ")}"
|
27
|
+
end
|
28
|
+
value
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(*args)
|
32
|
+
super(*args)
|
33
|
+
attributes[:pacman_optional_depends] = []
|
34
|
+
end # def initialize
|
35
|
+
|
36
|
+
def architecture
|
37
|
+
case @architecture
|
38
|
+
when nil
|
39
|
+
return %x{uname -m}.chomp # default to current arch
|
40
|
+
when "amd64" # debian and pacman disagree on architecture names
|
41
|
+
return "x86_64"
|
42
|
+
when "native"
|
43
|
+
return %x{uname -m}.chomp # 'native' is current arch
|
44
|
+
when "all", "any", "noarch"
|
45
|
+
return "any"
|
46
|
+
else
|
47
|
+
return @architecture
|
48
|
+
end
|
49
|
+
end # def architecture
|
50
|
+
|
51
|
+
def iteration
|
52
|
+
return @iteration || 1
|
53
|
+
end # def iteration
|
54
|
+
|
55
|
+
def config_files
|
56
|
+
return @config_files || []
|
57
|
+
end # def config_files
|
58
|
+
|
59
|
+
def dependencies
|
60
|
+
bogus_regex = /[^\sA-Za-z0-9><=-]/
|
61
|
+
# Actually modifies depencies if they are not right
|
62
|
+
bogus_dependencies = @dependencies.grep bogus_regex
|
63
|
+
if bogus_dependencies.any?
|
64
|
+
@dependencies.reject! { |a| a =~ bogus_regex }
|
65
|
+
logger.warn("Some of the dependencies looked like they weren't package " \
|
66
|
+
"names. Such dependency entries only serve to confuse arch. " \
|
67
|
+
"I am removing them.",
|
68
|
+
:removed_dependencies => bogus_dependencies,
|
69
|
+
:fixed_dependencies => @dependencies)
|
70
|
+
end
|
71
|
+
return @dependencies
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
# This method is invoked on a package when it has been converted to a new
|
76
|
+
# package format. The purpose of this method is to do any extra conversion
|
77
|
+
# steps, like translating dependency conditions, etc.
|
78
|
+
#def converted_from(origin)
|
79
|
+
# nothing to do by default. Subclasses may implement this.
|
80
|
+
# See the RPM package class for an example.
|
81
|
+
#end # def converted_from
|
82
|
+
|
83
|
+
# Add a new source to this package.
|
84
|
+
# The exact behavior depends on the kind of package being managed.
|
85
|
+
#
|
86
|
+
# For instance:
|
87
|
+
#
|
88
|
+
# * for FPM::Package::Dir, << expects a path to a directory or files.
|
89
|
+
# * for FPM::Package::RPM, << expects a path to an rpm.
|
90
|
+
#
|
91
|
+
# The idea is that you can keep pumping in new things to a package
|
92
|
+
# for later conversion or output.
|
93
|
+
#
|
94
|
+
# Implementations are expected to put files relevant to the 'input' in the
|
95
|
+
# staging_path
|
96
|
+
def input(pacman_pkg_path)
|
97
|
+
control = {}
|
98
|
+
# Unpack the control tarball
|
99
|
+
safesystem("tar", "-C", staging_path, "-xf", pacman_pkg_path)
|
100
|
+
pkginfo = staging_path(".PKGINFO")
|
101
|
+
mtree = staging_path(".MTREE")
|
102
|
+
install = staging_path(".INSTALL")
|
103
|
+
|
104
|
+
control_contents = File.read(pkginfo)
|
105
|
+
FileUtils.rm(pkginfo)
|
106
|
+
FileUtils.rm(mtree)
|
107
|
+
|
108
|
+
|
109
|
+
control_lines = control_contents.split("\n")
|
110
|
+
control_lines.each do |line|
|
111
|
+
key, val = line.split(/ += +/, 2)
|
112
|
+
if control.has_key? key
|
113
|
+
control[key].push(val)
|
114
|
+
else
|
115
|
+
control[key] = [val]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
self.name = control["pkgname"][0]
|
120
|
+
|
121
|
+
# Parse 'epoch:version-iteration' in the version string
|
122
|
+
version_re = /^(?:([0-9]+):)?(.+?)(?:-(.*))?$/
|
123
|
+
m = version_re.match(control["pkgver"][0])
|
124
|
+
if !m
|
125
|
+
raise "Unsupported version string '#{control["pkgver"][0]}'"
|
126
|
+
end
|
127
|
+
self.epoch, self.version, self.iteration = m.captures
|
128
|
+
|
129
|
+
self.maintainer = control["packager"][0]
|
130
|
+
|
131
|
+
# Arch has no notion of vendor, so...
|
132
|
+
#self.vendor =
|
133
|
+
|
134
|
+
self.url = control["url"][0]
|
135
|
+
# Groups could include more than one.
|
136
|
+
# Speaking of just taking the first entry of the field:
|
137
|
+
# A crude thing to do, but I suppose it's better than nothing.
|
138
|
+
# -- Daniel Haskin, 3/24/2015
|
139
|
+
self.category = control["group"][0] || self.category
|
140
|
+
|
141
|
+
# Licenses could include more than one.
|
142
|
+
# Speaking of just taking the first entry of the field:
|
143
|
+
# A crude thing to do, but I suppose it's better than nothing.
|
144
|
+
# -- Daniel Haskin, 3/24/2015
|
145
|
+
self.license = control["license"][0] || self.license
|
146
|
+
|
147
|
+
self.architecture = control["arch"][0]
|
148
|
+
|
149
|
+
self.dependencies = control["depend"] || self.dependencies
|
150
|
+
|
151
|
+
self.provides = control["provides"] || self.provides
|
152
|
+
|
153
|
+
self.conflicts = control["conflict"] || self.conflicts
|
154
|
+
|
155
|
+
self.replaces = control["replaces"] || self.replaces
|
156
|
+
|
157
|
+
self.description = control["pkgdesc"][0]
|
158
|
+
|
159
|
+
if control.include? "backup"
|
160
|
+
self.config_files = control["backup"].map{|file| "/" + file}
|
161
|
+
else
|
162
|
+
self.config_files = []
|
163
|
+
end
|
164
|
+
|
165
|
+
self.dependencies = control["depend"] || self.dependencies
|
166
|
+
|
167
|
+
self.attributes[:pacman_optional_depends] = control["optdepend"] || []
|
168
|
+
# There are other available attributes, but I didn't include them because:
|
169
|
+
# - makedepend: deps needed to make the arch package. But it's already
|
170
|
+
# made. It just needs to be converted at this point
|
171
|
+
# - checkdepend: See above
|
172
|
+
# - makepkgopt: See above
|
173
|
+
# - size: can be dynamically generated
|
174
|
+
# - builddate: Should be changed to time of package conversion in the new
|
175
|
+
# package, so this value should be thrown away.
|
176
|
+
|
177
|
+
if File.exist?(install)
|
178
|
+
functions = parse_install_script(install)
|
179
|
+
if functions.include?("pre_install")
|
180
|
+
self.scripts[:before_install] = functions["pre_install"].join("\n")
|
181
|
+
end
|
182
|
+
if functions.include?("post_install")
|
183
|
+
self.scripts[:after_install] = functions["post_install"].join("\n")
|
184
|
+
end
|
185
|
+
if functions.include?("pre_upgrade")
|
186
|
+
self.scripts[:before_upgrade] = functions["pre_upgrade"].join("\n")
|
187
|
+
end
|
188
|
+
if functions.include?("post_upgrade")
|
189
|
+
self.scripts[:after_upgrade] = functions["post_upgrade"].join("\n")
|
190
|
+
end
|
191
|
+
if functions.include?("pre_remove")
|
192
|
+
self.scripts[:before_remove] = functions["pre_remove"].join("\n")
|
193
|
+
end
|
194
|
+
if functions.include?("post_remove")
|
195
|
+
self.scripts[:after_remove] = functions["post_remove"].join("\n")
|
196
|
+
end
|
197
|
+
FileUtils.rm(install)
|
198
|
+
end
|
199
|
+
|
200
|
+
# Note: didn't use `self.directories`.
|
201
|
+
# Pacman doesn't really record that information, to my knowledge.
|
202
|
+
|
203
|
+
end # def input
|
204
|
+
|
205
|
+
def compression_option
|
206
|
+
case self.attributes[:pacman_compression]
|
207
|
+
when nil, "xz"
|
208
|
+
return "--xz"
|
209
|
+
when "none"
|
210
|
+
return ""
|
211
|
+
when "gz"
|
212
|
+
return "-z"
|
213
|
+
when "bzip2"
|
214
|
+
return "-j"
|
215
|
+
else
|
216
|
+
return "--xz"
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def compression_ending
|
221
|
+
case self.attributes[:pacman_compression]
|
222
|
+
when nil, "xz"
|
223
|
+
return ".xz"
|
224
|
+
when "none"
|
225
|
+
return ""
|
226
|
+
when "gz"
|
227
|
+
return ".gz"
|
228
|
+
when "bzip2"
|
229
|
+
return ".bz2"
|
230
|
+
else
|
231
|
+
return ".xz"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
# Output this package to the given path.
|
236
|
+
def output(output_path)
|
237
|
+
output_check(output_path)
|
238
|
+
|
239
|
+
# Copy all files from staging to BUILD dir
|
240
|
+
Find.find(staging_path) do |path|
|
241
|
+
src = path.gsub(/^#{staging_path}/, '')
|
242
|
+
dst = build_path(src)
|
243
|
+
copy_entry(path, dst, preserve=true, remove_destination=true)
|
244
|
+
copy_metadata(path, dst)
|
245
|
+
end
|
246
|
+
|
247
|
+
# This value is used later in the template for PKGINFO
|
248
|
+
size = safesystemout("du", "-sk", build_path).split(/\s+/)[0].to_i * 1024
|
249
|
+
builddate = Time.new.to_i
|
250
|
+
|
251
|
+
pkginfo = template("pacman.erb").result(binding)
|
252
|
+
pkginfo_file = build_path(".PKGINFO")
|
253
|
+
File.write(pkginfo_file, pkginfo)
|
254
|
+
|
255
|
+
if script?(:before_install) or script?(:after_install) or \
|
256
|
+
script?(:before_upgrade) or script?(:after_upgrade) or \
|
257
|
+
script?(:before_remove) or script?(:after_remove)
|
258
|
+
install_script = template("pacman/INSTALL.erb").result(binding)
|
259
|
+
install_script_file = build_path(".INSTALL")
|
260
|
+
File.write(install_script_file, install_script)
|
261
|
+
end
|
262
|
+
|
263
|
+
generate_mtree
|
264
|
+
|
265
|
+
File.expand_path(output_path).tap do |path|
|
266
|
+
::Dir.chdir(build_path) do
|
267
|
+
safesystem(*(["tar",
|
268
|
+
compression_option,
|
269
|
+
"-cf",
|
270
|
+
path] + data_tar_flags + \
|
271
|
+
::Dir.entries(".").reject{|entry| entry =~ /^\.{1,2}$/ }))
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end # def output
|
275
|
+
|
276
|
+
def data_tar_flags
|
277
|
+
data_tar_flags = []
|
278
|
+
if attributes[:pacman_use_file_permissions?].nil?
|
279
|
+
if !attributes[:pacman_user].nil?
|
280
|
+
if attributes[:pacman_user] == 'root'
|
281
|
+
data_tar_flags += [ "--numeric-owner", "--owner", "0" ]
|
282
|
+
else
|
283
|
+
data_tar_flags += [ "--owner", attributes[:deb_user] ]
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
if !attributes[:pacman_group].nil?
|
288
|
+
if attributes[:pacman_group] == 'root'
|
289
|
+
data_tar_flags += [ "--numeric-owner", "--group", "0" ]
|
290
|
+
else
|
291
|
+
data_tar_flags += [ "--group", attributes[:deb_group] ]
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
return data_tar_flags
|
296
|
+
end # def data_tar_flags
|
297
|
+
|
298
|
+
def default_output
|
299
|
+
v = version
|
300
|
+
v = "#{epoch}:#{v}" if epoch
|
301
|
+
if iteration
|
302
|
+
"#{name}_#{v}-#{iteration}_#{architecture}.#{type}"
|
303
|
+
else
|
304
|
+
"#{name}_#{v}_#{architecture}.#{type}"
|
305
|
+
end
|
306
|
+
end # def default_output
|
307
|
+
|
308
|
+
def to_s(format=nil)
|
309
|
+
# Default format if nil
|
310
|
+
# git_1.7.9.3-1_amd64.deb
|
311
|
+
return super("NAME-FULLVERSION-ARCH.pkg.tar#{compression_ending}") if format.nil?
|
312
|
+
return super(format)
|
313
|
+
end # def to_s
|
314
|
+
|
315
|
+
private
|
316
|
+
|
317
|
+
def generate_mtree
|
318
|
+
::Dir.chdir(build_path) do
|
319
|
+
cmd = "LANG=C bsdtar "
|
320
|
+
cmd += "-czf .MTREE "
|
321
|
+
cmd += "--format=mtree "
|
322
|
+
cmd += "--options='!all,use-set,type,uid,gid,mode,time,size,md5,sha256,link' "
|
323
|
+
cmd += ::Dir.entries(".").reject{|entry| entry =~ /^\.{1,2}$/ }.join(" ")
|
324
|
+
safesystem(cmd)
|
325
|
+
end
|
326
|
+
end # def generate_mtree
|
327
|
+
|
328
|
+
# KNOWN ISSUE:
|
329
|
+
# If an un-matched bracket is used in valid bash, as in
|
330
|
+
# `echo "{"`, this function will choke.
|
331
|
+
# However, to cover this case basically
|
332
|
+
# requires writing almost half a bash parser,
|
333
|
+
# and it is a very small corner case.
|
334
|
+
# Otherwise, this approach is very robust.
|
335
|
+
def gobble_function(cons,prod)
|
336
|
+
level = 1
|
337
|
+
while level > 0
|
338
|
+
line = cons.next
|
339
|
+
# Not the best, but pretty good
|
340
|
+
# short of writing an *actual* sh
|
341
|
+
# parser
|
342
|
+
level += line.count "{"
|
343
|
+
level -= line.count "}"
|
344
|
+
if level > 0
|
345
|
+
prod.push(line.rstrip())
|
346
|
+
else
|
347
|
+
fine = line.sub(/\s*[}]\s*$/, "")
|
348
|
+
if !(fine =~ /^\s*$/)
|
349
|
+
prod.push(fine.rstrip())
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end # def gobble_function
|
354
|
+
|
355
|
+
FIND_SCRIPT_FUNCTION_LINE =
|
356
|
+
/^\s*(\w+)\s*\(\s*\)\s*\{\s*([^}]+?)?\s*(\})?\s*$/
|
357
|
+
|
358
|
+
def parse_install_script(path)
|
359
|
+
global_lines = []
|
360
|
+
look_for = Set.new(["pre_install", "post_install",
|
361
|
+
"pre_upgrade", "post_upgrade",
|
362
|
+
"pre_remove", "post_remove"])
|
363
|
+
functions = {}
|
364
|
+
look_for.each do |fname|
|
365
|
+
functions[fname] = []
|
366
|
+
end
|
367
|
+
|
368
|
+
open(path, "r") do |iscript|
|
369
|
+
lines = iscript.each
|
370
|
+
begin
|
371
|
+
while true
|
372
|
+
line = lines.next
|
373
|
+
# This regex picks up beginning names of posix shell
|
374
|
+
# functions
|
375
|
+
# Examples:
|
376
|
+
# fname() {
|
377
|
+
# fname() { echo hi }
|
378
|
+
m = FIND_SCRIPT_FUNCTION_LINE.match(line)
|
379
|
+
if not m.nil? and look_for.include? m[1]
|
380
|
+
if not m[2].nil?
|
381
|
+
functions[m[1]].push(m[2].rstrip())
|
382
|
+
end
|
383
|
+
gobble_function(lines, functions[m[1]])
|
384
|
+
else
|
385
|
+
global_lines.push(line.rstrip())
|
386
|
+
end
|
387
|
+
end
|
388
|
+
rescue StopIteration
|
389
|
+
end
|
390
|
+
end
|
391
|
+
look_for.each do |name|
|
392
|
+
# Add global lines to each function to preserve global variables, etc.
|
393
|
+
functions[name] = global_lines + functions[name]
|
394
|
+
end
|
395
|
+
return functions
|
396
|
+
end # def parse_install_script
|
397
|
+
end # class FPM::Package::Pacman
|