fpm-aeppert 1.6.2 → 1.11.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.
@@ -1,5 +1,5 @@
1
1
  require "fpm/package"
2
- require "backports"
2
+ require "backports/latest"
3
3
  require "fileutils"
4
4
  require "find"
5
5
  require "arr-pm/file" # gem 'arr-pm'
@@ -24,9 +24,10 @@ class FPM::Package::RPM < FPM::Package
24
24
 
25
25
  COMPRESSION_MAP = {
26
26
  "none" => "w0.gzdio",
27
- "xz" => "w9.xzdio",
28
- "gzip" => "w9.gzdio",
29
- "bzip2" => "w9.bzdio"
27
+ "xz" => ".xzdio",
28
+ "xzmt" => "T.xzdio",
29
+ "gzip" => ".gzdio",
30
+ "bzip2" => ".bzdio"
30
31
  } unless defined?(COMPRESSION_MAP)
31
32
 
32
33
  option "--use-file-permissions", :flag,
@@ -67,6 +68,15 @@ class FPM::Package::RPM < FPM::Package
67
68
  value.downcase
68
69
  end
69
70
 
71
+ option "--compression-level", "[0-9]", "Select a compression level. 0 is store-only. 9 is max compression.",
72
+ :default => "9" do |value|
73
+ valint = value.to_i
74
+ unless value =~ /^\d$/ && valint >= 0 && valint <= 9
75
+ raise "Invalid compression level '#{value}'. Valid values are integers between 0 and 9 inclusive."
76
+ end
77
+ valint
78
+ end
79
+
70
80
  option "--compression", COMPRESSION_MAP.keys.join("|"),
71
81
  "Select a compression method. gzip works on the most platforms.",
72
82
  :default => "gzip" do |value|
@@ -141,6 +151,10 @@ class FPM::Package::RPM < FPM::Package
141
151
  "names in rpm requires instead of the redhat style " \
142
152
  "rubygem(foo).", :default => false
143
153
 
154
+ option "--macro-expansion", :flag,
155
+ "install-time macro expansion in %pre %post %preun %postun scripts " \
156
+ "(see: https://rpm.org/user_doc/scriptlet_expansion.html)", :default => false
157
+
144
158
  option "--verifyscript", "FILE",
145
159
  "a script to be run on verification" do |val|
146
160
  File.expand_path(val) # Get the full path to the script
@@ -472,6 +486,22 @@ class FPM::Package::RPM < FPM::Package
472
486
  self.directories = alldirs
473
487
  end
474
488
 
489
+ # include external config files
490
+ (attributes[:config_files] or []).each do |conf|
491
+ dest_conf = File.join(staging_path, conf)
492
+
493
+ if File.exist?(dest_conf)
494
+ logger.debug("Using --config-file from staging area", :path => conf)
495
+ elsif File.exist?(conf)
496
+ logger.info("Copying --config-file from local path", :path => conf)
497
+ FileUtils.mkdir_p(File.dirname(dest_conf))
498
+ FileUtils.cp_r conf, dest_conf
499
+ else
500
+ logger.error("Failed to find given --config-file", :path => conf)
501
+ raise "Could not find config file '#{conf}' in staging area or on host. This can happen if you specify `--config-file '#{conf}'` but this file does not exist in the source package and also does not exist in filesystem."
502
+ end
503
+ end
504
+
475
505
  # scan all conf file paths for files and add them
476
506
  allconfigs = []
477
507
  self.config_files.each do |path|
@@ -499,10 +529,11 @@ class FPM::Package::RPM < FPM::Package
499
529
  end
500
530
 
501
531
  # copy all files from staging to BUILD dir
532
+ # [#1538] Be sure to preserve the original timestamps.
502
533
  Find.find(staging_path) do |path|
