fpm 1.6.1 → 1.14.1

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.
@@ -3,9 +3,14 @@ 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
+ require "zlib"
10
+
11
+ # For handling conversion
12
+ require "fpm/package/cpan"
13
+ require "fpm/package/gem"
9
14
 
10
15
  # Support for debian packages (.deb files)
11
16
  #
@@ -18,10 +23,22 @@ class FPM::Package::Deb < FPM::Package
18
23
  :after_install => "postinst",
19
24
  :before_remove => "prerm",
20
25
  :after_remove => "postrm",
26
+ :after_purge => "postrm",
21
27
  } unless defined?(SCRIPT_MAP)
22
28
 
23
29
  # The list of supported compression types. Default is gz (gzip)
24
- COMPRESSION_TYPES = [ "gz", "bzip2", "xz" ]
30
+ COMPRESSION_TYPES = [ "gz", "bzip2", "xz", "none" ]
31
+
32
+ # https://www.debian.org/doc/debian-policy/ch-relationships.html#syntax-of-relationship-fields
33
+ # Example value with version relationship: libc6 (>= 2.2.1)
34
+ # Example value: libc6
35
+
36
+ # Version string docs here: https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-version
37
+ # The format is: [epoch:]upstream_version[-debian_revision].
38
+ # epoch - This is a single (generally small) unsigned integer
39
+ # upstream_version - must contain only alphanumerics 6 and the characters . + - ~
40
+ # debian_revision - only alphanumerics and the characters + . ~
41
+ RELATIONSHIP_FIELD_PATTERN = /^(?<name>[A-z0-9_-]+)(?: *\((?<relation>[<>=]+) *(?<version>(?:[0-9]+:)?[0-9A-Za-z+~.-]+(?:-[0-9A-Za-z+~.]+)?)\))?$/
25
42
 
26
43
  option "--ignore-iteration-in-dependencies", :flag,
27
44
  "For '=' (equal) dependencies, allow iterations on the specified " \
@@ -49,6 +66,8 @@ class FPM::Package::Deb < FPM::Package
49
66
  value
50
67
  end
51
68
 
69
+ option "--dist", "DIST-TAG", "Set the deb distribution.", :default => "unstable"
70
+
52
71
  # Take care about the case when we want custom control file but still use fpm ...
53
72
  option "--custom-control", "FILEPATH",
54
73
  "Custom version of the Debian control file." do |control|
@@ -87,6 +106,10 @@ class FPM::Package::Deb < FPM::Package
87
106
  File.expand_path(file)
88
107
  end
89
108
 
109
+ option "--generate-changes", :flag,
110
+ "Generate PACKAGENAME.changes file.",
111
+ :default => false
112
+
90
113
  option "--upstream-changelog", "FILEPATH", "Add FILEPATH as upstream changelog" do |file|
91
114
  File.expand_path(file)
92
115
  end
@@ -121,6 +144,18 @@ class FPM::Package::Deb < FPM::Package
121
144
  next @activated_triggers
122
145
  end
123
146
 
147
+ option "--interest-noawait", "EVENT", "Package is interested in EVENT trigger without awaiting" do |event|
148
+ @interested_noawait_triggers ||= []
149
+ @interested_noawait_triggers << event
150
+ next @interested_noawait_triggers
151
+ end
152
+
153
+ option "--activate-noawait", "EVENT", "Package activates EVENT trigger" do |event|
154
+ @activated_noawait_triggers ||= []
155
+ @activated_noawait_triggers << event
156
+ next @activated_noawait_triggers
157
+ end
158
+
124
159
  option "--field", "'FIELD: VALUE'", "Add custom field to the control file" do |fv|
125
160
  @custom_fields ||= {}
126
161
  field, value = fv.split(/: */, 2)
@@ -158,12 +193,27 @@ class FPM::Package::Deb < FPM::Package
158
193
  end
159
194
 
160
195
  option "--systemd", "FILEPATH", "Add FILEPATH as a systemd script",
161
- :multivalued => true do |file|
196
+ :multivalued => true do |file|
162
197
  next File.expand_path(file)
