fpm-itchio 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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELIST +629 -0
  3. data/CONTRIBUTORS +26 -0
  4. data/LICENSE +21 -0
  5. data/bin/fpm +8 -0
  6. data/lib/fpm.rb +18 -0
  7. data/lib/fpm/command.rb +642 -0
  8. data/lib/fpm/errors.rb +4 -0
  9. data/lib/fpm/namespace.rb +4 -0
  10. data/lib/fpm/package.rb +524 -0
  11. data/lib/fpm/package/cpan.rb +378 -0
  12. data/lib/fpm/package/deb.rb +887 -0
  13. data/lib/fpm/package/dir.rb +207 -0
  14. data/lib/fpm/package/empty.rb +13 -0
  15. data/lib/fpm/package/gem.rb +224 -0
  16. data/lib/fpm/package/npm.rb +120 -0
  17. data/lib/fpm/package/osxpkg.rb +164 -0
  18. data/lib/fpm/package/p5p.rb +124 -0
  19. data/lib/fpm/package/pacman.rb +397 -0
  20. data/lib/fpm/package/pear.rb +117 -0
  21. data/lib/fpm/package/pkgin.rb +35 -0
  22. data/lib/fpm/package/puppet.rb +120 -0
  23. data/lib/fpm/package/pyfpm/__init__.py +1 -0
  24. data/lib/fpm/package/pyfpm/get_metadata.py +104 -0
  25. data/lib/fpm/package/python.rb +317 -0
  26. data/lib/fpm/package/rpm.rb +583 -0
  27. data/lib/fpm/package/sh.rb +69 -0
  28. data/lib/fpm/package/solaris.rb +95 -0
  29. data/lib/fpm/package/tar.rb +74 -0
  30. data/lib/fpm/package/virtualenv.rb +145 -0
  31. data/lib/fpm/package/zip.rb +63 -0
  32. data/lib/fpm/rake_task.rb +59 -0
  33. data/lib/fpm/util.rb +253 -0
  34. data/lib/fpm/version.rb +3 -0
  35. data/templates/deb.erb +52 -0
  36. data/templates/deb/changelog.erb +5 -0
  37. data/templates/deb/ldconfig.sh.erb +13 -0
  38. data/templates/deb/postinst_upgrade.sh.erb +62 -0
  39. data/templates/deb/postrm_upgrade.sh.erb +46 -0
  40. data/templates/deb/preinst_upgrade.sh.erb +41 -0
  41. data/templates/deb/prerm_upgrade.sh.erb +39 -0
  42. data/templates/osxpkg.erb +11 -0
  43. data/templates/p5p_metadata.erb +12 -0
  44. data/templates/pacman.erb +47 -0
  45. data/templates/pacman/INSTALL.erb +41 -0
  46. data/templates/puppet/package.pp.erb +34 -0
  47. data/templates/puppet/package/remove.pp.erb +13 -0
  48. data/templates/rpm.erb +261 -0
  49. data/templates/rpm/filesystem_list +14514 -0
  50. data/templates/sh.erb +367 -0
  51. data/templates/solaris.erb +15 -0
  52. metadata +265 -0
