fpm 1.6.1 → 1.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CONTRIBUTORS CHANGED
@@ -20,6 +20,8 @@ llasram
20
20
  sbuss
21
21
  Brett Gailey (github: dnbert)
22
22
  Daniel Haskin (github: djhaskin987)
23
+ Richard Grainger (github: liger1978)
24
+ seph (github: directionless)
23
25
 
24
26
  If you have contributed (bug reports, feature requests, help in IRC, blog
25
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-2016 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/bin/fpm CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "rubygems"
4
3
  $: << File.join(File.dirname(__FILE__), "..", "lib")
5
4
  require "fpm"
6
5
  require "fpm/command"
data/lib/fpm/command.rb CHANGED
@@ -45,13 +45,13 @@ class FPM::Command < Clamp::Command
45
45
  return lines.join("\n")
46
46
  end # def help
47
47
 
48
- option "-t", "OUTPUT_TYPE",
48
+ option ["-t", "--output-type"], "OUTPUT_TYPE",
49
49
  "the type of package you want to create (deb, rpm, solaris, etc)",
50
50
  :attribute_name => :output_type
51
- option "-s", "INPUT_TYPE",
51
+ option ["-s", "--input-type"], "INPUT_TYPE",
52
52
  "the package type to use as input (gem, rpm, python, etc)",
53
53
  :attribute_name => :input_type
54
- option "-C", "CHDIR",
54
+ option ["-C", "--chdir"], "CHDIR",
55
55
  "Change directory to here before searching for files",
56
56
  :attribute_name => :chdir
57
57
  option "--prefix", "PREFIX",
@@ -233,6 +233,20 @@ class FPM::Command < Clamp::Command
233
233
  "copying, downloading, etc. Roughly any scratch space fpm needs to build " \
234
234
  "your package.", :default => Dir.tmpdir
235
235
 
236
+ option "--source-date-epoch-from-changelog", :flag,
237
+ "Use release date from changelog as timestamp on generated files to reduce nondeterminism. " \
238
+ "Experimental; only implemented for gem so far. ",
239
+ :default => false
240
+
241
+ option "--source-date-epoch-default", "SOURCE_DATE_EPOCH_DEFAULT",
242
+ "If no release date otherwise specified, use this value as timestamp on generated files to reduce nondeterminism. " \
243
+ "Reproducible build environments such as dpkg-dev and rpmbuild set this via envionment variable SOURCE_DATE_EPOCH " \
244
+ "variable to the integer unix timestamp to use in generated archives, " \
245
+ "and expect tools like fpm to use it as a hint to avoid nondeterministic output. " \
246
+ "This is a Unix timestamp, i.e. number of seconds since 1 Jan 1970 UTC. " \
247
+ "See https://reproducible-builds.org/specs/source-date-epoch ",
248
+ :environment_variable => "SOURCE_DATE_EPOCH"
249
+
236
250
  parameter "[ARGS] ...",
237
251
  "Inputs to the source package type. For the 'dir' type, this is the files" \
238
252
  " and directories you want to include in the package. For others, like " \
@@ -256,12 +270,6 @@ class FPM::Command < Clamp::Command
256
270
 
257
271
  # Execute this command. See Clamp::Command#execute and Clamp's documentation
258
272
  def execute
259
- # Short-circuit if someone simply runs `fpm --version`
260
- if ARGV == [ "--version" ]
261
- puts FPM::VERSION
262
- return 0
263
- end
264
-
265
273
  logger.level = :warn
266
274
  logger.level = :info if verbose? # --verbose
267
275
  logger.level = :debug if debug? # --debug
@@ -269,7 +277,6 @@ class FPM::Command < Clamp::Command
269
277
  logger.level = log_level.to_sym
270
278
  end
271
279
 
272
-
273
280
  if (stray_flags = args.grep(/^-/); stray_flags.any?)
274
281
  logger.warn("All flags should be before the first argument " \
275
282
  "(stray flags found: #{stray_flags}")
@@ -514,9 +521,16 @@ class FPM::Command < Clamp::Command
514
521
  end
515
522
  end # def execute
516
523
 
517
- def run(*run_args)
524
+ def run(run_args)
518
525
  logger.subscribe(STDOUT)
519
526
 
527
+ # Short circuit for a `fpm --version` or `fpm -v` short invocation that
528
+ # is the user asking us for the version of fpm.
529
+ if run_args == [ "-v" ] || run_args == [ "--version" ]
530
+ puts FPM::VERSION
531
+ return 0
532
+ end
533
+
520
534
  # fpm initialization files, note the order of the following array is
521
535
  # important, try .fpm in users home directory first and then the current
522
536
  # directory
@@ -557,7 +571,7 @@ class FPM::Command < Clamp::Command
557
571
 
558
572
  ARGV.unshift(*flags)
559
573
  ARGV.push(*args)
560
- super(*run_args)
574
+ super(run_args)
561
575
  rescue FPM::Package::InvalidArgument => e
562
576
  logger.error("Invalid package argument: #{e}")
563
577
  return 1
@@ -3,12 +3,12 @@ require "fpm/namespace"
3
3
  require "fpm/package"
4
4
  require "fpm/errors"
5
5
  require "fpm/util"
6
- require "backports"
6
+ require "backports/latest"
7
7
  require "fileutils"
8
8
  require "digest"
9
9
  require 'digest/sha1'
10
10
 
11
- # Support for debian packages (.deb files)
11
+ # Support for Alpine packages (.apk files)
12
12
  #
13
13
  # This class supports both input and output of packages.
14
14
  class FPM::Package::APK< FPM::Package
@@ -144,9 +144,9 @@ class FPM::Package::APK< FPM::Package
144
144
  scripts = {}
145
145
 
146
146
  scripts = register_script('post-install', :after_install, scripts)
147
- scripts = register_script('post-install', :before_install, scripts)
148
- scripts = register_script('post-install', :before_upgrade, scripts)
149
- scripts = register_script('post-install', :after_upgrade, scripts)
147
+ scripts = register_script('pre-install', :before_install, scripts)
148
+ scripts = register_script('pre-upgrade', :before_upgrade, scripts)
149
+ scripts = register_script('post-upgrade', :after_upgrade, scripts)
150
150
  scripts = register_script('pre-deinstall', :before_remove, scripts)
151
151
  scripts = register_script('post-deinstall', :after_remove, scripts)
152
152
 
@@ -238,7 +238,7 @@ class FPM::Package::APK< FPM::Package
238
238
  record_length = determine_record_length(record_length)
239
239
 
240
240
  until(data.length == record_length)
241
- data += file.read(TAR_CHUNK_SIZE)
241
+ data << file.read(TAR_CHUNK_SIZE)
242
242
  end
243
243
 
244
244
  # Clear ownership fields
@@ -3,6 +3,7 @@ require "fpm/package"
3
3
  require "fpm/util"
4
4
  require "fileutils"
5
5
  require "find"
6
+ require "pathname"
6
7
 
7
8
  class FPM::Package::CPAN < FPM::Package
8
9
  # Flags '--foo' will be accessable as attributes[:npm_foo]
@@ -24,6 +25,9 @@ class FPM::Package::CPAN < FPM::Package
24
25
  option "--test", :flag,
25
26
  "Run the tests before packaging?", :default => true
26
27
 
28
+ option "--verbose", :flag,
29
+ "Produce verbose output from cpanm?", :default => false
30
+
27
31
  option "--perl-lib-path", "PERL_LIB_PATH",
28
32
  "Path of target Perl Libraries"
29
33
 
@@ -48,6 +52,7 @@ class FPM::Package::CPAN < FPM::Package
48
52
 
49
53
  if File.exist?(package)
50
54
  moduledir = package
55
+ result = {}
51
56
  else
52
57
  result = search(package)
53
58
  tarball = download(result, version)
@@ -97,6 +102,12 @@ class FPM::Package::CPAN < FPM::Package
97
102
  self.name = fix_name(metadata["name"])
98
103
  end
99
104
 
105
+ unless metadata["module"].nil?
106
+ metadata["module"].each do |m|
107
+ self.provides << cap_name(m["name"]) + " = #{self.version}"
108
+ end
109
+ end
110
+
100
111
  # author is not always set or it may be a string instead of an array
101
112
  self.vendor = case metadata["author"]
102
113
  when String; metadata["author"]
@@ -129,24 +140,36 @@ class FPM::Package::CPAN < FPM::Package
129
140
  cpanm_flags += ["--mirror", "#{attributes[:cpan_mirror]}"] if !attributes[:cpan_mirror].nil?
130
141
  cpanm_flags += ["--mirror-only"] if attributes[:cpan_mirror_only?] && !attributes[:cpan_mirror].nil?
131
142
  cpanm_flags += ["--force"] if attributes[:cpan_cpanm_force?]
143
+ cpanm_flags += ["--verbose"] if attributes[:cpan_verbose?]
132
144
 
133
145
  safesystem(attributes[:cpan_cpanm_bin], *cpanm_flags)
134
146
 
135
147
  if !attributes[:no_auto_depends?]
136
- unless metadata["requires"].nil?
137
- metadata["requires"].each do |dep_name, version|
148
+ found_dependencies = {}
149
+ if metadata["requires"]
150
+ found_dependencies.merge!(metadata["requires"])
151
+ end
152
+ if metadata["prereqs"]
153
+ if metadata["prereqs"]["runtime"]
154
+ if metadata["prereqs"]["runtime"]["requires"]
155
+ found_dependencies.merge!(metadata["prereqs"]["runtime"]["requires"])
156
+ end
157
+ end
158
+ end
159
+ unless found_dependencies.empty?
160
+ found_dependencies.each do |dep_name, version|
138
161
  # Special case for representing perl core as a version.
139
162
  if dep_name == "perl"
163
+ m = version.to_s.match(/^(\d)\.(\d{3})(\d{3})$/)
164
+ if m
165
+ version = m[1] + '.' + m[2].sub(/^0*/, '') + '.' + m[3].sub(/^0*/, '')
166
+ end
140
167
  self.dependencies << "#{dep_name} >= #{version}"
141
168
  next
142
169
  end
143
170
  dep = search(dep_name)
144
171
 
145
- if dep.include?("distribution")
146
- name = fix_name(dep["distribution"])
147
- else
148
- name = fix_name(dep_name)
149
- end
172
+ name = cap_name(dep_name)
150
173
 
151
174
  if version.to_s == "0"
152
175
  # Assume 'Foo = 0' means any version?
@@ -154,12 +177,14 @@ class FPM::Package::CPAN < FPM::Package
154
177
  else
155
178
  # The 'version' string can be something complex like:
156
179
  # ">= 0, != 1.0, != 1.2"
180
+ # If it is not specified explicitly, require the given
181
+ # version or newer, as that is all CPAN itself enforces
157
182
  if version.is_a?(String)
158
183
  version.split(/\s*,\s*/).each do |v|
159
184
  if v =~ /\s*[><=]/
160
185
  self.dependencies << "#{name} #{v}"
161
186
  else
162
- self.dependencies << "#{name} = #{v}"
187
+ self.dependencies << "#{name} >= #{v}"
163
188
  end
164
189
  end
165
190
  else
@@ -220,11 +245,7 @@ class FPM::Package::CPAN < FPM::Package
220
245
  # Empty install_base to avoid local::lib being used.
221
246
  "INSTALL_BASE=")
