fpm 0.4.14 → 0.4.15

Sign up to get free protection for your applications and to get access to all the features.
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