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/CONTRIBUTORS
CHANGED
@@ -20,6 +20,7 @@ llasram
|
|
20
20
|
sbuss
|
21
21
|
Brett Gailey (github: dnbert)
|
22
22
|
Daniel Haskin (github: djhaskin987)
|
23
|
+
Richard Grainger (github: liger1978)
|
23
24
|
|
24
25
|
If you have contributed (bug reports, feature requests, help in IRC, blog
|
25
26
|
posts, code, etc) and aren't listed here, please let me know if you wish to be
|
data/LICENSE
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
(This is an MIT-style license)
|
2
2
|
|
3
|
-
Copyright (c) 2011-
|
3
|
+
Copyright (c) 2011-2017 Jordan Sissel and contributors.
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/bin/fpm
CHANGED
data/lib/fpm.rb
CHANGED
data/lib/fpm/command.rb
CHANGED
@@ -45,13 +45,13 @@ class FPM::Command < Clamp::Command
|
|
45
45
|
return lines.join("\n")
|
46
46
|
end # def help
|
47
47
|
|
48
|
-
option "-t", "OUTPUT_TYPE",
|
48
|
+
option ["-t", "--output-type"], "OUTPUT_TYPE",
|
49
49
|
"the type of package you want to create (deb, rpm, solaris, etc)",
|
50
50
|
:attribute_name => :output_type
|
51
|
-
option "-s", "INPUT_TYPE",
|
51
|
+
option ["-s", "--input-type"], "INPUT_TYPE",
|
52
52
|
"the package type to use as input (gem, rpm, python, etc)",
|
53
53
|
:attribute_name => :input_type
|
54
|
-
option "-C", "CHDIR",
|
54
|
+
option ["-C", "--chdir"], "CHDIR",
|
55
55
|
"Change directory to here before searching for files",
|
56
56
|
:attribute_name => :chdir
|
57
57
|
option "--prefix", "PREFIX",
|
@@ -233,6 +233,20 @@ class FPM::Command < Clamp::Command
|
|
233
233
|
"copying, downloading, etc. Roughly any scratch space fpm needs to build " \
|
234
234
|
"your package.", :default => Dir.tmpdir
|
235
235
|
|
236
|
+
option "--source-date-epoch-from-changelog", :flag,
|
237
|
+
"Use release date from changelog as timestamp on generated files to reduce nondeterminism. " \
|
238
|
+
"Experimental; only implemented for gem so far. ",
|
239
|
+
:default => false
|
240
|
+
|
241
|
+
option "--source-date-epoch-default", "SOURCE_DATE_EPOCH_DEFAULT",
|
242
|
+
"If no release date otherwise specified, use this value as timestamp on generated files to reduce nondeterminism. " \
|
243
|
+
"Reproducible build environments such as dpkg-dev and rpmbuild set this via envionment variable SOURCE_DATE_EPOCH " \
|
244
|
+
"variable to the integer unix timestamp to use in generated archives, " \
|
245
|
+
"and expect tools like fpm to use it as a hint to avoid nondeterministic output. " \
|
246
|
+
"This is a Unix timestamp, i.e. number of seconds since 1 Jan 1970 UTC. " \
|
247
|
+
"See https://reproducible-builds.org/specs/source-date-epoch ",
|
248
|
+
:environment_variable => "SOURCE_DATE_EPOCH"
|
249
|
+
|
236
250
|
parameter "[ARGS] ...",
|
237
251
|
"Inputs to the source package type. For the 'dir' type, this is the files" \
|
238
252
|
" and directories you want to include in the package. For others, like " \
|
@@ -256,12 +270,6 @@ class FPM::Command < Clamp::Command
|
|
256
270
|
|
257
271
|
# Execute this command. See Clamp::Command#execute and Clamp's documentation
|
258
272
|
def execute
|
259
|
-
# Short-circuit if someone simply runs `fpm --version`
|
260
|
-
if ARGV == [ "--version" ]
|
261
|
-
puts FPM::VERSION
|
262
|
-
return 0
|
263
|
-
end
|
264
|
-
|
265
273
|
logger.level = :warn
|
266
274
|
logger.level = :info if verbose? # --verbose
|
267
275
|
logger.level = :debug if debug? # --debug
|
@@ -269,7 +277,6 @@ class FPM::Command < Clamp::Command
|
|
269
277
|
logger.level = log_level.to_sym
|
270
278
|
end
|
271
279
|
|
272
|
-
|
273
280
|
if (stray_flags = args.grep(/^-/); stray_flags.any?)
|
274
281
|
logger.warn("All flags should be before the first argument " \
|
275
282
|
"(stray flags found: #{stray_flags}")
|
@@ -514,9 +521,16 @@ class FPM::Command < Clamp::Command
|
|
514
521
|
end
|
515
522
|
end # def execute
|
516
523
|
|
517
|
-
def run(
|
524
|
+
def run(run_args)
|
518
525
|
logger.subscribe(STDOUT)
|
519
526
|
|
527
|
+
# Short circuit for a `fpm --version` or `fpm -v` short invocation that
|
528
|
+
# is the user asking us for the version of fpm.
|
529
|
+
if run_args == [ "-v" ] || run_args == [ "--version" ]
|
530
|
+
puts FPM::VERSION
|
531
|
+
return 0
|
532
|
+
end
|
533
|
+
|
520
534
|
# fpm initialization files, note the order of the following array is
|
521
535
|
# important, try .fpm in users home directory first and then the current
|
522
536
|
# directory
|
@@ -557,7 +571,7 @@ class FPM::Command < Clamp::Command
|
|
557
571
|
|
558
572
|
ARGV.unshift(*flags)
|
559
573
|
ARGV.push(*args)
|
560
|
-
super(
|
574
|
+
super(run_args)
|
561
575
|
rescue FPM::Package::InvalidArgument => e
|
562
576
|
logger.error("Invalid package argument: #{e}")
|
563
577
|
return 1
|
data/lib/fpm/package.rb
CHANGED
@@ -3,7 +3,8 @@ require "fpm/util" # local
|
|
3
3
|
require "pathname" # stdlib
|
4
4
|
require "find"
|
5
5
|
require "tmpdir" # stdlib
|
6
|
-
require "
|
6
|
+
require "ostruct"
|
7
|
+
require "backports/latest"
|
7
8
|
require "socket" # stdlib, for Socket.gethostname
|
8
9
|
require "shellwords" # stdlib, for Shellwords.escape
|
9
10
|
require "erb" # stdlib, for template processing
|
@@ -118,7 +119,10 @@ class FPM::Package
|
|
118
119
|
|
119
120
|
def initialize
|
120
121
|
# Attributes for this specific package
|
121
|
-
@attributes = {
|
122
|
+
@attributes = {
|
123
|
+
# Default work location
|
124
|
+
:workdir => ::Dir.tmpdir
|
125
|
+
}
|
122
126
|
|
123
127
|
# Reference
|
124
128
|
# http://www.debian.org/doc/manuals/maint-guide/first.en.html
|
@@ -175,8 +179,8 @@ class FPM::Package
|
|
175
179
|
@directories = []
|
176
180
|
@attrs = {}
|
177
181
|
|
178
|
-
staging_path
|
179
182
|
build_path
|
183
|
+
# Dont' initialize staging_path just yet, do it lazily so subclass can get a word in.
|
180
184
|
end # def initialize
|
181
185
|
|
182
186
|
# Get the 'type' for this instance.
|
@@ -386,7 +390,7 @@ class FPM::Package
|
|
386
390
|
installdir = staging_path
|
387
391
|
end
|
388
392
|
|
389
|
-
Find.find(
|
393
|
+
Find.find(installdir) do |path|
|
390
394
|
match_path = path.sub("#{installdir.chomp('/')}/", '')
|
391
395
|
|
392
396
|
attributes[:excludes].each do |wildcard|
|
@@ -492,6 +496,22 @@ class FPM::Package
|
|
492
496
|
return scripts.include?(name)
|
493
497
|
end # def script?
|
494
498
|
|
499
|
+
# write all scripts to .scripts (tar and dir)
|
500
|
+
def write_scripts
|
501
|
+
scripts_path = File.join(staging_path, ".scripts")
|
502
|
+
target_scripts = [:before_install, :after_install, :before_remove, :after_remove]
|
503
|
+
if target_scripts.any? {|name| script?(name)}
|
504
|
+
::Dir.mkdir(scripts_path)
|
505
|
+
target_scripts.each do |name|
|
506
|
+
next unless script?(name)
|
507
|
+
out = File.join(scripts_path, name.to_s)
|
508
|
+
logger.debug('Writing script', :source => name, :target => out)
|
509
|
+
File.write(out, script(name))
|
510
|
+
File.chmod(0755, out)
|
511
|
+
end
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
495
515
|
# Get the contents of the script by a given name.
|
496
516
|
#
|
497
517
|
# If template_scripts? is set in attributes (often by the --template-scripts
|
data/lib/fpm/package/apk.rb
CHANGED
@@ -3,12 +3,12 @@ require "fpm/namespace"
|
|
3
3
|
require "fpm/package"
|
4
4
|
require "fpm/errors"
|
5
5
|
require "fpm/util"
|
6
|
-
require "backports"
|
6
|
+
require "backports/latest"
|
7
7
|
require "fileutils"
|
8
8
|
require "digest"
|
9
9
|
require 'digest/sha1'
|
10
10
|
|
11
|
-
# Support for
|
11
|
+
# Support for Alpine packages (.apk files)
|
12
12
|
#
|
13
13
|
# This class supports both input and output of packages.
|
14
14
|
class FPM::Package::APK< FPM::Package
|
@@ -144,9 +144,9 @@ class FPM::Package::APK< FPM::Package
|
|
144
144
|
scripts = {}
|
145
145
|
|
146
146
|
scripts = register_script('post-install', :after_install, scripts)
|
147
|
-
scripts = register_script('
|
148
|
-
scripts = register_script('
|
149
|
-
scripts = register_script('post-
|
147
|
+
scripts = register_script('pre-install', :before_install, scripts)
|
148
|
+
scripts = register_script('pre-upgrade', :before_upgrade, scripts)
|
149
|
+
scripts = register_script('post-upgrade', :after_upgrade, scripts)
|
150
150
|
scripts = register_script('pre-deinstall', :before_remove, scripts)
|
151
151
|
scripts = register_script('post-deinstall', :after_remove, scripts)
|
152
152
|
|
@@ -238,7 +238,7 @@ class FPM::Package::APK< FPM::Package
|
|
238
238
|
record_length = determine_record_length(record_length)
|
239
239
|
|
240
240
|
until(data.length == record_length)
|
241
|
-
data
|
241
|
+
data << file.read(TAR_CHUNK_SIZE)
|
242
242
|
end
|
243
243
|
|
244
244
|
# Clear ownership fields
|
data/lib/fpm/package/cpan.rb
CHANGED
@@ -25,6 +25,9 @@ class FPM::Package::CPAN < FPM::Package
|
|
25
25
|
option "--test", :flag,
|
26
26
|
"Run the tests before packaging?", :default => true
|
27
27
|
|
28
|
+
option "--verbose", :flag,
|
29
|
+
"Produce verbose output from cpanm?", :default => false
|
30
|
+
|
28
31
|
option "--perl-lib-path", "PERL_LIB_PATH",
|
29
32
|
"Path of target Perl Libraries"
|
30
33
|
|
@@ -49,6 +52,7 @@ class FPM::Package::CPAN < FPM::Package
|
|
49
52
|
|
50
53
|
if File.exist?(package)
|
51
54
|
moduledir = package
|
55
|
+
result = {}
|
52
56
|
else
|
53
57
|
result = search(package)
|
54
58
|
tarball = download(result, version)
|
@@ -98,6 +102,12 @@ class FPM::Package::CPAN < FPM::Package
|
|
98
102
|
self.name = fix_name(metadata["name"])
|
99
103
|
end
|
100
104
|
|
105
|
+
unless metadata["module"].nil?
|
106
|
+
metadata["module"].each do |m|
|
107
|
+
self.provides << cap_name(m["name"]) + " = #{self.version}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
101
111
|
# author is not always set or it may be a string instead of an array
|
102
112
|
self.vendor = case metadata["author"]
|
103
113
|
when String; metadata["author"]
|
@@ -130,6 +140,7 @@ class FPM::Package::CPAN < FPM::Package
|
|
130
140
|
cpanm_flags += ["--mirror", "#{attributes[:cpan_mirror]}"] if !attributes[:cpan_mirror].nil?
|
131
141
|
cpanm_flags += ["--mirror-only"] if attributes[:cpan_mirror_only?] && !attributes[:cpan_mirror].nil?
|
132
142
|
cpanm_flags += ["--force"] if attributes[:cpan_cpanm_force?]
|
143
|
+
cpanm_flags += ["--verbose"] if attributes[:cpan_verbose?]
|
133
144
|
|
134
145
|
safesystem(attributes[:cpan_cpanm_bin], *cpanm_flags)
|
135
146
|
|
@@ -149,16 +160,16 @@ class FPM::Package::CPAN < FPM::Package
|
|
149
160
|
found_dependencies.each do |dep_name, version|
|
150
161
|
# Special case for representing perl core as a version.
|
151
162
|
if dep_name == "perl"
|
163
|
+
m = version.to_s.match(/^(\d)\.(\d{3})(\d{3})$/)
|
164
|
+
if m
|
165
|
+
version = m[1] + '.' + m[2].sub(/^0*/, '') + '.' + m[3].sub(/^0*/, '')
|
166
|
+
end
|
152
167
|
self.dependencies << "#{dep_name} >= #{version}"
|
153
168
|
next
|
154
169
|
end
|
155
170
|
dep = search(dep_name)
|
156
171
|
|
157
|
-
|
158
|
-
name = fix_name(dep["distribution"])
|
159
|
-
else
|
160
|
-
name = fix_name(dep_name)
|
161
|
-
end
|
172
|
+
name = cap_name(dep_name)
|
162
173
|
|
163
174
|
if version.to_s == "0"
|
164
175
|
# Assume 'Foo = 0' means any version?
|
@@ -166,12 +177,14 @@ class FPM::Package::CPAN < FPM::Package
|
|
166
177
|
else
|
167
178
|
# The 'version' string can be something complex like:
|
168
179
|
# ">= 0, != 1.0, != 1.2"
|
180
|
+
# If it is not specified explicitly, require the given
|
181
|
+
# version or newer, as that is all CPAN itself enforces
|
169
182
|
if version.is_a?(String)
|
170
183
|
version.split(/\s*,\s*/).each do |v|
|
171
184
|
if v =~ /\s*[><=]/
|
172
185
|
self.dependencies << "#{name} #{v}"
|
173
186
|
else
|
174
|
-
self.dependencies << "#{name}
|
187
|
+
self.dependencies << "#{name} >= #{v}"
|
175
188
|
end
|
176
189
|
end
|
177
190
|
else
|
@@ -232,11 +245,7 @@ class FPM::Package::CPAN < FPM::Package
|
|
232
245
|
# Empty install_base to avoid local::lib being used.
|
233
246
|
"INSTALL_BASE=")
|
234
247
|
end
|
235
|
-
|
236
|
-
make = [ "env", "PERL5LIB=#{build_path("cpan/lib/perl5")}", "make" ]
|
237
|
-
else
|
238
|
-
make = [ "make" ]
|
239
|
-
end
|
248
|
+
make = [ "env", "PERL5LIB=#{build_path("cpan/lib/perl5")}", "make" ]
|
240
249
|
safesystem(*make)
|
241
250
|
safesystem(*(make + ["test"])) if attributes[:cpan_test?]
|
242
251
|
safesystem(*(make + ["DESTDIR=#{staging_path}", "install"]))
|
@@ -258,7 +267,7 @@ class FPM::Package::CPAN < FPM::Package
|
|
258
267
|
:path => path.gsub(staging_path, ""))
|
259
268
|
File.unlink(path)
|
260
269
|
end
|
261
|
-
|
270
|
+
|
262
271
|
# Remove useless .packlist files and their empty parent folders
|
263
272
|
# https://github.com/jordansissel/fpm/issues/1179
|
264
273
|
::Dir.glob(File.join(staging_path, glob_prefix, "**/.packlist")).each do |path|
|
@@ -308,38 +317,35 @@ class FPM::Package::CPAN < FPM::Package
|
|
308
317
|
:distribution => distribution,
|
309
318
|
:version => cpan_version)
|
310
319
|
|
311
|
-
# default to latest
|
320
|
+
# default to latest version unless we specify one
|
312
321
|
if cpan_version.nil?
|
313
|
-
self.version = metadata["version"]
|
322
|
+
self.version = "#{metadata["version"]}"
|
314
323
|
else
|
315
|
-
|
316
|
-
self.version = "v#{cpan_version}"
|
317
|
-
else
|
318
|
-
self.version = cpan_version
|
319
|
-
end
|
324
|
+
self.version = "#{cpan_version}"
|
320
325
|
end
|
321
326
|
|
322
|
-
|
327
|
+
# Search metacpan to get download URL for this version of the module
|
328
|
+
metacpan_search_url = "https://fastapi.metacpan.org/v1/release/_search"
|
329
|
+
metacpan_search_query = '{"fields":["download_url"],"filter":{"term":{"name":"' + "#{distribution}-#{self.version}" + '"}}}'
|
323
330
|
begin
|
324
|
-
|
331
|
+
search_response = httppost(metacpan_search_url,metacpan_search_query)
|
325
332
|
rescue Net::HTTPServerException => e
|
326
333
|
logger.error("metacpan release query failed.", :error => e.message,
|
327
|
-
:url =>
|
334
|
+
:url => metacpan_search_url)
|
328
335
|
raise FPM::InvalidPackageConfiguration, "metacpan release query failed"
|
329
336
|
end
|
330
337
|
|
331
|
-
data =
|
338
|
+
data = search_response.body
|
332
339
|
release_metadata = JSON.parse(data)
|
333
|
-
archive = release_metadata["archive"]
|
334
340
|
|
335
|
-
|
336
|
-
|
341
|
+
download_url = release_metadata['hits']['hits'][0]['fields']['download_url']
|
342
|
+
download_path = URI.parse(download_url).path
|
343
|
+
tarball = File.basename(download_path)
|
337
344
|
|
338
345
|
url_base = "http://www.cpan.org/"
|
339
346
|
url_base = "#{attributes[:cpan_mirror]}" if !attributes[:cpan_mirror].nil?
|
340
347
|
|
341
|
-
|
342
|
-
url = "#{url_base}/authors/id/#{author[0,1]}/#{author[0,2]}/#{author}/#{archive}"
|
348
|
+
url = "#{url_base}#{download_path}"
|
343
349
|
logger.debug("Fetching perl module", :url => url)
|
344
350
|
|
345
351
|
begin
|
@@ -360,7 +366,7 @@ class FPM::Package::CPAN < FPM::Package
|
|
360
366
|
|
361
367
|
def search(package)
|
362
368
|
logger.info("Asking metacpan about a module", :module => package)
|
363
|
-
metacpan_url = "
|
369
|
+
metacpan_url = "https://fastapi.metacpan.org/v1/module/" + package
|
364
370
|
begin
|
365
371
|
response = httpfetch(metacpan_url)
|
366
372
|
rescue Net::HTTPServerException => e
|
@@ -378,6 +384,10 @@ class FPM::Package::CPAN < FPM::Package
|
|
378
384
|
return metadata
|
379
385
|
end # def metadata
|
380
386
|
|
387
|
+
def cap_name(name)
|
388
|
+
return "perl(" + name.gsub("-", "::") + ")"
|
389
|
+
end # def cap_name
|
390
|
+
|
381
391
|
def fix_name(name)
|
382
392
|
case name
|
383
393
|
when "perl"; return "perl"
|
@@ -393,6 +403,7 @@ class FPM::Package::CPAN < FPM::Package
|
|
393
403
|
else
|
394
404
|
http = Net::HTTP.new(uri.host, uri.port)
|
395
405
|
end
|
406
|
+
http.use_ssl = uri.scheme == 'https'
|
396
407
|
response = http.request(Net::HTTP::Get.new(uri.request_uri))
|
397
408
|
case response
|
398
409
|
when Net::HTTPSuccess; return response
|
@@ -401,5 +412,22 @@ class FPM::Package::CPAN < FPM::Package
|
|
401
412
|
end
|
402
413
|
end
|
403
414
|
|
415
|
+
def httppost(url, body)
|
416
|
+
uri = URI.parse(url)
|
417
|
+
if ENV['http_proxy']
|
418
|
+
proxy = URI.parse(ENV['http_proxy'])
|
419
|
+
http = Net::HTTP.Proxy(proxy.host,proxy.port,proxy.user,proxy.password).new(uri.host, uri.port)
|
420
|
+
else
|
421
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
422
|
+
end
|
423
|
+
http.use_ssl = uri.scheme == 'https'
|
424
|
+
response = http.post(uri.request_uri, body)
|
425
|
+
case response
|
426
|
+
when Net::HTTPSuccess; return response
|
427
|
+
when Net::HTTPRedirection; return httppost(response["location"])
|
428
|
+
else; response.error!
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
404
432
|
public(:input)
|
405
433
|
end # class FPM::Package::NPM
|
data/lib/fpm/package/deb.rb
CHANGED
@@ -3,7 +3,7 @@ require "fpm/namespace"
|
|
3
3
|
require "fpm/package"
|
4
4
|
require "fpm/errors"
|
5
5
|
require "fpm/util"
|
6
|
-
require "backports"
|
6
|
+
require "backports/latest"
|
7
7
|
require "fileutils"
|
8
8
|
require "digest"
|
9
9
|
|
@@ -18,10 +18,11 @@ class FPM::Package::Deb < FPM::Package
|
|
18
18
|
:after_install => "postinst",
|
19
19
|
:before_remove => "prerm",
|
20
20
|
:after_remove => "postrm",
|
21
|
+
:after_purge => "postrm",
|
21
22
|
} unless defined?(SCRIPT_MAP)
|
22
23
|
|
23
24
|
# The list of supported compression types. Default is gz (gzip)
|
24
|
-
COMPRESSION_TYPES = [ "gz", "bzip2", "xz" ]
|
25
|
+
COMPRESSION_TYPES = [ "gz", "bzip2", "xz", "none" ]
|
25
26
|
|
26
27
|
option "--ignore-iteration-in-dependencies", :flag,
|
27
28
|
"For '=' (equal) dependencies, allow iterations on the specified " \
|
@@ -49,6 +50,8 @@ class FPM::Package::Deb < FPM::Package
|
|
49
50
|
value
|
50
51
|
end
|
51
52
|
|
53
|
+
option "--dist", "DIST-TAG", "Set the deb distribution.", :default => "unstable"
|
54
|
+
|
52
55
|
# Take care about the case when we want custom control file but still use fpm ...
|
53
56
|
option "--custom-control", "FILEPATH",
|
54
57
|
"Custom version of the Debian control file." do |control|
|
@@ -87,6 +90,10 @@ class FPM::Package::Deb < FPM::Package
|
|
87
90
|
File.expand_path(file)
|
88
91
|
end
|
89
92
|
|
93
|
+
option "--generate-changes", :flag,
|
94
|
+
"Generate PACKAGENAME.changes file.",
|
95
|
+
:default => false
|
96
|
+
|
90
97
|
option "--upstream-changelog", "FILEPATH", "Add FILEPATH as upstream changelog" do |file|
|
91
98
|
File.expand_path(file)
|
92
99
|
end
|
@@ -121,6 +128,18 @@ class FPM::Package::Deb < FPM::Package
|
|
121
128
|
next @activated_triggers
|
122
129
|
end
|
123
130
|
|
131
|
+
option "--interest-noawait", "EVENT", "Package is interested in EVENT trigger without awaiting" do |event|
|
132
|
+
@interested_noawait_triggers ||= []
|
133
|
+
@interested_noawait_triggers << event
|
134
|
+
next @interested_noawait_triggers
|
135
|
+
end
|
136
|
+
|
137
|
+
option "--activate-noawait", "EVENT", "Package activates EVENT trigger" do |event|
|
138
|
+
@activated_noawait_triggers ||= []
|
139
|
+
@activated_noawait_triggers << event
|
140
|
+
next @activated_noawait_triggers
|
141
|
+
end
|
142
|
+
|
124
143
|
option "--field", "'FIELD: VALUE'", "Add custom field to the control file" do |fv|
|
125
144
|
@custom_fields ||= {}
|
126
145
|
field, value = fv.split(/: */, 2)
|
@@ -162,8 +181,18 @@ class FPM::Package::Deb < FPM::Package
|
|
162
181
|
next File.expand_path(file)
|
163
182
|
end
|
164
183
|
|
184
|
+
option "--systemd-enable", :flag , "Enable service on install or upgrade", :default => false
|
185
|
+
|
186
|
+
option "--systemd-auto-start", :flag , "Start service after install or upgrade", :default => false
|
187
|
+
|
165
188
|
option "--systemd-restart-after-upgrade", :flag , "Restart service after upgrade", :default => true
|
166
189
|
|
190
|
+
option "--after-purge", "FILE",
|
191
|
+
"A script to be run after package removal to purge remaining (config) files " \
|
192
|
+
"(a.k.a. postrm purge within apt-get purge)" do |val|
|
193
|
+
File.expand_path(val) # Get the full path to the script
|
194
|
+
end # --after-purge
|
195
|
+
|
167
196
|
def initialize(*args)
|
168
197
|
super(*args)
|
169
198
|
attributes[:deb_priority] = "extra"
|
@@ -240,10 +269,32 @@ class FPM::Package::Deb < FPM::Package
|
|
240
269
|
end # def input
|
241
270
|
|
242
271
|
def extract_info(package)
|
272
|
+
compression = `#{ar_cmd[0]} t #{package}`.split("\n").grep(/control.tar/).first.split(".").last
|
273
|
+
case compression
|
274
|
+
when "gz"
|
275
|
+
controltar = "control.tar.gz"
|
276
|
+
compression = "-z"
|
277
|
+
when "bzip2","bz2"
|
278
|
+
controltar = "control.tar.bz2"
|
279
|
+
compression = "-j"
|
280
|
+
when "xz"
|
281
|
+
controltar = "control.tar.xz"
|
282
|
+
compression = "-J"
|
283
|
+
when 'tar'
|
284
|
+
controltar = "control.tar"
|
285
|
+
compression = ""
|
286
|
+
when nil
|
287
|
+
raise FPM::InvalidPackageConfiguration, "Missing control.tar in deb source package #{package}"
|
288
|
+
else
|
289
|
+
raise FPM::InvalidPackageConfiguration,
|
290
|
+
"Unknown compression type '#{compression}' for control.tar in deb source package #{package}"
|
291
|
+
end
|
292
|
+
|
243
293
|
build_path("control").tap do |path|
|
244
294
|
FileUtils.mkdir(path) if !File.directory?(path)
|
295
|
+
# unpack the control.tar.{,gz,bz2,xz} from the deb package into staging_path
|
245
296
|
# Unpack the control tarball
|
246
|
-
safesystem("
|
297
|
+
safesystem(ar_cmd[0] + " p #{package} #{controltar} | tar #{compression} -xf - -C #{path}")
|
247
298
|
|
248
299
|
control = File.read(File.join(path, "control"))
|
249
300
|
|
@@ -340,26 +391,29 @@ class FPM::Package::Deb < FPM::Package
|
|
340
391
|
|
341
392
|
def extract_files(package)
|
342
393
|
# Find out the compression type
|
343
|
-
compression =
|
394
|
+
compression = `#{ar_cmd[0]} t #{package}`.split("\n").grep(/data.tar/).first.split(".").last
|
344
395
|
case compression
|
345
396
|
when "gz"
|
346
397
|
datatar = "data.tar.gz"
|
347
398
|
compression = "-z"
|
348
|
-
when "bzip2"
|
399
|
+
when "bzip2","bz2"
|
349
400
|
datatar = "data.tar.bz2"
|
350
401
|
compression = "-j"
|
351
402
|
when "xz"
|
352
403
|
datatar = "data.tar.xz"
|
353
404
|
compression = "-J"
|
405
|
+
when 'tar'
|
406
|
+
datatar = "data.tar"
|
407
|
+
compression = ""
|
408
|
+
when nil
|
409
|
+
raise FPM::InvalidPackageConfiguration, "Missing data.tar in deb source package #{package}"
|
354
410
|
else
|
355
411
|
raise FPM::InvalidPackageConfiguration,
|
356
|
-
"Unknown compression type '#{
|
357
|
-
"in deb source package #{package}"
|
412
|
+
"Unknown compression type '#{compression}' for data.tar in deb source package #{package}"
|
358
413
|
end
|
359
414
|
|
360
415
|
# unpack the data.tar.{gz,bz2,xz} from the deb package into staging_path
|
361
|
-
safesystem("
|
362
|
-
"| tar #{compression} -xf - -C #{staging_path}")
|
416
|
+
safesystem(ar_cmd[0] + " p #{package} #{datatar} | tar #{compression} -xf - -C #{staging_path}")
|
363
417
|
end # def extract_files
|
364
418
|
|
365
419
|
def output(output_path)
|
@@ -387,6 +441,23 @@ class FPM::Package::Deb < FPM::Package
|
|
387
441
|
end
|
388
442
|
end
|
389
443
|
|
444
|
+
if attributes[:source_date_epoch].nil? and not attributes[:source_date_epoch_default].nil?
|
445
|
+
attributes[:source_date_epoch] = attributes[:source_date_epoch_default]
|
446
|
+
end
|
447
|
+
if attributes[:source_date_epoch] == "0"
|
448
|
+
logger.error("Alas, ruby's Zlib::GzipWriter does not support setting an mtime of zero. Aborting.")
|
449
|
+
raise "#{name}: source_date_epoch of 0 not supported."
|
450
|
+
end
|
451
|
+
if not attributes[:source_date_epoch].nil? and not ar_cmd_deterministic?
|
452
|
+
logger.error("Alas, could not find an ar that can handle -D option. Try installing recent gnu binutils. Aborting.")
|
453
|
+
raise "#{name}: ar is insufficient to support source_date_epoch."
|
454
|
+
end
|
455
|
+
if not attributes[:source_date_epoch].nil? and not tar_cmd_supports_sort_names_and_set_mtime?
|
456
|
+
logger.error("Alas, could not find a tar that can set mtime and sort. Try installing recent gnu tar. Aborting.")
|
457
|
+
raise "#{name}: tar is insufficient to support source_date_epoch."
|
458
|
+
end
|
459
|
+
|
460
|
+
attributes[:deb_systemd] = []
|
390
461
|
attributes.fetch(:deb_systemd_list, []).each do |systemd|
|
391
462
|
name = File.basename(systemd, ".service")
|
392
463
|
dest_systemd = staging_path("lib/systemd/system/#{name}.service")
|
@@ -394,42 +465,27 @@ class FPM::Package::Deb < FPM::Package
|
|
394
465
|
FileUtils.cp(systemd, dest_systemd)
|
395
466
|
File.chmod(0644, dest_systemd)
|
396
467
|
|
397
|
-
#
|
398
|
-
attributes[:deb_systemd]
|
468
|
+
# add systemd service name to attribute
|
469
|
+
attributes[:deb_systemd] << name
|
399
470
|
end
|
400
471
|
|
401
|
-
if script?(:before_upgrade) or script?(:after_upgrade) or attributes[:deb_systemd]
|
472
|
+
if script?(:before_upgrade) or script?(:after_upgrade) or attributes[:deb_systemd].any?
|
402
473
|
puts "Adding action files"
|
403
474
|
if script?(:before_install) or script?(:before_upgrade)
|
404
475
|
scripts[:before_install] = template("deb/preinst_upgrade.sh.erb").result(binding)
|
405
476
|
end
|
406
|
-
if script?(:before_remove) or attributes[:deb_systemd]
|
477
|
+
if script?(:before_remove) or not attributes[:deb_systemd].empty?
|
407
478
|
scripts[:before_remove] = template("deb/prerm_upgrade.sh.erb").result(binding)
|
408
479
|
end
|
409
|
-
if script?(:after_install) or script?(:after_upgrade) or attributes[:deb_systemd]
|
480
|
+
if script?(:after_install) or script?(:after_upgrade) or attributes[:deb_systemd].any?
|
410
481
|
scripts[:after_install] = template("deb/postinst_upgrade.sh.erb").result(binding)
|
411
482
|
end
|
412
483
|
if script?(:after_remove)
|
413
484
|
scripts[:after_remove] = template("deb/postrm_upgrade.sh.erb").result(binding)
|
414
485
|
end
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
# Tar up the staging_path into data.tar.{compression type}
|
420
|
-
case self.attributes[:deb_compression]
|
421
|
-
when "gz", nil
|
422
|
-
datatar = build_path("data.tar.gz")
|
423
|
-
compression = "-z"
|
424
|
-
when "bzip2"
|
425
|
-
datatar = build_path("data.tar.bz2")
|
426
|
-
compression = "-j"
|
427
|
-
when "xz"
|
428
|
-
datatar = build_path("data.tar.xz")
|
429
|
-
compression = "-J"
|
430
|
-
else
|
431
|
-
raise FPM::InvalidPackageConfiguration,
|
432
|
-
"Unknown compression type '#{self.attributes[:deb_compression]}'"
|
486
|
+
if script?(:after_purge)
|
487
|
+
scripts[:after_purge] = template("deb/postrm_upgrade.sh.erb").result(binding)
|
488
|
+
end
|
433
489
|
end
|
434
490
|
|
435
491
|
# There are two changelogs that may appear:
|
@@ -442,6 +498,9 @@ class FPM::Package::Deb < FPM::Package
|
|
442
498
|
mkdir_p(File.dirname(dest_changelog))
|
443
499
|
File.new(dest_changelog, "wb", 0644).tap do |changelog|
|
444
500
|
Zlib::GzipWriter.new(changelog, Zlib::BEST_COMPRESSION).tap do |changelog_gz|
|
501
|
+
if not attributes[:source_date_epoch].nil?
|
502
|
+
changelog_gz.mtime = attributes[:source_date_epoch].to_i
|
503
|
+
end
|
445
504
|
if attributes[:deb_changelog]
|
446
505
|
logger.info("Writing user-specified changelog", :source => attributes[:deb_changelog])
|
447
506
|
File.new(attributes[:deb_changelog]).tap do |fd|
|
@@ -461,6 +520,9 @@ class FPM::Package::Deb < FPM::Package
|
|
461
520
|
if attributes[:deb_upstream_changelog]
|
462
521
|
File.new(dest_upstream_changelog, "wb", 0644).tap do |changelog|
|
463
522
|
Zlib::GzipWriter.new(changelog, Zlib::BEST_COMPRESSION).tap do |changelog_gz|
|
523
|
+
if not attributes[:source_date_epoch].nil?
|
524
|
+
changelog_gz.mtime = attributes[:source_date_epoch].to_i
|
525
|
+
end
|
464
526
|
logger.info("Writing user-specified upstream changelog", :source => attributes[:deb_upstream_changelog])
|
465
527
|
File.new(attributes[:deb_upstream_changelog]).tap do |fd|
|
466
528
|
chunk = nil
|
@@ -494,6 +556,7 @@ class FPM::Package::Deb < FPM::Package
|
|
494
556
|
|
495
557
|
attributes.fetch(:deb_upstart_list, []).each do |upstart|
|
496
558
|
name = File.basename(upstart, ".upstart")
|
559
|
+
dest_init = staging_path("etc/init.d/#{name}")
|
497
560
|
name = "#{name}.conf" if !(name =~ /\.conf$/)
|
498
561
|
dest_upstart = staging_path("etc/init/#{name}")
|
499
562
|
mkdir_p(File.dirname(dest_upstart))
|
@@ -501,7 +564,6 @@ class FPM::Package::Deb < FPM::Package
|
|
501
564
|
File.chmod(0644, dest_upstart)
|
502
565
|
|
503
566
|
# Install an init.d shim that calls upstart
|
504
|
-
dest_init = staging_path("etc/init.d/#{name}")
|
505
567
|
mkdir_p(File.dirname(dest_init))
|
506
568
|
FileUtils.ln_s("/lib/init/upstart-job", dest_init)
|
507
569
|
end
|
@@ -527,21 +589,54 @@ class FPM::Package::Deb < FPM::Package
|
|
527
589
|
when "xz"
|
528
590
|
datatar = build_path("data.tar.xz")
|
529
591
|
compression = "-J"
|
592
|
+
when "none"
|
593
|
+
datatar = build_path("data.tar")
|
594
|
+
compression = ""
|
530
595
|
else
|
531
596
|
raise FPM::InvalidPackageConfiguration,
|
532
597
|
"Unknown compression type '#{self.attributes[:deb_compression]}'"
|
533
598
|
end
|
534
599
|
|
535
600
|
args = [ tar_cmd, "-C", staging_path, compression ] + data_tar_flags + [ "-cf", datatar, "." ]
|
601
|
+
if tar_cmd_supports_sort_names_and_set_mtime? and not attributes[:source_date_epoch].nil?
|
602
|
+
# Use gnu tar options to force deterministic file order and timestamp
|
603
|
+
args += ["--sort=name", ("--mtime=@%s" % attributes[:source_date_epoch])]
|
604
|
+
# gnu tar obeys GZIP environment variable with options for gzip; -n = forget original filename and date
|
605
|
+
args.unshift({"GZIP" => "-9n"})
|
606
|
+
end
|
536
607
|
safesystem(*args)
|
537
608
|
|
538
609
|
# pack up the .deb, which is just an 'ar' archive with 3 files
|
539
610
|
# the 'debian-binary' file has to be first
|
540
611
|
File.expand_path(output_path).tap do |output_path|
|
541
612
|
::Dir.chdir(build_path) do
|
542
|
-
safesystem(
|
613
|
+
safesystem(*ar_cmd, output_path, "debian-binary", "control.tar.gz", datatar)
|
543
614
|
end
|
544
615
|
end
|
616
|
+
|
617
|
+
# if a PACKAGENAME.changes file is to be created
|
618
|
+
if self.attributes[:deb_generate_changes?]
|
619
|
+
distribution = self.attributes[:deb_dist]
|
620
|
+
|
621
|
+
# gather information about the files to distribute
|
622
|
+
files = [ output_path ]
|
623
|
+
changes_files = []
|
624
|
+
files.each do |path|
|
625
|
+
changes_files.push({
|
626
|
+
:name => path,
|
627
|
+
:size => File.size?(path),
|
628
|
+
:md5sum => Digest::MD5.file(path).hexdigest,
|
629
|
+
:sha1sum => Digest::SHA1.file(path).hexdigest,
|
630
|
+
:sha256sum => Digest::SHA2.file(path).hexdigest,
|
631
|
+
})
|
632
|
+
end
|
633
|
+
|
634
|
+
# write change infos to .changes file
|
635
|
+
changes_path = File.basename(output_path, '.deb') + '.changes'
|
636
|
+
changes_data = template("deb/deb.changes.erb").result(binding)
|
637
|
+
File.write(changes_path, changes_data)
|
638
|
+
logger.log("Created changes", :path => changes_path)
|
639
|
+
end # if deb_generate_changes
|
545
640
|
end # def output
|
546
641
|
|
547
642
|
def converted_from(origin)
|
@@ -687,12 +782,37 @@ class FPM::Package::Deb < FPM::Package
|
|
687
782
|
write_triggers # write trigger config to 'triggers' file
|
688
783
|
write_md5sums # write the md5sums file
|
689
784
|
|
785
|
+
# Tar up the staging_path into control.tar.{compression type}
|
786
|
+
case self.attributes[:deb_compression]
|
787
|
+
when "gz", nil
|
788
|
+
controltar = "control.tar.gz"
|
789
|
+
compression = "-z"
|
790
|
+
when "bzip2"
|
791
|
+
controltar = "control.tar.bz2"
|
792
|
+
compression = "-j"
|
793
|
+
when "xz"
|
794
|
+
controltar = "control.tar.xz"
|
795
|
+
compression = "-J"
|
796
|
+
when "none"
|
797
|
+
controltar = "control.tar"
|
798
|
+
compression = ""
|
799
|
+
else
|
800
|
+
raise FPM::InvalidPackageConfiguration,
|
801
|
+
"Unknown compression type '#{self.attributes[:deb_compression]}'"
|
802
|
+
end
|
803
|
+
|
690
804
|
# Make the control.tar.gz
|
691
|
-
build_path(
|
805
|
+
build_path(controltar).tap do |controltar|
|
692
806
|
logger.info("Creating", :path => controltar, :from => control_path)
|
693
807
|
|
694
|
-
args = [ tar_cmd, "-C", control_path, "-
|
808
|
+
args = [ tar_cmd, "-C", control_path, compression, "-cf", controltar,
|
695
809
|
"--owner=0", "--group=0", "--numeric-owner", "." ]
|
810
|
+
if tar_cmd_supports_sort_names_and_set_mtime? and not attributes[:source_date_epoch].nil?
|
811
|
+
# Force deterministic file order and timestamp
|
812
|
+
args += ["--sort=name", ("--mtime=@%s" % attributes[:source_date_epoch])]
|
813
|
+
# gnu tar obeys GZIP environment variable with options for gzip; -n = forget original filename and date
|
814
|
+
args.unshift({"GZIP" => "-9n"})
|
815
|
+
end
|
696
816
|
safesystem(*args)
|
697
817
|
end
|
698
818
|
|
@@ -789,11 +909,25 @@ class FPM::Package::Deb < FPM::Package
|
|
789
909
|
|
790
910
|
# scan all conf file paths for files and add them
|
791
911
|
config_files.each do |path|
|
912
|
+
logger.debug("Checking if #{path} exists")
|
913
|
+
cfe = File.exist?("#{path}")
|
914
|
+
logger.debug("Check result #{cfe}")
|
792
915
|
begin
|
793
916
|
add_path(path, allconfigs)
|
794
917
|
rescue Errno::ENOENT
|
795
|
-
|
796
|
-
|
918
|
+
if !cfe
|
919
|
+
raise FPM::InvalidPackageConfiguration,
|
920
|
+
"Error trying to use '#{path}' as a config file in the package. Does it exist?"
|
921
|
+
else
|
922
|
+
dcl = File.join(staging_path, path)
|
923
|
+
if !File.exist?("#{dcl}")
|
924
|
+
logger.debug("Adding config file #{path} to Staging area #{staging_path}")
|
925
|
+
FileUtils.mkdir_p(File.dirname(dcl))
|
926
|
+
FileUtils.cp_r path, dcl
|
927
|
+
else
|
928
|
+
logger.debug("Config file aready exists in staging area.")
|
929
|
+
end
|
930
|
+
end
|
797
931
|
end
|
798
932
|
end
|
799
933
|
|
@@ -849,7 +983,7 @@ class FPM::Package::Deb < FPM::Package
|
|
849
983
|
|
850
984
|
if attributes[:deb_templates]
|
851
985
|
FileUtils.cp(attributes[:deb_templates], control_path("templates"))
|
852
|
-
File.chmod(
|
986
|
+
File.chmod(0644, control_path("templates"))
|
853
987
|
end
|
854
988
|
end # def write_debconf
|
855
989
|
|
@@ -865,7 +999,10 @@ class FPM::Package::Deb < FPM::Package
|
|
865
999
|
|
866
1000
|
def write_triggers
|
867
1001
|
lines = [['interest', :deb_interest],
|
868
|
-
['activate', :deb_activate]
|
1002
|
+
['activate', :deb_activate],
|
1003
|
+
['interest-noawait', :deb_interest_noawait],
|
1004
|
+
['activate-noawait', :deb_activate_noawait],
|
1005
|
+
].map { |label, attr|
|
869
1006
|
(attributes[attr] || []).map { |e| "#{label} #{e}\n" }
|
870
1007
|
}.flatten.join('')
|
871
1008
|
|