222
247
  end
223
- if attributes[:cpan_test?]
224
- make = [ "env", "PERL5LIB=#{build_path("cpan/lib/perl5")}", "make" ]
225
- else
226
- make = [ "make" ]
227
- end
248
+ make = [ "env", "PERL5LIB=#{build_path("cpan/lib/perl5")}", "make" ]
228
249
  safesystem(*make)
229
250
  safesystem(*(make + ["test"])) if attributes[:cpan_test?]
230
251
  safesystem(*(make + ["DESTDIR=#{staging_path}", "install"]))
@@ -246,6 +267,21 @@ class FPM::Package::CPAN < FPM::Package
246
267
  :path => path.gsub(staging_path, ""))
247
268
  File.unlink(path)
248
269
  end
270
+
271
+ # Remove useless .packlist files and their empty parent folders
272
+ # https://github.com/jordansissel/fpm/issues/1179
273
+ ::Dir.glob(File.join(staging_path, glob_prefix, "**/.packlist")).each do |path|
274
+ logger.debug("Removing useless file.",
275
+ :path => path.gsub(staging_path, ""))
276
+ File.unlink(path)
277
+ Pathname.new(path).parent.ascend do |parent|
278
+ if ::Dir.entries(parent).sort == ['.', '..'].sort
279
+ FileUtils.rmdir parent
280
+ else
281
+ break
282
+ end
283
+ end
284
+ end
249
285
  end
