fpm-itchio 1.4.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 +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
|