503
534
  src = path.gsub(/^#{staging_path}/, '')
504
535
  dst = File.join(build_path, build_sub_dir, src)
505
- copy_entry(path, dst)
536
+ copy_entry(path, dst, preserve=true)
506
537
  end
507
538
 
508
539
  rpmspec = template("rpm.erb").result(binding)
@@ -537,7 +568,7 @@ class FPM::Package::RPM < FPM::Package
537
568
 
538
569
  def summary
539
570
  if !attributes[:rpm_summary]
540
- return @description.split("\n").first || "_"
571
+ return @description.split("\n").find { |line| !line.strip.empty? } || "_"
541
572
  end
542
573
 
543
574
  return attributes[:rpm_summary]
@@ -580,7 +611,12 @@ class FPM::Package::RPM < FPM::Package
580
611
  end # def to_s
581
612
 
582
613
  def payload_compression
583
- return COMPRESSION_MAP[attributes[:rpm_compression]]
614
+ if attributes[:rpm_compression] == 'none'
615
+ # when 'none' ignore any compression level and return w0.gzdio
616
+ return COMPRESSION_MAP[attributes[:rpm_compression]]
617
+ else
618
+ return "w#{attributes[:rpm_compression_level]}" + COMPRESSION_MAP[attributes[:rpm_compression]]
619
+ end
584
620
  end # def payload_compression
585
621
 
586
622
  def digest_algorithm
@@ -3,7 +3,7 @@ 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
 
@@ -0,0 +1,130 @@
1
+ require "yaml"
2
+
3
+ require "fpm/package"
4
+ require "fpm/util"
5
+ require "fileutils"
6
+ require "fpm/package/dir"
7
+
8
+ # Support for snaps (.snap files).
9
+ #
10
+ # This supports the input and output of snaps.
11
+ class FPM::Package::Snap < FPM::Package
12
+
13
+ option "--yaml", "FILEPATH",
14
+ "Custom version of the snap.yaml file." do | snap_yaml |
15
+ File.expand_path(snap_yaml)
16
+ end
17
+
18
+ option "--confinement", "CONFINEMENT",
19
+ "Type of confinement to use for this snap.",
20
+ default: "devmode" do | confinement |
21
+ if ['strict', 'devmode', 'classic'].include? confinement
22
+ confinement
23
+ else
24
+ raise "Unsupported confinement type '#{confinement}'"
25
+ end
26
+ end
27
+
28
+ option "--grade", "GRADE", "Grade of this snap.",
29
+ default: "devel" do | grade |
30
+ if ['stable', 'devel'].include? grade
31
+ grade
32
+ else
33
+ raise "Unsupported grade type '#{grade}'"
34
+ end
35
+ end
36
+
37
+ # Input a snap
38
+ def input(input_snap)
39
+ extract_snap_to_staging input_snap
40
+ extract_snap_metadata_from_staging
41
+ end # def input
42
+
43
+ # Output a snap.
44
+ def output(output_snap)
45
+ output_check(output_snap)
46
+
47
+ write_snap_yaml
48
+
49
+ # Create the snap from the staging path
50
+ safesystem("mksquashfs", staging_path, output_snap, "-noappend", "-comp",
51
+ "xz", "-no-xattrs", "-no-fragments", "-all-root")
52
+ end # def output
53
+
54
+ def to_s(format=nil)
55
+ # Default format if nil
56
+ # name_version_arch.snap
57
+ return super(format.nil? ? "NAME_FULLVERSION_ARCH.EXTENSION" : format)
58
+ end # def to_s
59
+
60
+ private
61
+
62
+ def extract_snap_to_staging(snap_path)
63
+ safesystem("unsquashfs", "-f", "-d", staging_path, snap_path)
64
+ end
65
+
66
+ def extract_snap_metadata_from_staging
67
+ metadata = YAML.safe_load(File.read(
68
+ staging_path(File.join("meta", "snap.yaml"))))
69
+
70
+ self.name = metadata["name"]
71
+ self.version = metadata["version"]
72
+ self.description = metadata["summary"] + "\n" + metadata["description"]
73
+ self.architecture = metadata["architectures"][0]
74
+ self.attributes[:snap_confinement] = metadata["confinement"]
75
+ self.attributes[:snap_grade] = metadata["grade"]
76
+
77
+ if metadata["apps"].nil?
78
+ attributes[:snap_apps] = []
79
+ else
80
+ attributes[:snap_apps] = metadata["apps"]
81
+ end
82
+
83
+ if metadata["hooks"].nil?
84
+ attributes[:snap_hooks] = []
85
+ else
86
+ attributes[:snap_hooks] = metadata["hooks"]
87
+ end
88
+ end
89
+
90
+ def write_snap_yaml
91
+ # Write the snap.yaml
92
+ if attributes[:snap_yaml]
93
+ logger.debug("Using '#{attributes[:snap_yaml]}' as the snap.yaml")
94
+ yaml_data = File.read(attributes[:snap_yaml])
95
+ else
96
+ summary, *remainder = (self.description or "no summary given").split("\n")
97
+ description = "no description given"
98
+ if remainder.any?
99
+ description = remainder.join("\n")
100
+ end
101
+
102
+ yaml_data = {
103
+ "name" => self.name,
104
+ "version" => self.version,
105
+ "summary" => summary,
106
+ "description" => description,
107
+ "architectures" => [self.architecture],
108
+ "confinement" => self.attributes[:snap_confinement],
109
+ "grade" => self.attributes[:snap_grade],
110
+ }
111
+
112
+ unless attributes[:snap_apps].nil? or attributes[:snap_apps].empty?
113
+ yaml_data["apps"] = attributes[:snap_apps]
114
+ end
115
+
116
+ unless attributes[:snap_hooks].nil? or attributes[:snap_hooks].empty?
117
+ yaml_data["hooks"] = attributes[:snap_hooks]
118
+ end
119
+
120
+ yaml_data = yaml_data.to_yaml
121
+ end
122
+
123
+ FileUtils.mkdir_p(staging_path("meta"))
124
+ snap_yaml_path = staging_path(File.join("meta", "snap.yaml"))
125
+ logger.debug("Writing snap.yaml", :path => snap_yaml_path)
126
+ File.write(snap_yaml_path, yaml_data)
127
+ File.chmod(0644, snap_yaml_path)
128
+ edit_file(snap_yaml_path) if attributes[:edit?]
129
+ end # def write_snap_yaml
130
+ end # class FPM::Package::Snap
@@ -1,4 +1,4 @@
1
- require "backports" # gem backports
1
+ require "backports/latest" # gem backports
2
2
  require "fpm/package"
3
3
  require "fpm/util"
4
4
  require "fileutils"
@@ -50,15 +50,7 @@ class FPM::Package::Tar < FPM::Package
50
50
  output_check(output_path)
51
51
 
52
52
  # Write the scripts, too.
53
- scripts_path = File.join(staging_path, ".scripts")
54
- ::Dir.mkdir(scripts_path)
55
- [:before_install, :after_install, :before_remove, :after_remove].each do |name|
56
- next unless script?(name)
57
- out = File.join(scripts_path, name.to_s)
58
- logger.debug("Writing script", :source => name, :target => out)
59
- File.write(out, script(name))
60
- File.chmod(0755, out)
61
- end
53
+ write_scripts
62
54
 
63
55
  # Unpack the tarball to the staging path
64
56
  args = ["-cf", output_path, "-C", staging_path]
@@ -15,8 +15,11 @@ class FPM::Package::Virtualenv < FPM::Package
15
15
  option "--package-name-prefix", "PREFIX", "Name to prefix the package " \
16
16
  "name with.", :default => "virtualenv"
17
17
 
18
- option "--install-location", "DIRECTORY", "Location to which to " \
19
- "install the virtualenv by default.", :default => "/usr/share/python" do |path|
18
+ option "--install-location", "DIRECTORY", "DEPRECATED: Use --prefix instead." \
19
+ " Location to which to install the virtualenv by default.",
20
+ :default => "/usr/share/python" do |path|
21
+ logger.warn("Using deprecated flag: --install-location. Please use " \
22
+ "--prefix instead.")
20
23
  File.expand_path(path)
21
24
  end
22
25
 
@@ -30,6 +33,19 @@ class FPM::Package::Virtualenv < FPM::Package
30
33
  :multivalued => true, :attribute_name => :virtualenv_pypi_extra_index_urls,
31
34
  :default => nil
32
35
 
36
+ option "--setup-install", :flag, "After building virtualenv run setup.py install "\
37
+ "useful when building a virtualenv for packages and including their requirements from "
38
+ "requirements.txt"
39
+
40
+ option "--system-site-packages", :flag, "Give the virtual environment access to the "\
41
+ "global site-packages"
42
+
43
+ option "--find-links", "PIP_FIND_LINKS", "If a url or path to an html file, then parse for "\
44
+ "links to archives. If a local path or file:// url that's a directory, then look "\
45
+ "for archives in the directory listing.",
46
+ :multivalued => true, :attribute_name => :virtualenv_find_links_urls,
47
+ :default => nil
48
+
33
49
  private
34
50
 
35
51
  # Input a package.
@@ -69,23 +85,33 @@ class FPM::Package::Virtualenv < FPM::Package
69
85
  self.name].join("-")
