fpm-aeppert 1.6.2 → 1.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  require "fpm/package"
2
2
  require "fpm/util"
3
- require "backports"
3
+ require "backports/latest"
4
4
  require "fileutils"
5
5
  require "find"
6
6
  require "socket"
@@ -83,8 +83,8 @@ class FPM::Package::Dir < FPM::Package
83
83
  # can include license data from themselves (rpms, gems, etc),
84
84
  # but to make sure a simple dir -> rpm works without having
85
85
  # to specify a license.
86
- self.license = "unknown"
87
- self.vendor = [ENV["USER"], Socket.gethostname].join("@")
86
+ self.license ||= "unknown"
87
+ self.vendor ||= [ENV["USER"], Socket.gethostname].join("@")
88
88
  ensure
89
89
  # Clean up any logger context we added.
90
90
  logger.remove("method")
@@ -101,18 +101,7 @@ class FPM::Package::Dir < FPM::Package
101
101
  end
102
102
 
103
103
  # Write the scripts, too.
104
- scripts_path = File.join(output_path, ".scripts")
105
- ::Dir.mkdir(scripts_path)
106
- [:before_install, :after_install, :before_remove, :after_remove].each do |name|
107
- next unless script?(name)
108
- out = File.join(scripts_path, name.to_s)
109
- logger.debug("Writing script", :source => name, :target => out)
110
- File.write(out, script(name))
111
- require "pry"
112
- binding.pry
113
- File.chmod(0755, out)
114
- end
115
-
104
+ write_scripts
116
105
  ensure
117
106
  logger.remove("method")
118
107
  end # def output
@@ -147,14 +136,20 @@ class FPM::Package::Dir < FPM::Package
147
136
 
148
137
  # For single file copies, permit file destinations
149
138
  fileinfo = File.lstat(source)
150
- if fileinfo.file? && !File.directory?(destination)
139
+ destination_is_directory = File.directory?(destination)
140
+ if fileinfo.file? && !destination_is_directory
151
141
  if destination[-1,1] == "/"
152
142
  copy(source, File.join(destination, source))
153
143
  else
154
144
  copy(source, destination)
155
145
  end
156
146
  elsif fileinfo.symlink?
157
- copy(source, File.join(destination, source))
147
+ # Treat them same as files
148
+ if destination[-1,1] == "/"
149
+ copy(source, File.join(destination, source))
150
+ else
151
+ copy(source, destination)
152
+ end
158
153
  else
159
154
  # Copy all files from 'path' into staging_path
160
155
  Find.find(source) do |path|
@@ -1,5 +1,5 @@
1
1
  require "fpm/package"
2
- require "backports"
2
+ require "backports/latest"
3
3
 
4
4
  # Empty Package type. For strict/meta/virtual package creation
5
5
 
@@ -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 "digest"
@@ -12,18 +12,6 @@ class FPM::Package::FreeBSD < FPM::Package
12
12
  :after_remove => "post-deinstall",
13
13
  } unless defined?(SCRIPT_MAP)
14
14
 
15
- def self.default_abi
16
- abi_name = %x{uname -s}.chomp
17
- abi_version = %x{uname -r}.chomp.split(".")[0]
18
- abi_arch = %x{uname -m}.chomp
19
-
20
- [abi_name, abi_version, abi_arch].join(":")
21
- end
22
-
23
- option "--abi", "ABI",
24
- "Sets the FreeBSD abi pkg field to specify binary compatibility.",
25
- :default => default_abi
26
-
27
15
  option "--origin", "ABI",
28
16
  "Sets the FreeBSD 'origin' pkg field",
29
17
  :default => "fpm/<name>"
@@ -58,7 +46,7 @@ class FPM::Package::FreeBSD < FPM::Package
58
46
  pkg_version = (iteration and (iteration.to_i > 0)) ? "#{version}-#{iteration}" : "#{version}"
59
47
 
