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 task_desc do disttypes = $PROJECT_INFO['distribute'] || [ 'gem', 'tar.bz2', 'zip' ] "Build distribution packages (#{disttypes.join(', ')})." end MUST_EXCLUDE = [ 'InstalledFiles', '**/CVS/**/*', '**/*~', 'dist', 'pkg' ] LOCATIONS = [ '../leaf', '../dist', '../pkg', 'dist', 'pkg' ] attr_master :name, :version, :date, :series, :status, :author, :maintainer, :email, :homepage, :summary, :description, :license attr_master :dependencies, :executables, :requirements, :architecture, :category, :recommends, :replaces attr_accessor :source, :md5 attr_accessor :dir, :project, :exclude, :include, :format subsection :gem, :autorequire, :platform, :require_paths # generated attr_reader :package_name, :series_versioning def init( options={} ) @dir ||= LOCATIONS.find { |f| File.directory?(f) } || 'dist' #@name ||= master['name'] #@status ||= master['status'] || 'beta/stable' #@date ||= master['date'] || Time.now.strftime("%Y-%m-%d") #@series ||= master['series'] || '1' @maintainer ||= @author @status ||= 'beta/stable' @date ||= Time.now.strftime("%Y-%m-%d") @series ||= '1' @architecture ||= 'any' @license ||= 'Ruby/GPL' d = @date.split('-').collect{ |e| e.to_i } #d[0] = d[0] - 2000 # No need to keep the 2000 @version ||= d.join('.') if $BUILD_VERSION buildno = eval(Time.now.strftime("%H*60+%M")) @version += ".#{buildno}" end unless @series puts "Series is required." exit 0 end @package_name ||= @name + '-' + @version #@package_name ||= @name + ',' + @date # rubyforge doesn't allow commas #@author ||= master['author'] #@email ||= master['email'] #@summary ||= master['summary'] @project ||= master['rubyforge']['project'] #@homepage ||= master['homepage'] || master['rubyforge']['homepage'] @homepage ||= master['rubyforge']['homepage'] @exclude ||= [] @exclude |= MUST_EXCLUDE @include ||= ['**/*'] # format types include 'tgz', 'tbz', 'zip', 'tar.gz' 'tar.bz2', 'gem' and 'deb'. @format ||= master['distribute'] || [ 'gem', 'tar.bz2', 'zip' ] @format = [@format].flatten @format.collect! { |t| t.to_s.strip.downcase } @dependencies ||= [] @executables ||= [] @requirements ||= [] @recommends ||= [] @conflicts ||= [] @replaces ||= [] # gem specific (at least in this context) if defined?(Gem) if @platform begin @platform = ::Gem.const_get(@platform) rescue NameError @platform = ::Gem::Platform::RUBY end else @platform ||= ::Gem::Platform::RUBY end #@autorequire end end def run( options={} ) puts "Creating #{@format.join(',')} packages..." # create package image group_dir_path = File.join( @dir, @package_name ) package_dir_path = File.join( @dir, @package_name, @package_name ) if FileTest.directory?(group_dir_path) print "Package directory '#{package_name}' already exists. Conitnue anyway 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(*@include) package_files.exclude(*@exclude) if @exclude and not @exclude.empty? FileUtils.mkdir_p @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( @dir, @package_name ) ) do @format.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} #{@package_name}.#{prefix} #{@package_name}} if sh_cmd end puts end # create gem package if @format.include?('gem') if defined?(Gem) run_gem else puts "Package .gem requested, but rubygems not found (skipped)." end end # create debian package if @format.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 @format.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 # support methods ------------------------------------------- private # This builds the gem package. def run_gem spec = Gem::Specification.new { |s| s.name = @name s.version = @version @dependencies.each { |d,v| if v s.add_dependency(d, v) else s.add_dependency(d) end } s.platform = @platform s.summary = @summary s.requirements = @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(*@include) package_files.exclude(*@exclude) if @exclude and not @exclude.empty? s.files = package_files.to_a s.require_path = 'lib' s.autorequire = @autorequire if @autorequire s.author = @author s.email = @email s.rubyforge_project = @project s.homepage = @homepage s.executables = @executables s.require_paths = @require_paths if @require_paths 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( @dir, @package_name ) ) } #sh %{mv ./*.gem #{@dir}/} end # This build the Debiam package. def run_deb # build the debian control file dep = dependencies.collect{ |d, v| if v "#{d} (#{v})" else d end }.join(', ') # Some debian fields not yet used: # Installed-Size: 1024 # Conflicts: wile-e-coyote, ... # Replaces: sam-sheepdog # Pre-Depends: perl, ... # Suggests: docbook ctrl = %{ Package: #{name} Version: #{version} Priority: optional Architecture: #{architecture} Essential: no }.tabto(0) ctrl << "Section: #{category}" if category ctrl << "Depends: #{dep}" unless dep.empty? ctrl << "Recommends: #{recommends.join(' | ')}" unless recommends.empty? ctrl << %{ Maintainer: #{maintainer} [#{email}] Provides: #{name} Description: #{summary} . #{description} }.tabto(0) debname = architecture == 'any' ? "ruby_#{name}_#{version}.deb" : "ruby_#{name}_#{version}_#{architecture}.deb" debdir = File.join( @dir, @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 package def run_pac unless @source puts "URL 'source' is require for proto package." return nil end if section.key?('proto') _dep = section['proto']['dependenciers'] || dependencies _rep = section['proto']['replaces'] || replaces _con = section['proto']['conflicts'] || conflicts end _dep = _dep.collect{ |d| "'#{d}'" }.join(' ') _rep = _rep.collect{ |d| "'#{d}'" }.join(' ') _con = _rep.collect{ |d| "'#{d}'" }.join(' ') proto = %{ pkgname=#{name} pkgver=#{version} pkgrel=#{series} pkgdesc="#{summary}" url="#{homepage}" license="#{license}" depends=(#{_dep}) conflicts=(#{_con}) replaces=(#{_rep}) source=(#{source}) md5sums=(#{md5}) }.tabto(0) # What are these for? # install= # backup=() if 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( @dir, @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