fpm 0.3.11 → 0.4.0pre1

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 (43) hide show
  1. data/CHANGELIST +15 -0
  2. data/bin/fpm +2 -15
  3. data/lib/fpm.rb +5 -12
  4. data/lib/fpm/command.rb +323 -0
  5. data/lib/fpm/errors.rb +1 -0
  6. data/lib/fpm/namespace.rb +2 -11
  7. data/lib/fpm/package.rb +255 -100
  8. data/lib/fpm/package/deb.rb +367 -0
  9. data/lib/fpm/package/dir.rb +86 -0
  10. data/lib/fpm/package/gem.rb +162 -0
  11. data/lib/fpm/{source → package}/npm.rb +3 -3
  12. data/lib/fpm/package/pear.rb +41 -0
  13. data/lib/fpm/{target → package}/puppet.rb +1 -3
  14. data/lib/fpm/{source → package}/pyfpm/__init__.py +0 -0
  15. data/lib/fpm/package/pyfpm/__init__.pyc +0 -0
  16. data/lib/fpm/{source → package}/pyfpm/get_metadata.py +15 -3
  17. data/lib/fpm/package/pyfpm/get_metadata.pyc +0 -0
  18. data/lib/fpm/package/python.rb +125 -0
  19. data/lib/fpm/package/rpm.rb +132 -0
  20. data/lib/fpm/{target → package}/solaris.rb +3 -2
  21. data/lib/fpm/package/tar.rb +62 -0
  22. data/lib/fpm/util.rb +56 -7
  23. data/templates/deb.erb +12 -12
  24. data/templates/rpm.erb +32 -38
  25. data/templates/solaris.erb +1 -1
  26. metadata +119 -78
  27. data/lib/fpm/builder.rb +0 -220
  28. data/lib/fpm/flags.rb +0 -20
  29. data/lib/fpm/program.rb +0 -273
  30. data/lib/fpm/rubyfixes.rb +0 -11
  31. data/lib/fpm/source.rb +0 -155
  32. data/lib/fpm/source/dir.rb +0 -59
  33. data/lib/fpm/source/gem.rb +0 -162
  34. data/lib/fpm/source/python.rb +0 -137
  35. data/lib/fpm/source/rpm.rb +0 -28
  36. data/lib/fpm/source/tar.rb +0 -50
  37. data/lib/fpm/target/deb.rb +0 -184
  38. data/lib/fpm/target/rpm.rb +0 -68
  39. data/lib/rpm/header.rb +0 -89
  40. data/lib/rpm/lead.rb +0 -48
  41. data/lib/rpm/namespace.rb +0 -1
  42. data/lib/rpm/rpmfile.rb +0 -81
  43. data/lib/rpm/tag.rb +0 -304
