fpm 1.3.3 → 1.4.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.
@@ -23,7 +23,7 @@ class FPM::Package::Deb < FPM::Package
23
23
  # The list of supported compression types. Default is gz (gzip)
24
24
  COMPRESSION_TYPES = [ "gz", "bzip2", "xz" ]
25
25
 
26
- option "--ignore-iteration-in-dependencies", :flag,
26
+ option "--ignore-iteration-in-dependencies", :flag,
27
27
  "For '=' (equal) dependencies, allow iterations on the specified " \
28
28
  "version. Default is to be specific. This option allows the same " \
29
29
  "version of a package but any iteration is permitted"
@@ -73,10 +73,10 @@ class FPM::Package::Deb < FPM::Package
73
73
  value.to_i
74
74
  end
75
75
 
76
- option "--priority", "PRIORITY",
76
+ option "--priority", "PRIORITY",
77
77
  "The debian package 'priority' value.", :default => "extra"
78
78
 
79
- option "--use-file-permissions", :flag,
79
+ option "--use-file-permissions", :flag,
80
80
  "Use existing file permissions when defining ownership and modes"
81
81
 
82
82
  option "--user", "USER", "The owner of files in this package", :default => 'root'
@@ -124,6 +124,10 @@ class FPM::Package::Deb < FPM::Package
124
124
  next @custom_fields
125
125
  end
126
126
 
127
+ option "--no-default-config-files", :flag,
128
+ "Do not add all files in /etc as configuration files by default for Debian packages.",
129
+ :default => false
130
+
127
131
  option "--shlibs", "SHLIBS", "Include control/shlibs content. This flag " \
128
132
  "expects a string that is used as the contents of the shlibs file. " \
129
133
  "See the following url for a description of this file and its format: " \
@@ -162,7 +166,7 @@ class FPM::Package::Deb < FPM::Package
162
166
  @architecture = %x{dpkg --print-architecture 2> /dev/null}.chomp
163
167
  if $?.exitstatus != 0 or @architecture.empty?
164
168
  # if dpkg fails or emits nothing, revert back to uname -m
165
- @architecture = %x{uname -m}.chomp
169
+ @architecture = %x{uname -m}.chomp
166
170
  end
167
171
  else
168
172
  @architecture = %x{uname -m}.chomp
@@ -209,7 +213,7 @@ class FPM::Package::Deb < FPM::Package
209
213
 
210
214
  return @name
211
215
  end # def name
212
-
216
+
213
217
  def prefix
214
218
  return (attributes[:prefix] or "/")
215
219
  end # def prefix
@@ -227,7 +231,7 @@ class FPM::Package::Deb < FPM::Package
227
231
 
228
232
  control = File.read(File.join(path, "control"))
229
233
 
