From 52f8b9c0b1e1606a4260ef2e0df4d525497691b1 Mon Sep 17 00:00:00 2001 From: Ralph Amissah Date: Sat, 7 Jul 2007 09:21:47 +0100 Subject: cgi-sample search form; texinfo fix; xml scaffold; help, man pages etc. visited; screen output, color set to true; docbook entries removed * cgi generated sample search form * order results on files of the same title, in multiple files (with different filenames) * postgresql, character case sensitivity, control, on/off * tail decoration, gplv3 & sisu info * texinfo/info (pinfo) module starts to do something vaguely useful again [not a much used module, testing required] * print XML rendition of document structure to screen -T * sisurc.yml default, color set to true [apologies if this causes anyone any inconvenience, it is configurable in sisurc.yml] * help, man pages, README (man(8) related and env, 'sisu -V') * docbook entries removed for the present time * sisu-install (install ruby rant script renamed) and permissions set to executable --- CHANGELOG | 30 + README | 59 +- Rantfile | 19 +- conf/sisu/sisurc.yml | 7 +- data/doc/sisu/copyright | 46 +- data/doc/sisu/html/sisu.1.html | 58 +- data/doc/sisu/html/sisu.8.html | 195 ++- install | 3088 ---------------------------------------- lib/sisu/v0/cgi_pgsql.rb | 28 +- lib/sisu/v0/cgi_sql_common.rb | 196 ++- lib/sisu/v0/cgi_sqlite.rb | 11 +- lib/sisu/v0/docbook.rb | 567 -------- lib/sisu/v0/help.rb | 98 +- lib/sisu/v0/hub.rb | 14 +- lib/sisu/v0/sysenv.rb | 23 +- lib/sisu/v0/texinfo.rb | 29 +- lib/sisu/v0/texinfo_format.rb | 133 +- lib/sisu/v0/urls.rb | 6 +- lib/sisu/v0/xml_scaffold.rb | 203 +++ man/man1/sisu.1 | 8 +- man/man8/sisu.8 | 141 +- sisu-install | 3088 ++++++++++++++++++++++++++++++++++++++++ 22 files changed, 3977 insertions(+), 4070 deletions(-) delete mode 100644 install delete mode 100644 lib/sisu/v0/docbook.rb create mode 100644 lib/sisu/v0/xml_scaffold.rb create mode 100755 sisu-install diff --git a/CHANGELOG b/CHANGELOG index 78bd3c4d..9108d041 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,36 @@ Reverse Chronological: %% STABLE MANIFEST +%% sisu_0.55.2.orig.tar.gz (2007-07-07:27/6) +http://www.jus.uio.no/sisu/pkg/src/sisu_0.55.2.orig.tar.gz + sisu_0.55.2.orig.tar.gz + sisu_0.55.2-1.dsc + sisu_0.55.2-1.diff.gz + + * cgi generated sample search form + * order results on files of the same title, in multiple files (with + different filenames) + * postgresql, character case sensitivity, control, on/off + * tail decoration, gplv3 & sisu info + + * texinfo/info (pinfo) module starts to do something vaguely useful again + [not a much used module, testing required] + + * print XML rendition of document structure to screen -T + + * help on environment visited, sisu -V + + * sisurc.yml default, color set to true + [apologies if this causes anyone any inconvenience, it is configurable in + sisurc.yml] + + * help and man pages, some work man(8) related + + * docbook entries removed for the present time + + * sisu-install (install ruby rant script renamed) and permissions set to + executable + %% sisu_0.55.1.orig.tar.gz (2007-07-02:27/1) http://www.jus.uio.no/sisu/pkg/src/sisu_0.55.1.orig.tar.gz cabdec70ded52ea7a0f3da45987169de 1265187 sisu_0.55.1.orig.tar.gz diff --git a/README b/README index b2f8a69f..789f95e2 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ -SiSU 0.49 2007w08/5 20070223 -homepage: http://www.jus.uio.no/sisu +SiSU 0.55 2007w27/6 2007-07-07 +homepage: %% Description --------------- @@ -42,7 +42,7 @@ homepage: http://www.jus.uio.no/sisu the substantive content of the marked up documents provided is that provided by the author or original publisher. - Homepage: http://www.jus.uio.no/sisu + Homepage: ----- @@ -87,14 +87,11 @@ Once set up it is simple to use. %% Online Information, places to look --------------- -http://www.jus.uio.no/sisu + Download Sources: - http://www.jus.uio.no/sisu/SiSU/download.html#current - http://www.jus.uio.no/sisu/SiSU/download.html#debian -or the same: - http://www.jus.uio.no/sisu/sisu_download/download.html#current - http://www.jus.uio.no/sisu/sisu_download/download.html#debian + + %% Installation --------------- @@ -104,8 +101,7 @@ NB. Platform is Unix / Linux. --------------- If you use Debian use the Debian packages, check the information at: - http://www.jus.uio.no/sisu/SiSU/download.html#debian - http://www.jus.uio.no/sisu/sisu_download/download.html#debian + (A) SiSU is available directly off the Debian archives for Sid and testing. It should necessary only to run as root: @@ -135,13 +131,12 @@ RPMs are provided though untested, they are prepared by running alien against th source package, and against the debs. They may be downloaded from: - http://www.jus.uio.no/sisu/SiSU/download.html#rpm + %% Source package .tgz --------------- Otherwise to install SiSU from source, check information at: - http://www.jus.uio.no/sisu/SiSU/download.html#current - http://www.jus.uio.no/sisu/sisu_download/download.html#current + two alternative modes of installation from source are provided, setup.rb (by Minero Aoki) and a rant(by Stefan Lang) built install file, @@ -149,7 +144,7 @@ in either case: the first steps are the same, download and unpack the source file: 1. Download the latest source (information available) from: - http://www.jus.uio.no/sisu/SiSU/download.html#current + 2. Unpack the source @@ -164,16 +159,16 @@ in the root directory of the unpacked SiSU as root type: ruby setup.rb install further information: - http://i.loveruby.net/en/projects/setup/ - http://i.loveruby.net/en/projects/setup/doc/usage.html + + %% to use install (prapared with "Rant") --------------- in the root directory of the unpacked SiSU as root type: - ruby install + ruby ./sisu-install or - ruby install base + ruby ./sisu-install base This makes use of Rant (by Stefan Lang) and the provided Rantfile. It has been configured to do post installation setup setup configuration and generation of @@ -181,12 +176,12 @@ first test file. Note however, that additional external package dependencies, such as tetex-extra are not taken care of for you. further information: - http://make.rubyforge.org/ - http://rubyforge.org/frs/?group_id=615 + + For a list of alternative actions you may type: - ruby install help - ruby install -T + ruby ./sisu-install help + ruby ./sisu-install -T Dependencies -------------- @@ -262,7 +257,7 @@ examine source document, vim has syntax support gvim free_as_in_freedom.rms_and_free_software.sam_williams.sst additional markup samples in -http://www.jus.uio.no/sisu/SiSU/2.html + For help man sisu @@ -353,12 +348,15 @@ for questions about mappings, output paths etc. --------------- Once installed, type: sisu --help env +or + sisu -V %% Configuration File --------------- The defaults can be changed via SiSU's configure file sisurc.yml which the -program expects to find in ./_sisu ~/.sisu or /etc/sisu +program expects to find in ./_sisu ~/.sisu or /etc/sisu (searched in that +order, stopping on the first one found) %% Markup --------------- @@ -366,6 +364,8 @@ program expects to find in ./_sisu ~/.sisu or /etc/sisu See man pages. man sisu + man 8 sisu + Once installed there is some information on SiSU Markup in its help: sisu --help markup and @@ -379,9 +379,10 @@ These are installed on the system usually at: /usr/share/doc/sisu/sisu_markup_samples/dfsg More markup samples are available in the package sisu-markup-samples + Many more are available online off: - http://www.jus.uio.no/sisu/SiSU/2.html + %% Additional Things --------------- @@ -419,4 +420,8 @@ All Rights Reserved. * however note the License section - +CHANGELOG + ./CHANGELOG +and see + + diff --git a/Rantfile b/Rantfile index 04063df5..f46c89ec 100644 --- a/Rantfile +++ b/Rantfile @@ -189,7 +189,7 @@ task :default => [:default_notice,:project] desc "Setup/Install #{@proj[: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] desc "Setup/Install #{@proj[:name]}" -task :setup=> [:setup_bin, :setup_lib,:setup_conf,:setup_share,:setup_data,:post_install] #, :help] +task :setup=> [:setup_bin, :setup_lib,:setup_conf,:setup_share,:setup_data] #, :help] desc "Setup/Install #{@proj[:name]}: bin, lib and conf (no data)" task :setup_base=> [:setup_bin,:setup_lib,:setup_conf,:setup_share,:setup_man,:setup_vim] desc "Setup/Install #{@proj[:name]} bin, lib and conf (no data and no attempt to do postinstall setup)" @@ -290,8 +290,6 @@ if File.directory?('man') #man end desc "Setup Note" task :setup_note => [:help] -desc "Note on post installation" #remove conf -task :post_install_note => [:post_install_note] desc "System information used by #{@proj[:name]}" task :system => [:system_info,:project_help,:post_install_note] desc "show all system info available - parameters found" @@ -307,24 +305,19 @@ task :create_rant_independent_task_file => [:rant_independence] task :rant_independence do #notice resp='' while resp.length < 4 - resp='install' #default name install + resp='sisu-install' #default name install print %{#{@proj[:rant]} Create a rant dependency independent file provide filename default name is "install" [Warning, will overwrite file of name provided provide name or "quit" to exit]: } - #res=File.new('/dev/tty').gets.strip - #resp=res if res =~/\S{4,30}/ exit if resp =~/^(?:n|quit|exit)$/ end remove='y' #remove='n' - #remove=if FileTest.file?(resp) - # print "a file of the same name #{resp} exists, [y] to replace: " - # File.new('/dev/tty').gets.strip - #else 'y' - #end - if remove =~/y/; system("rant-import --force --auto #{resp}\n") - #puts "#{resp} updated" + if remove =~/y/ + system("rant-import --force --auto #{resp}; + chmod 755 #{resp} + ") else #puts "#{resp} not replaced" end end diff --git a/conf/sisu/sisurc.yml b/conf/sisu/sisurc.yml index bdc20329..ab07108e 100644 --- a/conf/sisu/sisurc.yml +++ b/conf/sisu/sisurc.yml @@ -1,4 +1,4 @@ -# Name: SiSU - Simple information Structuring Universe - Structured information, Serialized Units +# Name: SiSU - Simple information Structuring Universe # Author: Ralph@Amissah.com # Description: Site wide envionment defaults set here # system environment info / resource configuration file, for sisu @@ -53,8 +53,8 @@ show_output_on: 'filesystem_url' # concord_max: 400000 #% flag - set (non-default) processing flag shortcuts -1, -2 etc. (here adding colour and verbosity as default) flag: - color: false # colour now off by default (does not suit all terms/consoles) -c is color (on/f) toggle (note: set default true/false here, if -c is added to the shortuct defaults below, then another -c added to the command line won't toggle on/off) - default: '-mNhwpoabxXyYv' # includes verbose; -m would in any event be run by default + color: true # making colour default -c is toggle, and will now toggle colour off + default: '-NhwpoabxXyYv' # includes verbose; -m would in any event be run by default i: '-Nhwpoayv' # includes verbose; -m run by default ii: '-NhwpoabxXyv' # includes verbose; -m run by default iii: '-NhwpoabxXyYv' # includes verbose; -m run by default @@ -115,3 +115,4 @@ program_set: # action: http://localhost:8081/cgi-bin/sisu_sqlite.cgi ## action: http://search.sisudoc.org # db: sisu +# title: sample search form diff --git a/data/doc/sisu/copyright b/data/doc/sisu/copyright index c15699c4..6b129a77 100644 --- a/data/doc/sisu/copyright +++ b/data/doc/sisu/copyright @@ -8,33 +8,31 @@ The original source can always be found at: -Copyright (C) 1997, 1998, 1999, 2000, 20001, 2002, 2003, 2004, 2005 -Ralph Amissah +License: GPL 3 or later: -License: GPL v3 or later + SiSU, a framework for document structuring, publishing and search - GPL3 summary: + Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, + 2007 Ralph Amissah - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. - You should have received a copy of the GNU General Public License - along with this package; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - MA 02110-1301, USA + You should have received a copy of the GNU General Public License along with + this program. If not, see . If you have Internet connection, the latest version of the GPL should be - available from these locations: - - - + available at these locations: + + + On Debian systems, the complete text of the GNU General Public License can be found in `/usr/share/common-licenses/GPL'. @@ -42,7 +40,7 @@ License: GPL v3 or later The Free Software Foundation: -For installation purposes the SiSU tarball includes +For installation purposes the SiSU tarball includes: setup.rb by Minero Aoki @@ -52,9 +50,9 @@ Hompepage: License: LGPL -and +and -install, an installer generated by +sisu-install, an installer generated by Rant which is by Stefan Lang Homepage: @@ -64,4 +62,4 @@ License: LGPL NB: Rant is not included in the SiSU tarball, and is not itself required for - the Rant generated install file to work + the Rant generated install file to work, (ruby will suffice) diff --git a/data/doc/sisu/html/sisu.1.html b/data/doc/sisu/html/sisu.1.html index 61d0ab0d..968f8eb1 100644 --- a/data/doc/sisu/html/sisu.1.html +++ b/data/doc/sisu/html/sisu.1.html @@ -12,7 +12,7 @@ SiSU - Structured information, Serialized Units - a document publishing system

Synopsis