70
86
  end
71
87
 
88
+ # prefix wins over previous virtual_install_location behaviour
72
89
  virtualenv_folder =
73
- File.join(installdir,
74
- virtualenv_name)
90
+ if self.attributes[:prefix]
91
+ self.attributes[:prefix]
92
+ else
93
+ File.join(installdir,
94
+ virtualenv_name)
95
+ end
75
96
 
76
97
  virtualenv_build_folder = build_path(virtualenv_folder)
77
98
 
78
99
  ::FileUtils.mkdir_p(virtualenv_build_folder)
79
100
 
80
- safesystem("virtualenv", virtualenv_build_folder)
101
+ if self.attributes[:virtualenv_system_site_packages?]
102
+ logger.info("Creating virtualenv with --system-site-packages")
103
+ safesystem("virtualenv", "--system-site-packages", virtualenv_build_folder)
104
+ else
105
+ safesystem("virtualenv", virtualenv_build_folder)
106
+ end
107
+
81
108
  pip_exe = File.join(virtualenv_build_folder, "bin", "pip")
82
109
  python_exe = File.join(virtualenv_build_folder, "bin", "python")
83
110
 
84
111
  # Why is this hack here? It looks important, so I'll keep it in.
85
- safesystem(pip_exe, "install", "-U", "-i",
112
+ safesystem(python_exe, pip_exe, "install", "-U", "-i",
86
113
  attributes[:virtualenv_pypi],
87
- "pip", "distribute")
88
- safesystem(pip_exe, "uninstall", "-y", "distribute")
114
+ "pip")
89
115
 