230
- parse = lambda do |field|
234
+ parse = lambda do |field|
231
235
  value = control[/^#{field.capitalize}: .*/]
232
236
  if value.nil?
233
237
  return nil
@@ -267,6 +271,22 @@ class FPM::Package::Deb < FPM::Package
267
271
  #self.config_files = config_files
268
272
 
269
273
  self.dependencies += parse_depends(parse.call("Depends")) if !attributes[:no_auto_depends?]
274
+
275
+ if File.file?(File.join(path, "preinst"))
276
+ self.scripts[:before_install] = File.read(File.join(path, "preinst"))
277
+ end
278
+ if File.file?(File.join(path, "postinst"))
279
+ self.scripts[:after_install] = File.read(File.join(path, "postinst"))
280
+ end
281
+ if File.file?(File.join(path, "prerm"))
282
+ self.scripts[:before_remove] = File.read(File.join(path, "prerm"))
283
+ end
284
+ if File.file?(File.join(path, "postrm"))
285
+ self.scripts[:after_remove] = File.read(File.join(path, "postrm"))
286
+ end
287
+ if File.file?(File.join(path, "conffiles"))
288
+ self.config_files = File.read(File.join(path, "conffiles")).split("\n")
289
+ end
270
290
  end
271
291
  end # def extract_info
272
292
 
@@ -289,7 +309,7 @@ class FPM::Package::Deb < FPM::Package
289
309
  m = dep_re.match(dep)
290
310
  if m
291
311
  name, op, version = m.captures
292
- # deb uses ">>" and "<<" for greater and less than respectively.
312
+ # deb uses ">>" and "<<" for greater and less than respectively.
293
313
  # fpm wants just ">" and "<"
294
314
  op = "<" if op == "<<"
295
315
  op = ">" if op == ">>"
@@ -309,10 +329,10 @@ class FPM::Package::Deb < FPM::Package
309
329
  when "gz"
310
330
  datatar = "data.tar.gz"
311
331
  compression = "-z"
312
- when "bzip2"
332
+ when "bzip2"
313
333
  datatar = "data.tar.bz2"
314
334
  compression = "-j"
315
- when "xz"
335
+ when "xz"
316
336
  datatar = "data.tar.xz"
317
337
  compression = "-J"
318
338
  else
@@ -373,7 +393,7 @@ class FPM::Package::Deb < FPM::Package
373
393
  when "gz", nil
374
394
  datatar = build_path("data.tar.gz")
375
395
  compression = "-z"
376
- when "bzip2"
396
+ when "bzip2"
377
397
  datatar = build_path("data.tar.bz2")
378
398
  compression = "-j"
379
399
  when "xz"
@@ -577,7 +597,7 @@ class FPM::Package::Deb < FPM::Package
577
597
  with(build_path("control.tar.gz")) do |controltar|
578
598
  logger.info("Creating", :path => controltar, :from => control_path)
579
599
 
580
- args = [ tar_cmd, "-C", control_path, "-zcf", controltar,
600
+ args = [ tar_cmd, "-C", control_path, "-zcf", controltar,
581
601
  "--owner=0", "--group=0", "--numeric-owner", "." ]
582
602
  safesystem(*args)
583
603
  end
@@ -637,33 +657,48 @@ class FPM::Package::Deb < FPM::Package
637
657
  # deb maintainer scripts are required to be executable
638
658
  File.chmod(0755, controlscript)
639
659
  end
640
- end
660
+ end
641
661
  end # def write_scripts
642
662
 
643
663
  def write_conffiles
644
- return unless config_files.any?
645
-
646
- # scan all conf file paths for files and add them
647
664
  allconfigs = []
648
- config_files.each do |path|
665
+
666
+ # expand recursively a given path to be put in allconfigs
667
+ def add_path(path, allconfigs)
649
668
  # Strip leading /
650
669
  path = path[1..-1] if path[0,1] == "/"
651
670
  cfg_path = File.expand_path(path, staging_path)
671
+ Find.find(cfg_path).select { |p| File.file?(p) }.each do |p|
672
+ allconfigs << p.gsub("#{staging_path}/", '')
673
+ end
674
+ end
675
+
676
+ # scan all conf file paths for files and add them
677
+ config_files.each do |path|
652
678
  begin
653
- Find.find(cfg_path) do |p|
654
- allconfigs << p.gsub("#{staging_path}/", '') if File.file? p
655
- end
656
- rescue Errno::ENOENT => e
679
+ add_path(path, allconfigs)
680
+ rescue Errno::ENOENT
657
681
  raise FPM::InvalidPackageConfiguration,
658
- "Error trying to use '#{cfg_path}' as a config file in the package. Does it exist?"
682
+ "Error trying to use '#{path}' as a config file in the package. Does it exist?"
683
+ end
684
+ end
685
+
686
+ # Also add everything in /etc
687
+ begin
688
+ if !attributes[:deb_no_default_config_files?]
689
+ logger.warn("Debian packaging tools generally labels all files in /etc as config files, " \
690
+ "as mandated by policy, so fpm defaults to this behavior for deb packages. " \
691
+ "You can disable this default behavior with --deb-no-default-config-files flag")
692
+ add_path("/etc", allconfigs)
659
693
  end
694
+ rescue Errno::ENOENT
660
695
  end
696
+
661
697
  allconfigs.sort!.uniq!
698
+ return unless allconfigs.any?
662
699
 
663
700
  with(control_path("conffiles")) do |conffiles|
664
701
  File.open(conffiles, "w") do |out|
665
- # 'config_files' comes from FPM::Package and is usually set with
666
- # FPM::Command's --config-files flag
667
702
  allconfigs.each do |cf|
668
703
  # We need to put the leading / back. Stops lintian relative-conffile error.
669
704
  out.puts("/" + cf)
@@ -679,6 +714,7 @@ class FPM::Package::Deb < FPM::Package
679
714
  File.open(control_path("shlibs"), "w") do |out|
680
715
  out.write(attributes[:deb_shlibs])
681
716
  end
717
+ File.chmod(0644, control_path("shlibs"))
682
718
  end # def write_shlibs
683
719
 
684
720
  def write_debconf
@@ -75,7 +75,7 @@ class FPM::Package::Dir < FPM::Package
75
75
  end
76
76
  end
77
77
  rescue Errno::ENOENT => e
78
- raise FPM::InvalidPackageConfiguration,
78
+ raise FPM::InvalidPackageConfiguration,
79
79
  "Cannot chdir to '#{chdir}'. Does it exist?"
80
80
  end
81
81
 
@@ -133,14 +133,14 @@ class FPM::Package::Dir < FPM::Package
133
133
 
134
134
  # For single file copies, permit file destinations
135
135
  fileinfo = File.lstat(source)
136
- if fileinfo.file? && !File.directory?(destination)
136
+ if fileinfo.file? && !File.directory?(destination)
137
137
  if destination[-1,1] == "/"
138
138
  copy(source, File.join(destination, source))
139
139
  else
140
140
  copy(source, destination)
141
141
  end
142
142
  elsif fileinfo.symlink?
143
- copy(source, destination)
143
+ copy(source, File.join(destination, source))
144
144
  else
145
145
  # Copy all files from 'path' into staging_path
146
146
  Find.find(source) do |path|
@@ -157,8 +157,17 @@ class FPM::Package::Dir < FPM::Package
157
157
  def copy(source, destination)
158
158
  logger.debug("Copying path", :source => source, :destination => destination)
159
159
  directory = File.dirname(destination)
160
- if !File.directory?(directory)
160
+ # lstat to follow symlinks
161
+ dstat = File.stat(directory) rescue nil
162
+ if dstat.nil?
161
163
  FileUtils.mkdir_p(directory)
164
+ elsif dstat.directory?
165
+ # do nothing, it's already a directory!
166
+ else
167
+ # It exists and is not a directory. This is probably a user error or a bug.
168
+ readable_path = directory.gsub(staging_path, "")
169
+ logger.error("You wanted to copy a file into a directory, but that's not a directory, it's a file!", :path => readable_path, :stat => dstat)
170
+ raise FPM::InvalidPackageConfiguration, "Tried to treat #{readable_path} like a directory, but it's a file!"
162
171
  end
163
172
 
164
173
  if File.directory?(source)
@@ -194,27 +203,5 @@ class FPM::Package::Dir < FPM::Package
194
203
  copy_metadata(source, destination)
195
204
  end # def copy
196
205
 
197
- def copy_metadata(source, destination)
198
- source_stat = File::lstat(source)
199
- dest_stat = File::lstat(destination)
200
-
201
- # If this is a hard-link, there's no metadata to copy.
202
- # If this is a symlink, what it points to hasn't been copied yet.
203
- return if source_stat.ino == dest_stat.ino || dest_stat.symlink?
204
-
205
- File.utime(source_stat.atime, source_stat.mtime, destination)
206
- mode = source_stat.mode
207
- begin
208
- File.lchown(source_stat.uid, source_stat.gid, destination)
209
- rescue Errno::EPERM
210
- # clear setuid/setgid
211
- mode &= 01777
212
- end
213
-
214
- unless source_stat.symlink?
215
- File.chmod(mode, destination)
216
- end
217
- end # def copy_metadata
218
-
219
206
  public(:input, :output)
220
207
  end # class FPM::Package::Dir
@@ -4,4 +4,10 @@ require "backports"
4
4
  # Empty Package type. For strict/meta/virtual package creation
5
5
 
6
6
  class FPM::Package::Empty < FPM::Package
7
+ def output(output_path)
8
+ logger.warn("Your package has gone into the void.")
9
+ end
10
+ def to_s(fmt)
11
+ return ""
12
+ end
7
13
  end
@@ -58,7 +58,7 @@ class FPM::Package::Gem < FPM::Package
58
58
 
59
59
  def download_if_necessary(gem, gem_version)
60
60
  path = gem
61
- if !File.exists?(path)
61
+ if !File.exist?(path)
62
62
  path = download(gem, gem_version)
63
63
  end
64
64
 
@@ -114,7 +114,7 @@ class FPM::Package::Gem < FPM::Package
114
114
  # where missing 'build' number prevents correct dependency resolution by target
115
115
  # package manager. Ie. for dpkg 1.1 != 1.1.0
116
116
  m = spec.version.to_s.scan(/(\d+)\.?/)
117
- self.version = m.flatten.fill('0', m.length..2).join('.')
117
+ self.version = m.flatten.fill('0', m.length..2).join('.')
118
118
 
119
119
  self.vendor = spec.author
120
120
  self.url = spec.homepage
@@ -132,7 +132,7 @@ class FPM::Package::Gem < FPM::Package
132
132
  self.description = description_options.find { |d| !(d.nil? or d.strip.empty?) }
133
133
 
134
134
  # Upstream rpms seem to do this, might as well share.
135
- # TODO(sissel): Figure out how to hint this only to rpm?
135
+ # TODO(sissel): Figure out how to hint this only to rpm?
136
136
  # maybe something like attributes[:rpm_provides] for rpm specific stuff?
137
137
  # Or just ignore it all together.
138
138
  #self.provides << "rubygem(#{self.name})"
@@ -213,7 +213,7 @@ class FPM::Package::Gem < FPM::Package
213
213
  end
214
214
  end
215
215
  end # def install_to_staging
216
-
216
+
217
217
  # Sanitize package name.
218
218
  # This prefixes the package name with 'rubygem' (but depends on the attribute
219
219
  # :gem_package_name_prefix
@@ -72,7 +72,7 @@ class FPM::Package::NPM < FPM::Package
72
72
  end
73
73
 
74
74
  self.description = info["description"]
75
- # Supposedly you can upload a package for npm with no author/author email
75
+ # Supposedly you can upload a package for npm with no author/author email
76
76
  # so I'm being safer with this. Author can also be a hash or a string
77
77
  self.vendor = "Unknown <unknown@unknown.unknown>"
78
78
  if info.include?("author")
@@ -91,7 +91,7 @@ class FPM::Package::NPM < FPM::Package
91
91
  # 'npm install express' it installs dependencies (like 'connect')
92
92
  # to: node_modules/express/node_modules/connect/...
93
93
  #
94
- # To that end, I don't think we necessarily need to include
94
+ # To that end, I don't think we necessarily need to include
95
95
  # any automatic dependency information since every 'npm install'
96
96
  # is fully self-contained. That's why you don't see any bother, yet,
97
97
  # to include the package's dependencies in here.
@@ -21,7 +21,7 @@ class FPM::Package::OSXpkg < FPM::Package
21
21
  POSTINSTALL_ACTIONS = [ "logout", "restart", "shutdown" ]
22
22
  OWNERSHIP_OPTIONS = ["recommended", "preserve", "preserve-other"]
23
23
 
24
- option "--identifier-prefix", "IDENTIFIER_PREFIX",
24
+ option "--identifier-prefix", "IDENTIFIER_PREFIX",
25
25
  "Reverse domain prefix prepended to package identifier, " \
26
26
  "ie. 'org.great.my'. If this is omitted, the identifer " \
27
27
  "will be the package name."
@@ -87,12 +87,12 @@ class FPM::Package::OSXpkg < FPM::Package
87
87
  # scripts are required to be executable
88
88
  File.chmod(0755, pkgscript)
89
89
  end
90
- end
90
+ end
91
91
  end # def write_scripts
92
92
 
93
93
  # Returns path of a processed template PackageInfo given to 'pkgbuild --info'
94
94
  # note: '--info' is undocumented:
95
- # http://managingosx.wordpress.com/2012/07/05/stupid-tricks-with-pkgbuild
95
+ # http://managingosx.wordpress.com/2012/07/05/stupid-tricks-with-pkgbuild
96
96
  def pkginfo_template_path
97
97
  pkginfo_template = Tempfile.open("fpm-PackageInfo")
98
98
  pkginfo_data = template("osxpkg.erb").result(binding)
@@ -0,0 +1,124 @@
1
+ require "erb"
2
+ require "fpm/namespace"
3
+ require "fpm/package"
4
+ require "fpm/errors"
5
+ require "fpm/util"
6
+
7
+ class FPM::Package::P5P < FPM::Package
8
+
9
+ option "--user", "USER",
10
+ "Set the user to USER in the prototype files.",
11
+ :default => 'root'
12
+
13
+ option "--group", "GROUP",
14
+ "Set the group to GROUP in the prototype file.",
15
+ :default => 'root'
16
+
17
+ option "--zonetype", "ZONETYPE",
18
+ "Set the allowed zone types (global, nonglobal, both)",
19
+ :default => 'value=global value=nonglobal' do |value|
20
+ case @value
21
+ when "both"
22
+ value = "value=global value=nonglobal"
23
+ else
24
+ value = "value=#{value}"
25
+ end
26
+ end # value
27
+
28
+ option "--publisher", "PUBLISHER",
29
+ "Set the publisher name for the repository",
30
+ :default => 'FPM'
31
+
32
+ option "--lint" , :flag, "Check manifest with pkglint",
33
+ :default => true
34
+
35
+ option "--validate", :flag, "Validate with pkg install",
36
+ :default => true
37
+
38
+ def architecture
39
+ case @architecture
40
+ when nil, "native"
41
+ @architecture = %x{uname -p}.chomp
42
+ when "all"
43
+ @architecture = 'i386 value=sparc'
44
+ end
45
+
46
+ return @architecture
47
+ end # def architecture
48
+
49
+ def output(output_path)
50
+
51
+ # Fixup the category to an acceptable solaris category
52
+ case @category
53
+ when nil, "default"
54
+ @category = 'Applications/System Utilities'
55
+ end
56
+
57
+ # Manifest Filename
58
+ manifest_fn = build_path("#{name}.p5m")
59
+
60
+ # Generate a package manifest.
61
+ pkg_generate = safesystemout("pkgsend", "generate", "#{staging_path}")
62
+ File.write(build_path("#{name}.p5m.1"), pkg_generate)
63
+
64
+ # Add necessary metadata to the generated manifest.
65
+ metadata_template = template("p5p_metadata.erb").result(binding)
66
+ File.write(build_path("#{name}.mog"), metadata_template)
67
+
68
+ # Combine template and filelist; allow user to edit before proceeding
69
+ File.open(manifest_fn, "w") do |manifest|
70
+ manifest.write metadata_template
71
+ manifest.write pkg_generate
72
+ end
73
+ edit_file(manifest_fn) if attributes[:edit?]
74
+
75
+ # Execute the transmogrification on the manifest
76
+ pkg_mogrify = safesystemout("pkgmogrify", manifest_fn)
77
+ File.write(build_path("#{name}.p5m.2"), pkg_mogrify)
78
+ safesystem("cp", build_path("#{name}.p5m.2"), manifest_fn)
79
+
80
+ # Evaluate dependencies.
81
+ if !attributes[:no_auto_depends?]
82
+ pkgdepend_gen = safesystemout("pkgdepend", "generate", "-md", "#{staging_path}", manifest_fn)
83
+ File.write(build_path("#{name}.p5m.3"), pkgdepend_gen)
84
+
85
+ # Allow user to review added dependencies
86
+ edit_file(build_path("#{name}.p5m.3")) if attributes[:edit?]
87
+
88
+ safesystem("pkgdepend", "resolve", "-m", build_path("#{name}.p5m.3"))
89
+ safesystem("cp", build_path("#{name}.p5m.3.res"), manifest_fn)
90
+ end
91
+
92
+ # Final format of manifest
93
+ safesystem("pkgfmt", manifest_fn)
94
+
95
+ # Final edit for lint check and packaging
96
+ edit_file(manifest_fn) if attributes[:edit?]
97
+
98
+ # Add any facets or actuators that are needed.
99
+ # TODO(jcraig): add manpage actuator to enable install wo/ man pages
100
+
101
+ # Verify the package.
102
+ if attributes[:p5p_lint] then
103
+ safesystem("pkglint", manifest_fn)
104
+ end
105
+
106
+ # Publish the package.
107
+ repo_path = build_path("#{name}_repo")
108
+ safesystem("pkgrepo", "create", repo_path)
109
+ safesystem("pkgrepo", "set", "-s", repo_path, "publisher/prefix=#{attributes[:p5p_publisher]}")
110
+ safesystem("pkgsend", "-s", repo_path,
111
+ "publish", "-d", "#{staging_path}", "#{build_path}/#{name}.p5m")
112
+ safesystem("pkgrecv", "-s", repo_path, "-a",
113
+ "-d", build_path("#{name}.p5p"), name)
114
+
115
+ # Test the package
116
+ if attributes[:p5p_validate] then
117
+ safesystem("pkg", "install", "-nvg", build_path("#{name}.p5p"), name)
118
+ end
119
+
120
+ # Cleanup
121
+ safesystem("mv", build_path("#{name}.p5p"), output_path)
122
+
123
+ end # def output
124
+ end # class FPM::Package::IPS