fpm 1.6.1 → 1.14.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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