163
198
  end
164
199
 
200
+ option "--systemd-enable", :flag , "Enable service on install or upgrade", :default => false
201
+
202
+ option "--systemd-auto-start", :flag , "Start service after install or upgrade", :default => false
203
+
165
204
  option "--systemd-restart-after-upgrade", :flag , "Restart service after upgrade", :default => true
166
205
 
206
+ option "--after-purge", "FILE",
207
+ "A script to be run after package removal to purge remaining (config) files " \
208
+ "(a.k.a. postrm purge within apt-get purge)" do |val|
209
+ File.expand_path(val) # Get the full path to the script
210
+ end # --after-purge
211
+
212
+ option "--maintainerscripts-force-errorchecks", :flag ,
213
+ "Activate errexit shell option according to lintian. " \
214
+ "https://lintian.debian.org/tags/maintainer-script-ignores-errors.html",
215
+ :default => false
216
+
167
217
  def initialize(*args)
168
218
  super(*args)
169
219
  attributes[:deb_priority] = "extra"
@@ -193,6 +243,9 @@ class FPM::Package::Deb < FPM::Package
193
243
  when "x86_64"
194
244
  # Debian calls x86_64 "amd64"
195
245
  @architecture = "amd64"
246
+ when "aarch64"
247
+ # Debian calls aarch64 "arm64"
248
+ @architecture = "arm64"
196
249
  when "noarch"
197
250
  # Debian calls noarch "all"
198
251
  @architecture = "all"
@@ -240,10 +293,32 @@ class FPM::Package::Deb < FPM::Package
240
293
  end # def input
241
294
 
242
295
  def extract_info(package)
296
+ compression = `#{ar_cmd[0]} t #{package}`.split("\n").grep(/control.tar/).first.split(".").last
297
+ case compression
298
+ when "gz"
299
+ controltar = "control.tar.gz"
300
+ compression = "-z"
301
+ when "bzip2","bz2"
302
+ controltar = "control.tar.bz2"
303
+ compression = "-j"
304
+ when "xz"
305
+ controltar = "control.tar.xz"
306
+ compression = "-J"
307
+ when 'tar'
308
+ controltar = "control.tar"
309
+ compression = ""
310
+ when nil
311
+ raise FPM::InvalidPackageConfiguration, "Missing control.tar in deb source package #{package}"
312
+ else
313
+ raise FPM::InvalidPackageConfiguration,
314
+ "Unknown compression type '#{compression}' for control.tar in deb source package #{package}"
315
+ end
316
+
243
317
  build_path("control").tap do |path|
244
318
  FileUtils.mkdir(path) if !File.directory?(path)
319
+ # unpack the control.tar.{,gz,bz2,xz} from the deb package into staging_path
245
320
  # Unpack the control tarball
246
- safesystem("ar p #{package} control.tar.gz | tar -zxf - -C #{path}")
321
+ safesystem(ar_cmd[0] + " p #{package} #{controltar} | tar #{compression} -xf - -C #{path}")
247
322
 
248
323
  control = File.read(File.join(path, "control"))
249
324
 
@@ -340,30 +415,39 @@ class FPM::Package::Deb < FPM::Package
340
415
 
341
416
  def extract_files(package)
342
417
  # Find out the compression type
343
- compression = `ar t #{package}`.split("\n").grep(/data.tar/).first.split(".").last
418
+ compression = `#{ar_cmd[0]} t #{package}`.split("\n").grep(/data.tar/).first.split(".").last
344
419
  case compression
345
420
  when "gz"
346
421
  datatar = "data.tar.gz"
347
422
  compression = "-z"
348
- when "bzip2"
423
+ when "bzip2","bz2"
349
424
  datatar = "data.tar.bz2"
350
425
  compression = "-j"
351
426
  when "xz"
352
427
  datatar = "data.tar.xz"
353
428
  compression = "-J"
429
+ when 'tar'
430
+ datatar = "data.tar"
431
+ compression = ""
432
+ when nil
433
+ raise FPM::InvalidPackageConfiguration, "Missing data.tar in deb source package #{package}"
354
434
  else
