fpm 1.13.0 → 1.15.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f231a03d2baac73ae0f4f8f15094237ca94ec43de51ef0b86dde886a8647efa2
4
- data.tar.gz: 91666a6a7b09b6f3ab3bb6dccf32e647d58a43754d2163a4748ae8a2e14515e8
3
+ metadata.gz: d2157b42ae94755f7521964dc3f92af2a535ee87506303aca5bb72222b48495b
4
+ data.tar.gz: 8772b7c1f612dfe8bd698b136418bda8c7b63d9243b1b253832917ad926cab7c
5
5
  SHA512:
6
- metadata.gz: b21d482730c5e532f9bf6f9e7faf51bf712aa9f75ebab9b8453d1f1b9cd9f1e0ef5a32bb84f18808bc5bc8c15a8e1c47546ad1d474e9c3c581eaa7afe85e80b9
7
- data.tar.gz: 72963da4b7601fa8d416ab20ce26e15838960b7dca9c364b38312266857e3beb9b11b32a9c708ff393a612f0e5ff350b6098fd794c4b5b05fe767c0a4323dfdd
6
+ metadata.gz: 9cee7c2885fcf85d75cdc74b2e41399ddce10693fefc3c0b09c49e73b16fcd73140527d646ee5886ef231de7cb202a67f22130d01324d83923195833693f00e2
7
+ data.tar.gz: 18f5d405ecd21a0309abf1e08219b0b23aa60eb2e8e7e3f00d7c17ea31e5a3e7b4cbf3a9b9e5bbfb467111a4b8ea9424d61a0f0ff81c9179490e54b17cbfde29
data/CHANGELOG.rst CHANGED
@@ -1,6 +1,67 @@
1
1
  Release Notes and Change Log
2
2
  ============================
3
3
 
4
+ 1.15.1 (January 31, 2023)
5
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
6
+ * Ruby 3.2.0 now supported. This fixes error 'undefined method exists? for File' '(`#1981`_, `#1988`_; Nicholas Hubbard, romulasry)
7
+
8
+ 1.15.0 (November 13, 2022)
9
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
10
+ * New flag ``--fpm-options-file path/to/file`` which allows you to specify additional fpm flags in an external file of your choosing. (`#1905`_, `#1902`_, `#1827`_; Jordan Sissel, Will Furnell, hjpotter92)
11
+ * deb: Periods are now accepted in package names (`#1899`_; C. Cooke)
12
+ * Fix bug where fpm would crash if ``--workdir`` pointed at a path that didn't
13
+ exist. (`#1959`_; Jordan Sissel)
14
+ * osxpkg: this package format now supports the fpm ``--prefix`` flag(`#1909`_, `#1908`_; Jordan Sissel, mcataga)
15
+ * cpan: Fix bug where fpm would fail on certain Perl modules due to their source tarball structure (`#1940`_; Nicholas Hubbard, William N. Braswell, Jr.)
16
+ * cpan: Fix crash on certain CPAN modules where the author field was blank (`#1942`_, `#1937`_, `#1523`_, `#1528`_; Nicholas Hubbard, William N. Braswell, Jr.)
17
+ * deb: The distribution field of the debian changelog and changes files will now use the value set by ``--deb-dist`` (default is "unstable") (`#1934`_; Chabert Loïc)
18
+ * python: Fix errors in how fpm invoked ``pip``. Previously, fpm would use pip's ``--build`` flag, but this was removed a while ago, and fpm is now aware! (`#1896`_, `#1831`_, `#1893`_, `#1916`_; Jordan Sissel, Svyatogor Chuykov)
19
+ * pleaserun: Add ``--pleaserun-user`` flag. (`#1912`_; Evgeny Stambulchik)
20
+ * deb: The default ``--deb-priority`` is now "optional" instead of "extra" (`#1913`_; Chris Novakovic)
21
+ * Enable installation of fpm on older versions of ruby. This change removed ``git`` rubygem dependency. (`#1946`_, `#1923`_; Jordan Sissel, Andreas Wirooks, Ruslan Kuprieiev, jamshid, Lorenzo Castellino, Sam Hughes)
22
+ * Enable operation of fpm on very old versions of ruby (as old as Ruby 1.9.3). This changed removed ``json`` rubygem dependency. (`#1950`_, `#1949`_, `#1741`_, `#1264`_, `#1798`_, `#1800`_, `#1784`_; Jordan Sissel and many others)
23
+ * Fix bug where subprocesses could hang waiting for input (`#1955`_, `#1519`_, `#1522`_; Nicholas Hubbard, William N. Braswell, Jr.)
24
+ * Update Dockerfile to use ubuntu:20.04 (`#1935`_; Gnought)
25
+ * internal: Fix a code typo (`#1948`_; Nicholas Hubbard)
26
+ * internal tests: Support newer versions of lintian (`#1939`_, `#1907`_; Jordan Sissel)
27
+ * Improve support for Ruby 3.1.0 and newer that would previously crash with an error mentioning Psych::DisallowedClass (`#1898`_, `#1895`_; Jordan Sissel, Alexandre ZANNI)
28
+ * Improve support for Ruby 3.1.0 and newer that changed the API for ERB (`#1897`_; Jordan Sissel)
29
+
30
+ 1.14.2 (March 30, 2022)
31
+ ^^^^^^^^^^^^^^^^^^^^^^^
32
+ * deb: fix bug causing ``--deb-compression none`` to invoke ``tar`` incorrectly (`#1879`_; John Howard)
33
+ * rpm: Better support for paths that have spaces and mixed quotation marks in them. (`#1882`_, `#1886`_, `#1385`_; John Bollinger and Jordan Sissel)
34
+ * pacman: Fix typo preventing the use of ``--pacman-compression xz`` (`#1876`_; mszprejda)
35
+ * docs: All supported package types now have dedicated documentation pages. Some pages are small stubs and would benefit from future improvement. (`#1884`_; mcandre, Jordan Sissel)
36
+ * docs: Small but lovely documentation fixes (`#1875`_ by Corey Quinn, `#1864`_ by Geoff Beier)
37
+ * Fixed mistake causing the test suite to fail when ``rake`` wasn't available. (`#1877`_; Jordan Sissel)
38
+
39
+ 1.14.1 (November 10, 2021)
40
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
41
+ * Fix a bug that impacted fpm api usage (from other ruby programs) that caused an error "NameError: uninitialized constant FPM::Package::CPAN" when trying to output a Deb package. (`#1854`_, `#1856`_; Karol Bucek, Jordan Sissel)
42
+
43
+ 1.14.0 (November 9, 2021)
44
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
45
+ * python: Use pip by default for fetching Python packages. This matches the Python 3 "installation" docs which recommend calling pip as ``python -m pip`` where ``python`` depends on ``--python-bin`` (default "python"). Previous default was to use `easy_install` which is no longer available on many newer systems. To use easy_install, you can set ``--no-python-internal-pip`` to revert this pip default. Further, you can specify your own pip path instead of using ``python -m pip`` with the ``--python-pip /path/to/pip`` flag. (`#1820`_, `#1821`_; Jordan Sissel)
46
+ * python: Support extras_require build markers in python packages (`#1307`_, `#1816`_; Joris Vandermeersch)
47
+ * freebsd: Fix bug which caused fpm to generate incorrect FreeBSD packages "missing leading `/`" (`#1811`_, `#1812`_, `#1844`_, `#1832`_, `#1845`_; Vlastimil Holer, Clayton Wong, Markus Ueberall, Jordan Sissel)
48
+ * deb: In order to only allow fpm to create valid packages, fpm now rejects packages with invalid "provides" (``--provides``) values. (`#1829`_, `#1825`_; Jordan Sissel, Peter Teichman)
49
+ * deb: Only show a warning about /etc and config files if there are files in /etc (`#1852`_, `#1851`_; Jordan Sissel)
50
+
51
+ * rpm: replace dash with underscore in rpm's "Release" field aka what fpm calls ``--iteration``. (`#1834`_, `#1833`_; Jordan Sissel)
52
+ * empty: `fpm -s empty ...` now defaults to "all" architecture instead of "native". (`#1850`_, `#1846`_; Jordan Sissel)
53
+ * Significant documentation improvements rewriting most of the documentation. New overview pages, full CLI flag listing, and new sections dedicated package types (rpm, cpan, deb, etc). (`#1815`_, `#1817`_, `#1838`_; Vedant K, Jordan Sissel)
54
+ * Typo fixes in documentation are always appreciated! (`#1842`_; Clayton Wong)
55
+ * fpm can now (we hope!) now be tested more easily from docker (`#1818`_, `#1682`_, `#1453`_; @directionless, Jordan Sissel, Douglas Muth)
56
+
57
+ 1.13.1 (July 6, 2021)
58
+ ^^^^^^^^^^^^^^^^^^^^^
59
+ * deb: The `--provides` flag now allows for versions. Previously, fpm would
60
+ remove the version part of a provides field when generating deb packages.
61
+ (`#1788`_, `#1803`_; Jordan Sissel, Phil Schwartz, tympanix)
62
+ * osxpkg: Update documentation to include installing `rpm` tools on OSX
63
+ (`#1797`_; allen joslin)
64
+
4
65
  1.13.0 (June 19, 2021)