250
286
 
251
287
 
@@ -281,38 +317,35 @@ class FPM::Package::CPAN < FPM::Package
281
317
  :distribution => distribution,
282
318
  :version => cpan_version)
283
319
 
284
- # default to latest versionunless we specify one
320
+ # default to latest version unless we specify one
285
321
  if cpan_version.nil?
286
- self.version = metadata["version"]
322
+ self.version = "#{metadata["version"]}"
287
323
  else
288
- if metadata["version"] =~ /^v\d/
289
- self.version = "v#{cpan_version}"
290
- else
291
- self.version = cpan_version
292
- end
324
+ self.version = "#{cpan_version}"
293
325
  end
294
326
 
295
- metacpan_release_url = "http://api.metacpan.org/v0/release/#{author}/#{distribution}-#{self.version}"
327
+ # Search metacpan to get download URL for this version of the module
328
+ metacpan_search_url = "https://fastapi.metacpan.org/v1/release/_search"
329
+ metacpan_search_query = '{"fields":["download_url"],"filter":{"term":{"name":"' + "#{distribution}-#{self.version}" + '"}}}'
296
330
  begin
297
- release_response = httpfetch(metacpan_release_url)
331
+ search_response = httppost(metacpan_search_url,metacpan_search_query)
298
332
  rescue Net::HTTPServerException => e
