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:
commit
50e9174035
30
bin/fpm
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
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
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
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"%>
|
||||
|
Loading…
Reference in New Issue
Block a user