5
66
  ^^^^^^^^^^^^^^^^^^^^^^
6
67
  * Apple M1 users should now work (`#1772`_, `#1785`_, `#1786`_; Jordan Sissel)
@@ -12,8 +73,7 @@ Release Notes and Change Log
12
73
  * Ruby 3.0 support: Added `rexml` as a runtime dependency. In Ruby 2.0, `rexml` came by default, but in Ruby 3.0, `rexml` is now a bundled gem and some distributiosn do not include it by default. (`#1794`_; Jordan Sissel)
13
74
  * Fix error "git: not found (Git::GitExecuteError)". Now loads `git` library only when using git features. (`#1753`_, `#1748`_, `#1751`_, `#1766`_; Jordan Sissel, Cameron Nemo, Jason Rogers, Luke Short)
14
75
  * deb: Fix syntax error in `postinst` (`--after-install`) script. (`#1752`_, `#1749`_, `#1764`_; rmanus, Adam Mohammed, Elliot Murphy, kimw, Jordan Sissel)
15
- * deb: --deb-compression now uses the same compression and file suffix on the control.tar file (`#1760`_; Philippe Poilbarbe
16
- )
76
+ * deb: --deb-compression now uses the same compression and file suffix on the control.tar file (`#1760`_; Philippe Poilbarbe)
17
77
 
18
78
 
19
79
  1.12.0 (January 19, 2021)
@@ -51,7 +111,7 @@ Release Notes and Change Log
51
111
  * cpan: Adds `--[no-]cpan-verbose` flag which, when set, runs `cpanm` with the `--verbose` flag (`#1511`_; William N. Braswell, Jr)
52
112
 
53
113
  1.10.0 (May 21, 2018)
54
- ^^^^^^^^^^^^^^^^^^^^
114
+ ^^^^^^^^^^^^^^^^^^^^^
55
115
 
56
116
  * Pin `ruby-xz` dependency to one which allows Ruby versions older than 2.3.0 (`#1494`_; Marat Sharafutdinov)
57
117
  * Documentation improvements: `#1488`_; Arthur Burkart. `#1384`_; Justin Kolberg. `#1452`_; Anatoli Babenia.
@@ -79,7 +139,7 @@ Release Notes and Change Log
79
139
  * rpm: Fix `--config-files` handling (`#1390`_, `#1391`_; Jordan Sissel)
80
140
 
81
141
  1.9.1 (July 28, 2017) happy sysadmin day!
82
- ^^^^^^^^^^^^^^^^^^^^^
142
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
83
143
 
84
144
  * Documentation improvements: `#1291`_; Pablo Castellano. `#1321`_; ge-fa. `#1309`_; jesusbagpuss. `#1349`_; Perry Stole. `#1352`_, Jordan Sissel. `#1384`_; Justin Kolberg.
85
145
  * Testing improvements: `#1320`_; Rob Young. `#1266`_; Ryan Parman. `#1374`_; Thiago Figueiró.
@@ -108,9 +168,9 @@ Release Notes and Change Log
108
168
  * Other: Remove unused archive-tar-minitar as a dependency of fpm (`#1355`_; Diego Martins)
109
169
  * Other: Add stud as a runtime dependency (`#1354`_; Elan Ruusamäe)
110
170
 
111
- .. _reproducible_builds:: https://reproducible-builds.org/
112
- .. _path mapping:: http://fpm.readthedocs.io/en/latest/source/dir.html#path-mapping
113
- .. _Deterministic output:: http://fpm.readthedocs.io/en/latest/source/gem.html
171
+ .. _reproducible_builds: https://reproducible-builds.org/
172
+ .. _path mapping: source/dir.html#path-mapping
173
+ .. _Deterministic output: source/gem.html
114
174
 
115
175
  1.9.0 (July 28, 2017)
116
176
  ^^^^^^^^^^^^^^^^^^^^^
data/CONTRIBUTORS CHANGED
@@ -21,6 +21,7 @@ sbuss
21
21
  Brett Gailey (github: dnbert)
22
22
  Daniel Haskin (github: djhaskin987)
23
23
  Richard Grainger (github: liger1978)
24
+ seph (github: directionless)
24
25
 