60
48
  pkgdata = {
61
- "abi" => attributes[:freebsd_abi],
49
+ "arch" => architecture,
62
50
  "name" => name,
63
51
  "version" => pkg_version,
64
52
  "comment" => description,
@@ -110,6 +98,29 @@ class FPM::Package::FreeBSD < FPM::Package
110
98
  end
111
99
  end # def output
112
100
 
101
+ # Handle architecture naming conversion:
102
+ # <osname>:<osversion>:<arch>:<wordsize>[.other]
103
+ def architecture
104
+ osname = %x{uname -s}.chomp
105
+ osversion = %x{uname -r}.chomp.split('.').first
106
+
107
+ # Essentially because no testing on other platforms
108
+ arch = 'x86'
109
+
110
+ wordsize = case @architecture
111
+ when nil, 'native'
112
+ %x{getconf LONG_BIT}.chomp # 'native' is current arch
113
+ when 'amd64'
114
+ '64'
115
+ when 'i386'
116
+ '32'
117
+ else
118
+ %x{getconf LONG_BIT}.chomp # default to native, the current arch
119
+ end
120
+
121
+ return [osname, osversion, arch, wordsize].join(':')
122
+ end
123
+
113
124
  def add_path(tar, tar_path, path)
114
125
  stat = File.lstat(path)
115
126
  if stat.directory?
@@ -4,6 +4,7 @@ require "rubygems"
4
4
  require "fileutils"
5
5
  require "fpm/util"
6
6
  require "yaml"
7
+ require "git"
7
8
 
8
9
  # A rubygems package.
9
10
  #
@@ -44,9 +45,36 @@ class FPM::Package::Gem < FPM::Package
44
45
  option "--disable-dependency", "gem_name",
45
46
  "The gem name to remove from dependency list",
46
47
  :multivalued => true, :attribute_name => :gem_disable_dependencies
48
+ option "--embed-dependencies", :flag, "Should the gem dependencies " \
49
+ "be installed?", :default => false
47
50
 
48
51
  option "--version-bins", :flag, "Append the version to the bins", :default => false
49
52
 
53
+ option "--stagingdir", "STAGINGDIR",
54
+ "The directory where fpm installs the gem temporarily before conversion. " \
55
+ "Normally a random subdirectory of workdir."
56
+
57
+ option "--git-repo", "GIT_REPO",
58
+ "Use this git repo address as the source of the gem instead of " \
59
+ "rubygems.org.", :default => nil
60
+
61
+ option "--git-branch", "GIT_BRANCH",
62
+ "When using a git repo as the source of the gem instead of " \
63
+ "rubygems.org, use this git branch.",
64
+ :default => nil
65
+
66
+ # Override parent method
67
+ def staging_path(path=nil)
68
+ @gem_staging_path ||= attributes[:gem_stagingdir] || Stud::Temporary.directory("package-#{type}-staging")
69
+ @staging_path = @gem_staging_path
70
+
71
+ if path.nil?
72
+ return @staging_path
73
+ else
74
+ return File.join(@staging_path, path)
75
+ end
76
+ end # def staging_path
77
+
50
78
  def input(gem)
51
79
  # 'arg' is the name of the rubygem we should unpack.
52
80
  path_to_gem = download_if_necessary(gem, version)
@@ -73,21 +101,33 @@ class FPM::Package::Gem < FPM::Package
73
101
 
74
102
  logger.info("Trying to download", :gem => gem_name, :version => gem_version)
75
103
 
76
- gem_fetch = [ "#{attributes[:gem_gem]}", "fetch", gem_name]
77
-
78
- gem_fetch += ["--prerelease"] if attributes[:gem_prerelease?]
79
- gem_fetch += ["--version", gem_version] if gem_version
80
-
81
104
  download_dir = build_path(gem_name)
82
105
  FileUtils.mkdir(download_dir) unless File.directory?(download_dir)
83
106
 
84
- ::Dir.chdir(download_dir) do |dir|
85
- logger.debug("Downloading in directory #{dir}")
86
- safesystem(*gem_fetch)
107
+ if attributes[:gem_git_repo]
108
+ logger.debug("Git cloning in directory #{download_dir}")
109
+ g = Git.clone(attributes[:gem_git_repo],gem_name,:path => download_dir)
110
+ if attributes[:gem_git_branch]
111
+ g.branch(attributes[:gem_git_branch]).checkout
112
+ g.pull('origin',attributes[:gem_git_branch])
113
+ end
114
+ gem_build = [ "#{attributes[:gem_gem]}", "build", "#{g.dir.to_s}/#{gem_name}.gemspec"]
115
+ ::Dir.chdir(g.dir.to_s) do |dir|
116
+ logger.debug("Building in directory #{dir}")
117
+ safesystem(*gem_build)
118
+ end
119
+ gem_files = ::Dir.glob(File.join(g.dir.to_s, "*.gem"))
120
+ else
121
+ gem_fetch = [ "#{attributes[:gem_gem]}", "fetch", gem_name]
122
+ gem_fetch += ["--prerelease"] if attributes[:gem_prerelease?]
123
+ gem_fetch += ["--version", gem_version] if gem_version
124
+ ::Dir.chdir(download_dir) do |dir|
125
+ logger.debug("Downloading in directory #{dir}")
126
+ safesystem(*gem_fetch)
127
+ end
128
+ gem_files = ::Dir.glob(File.join(download_dir, "*.gem"))
87
129
  end
88
130
 
89
- gem_files = ::Dir.glob(File.join(download_dir, "*.gem"))
90
-
91
131
  if gem_files.length != 1
92
132
  raise "Unexpected number of gem files in #{download_dir}, #{gem_files.length} should be 1"
93
133
  end
@@ -144,7 +184,7 @@ class FPM::Package::Gem < FPM::Package
144
184
  # composing multiple packages, it's best to explicitly include it in the provides list.
145
185
  self.provides << "#{self.name} = #{self.version}"
146
186
 
147
- if !attributes[:no_auto_depends?]
187
+ if !attributes[:no_auto_depends?] && !attributes[:gem_embed_dependencies?]
148
188
  spec.runtime_dependencies.map do |dep|
149
189
  # rubygems 1.3.5 doesn't have 'Gem::Dependency#requirement'
150
190
  if dep.respond_to?(:requirement)
@@ -180,8 +220,18 @@ class FPM::Package::Gem < FPM::Package
180
220
 
181
221
  ::FileUtils.mkdir_p(installdir)
182
222
  # TODO(sissel): Allow setting gem tool path
183
- args = [attributes[:gem_gem], "install", "--quiet", "--no-ri", "--no-rdoc",
184
- "--no-user-install", "--install-dir", installdir, "--ignore-dependencies"]
223
+ args = [attributes[:gem_gem], "install", "--quiet", "--no-user-install", "--install-dir", installdir]
224
+ if ::Gem::VERSION =~ /^[012]\./
225
+ args += [ "--no-ri", "--no-rdoc" ]
226
+ else
227
+ # Rubygems 3.0.0 changed --no-ri to --no-document
228
+ args += [ "--no-document" ]
229
+ end
230
+
231
+ if !attributes[:gem_embed_dependencies?]
232
+ args += ["--ignore-dependencies"]
233
+ end
234
+
185
235
  if attributes[:gem_env_shebang?]
186
236
  args += ["-E"]
187
237
  end
@@ -231,6 +281,21 @@ class FPM::Package::Gem < FPM::Package
231
281
  FileUtils.mv("#{bin_path}/#{bin}", "#{bin_path}/#{bin}-#{self.version}")
232
282
  end
233
283
  end
284
+
285
+ if attributes[:source_date_epoch_from_changelog?]
286
+ detect_source_date_from_changelog(installdir)
287
+ end
288
+
289
+ # Remove generated Makefile and gem_make.out files, if any; they
290
+ # are not needed, and may contain generated paths that cause
291
+ # different output on successive runs.
292
+ Find.find(installdir) do |path|
293
+ if path =~ /.*(gem_make.out|Makefile|mkmf.log)$/
294
+ logger.info("Removing no longer needed file %s to reduce nondeterminism" % path)
295
+ File.unlink(path)
296
+ end
297
+ end
298
+
234
299
  end # def install_to_staging
235
300
 
236
301
  # Sanitize package name.
@@ -239,5 +304,75 @@ class FPM::Package::Gem < FPM::Package
239
304
  def fix_name(name)
240
305
  return [attributes[:gem_package_name_prefix], name].join("-")
241
306
  end # def fix_name
307
+
308
+ # Regular expression to accept a gem changelog line, and store date & version, if any, in named capture groups.
309
+ # Supports formats suggested by http://keepachangelog.com and https://github.com/tech-angels/vandamme
310
+ # as well as other similar formats that actually occur in the wild.
311
+ # Build it in pieces for readability, and allow version and date in either order.
312
+ # Whenever you change this, add a row to the test case in spec/fpm/package/gem_spec.rb.
313
+ # Don't even try to handle dates that lack four-digit years.
314
+ # Building blocks:
315
+ P_RE_LEADIN = '^[#=]{0,3}\s?'
316
+ P_RE_VERSION_ = '[\w\.-]+\.[\w\.-]+[a-zA-Z0-9]'
317
+ P_RE_SEPARATOR = '\s[-=/(]?\s?'
318
+ P_RE_DATE1 = '\d{4}-\d{2}-\d{2}'
319
+ P_RE_DATE2 = '\w+ \d{1,2}(?:st|nd|rd|th)?,\s\d{4}'
320
+ P_RE_DATE3 = '\w+\s+\w+\s+\d{1,2},\s\d{4}'
321
+ P_RE_DATE = "(?<date>#{P_RE_DATE1}|#{P_RE_DATE2}|#{P_RE_DATE3})"
322
+ P_RE_URL = '\(https?:[-\w/.%]*\)' # In parens, per markdown
323
+ P_RE_GTMAGIC = '\[\]' # github magic version diff, per chandler
324
+ P_RE_VERSION = "\\[?(?:Version |v)?(?<version>#{P_RE_VERSION_})\\]?(?:#{P_RE_URL}|#{P_RE_GTMAGIC})?"
325
+ # The final RE's:
326
+ P_RE_VERSION_DATE = "#{P_RE_LEADIN}#{P_RE_VERSION}#{P_RE_SEPARATOR}#{P_RE_DATE}"
327
+ P_RE_DATE_VERSION = "#{P_RE_LEADIN}#{P_RE_DATE}#{P_RE_SEPARATOR}#{P_RE_VERSION}"
328
+
329
+ # Detect release date, if found, store in attributes[:source_date_epoch]
330
+ def detect_source_date_from_changelog(installdir)
331
+ name = self.name.sub("rubygem-", "") + "-" + self.version
332
+ changelog = nil
333
+ datestr = nil
334
+ r1 = Regexp.new(P_RE_VERSION_DATE)
335
+ r2 = Regexp.new(P_RE_DATE_VERSION)
336
+
337
+ # Changelog doesn't have a standard name, so check all common variations
338
+ # Sort this list using LANG=C, i.e. caps first
339
+ [
340
+ "CHANGELIST",
341
+ "CHANGELOG", "CHANGELOG.asciidoc", "CHANGELOG.md", "CHANGELOG.rdoc", "CHANGELOG.rst", "CHANGELOG.txt",
342
+ "CHANGES", "CHANGES.md", "CHANGES.txt",
343
+ "ChangeLog", "ChangeLog.md", "ChangeLog.txt",
344
+ "Changelog", "Changelog.md", "Changelog.txt",
345
+ "changelog", "changelog.md", "changelog.txt",
346
+ ].each do |changelogname|
347
+ path = File.join(installdir, "gems", name, changelogname)
348
+ if File.exist?(path)
349
+ changelog = path
350
+ File.open path do |file|
351
+ file.each_line do |line|
352
+ if line =~ /#{self.version}/
353
+ [r1, r2].each do |r|
354
+ if r.match(line)
355
+ datestr = $~[:date]
356
+ break
357
+ end
358
+ end
359
+ end
360
+ end
361
+ end
362
+ end
363
+ end
364
+ if datestr
365
+ date = Date.parse(datestr)
366
+ sec = date.strftime("%s")
367
+ attributes[:source_date_epoch] = sec
368
+ logger.debug("Gem %s has changelog date %s, setting source_date_epoch to %s" % [name, datestr, sec])
369
+ elsif changelog
370
+ logger.debug("Gem %s changelog %s did not have recognizable date for release %s" % [name, changelog, self.version])
371
+ else
372
+ logger.debug("Gem %s did not have changelog with recognized name" % [name])
373
+ # FIXME: check rubygems.org?
374
+ end
375
+ end # detect_source_date_from_changelog
376
+
242
377
  public(:input, :output)
243
378
  end # class FPM::Package::Gem
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  require "fpm/package"
3
3
  require "fpm/util"
4
- require "backports"
4
+ require "backports/latest"
5
5
  require "fileutils"
6
6
  require "find"
7
7
 
@@ -10,13 +10,14 @@ require "pleaserun/cli"
10
10
  # This does not currently support 'output'
11
11
  class FPM::Package::PleaseRun < FPM::Package
12
12
  # TODO(sissel): Implement flags.
13
-
13
+
14
14
  require "pleaserun/platform/systemd"
15
15
  require "pleaserun/platform/upstart"
16
16
  require "pleaserun/platform/launchd"
17
17
  require "pleaserun/platform/sysv"
18
18
 
19
19
  option "--name", "SERVICE_NAME", "The name of the service you are creating"
20
+ option "--chdir", "CHDIR", "The working directory used by the service"
20
21
 
21
22
  private
22
23
  def input(command)
@@ -27,6 +28,10 @@ class FPM::Package::PleaseRun < FPM::Package
27
28
  ::PleaseRun::Platform::Launchd.new("10.9"), # OS X
28
29
  ::PleaseRun::Platform::SYSV.new("lsb-3.1") # Ancient stuff
29
30
  ]
