#-- # ___ _ # | _ \__ _ __| |____ _ __ _ ___ # | _/ _` / _| / / _` / _` / -_) # |_| \__,_\__|_\_\__,_\__, \___| # |___/ #++ require 'facet/fileutils/safe_ln.rb' require 'facet/filelist.rb' unless defined?( FileList ) # prevent overlap with Rake's module Reap # = Package # # This class creates standard .zip, .tgz, or .tbz # packages, plus .gem or .deb distributions. # # Builds distribution packages. The package task supports # tar.gz, tar.bz2, zip source packages and gem, pacman and # debian ditribution packages. # # Task specific settings: # # dir Directory in which to store distributions. # include Files to include in distribution. # exclude Files to exclude from those. # distribute List of distribution types desired. # (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. # # RubyGems specific settings: # # 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 # class Package include TaskUtils MUST_EXCLUDE = [ 'InstalledFiles', '**/CVS/**/*', '**/*~', 'dist', 'pkg', 'release' ] LOCATIONS = [ 'dist', 'pkg', 'release', 'package', 'distribution' ] attr :pkg # Setup package task settings. def initialize( pkg ) @pkg = pkg #pkg.name ||= master.name #pkg.title ||= master.title #pkg.version ||= master.version #pkg.project ||= master.project || master.rubyforge.project #pkg.homepage ||= master.homepage || master.rubyforge.homepage pkg.trunk ||= '.' # '.' probably will become the mater default. pkg.status ||= 'development' pkg.series ||= '1' pkg.author ||= "Anonymous" pkg.maintainer ||= pkg.author pkg.email ||= '' pkg.summary ||= '' pkg.architecture ||= 'any' pkg.license ||= 'Ruby/GPL' pkg.dir ||= LOCATIONS.find { |f| File.directory?(f) } || 'dist' pkg.date ||= Time.now.strftime("%Y-%m-%d") 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 # load rubygems if available # (only do this if need be in future?) begin require 'rubygems' rescue LoadError # no rubygems end 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 # Generate packages. def generate_packages release_folder = File.join( pkg.dir, pkg.package_name ) mirror_folder = File.join( pkg.dir, pkg.package_name, pkg.package_name ) @release_path = File.expand_path( release_folder ) @mirror_path = File.expand_path( mirror_folder ) if FileTest.directory?(release_folder) if $FORCE puts "Removing old directory '#{File.expand_path(release_folder)}'..." FileUtils.rm_r(release_folder) else puts "Package directory '#{pkg.package_name}' already exists. Use -f option to overwrite." return nil end end puts "Creating #{pkg.distribute.join(',')} packages..." # First we make a copy of the files to be distributed. FileUtils.mkdir_p( mirror_folder ) #pkg.dir #rescue nil @package_files = nil Dir.chdir( pkg.trunk ) do @package_files = ::FileList.new(*pkg.include) #package_files.include(*pkg.include) @package_files.exclude(*pkg.exclude) if pkg.exclude #and not pkg.exclude.empty? @package_files.resolve # reslove FileList here to be sure we get the right files! @package_files.each do |f| from = f #pkg.trunk ? File.join( pkg.trunk, f ) : f to = File.join( @mirror_path, f ) to_dir = File.dirname( to ) FileUtils.mkdir_p( to_dir ) if not File.exist?(to_dir) if File.directory?( from ) FileUtils.mkdir_p( to ) else FileUtils.rm_f( to ) FileUtils.safe_ln( from, to ) end end end # Now we create standard packages from the copy. FileUtils.chdir( @release_path ) 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 "\n[SHELL #{prefix.upcase}]" when 'tgz', 'tar.gz' prefix = ( t == 'tgz' ? 'tgz' : 'tar.gz' ) sh_cmd = 'tar --gzip -cvf' puts "\n[SHELL #{prefix.upcase}]" when 'zip' prefix = 'zip' sh_cmd = 'zip -r' puts "\n[SHELL #{prefix.upcase}]" when 'gem', 'deb', 'pac' sh_cmd = nil else puts "WARNING: 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 "WARNING: 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 "WARNING: 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 "WARNING: Pacman package requested, but required tools not found (skipped)." end end # we can remove mirror folder now #FileUtils.rm_r(mirror_folder) return true end private # This builds the gem package. def run_gem # use subsection if given if pkg.gem pkg = pkg().__merge__( pkg.gem ) else pkg = pkg() end 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 "[RUBYGEMS]" Dir.chdir( @mirror_path ) { Gem.manage_gems Gem::Builder.new(spec).build gems = Dir.glob( './*.gem' ) gems.each{ |f| FileUtils.mv( f, @release_path ) } } puts end # This build the Debiam package. def run_deb # use subsection if given if pkg.debian pkg = pkg().__merge__( pkg.debian ) else pkg = pkg() end # 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 = @release_path #File.join( pkg.dir, pkg.package_name ) debdir = File.join( pkgdir, 'debian' ) #debdebdir = File.join( debdir, 'DEBIAN' ) debfile = File.join( pkgdir, debname ) puts "[SHELL DEB]" FileUtils.mkdir_p(debdir) Dir.chdir( @mirror_path ) do unless provide_setup_rb puts "Setup.rb is missing. Forced to skip debian package creation." return nil end cmd = %{ruby setup.rb } cmd << '-q ' unless $VERBOSE cmd << %{all --installdirs=std --root=#{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}} end puts end # This builds a pacman (archlinux) PKGBUILD script. def run_pacman # use subsection if it exists if pkg.pacman pkg = pkg().__merge__( pkg.pacman ) else pkg = pkg() end unless pkg.source tell "SOURCE, a URL to the source package, is a required field" 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 proto << %{ makedepends=()" build() { cd $startdir/src/$pkgname-$pkgver ./ruby setup.rb --prefix=/usr make || return 1 make DESTDIR=$startdir/pkg install } }.tabto(0) else proto << %{ build() { cd $startdir/src/$pkgname-$pkgver ./ruby setup.rb --prefix=/usr } }.tabto(0) end pacdir = File.join( @release_path, 'pacman' ) #pacpacdir = File.join( pacdir, 'PACMAN' ) pacfile = File.join( pacdir, 'PKGBUILD' ) tell "[PACMAN PKGBUILD]" FileUtils.mkdir_p( pacdir ) File.open( pacfile, 'w') { |f| f << proto } tell "Created #{pacfile}" puts end end #class Package end #module Reap