fpm 1.15.1 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -156,7 +156,7 @@ class FPM::Package::RPM < FPM::Package
156
156
 
157
157
  option "--macro-expansion", :flag,
158
158
  "install-time macro expansion in %pre %post %preun %postun scripts " \
159
- "(see: https://rpm.org/user_doc/scriptlet_expansion.html)", :default => false
159
+ "(see: https://rpm-software-management.github.io/rpm/manual/scriptlet_expansion.html)", :default => false
160
160
 
161
161
  option "--verifyscript", "FILE",
162
162
  "a script to be run on verification" do |val|
@@ -175,7 +175,7 @@ class FPM::Package::RPM < FPM::Package
175
175
  rpm_trigger = []
176
176
  option "--trigger-#{trigger_type}", "'[OPT]PACKAGE: FILEPATH'", "Adds a rpm trigger script located in FILEPATH, " \
177
177
  "having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. " \
178
- "See: http://rpm.org/api/4.4.2.2/triggers.html" do |trigger|
178
+ "See: https://rpm-software-management.github.io/rpm/manual/triggers.html" do |trigger|
179
179
  match = trigger.match(/^(\[.*\]|)(.*): (.*)$/)
180
180
  @logger.fatal("Trigger '#{trigger_type}' definition can't be parsed ('#{trigger}')") unless match
181
181
  opt, pkg, file = match.captures
@@ -185,6 +185,9 @@ class FPM::Package::RPM < FPM::Package
185
185
  end
186
186
  end
187
187
 
188
+ option "--old-perl-dependency-name", :flag,
189
+ "Use older 'perl' depdency name. Newer Red Hat (and derivatives) use a dependency named 'perl-interpreter'."
190
+
188
191
  private
189
192
 
190
193
  # Fix path name
@@ -196,8 +199,8 @@ class FPM::Package::RPM < FPM::Package
196
199
  # If and only if any of the above are done, then also replace ' with \', " with \", and \ with \\\\
197
200
  # to accommodate escape and quote processing that rpm will perform in that case (but not otherwise)
198
201
  def rpm_fix_name(name)