25
26
  If you have contributed (bug reports, feature requests, help in IRC, blog
26
27
  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-2017 Jordan Sissel and contributors.
3
+ Copyright (c) 2011-2021 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/lib/fpm/command.rb CHANGED
@@ -247,6 +247,13 @@ class FPM::Command < Clamp::Command
247
247
  "See https://reproducible-builds.org/specs/source-date-epoch ",
248
248
  :environment_variable => "SOURCE_DATE_EPOCH"
249
249
 
250
+ option "--fpm-options-file", "FPM_OPTIONS_FILE",
251
+ "A file that contains additional fpm options. Any fpm flag format is valid in this file. " \
252
+ "This can be useful on build servers where you want to use a common configuration or " \
253
+ "inject other parameters from a file instead of from a command-line flag.." do |path|
254
+ load_options(path)
255
+ end
256
+
250
257
  parameter "[ARGS] ...",
251
258
  "Inputs to the source package type. For the 'dir' type, this is the files" \
252
259
  " and directories you want to include in the package. For others, like " \
@@ -291,6 +298,15 @@ class FPM::Command < Clamp::Command
291
298
  args << "."
292
299
  end
293
300
 
301
+ if !File.exist?(workdir)
302
+ logger.fatal("Given --workdir=#{workdir} is not a path that exists.")
303
+ raise FPM::Package::InvalidArgument, "The given workdir '#{workdir}' does not exist."
304
+ end
305
+ if !File.directory?(workdir)
306
+ logger.fatal("Given --workdir=#{workdir} must be a directory")
307
+ raise FPM::Package::InvalidArgument, "The given workdir '#{workdir}' must be a directory."
308
+ end
309
+
294
310
  logger.info("Setting workdir", :workdir => workdir)
295
311
  ENV["TMP"] = workdir
296
312
 
@@ -355,7 +371,7 @@ class FPM::Command < Clamp::Command
355
371
 
356
372
  # If --inputs was specified, read it as a file.
357
373
  if !inputs.nil?
358
- if !File.exists?(inputs)
374
+ if !File.exist?(inputs)
359
375
  logger.fatal("File given for --inputs does not exist (#{inputs})")
360
376
  return 1
361
377
  end
@@ -370,7 +386,7 @@ class FPM::Command < Clamp::Command
370
386
  # If --exclude-file was specified, read it as a file and append to
371
387
  # the exclude pattern list.
372
388
  if !exclude_file.nil?
373
- if !File.exists?(exclude_file)
389
+ if !File.exist?(exclude_file)
374
390
  logger.fatal("File given for --exclude-file does not exist (#{exclude_file})")
375
391
  return 1
376
392
  end
@@ -435,7 +451,7 @@ class FPM::Command < Clamp::Command
435
451
  # Skip scripts not set
436
452
  next if path.nil?
437
453
 
438
- if !File.exists?(path)
454
+ if !File.exist?(path)
439
455
  logger.error("No such file (for #{scriptname.to_s}): #{path.inspect}")
440
456
  script_errors << path
441
457
  end
@@ -571,12 +587,86 @@ class FPM::Command < Clamp::Command
571
587
 
572
588
  ARGV.unshift(*flags)
573
589
  ARGV.push(*args)
590
+
574
591
  super(run_args)
575
592
  rescue FPM::Package::InvalidArgument => e
576
593
  logger.error("Invalid package argument: #{e}")
577
594
  return 1
578
595
  end # def run
579
596
 
597
+ def load_options(path)
598
+ @loaded_files ||= []
599
+
600
+ if @loaded_files.include?(path)
601
+ #logger.error("Options file was already loaded once. Refusing to load a second time.", :path => path)
602
+ raise FPM::Package::InvalidArgument, "Options file already loaded once. Refusing to load a second time. Maybe a file tries to load itself? Path: #{path}"
603
+ end
604
+
605
+ if !File.exist?(path)
606
+ logger.fatal("Cannot load options from file because the file doesn't exist.", :path => path)
607
+ end
608
+
609
+ if !File.readable?(path)
610
+ logger.fatal("Cannot load options from file because the file isn't readable.", :path => path)
611
+ end
612
+
613
+ @loaded_files << path
614
+
615
+ logger.info("Loading flags from file", :path => path)
616
+
617
+ # Safety check, abort if the file is huge. Arbitrarily chosen limit is 100kb
618
+ stat = File.stat(path)
619
+ max = 100 * 1024
620
+ if stat.size > max
621
+ logger.fatal("Refusing to load options from file because the file seems pretty large.", :path => path, :size => stat.size)
622
+ raise FPM::Package::InvalidArgument, "Options file given to --fpm-options-file is seems too large. For safety, fpm is refusing to load this. Path: #{path} - Size: #{stat.size}, maximum allowed size #{max}."
623
+ end
624
+
625
+ File.read(path).split($/).each do |line|
626
+ logger.info("Processing flags from file", :path => path, :line => line)
627
+ # With apologies for this hack to mdub (Mike Williams, author of Clamp)...
628
+ # The following code will read a file and parse the file
629
+ # as flags as if they were in same argument position as the given --fpm-options-file option.
630
+
631
+ args = Shellwords.split(line)
632
+ while args.any?
633
+ arg = args.shift
634
+
635
+ # Lookup the Clamp option by its --flag-name or short name like -f
636
+ if arg =~ /^-/
637
+ # Single-letter options like -a or -z
638
+ if single_letter = arg.match(/^(-[A-Za-z0-9])(.*)$/)
639
+ option = self.class.find_option(single_letter.match(1))
640
+ arg, remainder = single_letter.match(1), single_letter.match(2)
641
+ if option.flag?
642
+ # Flags aka switches take no arguments, so we push the rest of the 'arg' entry back onto the args list
643
+
644
+ # For combined letter flags, like `-abc`, we want to consume the
645
+ # `-a` and then push `-bc` back to be processed.
646
+ # Only do this if there's more flags, like, not for `-a` but yes for `-abc`
647
+ args.unshift("-" + remainder) unless remainder.empty?
648
+ else
649
+ # Single letter options that take arguments, like `-ohello` same as `-o hello`
650
+
651
+ # For single letter flags with values, like `-ofilename` aka `-o filename`, push the remainder ("filename")
652
+ # back onto the args list so that it is consumed when we extract the flag value.
653
+ args.unshift(remainder) unless remainder.empty?
654
+ end
655
+ elsif arg.match(/^--/)
656
+ # Lookup the flag by its long --flag-name
657
+ option = self.class.find_option(arg)
658
+ end
659
+ end
660
+
661
+ # Extract the flag value, if any, from the remaining args list.
662
+ value = option.extract_value(arg, args)
663
+
664
+ # Process the flag into `self`
665
+ option.of(self).take(value)
666
+ end
667
+ end
668
+ end
669
+
580
670
  # A simple flag validator
581
671
  #
582
672
  # The goal of this class is to ensure the flags and arguments given
@@ -112,6 +112,7 @@ class FPM::Package::CPAN < FPM::Package
112
112
  self.vendor = case metadata["author"]
113
113
  when String; metadata["author"]
114
114
  when Array; metadata["author"].join(", ")
115
+ when NilClass; "No Vendor Or Author Provided"
115
116
  else
116
117
  raise FPM::InvalidPackageConfiguration, "Unexpected CPAN 'author' field type: #{metadata["author"].class}. This is a bug."
117
118
  end if metadata.include?("author")
@@ -304,7 +305,7 @@ class FPM::Package::CPAN < FPM::Package
304
305
  directory = build_path("module")
305
306
  ::Dir.mkdir(directory)
306
307
  args = [ "-C", directory, "-zxf", tarball,
307
- "--strip-components", "1" ]
308
+ %q{--transform=s,[./]*[^/]*/,,} ]
308
309
  safesystem("tar", *args)
309
310
  return directory
310
311
  end
@@ -8,6 +8,10 @@ require "fileutils"
8
8
  require "digest"
9
9
  require "zlib"
10
10
 
11
+ # For handling conversion
12
+ require "fpm/package/cpan"
13
+ require "fpm/package/gem"
14
+
11
15
  # Support for debian packages (.deb files)
12
16
  #
13
17
  # This class supports both input and output of packages.
@@ -25,6 +29,30 @@ class FPM::Package::Deb < FPM::Package
25
29
  # The list of supported compression types. Default is gz (gzip)
26
30
  COMPRESSION_TYPES = [ "gz", "bzip2", "xz", "none" ]
