require 'reap/task' begin require 'rubygems' rescue LoadError # no rubygems end # ___ _ _____ _ # | _ \__ _ __| |____ _ __ _ ___ |_ _|_ _ __| |__ # | _/ _` / _| / / _` / _` / -_) | |/ _` (_-< / / # |_| \__,_\__|_\_\__,_\__, \___| |_|\__,_/__/_\_\ # |___/ # = Package Task # # This task creates standard .zip, .tgz, or .tbz # packages, plus .gem or .deb distributions. class Reap::Package < Reap::Task MUST_EXCLUDE = [ 'InstalledFiles', '**/CVS/**/*', '**/*~', 'dist', 'pkg' ] LOCATIONS = [ 'dist', 'pkg', '../packages', '../dist', '../pkg' ] # Task line description task_desc "Create distribution packages." # if master.package # disttypes = master.package.distribute || master.distribute || [ 'gem', 'tar.bz2', 'zip' ] # else # disttypes = master.distribute || [ 'gem', 'tar.bz2', 'zip' ] # end # "Build distribution packages (#{disttypes.join(', ')})." # end # Help information task_help %{ reap package Builds distribution packages. The package task supports tar.gz, tar.bz2, zip source packages and gem, pacman and debian ditribution packages. dir Directory in which to store distributions. include Files to include in distribution. exclude Files to exclude from those. distribute Distribution types. tgz, tar.gz, tbz, tar.bz2, zip gem, deb, pac project Project name. category Software category. architecture Can be any, i368, i686, ppc, etc. dependencies List of packages this program depends. recommends List of packages that can be used with this package. replaces List of packages this one replaces. executables Executable files in this distribution. source URL of source package (typically a tar.gz file). md5 MD% checksum of source file. These are RubyGems specific. autorequire platform require_paths The package task also has subsection for each type of distribution. These can be used to override settings in the package information if they in some way differ. Possible subsections are: gems pacman debian } # Alternate for task properties accessor. alias_method :pkg, :task def run # setup package defaults # Do not look in master information for this pkg.dir = section.dir || LOCATIONS.find { |f| File.directory?(f) } || 'dist' pkg.status ||= 'beta/stable' pkg.date ||= Time.now.strftime("%Y-%m-%d") pkg.series ||= '1' pkg.author ||= "Anonymous" pkg.maintainer ||= pkg.author pkg.email ||= "" pkg.summary ||= "" pkg.architecture ||= 'any' pkg.license ||= 'Ruby/GPL' pkg.project ||= master.rubyforge.project pkg.homepage ||= master.rubyforge.homepage d = pkg.date.split('-').collect{ |e| e.to_i } #d[0] = d[0] - 2000 # No need to keep the 2000 pkg.version ||= d.join('.') if $BUILD_VERSION pkg.buildno = Time.now.strftime("%H*60+%M") pkg.version += ".#{pkg.buildno}" end pkg.package_name ||= "#{pkg.name}-#{pkg.version}" pkg.exclude ||= [] pkg.exclude |= MUST_EXCLUDE pkg.include ||= ['**/*'] # distribute types include 'tgz', 'tbz', 'zip', 'tar.gz' 'tar.bz2', 'gem', 'pac' and 'deb'. pkg.distribute ||= [ 'gem', 'tar.bz2', 'zip' ] pkg.distribute = [pkg.distribute].flatten.collect { |t| t.to_s.strip.downcase } pkg.dependencies ||= [] pkg.executables ||= [] pkg.requirements ||= [] pkg.recommends ||= [] pkg.conflicts ||= [] pkg.replaces ||= [] # Gem specific properties if defined?(::Gem) and pkg.gem if pkg.gem.platform begin pkg.gem.platform = ::Gem::Platform.const_get(pkg.gem.platform.upcase) rescue NameError pkg.gem.platform = ::Gem::Platform::RUBY end else pkg.gem.platform = ::Gem::Platform::RUBY end #@autorequire end # package it up group_dir_path = File.join( pkg.dir, pkg.package_name ) package_dir_path = File.join( pkg.dir, pkg.package_name, pkg.package_name ) if FileTest.directory?(group_dir_path) if $FORCE puts "Removing old directory '#{File.expand_path(group_dir_path)}'..." FileUtils.rm_r(group_dir_path) else puts "Package directory '#{pkg.package_name}' already exists. Use -f option to overwrite." return nil end end puts "Creating #{pkg.distribute.join(',')} packages..." package_files = FileList.new package_files.include(*pkg.include) package_files.exclude(*pkg.exclude) if pkg.exclude and not pkg.exclude.empty? FileUtils.mkdir_p pkg.dir #rescue nil package_files.each do |f| pkgf = File.join(package_dir_path, f) fdir = File.dirname(pkgf) FileUtils.mkdir_p(fdir) if not File.exist?(fdir) if File.directory?(f) FileUtils.mkdir_p(pkgf) else FileUtils.rm_f(pkgf) FileUtils.safe_ln(f, pkgf) end end # create standard package files FileUtils.chdir( File.join( pkg.dir, pkg.package_name ) ) do pkg.distribute.each do |t| sh_cmd = nil prefix = 'ERROR' # in case of unforseen bug case t when 'tbz', 'bz2', 'bzip2', 'tar.bz2' prefix = ( t == 'tbz' ? 'tbz' : 'tar.bz2' ) sh_cmd = 'tar --bzip2 -cvf' puts "\nReap is shelling out work to tar and bzip2..." when 'tgz', 'tar.gz' prefix = ( t == 'tgz' ? 'tgz' : 'tar.gz' ) sh_cmd = 'tar --gzip -cvf' puts "\nReap is shelling out work to tar and gzip..." when 'zip' prefix = 'zip' sh_cmd = 'zip -r' puts "\nReap is shelling out work to zip..." when 'gem', 'deb', 'pac' sh_cmd = nil else puts "Unknown package type '#{t}' skipped." sh_cmd = nil end sh %{#{sh_cmd} #{pkg.package_name}.#{prefix} #{pkg.package_name}} if sh_cmd end puts end # create gem package if pkg.distribute.include?('gem') if defined?(::Gem) run_gem else tell "Package .gem requested, but rubygems not found (skipped)." end end # create debian package if pkg.distribute.include?('deb') if true # TODO ensure required debian tools here run_deb else tell "Package .deb requested, but debian tools not found (skipped)." end end # create PKGBUILD (pacman, archlinux) if pkg.distribute.include?('pac') if true # TODO ensure required tools here run_pacman else tell "Pacman package requested, but required tools not found (skipped)." end end return true end private # This builds the gem package. def run_gem use_subsection :gems spec = Gem::Specification.new { |s| s.name = pkg.name s.version = pkg.version pkg.dependencies.each { |d,v| if v s.add_dependency(d, v) else s.add_dependency(d) end } s.summary = pkg.summary s.requirements = pkg.requirements # s.files = Dir.glob("lib/**/*").delete_if {|item| item.include?("CVS")} # s.files.concat Dir.glob("bin/**/*").delete_if {|item| item.include?("CVS")} package_files = FileList.new package_files.include(*pkg.include) package_files.exclude(*pkg.exclude) if pkg.exclude and not pkg.exclude.empty? s.files = package_files.to_a s.author = pkg.author s.email = pkg.email s.rubyforge_project = pkg.project s.homepage = pkg.homepage s.require_path = 'lib' s.require_paths = pkg.require_paths if pkg.require_paths s.autorequire = pkg.autorequire if pkg.autorequire s.platform = pkg.platform s.executables = pkg.executables s.bindir = "bin" s.has_rdoc = true } tell "Reap is shelling out work to the Gem Package Manager..." Gem.manage_gems Gem::Builder.new(spec).build gems = Dir.glob( './*.gem' ) gems.each{ |f| FileUtils.mv( f, File.join( pkg.dir, pkg.package_name ) ) } puts end # This build the Debiam package. def run_deb use_subsection :debian # build the debian control file dep = pkg.dependencies.collect{ |d, v| if v "#{d} (#{v})" else d end }.join(', ') # Some debian fields not yet used: # Installed-Size: 1024 # Replaces: sam-sheepdog # Pre-Depends: perl, ... # Suggests: docbook arch = pkg.architecture.downcase arch = (arch == 'any' ? 'all' : arch) ctrl = %{ Package: #{pkg.name} Version: #{pkg.version} Priority: optional Architecture: #{arch} Essential: no }.tabto(0) ctrl << "Section: #{pkg.category}\n" if pkg.category ctrl << "Depends: #{dep}\n" unless dep.empty? ctrl << "Recommends: #{pkg.recommends.join(' | ')}\n" unless pkg.recommends.empty? ctrl << "Conflicts: #{pkg.conflicts.join(', ')}\n" unless pkg.conflicts.empty? ctrl << "Maintainer: #{pkg.maintainer} <#{pkg.email}>\n" ctrl << "Provides: #{pkg.name}\n" ctrl << "Description: #{pkg.summary}\n" ctrl << " #{pkg.description}\n" if arch == 'all' debname = "#{pkg.name}-ruby_#{pkg.version}.deb" else debname = "#{pkg.name}-ruby_#{pkg.version}_#{pkg.architecture}.deb" end pkgdir = File.join( pkg.dir, pkg.package_name ) debdir = File.join( pkgdir, 'debian' ) #debdebdir = File.join( debdir, 'DEBIAN' ) debfile = File.join( pkgdir, debname ) unless provide_setup_rb puts "Setup.rb is missing. Forced to skip debian package creation." return nil end puts "Reap is shelling out work to the deb-pkg..." cmd = %{ruby setup.rb } cmd << '-q ' unless $VERBOSE cmd << %{all --installdirs=std --root=#{debdir}} FileUtils.mkdir_p(debdir) sh cmd FileUtils.mkdir_p( File.join(debdir, 'DEBIAN') ) File.open( File.join(debdir, 'DEBIAN', 'control'), 'w') { |f| f << ctrl } sh %{dpkg-deb -b #{debdir} #{debfile}} puts end # This builds a pacman (archlinux) PKGBUILD script. def run_pacman use_subsection :pacman unless @source tell "URL 'source' is require for proto package." return nil end _dep = pkg.dependencies.collect{ |d| "'#{d}'" }.join(' ') _rep = pkg.replaces.collect{ |d| "'#{d}'" }.join(' ') _con = pkg.conflicts.collect{ |d| "'#{d}'" }.join(' ') proto = %{ pkgname=#{pkg.name} pkgver=#{pkg.version} pkgrel=#{pkg.series} pkgdesc="#{pkg.summary}" url="#{pkg.homepage}" license="#{pkg.license}" depends=(#{_dep}) conflicts=(#{_con}) replaces=(#{_rep}) source=(#{pkg.source}) md5sums=(#{pkg.md5}) }.tabto(0) # What are these for? # install= # backup=() if pkg.usemake s << %{ makedepends=()" build() { cd $startdir/src/$pkgname-$pkgver ./ruby setup.rb --prefix=/usr make || return 1 make DESTDIR=$startdir/pkg install } }.tabto(0) else s << %{ build() { cd $startdir/src/$pkgname-$pkgver ./ruby setup.rb --prefix=/usr } } end pacdir = File.join( pkg.dir, pkg.package_name, 'pacman' ) pacpacdir = File.join( pacdir, 'PACMAN' ) pacfile = File.join( pacdir, 'PKGBUILD' ) tell "Reap is shelling out work to the pacman..." FileUtils.mkdir_p(pacdir) File.open( pacfile, 'w') { |f| f << proto } puts end end