fpm 0.3.11 → 0.4.0pre1

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