31
+ pleaserun_attributes = [ "chdir", "user", "group", "umask", "chroot", "nice", "limit_coredump",
32
+ "limit_cputime", "limit_data", "limit_file_size", "limit_locked_memory",
33
+ "limit_open_files", "limit_user_processes", "limit_physical_memory", "limit_stack_size",
34
+ "log_directory", "log_file_stderr", "log_file_stdout"]
30
35
 
31
36
  attributes[:pleaserun_name] ||= File.basename(command.first)
32
37
  attributes[:prefix] ||= "/usr/share/pleaserun/#{attributes[:pleaserun_name]}"
@@ -41,6 +46,13 @@ class FPM::Package::PleaseRun < FPM::Package
41
46
  else
42
47
  platform.name
43
48
  end
49
+ pleaserun_attributes.each do |attribute_name|
50
+ attribute = "pleaserun_#{attribute_name}".to_sym
51
+ if attributes.has_key?(attribute) and not attributes[attribute].nil?
52
+ platform.send("#{attribute_name}=", attributes[attribute])
53
+ end
54
+ end
55
+
44
56
  base = staging_path(File.join(attributes[:prefix], "#{platform.platform}/#{platform.target_version || "default"}"))
45
57
  target = File.join(base, "files")
46
58
  actions_script = File.join(base, "install_actions.sh")