299
333
  logger.error("metacpan release query failed.", :error => e.message,
300
- :url => metacpan_release_url)
334
+ :url => metacpan_search_url)
301
335
  raise FPM::InvalidPackageConfiguration, "metacpan release query failed"
302
336
  end
303
337
 
304
- data = release_response.body
338
+ data = search_response.body
305
339
  release_metadata = JSON.parse(data)
306
- archive = release_metadata["archive"]
307
340
 
308
- # should probably be basepathed from the url
309
- tarball = File.basename(archive)
341
+ download_url = release_metadata['hits']['hits'][0]['fields']['download_url']
342
+ download_path = URI.parse(download_url).path
343
+ tarball = File.basename(download_path)
310
344
 
311
345
  url_base = "http://www.cpan.org/"
312
346
  url_base = "#{attributes[:cpan_mirror]}" if !attributes[:cpan_mirror].nil?
313
347
 
314
- #url = "http://www.cpan.org/CPAN/authors/id/#{author[0,1]}/#{author[0,2]}/#{author}/#{tarball}"
315
- url = "#{url_base}/authors/id/#{author[0,1]}/#{author[0,2]}/#{author}/#{archive}"
348
+ url = "#{url_base}#{download_path}"
316
349
  logger.debug("Fetching perl module", :url => url)
317
350
 
318
351
  begin
@@ -333,7 +366,7 @@ class FPM::Package::CPAN < FPM::Package
333
366
 
334
367
  def search(package)
335
368
  logger.info("Asking metacpan about a module", :module => package)
336
- metacpan_url = "http://api.metacpan.org/v0/module/" + package
369
+ metacpan_url = "https://fastapi.metacpan.org/v1/module/" + package
337
370
  begin
338
371
  response = httpfetch(metacpan_url)
339
372
  rescue Net::HTTPServerException => e
@@ -351,6 +384,10 @@ class FPM::Package::CPAN < FPM::Package
351
384
  return metadata
352
385
  end # def metadata
353
386
 
387
+ def cap_name(name)
388
+ return "perl(" + name.gsub("-", "::") + ")"
389
+ end # def cap_name
390
+
354
391
  def fix_name(name)
355
392
  case name
356
393
  when "perl"; return "perl"
@@ -366,6 +403,7 @@ class FPM::Package::CPAN < FPM::Package
366
403
  else
367
404
  http = Net::HTTP.new(uri.host, uri.port)
368
405
  end
406
+ http.use_ssl = uri.scheme == 'https'
369
407
  response = http.request(Net::HTTP::Get.new(uri.request_uri))
370
408
  case response
371
409
  when Net::HTTPSuccess; return response
@@ -374,5 +412,22 @@ class FPM::Package::CPAN < FPM::Package
374
412
  end
375
413
  end
376
414
 
415
+ def httppost(url, body)
416
+ uri = URI.parse(url)
417
+ if ENV['http_proxy']
418
+ proxy = URI.parse(ENV['http_proxy'])
419
+ http = Net::HTTP.Proxy(proxy.host,proxy.port,proxy.user,proxy.password).new(uri.host, uri.port)
420
+ else
421
+ http = Net::HTTP.new(uri.host, uri.port)
422
+ end
423
+ http.use_ssl = uri.scheme == 'https'
424
+ response = http.post(uri.request_uri, body)
425
+ case response
426
+ when Net::HTTPSuccess; return response
427
+ when Net::HTTPRedirection; return httppost(response["location"])
428
+ else; response.error!
429
+ end
430
+ end
431
+
377
432
  public(:input)
378
433
  end # class FPM::Package::NPM