data/lib/fpm/rubyfixes.rb DELETED
@@ -1,11 +0,0 @@
1
- # Ruby 1.8.7 added String#start_with? - monkeypatch the
2
- # String class if it isn't supported (<= ruby 1.8.6)
3
- if !String.instance_methods.include?("start_with?")
4
- class String
5
- public
6
- def start_with?(str)
7
- return self[0 .. (str.length-1)] == str
8
- end
9
- end
10
- end
11
-
data/lib/fpm/source.rb DELETED
@@ -1,155 +0,0 @@
1
- require "fpm/namespace"
2
- require "fpm/util"
3
-
4
- # Abstract class for a "thing to build a package from"
5
- class FPM::Source
6
- # standard package metadata
7
- %w(
8
- name
9
- version
10
- iteration
11
- architecture
12
- maintainer
13
- category
14
- url
15
- description
16
- ).each do |attr|
17
- attr = :"#{attr}"
18
- define_method(attr) { self[attr] }
19
- define_method(:"#{attr}=") { |v| self[attr] = v}
20
- end
21
-
22
- def dependencies
23
- self[:dependencies] ||= []
24
- end
25
-
26
- attr_reader :paths
27
- attr_accessor :root
28
-
29
- def initialize(paths, root, params={})
30
- @logger = Logger.new(STDERR)
31
- @logger.level = $DEBUG ? Logger::DEBUG : Logger::WARN
32
-
33
- @paths = paths
34
- @root = root
35
-
36
- self[:suffix] = params[:suffix]
37
- self[:settings] = params[:settings]
38
-
39
- get_source(params)
40
- get_metadata
41
-
42
- # override the inferred data with the passed-in data
43
- params.each do |k,v|
44
- self[k] = v if v != nil
45
- end
46
- end # def initialize
47
-
48
- # this method should take the paths and root and infer as much
49
- # about the package as it can.
50
- def get_metadata
51
- raise NoMethodError,
52
- "Please subclass FPM::Source and define get_metadata"
53
- end # def get_metadata
54
-
55
- # This method should be overridden by package sources that need to do any
56
- # kind of fetching.
57
- def get_source(params)
58
- # noop by default
59
- end # def get_source
60
-
61
- def make_tarball!(tar_path, builddir)
62
- raise NoMethodError,
63
- "Please subclass FPM::Source and define make_tarball!(tar_path)"
64
- end
65
-
66
- def metadata
67
- @metadata ||= {}
68
- end
69
-
70
- def [](key)
71
- metadata[key.to_sym]
72
- end
73
-
74
- def []=(key,val)
75
- metadata[key.to_sym] = val
76
- end
77
-
78
- # MySourceClass.new('/tmp/build').package(FPM::Deb).assemble(params)
79
- def package(pkg_cls)
80
- pkg_cls.new(self)
81
- end
82
-
83
- private
84
- def tar(output, paths, chdir=".")
85
- dirs = []
86
-
87
- # Include all directory entries at the top of the tarball
88
- paths = [ paths ] if paths.is_a? String
89
- paths.each do |path|
90
- while path != "/" and path != "."
91
- dirs << path if !dirs.include?(path)
92
- path = File.dirname(path)
93
- end
94
- end # paths.each
95
-
96
- # Want directories to be sorted thusly: [ "/usr", "/usr/bin" ]
97
- # Why? tar and some package managers sometimes fail if the tar is created
98
- # like: [ "/opt/fizz", "/opt" ]
99
- # dpkg -i will fail if /opt doesn't exist, sorting it by length ensures
100
- # /opt is created before /opt/fizz.
101
- dirs.sort! { |a,b| a.size <=> b.size }
102
- paths.sort! { |a,b| a.size <=> b.size }
103
-
104
-
105
- # Solaris's tar is pretty neutered, so implement --exclude and such
106
- # ourselves.
107
- # TODO(sissel): May need to implement our own tar file generator
108
- # so we can enforce file ownership. Again, solaris' tar doesn't support
109
- # --owner, etc.
110
- #paths = []
111
- #dirs.each do |dir|
112
- #Dir.glob(File.join(dir, "**", "*")).each do |path|
113
- #next if excludesFile.fnmatch?(
114
- #end
115
- #end
116
-
117
- excludes = self[:exclude].map { |e| ["--exclude", e] }.flatten
118
-
119
- # TODO(sissel): To properly implement excludes as regexps, we
120
- # will need to find files ourselves. That may be more work
121
- # than it is worth. For now, rely on tar's --exclude.
122
- dir_tar = [tar_cmd, "--owner=root", "--group=root" ] \
123
- + excludes \
124
- + ["-cf", output, "--no-recursion" ]
125
-
126
- # Only if directories and paths do not have duplicates ...
127
- dirs -= paths
128
-
129
- if dirs.any?
130
- ::Dir.chdir(chdir) do
131
- safesystem *(dir_tar += dirs)
132
- end
133
- end
134
-
135
- files_tar = [ tar_cmd ] \
136
- + excludes \
137
- + [ "--owner=root", "--group=root", "-rf", output ] \
138
- + paths
139
- ::Dir.chdir(chdir) do
140
- safesystem(*files_tar)
141
- end
142
- end # def tar
143
-
144
- def tar_cmd
145
- # Rely on gnu tar for solaris and OSX.
146
- case %x{uname -s}.chomp
147
- when "SunOS"
148
- return "gtar"
149
- when "Darwin"
150
- return "gnutar"
151
- else
152
- return "tar"
153
- end
154
- end # def tar_cmd
155
- end # class FPM::Source
@@ -1,59 +0,0 @@
1
- require "fpm/source"
2
- require "fileutils"
3
- require "fpm/rubyfixes"
4
- require "fpm/util"
5
-
6
- class FPM::Source::Dir < FPM::Source
7
- def get_metadata
8
- self[:name] = File.basename(File.expand_path(root))
9
- end
10
-
11
- def make_tarball!(tar_path, builddir)
12
- if self[:prefix]
13
- # Trim leading '/' from prefix
14
- self[:prefix] = self[:prefix][1..-1] if self[:prefix] =~ /^\//
15
-
16
- # Prefix all files with a path if given.
17
- @paths.each do |path|
18
- # Trim @root (--chdir)
19
- if @root != "." and path.start_with?(@root)
20
- path = path[@root.size .. -1]
21
- end
22
-
23
- # Copy to self[:prefix] (aka --prefix)
24
- if File.directory?(path)
25
- # Turn 'path' into 'path/' so rsync copies it properly.
26
- path = "#{path}/" if path[-1,1] != "/"
27
- dest = "#{builddir}/tarbuild/#{self[:prefix]}/#{path}"
28
- else
29
- dest = "#{builddir}/tarbuild/#{self[:prefix]}/#{File.dirname(path)}"
30
- end
31
-
32
- ::FileUtils.mkdir_p(dest)
33
- rsync = ["rsync", "-a", path, dest]
34
- p rsync if $DEBUG
35
- safesystem(*rsync)
36
-
37
- # FileUtils.cp_r is pretty silly about how it copies files in some
38
- # cases (funky permissions, etc)
39
- # Use rsync instead..
40
- #FileUtils.cp_r(path, dest)
41
- end
42
-
43
- # Prefix paths with 'prefix' if necessary.
44
- if self[:prefix]
45
- @paths = @paths.collect { |p| File.join("/", self[:prefix], p) }
46
- end
47
-
48
- ::Dir.chdir("#{builddir}/tarbuild") do
49
- safesystem("ls #{builddir}/tarbuild") if $DEBUG
50
- tar(tar_path, ".")
51
- end
52
- else
53
- tar(tar_path, paths)
54
- end
55
-
56
- # TODO(sissel): Make a helper method.
57
- safesystem(*["gzip", "-f", tar_path])
58
- end # def make_tarball!
59
- end # class FPM::Source::Dir
@@ -1,162 +0,0 @@
1
- require "fpm/namespace"
2
- require "fpm/source"
3
- require "rubygems/package"
4
- require "rubygems"
5
- require "fileutils"
6
- require "fpm/util"
7
-
8
- class FPM::Source::Gem < FPM::Source
9
- def self.flags(opts, settings)
10
- settings.source[:gem] = "gem"
11
-
12
- opts.on("--bin-path DIRECTORY",
13
- "The directory to install gem executables") do |path|
14
- settings.source[:bin_path] = path
15
- end
16
- opts.on("--package-prefix PREFIX",
17
- "Prefix for gem packages") do |package_prefix|
18
- settings.source[:package_prefix] = package_prefix
19
- end
20
-
21
- opts.on("--gem PATH_TO_GEM",
22
- "The path to the 'gem' tool (defaults to 'gem' and searches " \
23
- "your $PATH)") do |path|
24
- settings.source[:gem] = path
25
- end
26
- end # def flags
27
-
28
- def get_source(params)
29
- gem = @paths.first
30
- looks_like_name_re = /^[A-Za-z0-9_-]+$/
31
- if !File.exists?(gem)
32
- if gem =~ looks_like_name_re
33
- download(gem, params[:version])
34
- else
35
- raise "Path '#{gem}' is not a file and does not appear to be the name of a rubygem."
36
- end
37
- end
38
- end # def get_source
39
-
40
- def can_recurse_dependencies
41
- true
42
- end
43
-
44
- def download(gem_name, version=nil)
45
- # This code mostly mutated from rubygem's fetch_command.rb
46
- # Code use permissible by rubygems's "GPL or these conditions below"
47
- # http://rubygems.rubyforge.org/rubygems-update/LICENSE_txt.html
48
-
49
- puts "Trying to download #{gem_name} (version=#{version || 'latest'})"
50
- dep = ::Gem::Dependency.new gem_name, version
51
- # How to handle prerelease? Some extra magic options?
52
- #dep.prerelease = options[:prerelease]
53
-
54
- if ::Gem::SpecFetcher.fetcher.respond_to?(:fetch_with_errors)
55
- specs_and_sources, errors =
56
- ::Gem::SpecFetcher.fetcher.fetch_with_errors(dep, true, true, false)
57
- else
58
- specs_and_sources =
59
- ::Gem::SpecFetcher.fetcher.fetch(dep, true)
60
- errors = "???"
61
- end
62
- spec, source_uri = specs_and_sources.sort_by { |s,| s.version }.last
63
-
64
- if spec.nil? then
65
- raise "Invalid gem? Name: #{gem_name}, Version: #{version}, Errors: #{errors}"
66
- end
67
-
68
- path = ::Gem::RemoteFetcher.fetcher.download spec, source_uri
69
- FileUtils.mv path, spec.file_name
70
- @paths = [spec.file_name]
71
- end
72
-
73
- def get_metadata
74
- File.open(@paths.first, 'r') do |f|
75
- ::Gem::Package.open(f, 'r') do |gem|
76
- spec = gem.metadata
77
- %w(
78
- description
79
- license
80
- summary
81
- version
82
- ).each do |field|
83
- self[field.to_sym] = spec.send(field) rescue "unknown"
84
- end
85
-
86
- if self[:settings][:package_prefix]
87
- self[:package_prefix] = self[:settings][:package_prefix]
88
- else
89
- self[:package_prefix] = "rubygem"
90
- end
91
- self[:name] = "#{self[:package_prefix]}#{self[:suffix]}-#{spec.name}"
92
- self[:maintainer] = spec.author
93
- self[:url] = spec.homepage
94
-
95
- # TODO [Jay]: this will be different for different
96
- # package managers. Need to decide how to handle this.
97
- self[:category] = 'Languages/Development/Ruby'
98
-
99
- # if the gemspec has extensions defined, then this should be a 'native' arch.
100
- if !spec.extensions.empty?
101
- self[:architecture] = "native"
102
- else
103
- self[:architecture] = "all"
104
- end
105
-
106
- # make sure we have a description
107
- descriptions = [ self[:description], self[:summary], "#{spec.name} - no description given" ]
108
- self[:description] = descriptions.detect { |d| !(d.nil? or d.strip.empty?) }
109
-
110
- self[:dependencies] = []
111
- spec.runtime_dependencies.map do |dep|
112
- # rubygems 1.3.5 doesn't have 'Gem::Dependency#requirement'
113
- if dep.respond_to?(:requirement)
114
- reqs = dep.requirement.to_s.gsub(/,/, '')
115
- else
116
- reqs = dep.version_requirements
117
- end
118
-
119
- # Some reqs can be ">= a, < b" versions, let's handle that.
120
- reqs.to_s.split(/, */).each do |req|
121
- self[:dependencies] << "#{self[:package_prefix]}#{self[:suffix]}-#{dep.name} #{req}"
122
- end
123
- end # runtime_dependencies
124
- end # ::Gem::Package
125
- end # File.open (the gem)
126
- end # def get_metadata
127
-
128
- def make_tarball!(tar_path, builddir)
129
- tmpdir = "#{tar_path}.dir"
130
- gem = @paths.first
131
- if self[:prefix]
132
- installdir = "#{tmpdir}/#{self[:prefix]}"
133
- # TODO(sissel): Overwriting @paths is bad mojo and confusing...
134
- # Maybe we shouldn't?
135
- @paths = [ self[:prefix] ]
136
- else
137
- installdir = File.join(tmpdir, ::Gem::dir)
138
- @paths = [ ::Gem::dir ]
139
- end
140
-
141
- ::FileUtils.mkdir_p(installdir)
142
- args = [self[:settings][:gem], "install", "--quiet", "--no-ri", "--no-rdoc",
143
- "--install-dir", installdir, "--ignore-dependencies", "-E"]
144
- if self[:settings][:bin_path]
145
- tmp_bin_path = File.join(tmpdir, self[:settings][:bin_path])
146
- args += ["--bindir", tmp_bin_path]
147
- @paths << self[:settings][:bin_path]
148
- FileUtils.mkdir_p(tmp_bin_path) # Fixes #27
149
- end
150
-
151
- args << gem
152
- safesystem(*args)
153
-
154
- # make paths relative (/foo becomes ./foo)
155
- tar(tar_path, @paths.collect {|p| ".#{p}"}, tmpdir)
156
- FileUtils.rm_r(tmpdir)
157
-
158
- # TODO(sissel): Make a helper method.
159
- safesystem(*["gzip", "-f", tar_path])
160
- end
161
-
162
- end # class FPM::Source::Gem
@@ -1,137 +0,0 @@
1
- require "fpm/namespace"
2
- require "fpm/source"
3
- require "fpm/util"
4
- require "rubygems/package"
5
- require "rubygems"
6
- require "fileutils"
7
- require "tmpdir"
8
- require "json"
9
-
10
- class FPM::Source::Python < FPM::Source
11
- def self.flags(opts, settings)
12
- settings.source[:python] = "python"
13
- settings.source[:easy_install] = "easy_install"
14
- settings.source[:pypi] ="http://pypi.python.org/simple"
15
-
16
- opts.on("--bin PYTHON_BINARY_LOCATION",
17
- "The path to the python you want to run. Default is 'python'") do |path|
18
- settings.source[:python] = path
19
- end
20
-
21
- opts.on("--easyinstall EASY_INSTALL_PATH",
22
- "The path to your easy_install tool. Default is 'easy_install'") do |path|
23
- settings.source[:easy_install] = path
24
- end
25
-
26
- opts.on("--pypi PYPI_SERVER",
27
- "PyPi Server uri for retrieving packages. Default is 'http://pypi.python.org/simple'") do |pypi|
28
- settings.source[:pypi] = pypi
29
- end
30
-
31
- opts.on("--package-prefix PREFIX",
32
- "Prefix for python packages") do |package_prefix|
33
- settings.source[:package_prefix] = package_prefix
34
- end
35
- end # def flags
36
-
37
- def get_source(params)
38
- package = @paths.first
39
- if ["setup.py", "."].include?(package)
40
- # Assume we're building from an existing python package.
41
- # Source already acquired, nothing to do!
42
- return
43
- end
44
-
45
- if !File.exists?(package)
46
- download(package, params[:version])
47
- else
48
- @paths = [ File.expand_path(package) ]
49
- end
50
- end # def get_source
51
-
52
- def download(package, version=nil)
53
- puts "Trying to download #{package} (using: #{self[:settings][:easy_install]})"
54
- @tmpdir = ::Dir.mktmpdir("python-build", ::Dir.pwd)
55
-
56
- if version.nil?
57
- want_pkg = "#{package}"
58
- else
59
- want_pkg = "#{package}==#{version}"
60
- end
61
-
62
- safesystem(self[:settings][:easy_install], "-i", self[:settings][:pypi],
63
- "--editable", "-U", "--build-directory", @tmpdir, want_pkg)
64
-
65
- # easy_install will put stuff in @tmpdir/packagename/, flatten that.
66
- # That is, we want @tmpdir/setup.py, and start with
67
- # @tmpdir/somepackage/setup.py
68
- dirs = ::Dir.glob(File.join(@tmpdir, "*"))
69
- if dirs.length != 1
70
- raise "Unexpected directory layout after easy_install. Maybe file a bug? The directory is #{@tmpdir}"
71
- end
72
- @paths = dirs
73
- end # def download
74
-
75
- def get_metadata
76
- setup_py = @paths.first
77
- if File.directory?(setup_py)
78
- setup_py = File.join(setup_py, "setup.py")
79
- @paths = [setup_py]
80
- end
81
-
82
- if !File.exists?(setup_py)
83
- raise "Unable to find python package; tried #{setup_py}"
84
- end
85
-
86
- pylib = File.expand_path(File.dirname(__FILE__))
87
- setup_cmd = "env PYTHONPATH=#{pylib} #{self[:settings][:python]} #{setup_py} --command-packages=pyfpm get_metadata"
88
- output = ::Dir.chdir(File.dirname(setup_py)) { `#{setup_cmd}` }
89
- puts output
90
- metadata = JSON.parse(output[/\{.*\}/msx])
91
- #p metadata
92
-
93
- if self[:settings][:package_prefix]
94
- self[:package_prefix] = self[:settings][:package_prefix]
95
- else
96
- self[:package_prefix] = "python"
97
- end
98
-
99
- self[:architecture] = metadata["architecture"]
100
- self[:description] = metadata["description"]
101
- self[:license] = metadata["license"]
102
- self[:version] = metadata["version"]
103
- self[:name] = "#{self[:package_prefix]}#{self[:suffix]}-#{metadata["name"]}"
104
- self[:url] = metadata["url"]
105
-
106
- self[:dependencies] = metadata["dependencies"].collect do |dep|
107
- name, cmp, version = dep.split
108
- "#{self[:package_prefix]}#{self[:suffix]}-#{name} #{cmp} #{version}"
109
- end
110
- end # def get_metadata
111
-
112
- def make_tarball!(tar_path, builddir)
113
- setup_py = @paths.first
114
- dir = File.dirname(setup_py)
115
-
116
- # Some setup.py's assume $PWD == current directory of setup.py, so let's
117
- # chdir first.
118
- ::Dir.chdir(dir) do
119
- safesystem(self[:settings][:python], "setup.py", "bdist")
120
- end
121
-
122
- dist_tar = ::Dir.glob(File.join(dir, "dist", "*.tar.gz")).first
123
- puts "Found dist tar: #{dist_tar}"
124
- puts "Copying to #{tar_path}"
125
-
126
- @paths = [ "." ]
127
-
128
- safesystem("cp", dist_tar, "#{tar_path}.gz")
129
- end # def make_tarball!
130
-
131
- def garbage
132
- trash = []
133
- trash << @tmpdir if @tmpdir
134
- return trash
135
- end # def garbage
136
-
137
- end # class FPM::Source::Gem