@@ -47,6 +47,11 @@ class get_metadata(Command):
47
47
 
48
48
  def process_dep(self, dep):
49
49
  deps = []
50
+ if hasattr(dep, 'marker') and dep.marker:
51
+ # PEP0508 marker present
52
+ if not dep.marker.evaluate():
53
+ return deps
54
+
50
55
  if dep.specs:
51
56
  for operator, version in dep.specs:
52
57
  deps.append("%s %s %s" % (dep.project_name,
@@ -73,6 +73,10 @@ class FPM::Package::Python < FPM::Package
73
73
  "The python package name to remove from dependency list",
74
74
  :multivalued => true, :attribute_name => :python_disable_dependency,
75
75
  :default => []
76
+ option "--setup-py-arguments", "setup_py_argument",
77
+ "Arbitrary argument(s) to be passed to setup.py",
78
+ :multivalued => true, :attribute_name => :python_setup_py_arguments,
79
+ :default => []
76
80
 
77
81
  private
78
82
 
@@ -225,7 +229,7 @@ class FPM::Package::Python < FPM::Package
225
229
 
226
230
  if !attributes[:no_auto_depends?] and attributes[:python_dependencies?]
227
231
  metadata["dependencies"].each do |dep|
228
- dep_re = /^([^<>!= ]+)\s*(?:([<>!=]{1,2})\s*(.*))?$/
232
+ dep_re = /^([^<>!= ]+)\s*(?:([~<>!=]{1,2})\s*(.*))?$/
229
233
  match = dep_re.match(dep)
230
234
  if match.nil?
231
235
  logger.error("Unable to parse dependency", :dependency => dep)
@@ -236,7 +240,7 @@ class FPM::Package::Python < FPM::Package
236
240
  next if attributes[:python_disable_dependency].include?(name)
237
241
 
238
242
  # convert == to =
239
- if cmp == "=="
243
+ if cmp == "==" or cmp == "~="
240
244
  logger.info("Converting == dependency requirement to =", :dependency => dep )
241
245
  cmp = "="
242
246
  end
@@ -310,6 +314,13 @@ class FPM::Package::Python < FPM::Package
310
314
  flags += [ "build_scripts", "--executable", attributes[:python_scripts_executable] ]
311
315
  end
312
316
 
317
+ if !attributes[:python_setup_py_arguments].nil? and !attributes[:python_setup_py_arguments].empty?
318
+ # Add optional setup.py arguments
319
+ attributes[:python_setup_py_arguments].each do |a|
320
+ flags += [ a ]
321
+ end
322
+ end
323
+
313
324
  safesystem(attributes[:python_bin], "setup.py", "install", *flags)
314
325
  end
315
326
  end # def install_to_staging