#!/usr/bin/env ruby
# A raw platform for creating packages.
require 'rbconfig'
require 'rake'
require 'rake/tasklib'
# The PackageTask will create the following targets:
#
# [:clobber_package]
# Delete all the package files. This target is automatically
# added to the main clobber target.
#
# [:repackage]
# Rebuild the package files from scratch, even if they are not out
# of date.
#
# ["package_dir/name-version.tgz"]
# Create a gzipped tar package (if need_tar is true).
#
# ["package_dir/name-version.tar.gz"]
# Create a gzipped tar package (if need_tar_gz is true).
#
# ["package_dir/name-version.tar.bz2"]
# Create a bzip2'd tar package (if need_tar_bz2 is true).
#
# ["package_dir/name-version.zip"]
# Create a zip package archive (if need_zip is true).
#
# Example:
#
# Rake::PackageTask.new("rake", "1.2.3") do |p|
# p.need_tar = true
# p.package_files.include("lib/**/*.rb")
# end
#
class Rake::RedLabPackageTask < Rake::TaskLib
# The different directory types we can manage.
DIRTYPES = {
:bindir => :bins,
:sbindir => :sbins,
:sitelibdir => :rubylibs
}
# Name of the package (from the GEM Spec).
attr_accessor :name
# Version of the package (e.g. '1.3.2').
attr_accessor :version
# Directory used to store the package files (default is 'pkg').
attr_accessor :package_dir
# The directory to which to publish packages and html and such.
attr_accessor :publishdir
# The package-specific publishing directory
attr_accessor :pkgpublishdir
# The Product name. Defaults to a capitalized version of the
# package name
attr_accessor :product
# The copyright message.
attr_accessor :copyright
# The vendor.
attr_accessor :vendor
# The license file. Defaults to COPYING.
attr_accessor :license
# The readme file. Defaults to README.
attr_accessor :readme
# The description.
attr_accessor :description
# The summary.
attr_accessor :summary
# The directory in which to put the binaries. Defaults to the system
# default.
attr_accessor :bindir
# The executables.
attr_accessor :bins
# The directory in which to put the system binaries. Defaults to the
# system default.
attr_accessor :sbindir
# The system binaries.
attr_accessor :sbins
# The libraries.
attr_accessor :rubylibs
# The directory in which to put Ruby libraries. Defaults to the
# system site_dir.
attr_accessor :sitelibdir
# The URL for the package.
attr_accessor :url
# The source for the package.
attr_accessor :source
# Our operating system.
attr_reader :os
# Add a required package.
def add_dependency(name, version = nil)
@requires[name] = version
end
# Create the tasks defined by this task library.
def define
fail "Version required (or :noversion)" if @version.nil?
@version = nil if :noversion == @version
directory pkgdest
file pkgdest => self.package_dir
directory self.package_dir
self.mkcopytasks
self
end
# Return the list of files associated with a dirname.
def files(dirname)
if @dirtypes.include?(dirname)
return self.send(@dirtypes[dirname])
else
raise "Could not find directory type %s" % dirname
end
end
# Create a Package Task with the given name and version.
def initialize(name=nil, version=nil)
# Theoretically, one could eventually add directory types here.
@dirtypes = DIRTYPES.dup
@requires = {}
@name = name
@version = version
@package_dir = 'pkg'
@product = name.capitalize
@bindir = Config::CONFIG["bindir"]
@sbindir = Config::CONFIG["sbindir"]
@sitelibdir = Config::CONFIG["sitelibdir"]
@license = "COPYING"
@readme = "README"
yield self if block_given?
define unless name.nil?
# Make sure they've provided everything necessary.
%w{copyright vendor description}.each do |attr|
unless self.send(attr)
raise "You must provide the attribute %s" % attr
end
end
end
# Make tasks for copying/linking all of the necessary files.
def mkcopytasks
basedir = pkgdest()
tasks = []
# Iterate across all of the file locations...
@dirtypes.each do |dirname, filemethod|
tname = ("copy" + dirname.to_s).intern
dir = self.send(dirname)
reqs = []
# This is where we're putting the files.
targetdir = self.targetdir(dirname)
# Make sure our target directories exist
directory targetdir
file targetdir => basedir
# Get the file list and remove the leading directory.
files = self.files(dirname) or next
reqs = []
files.each do |sourcefile|
# The file without the basedir. This is necessary because
# files are created with the path from ".", but they often
# have 'lib' changed to 'site_ruby' or something similar.
destfile = File.join(targetdir, sourcefile.sub(/^\w+\//, ''))
reqs << destfile
# Make sure the base directory is listed as a prereq
sourcedir = File.dirname(sourcefile)
destdir = nil
unless sourcedir == "."
destdir = File.dirname(destfile)
reqs << destdir
directory(destdir)
end
# Now make the task associated with creating the object in
# question.
if FileTest.directory?(sourcefile)
directory(destfile)
else
file(destfile => sourcefile) do
if FileTest.exists?(destfile)
if File.stat(sourcefile) > File.stat(destfile)
rm_f destfile
safe_ln(sourcefile, destfile)
end
else
safe_ln(sourcefile, destfile)
end
end
# If we've set the destdir, then list it as a prereq.
if destdir
file destfile => destdir
end
end
end
# And create a task for each one
task tname => reqs
# And then mark our task as a prereq
tasks << tname
end
task :copycode => [self.package_dir, pkgdest]
task :copycode => tasks do
puts "Finished copying"
end
end
# Where we're copying a given type of file.
def targetdir(dirname)
File.join(pkgdest(), self.send(dirname)).sub("//", "/")
end
private
def package_name
@version ? "#{@name}-#{@version}" : @name
end
def package_dir_path
"#{package_dir}/#{package_name}"
end
end