fpm-aeppert 1.6.2 → 1.11.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|