From c688ccaebbdea27994d915da684d271508ae3ccb Mon Sep 17 00:00:00 2001 From: Ralph Amissah Date: Fri, 8 Nov 2013 20:48:05 -0500 Subject: v4 v5: version & changelog --- data/doc/sisu/CHANGELOG_v4 | 7 +++++++ data/doc/sisu/CHANGELOG_v5 | 7 +++++++ data/sisu/v4/v/version.yml | 6 +++--- data/sisu/v5/v/version.yml | 6 +++--- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/data/doc/sisu/CHANGELOG_v4 b/data/doc/sisu/CHANGELOG_v4 index dcf40f63..09534da0 100644 --- a/data/doc/sisu/CHANGELOG_v4 +++ b/data/doc/sisu/CHANGELOG_v4 @@ -23,6 +23,13 @@ v2 branch is removed; it is available in sisu =< 3.3.2 %% Reverse Chronological: +%% 4.2.12.orig.tar.xz (2013-11-08:44/5) +http://sources.sisudoc.org/gitweb/?p=code/sisu.git;a=shortlog;h=refs/tags/sisu_4.2.12 +http://sources.sisudoc.org/gitweb/?p=code/sisu.git;a=shortlog;h=refs/tags/debian/sisu_4.2.12-1 +http://www.jus.uio.no/sisu/pkg/src/sisu_4.2.12.orig.tar.xz + sisu_4.2.12.orig.tar.xz + sisu_4.2.12-1.dsc + %% 4.2.11.orig.tar.xz (2013-11-05:44/2) http://sources.sisudoc.org/gitweb/?p=code/sisu.git;a=shortlog;h=refs/tags/sisu_4.2.11 http://sources.sisudoc.org/gitweb/?p=code/sisu.git;a=shortlog;h=refs/tags/debian/sisu_4.2.11-1 diff --git a/data/doc/sisu/CHANGELOG_v5 b/data/doc/sisu/CHANGELOG_v5 index 56ca73be..b44fef8d 100644 --- a/data/doc/sisu/CHANGELOG_v5 +++ b/data/doc/sisu/CHANGELOG_v5 @@ -23,6 +23,13 @@ v2 branch is removed; it is available in sisu =< 3.3.2 %% Reverse Chronological: +%% 5.0.25.orig.tar.xz (2013-11-08:44/5) +http://sources.sisudoc.org/gitweb/?p=code/sisu.git;a=shortlog;h=refs/tags/sisu_5.0.25 +http://sources.sisudoc.org/gitweb/?p=code/sisu.git;a=shortlog;h=refs/tags/debian/sisu_5.0.25-1 +http://www.jus.uio.no/sisu/pkg/src/sisu_5.0.25.orig.tar.xz + sisu_5.0.25.orig.tar.xz + sisu_5.0.25-1.dsc + %% 5.0.24.orig.tar.xz (2013-11-05:44/2) http://sources.sisudoc.org/gitweb/?p=code/sisu.git;a=shortlog;h=refs/tags/sisu_5.0.24 http://sources.sisudoc.org/gitweb/?p=code/sisu.git;a=shortlog;h=refs/tags/debian/sisu_5.0.24-1 diff --git a/data/sisu/v4/v/version.yml b/data/sisu/v4/v/version.yml index d010c88f..bc4a319b 100644 --- a/data/sisu/v4/v/version.yml +++ b/data/sisu/v4/v/version.yml @@ -1,5 +1,5 @@ --- -:version: 4.2.11 -:date_stamp: 2013w44/2 -:date: "2013-11-05" +:version: 4.2.12 +:date_stamp: 2013w44/5 +:date: "2013-11-08" :project: SiSU diff --git a/data/sisu/v5/v/version.yml b/data/sisu/v5/v/version.yml index 39bc4b65..530acb56 100644 --- a/data/sisu/v5/v/version.yml +++ b/data/sisu/v5/v/version.yml @@ -1,5 +1,5 @@ --- -:version: 5.0.24 -:date_stamp: 2013w44/2 -:date: "2013-11-05" +:version: 5.0.25 +:date_stamp: 2013w44/5 +:date: "2013-11-08" :project: SiSU -- cgit v1.2.3 From 7de03034813a591c34b0f31086a6ed87ab068c27 Mon Sep 17 00:00:00 2001 From: Ralph Amissah Date: Fri, 8 Nov 2013 20:50:41 -0500 Subject: v4 v5: sisu_manual, minor info addition --- data/doc/sisu/CHANGELOG_v4 | 2 ++ data/doc/sisu/CHANGELOG_v5 | 2 ++ .../markup-samples/sisu_manual/en/sisu_markup.sst | 25 ++++++++++++++++++++-- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/data/doc/sisu/CHANGELOG_v4 b/data/doc/sisu/CHANGELOG_v4 index 09534da0..f20d4b83 100644 --- a/data/doc/sisu/CHANGELOG_v4 +++ b/data/doc/sisu/CHANGELOG_v4 @@ -30,6 +30,8 @@ http://www.jus.uio.no/sisu/pkg/src/sisu_4.2.12.orig.tar.xz sisu_4.2.12.orig.tar.xz sisu_4.2.12-1.dsc +* sisu_manual, minor info addition + %% 4.2.11.orig.tar.xz (2013-11-05:44/2) http://sources.sisudoc.org/gitweb/?p=code/sisu.git;a=shortlog;h=refs/tags/sisu_4.2.11 http://sources.sisudoc.org/gitweb/?p=code/sisu.git;a=shortlog;h=refs/tags/debian/sisu_4.2.11-1 diff --git a/data/doc/sisu/CHANGELOG_v5 b/data/doc/sisu/CHANGELOG_v5 index b44fef8d..5cb6573d 100644 --- a/data/doc/sisu/CHANGELOG_v5 +++ b/data/doc/sisu/CHANGELOG_v5 @@ -30,6 +30,8 @@ http://www.jus.uio.no/sisu/pkg/src/sisu_5.0.25.orig.tar.xz sisu_5.0.25.orig.tar.xz sisu_5.0.25-1.dsc +* sisu_manual, minor info addition + %% 5.0.24.orig.tar.xz (2013-11-05:44/2) http://sources.sisudoc.org/gitweb/?p=code/sisu.git;a=shortlog;h=refs/tags/sisu_5.0.24 http://sources.sisudoc.org/gitweb/?p=code/sisu.git;a=shortlog;h=refs/tags/debian/sisu_5.0.24-1 diff --git a/data/doc/sisu/markup-samples/sisu_manual/en/sisu_markup.sst b/data/doc/sisu/markup-samples/sisu_manual/en/sisu_markup.sst index 92b7f430..ddf6e570 100644 --- a/data/doc/sisu/markup-samples/sisu_manual/en/sisu_markup.sst +++ b/data/doc/sisu/markup-samples/sisu_manual/en/sisu_markup.sst @@ -510,7 +510,7 @@ code{ normal text ~[* editors notes, numbered asterisk footnote/endnote series ]~ continues -normal text ~[+ editors notes, numbered asterisk footnote/endnote series ]~ continues +normal text ~[+ editors notes, numbered plus symbol footnote/endnote series ]~ continues }code @@ -518,7 +518,7 @@ normal text ~[+ editors notes, numbered asterisk footnote/endnote series ]~ cont normal text ~[* editors notes, numbered asterisk footnote/endnote series ]~ continues -normal text ~[+ editors notes, numbered asterisk footnote/endnote series ]~ continues +normal text ~[+ editors notes, numbered plus symbol footnote/endnote series ]~ continues !_ Alternative endnote pair notation for footnotes/endnotes: @@ -1285,3 +1285,24 @@ code{ }code The form described above should be relied on. Within the Vim editor it results in the text thus linked becoming hyperlinked to the document it is calling in which is convenient for editing. + +1~ Substitutions + +!_ markup example: + +code{ + +The current Debian is ${debian_stable} the next debian will be ${debian_testing} + +Configure substitution in _sisu/sisu_document_make + +@make: + :substitute: /${debian_stable}/,'*{Wheezy}*' /${debian_testing}/,'*{Jessie}*' + +}code + +!_ resulting output: + +The current Debian is ${debian_stable} the next debian will be ${debian_testing} + +Configure substitution in _sisu/sisu_document_make -- cgit v1.2.3 From cf8ff1a3ec40f321e9ecf7afdbc4f1b8254597a4 Mon Sep 17 00:00:00 2001 From: Ralph Amissah Date: Fri, 8 Nov 2013 20:52:43 -0500 Subject: v4 v5: rake (& rant) sisu installer * do less by default * remove rant generated sisu-install --- data/doc/sisu/CHANGELOG_v4 | 4 + data/doc/sisu/CHANGELOG_v5 | 4 + rbuild | 34 +- sisu-install | 3088 -------------------------------------------- 4 files changed, 22 insertions(+), 3108 deletions(-) delete mode 100755 sisu-install diff --git a/data/doc/sisu/CHANGELOG_v4 b/data/doc/sisu/CHANGELOG_v4 index f20d4b83..e1ca2f64 100644 --- a/data/doc/sisu/CHANGELOG_v4 +++ b/data/doc/sisu/CHANGELOG_v4 @@ -30,6 +30,10 @@ http://www.jus.uio.no/sisu/pkg/src/sisu_4.2.12.orig.tar.xz sisu_4.2.12.orig.tar.xz sisu_4.2.12-1.dsc +* rake (& rant) sisu installer + * do less by default + * removed rant generated sisu-install + * sisu_manual, minor info addition %% 4.2.11.orig.tar.xz (2013-11-05:44/2) diff --git a/data/doc/sisu/CHANGELOG_v5 b/data/doc/sisu/CHANGELOG_v5 index 5cb6573d..35f82417 100644 --- a/data/doc/sisu/CHANGELOG_v5 +++ b/data/doc/sisu/CHANGELOG_v5 @@ -30,6 +30,10 @@ http://www.jus.uio.no/sisu/pkg/src/sisu_5.0.25.orig.tar.xz sisu_5.0.25.orig.tar.xz sisu_5.0.25-1.dsc +* rake (& rant) sisu installer + * do less by default + * removed rant generated sisu-install + * sisu_manual, minor info addition %% 5.0.24.orig.tar.xz (2013-11-05:44/2) diff --git a/rbuild b/rbuild index f6220de5..084d3ad7 100644 --- a/rbuild +++ b/rbuild @@ -29,8 +29,6 @@ raise 'Please, use ruby1.9.3 or later.' if RUBY_VERSION < '1.9.3' rake -T [if rant is preferred and installed] rant -T - [else [if sisu-install is present]] - ruby sisu-install -T SiSU can also be Setup/Installation using: * Minero Aoki's setup.rb, provided along with SiSU, or @@ -106,7 +104,7 @@ class Project_details def version stamp={} v="#{dir.pwd}/conf/sisu/version.yml" - version=if File.exist?(v) + if File.exist?(v) stamp=YAML::load(File::open(v)) stamp[:version] else '' @@ -119,7 +117,7 @@ def answer?(ask) print ask + " ['yes', 'no' or 'quit']: " resp=File.new('/dev/tty').gets.strip #resp=gets.strip - ans=if resp == 'yes'; true + if resp == 'yes'; true elsif resp == 'no'; false elsif resp =~/^quit|exit$/; exit else puts "[please type: 'yes', 'no' or 'quit']" @@ -129,13 +127,9 @@ end def default_notice ans= %{#{@p.rake_rant} Information on alternative actions is available using: - [if rake is installed:] - "rake help" or "rake -T" - [if rant is installed:] - "rant help" or "rant -T" - [else [if sisu-install is present]:] - "sisu-install help" or "sisu-install -T" - Default action selected - "install and to setup #{@p.name}" proceed? } + [if rake (or rant) is installed:] + "rake help" or "rake -T" (or "rant help" or "rant -T") + Default action selected - "install #{@p.name}" proceed? } resp=answer?(ans) exit unless resp end @@ -217,23 +211,23 @@ def project_help Commands quick start list - #{@p.name} Rake/Rant Help: (This Rakefile or Rantfile uses the same directory structure as setup.rb) + #{@p.name} Rake/Rant Help: (Rakefile or Rantfile) rake -T or rant -T # a task list, (generated by Rake or Rant) for more complete and up to date help rake system or rant system # system info used Quick start install and remove project #{@p.name} as root: rake or rant # install #{@p.name} + rake base - rake setup or rant setup # install #{@p.name} (without additonal configuration and generating of test file) + rake setup # install #{@p.name} (larger install) - rake install or rant reinstall # reinstall #{@p.name} + rake install # reinstall #{@p.name} - rake remove or rant remove # clobber/remove #{@p.name}, current version: #{@p.version} - rake remove_package or rant remove_package # clobber/remove #{@p.name}, all versions - -For a more detailed and up to date list of command options use + rake remove # clobber/remove #{@p.name}, current version: #{@p.version} + rake remove_package # clobber/remove #{@p.name}, all versions +For a more detailed and up to date list of command options use: rake -T rant -T @@ -242,9 +236,9 @@ end def tasks sys('rant -T') end - #%% tasks + #% tasks desc "rake/rant (as root type 'rake' or 'rant' for default action)" -task :default => [:default_notice,:project] +task :default => [:default_notice,:setup_base] #task :default => [:help,:notice,:project] desc "Setup/Install #{@p.name} and try generate a file" task :project=> [:setup_bin,:setup_lib,:setup_conf,:setup_share,:setup_data,:setup_man,:setup_vim,:post_install_note] diff --git a/sisu-install b/sisu-install deleted file mode 100755 index 206867fd..00000000 --- a/sisu-install +++ /dev/null @@ -1,3088 +0,0 @@ -#!/usr/bin/env ruby - -# sisu-install - Monolithic rant script, autogenerated by rant-import 0.5.8. -# -# Copyright (C) 2005 Stefan Lang -# -# This program is free software. -# You can distribute/modify this program under the terms of -# the GNU LGPL, Lesser General Public License version 2.1. - - -require 'getoptlong' - - -require 'rbconfig' - -unless Process::Status.method_defined?(:success?) # new in 1.8.2 - class Process::Status - def success?; exitstatus == 0; end - end -end -unless Regexp.respond_to? :union # new in 1.8.1 - def Regexp.union(*patterns) - return /(?!)/ if patterns.empty? - Regexp.new(patterns.join("|")) - end -end -if RUBY_VERSION < "1.8.2" - class Array - undef_method :flatten, :flatten! - def flatten - cp = self.dup - cp.flatten! - cp - end - def flatten! - res = [] - flattened = false - self.each { |e| - if e.respond_to? :to_ary - res.concat(e.to_ary) - flattened = true - else - res << e - end - } - if flattened - replace(res) - flatten! - self - end - end - end -end - -class String - def _rant_sub_ext(ext, new_ext = nil) - if new_ext - self.sub(/#{Regexp.escape ext}$/, new_ext) - else - self.sub(/(\.[^.]*$)|$/, ".#{ext}") - end - end -end - -module Rant - VERSION = '0.5.8' - - @__rant_no_value__ = Object.new.freeze - def self.__rant_no_value__ - @__rant_no_value__ - end - - module Env - OS = ::Config::CONFIG['target'] - RUBY = ::Config::CONFIG['ruby_install_name'] - RUBY_BINDIR = ::Config::CONFIG['bindir'] - RUBY_EXE = File.join(RUBY_BINDIR, RUBY + ::Config::CONFIG["EXEEXT"]) - - @@zip_bin = false - @@tar_bin = false - - if OS =~ /mswin/i - def on_windows?; true; end - else - def on_windows?; false; end - end - - def have_zip? - if @@zip_bin == false - @@zip_bin = find_bin "zip" - end - !@@zip_bin.nil? - end - def have_tar? - if @@tar_bin == false - @@tar_bin = find_bin "tar" - end - !@@tar_bin.nil? - end - def pathes - path = ENV[on_windows? ? "Path" : "PATH"] - return [] unless path - path.split(on_windows? ? ";" : ":") - end - def find_bin bin_name - if on_windows? - bin_name_exe = nil - if bin_name !~ /\.[^\.]{1,3}$/i - bin_name_exe = bin_name + ".exe" - end - pathes.each { |dir| - file = File.join(dir, bin_name) - return file if test(?f, file) - if bin_name_exe - file = File.join(dir, bin_name_exe) - return file if test(?f, file) - end - } - else - pathes.each { |dir| - file = File.join(dir, bin_name) - return file if test(?x, file) - } - end - nil - end - def shell_path path - if on_windows? - path = path.tr("/", "\\") - if path.include? ' ' - '"' + path + '"' - else - path - end - else - if path.include? ' ' - "'" + path + "'" - else - path - end - end - end - extend self - end # module Env - - module Sys - def sp(arg) - if arg.respond_to? :to_ary - arg.to_ary.map{ |e| sp e }.join(' ') - else - _escaped_path arg - end - end - def escape(arg) - if arg.respond_to? :to_ary - arg.to_ary.map{ |e| escape e }.join(' ') - else - _escaped arg - end - end - if Env.on_windows? - def _escaped_path(path) - _escaped(path.to_s.tr("/", "\\")) - end - def _escaped(arg) - sarg = arg.to_s - return sarg unless sarg.include?(" ") - sarg << "\\" if sarg[-1].chr == "\\" - "\"#{sarg}\"" - end - def regular_filename(fn) - fn.to_str.tr("\\", "/").gsub(%r{/{2,}}, "/") - end - else - def _escaped_path(path) - path.to_s.gsub(/(?=\s)/, "\\") - end - alias _escaped _escaped_path - def regular_filename(fn) - fn.to_str.gsub(%r{/{2,}}, "/") - end - end - private :_escaped_path - private :_escaped - def split_all(path) - names = regular_filename(path).split(%r{/}) - names[0] = "/" if names[0] && names[0].empty? - names - end - extend self - end # module Sys - - - ROOT_RANTFILE = "root.rant" - SUB_RANTFILE = "sub.rant" - RANTFILES = [ "Rantfile", "rantfile", ROOT_RANTFILE ] - - CODE_IMPORTS = [] - - class RantAbortException < StandardError - end - - class RantDoneException < StandardError - end - - class Error < StandardError - end - - module Generators - end - - module RantVar - - class Error < Rant::Error - end - - class ConstraintError < Error - - attr_reader :constraint, :val - - def initialize(constraint, val, msg = nil) - @msg = msg - @constraint = constraint - @val = val - end - - def message - val_desc = @val.inspect - val_desc[7..-1] = "..." if val_desc.length > 10 - "#{val_desc} doesn't match constraint: #@constraint" - end - end - - class NotAConstraintFactoryError < Error - attr_reader :obj - def initialize(obj, msg = nil) - @msg = msg - @obj = obj - end - def message - obj_desc = @obj.inspect - obj_desc[7..-1] = "..." if obj_desc.length > 10 - "#{obj_desc} is not a valid constraint factory" - end - end - - class InvalidVidError < Error - def initialize(vid, msg = nil) - @msg = msg - @vid = vid - end - def message - vid_desc = @vid.inspect - vid_desc[7..-1] = "..." if vid_desc.length > 10 - "#{vid_desc} is not a valid var identifier" - end - end - - class InvalidConstraintError < Error - end - - class QueryError < Error - end - - class Space - - @@env_ref = Object.new - - def initialize - @store = {} - @constraints = {} - end - - def query(*args, &block) - case args.size - when 0 - raise QueryError, "no arguments", caller - when 1 - arg = args.first - if Hash === arg - if arg.size == 1 - arg.each { |k,v| - self[k] = v if self[k].nil? - } - self - else - init_all arg - end - else - self[arg] - end - when 2, 3 - vid, cf, val = *args - constrain vid, - get_factory(cf).rant_constraint - self[vid] = val if val - else - raise QueryError, "too many arguments" - end - end - - def restrict vid, ct, *ct_args - if vid.respond_to? :to_ary - vid.to_ary.each { |v| restrict(v, ct, *ct_args) } - else - constrain vid, - get_factory(ct).rant_constraint(*ct_args) - end - self - end - - def get_factory id - if String === id || Symbol === id - id = Constraints.const_get(id) rescue nil - end - unless id.respond_to? :rant_constraint - raise NotAConstraintFactoryError.new(id), caller - end - id - end - private :get_factory - - def [](vid) - vid = RantVar.valid_vid vid - val = @store[vid] - val.equal?(@@env_ref) ? ENV[vid] : val - end - - def []=(vid, val) - vid = RantVar.valid_vid(vid) - c = @constraints[vid] - if @store[vid] == @@env_ref - ENV[vid] = c ? c.filter(val) : val - else - @store[vid] = c ? c.filter(val) : val - end - end - - def env(*vars) - vars.flatten.each { |var| - vid = RantVar.valid_vid(var) - cur_val = @store[vid] - next if cur_val == @@env_ref - ENV[vid] = cur_val unless cur_val.nil? - @store[vid] = @@env_ref - } - nil - end - - def set_all hash - unless Hash === hash - raise QueryError, - "set_all argument has to be a hash" - end - hash.each_pair { |k, v| - self[k] = v - } - end - - def init_all hash - unless Hash === hash - raise QueryError, - "init_all argument has to be a hash" - end - hash.each_pair { |k, v| - self[k] = v if self[k].nil? - } - end - - def constrain vid, constraint - vid = RantVar.valid_vid(vid) - unless RantVar.valid_constraint? constraint - raise InvalidConstraintError, constraint - end - @constraints[vid] = constraint - if @store.member? vid - begin - val = @store[vid] - @store[vid] = constraint.filter(@store[vid]) - rescue - @store[vid] = constraint.default - raise ConstraintError.new(constraint, val) - end - else - @store[vid] = constraint.default - end - end - - def has_var?(vid) - !self[vid].nil? - end - - def _set(vid, val) #:nodoc: - @store[vid] = val - end - - def _get(vid) #:nodoc: - @store[vid] - end - - def _init(vid, val) #:nodoc: - @store[vid] ||= val - end - - end # class Space - - module Constraint - def matches? val - filter val - true - rescue - return false - end - end - - def valid_vid(obj) - case obj - when String; obj - when Symbol; obj.to_s - else - if obj.respond_to? :to_str - obj.to_str - else - raise InvalidVidError.new(obj) - end - end - end - - def valid_constraint?(obj) - obj.respond_to?(:filter) && - obj.respond_to?(:matches?) && - obj.respond_to?(:default) - end - - module_function :valid_constraint?, :valid_vid - - module Constraints - class AutoList - include Constraint - class << self - alias rant_constraint new - end - def filter(val) - if val.respond_to? :to_ary - val.to_ary - elsif val.nil? - raise ConstraintError.new(self, val) - else - [val] - end - end - def default - [] - end - def to_s - "list or single, non-nil value" - end - end - end # module Constraints - end # module RantVar -end # module Rant - - -require 'fileutils' - - -module Rant - def FileList(arg) - if arg.respond_to?(:to_rant_filelist) - arg.to_rant_filelist - elsif arg.respond_to?(:to_ary) - FileList.new(arg.to_ary) - else - raise TypeError, - "cannot convert #{arg.class} into Rant::FileList" - end - end - module_function :FileList - class FileList - include Enumerable - - ESC_SEPARATOR = Regexp.escape(File::SEPARATOR) - ESC_ALT_SEPARATOR = File::ALT_SEPARATOR ? - Regexp.escape(File::ALT_SEPARATOR) : nil - - class << self - def [](*patterns) - new.hide_dotfiles.include(*patterns) - end - def glob(*patterns) - fl = new.hide_dotfiles.ignore(".", "..").include(*patterns) - if block_given? then yield fl else fl end - end - def glob_all(*patterns) - fl = new.ignore(".", "..").include(*patterns) - if block_given? then yield fl else fl end - end - end - - def initialize(store = []) - @pending = false - @def_glob_dotfiles = true - @items = store - @ignore_rx = nil - @keep = {} - @actions = [] - end - alias _object_dup dup - private :_object_dup - def dup - c = _object_dup - c.items = @items.dup - c.actions = @actions.dup - c.ignore_rx = @ignore_rx.dup if @ignore_rx - c.instance_variable_set(:@keep, @keep.dup) - c - end - def copy - c = _object_dup - c.items = @items.map { |entry| entry.dup } - c.actions = @actions.dup - c.ignore_rx = @ignore_rx.dup if @ignore_rx - h_keep = {} - @keep.each_key { |entry| h_keep[entry] = true } - c.instance_variable_set(:@keep, h_keep) - c - end - def glob_dotfiles? - @def_glob_dotfiles - end - def glob_dotfiles=(flag) - @def_glob_dotfiles = flag ? true : false - end - def hide_dotfiles - @def_glob_dotfiles = false - self - end - def glob_dotfiles - @def_glob_dotfiles = true - self - end - - protected - attr_accessor :actions, :items - attr_accessor :pending - attr_accessor :ignore_rx - - public - def each(&block) - resolve if @pending - @items.each(&block) - self - end - def to_ary - resolve if @pending - @items - end - alias to_a to_ary - alias entries to_ary # entries: defined in Enumerable - def to_rant_filelist - self - end - def +(other) - if other.respond_to? :to_rant_filelist - c = other.to_rant_filelist.dup - c.actions.concat(@actions) - c.items.concat(@items) - c.pending = !c.actions.empty? - c - elsif other.respond_to? :to_ary - c = dup - c.actions << - [:apply_ary_method_1, :concat, other.to_ary.dup] - c.pending = true - c - else - raise TypeError, - "cannot add #{other.class} to Rant::FileList" - end - end - def <<(file) - @actions << [:apply_ary_method_1, :push, file] - @keep[file] = true - @pending = true - self - end - def keep(entry) - @keep[entry] = true - @items << entry - self - end - def concat(ary) - if @pending - ary = ary.to_ary.dup - @actions << [:apply_ary_method_1, :concat, ary] - else - ix = ignore_rx and ary = ary.to_ary.reject { |f| f =~ ix } - @items.concat(ary) - end - self - end - def size - resolve if @pending - @items.size - end - alias length size - def empty? - resolve if @pending - @items.empty? - end - def join(sep = ' ') - resolve if @pending - @items.join(sep) - end - def pop - resolve if @pending - @items.pop - end - def push(entry) - resolve if @pending - @items.push(entry) if entry !~ ignore_rx - self - end - def shift - resolve if @pending - @items.shift - end - def unshift(entry) - resolve if @pending - @items.unshift(entry) if entry !~ ignore_rx - self - end - if Object.method_defined?(:fcall) || Object.method_defined?(:funcall) # in Ruby 1.9 like __send__ - @@__send_private__ = Object.method_defined?(:fcall) ? :fcall : :funcall - def resolve - @pending = false - @actions.each{ |action| self.__send__(@@__send_private__, *action) }.clear - ix = ignore_rx - if ix - @items.reject! { |f| f =~ ix && !@keep[f] } - end - self - end - else - def resolve - @pending = false - @actions.each{ |action| self.__send__(*action) }.clear - ix = ignore_rx - if ix - @items.reject! { |f| f =~ ix && !@keep[f] } - end - self - end - end - def include(*pats) - @def_glob_dotfiles ? glob_all(*pats) : glob_unix(*pats) - end - alias glob include - def glob_unix(*patterns) - patterns.flatten.each { |pat| - @actions << [:apply_glob_unix, pat] - } - @pending = true - self - end - def glob_all(*patterns) - patterns.flatten.each { |pat| - @actions << [:apply_glob_all, pat] - } - @pending = true - self - end - if RUBY_VERSION < "1.8.2" - FN_DOTFILE_RX_ = ESC_ALT_SEPARATOR ? - /(^|(#{ESC_SEPARATOR}|#{ESC_ALT_SEPARATOR})+)\..* - ((#{ESC_SEPARATOR}|#{ESC_ALT_SEPARATOR})+|$)/x : - /(^|#{ESC_SEPARATOR}+)\..* (#{ESC_SEPARATOR}+|$)/x - def apply_glob_unix(pattern) - inc_files = Dir.glob(pattern) - unless pattern =~ /(^|\/)\./ - inc_files.reject! { |fn| fn =~ FN_DOTFILE_RX_ } - end - @items.concat(inc_files) - end - else - def apply_glob_unix(pattern) - @items.concat(Dir.glob(pattern)) - end - end - private :apply_glob_unix - def apply_glob_all(pattern) - @items.concat(Dir.glob(pattern, File::FNM_DOTMATCH)) - end - private :apply_glob_all - def exclude(*patterns) - patterns.each { |pat| - if Regexp === pat - @actions << [:apply_exclude_rx, pat] - else - @actions << [:apply_exclude, pat] - end - } - @pending = true - self - end - def ignore(*patterns) - patterns.each { |pat| - add_ignore_rx(Regexp === pat ? pat : mk_all_rx(pat)) - } - @pending = true - self - end - def add_ignore_rx(rx) - @ignore_rx = - if @ignore_rx - Regexp.union(@ignore_rx, rx) - else - rx - end - end - private :add_ignore_rx - def apply_exclude(pattern) - @items.reject! { |elem| - File.fnmatch?(pattern, elem, File::FNM_DOTMATCH) && !@keep[elem] - } - end - private :apply_exclude - def apply_exclude_rx(rx) - @items.reject! { |elem| - elem =~ rx && !@keep[elem] - } - end - private :apply_exclude_rx - def exclude_name(*names) - names.each { |name| - @actions << [:apply_exclude_rx, mk_all_rx(name)] - } - @pending = true - self - end - alias shun exclude_name - if File::ALT_SEPARATOR - def mk_all_rx(file) - /(^|(#{ESC_SEPARATOR}|#{ESC_ALT_SEPARATOR})+)#{Regexp.escape(file)} - ((#{ESC_SEPARATOR}|#{ESC_ALT_SEPARATOR})+|$)/x - end - else - def mk_all_rx(file) - /(^|#{ESC_SEPARATOR}+)#{Regexp.escape(file)} - (#{ESC_SEPARATOR}+|$)/x - end - end - private :mk_all_rx - def exclude_path(*patterns) - patterns.each { |pat| - @actions << [:apply_exclude_path, pat] - } - @pending = true - self - end - def apply_exclude_path(pattern) - flags = File::FNM_DOTMATCH|File::FNM_PATHNAME - @items.reject! { |elem| - File.fnmatch?(pattern, elem, flags) && !@keep[elem] - } - end - private :apply_exclude - def select(&block) - d = dup - d.actions << [:apply_select, block] - d.pending = true - d - end - alias find_all select - def apply_select blk - @items = @items.select(&blk) - end - private :apply_select - def map(&block) - d = dup - d.actions << [:apply_ary_method, :map!, block] - d.pending = true - d - end - alias collect map - def sub_ext(ext, new_ext=nil) - map { |f| f._rant_sub_ext ext, new_ext } - end - def ext(ext_str) - sub_ext(ext_str) - end - def arglist - Rant::Sys.sp to_ary - end - alias to_s arglist - alias object_inspect inspect - def uniq! - @actions << [:apply_ary_method, :uniq!] - @pending = true - self - end - def sort! - @actions << [:apply_ary_method, :sort!] - @pending = true - self - end - def map!(&block) - @actions << [:apply_ary_method, :map!, block] - @pending = true - self - end - def reject!(&block) - @actions << [:apply_ary_method, :reject!, block] - @pending = true - self - end - private - def apply_ary_method(meth, block=nil) - @items.send meth, &block - end - def apply_ary_method_1(meth, arg1, block=nil) - @items.send meth, arg1, &block - end - end # class FileList -end # module Rant - -if RUBY_VERSION == "1.8.3" - module FileUtils - METHODS = singleton_methods - %w(private_module_function - commands options have_option? options_of collect_method) - module Verbose - class << self - public(*::FileUtils::METHODS) - end - public(*::FileUtils::METHODS) - end - end -end - -if RUBY_VERSION < "1.8.1" - module FileUtils - undef_method :fu_list - def fu_list(arg) - arg.respond_to?(:to_ary) ? arg.to_ary : [arg] - end - end -end - -module Rant - class RacFileList < FileList - - attr_reader :subdir - attr_reader :basedir - - def initialize(rac, store = []) - super(store) - @rac = rac - @subdir = @rac.current_subdir - @basedir = Dir.pwd - @ignore_hash = nil - @add_ignore_args = [] - update_ignore_rx - end - def dup - c = super - c.instance_variable_set( - :@add_ignore_args, @add_ignore_args.dup) - c - end - def copy - c = super - c.instance_variable_set( - :@add_ignore_args, @add_ignore_args.map { |e| e.dup }) - c - end - alias filelist_ignore ignore - def ignore(*patterns) - @add_ignore_args.concat patterns - self - end - def ignore_rx - update_ignore_rx - @ignore_rx - end - alias filelist_resolve resolve - def resolve - Sys.cd(@basedir) { filelist_resolve } - end - def each_cd(&block) - old_pwd = Dir.pwd - Sys.cd(@basedir) - filelist_resolve if @pending - @items.each(&block) - ensure - Sys.cd(old_pwd) - end - private - def update_ignore_rx - ri = @rac.var[:ignore] - ri = ri ? (ri + @add_ignore_args) : @add_ignore_args - rh = ri.hash - unless rh == @ignore_hash - @ignore_rx = nil - filelist_ignore(*ri) - @ignore_hash = rh - end - end - end # class RacFileList - - class MultiFileList - - attr_reader :cur_list - - def initialize(rac) - @rac = rac - @cur_list = RacFileList.new(@rac) - @lists = [@cur_list] - end - - def each_entry(&block) - @lists.each { |list| - list.each_cd(&block) - } - end - - def add(filelist) - @cur_list = filelist - @lists << filelist - self - end - - def method_missing(sym, *args, &block) - if @cur_list && @cur_list.respond_to?(sym) - if @cur_list.subdir == @rac.current_subdir - @cur_list.send(sym, *args, &block) - else - add(RacFileList.new(@rac)) - @cur_list.send(sym, *args, &block) - end - else - super - end - end - end # class MultiFileList - - class CommandError < StandardError - attr_reader :cmd - attr_reader :status - def initialize(cmd, status=nil, msg=nil) - @msg = msg - @cmd = cmd - @status = status - end - def message - if !@msg && cmd - if status - "Command failed with status #{status.exitstatus}:\n" + - "[#{cmd}]" - else - "Command failed:\n[#{cmd}]" - end - else - @msg - end - end - end - - module Sys - include ::FileUtils::Verbose - - @symlink_supported = true - class << self - attr_accessor :symlink_supported - end - - def fu_output_message(msg) #:nodoc: - end - private :fu_output_message - - def fu_each_src_dest(src, *rest) - src = src.to_ary if src.respond_to? :to_ary - super(src, *rest) - end - private :fu_each_src_dest - - def sh(*cmd_args, &block) - cmd_args.flatten! - cmd = cmd_args.join(" ") - fu_output_message cmd - success = system(*cmd_args) - if block_given? - block[$?] - elsif !success - raise CommandError.new(cmd, $?) - end - end - - def ruby(*args, &block) - if args.empty? - sh(Env::RUBY_EXE, '', &block) - else - sh(args.unshift(Env::RUBY_EXE), &block) - end - end - def cd(dir, &block) - fu_output_message "cd #{dir}" - orig_pwd = Dir.pwd - Dir.chdir dir - if block - begin - block.arity == 0 ? block.call : block.call(Dir.pwd) - ensure - fu_output_message "cd -" - Dir.chdir orig_pwd - end - else - self - end - end - - def safe_ln(src, dest) - dest = dest.to_str - src = src.respond_to?(:to_ary) ? src.to_ary : src.to_str - unless Sys.symlink_supported - cp(src, dest) - else - begin - ln(src, dest) - rescue Exception # SystemCallError # Errno::EOPNOTSUPP - Sys.symlink_supported = false - cp(src, dest) - end - end - end - - def ln_f(src, dest) - ln(src, dest, :force => true) - end - - def split_path(str) - str.split(Env.on_windows? ? ";" : ":") - end - - if Env.on_windows? - def root_dir?(path) - path == "/" || path == "\\" || - path =~ %r{\A[a-zA-Z]+:(\\|/)\Z} - end - def absolute_path?(path) - path =~ %r{\A([a-zA-Z]+:)?(/|\\)} - end - else - def root_dir?(path) - path == "/" - end - def absolute_path?(path) - path =~ %r{\A/} - end - end - - extend self - - if RUBY_VERSION >= "1.8.4" # needed by 1.9.0, too - class << self - public(*::FileUtils::METHODS) - end - public(*::FileUtils::METHODS) - end - - end # module Sys - - class SysObject - include Sys - def initialize(rant) - @rant = rant or - raise ArgumentError, "rant application required" - end - def ignore(*patterns) - @rant.var[:ignore].concat(patterns) - nil - end - def filelist(arg = Rant.__rant_no_value__) - if Rant.__rant_no_value__.equal?(arg) - RacFileList.new(@rant) - elsif arg.respond_to?(:to_rant_filelist) - arg.to_rant_filelist - elsif arg.respond_to?(:to_ary) - RacFileList.new(@rant, arg.to_ary) - else - raise TypeError, - "cannot convert #{arg.class} into Rant::FileList" - end - end - def [](*patterns) - RacFileList.new(@rant).hide_dotfiles.include(*patterns) - end - def glob(*patterns, &block) - fl = RacFileList.new(@rant).hide_dotfiles.include(*patterns) - fl.ignore(".", "..") - if block_given? then yield fl else fl end - end - def glob_all(*patterns, &block) - fl = RacFileList.new(@rant).include(*patterns) - fl.ignore(".", "..") # use case: "*.*" as pattern - if block_given? then yield fl else fl end - end - def expand_path(path) - File.expand_path(@rant.project_to_fs_path(path)) - end - private - def fu_output_message(cmd) - @rant.cmd_msg cmd - end - end - - - class TaskFail < StandardError - def initialize(task, orig, msg) - @task = task - @orig = orig - @msg = msg - end - def exception - self - end - def task - @task - end - def tname - @task ? @task.name : nil - end - def orig - @orig - end - def msg - @msg - end - end - - class Rantfile - attr_reader :tasks, :path - attr_accessor :project_subdir - def initialize(path) - @path = path or raise ArgumentError, "path required" - @tasks = [] - @project_subdir = nil - end - alias to_s path - alias to_str path - end # class Rantfile - - module Node - - INVOKE_OPT = {}.freeze - - T0 = Time.at(0).freeze - - attr_reader :name - attr_reader :rac - attr_accessor :description - attr_accessor :rantfile - attr_accessor :line_number - attr_accessor :project_subdir - - def initialize - @description = nil - @rantfile = nil - @line_number = nil - @run = false - @project_subdir = "" - @success = nil - end - - def reference_name - sd = rac.current_subdir - case sd - when ""; full_name - when project_subdir; name - else "@#{full_name}".sub(/^@#{Regexp.escape sd}\//, '') - end - end - - alias to_s reference_name - alias to_rant_target name - - def full_name - sd = project_subdir - sd.empty? ? name : File.join(sd, name) - end - - def ch - {:file => rantfile.to_str, :ln => line_number} - end - - def goto_task_home - @rac.goto_project_dir project_subdir - end - - def file_target? - false - end - - def done? - @success - end - - def needed? - invoke(:needed? => true) - end - - def run? - @run - end - - def invoke(opt = INVOKE_OPT) - return circular_dep if run? - @run = true - begin - return !done? if opt[:needed?] - self.run if !done? - @success = true - ensure - @run = false - end - end - - def fail msg = nil, orig = nil - raise TaskFail.new(self, orig, msg) - end - - def each_target - end - - def has_actions? - defined? @block and @block - end - - def dry_run - text = "Executing #{name.dump}" - text << " [NOOP]" unless has_actions? - @rac.cmd_msg text - action_descs.each { |ad| - @rac.cmd_print " - " - @rac.cmd_msg ad.sub(/\n$/, '').gsub(/\n/, "\n ") - } - end - - private - def run - goto_task_home - return if @rac.running_task(self) - return unless has_actions? - @receiver.pre_run(self) if defined? @receiver and @receiver - @block.arity == 0 ? @block.call : @block[self] if @block - end - - def action_descs - descs = [] - if defined? @receiver and @receiver - descs.concat(@receiver.pre_action_descs) - end - @block ? descs << action_block_desc : descs - end - - def action_block_desc - @block.inspect =~ /^#$/i - fn, ln = $1, $2 - "Ruby Proc at #{fn.sub(/^#{Regexp.escape @rac.rootdir}\//, '')}:#{ln}" - end - - def circular_dep - rac.warn_msg "Circular dependency on task `#{full_name}'." - false - end - end # module Node - - - def self.init_import_nodes__default(rac, *rest) - rac.node_factory = DefaultNodeFactory.new - end - - class DefaultNodeFactory - def new_task(rac, name, pre, blk) - Task.new(rac, name, pre, &blk) - end - def new_file(rac, name, pre, blk) - FileTask.new(rac, name, pre, &blk) - end - def new_dir(rac, name, pre, blk) - DirTask.new(rac, name, pre, &blk) - end - def new_source(rac, name, pre, blk) - SourceNode.new(rac, name, pre, &blk) - end - def new_custom(rac, name, pre, blk) - UserTask.new(rac, name, pre, &blk) - end - def new_auto_subfile(rac, name, pre, blk) - AutoSubFileTask.new(rac, name, pre, &blk) - end - end - - class Task - include Node - - attr_accessor :receiver - - def initialize(rac, name, prerequisites = [], &block) - super() - @rac = rac or raise ArgumentError, "rac not given" - @name = name or raise ArgumentError, "name not given" - @pre = prerequisites || [] - @pre_resolved = false - @block = block - @run = false - @receiver = nil - end - - def prerequisites - @pre.collect { |pre| pre.to_s } - end - alias deps prerequisites - - def source - @pre.first.to_s - end - - def has_actions? - @block or @receiver && @receiver.has_pre_action? - end - - def <<(pre) - @pre_resolved = false - @pre << pre - end - - def invoked? - !@success.nil? - end - - def fail? - @success == false - end - - def enhance(deps = nil, &blk) - if deps - @pre_resolved = false - @pre.concat deps - end - if @block - if blk - first_block = @block - @block = lambda { |t| - first_block[t] - blk[t] - } - end - else - @block = blk - end - end - - def invoke(opt = INVOKE_OPT) - return circular_dep if @run - @run = true - begin - return if done? - internal_invoke opt - ensure - @run = false - end - end - - def internal_invoke(opt, ud_init = true) - goto_task_home - update = ud_init || opt[:force] - dep = nil - uf = false - each_dep { |dep| - if dep.respond_to? :timestamp - handle_timestamped(dep, opt) && update = true - elsif Node === dep - handle_node(dep, opt) && update = true - else - dep, uf = handle_non_node(dep, opt) - uf && update = true - dep - end - } - if @receiver - goto_task_home - update = true if @receiver.update?(self) - end - return update if opt[:needed?] - run if update - @success = true - update - rescue StandardError => e - @success = false - self.fail(nil, e) - end - private :internal_invoke - - def handle_node(dep, opt) - dep.invoke opt - end - - def handle_timestamped(dep, opt) - dep.invoke opt - end - - def handle_non_node(dep, opt) - @rac.err_msg "Unknown task `#{dep}',", - "referenced in `#{rantfile.path}', line #{@line_number}!" - self.fail - end - - def each_dep - t = nil - if @pre_resolved - return @pre.each { |t| yield(t) } - end - my_full_name = full_name - my_project_subdir = project_subdir - @pre.map! { |t| - if Node === t - if t.full_name == my_full_name - nil - else - yield(t) - t - end - else - t = t.to_s if Symbol === t - if t == my_full_name #TODO - nil - else - selection = @rac.resolve t, - my_project_subdir - if selection.empty? - yield(t) - else - selection.each { |st| yield(st) } - selection - end - end - end - } - if @pre.kind_of? Rant::FileList - @pre.resolve - else - @pre.flatten! - @pre.compact! - end - @pre_resolved = true - end - end # class Task - - class UserTask < Task - - def initialize(*args) - super - @block = nil - @needed = nil - @target_files = nil - yield self if block_given? - end - - def act(&block) - @block = block - end - - def needed(&block) - @needed = block - end - - def file_target? - @target_files and @target_files.include? @name - end - - def each_target(&block) - goto_task_home - @target_files.each(&block) if @target_files - end - - def file_target(*args) - args.flatten! - args << @name if args.empty? - if @target_files - @target_files.concat(args) - else - @target_files = args - end - end - - def invoke(opt = INVOKE_OPT) - return circular_dep if @run - @run = true - begin - return if done? - internal_invoke(opt, ud_init_by_needed) - ensure - @run = false - end - end - - private - def ud_init_by_needed - if @needed - goto_task_home - @needed.arity == 0 ? @needed.call : @needed[self] - end - end - end # class UserTask - - class FileTask < Task - - def initialize(*args) - super - @ts = T0 - end - - def file_target? - true - end - - def invoke(opt = INVOKE_OPT) - return circular_dep if @run - @run = true - begin - return if done? - goto_task_home - if File.exist? @name - @ts = File.mtime @name - internal_invoke opt, false - else - @ts = T0 - internal_invoke opt, true - end - ensure - @run = false - end - end - - def timestamp(opt = INVOKE_OPT) - File.exist?(@name) ? File.mtime(@name) : T0 - end - - def handle_node(dep, opt) - return true if dep.file_target? && dep.invoke(opt) - if File.exist? dep.name - File.mtime(dep.name) > @ts - elsif !dep.file_target? - @rac.err_msg @rac.pos_text(rantfile.path, line_number), - "in prerequisites: no such file: `#{dep.full_name}'" - self.fail - end - end - - def handle_timestamped(dep, opt) - return true if dep.invoke opt - dep.timestamp(opt) > @ts - end - - def handle_non_node(dep, opt) - goto_task_home # !!?? - unless File.exist? dep - @rac.err_msg @rac.pos_text(rantfile.path, line_number), - "in prerequisites: no such file or task: `#{dep}'" - self.fail - end - [dep, File.mtime(dep) > @ts] - end - - def each_target - goto_task_home - yield name - end - end # class FileTask - - module AutoInvokeDirNode - private - def run - goto_task_home - return if @rac.running_task(self) - dir = File.dirname(name) - @rac.build dir unless dir == "." || dir == "/" - return unless @block - @block.arity == 0 ? @block.call : @block[self] - end - end - - class AutoSubFileTask < FileTask - include AutoInvokeDirNode - end - - class DirTask < Task - - def initialize(*args) - super - @ts = T0 - @isdir = nil - end - - def invoke(opt = INVOKE_OPT) - return circular_dep if @run - @run = true - begin - return if done? - goto_task_home - @isdir = test(?d, @name) - if @isdir - @ts = @block ? test(?M, @name) : Time.now - internal_invoke opt, false - else - @ts = T0 - internal_invoke opt, true - end - ensure - @run = false - end - end - - def file_target? - true - end - - def handle_node(dep, opt) - return true if dep.file_target? && dep.invoke(opt) - if File.exist? dep.name - File.mtime(dep.name) > @ts - elsif !dep.file_target? - @rac.err_msg @rac.pos_text(rantfile.path, line_number), - "in prerequisites: no such file: `#{dep.full_name}'" - self.fail - end - end - - def handle_timestamped(dep, opt) - return @block if dep.invoke opt - @block && dep.timestamp(opt) > @ts - end - - def handle_non_node(dep, opt) - goto_task_home - unless File.exist? dep - @rac.err_msg @rac.pos_text(rantfile.path, line_number), - "in prerequisites: no such file or task: `#{dep}'" - self.fail - end - [dep, @block && File.mtime(dep) > @ts] - end - - def run - return if @rac.running_task(self) - @rac.sys.mkdir @name unless @isdir - if @block - @block.arity == 0 ? @block.call : @block[self] - goto_task_home - @rac.sys.touch @name - end - end - - def each_target - goto_task_home - yield name - end - end # class DirTask - - class SourceNode - include Node - def initialize(rac, name, prerequisites = []) - super() - @rac = rac - @name = name or raise ArgumentError, "name not given" - @pre = prerequisites - @run = false - @ts = nil - end - def prerequisites - @pre - end - def timestamp(opt = INVOKE_OPT) - return @ts if @ts - goto_task_home - if File.exist?(@name) - @ts = File.mtime @name - else - rac.abort_at(ch, "SourceNode: no such file -- #@name") - end - sd = project_subdir - @pre.each { |f| - nodes = rac.resolve f, sd - if nodes.empty? - if File.exist? f - mtime = File.mtime f - @ts = mtime if mtime > @ts - else - rac.abort_at(ch, - "SourceNode: no such file -- #{f}") - end - else - nodes.each { |node| - node.invoke(opt) - if node.respond_to? :timestamp - node_ts = node.timestamp(opt) - goto_task_home - @ts = node_ts if node_ts > @ts - else - rac.abort_at(ch, - "SourceNode can't depend on #{node.name}") - end - } - end - } - @ts - end - def invoke(opt = INVOKE_OPT) - false - end - def related_sources - @pre - end - end # class SourceNode - - module Generators - class Task - def self.rant_gen(rac, ch, args, &block) - unless args.size == 1 - rac.abort("Task takes only one argument " + - "which has to be like one given to the " + - "`task' function") - end - rac.prepare_task(args.first, nil, ch) { |name,pre,blk| - rac.node_factory.new_custom(rac, name, pre, block) - } - end - end - class Directory - def self.rant_gen(rac, ch, args, &block) - case args.size - when 1 - name, pre = rac.normalize_task_arg(args.first, ch) - self.task(rac, ch, name, pre, &block) - when 2 - basedir = args.shift - if basedir.respond_to? :to_str - basedir = basedir.to_str - else - rac.abort_at(ch, - "Directory: basedir argument has to be a string.") - end - name, pre = rac.normalize_task_arg(args.first, ch) - self.task(rac, ch, name, pre, basedir, &block) - else - rac.abort_at(ch, "Directory takes one argument, " + - "which should be like one given to the `task' command.") - end - end - - def self.task(rac, ch, name, prerequisites=[], basedir=nil, &block) - dirs = ::Rant::Sys.split_all(name) - if dirs.empty? - rac.abort_at(ch, - "Not a valid directory name: `#{name}'") - end - path = basedir - last_task = nil - task_block = nil - desc_for_last = rac.pop_desc - dirs.each { |dir| - pre = [path] - pre.compact! - if dir.equal?(dirs.last) - rac.cx.desc desc_for_last - - dp = prerequisites.dup - pre.each { |elem| dp << elem } - pre = dp - - task_block = block - end - path = path.nil? ? dir : File.join(path, dir) - last_task = rac.prepare_task({:__caller__ => ch, - path => pre}, task_block) { |name,pre,blk| - rac.node_factory.new_dir(rac, name, pre, blk) - } - } - last_task - end - end # class Directory - class SourceNode - def self.rant_gen(rac, ch, args) - unless args.size == 1 - rac.abort_at(ch, "SourceNode takes one argument.") - end - if block_given? - rac.abort_at(ch, "SourceNode doesn't take a block.") - end - rac.prepare_task(args.first, nil, ch) { |name, pre, blk| - rac.node_factory.new_source(rac, name, pre, blk) - } - end - end - class Rule - def self.rant_gen(rac, ch, args, &block) - unless args.size == 1 - rac.abort_at(ch, "Rule takes only one argument.") - end - rac.abort_at(ch, "Rule: block required.") unless block - arg = args.first - target = nil - src_arg = nil - if Symbol === arg - target = ".#{arg}" - elsif arg.respond_to? :to_str - target = arg.to_str - elsif Regexp === arg - target = arg - elsif Hash === arg && arg.size == 1 - arg.each_pair { |target, src_arg| } - src_arg = src_arg.to_str if src_arg.respond_to? :to_str - target = target.to_str if target.respond_to? :to_str - src_arg = ".#{src_arg}" if Symbol === src_arg - target = ".#{target}" if Symbol === target - else - rac.abort_at(ch, "Rule argument " + - "has to be a hash with one key-value pair.") - end - esc_target = nil - target_rx = case target - when String - esc_target = Regexp.escape(target) - /#{esc_target}$/ - when Regexp - target - else - rac.abort_at(ch, "rule target has " + - "to be a string or regular expression") - end - src_proc = case src_arg - when String, Array - unless String === target - rac.abort(ch, "rule target has to be " + - "a string if source is a string") - end - if src_arg.kind_of? String - lambda { |name| - name.sub(/#{esc_target}$/, src_arg) - } - else - lambda { |name| - src_arg.collect { |s_src| - s_src = ".#{s_src}" if Symbol === s_src - name.sub(/#{esc_target}$/, s_src) - } - } - end - when Proc; src_arg - when nil; lambda { |name| [] } - else - rac.abort_at(ch, "rule source has to be a " + - "String, Array or Proc") - end - rac.resolve_hooks << - (block.arity == 2 ? Hook : FileHook).new( - rac, ch, target_rx, src_proc, block) - nil - end - class Hook - attr_accessor :target_rx - def initialize(rant, ch, target_rx, src_proc, block) - @rant = rant - @ch = ch - @target_rx = target_rx - @src_proc = src_proc - @block = block - end - def call(target, rel_project_dir) - if @target_rx =~ target - have_src = true - src = @src_proc[target] - if src.respond_to? :to_ary - have_src = src.to_ary.all? { |s| - have_src?(rel_project_dir, s) - } - else - have_src = have_src?(rel_project_dir, src) - end - if have_src - create_nodes(rel_project_dir, target, src) - end - end - end - alias [] call - private - def have_src?(rel_project_dir, name) - return true unless - @rant.rec_save_resolve(name, self, rel_project_dir).empty? - test(?e, @rant.abs_path(rel_project_dir, name)) - end - def create_nodes(rel_project_dir, target, deps) - @rant.goto_project_dir rel_project_dir - case nodes = @block[target, deps] - when Array; nodes - when Node; [nodes] - else - @rant.abort_at(@ch, "Block has to " + - "return Node or array of Nodes.") - end - end - end - class FileHook < Hook - private - def have_src?(rel_project_dir, name) - test(?e, @rant.abs_path(rel_project_dir, name)) or - @rant.rec_save_resolve(name, self, rel_project_dir - ).any? { |t| t.file_target? } - end - def create_nodes(rel_project_dir, target, deps) - @rant.goto_project_dir rel_project_dir - t = @rant.file(:__caller__ => @ch, - target => deps, &@block) - [t] - end - end - end # class Rule - class Action - def self.rant_gen(rac, ch, args, &block) - case args.size - when 0 - unless (rac[:tasks] || rac[:stop_after_load]) - yield - end - when 1 - rx = args.first - unless rx.kind_of? Regexp - rac.abort_at(ch, "Action: argument has " + - "to be a regular expression.") - end - rac.resolve_hooks << self.new(rac, block, rx) - nil - else - rac.abort_at(ch, "Action: too many arguments.") - end - end - def initialize(rant, block, rx) - @rant = rant - @subdir = @rant.current_subdir - @block = block - @rx = rx - end - def call(target, rel_project_dir) - if target =~ @rx - @rant.resolve_hooks.delete(self) - @rant.goto_project_dir @subdir - @block.call - @rant.resolve(target, rel_project_dir) - end - end - alias [] call - end - end # module Generators -end # module Rant - -Rant::MAIN_OBJECT = self - -class String - alias sub_ext _rant_sub_ext - def to_rant_target - self - end -end - -module Rant::Lib - def parse_caller_elem(elem) - return { :file => "", :ln => 0 } unless elem - if elem =~ /^(.+):(\d+)(?::|$)/ - { :file => $1, :ln => $2.to_i } - else - $stderr.puts "parse_caller_elem: #{elem.inspect}" - { :file => elem, :ln => 0 } - end - - end - module_function :parse_caller_elem -end # module Lib - -module Rant::Console - RANT_PREFIX = "rant: " - ERROR_PREFIX = "[ERROR] " - WARN_PREFIX = "[WARNING] " - def msg_prefix - if defined? @msg_prefix and @msg_prefix - @msg_prefix - else - RANT_PREFIX - end - end - def msg(*text) - pre = msg_prefix - $stderr.puts "#{pre}#{text.join("\n" + ' ' * pre.length)}" - end - def vmsg(importance, *text) - msg(*text) if verbose >= importance - end - def err_msg(*text) - pre = msg_prefix + ERROR_PREFIX - $stderr.puts "#{pre}#{text.join("\n" + ' ' * pre.length)}" - end - def warn_msg(*text) - pre = msg_prefix + WARN_PREFIX - $stderr.puts "#{pre}#{text.join("\n" + ' ' * pre.length)}" - end - def ask_yes_no text - $stderr.print msg_prefix + text + " [y|n] " - case $stdin.readline - when /y|yes/i; true - when /n|no/i; false - else - $stderr.puts(' ' * msg_prefix.length + - "Please answer with `yes' or `no'") - ask_yes_no text - end - end - def prompt text - $stderr.print msg_prefix + text - input = $stdin.readline - input ? input.chomp : input - end - def option_listing opts - rs = "" - opts.each { |lopt, *opt_a| - if opt_a.size == 2 - mode, desc = opt_a - else - sopt, mode, desc = opt_a - end - next unless desc # "private" option - optstr = "" - arg = nil - if mode != GetoptLong::NO_ARGUMENT - if desc =~ /(\b[A-Z_]{2,}\b)/ - arg = $1 - end - end - if lopt - optstr << lopt - if arg - optstr << " " << arg - end - optstr = optstr.ljust(30) - end - if sopt - optstr << " " unless optstr.empty? - optstr << sopt - if arg - optstr << " " << arg - end - end - rs << " #{optstr}\n" - rs << " #{desc.split("\n").join("\n ")}\n" - } - rs - end - extend self -end # module Rant::Console - -module RantContext - include Rant::Generators - - Env = Rant::Env - FileList = Rant::FileList - - def task(targ, &block) - rant.task(targ, &block) - end - - def file(targ, &block) - rant.file(targ, &block) - end - - def enhance(targ, &block) - rant.enhance(targ, &block) - end - - def desc(*args) - rant.desc(*args) - end - - def gen(*args, &block) - rant.gen(*args, &block) - end - - def import(*args, &block) - rant.import(*args, &block) - end - - def plugin(*args, &block) - rant.plugin(*args, &block) - end - - def subdirs(*args) - rant.subdirs(*args) - end - - def source(opt, rantfile = nil) - rant.source(opt, rantfile) - end - - def sys(*args, &block) - rant.sys(*args, &block) - end - - def var(*args, &block) - rant.var(*args, &block) - end - - def make(*args, &block) - rant.make(*args, &block) - end - -end # module RantContext - -class RantAppContext - include RantContext - - def initialize(app) - @__rant__ = app - end - - def rant - @__rant__ - end - - def method_missing(sym, *args) - Rant::MAIN_OBJECT.send(sym, *args) - rescue NoMethodError - raise NameError, "NameError: undefined local " + - "variable or method `#{sym}' for main:Object", caller - end -end - -module Rant - - @__rant__ = nil - class << self - - def run(first_arg=nil, *other_args) - other_args = other_args.flatten - args = first_arg.nil? ? ARGV.dup : ([first_arg] + other_args) - if rant && !rant.run? - rant.run(args.flatten) - else - @__rant__ = Rant::RantApp.new - rant.run(args) - end - end - - def rant - @__rant__ - end - end - -end # module Rant - -class Rant::RantApp - include Rant::Console - - class AutoLoadNodeFactory - def initialize(rant) - @rant = rant - end - def method_missing(sym, *args, &block) - @rant.import "nodes/default" - @rant.node_factory.send(sym, *args, &block) - end - end - - - - OPTIONS = [ - [ "--help", "-h", GetoptLong::NO_ARGUMENT, - "Print this help and exit." ], - [ "--version", "-V", GetoptLong::NO_ARGUMENT, - "Print version of Rant and exit." ], - [ "--verbose", "-v", GetoptLong::NO_ARGUMENT, - "Print more messages to stderr." ], - [ "--quiet", "-q", GetoptLong::NO_ARGUMENT, - "Don't print commands." ], - [ "--err-commands", GetoptLong::NO_ARGUMENT, - "Print failed commands and their exit status." ], - [ "--directory","-C", GetoptLong::REQUIRED_ARGUMENT, - "Run rant in DIRECTORY." ], - [ "--cd-parent","-c", GetoptLong::NO_ARGUMENT, - "Run rant in parent directory with Rantfile." ], - [ "--look-up", "-u", GetoptLong::NO_ARGUMENT, - "Look in parent directories for root Rantfile." ], - [ "--rantfile", "-f", GetoptLong::REQUIRED_ARGUMENT, - "Process RANTFILE instead of standard rantfiles.\n" + - "Multiple files may be specified with this option." ], - [ "--force-run","-a", GetoptLong::REQUIRED_ARGUMENT, - "Force rebuild of TARGET and all dependencies." ], - [ "--dry-run", "-n", GetoptLong::NO_ARGUMENT, - "Print info instead of actually executing actions." ], - [ "--tasks", "-T", GetoptLong::NO_ARGUMENT, - "Show a list of all described tasks and exit." ], - - - [ "--import", "-i", GetoptLong::REQUIRED_ARGUMENT, nil ], - [ "--stop-after-load", GetoptLong::NO_ARGUMENT, nil ], - [ "--trace-abort", GetoptLong::NO_ARGUMENT, nil ], - ] - - ROOT_DIR_ID = "@" - ESCAPE_ID = "\\" - - attr_reader :args - attr_reader :rantfiles - attr_reader :force_targets - attr_reader :plugins - attr_reader :context - alias cx context - attr_reader :tasks - attr_reader :imports - attr_reader :current_subdir - attr_reader :resolve_hooks - attr_reader :rootdir - - attr_accessor :node_factory - - def initialize - @args = [] - @context = RantAppContext.new(self) - @sys = ::Rant::SysObject.new(self) - @rantfiles = [] - @tasks = {} - @opts = { - :verbose => 0, - :quiet => false, - } - @rootdir = Dir.pwd # root directory of project - @arg_rantfiles = [] # rantfiles given in args - @arg_targets = [] # targets given in args - @force_targets = [] # targets given with -a option - @run = false # run method was called at least once - @done = false # run method was successful - @plugins = [] - @var = Rant::RantVar::Space.new - @var.query :ignore, :AutoList, [] - @imports = [] - - @task_desc = nil - @last_build_subdir = "" - - @current_subdir = "" - @resolve_hooks = [] - - @node_factory = AutoLoadNodeFactory.new(self) - end - - def [](opt) - @opts[opt] - end - - def []=(opt, val) - @opts[opt] = val - end - - def expand_path(subdir, path) - case path - when nil; subdir.dup - when ""; subdir.dup - when /^@/; path.sub(/^@/, '') - else - path = path.sub(/^\\(?=@)/, '') - if subdir.empty? - path - else - File.join(subdir, path) - end - end - end - def resolve_root_ref(path) - return File.join(@rootdir, path[1..-1]) if path =~ /^@/ - path.sub(/^\\(?=@)/, '') - end - def project_to_fs_path(path) - sub = expand_path(@current_subdir, path) - sub.empty? ? @rootdir : File.join(@rootdir, sub) - end - def abs_path(subdir, fn) - return fn if Rant::Sys.absolute_path?(fn) - path = File.join(@rootdir, subdir, fn) - path.gsub!(%r{/+}, "/") - path.sub!(%r{/$}, "") if path.length > 1 - path - end - def goto(dir) - goto_project_dir(expand_path(@current_subdir, dir)) - end - def goto_project_dir(dir='') - @current_subdir = dir - abs_path = @current_subdir.empty? ? - @rootdir : File.join(@rootdir, @current_subdir) - unless Dir.pwd == abs_path - Dir.chdir abs_path - vmsg 1, "in #{abs_path}" - end - end - - def run? - @run - end - - def done? - @done - end - - def run(*args) - @run = true - @args.concat(args.flatten) - orig_pwd = @rootdir = Dir.pwd - process_args - Dir.chdir(@rootdir) rescue abort $!.message - load_rantfiles - - raise Rant::RantDoneException if @opts[:stop_after_load] - - @plugins.each { |plugin| plugin.rant_start } - if @opts[:tasks] - show_descriptions - raise Rant::RantDoneException - end - run_tasks - raise Rant::RantDoneException - rescue Rant::RantDoneException - @done = true - @plugins.each { |plugin| plugin.rant_done } - return 0 - rescue Rant::RantAbortException - $stderr.puts "rant aborted!" - return 1 - rescue Exception => e - ch = get_ch_from_backtrace(e.backtrace) - if ch && !@opts[:trace_abort] - err_msg(pos_text(ch[:file], ch[:ln]), e.message) - else - err_msg e.message, e.backtrace[0..4] - end - $stderr.puts "rant aborted!" - return 1 - ensure - Dir.chdir @rootdir if test ?d, @rootdir - hooks = var._get("__at_return__") - hooks.each { |hook| hook.call } if hooks - @plugins.each { |plugin| plugin.rant_plugin_stop } - @plugins.each { |plugin| plugin.rant_quit } - Dir.chdir orig_pwd - end - - - def desc(*args) - if args.empty? || (args.size == 1 && args.first.nil?) - @task_desc = nil - else - @task_desc = args.join("\n") - end - end - - def task(targ, &block) - prepare_task(targ, block) { |name,pre,blk| - @node_factory.new_task(self, name, pre, blk) - } - end - - def file(targ, &block) - prepare_task(targ, block) { |name,pre,blk| - @node_factory.new_file(self, name, pre, blk) - } - end - - def gen(*args, &block) - ch = Rant::Lib::parse_caller_elem(caller[1]) - generator = args.shift - unless generator.respond_to? :rant_gen - abort_at(ch, - "gen: First argument has to be a task-generator.") - end - generator.rant_gen(self, ch, args, &block) - end - - def import(*args, &block) - ch = Rant::Lib::parse_caller_elem(caller[1]) - if block - warn_msg pos_text(ch[:file], ch[:ln]), - "import: ignoring block" - end - args.flatten.each { |arg| - unless String === arg - abort_at(ch, "import: only strings allowed as arguments") - end - unless @imports.include? arg - unless Rant::CODE_IMPORTS.include? arg - begin - vmsg 2, "import #{arg}" - require "rant/import/#{arg}" - rescue LoadError => e - abort_at(ch, "No such import - #{arg}") - end - Rant::CODE_IMPORTS << arg.dup - end - init_msg = "init_import_#{arg.gsub(/[^\w]/, '__')}" - Rant.send init_msg, self if Rant.respond_to? init_msg - @imports << arg.dup - end - } - end - - def plugin(*args, &block) - clr = caller[1] - ch = Rant::Lib::parse_caller_elem(clr) - name = nil - pre = [] - ln = ch[:ln] || 0 - file = ch[:file] - - pl_name = args.shift - pl_name = pl_name.to_str if pl_name.respond_to? :to_str - pl_name = pl_name.to_s if pl_name.is_a? Symbol - unless pl_name.is_a? String - abort(pos_text(file, ln), - "Plugin name has to be a string or symbol.") - end - lc_pl_name = pl_name.downcase - import_name = "plugin/#{lc_pl_name}" - unless Rant::CODE_IMPORTS.include? import_name - begin - require "rant/plugin/#{lc_pl_name}" - Rant::CODE_IMPORTS << import_name - rescue LoadError - abort(pos_text(file, ln), - "no such plugin library -- #{lc_pl_name}") - end - end - pl_class = nil - begin - pl_class = ::Rant::Plugin.const_get(pl_name) - rescue NameError, ArgumentError - abort(pos_text(file, ln), - "no such plugin -- #{pl_name}") - end - - plugin = pl_class.rant_plugin_new(self, ch, *args, &block) - @plugins << plugin - vmsg 2, "Plugin `#{plugin.rant_plugin_name}' registered." - plugin.rant_plugin_init - plugin - end - - def enhance(targ, &block) - prepare_task(targ, block) { |name,pre,blk| - t = resolve(name).last - if t - unless t.respond_to? :enhance - abort("Can't enhance task `#{name}'") - end - t.enhance(pre, &blk) - return t - end - warn_msg "enhance \"#{name}\": no such task", - "Generating a new file task with the given name." - @node_factory.new_file(self, name, pre, blk) - } - end - - def source(opt, rantfile = nil) - unless rantfile - rantfile = opt - opt = nil - end - make_rf = opt != :n && opt != :now - rf, is_new = rantfile_for_path(rantfile) - return false unless is_new - make rantfile if make_rf - unless File.exist? rf.path - abort("source: No such file -- #{rantfile}") - end - - load_file rf - end - - def subdirs(*args) - args.flatten! - ch = Rant::Lib::parse_caller_elem(caller[1]) - args.each { |arg| - if arg.respond_to? :to_str - arg = arg.to_str - else - abort_at(ch, "subdirs: arguments must be strings") - end - loaded = false - prev_subdir = @current_subdir - begin - goto arg - if test(?f, Rant::SUB_RANTFILE) - path = Rant::SUB_RANTFILE - else - path = rantfile_in_dir - end - if path - if defined? @initial_subdir and - @initial_subdir == @current_subdir - rf, is_new = rantfile_for_path(path, false) - @rantfiles.unshift rf if is_new - else - rf, is_new = rantfile_for_path(path) - end - load_file rf if is_new - elsif !@opts[:no_warn_subdir] - warn_msg(pos_text(ch[:file], ch[:ln]), - "subdirs: No Rantfile in subdir `#{arg}'.") - end - ensure - goto_project_dir prev_subdir - end - } - rescue SystemCallError => e - abort_at(ch, "subdirs: " + e.message) - end - - def sys(*args, &block) - args.empty? ? @sys : @sys.sh(*args, &block) - end - - def var(*args, &block) - args.empty? ? @var : @var.query(*args, &block) - end - - def pop_desc - td = @task_desc - @task_desc = nil - td - end - - def abort(*msg) - err_msg(msg) unless msg.empty? - $stderr.puts caller if @opts[:trace_abort] - raise Rant::RantAbortException - end - - def abort_at(ch, *msg) - err_msg(pos_text(ch[:file], ch[:ln]), msg) - $stderr.puts caller if @opts[:trace_abort] - raise Rant::RantAbortException - end - - def show_help - puts "rant [-f Rantfile] [Options] [targets]" - puts - puts "Options are:" - print option_listing(OPTIONS) - end - - def show_descriptions - tlist = select_tasks { |t| t.description } - def_target = target_list.first - if tlist.empty? - puts "rant # => " + list_task_names( - resolve(def_target)).join(', ') - msg "No described tasks." - return - end - prefix = "rant " - infix = " # " - name_length = (tlist.map{ |t| t.to_s.length } << 7).max - cmd_length = prefix.length + name_length - unless tlist.first.to_s == def_target - defaults = list_task_names( - resolve(def_target)).join(', ') - puts "#{prefix}#{' ' * name_length}#{infix}=> #{defaults}" - end - tlist.each { |t| - print(prefix + t.to_s.ljust(name_length) + infix) - dt = t.description.sub(/\s+$/, "") - puts dt.gsub(/\n/, "\n" + ' ' * cmd_length + infix + " ") - } - true - end - - def list_task_names(*tasks) - rsl = [] - tasks.flatten.each { |t| - if t.respond_to?(:has_actions?) && t.has_actions? - rsl << t - elsif t.respond_to? :prerequisites - if t.prerequisites.empty? - rsl << t - else - t.prerequisites.each { |pre| - rsl.concat(list_task_names( - resolve(pre, t.project_subdir))) - } - end - else - rsl << t - end - } - rsl - end - private :list_task_names - - def verbose - @opts[:verbose] - end - - def quiet? - @opts[:quiet] - end - - def pos_text(file, ln) - t = "in file `#{file}'" - t << ", line #{ln}" if ln && ln > 0 - t << ": " - end - - def cmd_msg(cmd) - puts cmd unless quiet? - end - - def cmd_print(text) - print text unless quiet? - $stdout.flush - end - - def cmd_targets - @force_targets + @arg_targets - end - - def running_task(task) - if @current_subdir != @last_build_subdir - cmd_msg "(in #{@current_subdir.empty? ? - @rootdir : @current_subdir})" - @last_build_subdir = @current_subdir - end - if @opts[:dry_run] - task.dry_run - true - end - end - - private - def have_any_task? - !@tasks.empty? - end - - def target_list - if !have_any_task? && @resolve_hooks.empty? - abort("No tasks defined for this rant application!") - end - - target_list = @force_targets + @arg_targets - if target_list.empty? - def_tasks = resolve "default" - unless def_tasks.empty? - target_list << "default" - else - @rantfiles.each { |f| - first = f.tasks.first - if first - target_list << first.reference_name - break - end - } - end - end - target_list - end - - def run_tasks - target_list.each { |target| - if build(target) == 0 - abort("Don't know how to make `#{target}'.") - end - } - end - - def make(target, *args, &block) - ch = nil - if target.respond_to? :to_hash - targ = target.to_hash - ch = Rant::Lib.parse_caller_elem(caller[1]) - abort_at(ch, "make: too many arguments") unless args.empty? - tn = nil - prepare_task(targ, block, ch) { |name,pre,blk| - tn = name - @node_factory.new_file(self, name, pre, blk) - } - build(tn) - elsif target.respond_to? :to_rant_target - rt = target.to_rant_target - opt = args.shift - unless args.empty? - ch ||= Rant::Lib.parse_caller_elem(caller[1]) - abort_at(ch, "make: too many arguments") - end - if block - ch ||= Rant::Lib.parse_caller_elem(caller[1]) - prepare_task(rt, block, ch) { |name,pre,blk| - @node_factory.new_file(self, name, pre, blk) - } - build(rt) - else - build(rt, opt||{}) - end - elsif target.respond_to? :rant_gen - ch = Rant::Lib.parse_caller_elem(caller[1]) - rv = target.rant_gen(self, ch, args, &block) - unless rv.respond_to? :to_rant_target - abort_at(ch, "make: invalid generator return value") - end - build(rv.to_rant_target) - rv - else - ch = Rant::Lib.parse_caller_elem(caller[1]) - abort_at(ch, - "make: generator or target as first argument required.") - end - end - public :make - - def build(target, opt = {}) - opt[:force] = true if @force_targets.delete(target) - opt[:dry_run] = @opts[:dry_run] - matching_tasks = 0 - old_subdir = @current_subdir - old_pwd = Dir.pwd - resolve(target).each { |t| - unless opt[:type] == :file && !t.file_target? - matching_tasks += 1 - begin - t.invoke(opt) - rescue Rant::TaskFail => e - err_task_fail(e) - abort - end - end - } - @current_subdir = old_subdir - Dir.chdir old_pwd - matching_tasks - end - public :build - - def resolve(task_name, rel_project_dir = @current_subdir) - s = @tasks[expand_path(rel_project_dir, task_name)] - case s - when nil - @resolve_hooks.each { |s| - s = s[task_name, rel_project_dir] - return s if s - } - [] - when Rant::Node; [s] - else # assuming list of tasks - s - end - end - public :resolve - - def rec_save_resolve(task_name, excl_hook, rel_project_dir = @current_subdir) - s = @tasks[expand_path(rel_project_dir, task_name)] - case s - when nil - @resolve_hooks.each { |s| - next if s == excl_hook - s = s[task_name, rel_project_dir] - return s if s - } - [] - when Rant::Node; [s] - else - s - end - end - public :rec_save_resolve - - def at_resolve(&block) - @resolve_hooks << block if block - end - public :at_resolve - - def at_return(&block) - hooks = var._get("__at_return__") - if hooks - hooks << block - else - var._set("__at_return__", [block]) - end - end - public :at_return - - def select_tasks - selection = [] - @rantfiles.each { |rf| - rf.tasks.each { |t| - selection << t if yield t - } - } - selection - end - public :select_tasks - - def load_rantfiles - unless @arg_rantfiles.empty? - @arg_rantfiles.each { |fn| - if test(?f, fn) - rf, is_new = rantfile_for_path(fn) - load_file rf if is_new - else - abort "No such file -- #{fn}" - end - } - return - end - return if have_any_task? - fn = rantfile_in_dir - if @opts[:cd_parent] - old_root = @rootdir - until fn or @rootdir == "/" - @rootdir = File.dirname(@rootdir) - fn = rantfile_in_dir(@rootdir) - end - if @rootdir != old_root and fn - Dir.chdir @rootdir - cmd_msg "(in #@rootdir)" - end - end - if fn - rf, is_new = rantfile_for_path(fn) - load_file rf if is_new - return - end - have_sub_rantfile = test(?f, Rant::SUB_RANTFILE) - if have_sub_rantfile || @opts[:look_up] - cur_dir = Dir.pwd - until cur_dir == "/" - cur_dir = File.dirname(cur_dir) - Dir.chdir cur_dir - fn = rantfile_in_dir - if fn - @initial_subdir = @rootdir.sub( - /^#{Regexp.escape cur_dir}\//, '') - @rootdir = cur_dir - cmd_msg "(root is #@rootdir, in #@initial_subdir)" - @last_build_subdir = @initial_subdir - rf, is_new = rantfile_for_path(fn) - load_file rf if is_new - goto_project_dir @initial_subdir - if have_sub_rantfile - rf, is_new = rantfile_for_path( - Rant::SUB_RANTFILE, false) - if is_new - @rantfiles.unshift rf - load_file rf - end - end - break - end - end - end - if @rantfiles.empty? - abort("No Rantfile found, looking for:", - Rant::RANTFILES.join(", ")) - end - end - - def load_file(rantfile) - vmsg 1, "source #{rantfile}" - @context.instance_eval(File.read(rantfile), rantfile) - end - private :load_file - - def rantfile_in_dir(dir=nil) - ::Rant::RANTFILES.each { |rfn| - path = dir ? File.join(dir, rfn) : rfn - return path if test ?f, path - } - nil - end - - def process_args - old_argv = ARGV.dup - ARGV.replace(@args.dup) - cmd_opts = GetoptLong.new(*OPTIONS.collect { |lst| lst[0..-2] }) - cmd_opts.quiet = true - cmd_opts.each { |opt, value| - case opt - when "--verbose"; @opts[:verbose] += 1 - when "--version" - puts "rant #{Rant::VERSION}" - raise Rant::RantDoneException - when "--help" - show_help - raise Rant::RantDoneException - when "--directory" - @rootdir = File.expand_path(value) - when "--rantfile" - @arg_rantfiles << value - when "--force-run" - @force_targets << value - when "--import" - import value - else - @opts[opt.sub(/^--/, '').tr('-', "_").to_sym] = true - end - } - rescue GetoptLong::Error => e - abort(e.message) - ensure - rem_args = ARGV.dup - ARGV.replace(old_argv) - rem_args.each { |ra| - if ra =~ /(^[^=]+)=([^=]+)$/ - vmsg 2, "var: #$1=#$2" - @var[$1] = $2 - else - @arg_targets << ra - end - } - end - - def prepare_task(targ, block, clr = caller[2]) - - if targ.is_a? Hash - targ.reject! { |k, v| clr = v if k == :__caller__ } - end - ch = Hash === clr ? clr : Rant::Lib::parse_caller_elem(clr) - - name, pre = normalize_task_arg(targ, ch) - - file, is_new = rantfile_for_path(ch[:file]) - nt = yield(name, pre, block) - nt.rantfile = file - nt.project_subdir = @current_subdir - nt.line_number = ch[:ln] - nt.description = @task_desc - @task_desc = nil - file.tasks << nt - hash_task nt - nt - end - public :prepare_task - - def hash_task(task) - n = task.full_name - et = @tasks[n] - case et - when nil - @tasks[n] = task - when Rant::Node - mt = [et, task] - @tasks[n] = mt - else # assuming list of tasks - et << task - end - end - - def normalize_task_arg(targ, ch) - name = nil - pre = [] - - if targ.is_a? Hash - if targ.empty? - abort_at(ch, "Empty hash as task argument, " + - "task name required.") - end - if targ.size > 1 - abort_at(ch, "Too many hash elements, " + - "should only be one.") - end - targ.each_pair { |k,v| - name = normalize_task_name(k, ch) - pre = v - } - unless ::Rant::FileList === pre - if pre.respond_to? :to_ary - pre = pre.to_ary.dup - pre.map! { |elem| - normalize_task_name(elem, ch) - } - else - pre = [normalize_task_name(pre, ch)] - end - end - else - name = normalize_task_name(targ, ch) - end - - [name, pre] - end - public :normalize_task_arg - - def normalize_task_name(arg, ch) - return arg if arg.is_a? String - if Symbol === arg - arg.to_s - elsif arg.respond_to? :to_str - arg.to_str - else - abort_at(ch, "Task name has to be a string or symbol.") - end - end - - def rantfile_for_path(path, register=true) - abs_path = File.expand_path(path) - file = @rantfiles.find { |rf| rf.path == abs_path } - if file - [file, false] - else - file = Rant::Rantfile.new abs_path - file.project_subdir = @current_subdir - @rantfiles << file if register - [file, true] - end - end - - def get_ch_from_backtrace(backtrace) - backtrace.each { |clr| - ch = ::Rant::Lib.parse_caller_elem(clr) - if ::Rant::Env.on_windows? - return ch if @rantfiles.any? { |rf| - rf.path.tr("\\", "/").sub(/^\w\:/, '') == - ch[:file].tr("\\", "/").sub(/^\w\:/, '') - } - else - return ch if @rantfiles.any? { |rf| - rf.path == ch[:file] - } - end - } - nil - end - - def err_task_fail(e) - msg = [] - t_msg = ["Task `#{e.tname}' fail."] - orig = e - loop { orig = orig.orig; break unless Rant::TaskFail === orig } - if orig && orig != e && !(Rant::RantAbortException === orig) - ch = get_ch_from_backtrace(orig.backtrace) - msg << pos_text(ch[:file], ch[:ln]) if ch - unless Rant::CommandError === orig && !@opts[:err_commands] - msg << orig.message - msg << orig.backtrace[0..4] unless ch - end - end - if e.msg && !e.msg.empty? - ch = get_ch_from_backtrace(e.backtrace) - t_msg.unshift(e.msg) - t_msg.unshift(pos_text(ch[:file], ch[:ln])) if ch - end - err_msg msg unless msg.empty? - err_msg t_msg - end -end # class Rant::RantApp - -$".concat(['rant/rantlib.rb', 'rant/init.rb', 'rant/rantvar.rb', 'rant/rantsys.rb', 'rant/import/filelist/core.rb', 'rant/node.rb', 'rant/import/nodes/default.rb', 'rant/coregen.rb']) -Rant::CODE_IMPORTS.concat %w(nodes/default - ) - -# Catch a `require "rant"', sad... -alias require_backup_by_rant require -def require libf - if libf == "rant" - # TODO: needs rework! look at lib/rant.rb - self.class.instance_eval { include Rant } - else - begin - require_backup_by_rant libf - rescue - raise $!, caller - end - end -end - -exit Rant.run -- cgit v1.2.3 From 0a92145c2ef24e9c20bbbabcdf3c9c17f567d676 Mon Sep 17 00:00:00 2001 From: Ralph Amissah Date: Fri, 8 Nov 2013 20:54:52 -0500 Subject: v4 v5: vim, ftplugin sisu.vim, fix missing --- data/doc/sisu/CHANGELOG_v4 | 2 ++ data/doc/sisu/CHANGELOG_v5 | 2 ++ data/sisu/conf/editor-syntax-etc/vim/ftplugin/sisu.vim | 5 +---- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/data/doc/sisu/CHANGELOG_v4 b/data/doc/sisu/CHANGELOG_v4 index e1ca2f64..bd09381e 100644 --- a/data/doc/sisu/CHANGELOG_v4 +++ b/data/doc/sisu/CHANGELOG_v4 @@ -34,6 +34,8 @@ http://www.jus.uio.no/sisu/pkg/src/sisu_4.2.12.orig.tar.xz * do less by default * removed rant generated sisu-install +* vim, ftplugin sisu.vim, fix missing + * sisu_manual, minor info addition %% 4.2.11.orig.tar.xz (2013-11-05:44/2) diff --git a/data/doc/sisu/CHANGELOG_v5 b/data/doc/sisu/CHANGELOG_v5 index 35f82417..20bb5e81 100644 --- a/data/doc/sisu/CHANGELOG_v5 +++ b/data/doc/sisu/CHANGELOG_v5 @@ -34,6 +34,8 @@ http://www.jus.uio.no/sisu/pkg/src/sisu_5.0.25.orig.tar.xz * do less by default * removed rant generated sisu-install +* vim, ftplugin sisu.vim, fix missing + * sisu_manual, minor info addition %% 5.0.24.orig.tar.xz (2013-11-05:44/2) diff --git a/data/sisu/conf/editor-syntax-etc/vim/ftplugin/sisu.vim b/data/sisu/conf/editor-syntax-etc/vim/ftplugin/sisu.vim index 9cb8952a..43c7e531 100644 --- a/data/sisu/conf/editor-syntax-etc/vim/ftplugin/sisu.vim +++ b/data/sisu/conf/editor-syntax-etc/vim/ftplugin/sisu.vim @@ -95,9 +95,6 @@ "% directory files, placed in vertical split window :map ls :vs :Explore :map dir :vs :Explore -:if &diff -: cmap q qa -:endif "% remapping lines make cursor jump a line at a time within wrapped text :nnoremap j gj :nnoremap k gk @@ -140,7 +137,7 @@ :nmap :silent call ToggleHLSearched() "%% SiSU vim folds "% foldsearchx FoldSearch (opens result of search all else closed) t77 -:map fs :set foldmethod=expr foldcolumn=2 foldlevel=0 +:map fs :set foldmethod=expr foldcolumn=2 foldlevel=0 :map ff :F :map fe :F zE "% foldtoggle Fold Toggle mapped to -- cgit v1.2.3 From 897a46efc904b63e30ba10c49eb0386642cc608f Mon Sep 17 00:00:00 2001 From: Ralph Amissah Date: Fri, 8 Nov 2013 21:00:51 -0500 Subject: v4 v5: bin/sisu-* * use option flag full names * add sisu-html-scroll, sisu-html-seg, sisu-pdf-portrait, sisu-pdf-landscape --- bin/sisu-concordance | 2 +- bin/sisu-epub | 2 +- bin/sisu-html | 2 +- bin/sisu-html-scroll | 2 ++ bin/sisu-html-seg | 2 ++ bin/sisu-odf | 2 +- bin/sisu-pdf | 2 +- bin/sisu-pdf-landscape | 2 ++ bin/sisu-pdf-portrait | 2 ++ bin/sisu-pg | 2 +- bin/sisu-sqlite | 2 +- bin/sisu-txt | 2 +- data/doc/sisu/CHANGELOG_v4 | 4 ++++ data/doc/sisu/CHANGELOG_v5 | 4 ++++ man/man1/sisu-html-scroll.1 | 39 +++++++++++++++++++++++++++++++++++++++ man/man1/sisu-html-seg.1 | 39 +++++++++++++++++++++++++++++++++++++++ man/man1/sisu-pdf-landscape.1 | 39 +++++++++++++++++++++++++++++++++++++++ man/man1/sisu-pdf-portrait.1 | 39 +++++++++++++++++++++++++++++++++++++++ 18 files changed, 180 insertions(+), 8 deletions(-) create mode 100644 bin/sisu-html-scroll create mode 100644 bin/sisu-html-seg create mode 100644 bin/sisu-pdf-landscape create mode 100644 bin/sisu-pdf-portrait create mode 100644 man/man1/sisu-html-scroll.1 create mode 100644 man/man1/sisu-html-seg.1 create mode 100644 man/man1/sisu-pdf-landscape.1 create mode 100644 man/man1/sisu-pdf-portrait.1 diff --git a/bin/sisu-concordance b/bin/sisu-concordance index 6851494f..0eabb80c 100644 --- a/bin/sisu-concordance +++ b/bin/sisu-concordance @@ -1,2 +1,2 @@ #!/bin/sh -sisu -w ${@} +sisu --concordance ${@} diff --git a/bin/sisu-epub b/bin/sisu-epub index 9c57f955..2c7efc38 100644 --- a/bin/sisu-epub +++ b/bin/sisu-epub @@ -1,2 +1,2 @@ #!/bin/sh -sisu -e ${@} +sisu --epub ${@} diff --git a/bin/sisu-html b/bin/sisu-html index 537169ad..8f1e4dbc 100644 --- a/bin/sisu-html +++ b/bin/sisu-html @@ -1,2 +1,2 @@ #!/bin/sh -sisu -h ${@} +sisu --html ${@} diff --git a/bin/sisu-html-scroll b/bin/sisu-html-scroll new file mode 100644 index 00000000..f5098f32 --- /dev/null +++ b/bin/sisu-html-scroll @@ -0,0 +1,2 @@ +#!/bin/sh +sisu --html-scroll ${@} diff --git a/bin/sisu-html-seg b/bin/sisu-html-seg new file mode 100644 index 00000000..c5851331 --- /dev/null +++ b/bin/sisu-html-seg @@ -0,0 +1,2 @@ +#!/bin/sh +sisu --html-seg ${@} diff --git a/bin/sisu-odf b/bin/sisu-odf index 7caceec4..c6eee725 100644 --- a/bin/sisu-odf +++ b/bin/sisu-odf @@ -1,2 +1,2 @@ #!/bin/sh -sisu -o ${@} +sisu --odt ${@} diff --git a/bin/sisu-pdf b/bin/sisu-pdf index 2b0a2973..45a6ba7b 100644 --- a/bin/sisu-pdf +++ b/bin/sisu-pdf @@ -1,2 +1,2 @@ #!/bin/sh -sisu -p ${@} +sisu --pdf ${@} diff --git a/bin/sisu-pdf-landscape b/bin/sisu-pdf-landscape new file mode 100644 index 00000000..1fe79491 --- /dev/null +++ b/bin/sisu-pdf-landscape @@ -0,0 +1,2 @@ +#!/bin/sh +sisu --pdf-landscape ${@} diff --git a/bin/sisu-pdf-portrait b/bin/sisu-pdf-portrait new file mode 100644 index 00000000..4f40aa03 --- /dev/null +++ b/bin/sisu-pdf-portrait @@ -0,0 +1,2 @@ +#!/bin/sh +sisu --pdf-portrait ${@} diff --git a/bin/sisu-pg b/bin/sisu-pg index e2c31233..83585b75 100644 --- a/bin/sisu-pg +++ b/bin/sisu-pg @@ -1,2 +1,2 @@ #!/bin/sh -sisu -D ${@} +sisu --pg ${@} diff --git a/bin/sisu-sqlite b/bin/sisu-sqlite index 3cb11629..9863e983 100644 --- a/bin/sisu-sqlite +++ b/bin/sisu-sqlite @@ -1,2 +1,2 @@ #!/bin/sh -sisu -d ${@} +sisu --sqlite ${@} diff --git a/bin/sisu-txt b/bin/sisu-txt index 8d177b60..14dcb085 100644 --- a/bin/sisu-txt +++ b/bin/sisu-txt @@ -1,2 +1,2 @@ #!/bin/sh -sisu -t ${@} +sisu --txt ${@} diff --git a/data/doc/sisu/CHANGELOG_v4 b/data/doc/sisu/CHANGELOG_v4 index bd09381e..f540f185 100644 --- a/data/doc/sisu/CHANGELOG_v4 +++ b/data/doc/sisu/CHANGELOG_v4 @@ -38,6 +38,10 @@ http://www.jus.uio.no/sisu/pkg/src/sisu_4.2.12.orig.tar.xz * sisu_manual, minor info addition +* bin/sisu-* + * use option flag full names + * add sisu-html-scroll, sisu-html-seg, sisu-pdf-portrait, sisu-pdf-landscape + %% 4.2.11.orig.tar.xz (2013-11-05:44/2) http://sources.sisudoc.org/gitweb/?p=code/sisu.git;a=shortlog;h=refs/tags/sisu_4.2.11 http://sources.sisudoc.org/gitweb/?p=code/sisu.git;a=shortlog;h=refs/tags/debian/sisu_4.2.11-1 diff --git a/data/doc/sisu/CHANGELOG_v5 b/data/doc/sisu/CHANGELOG_v5 index 20bb5e81..398257ae 100644 --- a/data/doc/sisu/CHANGELOG_v5 +++ b/data/doc/sisu/CHANGELOG_v5 @@ -38,6 +38,10 @@ http://www.jus.uio.no/sisu/pkg/src/sisu_5.0.25.orig.tar.xz * sisu_manual, minor info addition +* bin/sisu-* + * use option flag full names + * add sisu-html-scroll, sisu-html-seg, sisu-pdf-portrait, sisu-pdf-landscape + %% 5.0.24.orig.tar.xz (2013-11-05:44/2) http://sources.sisudoc.org/gitweb/?p=code/sisu.git;a=shortlog;h=refs/tags/sisu_5.0.24 http://sources.sisudoc.org/gitweb/?p=code/sisu.git;a=shortlog;h=refs/tags/debian/sisu_5.0.24-1 diff --git a/man/man1/sisu-html-scroll.1 b/man/man1/sisu-html-scroll.1 new file mode 100644 index 00000000..a39fa7bf --- /dev/null +++ b/man/man1/sisu-html-scroll.1 @@ -0,0 +1,39 @@ +.TH SISU-HTML 1 "2013-11-08" "4.2.12" "SiSU" + +.SH NAME +\fBSiSU\fR \- Structured information, Serialized Units \- a document publishing system + +.SH SYNOPSIS +\fBsisu\-html\-scroll\fR \fIsisu_document.sst\fR | \fIsisu_document.ssm\fR + +.SH DESCRIPTION +\fBSiSU\fR is a lightweight markup based document structuring, publishing and search framework for document collections. +.PP +The \fBsisu\-html\-scroll\fR command is an alias for \fBsisu \-\-html\-scroll\fR which produces HTML single document (scroll) output of a SiSU markup file. + +.SH SEE ALSO +\fIsisu\fR(1), +.br +\fIsisu\-concordance\fR(1), +.br +\fIsisu\-epub\fR(1), +.br +\fIsisu\-harvest\fR(1), +.br +\fIsisu\-html\fR(1), +.br +\fIsisu\-pdf\fR(1), +.br +\fIsisu\-odf\fR(1), +.br +\fIsisu\-pg\fR(1), +.br +\fIsisu\-sqlite\fR(1), +.br +\fIsisu\-txt\fR(1). + +.SH HOMEPAGE +More information about \fBSiSU\fR can be found at <\fIhttp://www.sisudoc.org/\fR> or <\fIhttp://www.jus.uio.no/sisu/\fR>. + +.SH AUTHOR +\fBSiSU\fR is written by Ralph Amissah <\fIralph@amissah.com\fR>. diff --git a/man/man1/sisu-html-seg.1 b/man/man1/sisu-html-seg.1 new file mode 100644 index 00000000..858bfb9a --- /dev/null +++ b/man/man1/sisu-html-seg.1 @@ -0,0 +1,39 @@ +.TH SISU-HTML 1 "2013-11-08" "4.2.12" "SiSU" + +.SH NAME +\fBSiSU\fR \- Structured information, Serialized Units \- a document publishing system + +.SH SYNOPSIS +\fBsisu\-html\-seg\fR \fIsisu_document.sst\fR | \fIsisu_document.ssm\fR + +.SH DESCRIPTION +\fBSiSU\fR is a lightweight markup based document structuring, publishing and search framework for document collections. +.PP +The \fBsisu\-html\-seg\fR command is an alias for \fBsisu \-\-html\-seg\fR (or \fBsisu \-h\fR) which produces HTML segmented output of a SiSU markup file. + +.SH SEE ALSO +\fIsisu\fR(1), +.br +\fIsisu\-concordance\fR(1), +.br +\fIsisu\-epub\fR(1), +.br +\fIsisu\-harvest\fR(1), +.br +\fIsisu\-html\fR(1), +.br +\fIsisu\-pdf\fR(1), +.br +\fIsisu\-odf\fR(1), +.br +\fIsisu\-pg\fR(1), +.br +\fIsisu\-sqlite\fR(1), +.br +\fIsisu\-txt\fR(1). + +.SH HOMEPAGE +More information about \fBSiSU\fR can be found at <\fIhttp://www.sisudoc.org/\fR> or <\fIhttp://www.jus.uio.no/sisu/\fR>. + +.SH AUTHOR +\fBSiSU\fR is written by Ralph Amissah <\fIralph@amissah.com\fR>. diff --git a/man/man1/sisu-pdf-landscape.1 b/man/man1/sisu-pdf-landscape.1 new file mode 100644 index 00000000..080c8bfc --- /dev/null +++ b/man/man1/sisu-pdf-landscape.1 @@ -0,0 +1,39 @@ +.TH SISU-PDF 1 "2011-03-05" "2.8.1" "SiSU" + +.SH NAME +\fBSiSU\fR \- Structured information, Serialized Units \- a document publishing system + +.SH SYNOPSIS +\fBsisu\-pdf\-landscape\fR \fIsisu_document.sst\fR | \fIsisu_document.ssm\fR + +.SH DESCRIPTION +\fBSiSU\fR is a lightweight markup based document structuring, publishing and search framework for document collections. +.PP +The \fBsisu\-pdf\-landscape\fR command is an alias for \fBsisu \-\-pdf\-landscape\fR which produces PDF landscape output of a SiSU markup file. + +.SH SEE ALSO +\fIsisu\fR(1), +.br +\fIsisu\-concordance\fR(1), +.br +\fIsisu\-epub\fR(1), +.br +\fIsisu\-harvest\fR(1), +.br +\fIsisu\-html\fR(1), +.br +\fIsisu\-pdf\fR(1), +.br +\fIsisu\-odf\fR(1), +.br +\fIsisu\-pg\fR(1), +.br +\fIsisu\-sqlite\fR(1), +.br +\fIsisu\-txt\fR(1). + +.SH HOMEPAGE +More information about \fBSiSU\fR can be found at <\fIhttp://www.sisudoc.org/\fR> or <\fIhttp://www.jus.uio.no/sisu/\fR>. + +.SH AUTHOR +\fBSiSU\fR is written by Ralph Amissah <\fIralph@amissah.com\fR>. diff --git a/man/man1/sisu-pdf-portrait.1 b/man/man1/sisu-pdf-portrait.1 new file mode 100644 index 00000000..e0e734fb --- /dev/null +++ b/man/man1/sisu-pdf-portrait.1 @@ -0,0 +1,39 @@ +.TH SISU-PDF 1 "2011-03-05" "2.8.1" "SiSU" + +.SH NAME +\fBSiSU\fR \- Structured information, Serialized Units \- a document publishing system + +.SH SYNOPSIS +\fBsisu\-pdf\-portrait\fR \fIsisu_document.sst\fR | \fIsisu_document.ssm\fR + +.SH DESCRIPTION +\fBSiSU\fR is a lightweight markup based document structuring, publishing and search framework for document collections. +.PP +The \fBsisu\-pdf\-portrait\fR command is an alias for \fBsisu \-\-pdf\-portrait\fR which produces PDF portrait output of a SiSU markup file. + +.SH SEE ALSO +\fIsisu\fR(1), +.br +\fIsisu\-concordance\fR(1), +.br +\fIsisu\-epub\fR(1), +.br +\fIsisu\-harvest\fR(1), +.br +\fIsisu\-html\fR(1), +.br +\fIsisu\-pdf\fR(1), +.br +\fIsisu\-odf\fR(1), +.br +\fIsisu\-pg\fR(1), +.br +\fIsisu\-sqlite\fR(1), +.br +\fIsisu\-txt\fR(1). + +.SH HOMEPAGE +More information about \fBSiSU\fR can be found at <\fIhttp://www.sisudoc.org/\fR> or <\fIhttp://www.jus.uio.no/sisu/\fR>. + +.SH AUTHOR +\fBSiSU\fR is written by Ralph Amissah <\fIralph@amissah.com\fR>. -- cgit v1.2.3