require 'reap/task' begin require 'rubygems' rescue LoadError # no rubygems end # ___ _ _____ _ # | _ \__ _ __| |____ _ __ _ ___ |_ _|_ _ __| |__ # | _/ _` / _| / / _` / _` / -_) | |/ _` (_-< / / # |_| \__,_\__|_\_\__,_\__, \___| |_|\__,_/__/_\_\ # |___/ # = Package Task # # This task creates standard .zip, .tgz, or .tbz # packages, plus .gem distributions. class Reap::Package < Reap::Task MUST_EXCLUDE = [ 'InstalledFiles', '**/CVS/**/*', '**/*~', 'dist', 'pkg' ] LOCATIONS = [ '../leaf', '../dist', '../pkg', 'dist', 'pkg' ] # Task line description task_desc do disttypes = $PROJECT_INFO['distribute'] || [ 'gem', 'tar.bz2', 'zip' ] "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 it in some way differs. Possible subsections are: gems pacman debian } # Alternate for task properties accessor. task_attr :pkg # Setup package task. def init # Do not look in master information for this pkg.dir = section.dir || LOCATIONS.find { |f| File.directory?(f) } || 'dist' # Set defaults 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 end # Run package task. def run puts "Creating #{pkg.distribute.join(',')} packages..." # create package image 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) print "Package directory '#{pkg.package_name}' already exists. Continue or [R]emove and continue? [y/r/N] " until inp = $stdin.gets[0,1] ; sleep 1 ; end inp = inp.to_s.downcase case inp when 'y' # continue... when 'r' puts "Removing old directory '#{File.expand_path(group_dir_path)}'..." FileUtils.rm_r(group_dir_path) else puts "Reap package task canceled." return nil end end 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 puts "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 puts "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 puts "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 :gem #pkg = sub ? sub : pkg 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 } puts "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 ) ) } #sh %{mv ./*.gem #{@dir}/} end # This build the Debiam package. def run_deb use_subsection :deb # 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 ctrl = %{ Package: #{pkg.name} Version: #{pkg.version} Priority: optional Architecture: #{pkg.architecture} Essential: no }.tabto(0) ctrl << "Section: #{pkg.category}" if pkg.category ctrl << "Depends: #{pkg.dep}" unless _dep.empty? ctrl << "Recommends: #{pkg.recommends.join(' | ')}" unless pkg.recommends.empty? ctrl << "Conflicts: #{pkg.conflicts.join(', ')}" unless pkg.conflicts.empty? ctrl << %{ Maintainer: #{pkg.maintainer} [#{pkg.email}] Provides: #{pkg.name} Description: #{pkg.summary} . #{pkg.description} }.tabto(0) if pkg.architecture == 'any' debname = "ruby_#{pkg.name}_#{pkg.version}.deb" else debname = "ruby_#{pkg.name}_#{pkg.version}_#{pkg.architecture}.deb" end debdir = File.join( pkg.dir, pkg.package_name, 'debian' ) debdebdir = File.join( debdir, 'DEBIAN' ) debfile = File.join( debdir, debname ) puts "Reap is shelling out work to the deb-pkg..." FileUtils.mkdir_p(debdir) sh %{ruby setup.rb all --prefix=#{debdir}} FileUtils.mkdir_p(debdebdir) File.open( File.join(debdebdir, 'control'), 'w') { |f| f << ctrl } #sh %{dpkg-deb -b #{debdir} #{debfile}} end # This builds a pacman (archlinux) PKGBUILD script. def run_pacman use_subsection :pacman unless @source puts "URL 'source' is require for proto package." return nil end # if section.key?('pac') # _dep = pkg.pac.dependenciers || pkg.dependencies # _rep = pkg.pac.replaces || pkg.replaces # _con = pkg.pac.conflicts || pkg.conflicts # else _dep = pkg.dependencies _rep = pkg.replaces _con = pkg.conflicts # end _dep = _dep.collect{ |d| "'#{d}'" }.join(' ') _rep = _rep.collect{ |d| "'#{d}'" }.join(' ') _con = _rep.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' ) puts "Reap is shelling out work to the pacman..." FileUtils.mkdir_p(pacdir) #sh %{ruby setup.rb all --prefix=#{debdir}} #FileUtils.mkdir_p(pacpacdir) File.open( pacfile, 'w') { |f| f << proto } #sh %{dpkg-deb -b #{debdir} #{debfile}} end end