355
435
  raise FPM::InvalidPackageConfiguration,
356
- "Unknown compression type '#{self.attributes[:deb_compression]}' "
357
- "in deb source package #{package}"
436
+ "Unknown compression type '#{compression}' for data.tar in deb source package #{package}"
358
437
  end
359
438
 
360
439
  # unpack the data.tar.{gz,bz2,xz} from the deb package into staging_path
361
- safesystem("ar p #{package} #{datatar} " \
362
- "| tar #{compression} -xf - -C #{staging_path}")
440
+ safesystem(ar_cmd[0] + " p #{package} #{datatar} | tar #{compression} -xf - -C #{staging_path}")
363
441
  end # def extract_files
364
442
 
365
443
  def output(output_path)
366
444
  self.provides = self.provides.collect { |p| fix_provides(p) }
445
+
446
+ self.provides.each do |provide|
447
+ if !valid_provides_field?(provide)
448
+ raise FPM::InvalidPackageConfiguration, "Found invalid Provides field values (#{provide.inspect}). This is not valid in a Debian package."
449
+ end
450
+ end
367
451
  output_check(output_path)
368
452
  # Abort if the target path already exists.
369
453
 
@@ -387,6 +471,23 @@ class FPM::Package::Deb < FPM::Package
387
471
  end
388
472
  end
389
473
 
474
+ if attributes[:source_date_epoch].nil? and not attributes[:source_date_epoch_default].nil?
475
+ attributes[:source_date_epoch] = attributes[:source_date_epoch_default]
476
+ end
477
+ if attributes[:source_date_epoch] == "0"
478
+ logger.error("Alas, ruby's Zlib::GzipWriter does not support setting an mtime of zero. Aborting.")
479
+ raise "#{name}: source_date_epoch of 0 not supported."
480
+ end
481
+ if not attributes[:source_date_epoch].nil? and not ar_cmd_deterministic?
482
+ logger.error("Alas, could not find an ar that can handle -D option. Try installing recent gnu binutils. Aborting.")
483
+ raise "#{name}: ar is insufficient to support source_date_epoch."
484
+ end
485
+ if not attributes[:source_date_epoch].nil? and not tar_cmd_supports_sort_names_and_set_mtime?
486
+ logger.error("Alas, could not find a tar that can set mtime and sort. Try installing recent gnu tar. Aborting.")
487
+ raise "#{name}: tar is insufficient to support source_date_epoch."
488
+ end
489
+
490
+ attributes[:deb_systemd] = []
390
491
  attributes.fetch(:deb_systemd_list, []).each do |systemd|
391
492
  name = File.basename(systemd, ".service")
392
493
  dest_systemd = staging_path("lib/systemd/system/#{name}.service")
@@ -394,42 +495,27 @@ class FPM::Package::Deb < FPM::Package
394
495
  FileUtils.cp(systemd, dest_systemd)
395
496
  File.chmod(0644, dest_systemd)
396
497
 
397
- # set the attribute with the systemd service name
398
- attributes[:deb_systemd] = name
498
+ # add systemd service name to attribute
499
+ attributes[:deb_systemd] << name
399
500
  end
400
501
 
401
- if script?(:before_upgrade) or script?(:after_upgrade) or attributes[:deb_systemd]
502
+ if script?(:before_upgrade) or script?(:after_upgrade) or attributes[:deb_systemd].any?
402
503
  puts "Adding action files"
403
504
  if script?(:before_install) or script?(:before_upgrade)
404
505
  scripts[:before_install] = template("deb/preinst_upgrade.sh.erb").result(binding)
405
506
  end
406
- if script?(:before_remove) or attributes[:deb_systemd]
507
+ if script?(:before_remove) or not attributes[:deb_systemd].empty?
407
508
  scripts[:before_remove] = template("deb/prerm_upgrade.sh.erb").result(binding)
408
509
  end
409
- if script?(:after_install) or script?(:after_upgrade) or attributes[:deb_systemd]
510
+ if script?(:after_install) or script?(:after_upgrade) or attributes[:deb_systemd].any?
410
511
  scripts[:after_install] = template("deb/postinst_upgrade.sh.erb").result(binding)
