fpm 0.4.14 → 0.4.15

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/CHANGELIST CHANGED
@@ -1,3 +1,24 @@
1
+ 0.4.15 (September 6, 2012)
2
+ - pear: support custom channels with --pear-channel <channel> (#207)
3
+ Example: fpm -s pear -t deb --pear-channel pear.drush.org drush
4
+ - permit literal '\n' in --description, fpm will replace with a newline
5
+ character. Example: fpm --description "line one\nline two" (#251)
6
+ - improve error messaging when trying to output a package to a directory that
7
+ doesn't exist (#244)
8
+ - deb: convert '>' and '<' dependency operators to the correct '>>' and '<<'
9
+ debian version operators (#250, patch by Thomas Meson).
10
+ - deb: add --deb-priority flag (#232) for setting the debian 'priority'
11
+ value for your package.
12
+ - add --template-value. Used to expose arbitrary values to script templates.
13
+ If you do --template-value hello=world, in your template you can do
14
+ <%= hello %> to get 'world' to show up in your maintainer scripts.
15
+ - python: add --python-install-data flag to set the --install-data option to
16
+ setup.py (#255, patch by Thomas Meson)
17
+ - Reject bad dependency flags (ones containing commas) and offer alternative.
18
+ (#257)
19
+ - Try to copy a file if hardlinking fails with permission problems (#253,
20
+ patch by Jacek Lach)
21
+
1
22
  0.4.14 (August 24, 2012)
2
23
  - rpm: Replace newlines with space in any license setting. (#252)
3
24
 
@@ -60,6 +60,7 @@ class FPM::Command < Clamp::Command
60
60
  @dependencies ||= []
61
61
  @dependencies << val
62
62
  end # -d / --depends
63
+
63
64
  option "--provides", "PROVIDES",
64
65
  "What this package provides (usually a name). This flag can be "\
65
66
  "specified multiple times." do |val|
@@ -80,10 +81,10 @@ class FPM::Command < Clamp::Command
80
81
  end # --replaces
81
82
  option "--config-files", "CONFIG_FILES",
82
83
  "Mark a file in the package as being a config file. This uses 'conffiles'" \
83
- " in debs and %config in rpm. You can specify a directory to have it " \
84
- "scanned marking all files found as config files. If you have multiple " \
85
- "files to mark as configuration files, specify this flag multiple times." \
86
- do |val|
84
+ " in debs and %config in rpm. If you have multiple files to mark as " \
85
+ "configuration files, specify this flag multiple times." do |val|
86
+ #You can specify a directory to have it scanned marking all files found as
87
+ #config files. If you have multiple "
87
88
  @config_files ||= []
88
89
  @config_files << val
89
90
  end # --config-files
@@ -105,8 +106,12 @@ class FPM::Command < Clamp::Command
105
106
  @excludes ||= []
106
107
  @excludes << val
107
108
  end # -x / --exclude
108
- option "--description", "DESCRIPTION", "Add a description for this package.",
109
- :default => "no description"
109
+ option "--description", "DESCRIPTION", "Add a description for this package." \
110
+ " You can include '\n' sequences to indicate newline breaks.",
111
+ :default => "no description" do |val|
112
+ # Replace literal "\n" sequences with a newline character.
113
+ val.gsub("\\n", "\n")
114
+ end
110
115
  option "--url", "URI", "Add a url for this package.",
111
116
  :default => "http://example.com/no-uri-given"
112
117
  option "--inputs", "INPUTS_PATH",
@@ -157,6 +162,14 @@ class FPM::Command < Clamp::Command
157
162
  "see the fpm wiki: " \
158
163
  "https://github.com/jordansissel/fpm/wiki/Script-Templates"
159
164
 
165
+ option "--template-value", "KEY=VALUE",
166
+ "Make 'key' available in script templates, so <%= key %> given will be " \
167
+ "the provided value. Implies --template-scripts" do |kv|
168
+ @template_scripts = true
169
+ @template_values ||= []
170
+ @template_values << kv.split("=", 2)
171
+ end
172
+
160
173
  parameter "[ARGS] ...",
161
174
  "Inputs to the source package type. For the 'dir' type, this is the files" \
162
175
  " and directories you want to include in the package. For others, like " \
@@ -342,6 +355,13 @@ class FPM::Command < Clamp::Command
342
355
  # Convert to the output type
343
356
  output = input.convert(output_class)
344
357
 
358
+ # Provide any template values as methods on the package.
359
+ if !@template_values.nil?
360
+ @template_values.each do |key, value|
361
+ (class << output; self; end).send(:define_method, key) { value }
362
+ end
363
+ end
364
+
345
365
  # Write the output somewhere, package can be nil if no --package is specified,
346
366
  # and that's OK.
347
367
  begin
@@ -349,6 +369,9 @@ class FPM::Command < Clamp::Command
349
369
  rescue FPM::Package::FileAlreadyExists => e
350
370
  @logger.fatal(e.message)
351
371
  return 1
372
+ rescue FPM::Package::ParentDirectoryMissing => e
373
+ @logger.fatal(e.message)
374
+ return 1
352
375
  end
353
376
 
354
377
  return 0
@@ -406,6 +429,18 @@ class FPM::Command < Clamp::Command
406
429
  "Expected one of: #{types.join(", ")}")
407
430
  end
408
431
 
432
+ with (@command.dependencies) do |dependencies|
433
+ # Verify dependencies don't include commas (#257)
434
+ dependencies.each do |dep|
435
+ next unless dep.include?(",")
436
+ splitdeps = dep.split(/\s*,\s*/)
437
+ @messages << "Dependencies should not " \
438
+ "include commas. If you want to specify multiple dependencies, use " \
439
+ "the '-d' flag multiple times. Example: " + \
440
+ splitdeps.map { |d| "-d '#{d}'" }.join(" ")
441
+ end
442
+ end
443
+
409
444
  mandatory(@command.args.any?,
410
445
  "No parameters given. You need to pass additional command " \
411
446
  "arguments so that I know what you want to build packages " \
@@ -25,6 +25,14 @@ class FPM::Package
25
25
  end # def to_s
26
26
  end # class FileAlreadyExists
27
27
 
28
+ # This class is raised when you try to output a package to a path
29
+ # whose containing directory does not exist.
30
+ class ParentDirectoryMissing < StandardError
31
+ def to_s
32
+ return "Parent directory does not exist: #{File.dirname(super)} - cannot write to #{super}"
33
+ end # def to_s
34
+ end # class ParentDirectoryMissing
35
+
28
36
  # The name of this package
29
37
  attr_accessor :name
30
38
 
@@ -311,6 +319,7 @@ class FPM::Package
311
319
  end # def template
312
320
 
313
321
  def to_s(fmt="NAME.TYPE")
322
+ fmt = "NAME.TYPE" if fmt.nil?
314
323
  fullversion = version.to_s
315
324
  fullversion += "-#{iteration}" if iteration
316
325
  return fmt.gsub("ARCH", architecture.to_s) \
@@ -487,6 +496,12 @@ class FPM::Package
487
496
  end
488
497
  end # def script
489
498
 
499
+ def output_check(output_path)
500
+ if !File.directory?(File.dirname(output_path))
501
+ raise ParentDirectoryMissing.new(output_path)
502
+ end
503
+ end # def output_path
504
+
490
505
  # General public API
491
506
  public(:type, :initialize, :convert, :input, :output, :to_s, :cleanup, :files,
492
507
  :version, :script)
@@ -66,6 +66,18 @@ class FPM::Package::Deb < FPM::Package
66
66
  value.to_i
67
67
  end
68
68
 
69
+ option "--priority", "PRIORITY",
70
+ "The debian package 'priority' value.", :default => "extra"
71
+
72
+ option "--user", "USER", "The owner of files in this package"
73
+
74
+ option "--group", "GROUP", "The group owner of files in this package"
75
+
76
+ def initialize(*args)
77
+ super(*args)
78
+ attributes[:deb_priority] = "extra"
79
+ end # def initialize
80
+
69
81
  private
70
82
 
71
83
  # Return the architecture. This will default to native if not yet set.
@@ -77,7 +89,10 @@ class FPM::Package::Deb < FPM::Package
77
89
  # system about.
78
90
  if program_in_path?("dpkg")
79
91
  @architecture = %x{dpkg --print-architecture 2> /dev/null}.chomp
80
- @architecture = %{uname -m}.chomp if $?.exitstatus != 0
92
+ if $?.exitstatus != 0 or @architecture.empty?
93
+ # if dpkg fails or emits nothing, revert back to uname -m
94
+ @architecture = %x{uname -m}.chomp
95
+ end
81
96
  else
82
97
  @architecture = %x{uname -m}.chomp
83
98
  end
@@ -98,14 +113,15 @@ class FPM::Package::Deb < FPM::Package
98
113
  @logger.warn("Debian tools (dpkg/apt) don't do well with packages " \
99
114
  "that use capital letters in the name. In some cases it will " \
100
115
  "automatically downcase them, in others it will not. It is confusing." \
101
- "Best to not use any capital letters at all.",
116
+ " Best to not use any capital letters at all. I have downcased the " \
117
+ "package name for you just to be safe.",
102
118
  :oldname => @name, :fixedname => @name.downcase)
103
119
  @name = @name.downcase
104
120
  end
105
121
 
106
122
  if @name.include?("_")
107
- @logger.info("Package name includes underscores, converting to dashes",
108
- :name => @name)
123
+ @logger.info("Debian package names cannot include underscores; " \
124
+ "automatically converting to dashes", :name => @name)
109
125
  @name = @name.gsub(/[_]/, "-")
110
126
  end
111
127
 
@@ -130,7 +146,8 @@ class FPM::Package::Deb < FPM::Package
130
146
  if value.nil?
131
147
  return nil
132
148
  else
133
- value.split(": ",2).last
149
+ @logger.info("deb field", field => value.split(": ", 2).last)
150
+ return value.split(": ",2).last
134
151
  end
135
152
  end
136
153
 
@@ -197,7 +214,6 @@ class FPM::Package::Deb < FPM::Package
197
214
 
198
215
  def extract_files(package)
199
216
  # Find out the compression type
200
- p `ar t #{package}`
201
217
  compression = `ar t #{package}`.split("\n").grep(/data.tar/).first.split(".").last
202
218
  case compression
203
219
  when "gz"
@@ -221,6 +237,7 @@ class FPM::Package::Deb < FPM::Package
221
237
  end # def extract_files
222
238
 
223
239
  def output(output_path)
240
+ output_check(output_path)
224
241
  # Abort if the target path already exists.
225
242
  raise FileAlreadyExists.new(output_path) if File.exists?(output_path)
226
243
 
@@ -244,7 +261,14 @@ class FPM::Package::Deb < FPM::Package
244
261
  raise FPM::InvalidPackageConfiguration,
245
262
  "Unknown compression type '#{self.attributes[:deb_compression]}'"
246
263
  end
247
- safesystem(tar_cmd, "-C", staging_path, compression, "-cf", datatar, ".")
264
+ tar_flags = []
265
+ if !attributes[:deb_user].nil?
266
+ tar_flags += [ "--owner", attributes[:deb_user] ]
267
+ end
268
+ if !attributes[:deb_group].nil?
269
+ tar_flags += [ "--group", attributes[:deb_group] ]
270
+ end
271
+ safesystem(tar_cmd, "-C", staging_path, compression, *tar_flags, "-cf", datatar, ".")
248
272
 
249
273
  # pack up the .deb, which is just an 'ar' archive with 3 files
250
274
  # the 'debian-binary' file has to be first
@@ -270,6 +294,12 @@ class FPM::Package::Deb < FPM::Package
270
294
  end.flatten
271
295
  end # def converted_from
272
296
 
297
+ def debianize_op(op)
298
+ # Operators in debian packaging are <<, <=, =, >= and >>
299
+ # So any operator like < or > must be replaced
300
+ {:< => "<<", :> => ">>"}[op.to_sym] or op
301
+ end
302
+
273
303
  def fix_dependency(dep)
274
304
  # Deb dependencies are: NAME (OP VERSION), like "zsh (> 3.0)"
275
305
  # Convert anything that looks like 'NAME OP VERSION' to this format.
@@ -280,7 +310,7 @@ class FPM::Package::Deb < FPM::Package
280
310
  name, op, version = dep.split(/ +/)
281
311
  if !version.nil?
282
312
  # Convert strings 'foo >= bar' to 'foo (>= bar)'
283
- dep = "#{name} (#{op} #{version})"
313
+ dep = "#{name} (#{debianize_op(op)} #{version})"
284
314
  end
285
315
  end
286
316
 
@@ -49,11 +49,13 @@ class FPM::Package::Dir < FPM::Package
49
49
  end # def input
50
50
 
51
51
  # Output this package to the given directory.
52
- def output(dir)
53
- dir = File.expand_path(dir)
52
+ def output(output_path)
53
+ output_check(output_path)
54
+
55
+ output_path = File.expand_path(output_path)
54
56
  ::Dir.chdir(staging_path) do
55
57
  @logger["method"] = "output"
56
- clone(".", dir)
58
+ clone(".", output_path)
57
59
  end
58
60
  ensure
59
61
  @logger.remove("method")
@@ -110,7 +112,7 @@ class FPM::Package::Dir < FPM::Package
110
112
  begin
111
113
  @logger.debug("Linking", :source => source, :destination => destination)
112
114
  File.link(source, destination)
113
- rescue Errno::EXDEV
115
+ rescue Errno::EXDEV, Errno::EPERM
114
116
  # Hardlink attempt failed, copy it instead
115
117
  @logger.debug("Copying", :source => source, :destination => destination)
116
118
  FileUtils.copy_entry(source, destination)
@@ -10,6 +10,12 @@ class FPM::Package::PEAR < FPM::Package
10
10
  option "--package-name-prefix", "PREFIX",
11
11
  "Name prefix for pear package", :default => "php-pear"
12
12
 
13
+ option "--channel", "CHANNEL_URL",
14
+ "The pear channel url to use instead of the default."
15
+
16
+ option "--channel-update", :flag,
17
+ "call 'pear channel-update' prior to installation"
18
+
13
19
  # Input a PEAR package.
14
20
  #
15
21
  # The parameter is a PHP PEAR package name.
@@ -28,18 +34,35 @@ class FPM::Package::PEAR < FPM::Package
28
34
  installroot = attributes[:prefix] || "/usr/share"
29
35
  safesystem("pear", "config-create", staging_path(installroot), config)
30
36
 
31
- @logger.info("Fetching package information", :package => input_package)
37
+ # try channel-discover
38
+ if !attributes[:pear_channel].nil?
39
+ @logger.info("Custom channel specified", :channel => attributes[:pear_channel])
40
+ p ["pear", "-c", config, "channel-discover", attributes[:pear_channel]]
41
+ safesystem("pear", "-c", config, "channel-discover", attributes[:pear_channel])
42
+ input_package = "#{attributes[:pear_channel]}/#{input_package}"
43
+ @logger.info("Prefixing package name with channel", :package => input_package)
44
+ end
45
+
46
+ # do channel-update if requested
47
+ if attributes[:pear_channel_update?]
48
+ channel = attributes[:pear_channel] || "pear"
49
+ @logger.info("Updating the channel", :channel => channel)
50
+ safesystem("pear", "-c", config, "channel-update", channel)
51
+ end
52
+
32
53
  pear_cmd = "pear -c #{config} remote-info #{input_package}"
54
+ @logger.info("Fetching package information", :package => input_package, :command => pear_cmd)
33
55
  name = %x{#{pear_cmd} | sed -ne '/^Package\s*/s/^Package\s*//p'}.chomp
34
56
  self.name = "#{attributes[:pear_package_name_prefix]}-#{name}"
35
57
  self.version = %x{#{pear_cmd} | sed -ne '/^Latest\s*/s/^Latest\s*//p'}.chomp
36
58
  self.description = %x{#{pear_cmd} | sed -ne '/^Summary\s*/s/^Summary\s*//p'}.chomp
59
+ @logger.debug("Package info", :name => self.name, :version => self.version,
60
+ :description => self.description)
37
61
 
38
62
  @logger.info("Installing pear package", :package => input_package,
39
63
  :directory => staging_path)
40
64
  ::Dir.chdir(staging_path) do
41
- safesystem("pear", "-c", config, "install", "-n", "-f", "-P", ".",
42
- input_package)
65
+ safesystem("pear", "-c", config, "install", "-n", "-f", input_package)
43
66
  end
44
67
 
45
68
  # Remove the stuff we don't want
@@ -47,6 +47,9 @@ class FPM::Package::Python < FPM::Package
47
47
  "Want to what your target platform is using? Run this: " \
48
48
  "python -c 'from distutils.sysconfig import get_python_lib; " \
49
49
  "print get_python_lib()'"
50
+ option "--install-data", "DATA_PATH", "The path to where data should be." \
51
+ "installed to. This is equivalent to 'python setup.py --install-data " \
52
+ "DATA_PATH"
50
53
 
51
54
  private
52
55
 
@@ -188,13 +191,16 @@ class FPM::Package::Python < FPM::Package
188
191
  @logger.info("Setting default :python_install_lib attribute",
189
192
  :value => attributes[:python_install_lib])
190
193
  end
194
+ if attributes[:python_install_data].nil?
195
+ attributes[:python_install_data] = attributes[:python_install_lib]
196
+ end
191
197
  # Some setup.py's assume $PWD == current directory of setup.py, so let's
192
198
  # chdir first.
193
199
  ::Dir.chdir(project_dir) do
194
200
  safesystem(attributes[:python_bin], "setup.py", "install",
195
201
  "--root", staging_path,
196
202
  "--install-lib", File.join(prefix, attributes[:python_install_lib]),
197
- "--install-data", File.join(prefix, attributes[:python_install_lib]),
203
+ "--install-data", File.join(prefix, attributes[:python_install_data]),
198
204
  "--install-scripts", File.join(prefix, attributes[:python_install_bin]))
199
205
  end
200
206
  end # def install_to_staging
@@ -173,6 +173,8 @@ class FPM::Package::RPM < FPM::Package
173
173
  end # def input
174
174
 
175
175
  def output(output_path)
176
+ output_check(output_path)
177
+ raise FileAlreadyExists.new(output_path) if File.exists?(output_path)
176
178
  %w(BUILD RPMS SRPMS SOURCES SPECS).each { |d| FileUtils.mkdir_p(build_path(d)) }
177
179
  args = ["rpmbuild", "-bb",
178
180
  "--define", "buildroot #{build_path}/BUILD",
@@ -47,6 +47,8 @@ class FPM::Package::Tar < FPM::Package
47
47
  # If the output path ends predictably (like in .tar.gz) it will try to obey
48
48
  # the compression type.
49
49
  def output(output_path)
50
+ output_check(output_path)
51
+ raise FileAlreadyExists.new(output_path) if File.exists?(output_path)
50
52
  # Unpack the tarball to the staging path
51
53
  args = ["-cf", output_path, "-C", staging_path, "."]
52
54
  with(tar_compression_flag(output_path)) do |flag|
@@ -6,7 +6,7 @@ Architecture: <%= architecture %>
6
6
  Maintainer: <%= maintainer %>
7
7
  Installed-Size: <%= attributes[:deb_installed_size] %>
8
8
  <% if !dependencies.empty? -%>
9
- Depends: <%= dependencies.join(", ") %>
9
+ Depends: <%= dependencies.collect { |d| fix_dependency(d) }.flatten.join(", ") %>
10
10
  <% end -%>
11
11
  <% if !conflicts.empty? -%>
12
12
  Conflicts: <%= conflicts.join(", ") %>
@@ -22,7 +22,7 @@ Provides: <%= provides.join(", ") %>
22
22
  Replaces: <%= replaces.join(", ") %>
23
23
  <% end -%>
24
24
  Section: <%= category %>
25
- Priority: extra
25
+ Priority: <%= attributes[:deb_priority] %>
26
26
  Homepage: <%= url or "http://nourlgiven.example.com/" %>
27
27
  <% lines = (description or "no description given").split("\n") -%>
28
28
  <% firstline, *remainder = lines -%>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fpm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.14
4
+ version: 0.4.15
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-24 00:00:00.000000000 Z
12
+ date: 2012-09-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json
@@ -149,28 +149,26 @@ executables:
149
149
  extensions: []
150
150
  extra_rdoc_files: []
151
151
  files:
152
+ - lib/fpm/command.rb
153
+ - lib/fpm/namespace.rb
154
+ - lib/fpm/package.rb
152
155
  - lib/fpm/errors.rb
153
- - lib/fpm/package/npm.rb
154
- - lib/fpm/package/python.rb
155
- - lib/fpm/package/solaris.rb
156
- - lib/fpm/package/dir.rb
157
156
  - lib/fpm/package/gem.rb
158
- - lib/fpm/package/pear.rb
159
- - lib/fpm/package/puppet.rb
160
- - lib/fpm/package/pyfpm/__init__.py
161
- - lib/fpm/package/pyfpm/__init__.pyc
162
- - lib/fpm/package/pyfpm/get_metadata.pyc
157
+ - lib/fpm/package/dir.rb
163
158
  - lib/fpm/package/pyfpm/get_metadata.py
164
- - lib/fpm/package/tar.rb
159
+ - lib/fpm/package/pyfpm/__init__.py
160
+ - lib/fpm/package/npm.rb
161
+ - lib/fpm/package/pear.rb
165
162
  - lib/fpm/package/deb.rb
163
+ - lib/fpm/package/python.rb
166
164
  - lib/fpm/package/rpm.rb
165
+ - lib/fpm/package/puppet.rb
166
+ - lib/fpm/package/tar.rb
167
+ - lib/fpm/package/solaris.rb
167
168
  - lib/fpm/util.rb
168
- - lib/fpm/package.rb
169
- - lib/fpm/namespace.rb
170
- - lib/fpm/command.rb
171
169
  - lib/fpm.rb
172
- - bin/fpm
173
170
  - bin/fpm-npm
171
+ - bin/fpm
174
172
  - templates/deb.erb
175
173
  - templates/rpm.erb
176
174
  - templates/solaris.erb