90
116
  extra_index_url_args = []
91
117
  if attributes[:virtualenv_pypi_extra_index_urls]
@@ -94,6 +120,13 @@ class FPM::Package::Virtualenv < FPM::Package
94
120
  end
95
121
  end
96
122
 
123
+ find_links_url_args = []
124
+ if attributes[:virtualenv_find_links_urls]
125
+ attributes[:virtualenv_find_links_urls].each do |links_url|
126
+ find_links_url_args << "--find-links" << links_url
127
+ end
128
+ end
129
+
97
130
  target_args = []
98
131
  if is_requirements_file
99
132
  target_args << "-r" << package
@@ -101,12 +134,19 @@ class FPM::Package::Virtualenv < FPM::Package
101
134
  target_args << package
102
135
  end
103
136
 
104
- pip_args = [pip_exe, "install", "-i", attributes[:virtualenv_pypi]] << extra_index_url_args << target_args
137
+ pip_args = [python_exe, pip_exe, "install", "-i", attributes[:virtualenv_pypi]] << extra_index_url_args << find_links_url_args << target_args
105
138
  safesystem(*pip_args.flatten)
106
139
 
140
+ if attributes[:virtualenv_setup_install?]
141
+ logger.info("Running PACKAGE setup.py")
142
+ setup_args = [python_exe, "setup.py", "install"]
143
+ safesystem(*setup_args.flatten)
144
+ end
145
+
107
146
  if ! is_requirements_file && package_version.nil?