411
512
  end
412
513
  if script?(:after_remove)
413
514
  scripts[:after_remove] = template("deb/postrm_upgrade.sh.erb").result(binding)
414
515
  end
415
- end
416
-
417
- write_control_tarball
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]}'"
516
+ if script?(:after_purge)
517
+ scripts[:after_purge] = template("deb/postrm_upgrade.sh.erb").result(binding)
518
+ end
433
519
  end
434
520
 
435
521
  # There are two changelogs that may appear:
@@ -442,6 +528,9 @@ class FPM::Package::Deb < FPM::Package
442
528
  mkdir_p(File.dirname(dest_changelog))
443
529
  File.new(dest_changelog, "wb", 0644).tap do |changelog|
444
530
  Zlib::GzipWriter.new(changelog, Zlib::BEST_COMPRESSION).tap do |changelog_gz|
531
+ if not attributes[:source_date_epoch].nil?
532
+ changelog_gz.mtime = attributes[:source_date_epoch].to_i
533
+ end
445
534
  if attributes[:deb_changelog]
446
535
  logger.info("Writing user-specified changelog", :source => attributes[:deb_changelog])
447
536
  File.new(attributes[:deb_changelog]).tap do |fd|
@@ -461,6 +550,9 @@ class FPM::Package::Deb < FPM::Package
461
550
  if attributes[:deb_upstream_changelog]
462
551
  File.new(dest_upstream_changelog, "wb", 0644).tap do |changelog|
463
552
  Zlib::GzipWriter.new(changelog, Zlib::BEST_COMPRESSION).tap do |changelog_gz|
553
+ if not attributes[:source_date_epoch].nil?
554
+ changelog_gz.mtime = attributes[:source_date_epoch].to_i
555
+ end
464
556
  logger.info("Writing user-specified upstream changelog", :source => attributes[:deb_upstream_changelog])
465
557
  File.new(attributes[:deb_upstream_changelog]).tap do |fd|
466
558
  chunk = nil
@@ -494,6 +586,7 @@ class FPM::Package::Deb < FPM::Package
494
586
 
495
587
  attributes.fetch(:deb_upstart_list, []).each do |upstart|
496
588
  name = File.basename(upstart, ".upstart")
589
+ dest_init = staging_path("etc/init.d/#{name}")
497
590
  name = "#{name}.conf" if !(name =~ /\.conf$/)
498
591
  dest_upstart = staging_path("etc/init/#{name}")
499
592
  mkdir_p(File.dirname(dest_upstart))
@@ -501,7 +594,6 @@ class FPM::Package::Deb < FPM::Package
501
594
  File.chmod(0644, dest_upstart)
502
595
 
503
596
  # Install an init.d shim that calls upstart
504
- dest_init = staging_path("etc/init.d/#{name}")
505
597
  mkdir_p(File.dirname(dest_init))
506
598
  FileUtils.ln_s("/lib/init/upstart-job", dest_init)
507
599
  end
@@ -520,28 +612,65 @@ class FPM::Package::Deb < FPM::Package
520
612
  case self.attributes[:deb_compression]
521
613
  when "gz", nil
522
614
  datatar = build_path("data.tar.gz")
615
+ controltar = build_path("control.tar.gz")
523
616
  compression = "-z"
524
617
  when "bzip2"
525
618
  datatar = build_path("data.tar.bz2")
619
+ controltar = build_path("control.tar.gz")
526
620
  compression = "-j"
527
621
  when "xz"
528
622
  datatar = build_path("data.tar.xz")
623
+ controltar = build_path("control.tar.xz")
529
624
  compression = "-J"
625
+ when "none"
626
+ datatar = build_path("data.tar")
627
+ controltar = build_path("control.tar")
628
+ compression = ""
530
629
  else
531
630
  raise FPM::InvalidPackageConfiguration,
532
631
  "Unknown compression type '#{self.attributes[:deb_compression]}'"
533
632
  end
534
633
 
