require 'rbconfig' require 'fileutils' module Reap # = Installer # # The Installer class generates a specialized install.rb # script specifically for your project. It currently # does not support c/c++ ext/ compilation. class Installer include TaskUtils def self.config(name) # XXX use pathname prefix = Regexp.quote(Config::CONFIG["prefix"]) exec_prefix = Regexp.quote(Config::CONFIG["exec_prefix"]) Config::CONFIG[name].gsub(/\A\/?(#{prefix}|#{exec_prefix})\/?/, '') end KINDS = [ :bin, :lib, :ext, :data, :conf, :doc ] SITE_DIRS = { :bin => config("bindir"), :lib => config("sitelibdir"), :ext => config("sitearchdir"), :data => config("datadir"), :conf => config("sysconfdir"), :doc => File.join(config("datadir"), "doc"), } VEND_DIRS = { :bin => config("bindir"), :lib => config("rubylibdir"), :ext => config("archdir"), :data => config("datadir"), :conf => config("sysconfdir"), :doc => File.join(config("datadir"), "doc"), } MODES = { :bin => 0755, :lib => 0644, :ext => 0755, # was: 0555, :data => 0644, :conf => 0644, :doc => 0644, } attr_accessor :trunk, :template, :options def initialize( ins ) super @trunk = '.' unless @trunk @spec = parse( @template ) @transfer = Hash.new { |h,k| h[k] = [] } end #-- # TODO use shellwords #++ def parse( spec ) lines = spec.strip.split("\n") lines.each { |line| words = line.strip.split(/\s+/) send( *words ) } end # substitute variables def vsub( str ) return nil if str.nil? str = str.gsub( '$version', @options[:version].to_s ) str = str.gsub( '$name', @options[:name].to_s ) str end # Return the installation directory. def dir( kind, mode=:site ) case mode when :site SITE_DIRS[ kind ] when :vendor VEND_DIRS[ kind ] else raise ArgumentError, "unknown mode -- #{mode}" end end # Return installation prefix. def prefix( kind ) Config::CONFIG["prefix"] end #-- # DSL methods for setting installation spec. #++ # Setup a lib installation transfer. def lib( from, glob, to ) to = '' if to == '.' @transfer[:lib] << { :from=>vsub(from), :glob=>vsub(glob), :to=>vsub(to) } end # Setup a bin installation transfer. def bin( from, glob, to ) to = '' if to == '.' @transfer[:bin] << { :from=>vsub(from), :glob=>vsub(glob), :to=>vsub(to) } end # Compile script and write to install file (install.rb). def compile_and_write script = "" script << "# INSTALL SCRIPT\n" script << "# Generated by Reap\n" script << "# #{Time.now}\n" script << "\n" script << compile script << "\n" script << "# END" write( script ) end alias_method :call, :compile_and_write private # Compile installation instructions. def compile mkdirp = [] script = '' Dir.chdir( @trunk ) do KINDS.each { |kind| @transfer[kind].each { |trans| next unless File.directory?( trans[:from] ) files = [] Dir.chdir( trans[:from] ) { files = Dir.glob( trans[:glob] ).reject { |f| File.directory?( f ) } } files.each { |file| f = File.join( trans[:from], file ) t = File.join( prefix(kind), dir(kind), trans[:to], file ) m = MODES[kind] d = File.dirname(t) unless mkdirp.include?(d) script << "mkdir_p '%s'\n" % d mkdirp << d end script << "install '%s', '%s', :mode=>%o\n" % [ f, t, m ] } } } end script end def write( script ) install_file = File.join( @trunk, 'install.rb' ) if File.file?( install_file ) script_template = File.read( install_file ) script = script_template.gsub(/\# INSTALL SCRIPT.*\# END/, script) end File.open( install_file, 'w+' ) do |f| f << script end end end end end #module Reap