27
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
+ # Package name docs here: https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-source
37
+ # Package names (both source and binary, see Package) must consist only of lower case letters (a-z),
38
+ # digits (0-9), plus (+) and minus (-) signs, and periods (.).
39
+ # They must be at least two characters long and must start with an alphanumeric character.
40
+
41
+ # Version string docs here: https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-version
42
+ # The format is: [epoch:]upstream_version[-debian_revision].
43
+ # epoch - This is a single (generally small) unsigned integer
44
+ # upstream_version - must contain only alphanumerics 6 and the characters . + - ~
45
+ # debian_revision - only alphanumerics and the characters + . ~
46
+ VERSION_FIELD_PATTERN = /
47
+ (?:(?:[0-9]+):)? # The epoch, an unsigned int
48
+ (?:[A-Za-z0-9+~.-]+) # upstream version, probably should not contain dashes?
49
+ (?:-[A-Za-z0-9+~.]+)? # debian_revision
50
+ /x # Version field pattern
51
+ RELATIONSHIP_FIELD_PATTERN = /^
52
+ (?<name>[A-z0-9][A-z0-9_.-]+)
53
+ (?:\s*\((?<relation>[<>=]+)\s(?<version>#{VERSION_FIELD_PATTERN})\))?
54
+ $/x # Relationship field pattern
55
+
28
56
  option "--ignore-iteration-in-dependencies", :flag,
29
57
  "For '=' (equal) dependencies, allow iterations on the specified " \
30
58
  "version. Default is to be specific. This option allows the same " \
@@ -78,7 +106,7 @@ class FPM::Package::Deb < FPM::Package
78
106
  end
79
107
 
80
108
  option "--priority", "PRIORITY",
81
- "The debian package 'priority' value.", :default => "extra"
109
+ "The debian package 'priority' value.", :default => "optional"
82
110
 
83
111
  option "--use-file-permissions", :flag,
84
112
  "Use existing file permissions when defining ownership and modes"
@@ -201,7 +229,7 @@ class FPM::Package::Deb < FPM::Package
201
229
 
202
230
  def initialize(*args)
203
231
  super(*args)
204
- attributes[:deb_priority] = "extra"
232
+ attributes[:deb_priority] = "optional"
205
233
  end # def initialize
206
234
 
207
235
  private
@@ -272,6 +300,21 @@ class FPM::Package::Deb < FPM::Package
272
300
  return (attributes[:prefix] or "/")
273
301
  end # def prefix
274
302
 
303
+ def version
304
+ if @version.kind_of?(String)
305
+ if @version.start_with?("v") && @version.gsub(/^v/, "") =~ /^#{VERSION_FIELD_PATTERN}$/
306
+ logger.warn("Debian 'Version' field needs to start with a digit. I was provided '#{@version}' which seems like it just has a 'v' prefix to an otherwise-valid Debian version, I'll remove the 'v' for you.")
307
+ @version = @version.gsub(/^v/, "")
308
+ end
309
+
310
+ if @version !~ /^#{VERSION_FIELD_PATTERN}$/
311
+ raise FPM::InvalidPackageConfiguration, "The version looks invalid for Debian packages. Debian version field must contain only alphanumerics and . (period), + (plus), - (hyphen) or ~ (tilde). I have '#{@version}' which which isn't valid."
312
+ end
313
+ end
314
+
315
+ return @version
316
+ end
317
+
275
318
  def input(input_path)
276
319
  extract_info(input_path)
277
320
  extract_files(input_path)
@@ -427,6 +470,12 @@ class FPM::Package::Deb < FPM::Package
427
470
 
428
471
  def output(output_path)
429
472
  self.provides = self.provides.collect { |p| fix_provides(p) }
473
+
474
+ self.provides.each do |provide|
475
+ if !valid_provides_field?(provide)
476
+ raise FPM::InvalidPackageConfiguration, "Found invalid Provides field values (#{provide.inspect}). This is not valid in a Debian package."
477
+ end
478
+ end
430
479
  output_check(output_path)
431
480
  # Abort if the target path already exists.
432
481
 
@@ -542,7 +591,7 @@ class FPM::Package::Deb < FPM::Package
542
591
  end # No need to close, GzipWriter#close will close it.
543
592
  end
544
593
 
545
- if File.exists?(dest_changelog) and not File.exists?(dest_upstream_changelog)
594
+ if File.exist?(dest_changelog) and not File.exist?(dest_upstream_changelog)
546
595
  # see https://www.debian.org/doc/debian-policy/ch-docs.html#s-changelogs
547
596
  File.rename(dest_changelog, dest_upstream_changelog)
548
597
  end
@@ -592,25 +641,24 @@ class FPM::Package::Deb < FPM::Package
592
641
  when "gz", nil
593
642
  datatar = build_path("data.tar.gz")
594
643
  controltar = build_path("control.tar.gz")
595
- compression = "-z"
644
+ compression_flags = ["-z"]
596
645
  when "bzip2"
597
646
  datatar = build_path("data.tar.bz2")
598
- controltar = build_path("control.tar.bz2")
599
- compression = "-j"
647
+ controltar = build_path("control.tar.gz")
648
+ compression_flags = ["-j"]
600
649
  when "xz"
601
650
  datatar = build_path("data.tar.xz")
602
651
  controltar = build_path("control.tar.xz")
603
- compression = "-J"
652
+ compression_flags = ["-J"]
604
653
  when "none"
605
654
  datatar = build_path("data.tar")
606
655
  controltar = build_path("control.tar")
607
- compression = ""
656
+ compression_flags = []
608
657
  else
609
658
  raise FPM::InvalidPackageConfiguration,
610
659
  "Unknown compression type '#{self.attributes[:deb_compression]}'"
611
660
  end
612
-
613
- args = [ tar_cmd, "-C", staging_path, compression ] + data_tar_flags + [ "-cf", datatar, "." ]
661
+ args = [ tar_cmd, "-C", staging_path ] + compression_flags + data_tar_flags + [ "-cf", datatar, "." ]
614
662
  if tar_cmd_supports_sort_names_and_set_mtime? and not attributes[:source_date_epoch].nil?
615
663
  # Use gnu tar options to force deterministic file order and timestamp
616
664
  args += ["--sort=name", ("--mtime=@%s" % attributes[:source_date_epoch])]
@@ -660,9 +708,46 @@ class FPM::Package::Deb < FPM::Package
660
708
  fix_provides(provides)
661
709
  end.flatten
662
710
 
711
+ if origin == FPM::Package::CPAN
712
+ # The fpm cpan code presents dependencies and provides fields as perl(ModuleName)
713
+ # so we'll need to convert them to something debian supports.
714
+
715
+ # Replace perl(ModuleName) > 1.0 with Debian-style perl-ModuleName (> 1.0)
716
+ perldepfix = lambda do |dep|
717
+ m = dep.match(/perl\((?<name>[A-Za-z0-9_:]+)\)\s*(?<op>.*$)/)
718
+ if m.nil?
719
+ # 'dep' syntax didn't look like 'perl(Name) > 1.0'
720
+ dep
721
+ else
722
+ # Also replace '::' in the perl module name with '-'
723
+ modulename = m["name"].gsub("::", "-")
724
+
725
+ # Fix any upper-casing or other naming concerns Debian has about packages
726
+ name = "#{attributes[:cpan_package_name_prefix]}-#{modulename}"
727
+
728
+ if m["op"].empty?
729
+ name
730
+ else
731
+ # 'dep' syntax was like this (version constraint): perl(Module) > 1.0
732
+ "#{name} (#{m["op"]})"
733
+ end
734
+ end
735
+ end
736
+
737
+ rejects = [ "perl(vars)", "perl(warnings)", "perl(strict)", "perl(Config)" ]
738
+ self.dependencies = self.dependencies.reject do |dep|
739
+ # Reject non-module Perl dependencies like 'vars' and 'warnings'
740
+ rejects.include?(dep)
741
+ end.collect(&perldepfix).collect(&method(:fix_dependency))
742
+
743
+ # Also fix the Provides field 'perl(ModuleName) = version' to be 'perl-modulename (= version)'
744
+ self.provides = self.provides.collect(&perldepfix).collect(&method(:fix_provides))
745
+
746
+ end # if origin == FPM::Packagin::CPAN
747
+
663
748
  if origin == FPM::Package::Deb
664
749
  changelog_path = staging_path("usr/share/doc/#{name}/changelog.Debian.gz")
665
- if File.exists?(changelog_path)
750
+ if File.exist?(changelog_path)
666
751
  logger.debug("Found a deb changelog file, using it.", :path => changelog_path)
667
752
  attributes[:deb_changelog] = build_path("deb_changelog")
668
753
  File.open(attributes[:deb_changelog], "w") do |deb_changelog|
@@ -676,7 +761,7 @@ class FPM::Package::Deb < FPM::Package
676
761
 
677
762
  if origin == FPM::Package::Deb
678
763
  changelog_path = staging_path("usr/share/doc/#{name}/changelog.gz")
679
- if File.exists?(changelog_path)
764
+ if File.exist?(changelog_path)
680
765
  logger.debug("Found an upstream changelog file, using it.", :path => changelog_path)
681
766
  attributes[:deb_upstream_changelog] = build_path("deb_upstream_changelog")
682
767
  File.open(attributes[:deb_upstream_changelog], "w") do |deb_upstream_changelog|
@@ -687,6 +772,19 @@ class FPM::Package::Deb < FPM::Package
687
772
  File.unlink(changelog_path)
688
773
  end
689
774
  end
775
+
776
+ if origin == FPM::Package::Gem
777
+ # fpm's gem input will have provides as "rubygem-name = version"
778
+ # and we need to convert this to Debian-style "rubygem-name (= version)"
779
+ self.provides = self.provides.collect do |provides|
780
+ m = /^(#{attributes[:gem_package_name_prefix]})-([^\s]+)\s*=\s*(.*)$/.match(provides)
781
+ if m
782
+ "#{m[1]}-#{m[2]} (= #{m[3]})"
783
+ else
784
+ provides
785
+ end
786
+ end
787
+ end
690
788
  end # def converted_from
691
789
 
692
790
  def debianize_op(op)
@@ -761,6 +859,32 @@ class FPM::Package::Deb < FPM::Package
761
859
  end
762
860
  end # def fix_dependency
763
861
 
862
+ def valid_provides_field?(text)
863
+ m = RELATIONSHIP_FIELD_PATTERN.match(text)
864
+ if m.nil?
865
+ logger.error("Invalid relationship field for debian package: #{text}")
866
+ return false
867
+ end
868
+
869
+ # Per Debian Policy manual, https://www.debian.org/doc/debian-policy/ch-relationships.html#syntax-of-relationship-fields
870
+ # >> The relations allowed are <<, <=, =, >= and >> for strictly earlier, earlier or equal,
871
+ # >> exactly equal, later or equal and strictly later, respectively. The exception is the
872
+ # >> Provides field, for which only = is allowed
873
+ if m["relation"] == "=" || m["relation"] == nil
874
+ return true
875
+ end
876
+ return false
877
+ end
878
+
879
+ def valid_relationship_field?(text)
880
+ m = RELATIONSHIP_FIELD_PATTERN.match(text)
881
+ if m.nil?
882
+ logger.error("Invalid relationship field for debian package: #{text}")
883
+ return false
884
+ end
885
+ return true
886
+ end
887
+
764
888
  def fix_provides(provides)
765
889
  name_re = /^[^ \(]+/
766
890
  name = provides[name_re]
@@ -775,6 +899,11 @@ class FPM::Package::Deb < FPM::Package
775
899
  "debs don't like underscores")
776
900
  provides = provides.gsub("_", "-")
777
901
  end
902
+
903
+ if m = provides.match(/^([A-Za-z0-9_-]+)\s*=\s*(\d+.*$)/)
904
+ logger.warn("Replacing 'provides' entry #{provides} with syntax 'name (= version)'")
905
+ provides = "#{m[1]} (= #{m[2]})"
906
+ end
778
907
  return provides.rstrip
779
908
  end
780
909
 
@@ -802,18 +931,15 @@ class FPM::Package::Deb < FPM::Package
802
931
 
803
932
  # Tar up the staging_path into control.tar.{compression type}
804
933
  case self.attributes[:deb_compression]
805
- when "gz", nil
934
+ when "gz", "bzip2", nil
806
935
  controltar = "control.tar.gz"
807
- compression = "-z"
808
- when "bzip2"
809
- controltar = "control.tar.bz2"
810
- compression = "-j"
936
+ compression_flags = ["-z"]
811
937
  when "xz"
812
938
  controltar = "control.tar.xz"
813
- compression = "-J"
939
+ compression_flags = ["-J"]
814
940
  when "none"
815
941
  controltar = "control.tar"
816
- compression = ""
942
+ compression_flags = []
817
943
  else
818
944
  raise FPM::InvalidPackageConfiguration,
819
945
  "Unknown compression type '#{self.attributes[:deb_compression]}'"
@@ -823,7 +949,7 @@ class FPM::Package::Deb < FPM::Package
823
949
  build_path(controltar).tap do |controltar|
824
950
  logger.info("Creating", :path => controltar, :from => control_path)
825
951
 
826
- args = [ tar_cmd, "-C", control_path, compression, "-cf", controltar,
952
+ args = [ tar_cmd, "-C", control_path ] + compression_flags + [ "-cf", controltar,
827
953
  "--owner=0", "--group=0", "--numeric-owner", "." ]
828
954
  if tar_cmd_supports_sort_names_and_set_mtime? and not attributes[:source_date_epoch].nil?
829
955
  # Force deterministic file order and timestamp
@@ -912,7 +1038,7 @@ class FPM::Package::Deb < FPM::Package
912
1038
  etcfiles = []
913
1039
  # Add everything in /etc
914
1040
  begin
915
- if !attributes[:deb_no_default_config_files?]
1041
+ if !attributes[:deb_no_default_config_files?] && File.exist?(staging_path("/etc"))
916
1042
  logger.warn("Debian packaging tools generally labels all files in /etc as config files, " \
917
1043
  "as mandated by policy, so fpm defaults to this behavior for deb packages. " \
918
1044
  "You can disable this default behavior with --deb-no-default-config-files flag")
@@ -1086,5 +1212,5 @@ class FPM::Package::Deb < FPM::Package
1086
1212
  return data_tar_flags
1087
1213
  end # def data_tar_flags
1088
1214
 
1089
- public(:input, :output, :architecture, :name, :prefix, :converted_from, :to_s, :data_tar_flags)
1215
+ public(:input, :output, :architecture, :name, :prefix, :version, :converted_from, :to_s, :data_tar_flags)
1090
1216
  end # class FPM::Target::Deb
@@ -43,7 +43,7 @@ class FPM::Package::Dir < FPM::Package
43
43
  # This mapping should work the same way 'rsync -a' does
44
44
  # Meaning 'rsync -a source dest'
45
45
  # and 'source=dest' in fpm work the same as the above rsync
46
- if path =~ /.=./ && !File.exists?(chdir == '.' ? path : File.join(chdir, path))
46
+ if path =~ /.=./ && !File.exist?(chdir == '.' ? path : File.join(chdir, path))
47
47
  origin, destination = path.split("=", 2)
48
48
 
49
49
  if File.directory?(origin) && origin[-1,1] == "/"
@@ -4,6 +4,18 @@ require "backports/latest"
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
@@ -86,9 +86,7 @@ class FPM::Package::FreeBSD < FPM::Package
86
86
  # We use --files-from here to keep the tar entries from having `./` as the prefix.
87
87
  # This is done as a best effor to mimic what FreeBSD packages do, having everything at the top-level as
88
88
  # file names, like "+MANIFEST" instead of "./+MANIFEST"
89
- # Note: This will include top-level files like "/usr/bin/foo" listed in the tar as "usr/bin/fo" without
90
- # a leading slash. I don't know if this has any negative impact on freebsd packages.
91
- safesystem("tar", "-Jcf", output_path, "-C", staging_path, "--files-from", build_path("file_list"))
89
+ safesystem("tar", "-Jcf", output_path, "-C", staging_path, "--files-from", build_path("file_list"), "--transform", 's|^\([^+]\)|/\1|')
92
90
  end # def output
93
91
 
94
92
  # Handle architecture naming conversion:
@@ -104,19 +104,18 @@ class FPM::Package::Gem < FPM::Package
104
104
  FileUtils.mkdir(download_dir) unless File.directory?(download_dir)
105
105
 
106
106
  if attributes[:gem_git_repo]
107
- require "git"
108
107
  logger.debug("Git cloning in directory #{download_dir}")
109
- g = Git.clone(attributes[:gem_git_repo],gem_name,:path => download_dir)
108
+ safesystem("git", "-C", download_dir, "clone", attributes[:gem_git_repo], ".")
110
109
  if attributes[:gem_git_branch]
111
- g.branch(attributes[:gem_git_branch]).checkout
112
- g.pull('origin',attributes[:gem_git_branch])
110
+ safesystem("git", "-C", download_dir, "checkout", attributes[:gem_git_branch])
113
111
  end
114
- gem_build = [ "#{attributes[:gem_gem]}", "build", "#{g.dir.to_s}/#{gem_name}.gemspec"]
115
- ::Dir.chdir(g.dir.to_s) do |dir|
112
+
113
+ gem_build = [ "#{attributes[:gem_gem]}", "build", "#{download_dir}/#{gem_name}.gemspec"]
114
+ ::Dir.chdir(download_dir) do |dir|
116
115
  logger.debug("Building in directory #{dir}")
117
116
  safesystem(*gem_build)
118
117
  end
119
- gem_files = ::Dir.glob(File.join(g.dir.to_s, "*.gem"))
118
+ gem_files = ::Dir.glob(File.join(download_dir, "*.gem"))
120
119
  else
121
120
  gem_fetch = [ "#{attributes[:gem_gem]}", "fetch", gem_name]
122
121
  gem_fetch += ["--prerelease"] if attributes[:gem_prerelease?]
@@ -135,9 +134,19 @@ class FPM::Package::Gem < FPM::Package
135
134
  return gem_files.first
136
135
  end # def download
137
136
 
137
+ GEMSPEC_YAML_CLASSES = [ ::Gem::Specification, ::Gem::Version, Time, ::Gem::Dependency, ::Gem::Requirement, Symbol ]
138
138
  def load_package_info(gem_path)
139
-
140
- spec = YAML.load(%x{#{attributes[:gem_gem]} specification #{gem_path} --yaml})
139
+ # TODO(sissel): Maybe we should check if `safe_load` method exists instead of this version check?
140
+ if ::Gem::Version.new(RUBY_VERSION) >= ::Gem::Version.new("3.1.0")
141
+ # Ruby 3.1.0 switched to a Psych/YAML version that defaults to "safe" loading
142
+ # and unfortunately `gem specification --yaml` emits YAML that requires
143
+ # class loaders to process correctly
144
+ spec = YAML.load(%x{#{attributes[:gem_gem]} specification #{gem_path} --yaml},
145
+ :permitted_classes => GEMSPEC_YAML_CLASSES)
146
+ else
147
+ # Older versions of ruby call this method YAML.safe_load
148
+ spec = YAML.safe_load(%x{#{attributes[:gem_gem]} specification #{gem_path} --yaml}, GEMSPEC_YAML_CLASSES)
149
+ end
141
150
 
142
151
  if !attributes[:gem_package_prefix].nil?
143
152
  attributes[:gem_package_name_prefix] = attributes[:gem_package_prefix]
@@ -4,7 +4,6 @@ require "fileutils"
4
4
  require "fpm/package/dir"
5
5
  require 'tempfile' # stdlib
6
6
  require 'pathname' # stdlib
7
- require 'rexml/document' # stdlib
8
7
 
9
8
  # Use an OS X pkg built with pkgbuild.
10
9
  #
@@ -103,6 +102,7 @@ class FPM::Package::OSXpkg < FPM::Package
103
102
 
104
103
  # Extract name and version from PackageInfo XML
105
104
  def extract_info(package)
105
+ require 'rexml/document'
106
106
  build_path("expand").tap do |path|
107
107
  doc = REXML::Document.new File.open(File.join(path, "PackageInfo"))
108
108
  pkginfo_elem = doc.elements["pkg-info"]
@@ -148,6 +148,11 @@ class FPM::Package::OSXpkg < FPM::Package
148
148
  write_scripts
149
149
  args += ["--scripts", scripts_path]
150
150
  end
151
+
152
+ if attributes[:prefix]
153
+ args += ["--install-location", attributes[:prefix]]
154
+ end
155
+
151
156
  args << output_path
152
157
 
153
158
  safesystem("pkgbuild", *args)
@@ -234,7 +234,7 @@ class FPM::Package::Pacman < FPM::Package
234
234
  return ""
235
235
  when "gz"
236
236
  return ".gz"
237
- when "zx"
237
+ when "xz"
238
238
  return ".xz"
239
239
  when "bzip2"
240
240
  return ".bz2"
@@ -18,6 +18,7 @@ class FPM::Package::PleaseRun < FPM::Package
18
18
 
19
19
  option "--name", "SERVICE_NAME", "The name of the service you are creating"
20
20
  option "--chdir", "CHDIR", "The working directory used by the service"
21
+ option "--user", "USER", "The user to use for executing this program."
21
22
 
22
23
  private
23
24
  def input(command)
@@ -60,7 +60,7 @@ class FPM::Package::Puppet < FPM::Package
60
60
  end # case name
61
61
  end # self.scripts.each
62
62
 
63
- if File.exists?(params[:output])
63
+ if File.exist?(params[:output])
64
64
  # TODO(sissel): Allow folks to choose output?
65
65
  logger.error("Puppet module directory '#{params[:output]}' already " \
66
66
  "exists. Delete it or choose another output (-p flag)")
@@ -90,6 +90,11 @@ class get_metadata(Command):
90
90
  for dep in pkg_resources.parse_requirements(
91
91
  self.distribution.install_requires):
92
92
  final_deps.extend(self.process_dep(dep))
93
+ if getattr(self.distribution, 'extras_require', None):
94
+ for dep in pkg_resources.parse_requirements(
95
+ v for k, v in self.distribution.extras_require.items()
96
+ if k.startswith(':') and pkg_resources.evaluate_marker(k[1:])):
97
+ final_deps.extend(self.process_dep(dep))
93
98
 
94
99
  data["dependencies"] = final_deps
95
100
 
@@ -107,3 +112,4 @@ class get_metadata(Command):
107
112
  else:
108
113
  # For Python 2.5 and Debian's python-json
109
114
  output.write(json.write(data))
115
+ output.close()
@@ -79,7 +79,11 @@ class FPM::Package::Python < FPM::Package
79
79
  option "--setup-py-arguments", "setup_py_argument",
80
80
  "Arbitrary argument(s) to be passed to setup.py",
81
81
  :multivalued => true, :attribute_name => :python_setup_py_arguments,
82
- :default => []
82
+ :default => []
83
+ option "--internal-pip", :flag,
84
+ "Use the pip module within python to install modules - aka 'python -m pip'. This is the recommended usage since Python 3.4 (2014) instead of invoking the 'pip' script",
85
+ :attribute_name => :python_internal_pip,
86
+ :default => true
83
87
 
84
88
  private
85
89
 
@@ -130,23 +134,24 @@ class FPM::Package::Python < FPM::Package
130
134
  target = build_path(package)
131
135
  FileUtils.mkdir(target) unless File.directory?(target)
132
136
 
133
- if attributes[:python_pip].nil?
134
- # no pip, use easy_install
135
- logger.debug("no pip, defaulting to easy_install", :easy_install => attributes[:python_easyinstall])
136
- safesystem(attributes[:python_easyinstall], "-i",
137
- attributes[:python_pypi], "--editable", "-U",
138
- "--build-directory", target, want_pkg)
139
- else
137
+ if attributes[:python_internal_pip?]
138
+ # XXX: Should we detect if internal pip is available?
139
+ attributes[:python_pip] = [ attributes[:python_bin], "-m", "pip"]
140
+ end
141
+
142
+ # attributes[:python_pip] -- expected to be a path
143
+ if attributes[:python_pip]
140
144
  logger.debug("using pip", :pip => attributes[:python_pip])
141
145
  # TODO: Support older versions of pip
142
146
 
147
+ pip = [attributes[:python_pip]] if pip.is_a?(String)
143
148
  setup_cmd = [
144
- attributes[:python_pip],
149
+ *attributes[:python_pip],
145
150
  "download",
146
151
  "--no-clean",
147
152
  "--no-deps",
148
- "--no-binary",
149
- ":all:",
153
+ "--no-binary", ":all:",
154
+ "-d", build_path,
150
155
  "-i", attributes[:python_pypi],
151
156
  ]
152
157
 
@@ -157,13 +162,28 @@ class FPM::Package::Python < FPM::Package
157
162
  ]
158
163
  end
159
164
 
160
- setup_cmd += [
161
- "--build",
162
- target,
163
- want_pkg,
164
- ]
165
-
165
+ setup_cmd << want_pkg
166
+
166
167
  safesystem(*setup_cmd)
168
+
169
+ # Pip removed the --build flag sometime in 2021, it seems: https://github.com/pypa/pip/issues/8333
170
+ # A workaround for pip removing the `--build` flag. Previously, `pip download --build ...` would leave
171
+ # behind a directory with the Python package extracted and ready to be used.
172
+ # For example, `pip download ... Django` puts `Django-4.0.4.tar.tz` into the build_path directory.
173
+ # If we expect `pip` to leave an unknown-named file in the `build_path` directory, let's check for
174
+ # a single file and unpack it. I don't know if it will /always/ be a .tar.gz though.
175
+ files = ::Dir.glob(File.join(build_path, "*.tar.gz"))
176
+ if files.length != 1
177
+ raise "Unexpected directory layout after `pip download ...`. This might be an fpm bug? The directory is #{build_path}"
178
+ end
179
+
180
+ safesystem("tar", "-zxf", files[0], "-C", target)
181
+ else
182
+ # no pip, use easy_install
183
+ logger.debug("no pip, defaulting to easy_install", :easy_install => attributes[:python_easyinstall])
184
+ safesystem(attributes[:python_easyinstall], "-i",
185
+ attributes[:python_pypi], "--editable", "-U",
186
+ "--build-directory", target, want_pkg)
167
187
  end
168
188
 
169
189
  # easy_install will put stuff in @tmpdir/packagename/, so find that:
@@ -239,7 +259,9 @@ class FPM::Package::Python < FPM::Package
239
259
  self.description = metadata["description"]
240
260
  # Sometimes the license field is multiple lines; do best-effort and just
241
261
  # use the first line.
242
- self.license = metadata["license"].split(/[\r\n]+/).first
262
+ if metadata["license"]
263
+ self.license = metadata["license"].split(/[\r\n]+/).first
264
+ end
243
265
  self.version = metadata["version"]
244
266
  self.url = metadata["url"]
245
267
 
@@ -4,6 +4,9 @@ require "fileutils"
4
4
  require "find"
5
5
  require "arr-pm/file" # gem 'arr-pm'
6
6
 
7
+ # For conversion handling
8
+ require "fpm/package/gem"
9
+
7
10
  # RPM Package type.
8
11
  #
9
12
  # Build RPMs without having to waste hours reading Maximum-RPM.
@@ -189,17 +192,26 @@ class FPM::Package::RPM < FPM::Package
189
192
  # Replace * with [*] to make rpm not use globs
190
193
  # Replace ? with [?] to make rpm not use globs
191
194
  # Replace % with [%] to make rpm not expand macros
195
+ # Replace whitespace with ? to make rpm not split the filename
196
+ # If and only if any of the above are done, then also replace ' with \', " with \", and \ with \\\\
197
+ # to accommodate escape and quote processing that rpm will perform in that case (but not otherwise)
192
198
  def rpm_fix_name(name)
193
- name = name.gsub(/(\ |\[|\]|\*|\?|\%|\$|')/, {
194
- ' ' => '?',
195
- '%' => '[%]',
196
- '$' => '[$]',
197
- '?' => '[?]',
198
- '*' => '[*]',
199
- '[' => '[\[]',
200
- ']' => '[\]]',
201
- "'" => "\\'",
202
- })
199
+ if name.match?(/[ \t*?%$\[\]]/)
200
+ name = name.gsub(/(\ |\t|\[|\]|\*|\?|\%|\$|'|"|\\)/, {
201
+ ' ' => '?',
202
+ "\t" => '?',
203
+ '%' => '[%]',
204
+ '$' => '[$]',
205
+ '?' => '[?]',
206
+ '*' => '[*]',
207
+ '[' => '[\[]',
208
+ ']' => '[\]]',
209
+ '"' => '\\"',
210
+ "'" => "\\'",
211
+ '\\' => '\\\\\\\\',
212
+ })
213
+ end
214
+ name
203
215
  end
204
216
 
205
217
  def rpm_file_entry(file)
@@ -254,6 +266,12 @@ class FPM::Package::RPM < FPM::Package
254
266
 
255
267
  # This method ensures a default value for iteration if none is provided.
256
268
  def iteration
269
+ if @iteration.kind_of?(String) and @iteration.include?("-")
270
+ logger.warn("Package iteration '#{@iteration}' includes dashes, converting" \
271
+ " to underscores. rpmbuild does not allow the dashes in the package iteration (called 'Release' in rpm)")
272
+ @iteration = @iteration.gsub(/-/, "_")
273
+ end
274
+
257
275
  return @iteration ? @iteration : 1
258
276
  end # def iteration
259
277
 
@@ -2,6 +2,8 @@ require "fpm/namespace"
2
2
  require "fpm/package"
3
3
  require "fpm/util"
4
4
 
5
+ require "fpm/package/dir"
6
+
5
7
  # Support for python virtualenv packages.
6
8
  #
7
9
  # This supports input, but not output.
data/lib/fpm/package.rb CHANGED
@@ -331,11 +331,12 @@ class FPM::Package
331
331
  template_path = File.join(template_dir, path)
332
332
  template_code = File.read(template_path)
333
333
  logger.info("Reading template", :path => template_path)
334
- erb = ERB.new(template_code, nil, "-")
334
+ erb = erbnew(template_code)
335
335
  erb.filename = template_path
336
336
  return erb
337
337
  end # def template
338
338
 
339
+
339
340
  #######################################
340
341
  # The following methods are provided to
341
342
  # easily override particular substitut-
@@ -518,7 +519,7 @@ class FPM::Package
518
519
  # flag), then apply it as an ERB template.
519
520
  def script(script_name)
520
521
  if attributes[:template_scripts?]
521
- erb = ERB.new(scripts[script_name], nil, "-")
522
+ erb = erbnew(scripts[script_name])
522
523
  # TODO(sissel): find the original file name for the file.
523
524
  erb.filename = "script(#{script_name})"
524
525
  return erb.result(binding)
data/lib/fpm/util.rb CHANGED
@@ -154,10 +154,13 @@ module FPM::Util
154
154
 
155
155
  yield(*args3)
156
156
 
157
- stdin_w_close if opts[:stdin] and not stdin_w.closed?
157
+ stdin_w.close if opts[:stdin] and not stdin_w.closed?
158
158
  stdout_r.close unless stdout_r.closed?
159
159
  stderr_r.close unless stderr_r.closed?
160
160
  else
161
+ # If no block given (not interactive) we should close stdin_w because we
162
+ # won't be able to give input which may cause a hang.
163
+ stdin_w.close
161
164
  # Log both stdout and stderr as 'info' because nobody uses stderr for
162
165
  # actually reporting errors and as a result 'stderr' is a misnomer.
163
166
  logger.pipe(stdout_r => :info, stderr_r => :info)
@@ -342,7 +345,7 @@ module FPM::Util
342
345
  when 'characterSpecial', 'blockSpecial'
343
346
  raise UnsupportedSpecialFile.new("File is device which fpm doesn't know how to copy (#{File.ftype(src)}): #{src}")
344
347
  when 'directory'
345
- FileUtils.mkdir(dst) unless File.exists? dst
348
+ FileUtils.mkdir(dst) unless File.exist? dst
346
349
  else
347
350
  # if the file with the same dev and inode has been copied already -
348
351
  # hard link it's copy to `dst`, otherwise make an actual copy
@@ -406,6 +409,33 @@ module FPM::Util
406
409
  def logger
407
410
  @logger ||= Cabin::Channel.get
408
411
  end # def logger
412
+
413
+ def erbnew(template_code)
414
+ # In Ruby 2.6(?), Ruby changed how ERB::new is invoked.
415
+ # First, it added keyword args like `ERB.new(..., trim_mode: "-")`
416
+ # Later, it deprecated then removed the safe_level feature.
417
+ # As of Ruby 3.1, warnings are printed at runtime when ERB.new is called with the old syntax.
418
+ # Ruby 2.5 and older does not support the ERB.new keyword args.
419
+ #
420
+ # My tests showed:
421
+ # * Ruby 2.3.0 through 3.0 work correctly with the old syntax.
422
+ # * Ruby 3.1.0 and newer (at time of writing, Ruby 3.2) require the new syntax
423
+ # Therefore, in order to support the most versions of ruby, we need to do a version check
424
+ # to invoke ERB.new correctly and without printed warnings.
425
+ # References: https://github.com/jordansissel/fpm/issues/1894
426
+ # Honestly, I'm not sure if Gem::Version is correct to use in this situation, but it works.
427
+
428
+ # on older versions of Ruby, RUBY_VERSION is a frozen string, and
429
+ # Gem::Version.new calls String#strip! which throws an exception.
430
+ # so we have to call String#dup to get an unfrozen copy.
431
+ if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new("3.1.0")
432
+ # Ruby 3.0.x and older
433
+ return ERB.new(template_code, nil, "-")
434
+ else
435
+ # Ruby 3.1.0 and newer
436
+ return ERB.new(template_code, trim_mode: "-")
437
+ end
438
+ end
409
439
  end # module FPM::Util
410
440
 
411
441
  require 'fpm/util/tar_writer'
data/lib/fpm/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module FPM
2
- VERSION = "1.13.0"
2
+ VERSION = "1.15.1"
3
3
  end
@@ -1,4 +1,4 @@
1
- <%= name %> (<%= "#{epoch}:" if epoch %><%= version %><%= "-" + iteration.to_s if iteration %>) whatever; urgency=medium
1
+ <%= name %> (<%= "#{epoch}:" if epoch %><%= version %><%= "-" + iteration.to_s if iteration %>) <%= distribution %>; urgency=medium
2
2
 
3
3
  * Package created with FPM.
4
4
 
@@ -14,7 +14,7 @@ Description: <%= firstline %>
14
14
  <%= remainder.collect { |l| l =~ /^ *$/ ? " ." : " #{l}" }.join("\n") %>
15
15
  <% end -%>
16
16
  Changes:
17
- <%= name %> (<%= "#{epoch}:" if epoch %><%= version %><%= "-" + iteration.to_s if iteration %>) whatever; urgency=medium
17
+ <%= name %> (<%= "#{epoch}:" if epoch %><%= version %><%= "-" + iteration.to_s if iteration %>) <%= distribution %>; urgency=medium
18
18
  * Package created with FPM.
19
19
  Checksums-Sha1:
20
20
  <% changes_files.each do |file| -%>
data/templates/deb.erb CHANGED
@@ -25,7 +25,7 @@ Build-Depends: <%= attributes[:deb_build_depends].collect { |d| fix_dependency(d
25
25
  <% if !provides.empty? -%>
26
26
  <%# Turn each provides from 'foo = 123' to simply 'foo' because Debian :\ -%>
27
27
  <%# http://www.debian.org/doc/debian-policy/ch-relationships.html -%>
28
- Provides: <%= provides.map {|p| p.split(" ").first}.join ", " %>
28
+ Provides: <%= provides.join ", " %>
29
29
  <% end -%>
30
30
  <% if !replaces.empty? -%>
31
31
  Replaces: <%= replaces.collect { |d| fix_dependency(d) }.flatten.join(", ") %>
metadata CHANGED
@@ -1,35 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fpm
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.13.0
4
+ version: 1.15.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Sissel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-19 00:00:00.000000000 Z
11
+ date: 2023-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: json
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 1.7.7
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: '3.0'
23
- type: :runtime
24
- prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- version: 1.7.7
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: '3.0'
33
13
  - !ruby/object:Gem::Dependency
34
14
  name: cabin
35
15
  requirement: !ruby/object:Gem::Requirement
@@ -86,20 +66,6 @@ dependencies:
86
66
  - - "~>"
87
67
  - !ruby/object:Gem::Version
88
68
  version: 1.0.0
89
- - !ruby/object:Gem::Dependency
90
- name: rake
91
- requirement: !ruby/object:Gem::Requirement
92
- requirements:
93
- - - "~>"
94
- - !ruby/object:Gem::Version
95
- version: '10'
96
- type: :development
97
- prerelease: false
98
- version_requirements: !ruby/object:Gem::Requirement
99
- requirements:
100
- - - "~>"
101
- - !ruby/object:Gem::Version
102
- version: '10'
103
69
  - !ruby/object:Gem::Dependency
104
70
  name: pleaserun
105
71
  requirement: !ruby/object:Gem::Requirement
@@ -114,26 +80,6 @@ dependencies:
114
80
  - - "~>"
115
81
  - !ruby/object:Gem::Version
116
82
  version: 0.0.29
117
- - !ruby/object:Gem::Dependency
118
- name: git
119
- requirement: !ruby/object:Gem::Requirement
120
- requirements:
121
- - - ">="
122
- - !ruby/object:Gem::Version
123
- version: 1.3.0
124
- - - "<"
125
- - !ruby/object:Gem::Version
126
- version: '2.0'
127
- type: :runtime
128
- prerelease: false
129
- version_requirements: !ruby/object:Gem::Requirement
130
- requirements:
131
- - - ">="
132
- - !ruby/object:Gem::Version
133
- version: 1.3.0
134
- - - "<"
135
- - !ruby/object:Gem::Version
136
- version: '2.0'
137
83
  - !ruby/object:Gem::Dependency
138
84
  name: stud
139
85
  requirement: !ruby/object:Gem::Requirement
@@ -204,6 +150,20 @@ dependencies:
204
150
  - - ">="
205
151
  - !ruby/object:Gem::Version
206
152
  version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rake
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
207
167
  description: Convert directories, rpms, python eggs, rubygems, and more to rpms, debs,
208
168
  solaris packages and more. Win at package management without wasting pointless hours
209
169
  debugging bad rpm specs!
@@ -294,7 +254,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
294
254
  - !ruby/object:Gem::Version
295
255
  version: '0'
296
256
  requirements: []
297
- rubygems_version: 3.2.15
257
+ rubygems_version: 3.4.1
298
258
  signing_key:
299
259
  specification_version: 4
300
260
  summary: fpm - package building and mangling