535
634
  args = [ tar_cmd, "-C", staging_path, compression ] + data_tar_flags + [ "-cf", datatar, "." ]
635
+ if tar_cmd_supports_sort_names_and_set_mtime? and not attributes[:source_date_epoch].nil?
636
+ # Use gnu tar options to force deterministic file order and timestamp
637
+ args += ["--sort=name", ("--mtime=@%s" % attributes[:source_date_epoch])]
638
+ # gnu tar obeys GZIP environment variable with options for gzip; -n = forget original filename and date
639
+ args.unshift({"GZIP" => "-9n"})
640
+ end
536
641
  safesystem(*args)
537
642
 
538
643
  # pack up the .deb, which is just an 'ar' archive with 3 files
539
644
  # the 'debian-binary' file has to be first
540
645
  File.expand_path(output_path).tap do |output_path|
541
646
  ::Dir.chdir(build_path) do
542
- safesystem("ar", "-qc", output_path, "debian-binary", "control.tar.gz", datatar)
647
+ safesystem(*ar_cmd, output_path, "debian-binary", controltar, datatar)
543
648
  end
544
649
  end
650
+
651
+ # if a PACKAGENAME.changes file is to be created
652
+ if self.attributes[:deb_generate_changes?]
653
+ distribution = self.attributes[:deb_dist]
654
+
655
+ # gather information about the files to distribute
656
+ files = [ output_path ]
657
+ changes_files = []
658
+ files.each do |path|
659
+ changes_files.push({
660
+ :name => path,
661
+ :size => File.size?(path),
662
+ :md5sum => Digest::MD5.file(path).hexdigest,
663
+ :sha1sum => Digest::SHA1.file(path).hexdigest,
664
+ :sha256sum => Digest::SHA2.file(path).hexdigest,
665
+ })
666
+ end
667
+
668
+ # write change infos to .changes file
669
+ changes_path = File.basename(output_path, '.deb') + '.changes'
670
+ changes_data = template("deb/deb.changes.erb").result(binding)
671
+ File.write(changes_path, changes_data)
672
+ logger.log("Created changes", :path => changes_path)
673
+ end # if deb_generate_changes
545
674
  end # def output
546
675
 
547
676
  def converted_from(origin)
@@ -552,6 +681,43 @@ class FPM::Package::Deb < FPM::Package
552
681
  fix_provides(provides)
553
682
  end.flatten
554
683
 
684
+ if origin == FPM::Package::CPAN
685
+ # The fpm cpan code presents dependencies and provides fields as perl(ModuleName)
686
+ # so we'll need to convert them to something debian supports.
687
+
688
+ # Replace perl(ModuleName) > 1.0 with Debian-style perl-ModuleName (> 1.0)
689
+ perldepfix = lambda do |dep|
690
+ m = dep.match(/perl\((?<name>[A-Za-z0-9_:]+)\)\s*(?<op>.*$)/)
691
+ if m.nil?
692
+ # 'dep' syntax didn't look like 'perl(Name) > 1.0'
693
+ dep
694
+ else
695
+ # Also replace '::' in the perl module name with '-'
696
+ modulename = m["name"].gsub("::", "-")
697
+
698
+ # Fix any upper-casing or other naming concerns Debian has about packages
699
+ name = "#{attributes[:cpan_package_name_prefix]}-#{modulename}"
700
+
701
+ if m["op"].empty?
702
+ name
703
+ else
704
+ # 'dep' syntax was like this (version constraint): perl(Module) > 1.0
705
+ "#{name} (#{m["op"]})"
706
+ end
707
+ end
708
+ end
709
+
710
+ rejects = [ "perl(vars)", "perl(warnings)", "perl(strict)", "perl(Config)" ]
711
+ self.dependencies = self.dependencies.reject do |dep|
712
+ # Reject non-module Perl dependencies like 'vars' and 'warnings'
713
+ rejects.include?(dep)
714
+ end.collect(&perldepfix).collect(&method(:fix_dependency))
715
+
716
+ # Also fix the Provides field 'perl(ModuleName) = version' to be 'perl-modulename (= version)'
717
+ self.provides = self.provides.collect(&perldepfix).collect(&method(:fix_provides))
718
+
719
+ end # if origin == FPM::Packagin::CPAN
720
+
555
721
  if origin == FPM::Package::Deb