-sisu [ -AabcDdEeFHhIMmNnopqrRSstUuVvwXxYyZz0-9 +sisu [ -AabcDdEeFHhIMmNnopqRrSsTtUuVvwXxYyZz0-9 ] [ filename/ wildcard ]

sisu [ -Ddcv ] [ instruction ]

sisu [ -CcFLSVvW @@ -130,37 +130,37 @@ most web servers). [behaviour switched after 0.35 see -H].

-I [filename/wildcard]
-
produces texinfo file.
+
produces texinfo and info file, (view with pinfo).
-L
-
prints license information.
+
prints license information. +
+ +
-M [filename/wildcard/url]
+
maintenance mode files created for processing +preserved and their locations indicated. (also see -V)
+ +
-m [filename/wildcard/url] +
+
assumed for most other flags, creates new meta-markup file, (the metaverse +) that is used in all subsequent processing of other output. This step is +assumed for most processing flags. To skip it see -n
+ +
-N [filename/wildcard/url] +
+
document digest or document content certificate ( DCC ) as md5 digest tree +of the document: the digest for the document, and digests for each object +contained within the document (together with information on software versions +that produced it) (digest.txt). -NV for verbose digest output to screen.
+ +
-n [filename/wildcard/url] +
+
skip meta-markup (building of "metaverse"), this skips the equivalent of +-m which is otherwise assumed by most processing flags.
-
-M [filename/wildcard/url] +
-o [filename/wildcard/url]
-
maintenance mode files created for processing preserved and their locations -indicated. (also see -V)
- -
-m [filename/wildcard/url]
-
assumed for most other -flags, creates new meta-markup file, (the metaverse ) that is used in all -subsequent processing of other output. This step is assumed for most processing -flags. To skip it see -n
- -
-N [filename/wildcard/url]
-
document digest or document -content certificate ( DCC ) as md5 digest tree of the document: the digest -for the document, and digests for each object contained within the document -(together with information on software versions that produced it) (digest.txt). --NV for verbose digest output to screen.
- -
-n [filename/wildcard/url]
-
skip meta-markup -(building of "metaverse"), this skips the equivalent of -m which is otherwise -assumed by most processing flags.
- -
-o [filename/wildcard/url]
-
output basic -document in opendocument file format (opendocument.odt).
+
output basic document in opendocument file format (opendocument.odt).
-p [filename/wildcard]
@@ -1161,7 +1161,7 @@ set up, and first time must be run without other flags ie sisu -mrv [file sisu -mhwprv example_file.sst other_example_file.sst

to process a remote sisu marked up file (html,pdf,concordance), provide the url(s) (works for text -only files, will be downloaded and processed locally): sisu -mhwpv http://www.jus.uio.no/sisu/gpl3.fsf/gpl3.fsf.sst +only files, will be downloaded and processed locally): sisu -mhwpv http://www.jus.uio.no/sisu/sample/markup/gpl3.fsf.sst http://www.jus.uio.no/sisu/sample/markup/autonomy_markup0.sst

one file is local diff --git a/data/doc/sisu/html/sisu.8.html b/data/doc/sisu/html/sisu.8.html index b79b71b1..c6134b33 100644 --- a/data/doc/sisu/html/sisu.8.html +++ b/data/doc/sisu/html/sisu.8.html @@ -19,65 +19,72 @@ document publishing system, that from a simple single marked-up document, produces a multitude of output formats including: html, latex, pdf, info, and sql output, which can be cross referenced as having the same document structure and text object numbering, "object citation numbering". Features -include its’ simple syntax; the semantic identification of documents using -the Dublin Core; document management; built to be associated with a revision -control system; text object numbering for the identification of a texts -location in any of the output formats, easy skinning on a site wide, or -per document basis, ... for more see man 1 sisu or <http://www.jus.uio.no/sisu +include its’ simple syntax; the semantic tagging of documents; document +management; built to be associated with a revision control system; text +object numbering for the identification of a texts location in any of the +output formats, easy skinning on a site wide, or per document basis; granular +search; a degree of future proofing ... for more see man 1 sisu or <http://www.jus.uio.no/sisu >

-SiSU is an alternative way of publishing and managing documents. +SiSU is a way of preparing, publishing, managing and searching documents. +

Installation

-Up -to date information on SiSU downloads, and their installation should be -available from: <http://www.jus.uio.no/sisu/SiSU/download.html -> or at: <http://www.jus.uio.no/sisu/sisu_download/download.html +Up to date information on SiSU downloads, and their installation +should be available from: <http://www.jus.uio.no/sisu/SiSU/download.html +> or +at: <http://www.jus.uio.no/sisu/sisu_download/download.html +>

+There you should +find links to the latest source tarball, and instructions on how to install +SiSU.

+Sample marked up documents are are available at /usr/share/doc/sisu/sisu_markup_samples/dfsg +or equivalent directory, or online, see <http://www.jus.uio.no/sisu/SiSU/2.html >

-There you should find links to the latest source tarball, and instructions -on how to install SiSU.

-Sample marked up documents are are available at -/usr/share/doc/sisu/sisu_markup_samples/dfsg or equivalent directory, or -online at <http://www.jus.uio.no/sisu/sample/markup.html -> or for viewing in html -with syntax highlighting from <http://www.jus.uio.no/sisu/sample/syntax ->

-A syntax -table is provided at /usr/share/doc/sisu/on_markup.txt or equivalent, and -online at <http://www.jus.uio.no/sisu/sample/on_markup.txt ->

-man 1 sisu has a -syntax table along with processing commands.

-SiSU also provides some help -via the command: sisu --help and selecting an appropriate subject, e.g.

-sisu ---help commands

+man 1 sisu has a syntax table along with processing commands.

+SiSU also +provides some help via the command: sisu --help and selecting an appropriate +subject, e.g.

+sisu --help commands

sisu --help markup

sisu --help headers

-sisu --help env

-The rest -of this note is on post installation setup -

Post Installation Setup - Quick -start

-

-After installation of sisu-complete, move to the document samples directory +sisu +--help env

+The rest of this note is on post installation setup +

Post Installation +Setup - Quick start

+ +

After installation of sisu-complete, move to the document +samples directory,

cd /usr/share/doc/sisu/sisu_markup_samples/dfsg

-and run

- sisu -1 free_as_in_freedom.rms_and_free_software.sam_williams.sst
-

+[this is not where you would normally work but provides sample documents +for testing, you may prefer instead to copy the contents of that directory +to a local directory before proceeding]

+and in that directory, initialise +the output directory with the command

+sisu -CC

+then run:

+sisu -1 free_as_in_freedom.rms_and_free_software.sam_williams.sst +

or the same:

- sisu -NhwpoabxXyv free_as_in_freedom.rms_and_free_software.sam_williams.sst
-

+sisu -NhwpoabxXyv free_as_in_freedom.rms_and_free_software.sam_williams.sst +

look at output results, see the "sisu_manifest" page created for the document

-To generate an online document move to a writable directory, (create a -work directory and cd into it) as the file will be downloaded there and -e.g.

+for an overview of your current sisu setup, type:

+sisu --help env

+or

+sisu +-V

+To generate a document from a remote url accessible location move to +a writable directory, (create a work directory and cd into it) as the file +will be downloaded there and e.g.

sisu -1 http://www.jus.uio.no/sisu/gpl3.fsf/gpl3.fsf.sst -

+ +

sisu -3 http://www.jus.uio.no/sisu/free_culture.lawrence_lessig/free_culture.lawrence_lessig.sst

@@ -140,39 +147,76 @@ gives an idea of additional packages that SiSU can make use of if available, (the use/requirement of some of which are interdependent for specific actions by SiSU):

Package: sisu

-Depends: ruby (>= 1.8.4), libwebrick-ruby

+Depends: ruby (>= 1.8.2), libwebrick-ruby, unzip, zip +

+Conflicts: vim-sisu, sisu-vim, sisu-remote

+Replaces: vim-sisu, sisu-vim

Recommends: -sisu-pdf, sisu-sqlite, sisu-postgresql, librmagick-ruby, trang, tidy, librexml-ruby, -zip, unzip, openssl, rsync, openssh-client lsh-client,
- keychain, hyperestraier, kdissert
-

-Suggests: libfcgi-ruby1.8, rcs cvs, lv, texinfo, pinfo, rename

-Package: -sisu-complete

-Depends: ruby (>= 1.8.4), sisu, sisu-pdf, sisu-postgresql, sisu-sqlite +sisu-pdf, sisu-sqlite, sisu-postgresql, librmagick-ruby, trang, tidy, librexml-ruby, +openssl, rsync, openssh-client lsh-client, keychain, hyperestraier, kdissert +Suggests: rcs cvs, lv, texinfo, pinfo

+Package: sisu-complete

+Depends: ruby +(>= 1.8.2), sisu, sisu-pdf, sisu-postgresql, sisu-sqlite

+Recommends: hyperestraier

-Recommends: hyperestraier

Package: sisu-pdf

-Depends: sisu, tetex-bin texlive-base-bin, -tetex-extra texlive-latex-extra, texlive-latex-extra, latex-ucs
-

+Depends: sisu, texlive-latex-base, texlive-fonts-recommended, +texlive-latex-recommended, texlive-latex-extra

Suggests: evince, xpdf

-Package: sisu-postgresql

-Depends: sisu, postgresql-8.1, -libdbi-ruby, libdbm-ruby, libdbd-pg-ruby

-Suggests: pgaccess, libdbd-pgsql, postgresql-contrib-8.1 +Package: +sisu-postgresql

+Depends: sisu, libdbd-pg-ruby, libdbi-ruby, libdbm-ruby, postgresql

+Recommends: libfcgi-ruby

Package: sisu-sqlite

-Depends: sisu, sqlite, libdbi-ruby, libdbm-ruby, libdbd-sqlite-ruby +Depends: sisu, sqlite, libdbd-sqlite-ruby, +libdbi-ruby, libdbm-ruby

+Recommends: libfcgi-ruby

+Package: sisu-markup-samples

-Suggests: libdbd-sqlite

-Package: sisu-markup-samples

Depends: sisu

+ +

Package Description

+sisu

+Description: documents - structuring, +publishing in multiple formats and search

+SiSU is a lightweight markup +based, command line oriented, document structuring, publishing and search +framework for document collections.

+With minimal preparation of a plain-text, +(UTF-8) file, using its native markup syntax in your text editor of choice, +SiSU can generate various document formats (most of which share a common +object numbering system for locating content), including plain text, HTML, +XHTML, XML, OpenDocument text (ODF:ODT), LaTeX, PDF files, and populate +an SQL database with objects (roughly paragraph-sized chunks) so searches +may be performed and matches returned with that degree of granularity: +your search criteria is met by these documents and at these locations within +each document. Object numbering is particularly suitable for "published" +works (finalized texts as opposed to works that are frequently changed +or updated) for which it provides a fixed means of reference of content. +Document outputs also share semantic meta-data provided.

+SiSU also provides +concordance files, document content certificates and manifests of generated +output.

+A vim syntax highlighting file and an ftplugin with folds for sisu +markup is provided, as are syntax highlighting files for kate, kwrite, +gedit and diakonos. Vim 7 includes syntax highlighting for SiSU.

+man pages, +and interactive help are provided.

+Dependencies for various features are +taken care of in sisu related packages. The package sisu-complete installs +the whole of SiSU.

+Additional document markup samples are provided in the +package sisu-markup-samples which is found in the non-free archive the licenses +for the substantive content of the marked up documents provided is that +provided by the author or original publisher.

+Homepage: <http://www.jus.uio.no/sisu +> -

Document -Resource Configuration

-sisu resource configuration information is obtained -from sources (where they exist):
+

Document Resource Configuration

+sisu resource configuration information +is obtained from sources (where they exist):
~/.sisu/sisurc.yaml/etc/sisu/[sisu version]/sisurc.yamlsisu program defaults

Skins

@@ -190,16 +234,16 @@ of documents.

Usually all skin files are placed in the document skin directory: ~/.sisu/skin/doc with softlinks being made to the skins contained there from other skin directories as required. -

Further Information

+

Further Information

For more information on SiSU see: <http://www.jus.uio.no/sisu >

or man sisu -

Author

+

Author

Ralph Amissah <ralph@amissah.com> or <ralph.amissah@gmail.com> -

See Also

+

See Also

sisu(1) , sisu_examples(1) , sisu_webrick(1) @@ -219,10 +263,11 @@ or <ralph.amissah@gmail.com>
  • Installation
  • Post Installation Setup - Quick start
  • Debian INSTALLATION Note
  • -
  • Document Resource Configuration
  • -
  • Further Information
  • -
  • Author
  • -
  • See Also
  • +
  • Package Description
  • +
  • Document Resource Configuration
  • +
  • Further Information
  • +
  • Author
  • +
  • See Also
  • diff --git a/install b/install deleted file mode 100644 index 78ad16a4..00000000 --- a/install +++ /dev/null @@ -1,3088 +0,0 @@ -#!/usr/bin/env ruby - -# 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 diff --git a/lib/sisu/v0/cgi_pgsql.rb b/lib/sisu/v0/cgi_pgsql.rb index e5260a5f..0032a927 100644 --- a/lib/sisu/v0/cgi_pgsql.rb +++ b/lib/sisu/v0/cgi_pgsql.rb @@ -92,7 +92,7 @@ module SiSU_CGI_pgsql f2 << " end\n" if FileTest.writable?('.') output=File.open('sisu_pgsql.cgi','w') - output << header0 << header1 << header_desc << header2 << f1 << buttons1 << buttons_note << buttons2 << search_request << search_statement << search_statement_common << search_query1 << @common.pages << search_query2 << @common.tail << @common.main1 << f2 << dbi_connect << @common.main2 + output << header0 << header1 << header_desc << header2 << f1 << buttons1 << buttons2 << buttons2_pgsql << buttons3 << search_request << search_statement << search_statement_common << search_query1 << @common.pages << search_query2 << @common.tail << @common.main1 << f2 << dbi_connect << @common.main2 a=%{ generated sisu_pgsql.cgi, BASED ON ALREADY EXISTING directories that could potentially be used to populate postgresql db, (-D) } @@ -139,8 +139,8 @@ module SiSU_CGI_pgsql def search_statement <<-'WOK_SQL' class Dbi_search_string - def initialize(l,t,q) - @l,@t,@q=l,t,q + def initialize(l,t,q,cse=false) + @l,@t,@q,@c=l,t,q,cse end def string search={ :search => [],:flag => false } @@ -149,8 +149,13 @@ module SiSU_CGI_pgsql elsif @q =~/\S+/; unescaped_search=CGI.unescape(@q) end search_construct=[] - unescaped_search.gsub!(/\s*(AND|OR)\s*/,"' \) \\1 #@l~\( '") - unescaped_search.gsub!(/(.+)/,"#@l~\( '\\1' \)") + if @c + unescaped_search.gsub!(/\s*(AND|OR)\s*/,"' \) \\1 #@l~\( '") + unescaped_search.gsub!(/(.+)/,"#@l~\( '\\1' \)") + else + unescaped_search.gsub!(/\s*(AND|OR)\s*/,"' \) \\1 #@l~*\( '") + unescaped_search.gsub!(/(.+)/,"#@l~*\( '\\1' \)") + end search_construct << unescaped_search search_construct=search_construct.join(' ') search[:search] << search_construct @@ -162,9 +167,6 @@ module SiSU_CGI_pgsql end WOK_SQL end - def buttons_note - ' case sensitive' - end def search_query1 <<-'WOK_SQL' @search_text,@search_endnotes=[],[] @@ -183,7 +185,7 @@ module SiSU_CGI_pgsql def sql_select_body limit ||=@@limit offset ||=@@offset - @sql_statement[:body]=%{SELECT metadata.title, metadata.creator, metadata.filename, metadata.suffix, documents.body, documents.seg, documents.ocn, metadata.tid FROM documents, metadata WHERE (#@search_text) AND documents.metadata_tid = metadata.tid ORDER BY metadata.title, documents.ocn} + @sql_statement[:body]=%{SELECT metadata.title, metadata.creator, metadata.filename, metadata.suffix, documents.body, documents.seg, documents.ocn, metadata.tid FROM documents, metadata WHERE (#@search_text) AND documents.metadata_tid = metadata.tid ORDER BY metadata.title, metadata.filename, documents.ocn} @sql_statement[:range]=%{LIMIT #{limit} OFFSET #{offset} ;} select=@sql_statement[:body] + ' ' + @sql_statement[:range] select @@ -191,7 +193,7 @@ module SiSU_CGI_pgsql def sql_select_endnotes limit ||=@@limit offset ||=@@offset - @sql_statement[:endnotes]=%{SELECT metadata.title, metadata.creator, metadata.filename, endnotes.body, endnotes.nr, endnotes.ocn, endnotes.metadata_tid FROM metadata, endnotes WHERE (#@search_endnotes) AND metadata.tid = endnotes.metadata_tid ORDER BY metadata.title, endnotes.nr} + @sql_statement[:endnotes]=%{SELECT metadata.title, metadata.creator, metadata.filename, endnotes.body, endnotes.nr, endnotes.ocn, endnotes.metadata_tid FROM metadata, endnotes WHERE (#@search_endnotes) AND metadata.tid = endnotes.metadata_tid ORDER BY metadata.title, metadata.filename, endnotes.nr} @sql_statement[:range]=%{LIMIT #{limit} OFFSET #{offset} ;} select=@sql_statement[:endnotes] + ' ' + @sql_statement[:range] select @@ -211,6 +213,12 @@ module SiSU_CGI_pgsql end WOK_SQL end + def buttons2_pgsql + <<-'WOK_SQL' + + case sensitive + WOK_SQL + end def dbi_connect <<-'WOK_SQL' dbi="dbi:Pg:database=#{@db};port=#{@port}" diff --git a/lib/sisu/v0/cgi_sql_common.rb b/lib/sisu/v0/cgi_sql_common.rb index 6045bf10..37ca67b8 100644 --- a/lib/sisu/v0/cgi_sql_common.rb +++ b/lib/sisu/v0/cgi_sql_common.rb @@ -131,11 +131,11 @@ module SiSU_CGI_sql @color_heading='#DDFFAA' @color_match='#ffff48' class Form - def initialize(base,search_field,selected_db,checked_index,checked_text,checked_tip,checked_searched,checked_url,checked_echo,checked_sql,checked_all,checked_none,checked_ignore,search_note,the_can='') + def initialize(base,search_field,selected_db,checked_index,checked_text,checked_tip,checked_searched,checked_url,checked_case,checked_echo,checked_sql,checked_all,checked_none,checked_ignore,search_note,the_can='') search_note='' if checked_searched !~/\S/ the_can='' if checked_url !~/\S/ search_field='' if checked_echo !~/\S/ - @base,@search_field,@selected_db,@checked_index,@checked_text,@checked_tip,@checked_searched,@checked_url,@checked_echo,@checked_sql,@checked_all,@checked_none,@checked_ignore,@search_note,@the_can=base,search_field,selected_db,checked_index,checked_text,checked_tip,checked_searched,checked_url,checked_echo,checked_sql,checked_all,checked_none,checked_ignore,search_note,the_can + @base,@search_field,@selected_db,@checked_index,@checked_text,@checked_tip,@checked_searched,@checked_url,@checked_case,@checked_echo,@checked_sql,@checked_all,@checked_none,@checked_ignore,@search_note,@the_can=base,search_field,selected_db,checked_index,checked_text,checked_tip,checked_searched,checked_url,checked_case,checked_echo,checked_sql,checked_all,checked_none,checked_ignore,search_note,the_can @tip=if checked_tip =~/\S/ 'text:__; keywords:__; title:__; author:__; subject:__; description:__; publisher:__; contributor:__; date:__; type:__; format:__; identifier:__; source:__; language:__; relation:__; coverage:__; rights:__; comment:__; abstract:__; filename:__;' else '' @@ -205,8 +205,13 @@ module SiSU_CGI_sql #@tip #@search_note #@the_can -
    - +
    +
    + WOK_SQL + end + def buttons3 + <<-'WOK_SQL' +
    echo previous search search result stats url for search @@ -319,106 +324,109 @@ module SiSU_CGI_sql <<-'WOK_SQL' class Dbi_search_statement attr_reader :text_search_flag,:sql_select_body_format,:sql_select_endnotes_format,:sql_offset,:sql_limit - def initialize(conn,search_for,q) + def initialize(conn,search_for,q,c) @conn=conn @text_search_flag=false @sql_statement={ :body=>'',:endnotes=>'',:range=>'' } #@offset||=@@offset #@offset+=@@limit search={ :text => [],:endnotes => [] } - st=Dbi_search_string.new('documents.clean',search_for.text1,q['s1']).string - se=Dbi_search_string.new('endnotes.clean',search_for.text1,q['s1']).string + cse=if c =~/\S/; true + else false + end + st=Dbi_search_string.new('documents.clean',search_for.text1,q['s1'],cse).string + se=Dbi_search_string.new('endnotes.clean',search_for.text1,q['s1'],cse).string @text_search_flag=st[:flag] if st[:flag] search[:text] << st[:search] search[:endnotes] << se[:search] end - st=Dbi_search_string.new('metadata.keywords',search_for.keywords,q['key']).string + st=Dbi_search_string.new('metadata.keywords',search_for.keywords,q['key'],cse).string if st[:flag] search[:text] << st[:search] search[:endnotes] << st[:search] end - st=Dbi_search_string.new('metadata.title',search_for.title,q['ti']).string + st=Dbi_search_string.new('metadata.title',search_for.title,q['ti'],cse).string if st[:flag] search[:text] << st[:search] search[:endnotes] << st[:search] end - st=Dbi_search_string.new('metadata.creator',search_for.author,q['au']).string + st=Dbi_search_string.new('metadata.creator',search_for.author,q['au'],cse).string if st[:flag] search[:text] << st[:search] search[:endnotes] << st[:search] end - st=Dbi_search_string.new('metadata.subject',search_for.subject,q['sj']).string + st=Dbi_search_string.new('metadata.subject',search_for.subject,q['sj'],cse).string if st[:flag] search[:text] << st[:search] search[:endnotes] << st[:search] end - st=Dbi_search_string.new('metadata.description',search_for.description,q['dsc']).string + st=Dbi_search_string.new('metadata.description',search_for.description,q['dsc'],cse).string if st[:flag] search[:text] << st[:search] search[:endnotes] << st[:search] end - st=Dbi_search_string.new('metadata.publisher',search_for.publisher,q['pb']).string + st=Dbi_search_string.new('metadata.publisher',search_for.publisher,q['pb'],cse).string if st[:flag] search[:text] << st[:search] search[:endnotes] << st[:search] end - st=Dbi_search_string.new('metadata.contributor',search_for.contributor,q['cntr']).string + st=Dbi_search_string.new('metadata.contributor',search_for.contributor,q['cntr'],cse).string if st[:flag] search[:text] << st[:search] search[:endnotes] << st[:search] end - st=Dbi_search_string.new('metadata.date',search_for.date,q['dt']).string + st=Dbi_search_string.new('metadata.date',search_for.date,q['dt'],cse).string if st[:flag] search[:text] << st[:search] search[:endnotes] << st[:search] end - st=Dbi_search_string.new('metadata.type',search_for.type,q['ty']).string + st=Dbi_search_string.new('metadata.type',search_for.type,q['ty'],cse).string if st[:flag] search[:text] << st[:search] search[:endnotes] << st[:search] end - st=Dbi_search_string.new('metadata.identifier',search_for.identifier,q['id']).string + st=Dbi_search_string.new('metadata.identifier',search_for.identifier,q['id'],cse).string if st[:flag] search[:text] << st[:search] search[:endnotes] << st[:search] end - st=Dbi_search_string.new('metadata.source',search_for.source,q['src']).string + st=Dbi_search_string.new('metadata.source',search_for.source,q['src'],cse).string if st[:flag] search[:text] << st[:search] search[:endnotes] << st[:search] end - st=Dbi_search_string.new('metadata.language',search_for.language,q['lang']).string + st=Dbi_search_string.new('metadata.language',search_for.language,q['lang'],cse).string if st[:flag] search[:text] << st[:search] search[:endnotes] << st[:search] end - st=Dbi_search_string.new('metadata.relation',search_for.relation,q['rel']).string + st=Dbi_search_string.new('metadata.relation',search_for.relation,q['rel'],cse).string if st[:flag] search[:text] << st[:search] search[:endnotes] << st[:search] end - st=Dbi_search_string.new('metadata.coverage',search_for.coverage,q['cov']).string + st=Dbi_search_string.new('metadata.coverage',search_for.coverage,q['cov'],cse).string if st[:flag] search[:text] << st[:search] search[:endnotes] << st[:search] end - st=Dbi_search_string.new('metadata.rights',search_for.rights,q['cr']).string + st=Dbi_search_string.new('metadata.rights',search_for.rights,q['cr'],cse).string if st[:flag] search[:text] << st[:search] search[:endnotes] << st[:search] end - st=Dbi_search_string.new('metadata.comment',search_for.comment,q['co']).string + st=Dbi_search_string.new('metadata.comment',search_for.comment,q['co'],cse).string if st[:flag] search[:text] << st[:search] search[:endnotes] << st[:search] end - st=Dbi_search_string.new('metadata.abstract',search_for.abstract,q['ab']).string + st=Dbi_search_string.new('metadata.abstract',search_for.abstract,q['ab'],cse).string if st[:flag] search[:text] << st[:search] search[:endnotes] << st[:search] end - st=Dbi_search_string.new('metadata.filename',search_for.filename,q['fns']).string + st=Dbi_search_string.new('metadata.filename',search_for.filename,q['fns'],cse).string if st[:flag] search[:text] << st[:search] search[:endnotes] << st[:search] @@ -479,32 +487,99 @@ module SiSU_CGI_sql WOK_SQL end def tail + v=SiSU_Env::Info_version.new.get_version <<-WOK_SQL def tail <<-'WOK'


    -
    - - -

    - presentations' look and feel
    - generated by
    - SiSU in Ruby with the usual GPL (or OSS) suspects - Way Better!
    - SiSU
    - version 0.50
    2007w11/1 (2007-03-12)
    - - - © Ralph Amissah
    - 1993, current 2007
    - GPL 3
    - w3 since October 3 1993
    - ralph@amissah.com
    -

    -
    - -

    the usual GPL (or OSS) suspects:
    Better - "performance, reliability, scalability, security
    & total cost of ownership"
    [not to mention flexibility & choice]

    <<Way Better!>>

    - -
    + + + + +
    + +
    +

    + + + GPLv3 + +

    +
    +

    + SiSU © Ralph Amissah + 1993, current 2007 + All Rights Reserved. +
    + SiSU is released under + GPL v3 + or later + + http://www.gnu.org/licenses/gpl.html + +

    +
    +

    + Developed using + + Ruby + + on + + Debian/Gnu/Linux + + software infrastructure, + & with the usual GPL (or OSS) suspects. +
    + Better - "performance, reliability, scalability, security & total cost of ownership" + [not to mention flexibility & choice] +
    + Get With the Future + + Way Better! + +

    +
    +

    + + SiSU + +

    +
    + +

    + Generated by + + SiSU + + #{v[:project]} #{v[:version]} #{v[:date]} (#{v[:date_stamp]}) +
    + + www.jus.uio.no/sisu + + and + + www.sisudoc.org + +
    +
    + w3 since October 3 1993 + + ralph@amissah.com + +

    +
    +

    + Using: +
    Standard SiSU markup syntax, +
    Standard SiSU meta-markup syntax, and the +
    Standard SiSU object citation numbering and system, (object/text positioning system) +
    + © Ralph Amissah 1997, current 2007. + All Rights Reserved. +

    +
    + WOK end @@ -526,13 +601,14 @@ module SiSU_CGI_sql @stub='sisu' 'SiSU_sisu' end - checked_url,checked_searched,checked_tip,checked_echo,checked_sql,checked_all,checked_none,checked_ignore,selected_db='','','','','','','','' + checked_url,checked_searched,checked_tip,checked_case,checked_echo,checked_sql,checked_all,checked_none,checked_ignore,selected_db='','','','','','','','','' if cgi['view']=~/text/; checked_index,checked_text='','checked' else checked_index,checked_text='checked','' end checked_url='checked' if cgi['url'] =~/\S/ or cgi['u'].to_i==1 checked_searched='checked' if cgi['searched'] =~/\S/ checked_tip='checked' if cgi['tip'] =~/\S/ + checked_case='checked' if cgi['casesense'] =~/\S/ checked_echo='checked' if cgi['echo'] =~/\S/ checked_sql='checked' if cgi['sql'] =~/\S/ if cgi['checks'] =~/check_all/ or cgi['check_all'] =~/\S/ or cgi['a'].to_i==1 @@ -580,8 +656,13 @@ module SiSU_CGI_sql "#@base?#{s1}#{key}#{ti}#{au}#{sj}#{dsc}#{pb}#{cntr}#{dt}#{ty}#{id}#{src}#{lang}#{rel}#{cov}#{cr}#{co}#{ab}#{dtc}#{dti}#{dtm}#{dta}#{dtv}#{fns}&db=#{cgi['db']}&view=#{cgi['view']}&a=1" else "#@base?#{s1}#{key}#{ti}#{au}#{sj}#{dsc}#{pb}#{cntr}#{dt}#{ty}#{id}#{src}#{lang}#{rel}#{cov}#{cr}#{co}#{ab}#{dtc}#{dti}#{dtm}#{dta}#{dtv}#{fns}&db=#{cgi['db']}&view=#{cgi['view']}&u=1&e=1" end - @search[:text][1]=%{documents.clean~'#{@search_for.text1}'} #s1 - @search[:endnotes][1]=%{endnotes.clean~'#{@search_for.text1}'} #s1 + if checked_case=~/\S/ + @search[:text][1]=%{documents.clean~'#{@search_for.text1}'} #s1 + @search[:endnotes][1]=%{endnotes.clean~'#{@search_for.text1}'} #s1 + else + @search[:text][1]=%{documents.clean~*'#{@search_for.text1}'} #s1 + @search[:endnotes][1]=%{endnotes.clean~*'#{@search_for.text1}'} #s1 + end canned_note='previous search url:' else @@canned_search_url="#@base?s1=United+Nations&db=documents&view=index" @@ -635,7 +716,7 @@ module SiSU_CGI_sql WOK #eg = %{canned search e.g.:
    #{url}
    find: #{analyze}
    database: #{database}} #dbi_canning - @header=Form.new(@base,search_field,selected_db,checked_index,checked_text,checked_tip,checked_searched,checked_url,checked_echo,checked_sql,checked_all,checked_none,checked_ignore,search_note,the_can).submission_form #% form + @header=Form.new(@base,search_field,selected_db,checked_index,checked_text,checked_tip,checked_searched,checked_url,checked_case,checked_echo,checked_sql,checked_all,checked_none,checked_ignore,search_note,the_can).submission_form #% form unless q['s1'] =~/\S/ or q['au'] =~/\S/ or @search[:text][1] =~/\S/ print "Content-type: text/html\n\n" puts (@header+@tail) @@ -644,10 +725,15 @@ module SiSU_CGI_sql @search_for.text1 else 'Unavailable' end - @search[:text]<<%{documents.clean~'#{CGI.unescape(s1)}'} - @search[:endnotes]<<%{endnotes.clean~'#{CGI.unescape(s1)}'} + if checked_case=~/\S/ + @search[:text]<<%{documents.clean~'#{CGI.unescape(s1)}'} + @search[:endnotes]<<%{endnotes.clean~'#{CGI.unescape(s1)}'} + else + @search[:text]<<%{documents.clean~*'#{CGI.unescape(s1)}'} + @search[:endnotes]<<%{endnotes.clean~*'#{CGI.unescape(s1)}'} + end #dbi_request - dbi_statement=Dbi_search_statement.new(@conn,@search_for,q) + dbi_statement=Dbi_search_statement.new(@conn,@search_for,q,checked_case) @text_search_flag=false @text_search_flag=dbi_statement.text_search_flag s_contents=dbi_statement.contents @@ -710,7 +796,7 @@ module SiSU_CGI_sql end matched_para=if (@search_regx.to_s.class==String && @search_regx.to_s=~/\S\S+/) matched=if c['body'] =~/\\1})) + else (c['body'].gsub(/(#@search_regx)/,%{\\1})) end matched else c['body'] diff --git a/lib/sisu/v0/cgi_sqlite.rb b/lib/sisu/v0/cgi_sqlite.rb index 1113403a..4565ebe2 100644 --- a/lib/sisu/v0/cgi_sqlite.rb +++ b/lib/sisu/v0/cgi_sqlite.rb @@ -92,7 +92,7 @@ module SiSU_CGI_sqlite f3 << " end\n" if FileTest.writable?('.') output=File.open('sisu_sqlite.cgi','w') - output << header0 << header1 << header_desc << header2 << f1 << buttons1 << buttons2 << search_request << search_statement << search_statement_common << search_query1 << @common.pages << search_query2 << @common.tail << @common.main1 << f2 << f3 << dbi_connect << @common.main2 + output << header0 << header1 << header_desc << header2 << f1 << buttons1 << buttons2 << buttons3 << search_request << search_statement << search_statement_common << search_query1 << @common.pages << search_query2 << @common.tail << @common.main1 << f2 << f3 << dbi_connect << @common.main2 a=%{ generated sisu_sqlite.cgi, BASED ON ALREADY CREATED sisu_sqlite.db OUTPUT, (-d) } @@ -134,12 +134,11 @@ module SiSU_CGI_sqlite def search_statement <<-'WOK_SQL' class Dbi_search_string - def initialize(l,t,q) + def initialize(l,t,q,cse=false) @l,@t,@q=l,t,q end def string - search={ :search => [] } - search[:flag]=false + search={ :search => [],:flag => false } if @t =~/\S+/ or @q =~/\S+/ if @t =~/\S+/; unescaped_search=CGI.unescape(@t) elsif @q =~/\S+/; unescaped_search=CGI.unescape(@q) @@ -176,7 +175,7 @@ module SiSU_CGI_sqlite def sql_select_body limit ||=@@limit offset ||=@@offset - @sql_statement[:body]=%{SELECT metadata.title, metadata.creator, metadata.filename, metadata.suffix, documents.body, documents.seg, documents.ocn, metadata.tid FROM documents, metadata WHERE #{@search_text} AND documents.metadata_tid = metadata.tid ORDER BY metadata.title, documents.ocn} + @sql_statement[:body]=%{SELECT metadata.title, metadata.creator, metadata.filename, metadata.suffix, documents.body, documents.seg, documents.ocn, metadata.tid FROM documents, metadata WHERE #{@search_text} AND documents.metadata_tid = metadata.tid ORDER BY metadata.title, metadata.filename, documents.ocn} @sql_statement[:range]=%{LIMIT #{limit} OFFSET #{offset} ;} select=@sql_statement[:body] + ' ' + @sql_statement[:range] select @@ -184,7 +183,7 @@ module SiSU_CGI_sqlite def sql_select_endnotes limit ||=@@limit offset ||=@@offset - @sql_statement[:endnotes]= %{SELECT metadata.title, metadata.creator, metadata.filename, endnotes.body, endnotes.nr, endnotes.ocn, endnotes.metadata_tid FROM metadata, endnotes WHERE #{@search_endnotes} AND metadata.tid = endnotes.metadata_tid ORDER BY metadata.title, endnotes.nr} + @sql_statement[:endnotes]= %{SELECT metadata.title, metadata.creator, metadata.filename, endnotes.body, endnotes.nr, endnotes.ocn, endnotes.metadata_tid FROM metadata, endnotes WHERE #{@search_endnotes} AND metadata.tid = endnotes.metadata_tid ORDER BY metadata.title, metadata.filename, endnotes.nr} @sql_statement[:range]=%{LIMIT #{limit} OFFSET #{offset} ;} select=@sql_statement[:endnotes] + ' ' + @sql_statement[:range] select diff --git a/lib/sisu/v0/docbook.rb b/lib/sisu/v0/docbook.rb deleted file mode 100644 index 6324cc28..00000000 --- a/lib/sisu/v0/docbook.rb +++ /dev/null @@ -1,567 +0,0 @@ -=begin - - * Name: SiSU - - * Description: a framework for document structuring, publishing and search - - * Author: Ralph Amissah - - * Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2007 Ralph Amissah All Rights Reserved. - - * License: GPL 3 or later: - - SiSU, a framework for document structuring, publishing and search - - Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2007 Ralph Amissah - - This program is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation, either version 3 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program. If not, see . - - If you have Internet connection, the latest version of the GPL should be - available at these locations: - - - - - * SiSU uses: - * Standard SiSU markup syntax, - * Standard SiSU meta-markup syntax, and the - * Standard SiSU object citation numbering and system - - * Hompages: - - - - * Download: - - - * Ralph Amissah - - - - ** Description: docbook, ... not developed - -=end -module SiSU_Docbook - require "#{SiSU_lib}/defaults" - require "#{SiSU_lib}/param" - include SiSU_Param - include SiSU_Viz - require "#{SiSU_lib}/sysenv" - include SiSU_Env - require "#{SiSU_lib}/dal" - require "#{SiSU_lib}/shared_xml" - require "#{SiSU_lib}/xml_format" - include SiSU_XML_format - include SiSU_XML_munge - require "#{SiSU_lib}/rexml" - include SiSU_Rexml - @@alt_id_count,@@tablehead,@@number_of_cols=0,0,0 - @@tablefoot='' - class Source - def initialize(opt) - @opt=opt - end - def read - begin - @md=SiSU_Param::Parameters.new(@opt).get - @env=SiSU_Env::Info_env.new(@opt.fns) - path=@env.path.output_tell - loc=@env.url.output_tell - tool=if @opt.cmd =~/[MV]/; "#{@env.program.web_browser} #{loc}/#{@md.fnb}/#{@md.fn[:docbook]}\n\t#{@env.program.xml_viewer} #{path}/#{@md.fnb}/#{@md.fn[:docbook]}" - elsif @opt.cmd =~/v/; "#{@env.program.web_browser} #{loc}/#{@md.fnb}/#{@md.fn[:docbook]}" - else '' - end - tell=SiSU_Screen::Ansi.new(@opt.cmd,'invert','XML DOM',tool) - tell.colorize unless @opt.cmd =~/q/ - tell=SiSU_Screen::Ansi.new(@opt.cmd,@opt.fns,"#{@env.path.output_tell}/#{@md.fnb}/#{@md.fn[:docbook]}") - tell.flow if @opt.cmd =~/[MV]/ - @dal_array=SiSU_DAL::Source.new(@opt).get # dal file drawn here - SiSU_Docbook::Source::Songsheet.new(@dal_array,@md,@env).songsheet - rescue; SiSU_Errors::Info_error.new($!,$@,@opt.cmd,@opt.fns).error - ensure #file closed in songsheet - end - end - private - class Songsheet - def initialize(data,md='',dir='') - @data,@md,@env=data,md,dir - end - def songsheet - begin - SiSU_Docbook::Source::Scroll.new(@data,@md).songsheet - SiSU_Docbook::Source::Tidy.new(@md,@env).xml if @md.cmd =~/[vVM]/i # test wellformedness, comment out when not in use - SiSU_Rexml::Rexml.new(@md,@md.fn[:docbook]).xml if @md.cmd =~/M/ # test rexml parsing, comment out when not in use #debug - rescue; SiSU_Errors::Info_error.new($!,$@,@md.cmd,@md.fns).error - ensure - end - end - end - class Scroll - Heading,Heading_close,Contents=[],[],[] - Heading[0]='part' - Heading[1]='part level="1"' - Heading[2]='part level="2"' - Heading[3]='part level="3"' - Heading_close[1]=Heading[0] - Heading_close[2]=Heading[0] - Heading_close[3]=Heading[0] - #Contents[0]='preface' - Contents[1]='chapter' - Contents[2]='sect1' - Contents[3]='sect2' - @@xml={ :body=>[],:open=>[],:close=>[],:head=>[],:sc=[] } - @@dp=nil - require "#{SiSU_lib}/shared_txt" - include SiSU_text_utils - def initialize(data='',md='') - @data,@md=data,md - @vz=SiSU_Env::Get_init.instance.skin - @dp=@@dp ||=SiSU_Env::Info_env.new.digest.pattern - @regx=/^(?:(?:<:p[bn]>\s*)?\d~(?:(\S+))?\s+)?(.+?)\s*<~(\d+);(?:\w|[0-6]:)\d+;\w\d+><#@dp:#@dp>$/ - @tab="\t" - @trans=SiSU_XML_munge::Trans.new(@md) - @sys=SiSU_Env::System_call.new - end - def songsheet - pre - markup - post - publish - end - protected - def xml_markup(para='') - para.gsub!(/~\{(\d+)\s+(.+?)\s*<#@dp>\}~/, - '\1 \2 ') - end - def xml_head(meta) - txt=meta.text - txt.gsub!(//,'') - txt.gsub!(/ & /,' and ') - @@xml[:head] <<=if meta.type == 'meta' - < -#{@tab*2}#{txt} -#{@tab} -WOK - else '' - end - end - def xml_sc(md='') - sc=if @md.sc_info - < - - #{@md.sc_filename} - - - #{@md.sc_number} - - - #{@md.sc_date} - - -WOK - else '' - end - @@xml[:sc]=sc - end - def xml_element(lv='',ocn='',para='',hname='',tag='',xml_element='') - lv=lv.to_i - n=lv - 1 - n1=lv - n2=lv + 1 - n3=lv + 2 - v=lv - 3 - tag='' - tag="\n#{@tab*n3}#{hname}\n" if hname - @@xml[:body] <<<#{para[@regx, 2]} -WOK - if lv == 4 - @copen[1]=true - @copen[2]=@copen[3]=false - elsif lv == 5 - @copen[2]=true - @copen[3]=false - elsif lv == 6 - @copen[3]=true - end - end - def xml_structure(lv='',ocn='',para='',hname='' ) - lv=lv.to_i - n=lv - 1 - n1=lv - n2=lv + 1 - n3=lv + 2 - v=lv - 3 - tag='' - tag="\n#{@tab*n3}#{hname}\n" if hname !=nil - #if para[@regx] - # paragraph="#{para[@regx, 2]}" - # util=SiSU_text_utils::Paragraph.new(paragraph, 70) - # wrapped=util.line_wrap - #end - case lv - when 1..3 - xml_element="<#{Heading[lv]}>" - 3.downto(lv) do |x| - y=x - 1 - @cont[1]=false if @cont[1] - @cont[2]=false if @cont[2] - @cont[3]=false if @cont[3] - ####### attempt to close contents - if @copen[3] # 6~ - [3,2,1].each do |v| - @@xml[:body] << "#{@tab*n}\n" - end - @copen[1]=@copen[2]=@copen[3]=false - elsif @copen[2] # 5~ - [2,1].each do |v| - @@xml[:body] << "#{@tab*n}\n" - end - @copen[1]=@copen[2]=@copen[3]=false - elsif @copen[1] # 4~ - [1].each do |v| - @@xml[:body] << "#{@tab*n}\n" - end - @copen[1]=@copen[2]=@copen[3]=false - end - @@xml[:body] << "#{@tab*y}\n" if @level[x] - @level[x]=false - end - when 4..6 - 6.downto(lv) do |x| - y=x - 1 - if @level[x] == true - u=x - 3; - @xml_contents_close[x]='' - end - end - cv=lv - 3 - if para =~/^4~\S+/ - m=/^4~(\S+)/.match(para)[1] - id=if m =~/^\d+$/; 'ch' + m - else 'ch_' + m - end - elsif para =~/^5~\S+/ - m=/^5~(\S+)/.match(para)[1] - id= 'sec_' + m - elsif para =~/^6~\S+/ - m=/^6~(\S+)/.match(para)[1] - id= 'subsec_' + m - else '' - end - xml_element=%{<#{Contents[cv]} id="#{id}">} #hmmm gsub were it possible - case lv - when 4 - if @copen[3] == true # 6~ - [3,2,1].each do |v| - @@xml[:body] << "#{@tab*n}\n" - end - elsif @copen[2] == true # 5~ - [2,1].each do |v| - @@xml[:body] << "#{@tab*n}\n" - end - elsif @copen[1] == true # 4~ - [1].each do |v| - @@xml[:body] << "#{@tab*n}\n" - end - end - @cont[1]=true - when 5 - if @copen[3] == true #6~ - [3,2].each do |v| - @@xml[:body] << "#{@tab*n}\n" - end - elsif @copen[2] == true #5~ - [2].each do |v| - @@xml[:body] << "#{@tab*n}\n" - end - end - @cont[2]=true - when 6 - [3].each do |v| - @@xml[:body] << "#{@tab*n}\n" if @copen[3] #watch should possibly be outside... - end - @cont[3]=true - end - end - xml_element(lv,ocn,para,hname,tag,xml_element) - @level[lv]=true - ((lv+1)..6).each { |x| @level[x]=false } - end - def group_structure(para='',ocn='') - para.gsub!(/<:group(?:-end)?>/,'') - para.strip! - @@xml[:body] << %{#{@tab*7}#{@tab*1}\n} - @@xml[:body] << %{#{@tab*8}#{para}#{@tab*1}\n} - @@xml[:body] << %{#{@tab*7}\n} - end - def poem_structure(para='',ocn='') - para.gsub!(/<:verse(?:-end)?>/,'') - para.strip! - @@xml[:body] << %{#{@tab*7}#{@tab*1}\n} - @@xml[:body] << %{#{@tab*8}#{para}#{@tab*1}\n} - @@xml[:body] << %{#{@tab*7}\n} - end - def code_structure(para='',ocn='') - para.gsub!(/<:code(?:-end)?>/,'') - para.strip! - @@xml[:body] << %{#{@tab*7}#{@tab*1}\n} - @@xml[:body] << %{#{@tab*8}#{para}#{@tab*1}\n} - @@xml[:body] << %{#{@tab*7}\n} - end - #def table_structure(table='',ocn='') #tables - # @@xml[:body] << %{#{@tab*1}#{table}\n#{@tab*1}\n} # unless lv # main text, contents, body KEEP #{ocn} - # @endnotes=[] - #end - def tidywords(wordlist) - wordlist.each do |x| - x.gsub!(/&/,'&') unless x =~/&\S+;/ - end - end - def markup - data=@data - dir=SiSU_Env::Info_env.new(@md.fns) - xml_sc(@md) - @rcdc=false - @level,@cont,@copen,@xml_contents_close=[],[],[],[] - (0..6).each { |x| @cont[x]=@level[x]=false } - (4..6).each { |x| @xml_contents_close[x]='' } - data.each do |para| - wordlist=para.scan(/\S+|\n/) #\n needed for tables, check though added 2005w17 - para=tidywords(wordlist).join(' ').strip - para.gsub!(/<[-~]#>/,'') - para.gsub!(/<0;\w\d+;[um]\d+><#@dp:#@dp>/,'') - para.gsub!(/<:pb>\s*/,'') - para.gsub!(/\{(\S+?\.(?:png|jpg|gif)) .+?\}(?:(?:https?|ftp):\/\/\S+|image)/, - %{}) - #para.gsub!(/\{(\S+?\.png) \d+x\d+ \".+?\" \}(?:http:\/\/\S+|image)/,'\1') - para.gsub!(/ /,' ') - @trans.char_enc.utf8(para) if @sys.locale =~/utf-?8/i #% utf8 - if para =~/^0~(\S+)\s+(.+?)\Z/m # for headers - d_meta=SiSU_text_utils::Header_scan.new(@md,para).meta - if d_meta; xml_head(d_meta) - end - end - @rcdc=true if @rcdc ==false and (para =~/^\d~metadata/ or para =~/^1~\s+Document Information/) - if para !~/(^0~||)/ - if para =~/.+?<~\d+;(?:\w|[0-6]:)\d+;\w\d+><#@dp:#@dp>$/ - paranum=para[@regx, 3] - @p_num=SiSU_XML_format::Paragraph_number.new(@md,paranum) - end - @sto=SiSU_text_parts::Split_text_object.new(@md,para).lev_segname_para_ocn - ### problem in scroll, it appears tables are getting paragraph numbers - unless @rcdc - m=/<~(\d+);(?:\w|[0-6]:)\d+;\w\d+><#@dp:#@dp>$/ - if para =~m - format_scroll=SiSU_XML_format::Format_scroll.new(@md,@sto.text) if @sto.format =~/i[12]|null/ - case @sto.format - when /^(1)~(?:(\S+))?/ - xml_markup(para) - xml_structure($1,@sto.ocn,para,$2) - para=@sto.lev_para_ocn.heading_body1 - when /^(2)~(?:(\S+))?/ - xml_markup(para) - xml_structure($1,@sto.ocn,para,$2) - para=@sto.lev_para_ocn.heading_body2 - when /^(3)~(?:(\S+))?/ - xml_markup(para) - xml_structure($1,@sto.ocn,para,$2) - para=@sto.lev_para_ocn.heading_body3 - when /^(4)~(\S+)/ # work on see SiSU_text_parts::Split_text_object - xml_markup(para) - xml_structure($1,@sto.ocn,para,$2) - para=@sto.lev_para_ocn.heading_body4 - when /^(5)~(?:(\S+))?/ - xml_markup(para) - xml_structure($1,@sto.ocn,para,$2) - para=@sto.lev_para_ocn.heading_body5 - when /^(6)~(?:(\S+))?/ - xml_markup(para) - xml_structure($1,@sto.ocn,para,$2) - para=@sto.lev_para_ocn.heading_body6 - #when /^(i1)$/ - # #format_scroll.gsubBody - # #para=@sto.lev_para_ocn.scrIndent1 - #when /^(i2)$/ - # format_scroll.gsubBody - # para=@sto.lev_para_ocn.scrIndent2 - #when /^(center)$/ - # para.gsub!(/(.+)/, - # %{
    (\\1)
    }) - # para=@sto.lev_para_ocn.scrPara - #when /^(b|bold)$/ - # para.gsub!(/(.+)/, - # %{(\\1)}) - # para=@sto.lev_para_ocn.scrPara - #when /null/ # see whether u can improve - # if (para !~/#{@margin.txt_0}|#{@margin.txt_1}|#{@margin.txt_2}/) - # #format_scroll.gsubBody - # #para=@sto.lev_para_ocn.scrPara - # end - else - matched=/<~(\d+);(?:\w|[0-6]:)\d+;\w\d+><#@dp:#@dp>$/mi.match(para) - stamp,ocn=matched[0],matched[1] - if para =~ /<:verse>/ - para.gsub!(/#{stamp}/,'') - poem_structure(para,ocn) - elsif para =~ /<:group>/ - para.gsub!(/#{stamp}/,'') - group_structure(para,ocn) - elsif para =~ /<:code>/ - para.gsub!(/#{stamp}/,'') - code_structure(para,ocn) - elsif para =~/#{para[@regx, 2]}\n" if para[@regx, 2] # main text, contents, body KEEP ocn = #{para[@regx, 3]} == #{ocn} - end - end - elsif para =~/(Note|Endnotes?)/ and para !~/<~\d+;(?:\w|[0-6]:)\d+;\w\d+><#@dp:#@dp>$/ - #format_scroll=MonoSiSU.new('
    Note') - #para=format_scroll.boldPara - elsif para =~/(MetaData)/ and para =~/<~\d+;[m]\d+;\w\d+><#@dp:#@dp>$/ #debug 2003w46 add rc info - format_scroll=Format_scroll.new(@md,'
    MetaData') - para=format_scroll.bold_para - elsif para =~/(Owner Details)/ and para !~/<~\d+;(?:\w|[0-6]:)\d+;\w\d+><#@dp:#@dp>$/ - format_scroll=Format_scroll.new(@md,'
    Owner Details') - @@xml[:owner_details]=format_scroll.bold_para - para='' - elsif para =~/(.*)<:#>(.*)/ - one, two=$1,$2 - format_text=Format_text_object.new(one,two) - para=format_text.seg_no_paranum - end - para='' if para =~// and para =~/^(-\{{2}~\d+|)/ # -endnote - if para =~/.*<:#>.*$/ - para=case para - when /<:i1>/ - format_text=Format_text_object.new(para,'') - format_text.scr_inden_ocn_e_no_paranum - when /<:i2>/ - format_text=Format_text_object.new(para,'') - format_text.scr_inden_ocn_e_no_paranum - end - end - if para =~/<:center>/ - one, two=/(.*)<:center>(.*)/.match(para)[1,2] - format_text=Format_text_object.new(one, two) - para=format_text.center - end - else - end - para.gsub!(/<:\S+?>/,'') - para.gsub!(//,' ') - end - end - @content_flag=true - 6.downto(4) do |x| - y=x - 1; v=x - 3 - if @level[x] == true #2004w36 bug fix? watch/test previous logic broke on free.for.all @coontent_flag introduced - if @content_flag==true - @@xml[:body] << "\n#{@tab*y}\n" - @content_flag=false - else - @@xml[:body] << "\n#{@tab*y}\n" - end - end - end - 3.downto(1) do |x| - y=x - 1 - @@xml[:body] << "#{@tab*y}\n" if @level[x] == true - end - end - def pre - rdf=SiSU_XML_tags::RDF.new(@md) - dir=SiSU_Env::Info_env.new - css=SiSU_Env::CSS_select.new(@md).docbook_xml - encoding=' -' - #encoding='' - @@xml[:open] =< -#{rdf.comment_xml} - -WOK - @@xml[:head] << "\n" - end - def post - @@xml[:head] << @@xml[:sc] - @@xml[:head] << "\n" - @@xml[:close] = "\n" - end - def publish - content=[] - data=@data - content << @@xml[:open] << @@xml[:head] << @@xml[:body] << @@xml[:metadata] - content << @@xml[:owner_details] if @md.stmp =~/\w\w/ - content << @@xml[:tail] << @@xml[:close] - Output.new(content.to_s,@md).xml - @@xml[:head],@@xml[:body],@@xml[:tail]=[],[],[] - end - end - class Output - include SiSU_Param - def initialize(data,md) - @data,@md=data,md - end - def xml - @sisu=[] - @data.each do |para| - para.gsub!(/<:\S+?>/,'') - para.gsub!(//,'') - para="#{para}\n" unless para.empty? - @sisu << para - end - new_file_data=@sisu.to_s - @sisu=new_file_data.scan(/.+/) - SiSU_Env::SiSU_file.new(@md).mkdir - filename_xml=SiSU_Env::SiSU_file.new(@md,@md.fn[:docbook]).mkfile - @sisu.each {|para| filename_xml.puts para} - filename_xml.close - end - end - class Tidy - def initialize(md,dir) - @md,@env=md,dir - @prog=SiSU_Env::Info_program.new - end - def xml - if @prog.tidy !=false - if @md.cmd =~/[VM]/ - tell=SiSU_Screen::Ansi.new(@md.cmd,'invert','Using XML Tidy','check document structure') - tell.colorize unless @md.cmd =~/q/ - tell.grey_open unless @md.cmd =~/q/ - tidyfile='/dev/null' #don't want one or screen output, check for alternative flags - tidy=SiSU_Env::System_call.new("#{@env.path.output}/#{@md.fnb}/#{@md.fn[:docbook]}",tidyfile) - tidy.well_formed? - tell.p_off unless @md.cmd =~/q/ - end - end - end - end - end -end -__END__ - diff --git a/lib/sisu/v0/help.rb b/lib/sisu/v0/help.rb index 23cccc04..9c10c27e 100644 --- a/lib/sisu/v0/help.rb +++ b/lib/sisu/v0/help.rb @@ -988,15 +988,22 @@ WOK help_env end def program_found?(program) - rc=if SiSU_Env::Info_settings.new.program?(program) - "rc: #{SiSU_Env::Info_settings.new.program?(program)} " - else '' + if program + rc=if SiSU_Env::Info_settings.new.program?(program) + SiSU_Env::Info_settings.new.program?(program) + else '' + end + if program =='rmagick'; program='identify' #rmagick is ruby lib uses imagemagick's identify + end + bin=if SiSU_Env::System_call.new.program_found?(program) + SiSU_Env::System_call.new.program_found?(program) + else 'false' + end + else bin,rc='false','false' end - bin=if SiSU_Env::System_call.new.program_found?(program) - "bin: #{SiSU_Env::System_call.new.program_found?(program)}" - else '' + if program; "#{@cX.blue}#{program}#{@cX.off} bin: #{@cX.brown}#{bin}#{@cX.off} rc: #{@cX.brown}#{rc}#{@cX.off}" + else "bin: #{@cX.brown}#{bin}#{@cX.off} rc: #{@cX.brown}#{rc}#{@cX.off}" end - "#{@cX.brown}#{rc}#{bin}#{@cX.off}" end def environment cf_defaults=SiSU_Env::Info_processing_flag.new @@ -1010,7 +1017,6 @@ WOK current directory: #{@cX.blue}#{@env.path.pwd}#{@cX.off} document output root directory set to: #{@cX.blue}#{@env.path.webserv}#{@cX.off} documents from current directory placed in: #{@cX.blue}#{@env.path.output}#{@cX.off} - sisurc.yml used: #{@cX.blue}#{@env.path.yamlrc}#{@cX.off} webrick url: #{@cX.blue}#{@env.url.webserv_base_cgi}#{@cX.off} (to start webrick server 'sisu -W') sqlite db for present directory: #{@cX.blue}sqlite #{@env.path.output}/sisu_sqlite.db#{@cX.off} @@ -1022,7 +1028,7 @@ WOK [generated postgresql cgi search form]: #{@cX.blue}#{@env.url.webserv_base_cgi}/cgi-bin/sisu_pgsql.cgi#{@cX.off} (to generate 'sisu -F' or 'sisu -F webrick') #{@cX.green}configuration files#{@cX.off} - sisurc.yml used: #{@cX.blue}#{@env.path.yamlrc}#{@cX.off} + sisurc.yml used: #{@cX.blue}#{@env.path.yamlrc}#{@cX.off} configuration information search path: #{@cX.blue}#{@env.path.rc.join(', ')}#{@cX.off} (directory also relevant for skins and images) digest (md5 or sha256): #{@cX.blue}#{@env.digest.type}#{@cX.off} @@ -1040,13 +1046,13 @@ WOK odf viewer: #{@cX.blue}#{@env.program.odf_viewer}#{@cX.off} (default selections can be changed in sisurc.yml under program_select:) #{@cX.green}programs used if available#{@cX.off} - word count: #{@cX.blue}#{@env.program.wc}#{@cX.off} #{program_found?(@env.program.wc)} - imagemagick/rmagick: #{program_found?('rmagick')} - tidy: #{@cX.blue}#{@env.program.tidy}#{@cX.off} #{program_found?(@env.program.tidy)} - rexml: #{@cX.blue}#{@env.program.rexml}#{@cX.off} #{program_found?(@env.program.rexml)} - latex to pdf: #{@cX.blue}#{@env.program.pdflatex}#{@cX.off} #{program_found?(@env.program.pdflatex)} - postgresql: #{@cX.blue}#{@env.program.postgresql}#{@cX.off} #{program_found?(@env.program.postgresql)} - sqlite: #{@cX.blue}#{@env.program.sqlite}#{@cX.off} #{program_found?(@env.program.sqlite)} + word count: #{program_found?(@env.program.wc)} + imagemagick/rmagick: #{program_found?(@env.program.rmagick)} + tidy: #{program_found?(@env.program.tidy)} + rexml: #{program_found?(@env.program.rexml)} + latex to pdf: #{program_found?(@env.program.pdflatex)} + postgresql: #{program_found?(@env.program.postgresql)} + sqlite: #{program_found?(@env.program.sqlite)} (these can be turned off if unavailable in sisurc.yaml under program_set:) #{@cX.green}processing shortcut defaults set to:#{@cX.off} color defaut set (on==true) #{@cX.blue}#{cf_defaults.color}#{@cX.off} @@ -1349,9 +1355,25 @@ WOK print < - ** Description: SiSU information Structuring Universe, processing + ** Description: SiSU information Structuring Universe, text structuring, + processing, publishing, search =end module SiSU @@ -145,12 +146,13 @@ module SiSU when /^sisupod_make$/; SiSU_Doc::Source.new(@opt).read # -S when /^source_kdissert$/; SiSU_Kdi_source::Source.new(@opt).read ## -S when /^digests$/; SiSU_Digest_view::Source.new(@opt).read # -N + when /^xml_scaffold$/; SiSU_XML_scaffold::Source.new(@opt).read # -T when /^plaintext$/; SiSU_Plaintext::Source.new(@opt).read # -a -A -e -E -f when /^wikispeak$/; SiSU_Wikispeak::Source.new(@opt).read # -g when /^odf$/; SiSU_ODF::Source.new(@opt).read # -o when /^texpdf$/; SiSU_TeX::Source.new(@opt).read # -p when /^texinfo$/; SiSU_TexInfo::Source.new(@opt).read # -I - when /^docbook$/; SiSU_Docbook::Source.new(@opt).read # -B + #when /^docbook$/; SiSU_Docbook::Source.new(@opt).read # -B when /^html$/; SiSU_HTML::Source.new(@opt).read # -h -H when /^xml$/; SiSU_XML_SAX::Source.new(@opt).read # -x when /^xml_dom$/; SiSU_XML_DOM::Source.new(@opt).read # -X @@ -290,7 +292,7 @@ p "here #{__FILE__} #{__LINE__}" if @opt =~/M/ flag=SiSU_Env::Info_processing_flag.new extra='' if @opt.cmd !~/[mn]/ - extra+=if @opt.cmd =~/[abBeghHhINoptwXxz]/ and @opt.cmd !~/[mn]/; 'm' #% add dal + extra+=if @opt.cmd =~/[abeghHhINoptTwXxz]/ and @opt.cmd !~/[mn]/; 'm' #% add dal elsif ((@opt.cmd =~/[Dd]/ or (@opt.mod.inspect =~/--(?:(?:sq)?lite|pg(?:sql)?)/)) \ and @opt.mod.inspect !~/(?:remove|(?:(?:re)?create(?:all)?|dropall|drop)$)/) \ and @opt.cmd !~/[mn]/ @@ -466,8 +468,8 @@ p "here #{__FILE__} #{__LINE__}" if @opt =~/M/ end if @opt.cmd =~/b/; op('xhtml','xhtml sax') #% -b xhtml sax type end - if @opt.cmd =~/B/; op('docbook','docbook xml') #% -B docbook xml - end + #if @opt.cmd =~/B/; op('docbook','docbook xml') #% -B docbook xml + #end if @opt.cmd =~/w/; op('concordance','Concordance') #% -w concordance end if @opt.cmd =~/t/ #% -t termsheet/standard form @@ -484,6 +486,8 @@ p "here #{__FILE__} #{__LINE__}" if @opt =~/M/ end Operations.new.counter end + if @opt.cmd =~/T/; op('xml_scaffold','XML scaffold') #% -T temporary tests + end if @opt.cmd =~/p/; op('texpdf','LaTeX pdf') #% -p latex/ texpdf end if @opt.cmd =~/I/; op('texinfo','TeX Info') #% -I texinfo (i taken by db import) diff --git a/lib/sisu/v0/sysenv.rb b/lib/sisu/v0/sysenv.rb index f1aa19fc..c2d694f2 100644 --- a/lib/sisu/v0/sysenv.rb +++ b/lib/sisu/v0/sysenv.rb @@ -92,7 +92,7 @@ module SiSU_Env out=Config::CONFIG['localstatedir'] etc=Config::CONFIG['sysconfdir'] + '/sisu' share=Config::CONFIG['datadir'] + '/sisu' - data=Config::CONFIG['datadir'] + '/sisu-examples/sample' + data=Config::CONFIG['datadir'] + '/doc/sisu' m=/.+\/(\S+)/m @stub_pwd ||=@@pwd[m,1] prcss_dir='_sisu_processing' @@ -506,7 +506,7 @@ module SiSU_Env def rcs #rcs for document markup data program='rcs' program_ref="\n\t\tdocument version information requested" - if program_found?(rcs); true + if program_found?(program); true else puts "\tWARN: #{program} is not installed #{program_ref}" #if @cmd =~/v/ false end @@ -514,7 +514,7 @@ module SiSU_Env def cvs #cvs for document markup data program='cvs' program_ref="\n\t\tdocument version information requested" - if program_found?(cvs); true + if program_found?(program); true else puts "\tWARN: #{program} is not installed #{program_ref}" #if @cmd =~/v/ false end @@ -574,6 +574,14 @@ module SiSU_Env else puts "\tWARN: #{program} is not installed #{program_ref}" if cmd =~/V/ end end + def rmagick #rmagick is a ruby library + program='identify' + program_ref="\n\t\tsee http://www.imagemagick.org/" + if program_found?(program); true + else puts "\tWARN: #{program} is not installed #{program_ref}" #if @cmd =~/v/ + false + end + end def well_formed? #tidy - check for well formed xml xhtml etc. program=@prog.tidy program_ref="\n\t\tsee http://tidy.sourceforge.net/" @@ -610,7 +618,7 @@ module SiSU_Env def makeinfo #texinfo program='makeinfo' program_ref="\n\t\tsee http://www.gnu.org/software/texinfo/" - if program_found?(program); system("makeinfo #@input\n") + if program_found?(program); system("#{program} #@input\n") else puts "\tWARN: #{program} is not installed #{program_ref}" end end @@ -1556,6 +1564,13 @@ module SiSU_Env end is end + def rmagick + if defined? @rc['program_set']['rmagick']; is=@rc['program_set']['rmagick'] + end + if is.nil? or is==true; is='rmagick' + end + is + end def rexml #should be part of ruby 1.8 but apparently not always is=if FileTest.directory?("#{Config::CONFIG['rubylibdir']}/rexml") #Config::CONFIG['sitedir'] true diff --git a/lib/sisu/v0/texinfo.rb b/lib/sisu/v0/texinfo.rb index 29f31421..88f91d7d 100644 --- a/lib/sisu/v0/texinfo.rb +++ b/lib/sisu/v0/texinfo.rb @@ -87,7 +87,7 @@ module SiSU_TexInfo when /\.[_-]?sst$/ Dir.mkdir(@env.path.output) unless FileTest.directory?("#{@env.path.output}") Dir.mkdir(@env.path.texi) unless FileTest.directory?(@env.path.tex) - @@filename_texinfo=File.new(%{#{@env.path.texi}/#@opt.fnb.texinfo},'w+') + @@filename_texinfo=File.new(%{#{@env.path.texi}/#{@opt.fnb}.texinfo},'w+') end rescue; STDERR.puts SiSU_Screen::Ansi.new(@opt.cmd,$!,$@).rescue ensure @@ -158,13 +158,13 @@ module SiSU_TexInfo @tex_file=[] data=@data data.each do |para| - para.gsub!(/&/,'<=and>') # DEBUG 2003w16 this is a kludge, because i could not get parameters # from param, Sort out ... revert to more elegant solution if para =~ //,'') + para.gsub!(/(^|\s)\{(.+?)\}(http:\/\/\S+)/,'\1(\2 [linked to:] \3)') do_mono=TexInfoFormat::Texinfo.new(para,@md) @tex_file << do_mono.spec_char end @@ -176,8 +176,10 @@ module SiSU_TexInfo @tex_file=[] data.each do |para| # BUG bug -> have problems with endnotes in headers - if para =~ /\\~\\\{\d+\s+/ #if para =~ /\\\}\\~/m,' @footnote{ \2} ') + if para =~ /\\~@\{\d+\s+/ #if para =~ /@\}\\~/m,' @footnote{ \1} ') + elsif para =~ /\\~@\{\*+\s+/ #if para =~ /@\}\\~/m,' @footnote{ \1} ') end @tex_file << para end @@ -226,7 +228,7 @@ module SiSU_TexInfo if @@flag['code']==1 line.gsub!(/^\s*(.+)/m, "\\noindent \\marginpar\[left-text\]{\\begin{tiny}#{@@counting}\\end{tiny}}\\1\\") @@counting+=1 if @@flag['code']==1 - else line.gsub!(/(.+)/m,'\noindent\1\') + else line.gsub!(/(.+)/m,'\noindent\1') end end end @@ -258,7 +260,7 @@ module SiSU_TexInfo toc=TexInfoFormat::Texinfo.new($1,@md) texinfo_menu << toc.menu end - if para =~ /^[4-6]\\+~\S+\s*(.+?)\s*$/ + if para =~ /^[4-6]\\+~(?:\S+)?\s+(.+?)\s*$/ toc=TexInfoFormat::Texinfo.new($1,@md) texinfo_menu << toc.menu case para @@ -270,6 +272,8 @@ module SiSU_TexInfo @subsubmenu[n_menu]=[] @submenu[n_menu] << toc.menu when /^[6]\\+~\S+\s+(.+?)\s*$/ + n_submenu+=1 + @subsubmenu[n_submenu]=[] @subsubmenu[n_submenu] << toc.menu end end @@ -279,7 +283,7 @@ module SiSU_TexInfo @tex_file << texinfo_menu @tex_file << "* Index::\n" + "@end menu\n\n" + - "@c {{{ 5\n\n" + "@c %% 5\n\n" n_menu,n_submenu=0,0 @@do_submenu,@@do_subsubmenu=1,1 data.each do |para| @@ -325,14 +329,13 @@ module SiSU_TexInfo if para !~/\S/ para=nil else - para.gsub!(/<\\~(\d+);\w\d+;\w\d+><#@dp:#@dp>/,'~[\1]') - #para.gsub!(/[1-3]\\\\\{\\\\\{\\\\\{\s+/, '') - #para.gsub!(/[1-3]\\\\\{\s+/, '') + para.gsub!(/<\\~(\d+);(?:\w|[0-6]:)\d+;\w\d+><#@dp:#@dp>$/,'<\1>') + #para.gsub!(/<\\~(\d+);\w\d+;\w\d+><#@dp:#@dp>/,'<\1>') + #para.gsub!(/<\\~(\d+);\w\d+;\w\d+><#@dp:#@dp>/,'<\1>') para=para end - #para.gsub!(/^\s+$/mi, "") end -#%case with endnotes + #%case with endnotes para.gsub!(/\s*[0-8]\\+(\S+)?\s+/,' ') if para @tex_file << para if para end @@ -397,7 +400,7 @@ module SiSU_TexInfo end def makeinfo if @md.fns =~/\.[_-]?sst$/ - m=/(.+?)\.[_-]?sst$/.match(@md.fns) + m=/(.+?)\.([_-]?sst)$/.match(@md.fns) fnb,sfx=m[1],m[2] pwd=Dir.pwd case sfx diff --git a/lib/sisu/v0/texinfo_format.rb b/lib/sisu/v0/texinfo_format.rb index bb60895d..3184ee80 100644 --- a/lib/sisu/v0/texinfo_format.rb +++ b/lib/sisu/v0/texinfo_format.rb @@ -90,6 +90,8 @@ module TexInfoFormat author=@md.dc_creator if @md.dc_creator author ||='' author.gsub!(/[\*]/,'') #if author + v=SiSU_Env::Info_version.new.get_version + #(version @value{VERSION} #{v[:version]}, @value{UPDATED} #{v[:date]}) head =<|<\/\s*(br|p|i)>|<(br|p)\s*\/>/," #{@@tex_backslash*2} ") @one.gsub!(/\$/,"\\$") @one.gsub!(/[,]\s*/,' - ') - "@c {{{ 4\n" + + "@c %% 4\n" + "@ifnottex\n" + "@node Top\n" + "@top #@one\n\n" + @@ -201,7 +202,7 @@ WOK dc_coverage="Coverage: #{dc_coverage}\n\n" if dc_coverage dc_rights="Rights: #{dc_rights}\n\n" if dc_rights "@node Dublin Core\n" + - "@chapter Dublin Core\n" + + "@unnumbered Dublin Core\n" + "@cindex chapter, Dublin Core\n\n" + "#{dc_title}" + "#{dc_creator}" + @@ -225,91 +226,80 @@ WOK "\n\n" end def tail - "@c {{{ 6\n" + + "@c %% 6\n" + "@node Index\n" + "@unnumbered Index\n" + "@printindex cp\n\n" + "@bye" end + def clean(para) + para.gsub!(/<\\~(\d+);(?:\w|[0-6]:)\d+;\w\d+><#@dp:#@dp>$/,'<\1>') + para.gsub!(/\s*[,:]\s*/,' - ') + para.gsub!(/<:#>/,'') + para.strip! + para + end def menu - @para.gsub!(/<\\~(\d+);\w\d+;\w\d+><#@dp:#@dp>$/,'~[\1]') - @para.gsub!(/\s*[,:]\s*/,' - ') - @para.gsub!(/<:#>/,'') - @para.strip! - "* #@para::" + para=clean(@para) + para=para.gsub(/@footnote\{.+?\}\s+/,'') + "* #{para}::" end def level1 @para.gsub!(/[1]\\+~/,'') - @para.gsub!(/<\\~(\d+);\w\d+;\w\d+><#@dp:#@dp>$/,'~[\1]') - @para.gsub!(/\s*[,:]\s*/,' - ') - @para.gsub!(/<:#>/,'') - @para.strip! - para="@node #@para\n@chapter #@para\n@cindex chapter, #@para\n" + para=clean(@para) + nd=para.gsub(/@footnote\{.+?\}\s+/,'') + para="@node #{nd}\n@unnumbered #{para}\n@cindex chapter, #{nd}\n" @para.gsub!(/.+/,"#{para}") end def level2 @para.gsub!(/[2]\\+~/,'') - @para.gsub!(/<\\~(\d+);\w\d+;\w\d+><#@dp:#@dp>$/,'~[\1]') - @para.gsub!(/\s*[,:]\s*/,' - ') - @para.gsub!(/<:#>/,'') - @para.strip! - para="@node #@para\n@chapter #@para\n@cindex chapter, #@para\n" + para=clean(@para) + nd=para.gsub(/@footnote\{.+?\}\s+/,'') + para="@node #{nd}\n@unnumbered #{para}\n@cindex chapter, #{nd}\n" @para.gsub!(/.+/,"#{para}") end def level3 @para.gsub!(/[3]\\+\~/,'') - @para.gsub!(/<\\~(\d+);\w\d+;\w\d+><#@dp:#@dp>$/,'~[\1]') - @para.gsub!(/\s*[,:]\s*/,' - ') - @para.gsub!(/<:#>/,'') - @para.strip! - para="@node #@para\n@chapter #@para\n@cindex chapter, #@para\n" + para=clean(@para) + nd=para.gsub(/@footnote\{.+?\}\s+/,'') + #para=para.gsub(/(.+?)\s*(@footnote\{.+?\})\s*(.+)$/,"\\1 \\3\n\\2") + #para=para.gsub(/(.+?)\s*(@footnote\{.+?\})\s*(.+)$/,'\1 \3 \2') + para="@node #{nd}\n@unnumbered #{para}\n@cindex chapter, #{nd}\n" @para.gsub!(/.+/,"#{para}") end def level4 @para.gsub!(/[4]\\+~\S+/,'') - @para.gsub!(/<\\~(\d+);\w\d+;\w\d+><#@dp:#@dp>$/,'~[\1]') - @para.gsub!(/\s*[,:]\s*/,' - ') - @para.gsub!(/<:#>/,'') - @para.strip! - para="@node #@para\n@chapter #@para\n@cindex chapter, #@para\n" + para=clean(@para) + nd=para.gsub(/@footnote\{.+?\}\s+/,'') + para="@node #{nd}\n@unnumbered #{para}\n@cindex chapter, #{nd}\n" @para.gsub!(/.+/,"#{para}") end def level5 @para.gsub!(/[5]\\+~\S+/,'') - @para.gsub!(/<\\~(\d+);\w\d+;\w\d+><#@dp:#@dp>$/,'~[\1]') - @para.gsub!(/\s*[,:]\s*/,' - ') - @para.gsub!(/<:#>/,'') - @para.strip! - para="@node #@para\n@chapter #@para\n@cindex chapter, #@para\n" + para=clean(@para) + nd=para.gsub(/@footnote\{.+?\}\s+/,'') + para="@node #{nd}\n@unnumbered #{para}\n@cindex chapter, #{nd}\n" @para.gsub!(/.+/,"#{para}") end def level6 @para.gsub!(/[6]\\+~\S+/,'') - @para.gsub!(/<\\~(\d+);\w\d+;\w\d+><#@dp:#@dp>$/,'~[\1]') - @para.gsub!(/\s*[,:]\s*/,' - ') - @para.gsub!(/<:#>/,'') - @para.strip! - para="@node #@para\n@chapter #@para\n@cindex chapter, #@para\n" + para=clean(@para) + nd=para.gsub(/@footnote\{.+?\}\s+/,'') + para="@node #{nd}\n@unnumbered #{para}\n@cindex chapter, #{nd}\n" @para.gsub!(/.+/,"#{para}") end def submenu @para=@para.join("\n") @para.gsub!(/[5]\\+~\S+/,'') - @para.gsub!(/<\\~(\d+);\w\d+;\w\d+><#@dp:#@dp>$/,'~[\1]') - @para.gsub!(/\s*[,]\s*/,' - ') - @para.gsub!(/<:#>/,'') - @para.strip! - para="@menu\n#@para\n@end menu\n\n" + para=clean(@para) + para="@menu\n#{para}\n@end menu\n\n" @para.gsub!(/.+/m,"#{para}") end def subsubmenu @para=@para.join("\n") @para.gsub!(/[6]\\+~\S+/,'') - @para.gsub!(/<\\~(\d+);\w\d+;\w\d+><#@dp:#@dp>$/,'~[\1]') - @para.gsub!(/\s*[,]\s*/,' - ') - @para.gsub!(/<:#>/,'') - @para.strip! - para="@menu\n#@para\n@menu\n\n" + para=clean(@para) + para="@menu\n#{para}\n@end menu\n\n" @para.gsub!(/.+/m,"#{para}") end def indent1 @@ -320,12 +310,15 @@ WOK end def spec_char # special characters @para.gsub!(//i,'') - @para.gsub!(/@/i,'@@') - @para.gsub!(/&(lt|#060);/,'\< ') - @para.gsub!(/&(gt|#062);/,' \>') - @para.gsub!(/{/,'\{ ') - @para.gsub!(/}/,'\} ') - @para.gsub!(/&#(126|152);/i,'~ ') + @para.gsub!(/©/,'(c)') + @para.gsub!(/&(lt|#060);/,'<'); @para.gsub!(/&(gt|#062);/,'>') + @para.gsub!(/{/,'{'); @para.gsub!(/}/,'}') + @para.gsub!(/&#(126|152);/i,'~') + @para.gsub!(/!/,'!') + @para.gsub!(/#/,'#') + @para.gsub!(/*/,'*') + @para.gsub!(///,'/') + @para.gsub!(/_/,'_') @para.gsub!(/&atild;<\/font><\/sup>/,' ') @para.gsub!(/\\/,'\\backslash ') @para.gsub!(/<:pb>/,'\\newpage') @@ -337,13 +330,6 @@ WOK if @para !~ /^\s*<:image|\}:image\s/ @para.gsub!(/_/,'\_') end - @para.gsub!(/\{/,"\\{") - @para.gsub!(/\}/,"\\}") - @para.gsub!(/  /,' ') # ~ character for hardspace - @para.gsub!(/ /,' ') # ~ character for hardspace - @para.gsub!(/&(\S+?);/,'') - @para.gsub!(/(\s+&\s+)/,' and ') - @para.gsub!(/(\&)/,"\\&") @para.gsub!(/§/i,'\S') @para.gsub!(/£/i,'\pounds') @para.gsub!(/Ã¥/i,'\aa') @@ -352,7 +338,6 @@ WOK @para.gsub!(/Ã…/i,'\AA') @para.gsub!(/Æ/i,'\AE') @para.gsub!(/Ø/i,'\O') - @para.gsub!(/&(.+?);/i,' ') @para.gsub!(//i,' ') @para.gsub!(/<\/a>/i,' ') @para.gsub!(/<:ee>/i,'') @@ -360,6 +345,15 @@ WOK @para.gsub!(/(.+?)<\/b>/,'\*\1\*') @para.gsub!(/(.+?)<\/i>/,'\/\1\/') @para.gsub!(/(.+?)<\/u>/,'\_\1\_') + @para.gsub!(/@/i,'@@') + @para.gsub!(/\{/,'@{'); @para.gsub!(/\}/,'@}') + #@para.gsub!(/(^|[\s*!\/#_-])\{/,'\1@{'); @para.gsub!(/\}([\s*!\/#_-]|$)/,'@}\1') + @para.gsub!(/  /,' ') # ~ character for hardspace + @para.gsub!(/ /,' ') # ~ character for hardspace + @para.gsub!(/&(\S+?);/,' ') + @para.gsub!(/&/,'<=and>') + @para.gsub!(/(\s+&\s+)/,' and ') + @para.gsub!(/(\&)/,"\\&") @para.gsub!(/"(.+?)"/,"`\\1'") # open & close " @para.gsub!(/\s+"/," `") # open " @para.gsub!(/^([1-6-]\\+(?:~\S+)?|<.+?>)?\s*"/,'\1`') # open " @@ -368,11 +362,6 @@ WOK @para.gsub!(/"(\.|,)/,"'") # close " @para.gsub!(/\s+'/," `") # open ' @para.gsub!(/^([1-6-]\\+(?:~\S+)?|<.+?>)?\s*'/,'\1`') # open ' - #if @para=~/#{@@tex_1}/ - #end - #@para.gsub!(/^([1-6-](?:#{@@tex_2}|#{@@tex_1})(?:\\~\S+)?|<.+?>)?\s*"/i,"\\1`") # open " - #@para.gsub!(/"([1-6-](?:#{@@tex_2}|#{@@tex_1})(?:\\~\S+)?|<.+?>)?\s*$/i,"'\\1") # close " - #@para.gsub!(/^([1-6-](?:#{@@tex_2}|#{@@tex_1})(?:\\~\S+)?|<.+?>)?\s*'/i,"\\1`") # open ' @para.gsub!(/(|<\/font>)/,'') @para.gsub!(/\s*(\S+?)<\/sup>/,'^\1') @para.gsub!(/(|<\/sup>)/,'') diff --git a/lib/sisu/v0/urls.rb b/lib/sisu/v0/urls.rb index a18cdc2f..09b15f2d 100644 --- a/lib/sisu/v0/urls.rb +++ b/lib/sisu/v0/urls.rb @@ -103,7 +103,7 @@ module SiSU_urls 'a (Plain-text (footnotes))'=>@fn[:plain], 'A (Plain-text (footnotes) dos)'=>@fn[:plain], 'b (XHTML)'=>@fn[:xhtml], - 'B (Docbook XML)'=>@fn[:docbook], + #'B (Docbook XML)'=>@fn[:docbook], 'D[iu] (DBI import/update postgresql)'=>'dbi psql', 'd[iu] (DBI import/update sqlite)'=>'dbi sqlite', 'e (Plain-text (endnotes))'=>@fn[:plain], @@ -137,7 +137,7 @@ module SiSU_urls end end def urls_maintenance(opt,x,y) - if x=~/^([aAbBceEhHmNopwxXy])/ and opt.cmd =~/[aAbBceEhHmNopwxXy]/ and x=~/^[#{opt.cmd}]/ + if x=~/^([aAbceEhHmNopwxXy])/ and opt.cmd =~/[aAbceEhHmNopwxXy]/ and x=~/^[#{opt.cmd}]/ m=$1 f=y tool=@editor @@ -180,7 +180,7 @@ module SiSU_urls @pwd_stub="#@webserv_url"[m,1] @u.each do |x,y| if @opt.fns =~ @m_regular - if x=~/^([aAbBceEhHNopsSwxXyY])/ and @opt.cmd=~/[aAbBceEhHNopsSwxXyY]/ and x=~/^[#{@opt.cmd}]/ + if x=~/^([aAbceEhHNopsSwxXyY])/ and @opt.cmd=~/[aAbceEhHNopsSwxXyY]/ and x=~/^[#{@opt.cmd}]/ m=$1 tell=SiSU_Screen::Ansi.new(@opt.cmd,"-#{x}","#@browser #@webserv_url/#@fnb/#{y}") tell.result unless @opt.cmd =~/q/ diff --git a/lib/sisu/v0/xml_scaffold.rb b/lib/sisu/v0/xml_scaffold.rb new file mode 100644 index 00000000..93987840 --- /dev/null +++ b/lib/sisu/v0/xml_scaffold.rb @@ -0,0 +1,203 @@ +=begin + + * Name: SiSU + + * Description: extract and print an XML rendition of document structure to screen + + * Author: Ralph Amissah + + * Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, + 2007 Ralph Amissah All Rights Reserved. + + * License: GPL 3 or later: + + SiSU, a framework for document structuring, publishing and search + + Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, + 2007 Ralph Amissah + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program. If not, see . + + If you have Internet connection, the latest version of the GPL should be + available at these locations: + + + + + * SiSU uses: + * Standard SiSU markup syntax, + * Standard SiSU meta-markup syntax, and the + * Standard SiSU object citation numbering and system + + * Hompages: + + + + * Download: + + + * Ralph Amissah + + + + ** Description: SiSU information Structuring Universe, processing + +=end +module SiSU_XML_scaffold + require "#{SiSU_lib}/dal" + require "#{SiSU_lib}/sysenv" + include SiSU_Env + include SiSU_Param + pwd=Dir.pwd + class Source + def initialize(opt) + @opt=opt + @sp=' ' + end + def read + begin + @md=SiSU_Param::Parameters.new(@opt).get + @dal_array=SiSU_DAL::Source.new(@opt).get # dal file drawn here + SiSU_XML_scaffold::Source::Scroll.new(@dal_array,@md).songsheet + rescue; SiSU_Errors::Info_error.new($!,$@,@opt.cmd,@opt.fns).error + ensure + end + end + private + class Scroll \n\n" + ds.each {|x| puts "#{x[:ocn]} #{x[:lev]} #{x[:hdr]}" } + end + def structure_simple(ds) + puts "\nheading outline --->\n\n" + ds.each_with_index do |x,i| + #puts "#{x[:ocn]} #{x[:lev]} #{x[:hdr]}" + if x[:lev] =~ /^([1-6])/; puts "<#{@s[$1.to_i]}>#{x[:ocn]} #{x[:lev]} #{x[:hdr]}" + end + end + end + def structure_build_tag_close(lev,h) + @sp=' ' + case h[0] + when 1 + puts "#{@sp*1}" if (lev <= 1) and h[1] + puts "" if (lev == 0) + when 2 + puts "#{@sp*2}" if (lev <= 2) and h[2] + puts "#{@sp*1}" if (lev <= 1) and h[1] + puts "" if (lev == 0) + when 3 + puts "#{@sp*3}" if (lev <= 3) and h[3] + puts "#{@sp*2}" if (lev <= 2) and h[2] + puts "#{@sp*1}" if (lev <= 1) and h[1] + puts "" if (lev == 0) + when 4 + puts "#{@sp*4}" if (lev <= 4) + puts "#{@sp*3}" if (lev <= 3) and h[3] + puts "#{@sp*2}" if (lev <= 2) and h[2] + puts "#{@sp*1}" if (lev <= 1) and h[1] + puts "" if (lev == 0) + when 5 + puts "#{@sp*5}" if (lev <= 5) + puts "#{@sp*4}" if (lev <= 4) + puts "#{@sp*3}" if (lev <= 3) and h[3] + puts "#{@sp*2}" if (lev <= 2) and h[2] + puts "#{@sp*1}" if (lev <= 1) and h[1] + puts "" if (lev == 0) + when 6 + puts "#{@sp*6}" if (lev <= 6) + puts "#{@sp*5}" if (lev <= 5) + puts "#{@sp*4}" if (lev <= 4) + puts "#{@sp*3}" if (lev <= 3) and h[3] + puts "#{@sp*2}" if (lev <= 2) and h[2] + puts "#{@sp*1}" if (lev <= 1) and h[1] + puts "" if (lev == 0) + end + end + def structure_build(ds) + puts "\nXML [#@t type] structure outline --->\n\n" + @h=[0,false,false,false] + puts "<#{@s[0]}>" + ds.each_with_index do |x,i| + case x[:lev] + when /^1/ + structure_build_tag_close(x[:lev].to_i,@h) + puts "#{@sp*1}<#{@s[1]}>\n#{@sp*1} #{x[:ocn]} #{x[:lev]} #{x[:hdr]}" + @h=[1,true,false,false] + when /^2/ + structure_build_tag_close(x[:lev].to_i,@h) + puts "#{@sp*2}<#{@s[2]}>\n#{@sp*2} #{x[:ocn]} #{x[:lev]} #{x[:hdr]}" + @h=[2,true,true,false] + when /^3/ + structure_build_tag_close(x[:lev].to_i,@h) + puts "#{@sp*3}<#{@s[3]}>\n#{@sp*3} #{x[:ocn]} #{x[:lev]} #{x[:hdr]}" + @h=[3,true,true,true] + when /^4/ + structure_build_tag_close(x[:lev].to_i,@h) + puts "#{@sp*4}<#{@s[4]}>\n#{@sp*4} #{x[:ocn]} #{x[:lev]} #{x[:hdr]}" + @h[0]=4 + when /^5/ + structure_build_tag_close(x[:lev].to_i,@h) + puts "#{@sp*5}<#{@s[5]}>\n#{@sp*5} #{x[:ocn]} #{x[:lev]} #{x[:hdr]}" + @h[0]=5 + when /^6/ + structure_build_tag_close(x[:lev].to_i,@h) + puts "#{@sp*6}<#{@s[6]}>\n#{@sp*6} #{x[:ocn]} #{x[:lev]} #{x[:hdr]}" + @h[0]=6 + end + end + structure_build_tag_close(0,@h) + end + def structure + data=@data + @ds=[] + c=0 + data.each do |para| + if para =~/<~\d+;(?:\w|[0-6]:)\d+;\w\d+>/ + x=(/<~(\d+);((?:\w|[0-6]:)\d+);(\w\d+)>/).match(para) + if x[3] =~/^[hu]\d+/ + @ds[c]={} + @ds[c][:ocn]=x[1] + @ds[c][:lev]=x[2] + @ds[c][:hdr]=x[3] + c+=1 + #puts "#{x[1]} #{x[2]} #{x[3]}" + end + end + end + structure_outline(@ds) if @md.cmd =~/V/ + structure_simple(@ds) if @md.cmd =~/V/ + structure_build(@ds) + @ds + end + end + end +end +__END__ diff --git a/man/man1/sisu.1 b/man/man1/sisu.1 index ce47abce..7af13c9d 100644 --- a/man/man1/sisu.1 +++ b/man/man1/sisu.1 @@ -9,14 +9,14 @@ .\" /[^\\][-'] .\" :%s/\([^\\]\)\([-']\)/\1\\\2/c .\" |sisu.1|@|^| -.TH "sisu" "1" "June 29, 2007" "version 0.54" "USER COMMANDS and basic Markup" +.TH "sisu" "1" "July 7, 2007" "version 0.55" "USER COMMANDS and basic Markup" .SH "NAME" .B SiSU \- Structured information, Serialized Units \- a document publishing system .SH "SYNOPSIS" .B sisu .B [ -.I \-AabcDdEeFHhIMmNnopqrRSstUuVvwXxYyZz0\-9 +.I \-AabcDdEeFHhIMmNnopqRrSsTtUuVvwXxYyZz0\-9 .B ] [ .I filename/ wildcard .B ] @@ -186,7 +186,9 @@ html, with internal document links that include the document suffix, i.e. whethe .BI \-I \ [filename/wildcard] produces .I texinfo -file. +and +.I info +file, (view with pinfo). .TP .BI \-L prints license information. diff --git a/man/man8/sisu.8 b/man/man8/sisu.8 index 005759fa..e3e676ae 100644 --- a/man/man8/sisu.8 +++ b/man/man8/sisu.8 @@ -22,16 +22,16 @@ A document publishing system, that from a simple single marked\-up document, produces a multitude of output formats including: html, latex, pdf, info, and sql output, which can be cross referenced as having the same document structure and text object numbering, "object citation numbering". Features include its\' -simple syntax; the semantic identification of documents using the Dublin Core; -document management; built to be associated with a revision control system; -text object numbering for the identification of a texts location in any of the -output formats, easy skinning on a site wide, or per document basis, ... for -more see +simple syntax; the semantic tagging of documents; document management; built to +be associated with a revision control system; text object numbering for the +identification of a texts location in any of the output formats, easy skinning +on a site wide, or per document basis; granular search; a degree of future +proofing ... for more see .I man 1 sisu or .I .PP -.B SiSU is an alternative way of publishing and managing documents. +.B SiSU is a way of preparing, publishing, managing and searching documents. .\"%% Installation .SH INSTALLATION .PP @@ -46,15 +46,8 @@ how to install SiSU. .PP Sample marked up documents are are available at .I /usr/share/doc/sisu/sisu_markup_samples/dfsg -or equivalent directory, or online at -.I -or for viewing in html with syntax highlighting from -.I -.PP -A syntax table is provided at -.I /usr/share/doc/sisu/on_markup.txt -or equivalent, and online at -.I +or equivalent directory, or online, see +.I .PP .I man 1 sisu has a syntax table along with processing commands. @@ -75,22 +68,40 @@ The rest of this note is on post installation setup .\"%% Post Installation Setup .SH Post Installation Setup \- Quick start .PP -After installation of sisu-complete, move to the document samples directory + +After installation of sisu\-complete, move to the document samples directory, .PP cd /usr/share/doc/sisu/sisu_markup_samples/dfsg .PP -and run +[this is not where you would normally work but provides sample documents for +testing, you may prefer instead to copy the contents of that directory to a local +directory before proceeding] +.PP +and in that directory, initialise the output directory with the command .PP - sisu \-1 free_as_in_freedom.rms_and_free_software.sam_williams.sst +.I sisu \-CC +.PP +then run: +.PP +.I sisu \-1 free_as_in_freedom.rms_and_free_software.sam_williams.sst .PP or the same: .PP - sisu \-NhwpoabxXyv free_as_in_freedom.rms_and_free_software.sam_williams.sst +.I sisu \-NhwpoabxXyv free_as_in_freedom.rms_and_free_software.sam_williams.sst .PP look at output results, see the "sisu_manifest" page created for the document .PP -To generate an online document move to a writable directory, (create a work -directory and cd into it) as the file will be downloaded there and e.g. +for an overview of your current sisu setup, type: +.PP +.I sisu \-\-help env +.PP +or +.PP +.I sisu \-V +.PP +To generate a document from a remote url accessible location move to a +writable directory, (create a work directory and cd into it) as the file will +be downloaded there and e.g. .PP .I sisu \-1 http://www.jus.uio.no/sisu/gpl3.fsf/gpl3.fsf.sst .PP @@ -103,11 +114,15 @@ gvim free_as_in_freedom.rms_and_free_software.sam_williams.sst additional markup samples in .I .PP -it should also be possible to run sisu against sisupods (prepared zip files, created by running the command sisu -S [filename]), whether stored locally or remotely. +it should also be possible to run sisu against sisupods (prepared zip files, +created by running the command sisu \-S [filename]), whether stored locally or +remotely. .PP .I sisu \-3 http://www.jus.uio.no/sisu/free_culture.lawrence_lessig/sisupod.zip .PP -there is a security issue associated with the running of document skins that are not your own, so these are turned of by default, and the use of the following command, which switches on the associated skin is not recommended: +there is a security issue associated with the running of document skins that +are not your own, so these are turned of by default, and the use of the +following command, which switches on the associated skin is not recommended: .PP .I sisu \-3 \-\-trust http://www.jus.uio.no/sisu/free_culture.lawrence_lessig/sisupod.zip .PP @@ -174,43 +189,83 @@ SiSU): .PP Package: sisu .PP -Depends: ruby (>= 1.8.4), libwebrick-ruby +Depends: ruby (>= 1.8.2), libwebrick\-ruby, unzip, zip .PP -Recommends: sisu-pdf, sisu-sqlite, sisu-postgresql, librmagick-ruby, trang, - tidy, librexml-ruby, zip, unzip, openssl, rsync, openssh-client \| lsh-client, - keychain, hyperestraier, kdissert +Conflicts: vim\-sisu, sisu\-vim, sisu\-remote .PP -Suggests: libfcgi-ruby1.8, rcs \| cvs, lv, texinfo, pinfo, rename +Replaces: vim\-sisu, sisu\-vim .PP -Package: sisu-complete +Recommends: sisu\-pdf, sisu\-sqlite, sisu\-postgresql, librmagick\-ruby, trang, +tidy, librexml\-ruby, openssl, rsync, openssh\-client \| lsh\-client, keychain, +hyperestraier, kdissert Suggests: rcs \| cvs, lv, texinfo, pinfo .PP -Depends: ruby (>= 1.8.4), sisu, sisu-pdf, sisu-postgresql, sisu-sqlite +Package: sisu\-complete +.PP +Depends: ruby (>= 1.8.2), sisu, sisu\-pdf, sisu\-postgresql, sisu\-sqlite .PP Recommends: hyperestraier .PP -Package: sisu-pdf +Package: sisu\-pdf .PP -Depends: sisu, tetex-bin \| texlive-base-bin, tetex-extra \| texlive-latex-extra, - texlive-latex-extra, latex-ucs +Depends: sisu, texlive\-latex\-base, texlive\-fonts\-recommended, +texlive\-latex\-recommended, texlive\-latex\-extra .PP Suggests: evince, xpdf .PP -Package: sisu-postgresql +Package: sisu\-postgresql .PP -Depends: sisu, postgresql-8.1, libdbi-ruby, libdbm-ruby, libdbd-pg-ruby +Depends: sisu, libdbd\-pg\-ruby, libdbi\-ruby, libdbm\-ruby, postgresql .PP -Suggests: pgaccess, libdbd-pgsql, postgresql-contrib-8.1 +Recommends: libfcgi\-ruby .PP -Package: sisu-sqlite +Package: sisu\-sqlite .PP -Depends: sisu, sqlite, libdbi-ruby, libdbm-ruby, libdbd-sqlite-ruby +Depends: sisu, sqlite, libdbd\-sqlite\-ruby, libdbi\-ruby, libdbm\-ruby .PP -Suggests: libdbd-sqlite +Recommends: libfcgi\-ruby .PP -Package: sisu-markup-samples +Package: sisu\-markup\-samples .PP Depends: sisu .PP +.SH Package Description +.B sisu +.PP +Description: documents \- structuring, publishing in multiple formats and search +.PP +SiSU is a lightweight markup based, command line oriented, document +structuring, publishing and search framework for document collections. +.PP +With minimal preparation of a plain\-text, (UTF\-8) file, using its native markup +syntax in your text editor of choice, SiSU can generate various document +formats (most of which share a common object numbering system for locating +content), including plain text, HTML, XHTML, XML, OpenDocument text (ODF:ODT), +LaTeX, PDF files, and populate an SQL database with objects (roughly +paragraph\-sized chunks) so searches may be performed and matches returned with +that degree of granularity: your search criteria is met by these documents and +at these locations within each document. Object numbering is particularly +suitable for "published" works (finalized texts as opposed to works that are +frequently changed or updated) for which it provides a fixed means of reference +of content. Document outputs also share semantic meta\-data provided. +.PP +SiSU also provides concordance files, document content certificates and +manifests of generated output. +.PP +A vim syntax highlighting file and an ftplugin with folds for sisu markup is +provided, as are syntax highlighting files for kate, kwrite, gedit and +diakonos. Vim 7 includes syntax highlighting for SiSU. +.PP +man pages, and interactive help are provided. +.PP +Dependencies for various features are taken care of in sisu related packages. +The package sisu\-complete installs the whole of SiSU. +.PP +Additional document markup samples are provided in the package +sisu\-markup\-samples which is found in the non\-free archive the licenses for +the substantive content of the marked up documents provided is that provided +by the author or original publisher. +.PP +Homepage: .fi .\"%% Configuration Files .SH DOCUMENT RESOURCE CONFIGURATION @@ -235,7 +290,8 @@ sub\-directories located at the following paths: .I /etc/sisu/skin .fi .PP -more specifically, the following locations (or their /etc/sisu equivalent) should be used: +more specifically, the following locations (or their /etc/sisu equivalent) +should be used: .PP .I ~/.sisu/skin/doc skins for individual documents; @@ -249,7 +305,8 @@ modifying the site\-wide appearance of documents. .PP Usually all skin files are placed in the document skin directory: .I ~/.sisu/skin/doc -with softlinks being made to the skins contained there from other skin directories as required. +with softlinks being made to the skins contained there from other skin +directories as required. .\"%% Further Information .SH FURTHER INFORMATION .PP diff --git a/sisu-install b/sisu-install new file mode 100755 index 00000000..3d78c6c1 --- /dev/null +++ b/sisu-install @@ -0,0 +1,3088 @@ +#!/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