1
0
mirror of https://github.com/jordansissel/fpm synced 2025-04-29 14:58:00 +02:00

Merge branch 'jayferd_sources_and_builder'

This commit is contained in:
Jeanine Adkisson 2011-01-05 18:36:22 -08:00
commit 50e9174035
9 changed files with 295 additions and 101 deletions

30
bin/fpm

@ -49,29 +49,23 @@ def main(args)
opts.on("-C DIRECTORY", "Change directory before searching for files") do |dir|
settings.chdir = dir
end
opts.on("-t PACKAGE_TYPE", "the type of package you want to create") do |type|
settings.package_type = type
end
opts.on("-s SOURCE_TYPE", "what to build the package from") do |st|
settings.source_type = st
end
end # OptionParser
opts.parse!(args)
if !settings.package_path
$stderr.puts "No package file given to manage. Give with -p PACKAGEFILE"
return 1
end
package = FPM::Deb.new
package.name = settings.package_name
package.version = settings.version
package.maintainer = settings.maintainer if settings.maintainer
package.architecture = (settings.architecture or %x{uname -m}.chomp)
package.dependencies = (settings.dependencies or [])
p settings
package.assemble({
"output" => settings.package_path,
"root" => settings.chdir,
"paths" => args, # Remainder of args are paths.
})
FPM::Builder.new(settings, args).assemble!
return 0
end # def main
ret = main(ARGV)
ret = main(ARGV)
exit(ret != nil ? ret : 0)

@ -1,3 +1,9 @@
require "fpm/namespace"
require "fpm/builder"
require "fpm/package"
require "fpm/deb"
require "fpm/rpm"
require "fpm/source"
require "fpm/dir"

139
lib/fpm/builder.rb Normal file