556
722
  changelog_path = staging_path("usr/share/doc/#{name}/changelog.Debian.gz")
557
723
  if File.exists?(changelog_path)
@@ -579,6 +745,19 @@ class FPM::Package::Deb < FPM::Package
579
745
  File.unlink(changelog_path)
580
746
  end
581
747
  end
748
+
749
+ if origin == FPM::Package::Gem
750
+ # fpm's gem input will have provides as "rubygem-name = version"
751
+ # and we need to convert this to Debian-style "rubygem-name (= version)"
752
+ self.provides = self.provides.collect do |provides|
753
+ m = /^(#{attributes[:gem_package_name_prefix]})-([^\s]+)\s*=\s*(.*)$/.match(provides)
754
+ if m
755
+ "#{m[1]}-#{m[2]} (= #{m[3]})"
756
+ else
757
+ provides
758
+ end
759
+ end
760
+ end
582
761
  end # def converted_from
583
762
 
584
763
  def debianize_op(op)
@@ -620,8 +799,13 @@ class FPM::Package::Deb < FPM::Package
620
799
  name, version = dep.gsub(/[()~>]/, "").split(/ +/)[0..1]
621
800
  nextversion = version.split(".").collect { |v| v.to_i }
622
801
  l = nextversion.length
623
- nextversion[l-2] += 1
624
- nextversion[l-1] = 0
802
+ if l > 1
803
+ nextversion[l-2] += 1
804
+ nextversion[l-1] = 0
805
+ else
806
+ # Single component versions ~> 1
807
+ nextversion[l-1] += 1
808
+ end
625
809
  nextversion = nextversion.join(".")
626
810
  return ["#{name} (>= #{version})", "#{name} (<< #{nextversion})"]
627
811
  elsif (m = dep.match(/(\S+)\s+\(!= (.+)\)/))
@@ -648,6 +832,32 @@ class FPM::Package::Deb < FPM::Package
648
832
  end
649
833
  end # def fix_dependency
650
834
 
835
+ def valid_provides_field?(text)
836
+ m = RELATIONSHIP_FIELD_PATTERN.match(text)
837
+ if m.nil?
838
+ logger.error("Invalid relationship field for debian package: #{text}")
839
+ return false
840
+ end
841
+
842
+ # Per Debian Policy manual, https://www.debian.org/doc/debian-policy/ch-relationships.html#syntax-of-relationship-fields
843
+ # >> The relations allowed are <<, <=, =, >= and >> for strictly earlier, earlier or equal,
844
+ # >> exactly equal, later or equal and strictly later, respectively. The exception is the
845
+ # >> Provides field, for which only = is allowed
846
+ if m["relation"] == "=" || m["relation"] == nil
847
+ return true
848
+ end
849
+ return false
850
+ end
851
+
852
+ def valid_relationship_field?(text)
853
+ m = RELATIONSHIP_FIELD_PATTERN.match(text)
854
+ if m.nil?
855
+ logger.error("Invalid relationship field for debian package: #{text}")
856
+ return false
857
+ end
858
+ return true
859
+ end
860
+
651
861
  def fix_provides(provides)
652
862
  name_re = /^[^ \(]+/
653
863
  name = provides[name_re]
@@ -662,6 +872,11 @@ class FPM::Package::Deb < FPM::Package
662
872
  "debs don't like underscores")
663
873
  provides = provides.gsub("_", "-")
664
874
  end
875
+
876
+ if m = provides.match(/^([A-Za-z0-9_-]+)\s*=\s*(\d+.*$)/)
877
+ logger.warn("Replacing 'provides' entry #{provides} with syntax 'name (= version)'")
878
+ provides = "#{m[1]} (= #{m[2]})"
879
+ end
665
880
  return provides.rstrip
666
881
  end
667
882
 
@@ -687,12 +902,34 @@ class FPM::Package::Deb < FPM::Package
687
902
  write_triggers # write trigger config to 'triggers' file
688
903
  write_md5sums # write the md5sums file
689
904
 
905
+ # Tar up the staging_path into control.tar.{compression type}
906
+ case self.attributes[:deb_compression]
907
+ when "gz", "bzip2", nil
908
+ controltar = "control.tar.gz"
909
+ compression = "-z"
910
+ when "xz"
911
+ controltar = "control.tar.xz"
912
+ compression = "-J"
913
+ when "none"
914
+ controltar = "control.tar"
915
+ compression = ""
916
+ else
917
+ raise FPM::InvalidPackageConfiguration,
918
+ "Unknown compression type '#{self.attributes[:deb_compression]}'"
919
+ end
920
+
690
921
  # Make the control.tar.gz
691
- build_path("control.tar.gz").tap do |controltar|
922
+ build_path(controltar).tap do |controltar|
692
923
  logger.info("Creating", :path => controltar, :from => control_path)
693
924
 
694
- args = [ tar_cmd, "-C", control_path, "-zcf", controltar,
925
+ args = [ tar_cmd, "-C", control_path, compression, "-cf", controltar,
695
926
  "--owner=0", "--group=0", "--numeric-owner", "." ]
927
+ if tar_cmd_supports_sort_names_and_set_mtime? and not attributes[:source_date_epoch].nil?
928
+ # Force deterministic file order and timestamp
929
+ args += ["--sort=name", ("--mtime=@%s" % attributes[:source_date_epoch])]
930
+ # gnu tar obeys GZIP environment variable with options for gzip; -n = forget original filename and date
931
+ args.unshift({"GZIP" => "-9n"})
932
+ end
696
933
  safesystem(*args)
697
934
  end
698
935
 
@@ -774,7 +1011,7 @@ class FPM::Package::Deb < FPM::Package
774
1011
  etcfiles = []
775
1012
  # Add everything in /etc
776
1013
  begin
777
- if !attributes[:deb_no_default_config_files?]
1014
+ if !attributes[:deb_no_default_config_files?] && File.exists?(staging_path("/etc"))
778
1015
  logger.warn("Debian packaging tools generally labels all files in /etc as config files, " \
779
1016
  "as mandated by policy, so fpm defaults to this behavior for deb packages. " \
780
1017
  "You can disable this default behavior with --deb-no-default-config-files flag")
@@ -789,11 +1026,25 @@ class FPM::Package::Deb < FPM::Package
789
1026
 
790
1027
  # scan all conf file paths for files and add them
791
1028
  config_files.each do |path|
1029
+ logger.debug("Checking if #{path} exists")
1030
+ cfe = File.exist?("#{path}")
1031
+ logger.debug("Check result #{cfe}")
792
1032
  begin
793
1033
  add_path(path, allconfigs)
794
1034
  rescue Errno::ENOENT
795
- raise FPM::InvalidPackageConfiguration,
796
- "Error trying to use '#{path}' as a config file in the package. Does it exist?"
1035
+ if !cfe
1036
+ raise FPM::InvalidPackageConfiguration,
1037
+ "Error trying to use '#{path}' as a config file in the package. Does it exist?"
1038
+ else
1039
+ dcl = File.join(staging_path, path)
1040
+ if !File.exist?("#{dcl}")
1041
+ logger.debug("Adding config file #{path} to Staging area #{staging_path}")
1042
+ FileUtils.mkdir_p(File.dirname(dcl))
1043
+ FileUtils.cp_r path, dcl
1044
+ else
1045
+ logger.debug("Config file aready exists in staging area.")
1046
+ end
1047
+ end
797
1048
  end
798
1049
  end
799
1050
 
@@ -849,7 +1100,7 @@ class FPM::Package::Deb < FPM::Package
849
1100
 
850
1101
  if attributes[:deb_templates]
851
1102
  FileUtils.cp(attributes[:deb_templates], control_path("templates"))
852
- File.chmod(0755, control_path("templates"))
1103
+ File.chmod(0644, control_path("templates"))
853
1104
  end
854
1105
  end # def write_debconf
855
1106
 
@@ -865,7 +1116,10 @@ class FPM::Package::Deb < FPM::Package
865
1116
 
866
1117
  def write_triggers
867
1118
  lines = [['interest', :deb_interest],
868
- ['activate', :deb_activate]].map { |label, attr|
1119
+ ['activate', :deb_activate],
1120
+ ['interest-noawait', :deb_interest_noawait],
1121
+ ['activate-noawait', :deb_activate_noawait],
1122
+ ].map { |label, attr|
869
1123
  (attributes[attr] || []).map { |e| "#{label} #{e}\n" }
870
1124
  }.flatten.join('')
871
1125
 
@@ -1,6 +1,6 @@
1
1
  require "fpm/package"
2
2
  require "fpm/util"
3
- require "backports"
3
+ require "backports/latest"
4
4
  require "fileutils"
5
5
  require "find"
6
6
  require "socket"
@@ -83,8 +83,8 @@ class FPM::Package::Dir < FPM::Package
83
83
  # can include license data from themselves (rpms, gems, etc),
84
84
  # but to make sure a simple dir -> rpm works without having
85
85
  # to specify a license.
86
- self.license = "unknown"
87
- self.vendor = [ENV["USER"], Socket.gethostname].join("@")
86
+ self.license ||= "unknown"
87
+ self.vendor ||= [ENV["USER"], Socket.gethostname].join("@")
88
88
  ensure
89
89
  # Clean up any logger context we added.
90
90
  logger.remove("method")
@@ -101,18 +101,7 @@ class FPM::Package::Dir < FPM::Package
101
101
  end
102
102
 
103
103
  # Write the scripts, too.
104
- scripts_path = File.join(output_path, ".scripts")
105
- ::Dir.mkdir(scripts_path)
106
- [:before_install, :after_install, :before_remove, :after_remove].each do |name|
107
- next unless script?(name)
108
- out = File.join(scripts_path, name.to_s)
109
- logger.debug("Writing script", :source => name, :target => out)
110
- File.write(out, script(name))
111
- require "pry"
112
- binding.pry
113
- File.chmod(0755, out)
114
- end
115
-
104
+ write_scripts
116
105
  ensure
117
106
  logger.remove("method")
118
107
  end # def output
@@ -147,14 +136,20 @@ class FPM::Package::Dir < FPM::Package
147
136
 
148
137
  # For single file copies, permit file destinations
149
138
  fileinfo = File.lstat(source)
150
- if fileinfo.file? && !File.directory?(destination)
139
+ destination_is_directory = File.directory?(destination)
140
+ if fileinfo.file? && !destination_is_directory
151
141
  if destination[-1,1] == "/"
152
142
  copy(source, File.join(destination, source))
153
143
  else
154
144
  copy(source, destination)
155
145
  end
156
146
  elsif fileinfo.symlink?
157
- copy(source, File.join(destination, source))
147
+ # Treat them same as files
148
+ if destination[-1,1] == "/"
149
+ copy(source, File.join(destination, source))
150
+ else
151
+ copy(source, destination)
152
+ end
158
153
  else
159
154
  # Copy all files from 'path' into staging_path
160
155
  Find.find(source) do |path|
@@ -1,9 +1,21 @@
1
1
  require "fpm/package"
2
- require "backports"
2
+ require "backports/latest"
3
3
 
4
4
  # Empty Package type. For strict/meta/virtual package creation
5
5
 
6
6
  class FPM::Package::Empty < FPM::Package
7
+ def initialize(*args)
8
+ super(*args)
9
+
10
+ # Override FPM::Package's default "native" architecture value
11
+ # This feels like the right default because an empty package has no
12
+ # architecture-specific files, and in most cases an empty package should be
13
+ # installable anywhere.
14
+ #
15
+ # https://github.com/jordansissel/fpm/issues/1846
16
+ @architecture = "all"
17
+ end
18
+
7
19
  def output(output_path)
8
20
  logger.warn("Your package has gone into the void.")
9
21
  end