199
- if name.match?(/[ \t*?%$\[\]]/)
200
- name = name.gsub(/(\ |\t|\[|\]|\*|\?|\%|\$|'|"|\\)/, {
202
+ if name.match?(/[ \t*?%${}\[\]]/)
203
+ name = name.gsub(/(\ |\t|\[|\]|\*|\?|\%|\$|'|"|\{|\}|\\)/, {
201
204
  ' ' => '?',
202
205
  "\t" => '?',
203
206
  '%' => '[%]',
@@ -206,6 +209,10 @@ class FPM::Package::RPM < FPM::Package
206
209
  '*' => '[*]',
207
210
  '[' => '[\[]',
208
211
  ']' => '[\]]',
212
+ #'{' => '[\{]',
213
+ #'}' => '[\}]',
214
+ '{' => '?',
215
+ '}' => '?',
209
216
  '"' => '\\"',
210
217
  "'" => "\\'",
211
218
  '\\' => '\\\\\\\\',
@@ -275,9 +282,41 @@ class FPM::Package::RPM < FPM::Package
275
282
  return @iteration ? @iteration : 1
276
283
  end # def iteration
277
284
 
285
+ # Generate a generic changelog or return an existing definition
286
+ def changelog
287
+ if attributes[:rpm_changelog]
288
+ return attributes[:rpm_changelog]
289
+ end
290
+
291
+ reldate = if attributes[:source_date_epoch].nil?
292
+ Time.now()
293
+ else
294
+ Time.at(attributes[:source_date_epoch].to_i)
295
+ end
296
+ changed = reldate.strftime("%a %b %_e %Y")
297
+ changev = "#{version}-#{iteration}"
298
+ changev += "%{?dist}" if attributes[:rpm_dist]
299
+
300
+ "* #{changed} #{maintainer} - #{changev}\n- Package created with FPM\n"
301
+ end
302
+
278
303
  # See FPM::Package#converted_from
279
304
  def converted_from(origin)
280
- if origin == FPM::Package::Gem
305
+ if origin == FPM::Package::CPAN
306
+ if !attributes[:rpm_old_perl_dependency_name?]
307
+ fixed_deps = []
308
+ self.dependencies.collect do |dep|
309
+ # RPM package "perl" is a metapackage which install all the Perl bits and core modules, then gcc...
310
+ # this must be replaced by perl-interpreter
311
+ if name=/^perl([\s<>=].*)$/.match(dep)
312
+ fixed_deps.push("perl-interpreter#{name[1]}")
313
+ else
314
+ fixed_deps.push(dep)
315
+ end
316
+ end
317
+ self.dependencies = fixed_deps
318
+ end
319
+ elsif origin == FPM::Package::Gem
281
320
  fixed_deps = []
282
321
  self.dependencies.collect do |dep|
283
322
  # Gem dependency operator "~>" is not compatible with rpm. Translate any found.
@@ -473,6 +512,7 @@ class FPM::Package::RPM < FPM::Package
473
512
  args += ["--define", "dist .#{attributes[:rpm_dist]}"] if attributes[:rpm_dist]
474
513
 
475
514
  args += [
515
+ "--buildroot", "#{build_path}/BUILD",
476
516
  "--define", "buildroot #{build_path}/BUILD",
477
517
  "--define", "_topdir #{build_path}",
478
518
  "--define", "_sourcedir #{build_path}",
@@ -36,7 +36,7 @@ class FPM::Package::Virtualenv < FPM::Package
36
36
  :default => nil
37
37
 
38
38
  option "--setup-install", :flag, "After building virtualenv run setup.py install "\
39
- "useful when building a virtualenv for packages and including their requirements from "
39
+ "useful when building a virtualenv for packages and including their requirements from "\
40
40
  "requirements.txt"
41
41
 
42
42
  option "--system-site-packages", :flag, "Give the virtual environment access to the "\
@@ -158,6 +158,31 @@ class FPM::Package::Virtualenv < FPM::Package
158
158
  end
159
159
  end
160
160
 
161
+ # [2025-09-30] virtualenv-tools seems broken?
162
+ # The --update-path will look for a VIRTUAL_ENV= line in bin/activate,
163
+ # however, the version I tested looks for it with quotations, like VIRTUAL_ENV='
164
+ # And at time of writing, my `virtualenv` tool doesn't use quotations on this variable
165
+ #
166
+ # Maybe best case we can patch it here instead. The path update tool
167
+ # looks for the original virtualenv path and I think updates any bin
168
+ # files which point to it.
169
+ patched = []
170
+ activate_bin = File.join(virtualenv_build_folder, "bin/activate")
171
+ fd = File.open(activate_bin)
172
+ fd.each_line do |line|
173
+ re = /^VIRTUAL_ENV=([^'"].*)$/
174
+ match = line.match(re)
175
+ if match
176
+ # Quote the VIRTUAL_ENV var assignment to help virtualenv-tools work?
177
+ patched << "VIRTUAL_ENV='#{match}'\n"
178
+ else
179
+ patched << line
180
+ end
181
+ end
182
+ fd.close
183
+ File.write(activate_bin, patched.join)
184
+
185
+ # Rewrite the base path inside the virtualenv to prepare it to be packaged.
161
186
  ::Dir.chdir(virtualenv_build_folder) do
162
187
  safesystem("virtualenv-tools", "--update-path", virtualenv_folder)
163
188
  end
@@ -191,7 +216,6 @@ class FPM::Package::Virtualenv < FPM::Package
191
216
  dir.input(".")
192
217
  @staging_path = dir.staging_path
193
218
  dir.cleanup_build
194
-
195
219
  end # def input
196
220
 
197
221
  # Delete python precompiled files found in a given folder.
data/lib/fpm/package.rb CHANGED
@@ -3,7 +3,6 @@ require "fpm/util" # local
3
3
  require "pathname" # stdlib
4
4
  require "find"
5
5
  require "tmpdir" # stdlib
6
- require "ostruct"
7
6
  require "backports/latest"
8
7
  require "socket" # stdlib, for Socket.gethostname
9
8
  require "shellwords" # stdlib, for Shellwords.escape
data/lib/fpm/rake_task.rb CHANGED
@@ -1,13 +1,39 @@
1
1
  require "fpm/namespace"
2
- require "ostruct"
3
2
  require "rake"
4
3
  require "rake/tasklib"
5
4
 
6
5
  class FPM::RakeTask < Rake::TaskLib
6
+ class Options
7
+ attr_accessor :args
8
+
9
+ def initialize(defaults=nil)
10
+ if defaults.nil?
11
+ @h = Hash.new
12
+ else
13
+ @h = defaults
14
+ end
15
+ end
16
+
17
+ def method_missing(m, *args)
18
+ if m.end_with?("=")
19
+ raise ArgumentError, "#{self.class.name}##{m} ... Expected 1 arg, got #{args.length}" if args.length != 1
20
+ @h[m[0...-1]] = args[0]
21
+ else
22
+ raise ArgumentError, "Expected 0 arg, got #{args.length}" if args.length != 0
23
+ return @h[m]
24
+ end
25
+ end
26
+
27
+ def to_h
28
+ return @h
29
+ end
30
+ end # Options
31
+
7
32
  attr_reader :options
8
33
 
9
34
  def initialize(package_name, opts = {}, &block)
10
- @options = OpenStruct.new(:name => package_name.to_s)
35
+ #@options = OpenStruct.new(:name => package_name.to_s)
36
+ @options = Options.new(:name => package_name.to_s)
11
37
  @source, @target = opts.values_at(:source, :target).map(&:to_s)
12
38
  @directory = File.expand_path(opts[:directory].to_s)
13
39
 
@@ -18,8 +44,8 @@ class FPM::RakeTask < Rake::TaskLib
18
44
 
19
45
  task(options.name) do |_, task_args|
20
46
  block.call(*[options, task_args].first(block.arity)) if block_given?
21
- abort("Must specify args") unless options.respond_to?(:args)
22
- @args = options.delete_field(:args)
47
+ abort("Must specify args") if options.args.nil?
48
+ @args = options.args
23
49
  run_cli
24
50
  end
25
51
  end
data/lib/fpm/util.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "fpm/namespace"
2
2
  require "fileutils"
3
+ require "stud/temporary"
3
4
 
4
5
  # Some utility functions
5
6
  module FPM::Util
@@ -135,7 +136,7 @@ module FPM::Util
135
136
  raise ExecutableNotFound.new(program)
136
137
  end
137
138
 
138
- logger.debug("Running command", :args => args2)
139
+ logger.info("Running command", :args => args2)
139
140
 
140
141
  stdout_r, stdout_w = IO.pipe
141
142
  stderr_r, stderr_w = IO.pipe
@@ -229,15 +230,18 @@ module FPM::Util
229
230
  @@ar_cmd_deterministic = false
230
231
 
231
232
  # FIXME: don't assume current directory writeable
232
- FileUtils.touch(["fpm-dummy.tmp"])
233
+ emptyfile = Stud::Temporary.pathname
234
+ testarchive = Stud::Temporary.pathname
235
+ FileUtils.touch([emptyfile])
236
+
233
237
  ["ar", "gar"].each do |ar|
234
238
  ["-qc", "-qcD"].each do |ar_create_opts|
235
- FileUtils.rm_f(["fpm-dummy.ar.tmp"])
239
+ FileUtils.rm_f([testarchive])
236
240
  # Return this combination if it creates archives without uids or timestamps.
237
241
  # Exitstatus will be nonzero if the archive can't be created,
238
242
  # or its table of contents doesn't match the regular expression.
239
243
  # Be extra-careful about locale and timezone when matching output.
240
- system("#{ar} #{ar_create_opts} fpm-dummy.ar.tmp fpm-dummy.tmp 2>/dev/null && env TZ=UTC LANG=C LC_TIME=C #{ar} -tv fpm-dummy.ar.tmp | grep '0/0.*1970' > /dev/null 2>&1")
244
+ system("#{ar} #{ar_create_opts} #{testarchive} #{emptyfile} 2>/dev/null && env TZ=UTC LANG=C LC_TIME=C #{ar} -tv #{testarchive} | grep '0/0.*1970' > /dev/null 2>&1")
241
245
  if $?.exitstatus == 0
242
246
  @@ar_cmd = [ar, ar_create_opts]
243
247
  @@ar_cmd_deterministic = true
@@ -247,10 +251,8 @@ module FPM::Util
247
251
  end
248
252
  # If no combination of ar and options omits timestamps, fall back to default.
249
253
  @@ar_cmd = ["ar", "-qc"]
254
+ FileUtils.rm_f([testarchive, emptyfile])
250
255
  return @@ar_cmd
251
- ensure
252
- # Clean up
253
- FileUtils.rm_f(["fpm-dummy.ar.tmp", "fpm-dummy.tmp"])
254
256
  end # def ar_cmd
255
257
 
256
258
  # Return whether the command returned by ar_cmd can create deterministic archives
@@ -264,7 +266,10 @@ module FPM::Util
264
266
  return @@tar_cmd if defined? @@tar_cmd
265
267
 
266
268
  # FIXME: don't assume current directory writeable
267
- FileUtils.touch(["fpm-dummy.tmp"])
269
+ emptyfile = Stud::Temporary.pathname
270
+ testarchive = Stud::Temporary.pathname
271
+
272
+ FileUtils.touch([emptyfile])
268
273
 
269
274
  # Prefer tar that supports more of the features we want, stop if we find tar of our dreams
270
275
  best="tar"
@@ -276,7 +281,7 @@ module FPM::Util
276
281
  opts=[]
277
282
  score=0
278
283
  ["--sort=name", "--mtime=@0"].each do |opt|
279
- system("#{tar} #{opt} -cf fpm-dummy.tar.tmp fpm-dummy.tmp > /dev/null 2>&1")
284
+ system("#{tar} #{opt} -cf #{testarchive} #{emptyfile} > /dev/null 2>&1")
280
285
  if $?.exitstatus == 0
281
286
  opts << opt
282
287
  score += 1
@@ -292,10 +297,9 @@ module FPM::Util
292
297
  end
293
298
  end
294
299
  @@tar_cmd = best
300
+ FileUtils.rm_f([testarchive, emptyfile])
301
+
295
302
  return @@tar_cmd
296
- ensure
297
- # Clean up
298
- FileUtils.rm_f(["fpm-dummy.tar.tmp", "fpm-dummy.tmp"])
299
303
  end # def tar_cmd
300
304
 
301
305
  # Return whether the command returned by tar_cmd can create deterministic archives
@@ -328,7 +332,15 @@ module FPM::Util
328
332
 
329
333
 
330
334
  def copy_entry(src, dst, preserve=false, remove_destination=false)
331
- case File.ftype(src)
335
+ st = File.lstat(src)
336
+
337
+ filetype = if st.ftype == "file" && st.nlink > 1
338
+ "hardlink"
339
+ else
340
+ st.ftype
341
+ end
342
+
343
+ case filetype
332
344
  when 'fifo'
333
345
  if File.respond_to?(:mkfifo)
334
346
  File.mkfifo(dst)
@@ -346,18 +358,23 @@ module FPM::Util
346
358
  raise UnsupportedSpecialFile.new("File is device which fpm doesn't know how to copy (#{File.ftype(src)}): #{src}")
347
359
  when 'directory'
348
360
  FileUtils.mkdir(dst) unless File.exist? dst
349
- else
350
- # if the file with the same dev and inode has been copied already -
361
+ when 'hardlink'
362
+ # Handle hardlinks
363
+ # if the file with the same dev and inode has been copied already.
351
364
  # hard link it's copy to `dst`, otherwise make an actual copy
352
- st = File.lstat(src)
353
365
  known_entry = copied_entries[[st.dev, st.ino]]
354
366
  if known_entry
355
367
  FileUtils.ln(known_entry, dst)
368
+ logger.debug("Copying hardlink", :src => src, :dst => dst, :link => known_entry)
356
369
  else
357
370
  FileUtils.copy_entry(src, dst, preserve, false,
358
371
  remove_destination)
359
372
  copied_entries[[st.dev, st.ino]] = dst
360
373
  end
374
+ else
375
+ # Normal file, just copy it.
376
+ FileUtils.copy_entry(src, dst, preserve, false,
377
+ remove_destination)
361
378
  end # else...
362
379
  end # def copy_entry
363
380
 
data/lib/fpm/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module FPM
2
- VERSION = "1.15.1"
2
+ VERSION = "1.17.0"
3
3
  end
data/templates/rpm.erb CHANGED
@@ -260,4 +260,4 @@ fi
260
260
  <% end -%>
261
261
 
262
262
  %changelog
263
- <%= attributes[:rpm_changelog] %>
263
+ <%= changelog %>
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fpm
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.15.1
4
+ version: 1.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Sissel
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2023-02-01 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: cabin
@@ -16,14 +15,14 @@ dependencies:
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: 0.6.0
18
+ version: 0.9.1
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - ">="
25
24
  - !ruby/object:Gem::Version
26
- version: 0.6.0
25
+ version: 0.9.1
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: backports
29
28
  requirement: !ruby/object:Gem::Requirement
@@ -56,14 +55,14 @@ dependencies:
56
55
  name: clamp
57
56
  requirement: !ruby/object:Gem::Requirement
58
57
  requirements:
59
- - - "~>"
58
+ - - ">="
60
59
  - !ruby/object:Gem::Version
61
60
  version: 1.0.0
62
61
  type: :runtime
63
62
  prerelease: false
64
63
  version_requirements: !ruby/object:Gem::Requirement
65
64
  requirements:
66
- - - "~>"
65
+ - - ">="
67
66
  - !ruby/object:Gem::Version
68
67
  version: 1.0.0
69
68
  - !ruby/object:Gem::Dependency
@@ -114,14 +113,14 @@ dependencies:
114
113
  requirements:
115
114
  - - "~>"
116
115
  - !ruby/object:Gem::Version
117
- version: 3.0.0
116
+ version: 3.13.0
118
117
  type: :development
119
118
  prerelease: false
120
119
  version_requirements: !ruby/object:Gem::Requirement
121
120
  requirements:
122
121
  - - "~>"
123
122
  - !ruby/object:Gem::Version
124
- version: 3.0.0
123
+ version: 3.13.0
125
124
  - !ruby/object:Gem::Dependency
126
125
  name: insist
127
126
  requirement: !ruby/object:Gem::Requirement
@@ -199,6 +198,7 @@ files:
199
198
  - lib/fpm/package/puppet.rb
200
199
  - lib/fpm/package/pyfpm/__init__.py
201
200
  - lib/fpm/package/pyfpm/get_metadata.py
201
+ - lib/fpm/package/pyfpm/parse_requires.py
202
202
  - lib/fpm/package/python.rb
203
203
  - lib/fpm/package/rpm.rb
204
204
  - lib/fpm/package/sh.rb
@@ -238,7 +238,6 @@ homepage: https://github.com/jordansissel/fpm
238
238
  licenses:
239
239
  - MIT-like
240
240
  metadata: {}
241
- post_install_message:
242
241
  rdoc_options: []
243
242
  require_paths:
244
243
  - lib
@@ -254,8 +253,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
254
253
  - !ruby/object:Gem::Version
255
254
  version: '0'
256
255
  requirements: []
257
- rubygems_version: 3.4.1
258
- signing_key:
256
+ rubygems_version: 3.6.7
259
257
  specification_version: 4
260
258
  summary: fpm - package building and mangling
261
259
  test_files: []