Rakefile in reap-9.3.1 vs Rakefile in reap-9.3.3

- old
+ new

@@ -1,1496 +1,2 @@ -#!/usr/bin/env ruby -require 'optparse' -require 'rbconfig' - -# TODO: Is this the best way to do this? Is there any other way? -PACKAGE = ( - if file = Dir['{.,meta/}unixname{,.txt}'].first - File.read(file).strip - else - abort "Requires package unix-name. Edit .unixname or meta/unixname." - end -) -GENERATE_DOCS = true # TODO: maybe just check if it already exists instead? - -# UberTask defines all the tasks one needs for the typical end-user -# to configure, compile, test and install a package to their system. - -class UberTask - - attr_accessor :package - attr_accessor :gendocs - - attr :config - - # - def initialize(package_name, generate_docs=true) #:yield: - @package = package_name - @gendocs = generate_docs - @config = Configure.new - yield[self] if block_given? - define - end - - # - def define - # Default task will compile and test. - - task :default => [:setup, :test] - - # - # TASK config - # - - desc "Configure for your system." - task :config => [:config_load] do - config.quiet = Rake.application.options.silent - config.exec_config - end - - if File.exist?(Configure::FILENAME) - desc "Reconfigure for your system." - task :reconfig do - config.quiet = Rake.application.options.silent - config.exec_config - end - end - - # - - task :config_load do - if File.file?('.config') - config.load - else - abort "Run rake config first." - end - end - - # - # TASK show - # - - desc "Display current configuraiton." - task :show do - config.show - end - - # - # TASK clean & clobber - # - - require 'rake/clean' - - CLOBBER.include(Configure::FILENAME) - CLOBBER.include(Installer::MANIFEST) - CLOBBER.include(File.join('doc', PACKAGE, 'rdoc')) if GENERATE_DOCS - - task :clean => [:makeclean] - task :clobber => [:distclean] - - task :makeclean do - config.extensions.each do |dir| - Dir.chdir(dir) do - config.make 'clean' if File.file?('Makefile') - end - end - end - - task :distclean do - config.extensions.each do |dir| - Dir.chdir(dir) do - config.make 'distclean' if File.file?('Makefile') - end - end - end - - # - # TASK all - # - - if File.exist?('.config') - desc "Setup, test, document and install." - task :all => [:setup, :test, :doc, :index, :install] - else - # shortcut - desc "Configure, setup, test, document and install." - task :all => [:config, :setup, :test, :doc, :install] - end - - # - # TASK setup - # - - # TODO: No shebang until it works at install time and doesn't overwrite the repo scripts. - - desc "Compile extensions." # update shebangs - task :setup => [:config_load, :extconf, :make] #, :shebang] - - task :extconf => [:config_load] do - config.extensions.each do |dir| - next if File.file?(File.join(dir, 'Makefile')) - Dir.chdir(dir) do - config.ruby('extconf.rb', config.configopt) - end - end - end - - task :make => [:config_load] do - config.extensions.each do |dir| - Dir.chdir(dir) do - config.make - end - end - end - - task :shebang => [:config_load, :installer] do - Dir.chdir('bin') do - executables = Dir['*'].select{ |f| File.file?(f) } - executables.each do |file| - INSTALLER.update_shebang_line(file) - end - end - end - - # - # TASK test - # - - # You can provide a test/suite.rb file to be run if - # by the testrb command, if you special testing requirements. - - desc "Run unit tests." - task :test => [:config_load, :setup] do - runner = config.testrunner - # build testrb options - opt = [] - opt << " -v" if verbose? - opt << " --runner #{runner}" - if File.file?('test/suite.rb') - notests = false - opt << "test/suite.rb" - else - notests = Dir["test/**/*.rb"].empty? - lib = ["lib"] + config.extensions.collect{ |d| File.dirname(d) } - opt << "-I" + lib.join(':') - opt << Dir["test/**/{test,tc}*.rb"] - end - opt = opt.flatten.join(' ').strip - # run tests - if notests - $stderr.puts 'No tests.' #if verbose? - else - cmd = "testrb #{opt}" - $stderr.puts cmd if verbose? - system cmd #config.ruby "-S tesrb", opt - end - end - - # - # TASK doc - # - - # If a .document file is available, it will be - # used to compile the list of toplevel files - # to document. (For some reason it doesn't use - # the .document file on it's own.) - # - # Note that this places the rdoc in doc/name/rdoc, - # So that they are subsequently installed to your - # system by the installer. To prevent this use - # the @without_doc@ config option. - - if GENERATE_DOCS - desc "Generate html docs." - task :doc => [:config_load] do - output = File.join('doc', PACKAGE, 'rdoc') - title = (PACKAGE.capitalize + " API").strip - main = Dir.glob("README{,.txt}", File::FNM_CASEFOLD).first - template = config.rdoctemplate || 'html' - - opt = [] - opt << "-U" - opt << "-S" - opt << "--op=#{output}" - opt << "--template=#{template}" - opt << "--title=#{title}" - opt << "--main=#{main}" if main - - if File.exist?('.document') - files = File.read('.document').split("\n") - files.reject!{ |l| l =~ /^\s*[#]/ || l !~ /\S/ } - files.collect!{ |f| f.strip } - opt << files - else - opt << main if main - opt << ["lib", "ext"] - end - - opt = opt.flatten - - if no_harm? - puts "rdoc #{opt.join(' ').strip}" - else - #sh "rdoc {opt.join(' ').strip}" - require 'rdoc/rdoc' - ::RDoc::RDoc.new.document(opt) - end - end - else - task :doc do - end - end - - # - # TASK index - # - - # This task generates and installs the ri docs to - # the designated installdirs-based location. - # - # It is unfortunate that this isn't more like rdocing. - # In that we can't first generate them, then install them. - # We have to do it all at once. We may be able to fix this - # later, but it requires special action by the installer, - # so it will have to wait. - - desc "Generate and install index docs." - task :index => [:config_load] do - case config.installdirs - when 'std' - output = "--ri-system" - when 'site' - output = "--ri-site" - when 'home' - output = "--ri" - else - abort "bad config: sould not be possible -- installdirs = #{config.installdirs}" - end - - opt = [] - - if File.exist?('.document') - files = File.read('.document').split("\n") - files.reject!{ |l| l =~ /^\s*[#]/ || l !~ /\S/ } - files.collect!{ |f| f.strip } - opt << files - else - opt << ["lib", "ext"] - end - - opt << "-U" - opt << output - opt << files - opt = opt.flatten - - if no_harm? - puts "rdoc #{opt.join(' ').strip}" - else - #sh "rdoc #{opt.join(' ').strip}" - require 'rdoc/rdoc' - ::RDoc::RDoc.new.document(opt) - end - end - - # - # TASK install & uninstall - # - - # Install uses the installation procedures developed by Minero Aoki - # for setup.rb. Over time it would be nice to "rakeify" these. Every - # file installed is listed in the install manifest (.installedfiles). - # - # The uninstall task simply reads the install manifest, and removes - # the files listed there from your system. Note, when you use the - # clobber task, this file is removed. So be sure not to clobber, - # if you pan to uninstall! - # - # TODO: Maybe the install manifest should never be clobber, expect - # after an uninstall? - - desc "Install package files." - task :install => [:config_load, :setup, :installer] do - @installer.exec_install - unless config.without_index? - Rake::Task[:index].invoke - end - end - - if Installer.uninstallable? - desc "Remove previously installed files." - task :uninstall => [:confg_load, :installer] do - @installer.exec_uninstall - end - end - - task :installer do - @installer = Installer.new(config) - @installer.verbose = env('verbose') - @installer.no_harm = env('noharm') - end - - # - # TASK help - # - - # Yea, we all need help some times ;) - - desc "Display config help information." - task :help do - puts Configure::HELP - end - end - - # Get environament variables. - - def env(*keys) - key = keys.find{ |k| ENV[k.to_s] || ENV[k.to_s.downcase] || ENV[k.to_s.upcase] } - ENV[key] if key - end - - def verbose? - env('verbose') - end - - def no_harm? - env('noharm','nowrite') - end - -end - -# Configure class is used to generate the .config file -# contining the settings used for installing a package. -# These settings can be altered by the user if required -# for their particular system, either via the command line -# or environment variables. - -class Configure - - Version = [1,0,0] - Copyright = "Copyright (c) 2008 Trans" - - Error = Class.new(StandardError) - - RBCONFIG = ::Config::CONFIG - FILENAME = '.config' - - DESCRIPTIONS = [ - [:prefix , 'Path prefix of target environment'], - [:bindir , 'Directory for commands'], - [:libdir , 'Directory for libraries'], - [:datadir , 'Directory for shared data'], - [:mandir , 'Directory for man pages'], - [:docdir , 'Directory for documentation'], - [:sysconfdir , 'Directory for system configuration files'], - [:localstatedir , 'Directory for local state data'], - [:libruby , 'Directory for ruby libraries'], - [:librubyver , 'Directory for standard ruby libraries'], - [:librubyverarch , 'Directory for standard ruby extensions'], - [:siteruby , 'Directory for version-independent aux ruby libraries'], - [:siterubyver , 'Directory for aux ruby libraries'], - [:siterubyverarch , 'Directory for aux ruby binaries'], - [:rbdir , 'Directory for ruby scripts'], - [:sodir , 'Directory for ruby extentions'], - [:rubypath , 'Path to set to #! line'], - [:rubyprog , 'Ruby program using for installation'], - [:makeprog , 'Make program to compile ruby extentions'], - [:without_ext , 'Do not compile/install ruby extentions'], - [:without_doc , 'Do not install docs'], - [:without_index , 'Do not generate ri docs'], - [:shebang , 'Shebang line (#!) editing mode (all,ruby,never)'], - [:installdirs , 'Install location mode (std,site,home)'], - [:testrunner , 'Runner to use for testing (console|tk|gtk|gtk2)'], - [:rdoctemplate , 'Document template to use (html)'] - ] - - # List of configurable options. - OPTIONS = DESCRIPTIONS.collect{ |(k,v)| k.to_s } - - # Pathname attribute. Pathnames are automatically expanded - # unless they start with '$', a path variable. - def self.attr_pathname(name) - class_eval %{ - def #{name} - @#{name}.gsub(%r<\\$([^/]+)>){ self[$1] } - end - def #{name}=(path) - raise Error, "bad config: #{name.to_s.upcase} requires argument" unless path - @#{name} = (path[0,1] == '$' ? path : File.expand_path(path)) - end - } - end - - # List of pathnames. These are not expanded though. - def self.attr_pathlist(name) - class_eval %{ - def #{name} - @#{name} - end - def #{name}=(pathlist) - case pathlist - when Array - @#{name} = pathlist - else - @#{name} = pathlist.to_s.split(/[:;,]/) - end - end - } - end - - # Adds boolean support. - def self.attr_accessor(*names) - bools, attrs = names.partition{ |name| name.to_s =~ /\?$/ } - attr_boolean *bools - super *attrs - end - - # Boolean attribute. Can be assigned true, false, nil, or - # a string matching yes|true|y|t or no|false|n|f. - def self.attr_boolean(*names) - names.each do |name| - name = name.to_s.chomp('?') - attr_reader name # MAYBE: Deprecate - code = %{ - def #{name}?; @#{name}; end - def #{name}=(val) - case val - when true, false, nil - @#{name} = val - else - case val.to_s.downcase - when 'y', 'yes', 't', 'true' - @#{name} = true - when 'n', 'no', 'f', 'false' - @#{name} = false - else - raise Error, "bad config: use #{name.upcase}=(yes|no) [\#{val}]" - end - end - end - } - class_eval code - end - end - - # path prefix of target environment - attr_pathname :prefix - - # directory for commands - attr_pathname :bindir - - #directory for libraries - attr_pathname :libdir - - # directory for shared data - attr_pathname :datadir - - # directory for man pages - attr_pathname :mandir - - # directory for documentation - attr_pathname :docdir - - # directory for system configuration files - attr_pathname :sysconfdir - - # directory for local state data - attr_pathname :localstatedir - - # directory for ruby libraries - attr_pathname :libruby - - # directory for standard ruby libraries - attr_pathname :librubyver - - # directory for standard ruby extensions - attr_pathname :librubyverarch - - # directory for version-independent aux ruby libraries - attr_pathname :siteruby - - # directory for aux ruby libraries - attr_pathname :siterubyver - - # directory for aux ruby binaries - attr_pathname :siterubyverarch - - # directory for ruby scripts - attr_pathname :rbdir - - # directory for ruby extentions - attr_pathname :sodir - - # path to set to #! line - attr_accessor :rubypath - - # ruby program using for installation - attr_accessor :rubyprog - - # program to compile ruby extentions - attr_accessor :makeprog - - # shebang line (#!) editing mode (all,ruby,never)', 'all/ruby/never - attr_accessor :shebang - - # install location mode (std: libruby, site: site_ruby, home: $HOME) - attr_accessor :installdirs - - # options to pass to extconfig.rb - attr_accessor :configopt - - # do not compile/install ruby extentions - attr_accessor :without_ext? - - # do not compile/install ruby extentions - attr_accessor :without_doc? - - # do not compile/install ruby extentions - attr_accessor :without_index? - - # document template to use [html] - attr_accessor :rdoctemplate - - # runner to use for testing (console|tk|gtk|gtk2) - attr_accessor :testrunner - - # Run silently. - attr_accessor :quiet? - - # shebang has only three options. - def shebang=(val) - if %w(all ruby never).include?(val) - @shebang = val - else - raise Error, "bad config: use SHEBANG=(all|ruby|never) [#{val}]" - end - end - - # installdirs has only three options; and it has side-effects. - def installdirs=(val) - @installdirs = val - case val.to_s - when 'std' - self.rbdir = '$librubyver' - self.sodir = '$librubyverarch' - when 'site' - self.rbdir = '$siterubyver' - self.sodir = '$siterubyverarch' - when 'home' - raise Error, 'HOME is not set.' unless ENV['HOME'] - self.prefix = ENV['HOME'] - self.rbdir = '$libdir/ruby' - self.sodir = '$libdir/ruby' - else - raise Error, "bad config: use INSTALLDIRS=(std|site|home|local) [#{val}]" - end - end - - # Get configuration from environment. - def getenv - OPTIONS.each do |name| - if value = ENV[name] || ENV[name.upcase] - __send__("#{name}=",value) - end - end - end - - # Load configuration. - def load - #if File.file?(FILENAME) - begin - File.foreach(FILENAME) do |line| - k, v = *line.split(/=/, 2) - __send__("#{k}=",v.strip) #self[k] = v.strip - end - rescue Errno::ENOENT - raise Error, $!.message + "\n#{File.basename($0)} config first" - end - #end - end - - # Save configuration. - def save - File.open(FILENAME, 'w') do |f| - OPTIONS.each do |name| - val = self[name] - case val - when Array - f << "#{name}=#{val.join(';')}\n" - else - f << "#{name}=#{val}\n" - end - end - end - end - - def show - fmt = "%-20s %s\n" - OPTIONS.each do |name| - value = self[name] - printf fmt, name, __send__(name) if value - end - printf fmt, 'VERBOSE', verbose? ? 'yes' : 'no' - printf fmt, 'NOHARM', no_harm? ? 'yes' : 'no' - end - - # Get unresloved attribute. - def [](name) - instance_variable_get("@#{name}") - end - - # Set attribute. - def []=(name, value) - instance_variable_set("@#{name}", value) - end - - # Resolved attribute. (for paths) - #def resolve(name) - # self[name].gsub(%r<\\$([^/]+)>){ self[$1] } - #end - - # New ConfigTable - def initialize(values=nil) - initialize_defaults - if values - values.each{ |k,v| __send__("#{k}=", v) } - end - yeild(self) if block_given? - end - - # Assign CONFIG defaults - # - # TODO: Does this handle 'nmake' on windows? - - def initialize_defaults - prefix = RBCONFIG['prefix'] - - rubypath = File.join(RBCONFIG['bindir'], RBCONFIG['ruby_install_name'] + RBCONFIG['EXEEXT']) - - # V > 1.6.3 - libruby = "#{prefix}/lib/ruby" - librubyver = RBCONFIG['rubylibdir'] - librubyverarch = RBCONFIG['archdir'] - siteruby = RBCONFIG['sitedir'] - siterubyver = RBCONFIG['sitelibdir'] - siterubyverarch = RBCONFIG['sitearchdir'] - - if arg = RBCONFIG['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } - makeprog = arg.sub(/'/, '').split(/=/, 2)[1] - else - makeprog = 'make' - end - - parameterize = lambda do |path| - val = RBCONFIG[path] - val.sub(/\A#{Regexp.quote(prefix)}/, '$prefix') - end - - self.prefix = prefix - self.bindir = parameterize['bindir'] - self.libdir = parameterize['libdir'] - self.datadir = parameterize['datadir'] - self.mandir = parameterize['mandir'] - self.docdir = File.dirname(parameterize['docdir']) # b/c of trailing $(PACKAGE) - self.sysconfdir = parameterize['sysconfdir'] - self.localstatedir = parameterize['localstatedir'] - self.libruby = libruby - self.librubyver = librubyver - self.librubyverarch = librubyverarch - self.siteruby = siteruby - self.siterubyver = siterubyver - self.siterubyverarch = siterubyverarch - self.rbdir = '$siterubyver' - self.sodir = '$siterubyverarch' - self.rubypath = rubypath - self.rubyprog = rubypath - self.makeprog = makeprog - self.shebang = 'ruby' - self.without_ext = 'no' - self.without_doc = 'no' - self.without_index = 'no' - self.installdirs = 'site' - self.rdoctemplate = 'html' - self.testrunner = 'console' - self.configopt = '' - end - - def show - fmt = "%-20s %s\n" - OPTIONS.each do |name| - value = self[name] - printf fmt, name, __send__(name) - end - end - - # - def exec_config - getenv - save - #create_makefiles if compiles? - create_rakefile - show unless quiet? - puts "Configuration saved." - end - - def extconfs - @extconfs ||= Dir['ext/**/extconf.rb'] - end - - def extensions - @extensions ||= extconfs.collect{ |f| File.dirname(f) } - end - - def compiles? - !extensions.empty? - end - - #def create_makefiles - # extensions.each do |dir| - # Dir.chdir(dir) do - # ruby('extconf.rb', configopt) - # end - # end - #end - - # Create rakefile, if it doesn't exist. - def create_rakefile - unless Dir['[Rr]akefile{,.rb}'].first - File.open('Rakefile', 'w') do |f| - f << DATA.read - end - end - end - - def ruby(*args) - command rubyprog, *args - end - - def make(task = nil) - command(*[makeprog, task].compact) - end - - def command(*args) - $stderr.puts args.join(' ') if $DEBUG - system(*args) or raise RuntimeError, "system(#{args.map{|a| a.inspect }.join(' ')}) failed" - end - - # Help output. - - HELP = <<-END - The Uber Rakefile v#{Version.join('.')} - - Usage: - - #{File.basename($0)} [options] - - The Uber Rakefile is designed to install a Ruby package. It does this by breaking - the steps involved down into individual rake tasks. This gives the installer the - opportunity to adjust installation settings as required for a particular - platform. A typical installation procedure is: - - $ rake config - $ rake setup - $ rake install - - If you are certain of the default configuration settings (which are usually correct), - you can use the simple shortcut: - - $ rake all - - See rake -T for all available tasks. - - Below is the list of options available for the config task. - - Configuration options: - END - - fmt = " %-20s %s\n" - DESCRIPTIONS.each do |name, desc| - HELP << fmt % ["#{name}", desc] - end - - HELP << <<-END - - Other options: - verbose Provide extra ouput - nowrite Do not write to disk. - noharm Same as nowrite. - - Installdirs options correspond to: libruby, site_ruby and $HOME repsectively. - - END - -# Other options: -# -q --quiet Run silently -# -h --help Display this help information -# --version Show version -# --copyright Show copyright -# -# END - - HELP.gsub!(/^\ \ /,'') - - # CLI runner. This uses OptionParser to parse - # command line arguments. (May chnage to GetoptLong). - - def self.start_cli - config = new - - opts = OptionParser.new - - DESCRIPTIONS.each do |name, desc| - opts.on("--#{name}", desc) do |val| - ENV[name.upcase] = val - end - end - - # Tail options (eg. commands in option form) - - opts.on("-q", "--quiet", "Run silently") do |val| - config.quiet = true - end - - opts.on_tail("-h", "--help", "Display help information") do - puts HELP - exit - end - - opts.on_tail("--version", "Show version") do - puts File.basename($0) + ' v' + Setup::Version.join('.') - exit - end - - opts.on_tail("--copyright", "Show copyright") do - puts Setup::Copyright - exit - end - - begin - opts.parse!(ARGV) - rescue OptionParser::InvalidOption - $stderr.puts $!.capitalize - exit 1 - end - - begin - config.exec_config - rescue Configure::Error - raise if $DEBUG - $stderr.puts $!.message - $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." - exit 1 - end - end - -end - -# Command line run -if __FILE__ == $0 - Configure.start_cli -end - -# -# -# - -class Installer - - MANIFEST = '.installedfiles' - - FILETYPES = %w( bin lib ext data conf man doc ) - - # Has this been installed previously? - def self.uninstallable? - File.exist?(MANIFEST) - end - - # Configuration - attr :config - - attr_writer :no_harm - attr_writer :verbose - - attr_accessor :install_prefix - - # New Installer. - def initialize(config) #:yield: - srcroot = '.' - objroot = '.' - - @config = config - - @srcdir = File.expand_path(srcroot) - @objdir = File.expand_path(objroot) - @currdir = '.' - - @verbose = false - - #self.verbose = ENV['VERBOSE'] if ENV['VERBOSE'] - #self.no_harm = ENV['NO_HARM'] if ENV['NO_HARM'] - - yield(self) if block_given? - end - - def inspect - "#<#{self.class} #{File.basename(@srcdir)}>" - end - - # Do not write to disk. - def no_harm? ; @no_harm; end - - # Verbose output? - def verbose? ; @verbose || @no_harm; end - - # Yes, very very verbose output. - def very_verbose? ; @very_verbose; end - - def verbose_off #:yield: - begin - save, @verbose = verbose?, false - yield - ensure - @verbose = save - end - end - - # Are we running an installation? - def installation?; @installation; end - def installation!; @installation = true; end - - # - # Hook Script API bases - # - - def srcdir_root - @srcdir - end - - def objdir_root - @objdir - end - - def relpath - @currdir - end - - # Used as a null traversal. - def noop(rel) ; end - - def update_shebang_line(path) - return if no_harm? - return if config.shebang == 'never' - old = Shebang.load(path) - if old - if old.args.size > 1 - $stderr.puts "warning: #{path}" - $stderr.puts "Shebang line has too many args." - $stderr.puts "It is not portable and your program may not work." - end - new = new_shebang(old) - return if new.to_s == old.to_s - else - return unless config.shebang == 'all' - new = Shebang.new(config.rubypath) - end - $stderr.puts "updating shebang: #{File.basename(path)}" if verbose? - open_atomic_writer(path) {|output| - File.open(path, 'rb') {|f| - f.gets if old # discard - output.puts new.to_s - output.print f.read - } - } - end - - def new_shebang(old) - if /\Aruby/ =~ File.basename(old.cmd) - Shebang.new(config.rubypath, old.args) - elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby' - Shebang.new(config.rubypath, old.args[1..-1]) - else - return old unless config.shebang == 'all' - Shebang.new(config.rubypath) - end - end - - def open_atomic_writer(path, &block) - tmpfile = File.basename(path) + '.tmp' - begin - File.open(tmpfile, 'wb', &block) - File.rename tmpfile, File.basename(path) - ensure - File.unlink tmpfile if File.exist?(tmpfile) - end - end - - class Shebang - def Shebang.load(path) - line = nil - File.open(path) {|f| - line = f.gets - } - return nil unless /\A#!/ =~ line - parse(line) - end - - def Shebang.parse(line) - cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ') - new(cmd, args) - end - - def initialize(cmd, args = []) - @cmd = cmd - @args = args - end - - attr_reader :cmd - attr_reader :args - - def to_s - "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}") - end - end - - # - # TASK install - # - - def exec_install - installation! # mark that we are installing - #rm_f MANIFEST # we'll append rather then delete - exec_task_traverse 'install' - end - - def install_dir_bin(rel) - install_files targetfiles(), "#{config.bindir}/#{rel}", 0755 - end - - def install_dir_lib(rel) - install_files libfiles(), "#{config.rbdir}/#{rel}", 0644 - end - - def install_dir_ext(rel) - return unless extdir?(curr_srcdir()) - install_files rubyextentions('.'), - "#{config.sodir}/#{File.dirname(rel)}", 0555 - end - - def install_dir_data(rel) - install_files targetfiles(), "#{config.datadir}/#{rel}", 0644 - end - - def install_dir_doc(rel) - return if config.without_doc? - install_files targetfiles(), "#{config.docdir}/#{rel}", 0644 - end - - def install_dir_conf(rel) - # FIXME: should not remove current config files - # (rename previous file to .old/.org) - install_files targetfiles(), "#{config.sysconfdir}/#{rel}", 0644 - end - - def install_dir_man(rel) - install_files targetfiles(), "#{config.mandir}/#{rel}", 0644 - end - - def install_files(list, dest, mode) - mkdir_p dest, install_prefix - list.each do |fname| - install fname, dest, mode, install_prefix - end - end - - def libfiles - glob_reject(%w(*.y *.output), targetfiles()) - end - - def rubyextentions(dir) - ents = glob_select("*.#{dllext}", targetfiles()) - if ents.empty? - setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first" - end - ents - end - - def dllext - RBCONFIG['DLEXT'] - end - - def targetfiles - mapdir(existfiles() - hookfiles()) - end - - def mapdir(ents) - ents.map {|ent| - if File.exist?(ent) - then ent # objdir - else "#{curr_srcdir()}/#{ent}" # srcdir - end - } - end - - # picked up many entries from cvs-1.11.1/src/ignore.c - JUNK_FILES = %w( - core RCSLOG tags TAGS .make.state - .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb - *~ *.old *.bak *.BAK *.orig *.rej _$* *$ - - *.org *.in .* - ) - - def existfiles - glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.'))) - end - - def hookfiles - %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| - %w( config setup install clean ).map {|t| sprintf(fmt, t) } - }.flatten - end - - def glob_select(pat, ents) - re = globs2re([pat]) - ents.select {|ent| re =~ ent } - end - - def glob_reject(pats, ents) - re = globs2re(pats) - ents.reject {|ent| re =~ ent } - end - - GLOB2REGEX = { - '.' => '\.', - '$' => '\$', - '#' => '\#', - '*' => '.*' - } - - def globs2re(pats) - /\A(?:#{ - pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|') - })\z/ - end - - # - # TASK uninstall - # - - def exec_uninstall - files = File.read(MANIFEST).split("\n") - files.each do |file| - next if /^\#/ =~ file # skip comments - rm_f(file) if File.exist?(file) - end - end - - # - # Traversing - # - - # - def exec_task_traverse(task) - run_hook "pre-#{task}" - FILETYPES.each do |type| - if type == 'ext' and config.without_ext == 'yes' - $stderr.puts 'skipping ext/* by user option' if verbose? - next - end - traverse task, type, "#{task}_dir_#{type}" - end - run_hook "post-#{task}" - end - - # - def traverse(task, rel, mid) - dive_into(rel) { - run_hook "pre-#{task}" - __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') - directories_of(curr_srcdir()).each do |d| - traverse task, "#{rel}/#{d}", mid - end - run_hook "post-#{task}" - } - end - - # - def dive_into(rel) - return unless File.dir?("#{@srcdir}/#{rel}") - - dir = File.basename(rel) - Dir.mkdir dir unless File.dir?(dir) - prevdir = Dir.pwd - Dir.chdir dir - $stderr.puts '---> ' + rel if very_verbose? - @currdir = rel - yield - Dir.chdir prevdir - $stderr.puts '<--- ' + rel if very_verbose? - @currdir = File.dirname(rel) - end - - # - def run_hook(id) - path = [ "#{curr_srcdir()}/#{id}", - "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) } - return unless path - begin - instance_eval File.read(path), path, 1 - rescue - raise if $DEBUG - setup_rb_error "hook #{path} failed:\n" + $!.message - end - end - - # File Operations - # - # These use: #verbose? and #no_harm? - - def binread(fname) - File.open(fname, 'rb'){ |f| - return f.read - } - end - - def mkdir_p(dirname, prefix = nil) - dirname = prefix + File.expand_path(dirname) if prefix - $stderr.puts "mkdir -p #{dirname}" if verbose? - return if no_harm? - - # Does not check '/', it's too abnormal. - dirs = File.expand_path(dirname).split(%r<(?=/)>) - if /\A[a-z]:\z/i =~ dirs[0] - disk = dirs.shift - dirs[0] = disk + dirs[0] - end - dirs.each_index do |idx| - path = dirs[0..idx].join('') - Dir.mkdir path unless File.dir?(path) - end - end - - def rm_f(path) - $stderr.puts "rm -f #{path}" if verbose? - return if no_harm? - force_remove_file path - end - - def rm_rf(path) - $stderr.puts "rm -rf #{path}" if verbose? - return if no_harm? - remove_tree path - end - - def remove_tree(path) - if File.symlink?(path) - remove_file path - elsif File.dir?(path) - remove_tree0 path - else - force_remove_file path - end - end - - def remove_tree0(path) - Dir.foreach(path) do |ent| - next if ent == '.' - next if ent == '..' - entpath = "#{path}/#{ent}" - if File.symlink?(entpath) - remove_file entpath - elsif File.dir?(entpath) - remove_tree0 entpath - else - force_remove_file entpath - end - end - begin - Dir.rmdir path - rescue Errno::ENOTEMPTY - # directory may not be empty - end - end - - def move_file(src, dest) - force_remove_file dest - begin - File.rename src, dest - rescue - File.open(dest, 'wb') {|f| - f.write binread(src) - } - File.chmod File.stat(src).mode, dest - File.unlink src - end - end - - def force_remove_file(path) - begin - remove_file path - rescue - end - end - - def remove_file(path) - File.chmod 0777, path - File.unlink path - end - - def install(from, dest, mode, prefix = nil) - $stderr.puts "install #{from} #{dest}" if verbose? - return if no_harm? - - realdest = prefix ? prefix + File.expand_path(dest) : dest - realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) - str = binread(from) - if diff?(str, realdest) - verbose_off { - rm_f realdest if File.exist?(realdest) - } - File.open(realdest, 'wb') {|f| - f.write str - } - File.chmod mode, realdest - - File.open("#{objdir_root()}/#{MANIFEST}", 'a') {|f| - if prefix - f.puts realdest.sub(prefix, '') - else - f.puts realdest - end - } - end - end - - def diff?(new_content, path) - return true unless File.exist?(path) - new_content != binread(path) - end - - def command(*args) - $stderr.puts args.join(' ') if verbose? - system(*args) or raise RuntimeError, - "system(#{args.map{|a| a.inspect }.join(' ')}) failed" - end - - def ruby(*args) - command config.rubyprog, *args - end - - def make(task = nil) - command(*[config.makeprog, task].compact) - end - - def extdir?(dir) - File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb") - end - - def files_of(dir) - Dir.open(dir) {|d| - return d.select {|ent| File.file?("#{dir}/#{ent}") } - } - end - - DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn ) - - def directories_of(dir) - Dir.open(dir) {|d| - return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT - } - end - - # - # Hook Script API - # - # These require: #srcdir_root, #objdir_root, #relpath - # - - # - def get_config(key) - config.__send__(key) - end - - # obsolete: use metaconfig to change configuration - # TODO: what to do with? - def set_config(key, val) - config[key] = val - end - - # - # srcdir/objdir (works only in the package directory) - # - - def curr_srcdir - "#{srcdir_root()}/#{relpath()}" - end - - def curr_objdir - "#{objdir_root()}/#{relpath()}" - end - - def srcfile(path) - "#{curr_srcdir()}/#{path}" - end - - def srcexist?(path) - File.exist?(srcfile(path)) - end - - def srcdirectory?(path) - File.dir?(srcfile(path)) - end - - def srcfile?(path) - File.file?(srcfile(path)) - end - - def srcentries(path = '.') - Dir.open("#{curr_srcdir()}/#{path}") {|d| - return d.to_a - %w(. ..) - } - end - - def srcfiles(path = '.') - srcentries(path).select {|fname| - File.file?(File.join(curr_srcdir(), path, fname)) - } - end - - def srcdirectories(path = '.') - srcentries(path).select {|fname| - File.dir?(File.join(curr_srcdir(), path, fname)) - } - end - -end - -# -# Ruby extensions -# - -unless File.respond_to?(:read) # Ruby 1.6 and less - def File.read(fname) - open(fname) {|f| - return f.read - } - end -end - -unless Errno.const_defined?(:ENOTEMPTY) # Windows? - module Errno - class ENOTEMPTY - # We do not raise this exception, implementation is not needed. - end - end -end - -# for corrupted Windows' stat(2) -def File.dir?(path) - File.directory?((path[-1,1] == '/') ? path : path + '/') -end - -# -# The End -# - -UberTask.new(PACKAGE, GENERATE_DOCS) +require File.join(File.dirname(__FILE__), "setup.rb")