@ -0,0 +1,139 @@
require 'fileutils'
class FPM::Builder
# where is the package's root?
def root
@root ||= (@source.root || '.')
end
# where the package goes
def output
@output ||= begin
o = @package.default_output
if o.start_with? '/'
o
else
File.join(@working_dir, o)
end
end
end
# things to clean up afterwards
def garbage
@garbage ||= []
end
# the spec or control file
def spec
@spec ||= @source.render(@package.template)
end
attr_reader :paths
attr_reader :package
attr_reader :source
def initialize(settings, paths=[])
@working_dir = Dir.pwd
root = settings.chdir || '.'
paths = ['.'] if paths.empty?
@source = source_class_for(settings.source_type || 'dir').new(paths, root, :version => settings.version)
@package = package_class_for(settings.package_type).new(@source)
@paths = paths
@output = settings.package_path
if @output
@output.gsub! /VERSION/, @source[:version]
@output.gsub! /ARCH/, @package.architecture
end
end # def initialize
def tar_path
@tar_path ||= "#{builddir}/data.tar"
end
# Assemble the package
def assemble!
output.gsub!(/VERSION/, "#{@source[:version]}-#{@source[:iteration]}")
output.gsub!(/ARCH/, @package.architecture)
File.delete(output) if File.exists?(output)
make_builddir!
::Dir.chdir root do
@source.make_tarball!(tar_path)
generate_md5sums
generate_specfile
end
::Dir.chdir(builddir) do
@package.build!({
:tarball => tar_path,
:output => output
})
end
cleanup!
end # def assemble!
private
def builddir
@builddir ||= File.expand_path(
"#{Dir.pwd}/build-#{@package.type}-#{File.basename(output)}"
)
end
def make_builddir!
FileUtils.rm_rf builddir
garbage << builddir
FileUtils.mkdir(builddir) if !File.directory?(builddir)
p :exists => File.directory?(builddir)
end
# TODO: [Jay] make this better.
def package_class_for(type)
({
:deb => FPM::Deb,
:rpm => FPM::Rpm
})[:"#{type}"]
end
# TODO: [Jay] make this better.
def source_class_for(type)
case type.to_s
when 'gem'
FPM::Gem
when 'dir'
FPM::Dir
when 'tar'
FPM::Tar
else
raise ArgumentError, "unknown package type #{type.inspect}"
end
end
def cleanup!
return [] if garbage.empty?
FileUtils.rm_rf(garbage) && garbage.clear
end
def generate_specfile
File.open(@package.specfile(builddir), "w") { |f| f.puts spec }
end
def generate_md5sums
md5sums = checksum(paths)
File.open("#{builddir}/md5sums", "w") { |f| f.puts md5sums }
md5sums
end
def checksum(paths)
md5sums = []
paths.each do |path|
md5sums += %x{find #{path} -type f -print0 | xargs -0 md5sum}.split("\n")
end
end # def checksum
end

@ -19,7 +19,7 @@ class FPM::Deb < FPM::Package
"#{builddir}/control"
end
def build(params)
def build!(params)
# Make the control
system("tar -zcf control.tar.gz control md5sums")
@ -27,7 +27,7 @@ class FPM::Deb < FPM::Package
File.open("debian-binary", "w") { |f| f.puts "2.0" }
# pack up the .deb
system("ar -qc #{params["output"]} debian-binary control.tar.gz data.tar.gz")
system("ar -qc #{params[:output]} debian-binary control.tar.gz data.tar.gz")
end # def build
end # class FPM::Deb

12
lib/fpm/dir.rb Normal file

@ -0,0 +1,12 @@
class FPM::Dir < FPM::Source
def get_metadata
self[:name] = File.basename(File.expand_path(root))
end
def make_tarball!(tar_path)
tar(tar_path, paths)
# TODO(sissel): Make a helper method.
system(*["gzip", "-f", tar_path])
end
end

@ -1 +1,12 @@
module FPM; end
module FPM
DIRS = {
:templates => File.expand_path(
File.join(
File.dirname(__FILE__),
'..',
'..',
'templates'
)
)
}
end

@ -38,71 +38,21 @@ class FPM::Package
# Array of dependencies.
attr_accessor :dependencies
def initialize
@iteration = 1
@url = "http://nourlgiven.example.com/no/url/given"
@category = "default"
@license = "unknown"
@maintainer = "<#{ENV["USER"]}@#{Socket.gethostname}>"
@architecture = nil
@summary = "no summary given"
def initialize(source)
@source = source
# Garbage is stuff you may want to clean up.
@garbage = []
@name = source[:name] # || fail
@version = source[:version] # || fail
@iteration = source[:iteration] || 1
@url = source[:url] || "http://nourlgiven.example.com/no/url/given"
@category = source[:category] || "default"
@license = source[:license] || "unknown"
@maintainer = source[:maintainer] || "<#{ENV["USER"]}@#{Socket.gethostname}>"
@architecture = source[:architecture] || %x{uname -m}.chomp
@summary = source[:summary] || "no summary given"
end
def tar(output, paths)
dirs = []
paths.each do |path|
while path != "/" and path != "."
dirs << path if !dirs.include?(path)
path = File.dirname(path)
end
end # paths.each
dirs = dirs.sort { |a,b| a.length <=> b.length}
system(*["tar", "--owner=root", "--group=root", "-cf", output, "--no-recursion", *dirs])
system(*["tar", "--owner=root", "--group=root", "-rf", output, *paths])
end
# Assemble the package.
# params:
# "root" => "/some/path" # the 'root' of your package directory
# "paths" => [ "/some/path" ...] # paths to icnlude in this package
# "output" => "foo.deb" # what to output to.
#
# The 'output' file path will have 'VERSION' and 'ARCH' replaced with
# the appropriate values if if you want the filename generated.
def assemble(params)
raise "No package name given. Can't assemble package" if !@name
root = params["root"] || '.'
paths = params["paths"]
output = params["output"]
output.gsub!(/VERSION/, "#{version}-#{iteration}")
output.gsub!(/ARCH/, architecture)
File.delete(output) if File.exists?(output)
builddir = "#{Dir.pwd}/build-#{type}-#{File.basename(output)}"
@garbage << builddir
Dir.mkdir(builddir) if !File.directory?(builddir)
Dir.chdir root do
tar("#{builddir}/data.tar", paths)
# TODO(sissel): Make a helper method.
system(*["gzip", "-f", "#{builddir}/data.tar"])
generate_md5sums(builddir, paths)
generate_specfile(builddir, paths)
end
Dir.chdir(builddir) do
build(params)
end
end # def assemble
def generate_specfile(builddir, paths)
spec = template.result(binding)
File.open(specfile(builddir), "w") { |f| f.puts spec }
@ -114,13 +64,6 @@ class FPM::Package
md5sums
end
def checksum(paths)
md5sums = []
paths.each do |path|
md5sums += %x{find #{path} -type f -print0 | xargs -0 md5sum}.split("\n")
end
end # def checksum
# TODO [Jay]: make this better...?
def type
self.class.name.split(':').last.downcase
@ -129,10 +72,13 @@ class FPM::Package
def template
@template ||= begin
tpl = File.read(
"#{File.dirname(__FILE__)}/../../templates/#{type}.erb"
"#{FPM::DIRS[:templates]}/#{type}.erb"
)
ERB.new(tpl, nil, "<>")
end
end
def default_output
"#{name}-#{version}-#{iteration}.#{architecture}.#{type}"
end
end

86
lib/fpm/source.rb Normal file

@ -0,0 +1,86 @@
require "fpm/namespace"
# Abstract class for a "thing to build a package from"
class FPM::Source
# standard package metadata
*%w(
name
version
iteration
architecture
maintainer
category
url
summary
).each do |attr|
attr = :"#{attr}"
define_method(attr) { self[attr] }
define_method(:"#{attr}=") { |v| self[attr] = v}
end
def dependencies
self[:dependencies] ||= []
end
attr_reader :paths
attr_reader :root
def initialize(paths, root, params={})
@paths = paths
@root = root
get_metadata
# override the inferred data with the passed-in data
params.each do |k,v|
self[k] = v
end
end
# this method should take the paths and root and infer as much
# about the package as it can.
def get_metadata
raise NoMethodError,
"Please subclass FPM::Source and define get_metadata"
end
def make_tarball!(tar_path)
raise NoMethodError,
"Please subclass FPM::Source and define make_tarball!(tar_path)"
end
def metadata
@metadata ||= {}
end
def [](key)
metadata[key.to_sym]
end
def []=(key,val)
metadata[key.to_sym] = val
end
# MySourceClass.new('/tmp/build').package(FPM::Deb).assemble(params)
def package(pkg_cls)
pkg_cls.new(self)
end
# make the binding public for erb templating
def render(template)
template.result(binding)
end
private
def tar(output, paths)
dirs = []
paths.each do |path|
while path != "/" and path != "."
dirs << path if !dirs.include?(path)
path = File.dirname(path)
end
end # paths.each
system(*["tar", "--owner=root", "--group=root", "-cf", output, "--no-recursion", *dirs]) if dirs.any?
system(*["tar", "--owner=root", "--group=root", "-rf", output, *paths])
end # def tar
end

@ -1,13 +1,13 @@
Package: <%= @name %>
Version: <%= @version %>-<%= @iteration %>
Architecture: <%= @architecture %>
Maintainer: <%= @maintainer or "<unknown>" %>
<% if @dependencies.size > 0 %>
Depends: <%= @dependencies.join(", ") %>
Package: <%= name %>
Version: <%= version %>-<%= iteration %>
Architecture: <%= architecture %>
Maintainer: <%= maintainer or "<unknown>" %>
<% if dependencies.size > 0 %>
Depends: <%= dependencies.join(", ") %>
<% end %>
Standards-Version: 3.9.1
Section: <%= @category or "unknown" %>
Section: <%= category or "unknown" %>
Priority: extra
Homepage: <%= @url or "http://nourlgiven.example.com/" %>
Description: <%= @summary or "no summary given" %>
<%= @summary or "no description given"%>
Homepage: <%= url or "http://nourlgiven.example.com/" %>
Description: <%= summary or "no summary given" %>
<%= summary or "no description given"%>