108
- frozen = safesystemout(pip_exe, "freeze")
109
- package_version = frozen[/#{package}==[^=]+$/].split("==")[1].chomp!
147
+ frozen = safesystemout(python_exe, pip_exe, "freeze")
148
+ frozen_version = frozen[/#{package}==[^=]+$/]
149
+ package_version = frozen_version && frozen_version.split("==")[1].chomp!
110
150
  self.version ||= package_version
111
151
  end
112
152
 
@@ -135,7 +175,8 @@ class FPM::Package::Virtualenv < FPM::Package
135
175
  # use dir to set stuff up properly, mainly so I don't have to reimplement
136
176
  # the chdir/prefix stuff special for tar.
137
177
  dir = convert(FPM::Package::Dir)
138
-
178
+ # don't double prefix the files
179
+ dir.attributes[:prefix] = nil
139
180
  if attributes[:chdir]
140
181
  dir.attributes[:chdir] = File.join(build_path, attributes[:chdir])
141
182
  else
@@ -1,4 +1,4 @@
1
- require "backports" # gem backports
1
+ require "backports/latest" # gem backports
2
2
  require "fpm/package"
3
3
  require "fpm/util"
4
4
  require "fileutils"
@@ -36,28 +36,12 @@ class FPM::Package::Zip < FPM::Package
36
36
  dir.cleanup_build
37
37
  end # def input
38
38
 
39
- # Output a tarball.
40
- #
41
- # If the output path ends predictably (like in .tar.gz) it will try to obey
42
- # the compression type.
39
+ # Output a zipfile.
43
40
  def output(output_path)
44
41
  output_check(output_path)
45
-
46
- files = Find.find(staging_path).to_a
47
- safesystem("zip", output_path, *files)
48
- end # def output
49
-
50
- # Generate the proper tar flags based on the path name.
51
- def tar_compression_flag(path)
52
- case path
53
- when /\.tar\.bz2$/
54
- return "-j"
55
- when /\.tar\.gz$|\.tgz$/
56
- return "-z"
57
- when /\.tar\.xz$/
58
- return "-J"
59
- else
60
- return nil
42
+ realpath = Pathname.new(output_path).realdirpath.to_s
43
+ ::Dir.chdir(staging_path) do
44
+ safesystem("zip", "-9r", realpath, ".")
61
45
  end
62
- end # def tar_compression_flag
46
+ end # def output
63
47
  end # class FPM::Package::Tar
@@ -1,6 +1,7 @@
1
1
  require "fpm/namespace"
2
2
  require "childprocess"
3
3
  require "ffi"
4
+ require "fileutils"
4
5
 
5
6
  # Some utility functions
6
7
  module FPM::Util
@@ -190,9 +191,14 @@ module FPM::Util
190
191
  if args.size == 1
191
192
  args = [ default_shell, "-c", args[0] ]
192
193
  end
193
- program = args[0]
194
194
 
195
- exit_code = execmd(args)
195
+ if args[0].kind_of?(Hash)
196
+ env = args.shift()
197
+ exit_code = execmd(env, args)
198
+ else
199
+ exit_code = execmd(args)
200
+ end
201
+ program = args[0]
196
202
  success = (exit_code == 0)
197
203
 
198
204
  if !success
@@ -226,26 +232,90 @@ module FPM::Util
226
232
  return stdout_r_str
227
233
  end # def safesystemout
228
234
 
235
+ # Get an array containing the recommended 'ar' command for this platform
236
+ # and the recommended options to quickly create/append to an archive
237
+ # without timestamps or uids (if possible).
238
+ def ar_cmd
239
+ return @@ar_cmd if defined? @@ar_cmd
240
+
241
+ @@ar_cmd_deterministic = false
242
+
243
+ # FIXME: don't assume current directory writeable
244
+ FileUtils.touch(["fpm-dummy.tmp"])
245
+ ["ar", "gar"].each do |ar|
246
+ ["-qc", "-qcD"].each do |ar_create_opts|
247
+ FileUtils.rm_f(["fpm-dummy.ar.tmp"])
248
+ # Return this combination if it creates archives without uids or timestamps.
249
+ # Exitstatus will be nonzero if the archive can't be created,
250
+ # or its table of contents doesn't match the regular expression.
251
+ # Be extra-careful about locale and timezone when matching output.
252
+ 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")
253
+ if $?.exitstatus == 0
254
+ @@ar_cmd = [ar, ar_create_opts]
255
+ @@ar_cmd_deterministic = true
256
+ return @@ar_cmd
257
+ end
258
+ end
259
+ end
260
+ # If no combination of ar and options omits timestamps, fall back to default.
261
+ @@ar_cmd = ["ar", "-qc"]
262
+ return @@ar_cmd
263
+ ensure
264
+ # Clean up
265
+ FileUtils.rm_f(["fpm-dummy.ar.tmp", "fpm-dummy.tmp"])
266
+ end # def ar_cmd
267
+
268
+ # Return whether the command returned by ar_cmd can create deterministic archives
269
+ def ar_cmd_deterministic?
270
+ ar_cmd if not defined? @@ar_cmd_deterministic
271
+ return @@ar_cmd_deterministic
272
+ end
273
+
229
274
  # Get the recommended 'tar' command for this platform.
230
275
  def tar_cmd
231
- # Rely on gnu tar for solaris and OSX.
232
- case %x{uname -s}.chomp
233
- when "SunOS"
234
- return "gtar"
235
- when "Darwin"
236
- # Try running gnutar, it was renamed(??) in homebrew to 'gtar' at some point, I guess? I don't know.
237
- ["gnutar", "gtar"].each do |tar|
238
- system("#{tar} > /dev/null 2> /dev/null")
239
- return tar unless $?.exitstatus == 127
276
+ return @@tar_cmd if defined? @@tar_cmd
277
+
278
+ # FIXME: don't assume current directory writeable
279
+ FileUtils.touch(["fpm-dummy.tmp"])
280
+
281
+ # Prefer tar that supports more of the features we want, stop if we find tar of our dreams
282
+ best="tar"
283
+ bestscore=0
284
+ @@tar_cmd_deterministic = false
285
+ # GNU Tar, if not the default, is usually on the path as gtar, but
286
+ # Mac OS X 10.8 and earlier shipped it as /usr/bin/gnutar
287
+ ["tar", "gtar", "gnutar"].each do |tar|
288
+ opts=[]
289
+ score=0
290
+ ["--sort=name", "--mtime=@0"].each do |opt|
291
+ system("#{tar} #{opt} -cf fpm-dummy.tar.tmp fpm-dummy.tmp > /dev/null 2>&1")
292
+ if $?.exitstatus == 0
293
+ opts << opt
294
+ score += 1
295
+ end
296
+ end
297
+ if score > bestscore
298
+ best=tar
299
+ bestscore=score
300
+ if score == 2
301
+ @@tar_cmd_deterministic = true
302
+ break
303
+ end
240
304
  end
241
- when "FreeBSD"
242
- # use gnutar instead
243
- return "gtar"
244
- else
245
- return "tar"
246
305
  end
306
+ @@tar_cmd = best
307
+ return @@tar_cmd
308
+ ensure
309
+ # Clean up
310
+ FileUtils.rm_f(["fpm-dummy.tar.tmp", "fpm-dummy.tmp"])
247
311
  end # def tar_cmd
248
312
 
313
+ # Return whether the command returned by tar_cmd can create deterministic archives
314
+ def tar_cmd_supports_sort_names_and_set_mtime?
315
+ tar_cmd if not defined? @@tar_cmd_deterministic
316
+ return @@tar_cmd_deterministic
317
+ end
318
+
249
319
  # wrapper around mknod ffi calls
250
320
  def mknod_w(path, mode, dev)
251
321
  rc = -1
@@ -298,8 +368,8 @@ module FPM::Util
298
368
  if known_entry
299
369
  FileUtils.ln(known_entry, dst)
300
370
  else
301
- FileUtils.copy_entry(src, dst, preserve=preserve,
302
- remove_destination=remove_destination)
371
+ FileUtils.copy_entry(src, dst, preserve, false,
372
+ remove_destination)
303
373
  copied_entries[[st.dev, st.ino]] = dst
304
374
  end
305
375
  end # else...