@@ -0,0 +1,59 @@
1
+ require "ostruct"
2
+ require "rake"
3
+ require "rake/tasklib"
4
+
5
+ class FPM::RakeTask < Rake::TaskLib
6
+ attr_reader :options
7
+
8
+ def initialize(package_name, opts = {}, &block)
9
+ @options = OpenStruct.new(:name => package_name.to_s)
10
+ @source, @target = opts.values_at(:source, :target).map(&:to_s)
11
+ @directory = File.expand_path(opts[:directory].to_s)
12
+
13
+ (@source.empty? || @target.empty? || options.name.empty?) &&
14
+ abort("Must specify package name, source and output")
15
+
16
+ desc "Package #{@name}" unless ::Rake.application.last_comment
17
+
18
+ task(options.name) do |_, task_args|
19
+ block.call(*[options, task_args].first(block.arity)) if block_given?
20
+ abort("Must specify args") unless options.respond_to?(:args)
21
+ @args = options.delete_field(:args)
22
+ run_cli
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def parsed_options
29
+ options.to_h.map do |option, value|
30
+ opt = option.to_s.tr("_", "-")
31
+
32
+ case
33
+ when value.is_a?(String), value.is_a?(Symbol)
34
+ %W(--#{opt} #{value})
35
+ when value.is_a?(Array)
36
+ value.map { |v| %W(--#{opt} #{v}) }
37
+ when value.is_a?(TrueClass)
38
+ "--#{opt}"
39
+ when value.is_a?(FalseClass)
40
+ "--no-#{opt}"
41
+ else
42
+ fail TypeError, "Unexpected type: #{value.class}"
43
+ end
44
+ end
45
+ end
46
+
47
+ def run_cli
48
+ require "fpm"
49
+ require "fpm/command"
50
+
51
+ args = %W(-t #{@target} -s #{@source} -C #{@directory})
52
+ args << parsed_options
53
+ args << @args
54
+
55
+ args.flatten!.compact!
56
+
57
+ exit(FPM::Command.new("fpm").run(args) || 0)
58
+ end
59
+ end
@@ -0,0 +1,253 @@
1
+ require "fpm/namespace"
2
+ require "childprocess"
3
+ require "ffi"
4
+
5
+ # Some utility functions
6
+ module FPM::Util
7
+ extend FFI::Library
8
+ ffi_lib FFI::Library::LIBC
9
+
10
+ # mknod is __xmknod in glibc a wrapper around mknod to handle
11
+ # various stat struct formats. See bits/stat.h in glibc source
12
+ begin
13
+ attach_function :mknod, :mknod, [:string, :uint, :ulong], :int
14
+ rescue FFI::NotFoundError
15
+ # glibc/io/xmknod.c int __xmknod (int vers, const char *path, mode_t mode, dev_t *dev)
16
+ attach_function :xmknod, :__xmknod, [:int, :string, :uint, :pointer], :int
17
+ end
18
+
19
+ # Raised if safesystem cannot find the program to run.
20
+ class ExecutableNotFound < StandardError; end
21
+
22
+ # Raised if a safesystem program exits nonzero
23
+ class ProcessFailed < StandardError; end
24
+
25
+ # Is the given program in the system's PATH?
26
+ def program_in_path?(program)
27
+ # return false if path is not set
28
+ return false unless ENV['PATH']
29
+ # Scan path to find the executable
30
+ # Do this to help the user get a better error message.
31
+ envpath = ENV["PATH"].split(":")
32
+ return envpath.select { |p| File.executable?(File.join(p, program)) }.any?
33
+ end # def program_in_path
34
+
35
+ def program_exists?(program)
36
+ # Scan path to find the executable
37
+ # Do this to help the user get a better error message.
38
+ return program_in_path?(program) if !program.include?("/")
39
+ return File.executable?(program)
40
+ end # def program_exists?
41
+
42
+ def default_shell
43
+ shell = ENV["SHELL"]
44
+ return "/bin/sh" if shell.nil? || shell.empty?
45
+ return shell
46
+ end
47
+
48
+ # Run a command safely in a way that gets reports useful errors.
49
+ def safesystem(*args)
50
+ # ChildProcess isn't smart enough to run a $SHELL if there's
51
+ # spaces in the first arg and there's only 1 arg.
52
+ if args.size == 1
53
+ args = [ default_shell, "-c", args[0] ]
54
+ end
55
+ program = args[0]
56
+
57
+ if !program_exists?(program)
58
+ raise ExecutableNotFound.new(program)
59
+ end
60
+
61
+ logger.debug("Running command", :args => args)
62
+
63
+ # Create a pair of pipes to connect the
64
+ # invoked process to the cabin logger
65
+ stdout_r, stdout_w = IO.pipe
66
+ stderr_r, stderr_w = IO.pipe
67
+
68
+ process = ChildProcess.build(*args)
69
+ process.io.stdout = stdout_w
70
+ process.io.stderr = stderr_w
71
+
72
+ process.start
73
+ stdout_w.close; stderr_w.close
74
+ logger.debug('Process is running', :pid => process.pid)
75
+ # Log both stdout and stderr as 'info' because nobody uses stderr for
76
+ # actually reporting errors and as a result 'stderr' is a misnomer.
77
+ logger.pipe(stdout_r => :info, stderr_r => :info)
78
+
79
+ process.wait
80
+ success = (process.exit_code == 0)
81
+
82
+ if !success
83
+ raise ProcessFailed.new("#{program} failed (exit code #{process.exit_code})" \
84
+ ". Full command was:#{args.inspect}")
85
+ end
86
+ return success
87
+ end # def safesystem
88
+
89
+ # Run a command safely in a way that captures output and status.
90
+ def safesystemout(*args)
91
+ if args.size == 1
92
+ args = [ ENV["SHELL"], "-c", args[0] ]
93
+ end
94
+ program = args[0]
95
+
96
+ if !program.include?("/") and !program_in_path?(program)
97
+ raise ExecutableNotFound.new(program)
98
+ end
99
+
100
+ logger.debug("Running command", :args => args)
101
+
102
+ stdout_r, stdout_w = IO.pipe
103
+ stderr_r, stderr_w = IO.pipe
104
+
105
+ process = ChildProcess.build(*args)
106
+ process.io.stdout = stdout_w
107
+ process.io.stderr = stderr_w
108
+
109
+ process.start
110
+ stdout_w.close; stderr_w.close
111
+ stdout_r_str = stdout_r.read
112
+ stdout_r.close; stderr_r.close
113
+ logger.debug("Process is running", :pid => process.pid)
114
+
115
+ process.wait
116
+ success = (process.exit_code == 0)
117
+
118
+ if !success
119
+ raise ProcessFailed.new("#{program} failed (exit code #{process.exit_code})" \
120
+ ". Full command was:#{args.inspect}")
121
+ end
122
+
123
+ return stdout_r_str
124
+ end # def safesystemout
125
+
126
+ # Get the recommended 'tar' command for this platform.
127
+ def tar_cmd
128
+ # Rely on gnu tar for solaris and OSX.
129
+ case %x{uname -s}.chomp
130
+ when "SunOS"
131
+ return "gtar"
132
+ when "Darwin"
133
+ # Try running gnutar, it was renamed(??) in homebrew to 'gtar' at some point, I guess? I don't know.
134
+ ["gnutar", "gtar"].each do |tar|
135
+ system("#{tar} > /dev/null 2> /dev/null")
136
+ return tar unless $?.exitstatus == 127
137
+ end
138
+ when "FreeBSD"
139
+ # use gnutar instead
140
+ return "gtar"
141
+ else
142
+ return "tar"
143
+ end
144
+ end # def tar_cmd
145
+
146
+ # wrapper around mknod ffi calls
147
+ def mknod_w(path, mode, dev)
148
+ rc = -1
149
+ case %x{uname -s}.chomp
150
+ when 'Linux'
151
+ # bits/stat.h #define _MKNOD_VER_LINUX 0
152
+ rc = xmknod(0, path, mode, FFI::MemoryPointer.new(dev))
153
+ else
154
+ rc = mknod(path, mode, dev)
155
+ end
156
+ rc
157
+ end
158
+
159
+ def copy_metadata(source, destination)
160
+ source_stat = File::lstat(source)
161
+ dest_stat = File::lstat(destination)
162
+
163
+ # If this is a hard-link, there's no metadata to copy.
164
+ # If this is a symlink, what it points to hasn't been copied yet.
165
+ return if source_stat.ino == dest_stat.ino || dest_stat.symlink?
166
+
167
+ File.utime(source_stat.atime, source_stat.mtime, destination)
168
+ mode = source_stat.mode
169
+ begin
170
+ File.lchown(source_stat.uid, source_stat.gid, destination)
171
+ rescue Errno::EPERM
172
+ # clear setuid/setgid
173
+ mode &= 01777
174
+ end
175
+
176
+ unless source_stat.symlink?
177
+ File.chmod(mode, destination)
178
+ end
179
+ end # def copy_metadata
180
+
181
+
182
+ def copy_entry(src, dst, preserve=false, remove_destination=false)
183
+ case File.ftype(src)
184
+ when 'fifo', 'characterSpecial', 'blockSpecial', 'socket'
185
+ st = File.stat(src)
186
+ rc = mknod_w(dst, st.mode, st.dev)
187
+ raise SystemCallError.new("mknod error", FFI.errno) if rc == -1
188
+ when 'directory'
189
+ FileUtils.mkdir(dst) unless File.exists? dst
190
+ else
191
+ # if the file with the same dev and inode has been copied already -
192
+ # hard link it's copy to `dst`, otherwise make an actual copy
193
+ st = File.lstat(src)
194
+ known_entry = copied_entries[[st.dev, st.ino]]
195
+ if known_entry
196
+ FileUtils.ln(known_entry, dst)
197
+ else
198
+ FileUtils.copy_entry(src, dst, preserve=preserve,
199
+ remove_destination=remove_destination)
200
+ copied_entries[[st.dev, st.ino]] = dst
201
+ end
202
+ end # else...
203
+ end # def copy_entry
204
+
205
+ def copied_entries
206
+ # TODO(sissel): I wonder that this entry-copy knowledge needs to be put
207
+ # into a separate class/module. As is, calling copy_entry the same way
208
+ # in slightly different contexts will result in weird or bad behavior.
209
+ # What I mean is if we do:
210
+ # pkg = FPM::Package::Dir...
211
+ # pkg.output()...
212
+ # pkg.output()...
213
+ # The 2nd output call will fail or behave weirdly because @copied_entries
214
+ # is already populated. even though this is anew round of copying.
215
+ return @copied_entries ||= {}
216
+ end # def copied_entries
217
+
218
+ def expand_pessimistic_constraints(constraint)
219
+ name, op, version = constraint.split(/\s+/)
220
+
221
+ if op == '~>'
222
+
223
+ new_lower_constraint = "#{name} >= #{version}"
224
+
225
+ version_components = version.split('.').collect { |v| v.to_i }
226
+
227
+ version_prefix = version_components[0..-3].join('.')
228
+ portion_to_work_with = version_components.last(2)
229
+
230
+ prefix = ''
231
+ unless version_prefix.empty?
232
+ prefix = version_prefix + '.'
233
+ end
234
+
235
+ one_to_increment = portion_to_work_with[0].to_i
236
+ incremented = one_to_increment + 1
237
+
238
+ new_version = ''+ incremented.to_s + '.0'
239
+
240
+ upper_version = prefix + new_version
241
+
242
+ new_upper_constraint = "#{name} < #{upper_version}"
243
+
244
+ return [new_lower_constraint,new_upper_constraint]
245
+ else
246
+ return [constraint]
247
+ end
248
+ end #def expand_pesimistic_constraints
249
+
250
+ def logger
251
+ @logger ||= Cabin::Channel.get
252
+ end # def logger
253
+ end # module FPM::Util
@@ -0,0 +1,3 @@
1
+ module FPM
2
+ VERSION = "1.4.0"
3
+ end
@@ -0,0 +1,52 @@
1
+ Package: <%= name %>
2
+ Version: <%= "#{epoch}:" if epoch %><%= version %><%= "-" + iteration.to_s if iteration %>
3
+ License: <%= license %>
4
+ <% if !vendor.nil? and !vendor.empty? -%>
5
+ Vendor: <%= vendor %>
6
+ <% end -%>
7
+ Architecture: <%= architecture %>
8
+ Maintainer: <%= maintainer %>
9
+ Installed-Size: <%= attributes[:deb_installed_size] %>
10
+ <% if !dependencies.empty? and !attributes[:no_depends?] -%>
11
+ Depends: <%= dependencies.collect { |d| fix_dependency(d) }.flatten.join(", ") %>
12
+ <% end -%>
13
+ <% if !conflicts.empty? -%>
14
+ Conflicts: <%= conflicts.collect { |d| fix_dependency(d) }.flatten.join(", ") %>
15
+ <% end -%>
16
+ <% if attributes[:deb_breaks] -%>
17
+ Breaks: <%= attributes[:deb_breaks].collect { |d| fix_dependency(d) }.flatten.join(", ") %>
18
+ <% end -%>
19
+ <% if attributes[:deb_pre_depends_given?] -%>
20
+ Pre-Depends: <%= attributes[:deb_pre_depends].collect { |d| fix_dependency(d) }.flatten.join(", ") %>
21
+ <% end -%>
22
+ <% if attributes[:deb_build_depends_given?] -%>
23
+ Build-Depends: <%= attributes[:deb_build_depends].collect { |d| fix_dependency(d) }.flatten.join(", ") %>
24
+ <% end -%>
25
+ <% if !provides.empty? -%>
26
+ <%# Turn each provides from 'foo = 123' to simply 'foo' because Debian :\ -%>
27
+ <%# http://www.debian.org/doc/debian-policy/ch-relationships.html -%>
28
+ Provides: <%= provides.map {|p| p.split(" ").first}.join ", " %>
29
+ <% end -%>
30
+ <% if !replaces.empty? -%>
31
+ Replaces: <%= replaces.join(", ") %>
32
+ <% end -%>
33
+ <% if attributes[:deb_recommends_given?] -%>
34
+ Recommends: <%= attributes[:deb_recommends].collect { |d| fix_dependency(d) }.flatten.join(", ") %>
35
+ <% end -%>
36
+ <% if attributes[:deb_suggests_given?] -%>
37
+ Suggests: <%= attributes[:deb_suggests].collect { |d| fix_dependency(d) }.flatten.join(", ") %>
38
+ <% end -%>
39
+ Section: <%= category %>
40
+ Priority: <%= attributes[:deb_priority] %>
41
+ Homepage: <%= url or "http://nourlgiven.example.com/" %>
42
+ <% lines = (description or "no description given").split("\n") -%>
43
+ <% firstline, *remainder = lines -%>
44
+ Description: <%= firstline %>
45
+ <% if remainder.any? -%>
46
+ <%= remainder.collect { |l| l =~ /^ *$/ ? " ." : " #{l}" }.join("\n") %>
47
+ <% end -%>
48
+ <% if attributes[:deb_field_given?] -%>
49
+ <% attributes[:deb_field].each do |field, value| -%>
50
+ <%= field %>: <%= value %>
51
+ <% end -%>
52
+ <% end -%>
@@ -0,0 +1,5 @@
1
+ <%= name %> (<%= "#{epoch}:" if epoch %><%= version %><%= "-" + iteration.to_s if iteration %>) whatever; urgency=medium
2
+
3
+ * Package created with FPM.
4
+
5
+ -- <%= maintainer %> <%= Time.now.strftime("%a, %d %b %Y %T %z") %>
@@ -0,0 +1,13 @@
1
+ #!/bin/sh
2
+ # This script is automatically added by fpm when you specify
3
+ # conditions that usually require running ldconfig upon
4
+ # package installation and removal.
5
+ #
6
+ # For example, if you set '--deb-shlibs' in creating your package,
7
+ # fpm will use this script if you don't provide your own --after-install or
8
+ # --after-remove
9
+ set -e
10
+
11
+ case $1 in
12
+ configure|remove) ldconfig ;;
13
+ esac
@@ -0,0 +1,62 @@
1
+ #!/bin/sh
2
+ after_upgrade() {
3
+ <%# Making sure that at least one command is in the function -%>
4
+ <%# avoids a lot of potential errors, including the case that -%>
5
+ <%# the script is non-empty, but just whitespace and/or comments -%>
6
+ :
7
+ <% if script?(:after_upgrade) -%>
8
+ <%= script(:after_upgrade) %>
9
+ <% end -%>
10
+
11
+ <% if attributes[:deb_systemd] -%>
12
+ systemctl --system daemon-reload >/dev/null || true
13
+ if ! systemctl is-enabled <%= attributes[:deb_systemd] %> >/dev/null
14
+ then
15
+ systemctl enable <%= attributes[:deb_systemd] %> >/dev/null || true
16
+ systemctl start <%= attributes[:deb_systemd] %> >/dev/null || true
17
+ <% if attributes[:deb_systemd_restart_after_upgrade?] -%>
18
+ else
19
+ systemctl restart <%= attributes[:deb_systemd] %> >/dev/null || true
20
+ <% end -%>
21
+ fi
22
+ <% end -%>
23
+ }
24
+
25
+ after_install() {
26
+ <%# Making sure that at least one command is in the function -%>
27
+ <%# avoids a lot of potential errors, including the case that -%>
28
+ <%# the script is non-empty, but just whitespace and/or comments -%>
29
+ :
30
+ <% if script?(:after_install) -%>
31
+ <%= script(:after_install) %>
32
+ <% end -%>
33
+
34
+ <% if attributes[:deb_systemd] -%>
35
+ systemctl --system daemon-reload >/dev/null || true
36
+ systemctl enable <%= attributes[:deb_systemd] %> >/dev/null || true
37
+ systemctl start <%= attributes[:deb_systemd] %> >/dev/null || true
38
+ <% end -%>
39
+ }
40
+
41
+ if [ "${1}" = "configure" -a -z "${2}" ] || \
42
+ [ "${1}" = "abort-remove" ]
43
+ then
44
+ # "after install" here
45
+ # "abort-remove" happens when the pre-removal script failed.
46
+ # In that case, this script, which should be idemptoent, is run
47
+ # to ensure a clean roll-back of the removal.
48
+ after_install
49
+ elif [ "${1}" = "configure" -a -n "${2}" ]
50
+ then
51
+ upgradeFromVersion="${2}"
52
+ # "after upgrade" here
53
+ # NOTE: This slot is also used when deb packages are removed,
54
+ # but their config files aren't, but a newer version of the
55
+ # package is installed later, called "Config-Files" state.
56
+ # basically, that still looks a _lot_ like an upgrade to me.
57
+ after_upgrade "${2}"
58
+ elif echo "${1}" | grep -E -q "(abort|fail)"
59
+ then
60
+ echo "Failed to install before the post-installation script was run." >&2
61
+ exit 1
62
+ fi