pax_global_header 0000666 0000000 0000000 00000000064 13444221025 0014507 g ustar 00root root 0000000 0000000 52 comment=37f67e5096816ca93582a03b4f351b02deefeb84
LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84/ 0000775 0000000 0000000 00000000000 13444221025 0025756 5 ustar 00root root 0000000 0000000 .project 0000664 0000000 0000000 00000000314 13444221025 0027344 0 ustar 00root root 0000000 0000000 LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84
LECABashLib
LICENSE 0000664 0000000 0000000 00000052425 13444221025 0026714 0 ustar 00root root 0000000 0000000 LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84
CeCILL FREE SOFTWARE LICENSE AGREEMENT
Version 2.1 dated 2013-06-21
Notice
This Agreement is a Free Software license agreement that is the result
of discussions between its authors in order to ensure compliance with
the two main principles guiding its drafting:
* firstly, compliance with the principles governing the distribution
of Free Software: access to source code, broad rights granted to users,
* secondly, the election of a governing law, French law, with which it
is conformant, both as regards the law of torts and intellectual
property law, and the protection that it offers to both authors and
holders of the economic rights over software.
The authors of the CeCILL (for Ce[a] C[nrs] I[nria] L[ogiciel] L[ibre])
license are:
Commissariat à l'énergie atomique et aux énergies alternatives - CEA, a
public scientific, technical and industrial research establishment,
having its principal place of business at 25 rue Leblanc, immeuble Le
Ponant D, 75015 Paris, France.
Centre National de la Recherche Scientifique - CNRS, a public scientific
and technological establishment, having its principal place of business
at 3 rue Michel-Ange, 75794 Paris cedex 16, France.
Institut National de Recherche en Informatique et en Automatique -
Inria, a public scientific and technological establishment, having its
principal place of business at Domaine de Voluceau, Rocquencourt, BP
105, 78153 Le Chesnay cedex, France.
Preamble
The purpose of this Free Software license agreement is to grant users
the right to modify and redistribute the software governed by this
license within the framework of an open source distribution model.
The exercising of this right is conditional upon certain obligations for
users so as to preserve this status for all subsequent redistributions.
In consideration of access to the source code and the rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty and the software's author, the holder of the
economic rights, and the successive licensors only have limited liability.
In this respect, the risks associated with loading, using, modifying
and/or developing or reproducing the software by the user are brought to
the user's attention, given its Free Software status, which may make it
complicated to use, with the result that its use is reserved for
developers and experienced professionals having in-depth computer
knowledge. Users are therefore encouraged to load and test the
suitability of the software as regards their requirements in conditions
enabling the security of their systems and/or data to be ensured and,
more generally, to use and operate it in the same conditions of
security. This Agreement may be freely reproduced and published,
provided it is not altered, and that no provisions are either added or
removed herefrom.
This Agreement may apply to any or all software for which the holder of
the economic rights decides to submit the use thereof to its provisions.
Frequently asked questions can be found on the official website of the
CeCILL licenses family (http://www.cecill.info/index.en.html) for any
necessary clarification.
Article 1 - DEFINITIONS
For the purpose of this Agreement, when the following expressions
commence with a capital letter, they shall have the following meaning:
Agreement: means this license agreement, and its possible subsequent
versions and annexes.
Software: means the software in its Object Code and/or Source Code form
and, where applicable, its documentation, "as is" when the Licensee
accepts the Agreement.
Initial Software: means the Software in its Source Code and possibly its
Object Code form and, where applicable, its documentation, "as is" when
it is first distributed under the terms and conditions of the Agreement.
Modified Software: means the Software modified by at least one
Contribution.
Source Code: means all the Software's instructions and program lines to
which access is required so as to modify the Software.
Object Code: means the binary files originating from the compilation of
the Source Code.
Holder: means the holder(s) of the economic rights over the Initial
Software.
Licensee: means the Software user(s) having accepted the Agreement.
Contributor: means a Licensee having made at least one Contribution.
Licensor: means the Holder, or any other individual or legal entity, who
distributes the Software under the Agreement.
Contribution: means any or all modifications, corrections, translations,
adaptations and/or new functions integrated into the Software by any or
all Contributors, as well as any or all Internal Modules.
Module: means a set of sources files including their documentation that
enables supplementary functions or services in addition to those offered
by the Software.
External Module: means any or all Modules, not derived from the
Software, so that this Module and the Software run in separate address
spaces, with one calling the other when they are run.
Internal Module: means any or all Module, connected to the Software so
that they both execute in the same address space.
GNU GPL: means the GNU General Public License version 2 or any
subsequent version, as published by the Free Software Foundation Inc.
GNU Affero GPL: means the GNU Affero General Public License version 3 or
any subsequent version, as published by the Free Software Foundation Inc.
EUPL: means the European Union Public License version 1.1 or any
subsequent version, as published by the European Commission.
Parties: mean both the Licensee and the Licensor.
These expressions may be used both in singular and plural form.
Article 2 - PURPOSE
The purpose of the Agreement is the grant by the Licensor to the
Licensee of a non-exclusive, transferable and worldwide license for the
Software as set forth in Article 5 <#scope> hereinafter for the whole
term of the protection granted by the rights over said Software.
Article 3 - ACCEPTANCE
3.1 The Licensee shall be deemed as having accepted the terms and
conditions of this Agreement upon the occurrence of the first of the
following events:
* (i) loading the Software by any or all means, notably, by
downloading from a remote server, or by loading from a physical medium;
* (ii) the first time the Licensee exercises any of the rights granted
hereunder.
3.2 One copy of the Agreement, containing a notice relating to the
characteristics of the Software, to the limited warranty, and to the
fact that its use is restricted to experienced users has been provided
to the Licensee prior to its acceptance as set forth in Article 3.1
<#accepting> hereinabove, and the Licensee hereby acknowledges that it
has read and understood it.
Article 4 - EFFECTIVE DATE AND TERM
4.1 EFFECTIVE DATE
The Agreement shall become effective on the date when it is accepted by
the Licensee as set forth in Article 3.1 <#accepting>.
4.2 TERM
The Agreement shall remain in force for the entire legal term of
protection of the economic rights over the Software.
Article 5 - SCOPE OF RIGHTS GRANTED
The Licensor hereby grants to the Licensee, who accepts, the following
rights over the Software for any or all use, and for the term of the
Agreement, on the basis of the terms and conditions set forth hereinafter.
Besides, if the Licensor owns or comes to own one or more patents
protecting all or part of the functions of the Software or of its
components, the Licensor undertakes not to enforce the rights granted by
these patents against successive Licensees using, exploiting or
modifying the Software. If these patents are transferred, the Licensor
undertakes to have the transferees subscribe to the obligations set
forth in this paragraph.
5.1 RIGHT OF USE
The Licensee is authorized to use the Software, without any limitation
as to its fields of application, with it being hereinafter specified
that this comprises:
1. permanent or temporary reproduction of all or part of the Software
by any or all means and in any or all form.
2. loading, displaying, running, or storing the Software on any or all
medium.
3. entitlement to observe, study or test its operation so as to
determine the ideas and principles behind any or all constituent
elements of said Software. This shall apply when the Licensee
carries out any or all loading, displaying, running, transmission or
storage operation as regards the Software, that it is entitled to
carry out hereunder.
5.2 ENTITLEMENT TO MAKE CONTRIBUTIONS
The right to make Contributions includes the right to translate, adapt,
arrange, or make any or all modifications to the Software, and the right
to reproduce the resulting software.
The Licensee is authorized to make any or all Contributions to the
Software provided that it includes an explicit notice that it is the
author of said Contribution and indicates the date of the creation thereof.
5.3 RIGHT OF DISTRIBUTION
In particular, the right of distribution includes the right to publish,
transmit and communicate the Software to the general public on any or
all medium, and by any or all means, and the right to market, either in
consideration of a fee, or free of charge, one or more copies of the
Software by any means.
The Licensee is further authorized to distribute copies of the modified
or unmodified Software to third parties according to the terms and
conditions set forth hereinafter.
5.3.1 DISTRIBUTION OF SOFTWARE WITHOUT MODIFICATION
The Licensee is authorized to distribute true copies of the Software in
Source Code or Object Code form, provided that said distribution
complies with all the provisions of the Agreement and is accompanied by:
1. a copy of the Agreement,
2. a notice relating to the limitation of both the Licensor's warranty
and liability as set forth in Articles 8 and 9,
and that, in the event that only the Object Code of the Software is
redistributed, the Licensee allows effective access to the full Source
Code of the Software for a period of at least three years from the
distribution of the Software, it being understood that the additional
acquisition cost of the Source Code shall not exceed the cost of the
data transfer.
5.3.2 DISTRIBUTION OF MODIFIED SOFTWARE
When the Licensee makes a Contribution to the Software, the terms and
conditions for the distribution of the resulting Modified Software
become subject to all the provisions of this Agreement.
The Licensee is authorized to distribute the Modified Software, in
source code or object code form, provided that said distribution
complies with all the provisions of the Agreement and is accompanied by:
1. a copy of the Agreement,
2. a notice relating to the limitation of both the Licensor's warranty
and liability as set forth in Articles 8 and 9,
and, in the event that only the object code of the Modified Software is
redistributed,
3. a note stating the conditions of effective access to the full source
code of the Modified Software for a period of at least three years
from the distribution of the Modified Software, it being understood
that the additional acquisition cost of the source code shall not
exceed the cost of the data transfer.
5.3.3 DISTRIBUTION OF EXTERNAL MODULES
When the Licensee has developed an External Module, the terms and
conditions of this Agreement do not apply to said External Module, that
may be distributed under a separate license agreement.
5.3.4 COMPATIBILITY WITH OTHER LICENSES
The Licensee can include a code that is subject to the provisions of one
of the versions of the GNU GPL, GNU Affero GPL and/or EUPL in the
Modified or unmodified Software, and distribute that entire code under
the terms of the same version of the GNU GPL, GNU Affero GPL and/or EUPL.
The Licensee can include the Modified or unmodified Software in a code
that is subject to the provisions of one of the versions of the GNU GPL,
GNU Affero GPL and/or EUPL and distribute that entire code under the
terms of the same version of the GNU GPL, GNU Affero GPL and/or EUPL.
Article 6 - INTELLECTUAL PROPERTY
6.1 OVER THE INITIAL SOFTWARE
The Holder owns the economic rights over the Initial Software. Any or
all use of the Initial Software is subject to compliance with the terms
and conditions under which the Holder has elected to distribute its work
and no one shall be entitled to modify the terms and conditions for the
distribution of said Initial Software.
The Holder undertakes that the Initial Software will remain ruled at
least by this Agreement, for the duration set forth in Article 4.2 <#term>.
6.2 OVER THE CONTRIBUTIONS
The Licensee who develops a Contribution is the owner of the
intellectual property rights over this Contribution as defined by
applicable law.
6.3 OVER THE EXTERNAL MODULES
The Licensee who develops an External Module is the owner of the
intellectual property rights over this External Module as defined by
applicable law and is free to choose the type of agreement that shall
govern its distribution.
6.4 JOINT PROVISIONS
The Licensee expressly undertakes:
1. not to remove, or modify, in any manner, the intellectual property
notices attached to the Software;
2. to reproduce said notices, in an identical manner, in the copies of
the Software modified or not.
The Licensee undertakes not to directly or indirectly infringe the
intellectual property rights on the Software of the Holder and/or
Contributors, and to take, where applicable, vis-à-vis its staff, any
and all measures required to ensure respect of said intellectual
property rights of the Holder and/or Contributors.
Article 7 - RELATED SERVICES
7.1 Under no circumstances shall the Agreement oblige the Licensor to
provide technical assistance or maintenance services for the Software.
However, the Licensor is entitled to offer this type of services. The
terms and conditions of such technical assistance, and/or such
maintenance, shall be set forth in a separate instrument. Only the
Licensor offering said maintenance and/or technical assistance services
shall incur liability therefor.
7.2 Similarly, any Licensor is entitled to offer to its licensees, under
its sole responsibility, a warranty, that shall only be binding upon
itself, for the redistribution of the Software and/or the Modified
Software, under terms and conditions that it is free to decide. Said
warranty, and the financial terms and conditions of its application,
shall be subject of a separate instrument executed between the Licensor
and the Licensee.
Article 8 - LIABILITY
8.1 Subject to the provisions of Article 8.2, the Licensee shall be
entitled to claim compensation for any direct loss it may have suffered
from the Software as a result of a fault on the part of the relevant
Licensor, subject to providing evidence thereof.
8.2 The Licensor's liability is limited to the commitments made under
this Agreement and shall not be incurred as a result of in particular:
(i) loss due the Licensee's total or partial failure to fulfill its
obligations, (ii) direct or consequential loss that is suffered by the
Licensee due to the use or performance of the Software, and (iii) more
generally, any consequential loss. In particular the Parties expressly
agree that any or all pecuniary or business loss (i.e. loss of data,
loss of profits, operating loss, loss of customers or orders,
opportunity cost, any disturbance to business activities) or any or all
legal proceedings instituted against the Licensee by a third party,
shall constitute consequential loss and shall not provide entitlement to
any or all compensation from the Licensor.
Article 9 - WARRANTY
9.1 The Licensee acknowledges that the scientific and technical
state-of-the-art when the Software was distributed did not enable all
possible uses to be tested and verified, nor for the presence of
possible defects to be detected. In this respect, the Licensee's
attention has been drawn to the risks associated with loading, using,
modifying and/or developing and reproducing the Software which are
reserved for experienced users.
The Licensee shall be responsible for verifying, by any or all means,
the suitability of the product for its requirements, its good working
order, and for ensuring that it shall not cause damage to either persons
or properties.
9.2 The Licensor hereby represents, in good faith, that it is entitled
to grant all the rights over the Software (including in particular the
rights set forth in Article 5 <#scope>).
9.3 The Licensee acknowledges that the Software is supplied "as is" by
the Licensor without any other express or tacit warranty, other than
that provided for in Article 9.2 <#good-faith> and, in particular,
without any warranty as to its commercial value, its secured, safe,
innovative or relevant nature.
Specifically, the Licensor does not warrant that the Software is free
from any error, that it will operate without interruption, that it will
be compatible with the Licensee's own equipment and software
configuration, nor that it will meet the Licensee's requirements.
9.4 The Licensor does not either expressly or tacitly warrant that the
Software does not infringe any third party intellectual property right
relating to a patent, software or any other property right. Therefore,
the Licensor disclaims any and all liability towards the Licensee
arising out of any or all proceedings for infringement that may be
instituted in respect of the use, modification and redistribution of the
Software. Nevertheless, should such proceedings be instituted against
the Licensee, the Licensor shall provide it with technical and legal
expertise for its defense. Such technical and legal expertise shall be
decided on a case-by-case basis between the relevant Licensor and the
Licensee pursuant to a memorandum of understanding. The Licensor
disclaims any and all liability as regards the Licensee's use of the
name of the Software. No warranty is given as regards the existence of
prior rights over the name of the Software or as regards the existence
of a trademark.
Article 10 - TERMINATION
10.1 In the event of a breach by the Licensee of its obligations
hereunder, the Licensor may automatically terminate this Agreement
thirty (30) days after notice has been sent to the Licensee and has
remained ineffective.
10.2 A Licensee whose Agreement is terminated shall no longer be
authorized to use, modify or distribute the Software. However, any
licenses that it may have granted prior to termination of the Agreement
shall remain valid subject to their having been granted in compliance
with the terms and conditions hereof.
Article 11 - MISCELLANEOUS
11.1 EXCUSABLE EVENTS
Neither Party shall be liable for any or all delay, or failure to
perform the Agreement, that may be attributable to an event of force
majeure, an act of God or an outside cause, such as defective
functioning or interruptions of the electricity or telecommunications
networks, network paralysis following a virus attack, intervention by
government authorities, natural disasters, water damage, earthquakes,
fire, explosions, strikes and labor unrest, war, etc.
11.2 Any failure by either Party, on one or more occasions, to invoke
one or more of the provisions hereof, shall under no circumstances be
interpreted as being a waiver by the interested Party of its right to
invoke said provision(s) subsequently.
11.3 The Agreement cancels and replaces any or all previous agreements,
whether written or oral, between the Parties and having the same
purpose, and constitutes the entirety of the agreement between said
Parties concerning said purpose. No supplement or modification to the
terms and conditions hereof shall be effective as between the Parties
unless it is made in writing and signed by their duly authorized
representatives.
11.4 In the event that one or more of the provisions hereof were to
conflict with a current or future applicable act or legislative text,
said act or legislative text shall prevail, and the Parties shall make
the necessary amendments so as to comply with said act or legislative
text. All other provisions shall remain effective. Similarly, invalidity
of a provision of the Agreement, for any reason whatsoever, shall not
cause the Agreement as a whole to be invalid.
11.5 LANGUAGE
The Agreement is drafted in both French and English and both versions
are deemed authentic.
Article 12 - NEW VERSIONS OF THE AGREEMENT
12.1 Any person is authorized to duplicate and distribute copies of this
Agreement.
12.2 So as to ensure coherence, the wording of this Agreement is
protected and may only be modified by the authors of the License, who
reserve the right to periodically publish updates or new versions of the
Agreement, each with a separate number. These subsequent versions may
address new issues encountered by Free Software.
12.3 Any Software distributed under a given version of the Agreement may
only be subsequently distributed under the same version of the Agreement
or a subsequent version, subject to the provisions of Article 5.3.4
<#compatibility>.
Article 13 - GOVERNING LAW AND JURISDICTION
13.1 The Agreement is governed by French law. The Parties agree to
endeavor to seek an amicable solution to any disagreements or disputes
that may arise during the performance of the Agreement.
13.2 Failing an amicable solution within two (2) months as from their
occurrence, and unless emergency proceedings are necessary, the
disagreements or disputes shall be referred to the Paris Courts having
jurisdiction, by the more diligent Party.
README.md 0000664 0000000 0000000 00000033057 13444221025 0027166 0 ustar 00root root 0000000 0000000 LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84 # The *LECA Bash Library*
The LECA Bash Library aims to provide a set of function helping the development
of bash scripts used to submit jobs on the computation grid.
The LECA Bash Library is constituted by a set of bash scripts that can be
sourced in your script or directly from the interactive shell if you want
to use the functionalities of the LECA Bash Library from your interactive
session.
For activating the *LECA Bash Library* you must source the `lecabashlib.sh` bash script.
```{shell}
> source $LECABASHHOME/lecabashlib.sh
```
once activated modules can be loaded using the `include` command.
```{shell}
> include timeout
```
The include command is aware about already loaded modules and takes care to not
reload several time the same module. To force the reloading of a module, use the
`reload` command.
```{shell}
> reload timeout
```
The module is reloaded with all its dependancies. A logging message advertise the
name of each reloaded module.
You can specify alternative place where to look for non standard modules by setting
the `LECABASHLIB_PATH` environment variable. If several paths have to be declared, you
must separate them using colon
```{shell}
> export LECABASHLIB_PATH="/new/path/1:/new/path/2:${LECABASHLIB_PATH}"
```
----------------------------------------------------------
# Modules provided by the *LECA Bash Library*
- **[atexit](#atexit)** : for automatically execute task at the end of the execution
- **[clobber](#clobber)** : for managing the clobber/noclobber status
- **[download](#download)** : for managing download from FTP and Web including MD5 checks
- **[ifs](#ifs)** : for managing the *input field separator*
- **[irods](#irods)** : provide functions wrapping the iRods iget and iput icommands.
- **[lecaluke](#lecaluke)** : declare variable related for the LECA computers in LUKE
- **[logging](#logging)** : adds functionnalities for managing log files and log levels
- **[mutex](#mutex)** : manages concurent access to resources through locks and semaphores
- **[sets](#sets)** : manages *set* of values
- **[signal](#signal)** : manages signal handler functions
- **[stacks](#stacks)** : manages *stacks* of values
- **[tempdir](#tempdir)** : manages the creation of temporary directories and their erasements
- **[timeout](#timeout)** : provides a function for limiting the maximum execution time of a command
- **[xml](#xml)** : provides a set of functions to write basic XML files
----------------------------------------------------------
# Detailed description of modules
## atexit
### Activating the module
```{shell}
> source $LECABASHHOME/lecabashlib.sh
> include atexit
```
### Functions provided:
#### registeratexit
Allows to register commands that will be automatically executed at the end
of the script execution.
```{shell}
> include atexit
> registeratexit "echo this is the end of the script"
```
----------------------------------------------------------
## clobber
Manages the **clobber**/**noclobber** property of the bash shell
When the **noclobber** mode is `on` you cannot substitute an existing file by a
empty one using a UNIX redirection.
### Activating the module
```{shell}
> source $LECABASHHOME/lecabashlib.sh
> include clobber
```
### Functions provided:
#### setnoclobber
Sets the **noclobber** mode on.
You cannot erase an existing file by a redirection
```{shell}
> include clobber
> setnoclobber
> getnoclobber
on
```
#### setclobber
Sets the **noclobber** mode off.
You can erase an existing file by a redirection
```{shell}
> include clobber
> setclobber
> getnoclobber
off
```
#### getnoclobber
```{shell}
getnoclobber
```
Returns the noclobber status as a string
- `on`: the noclobber mode is on
- `off`: the noclobber mode is off
```{shell}
> include clobber
> getnoclobber
off
```
#### pushclobber
```{shell}
pushclobber
```
Saves the current noclobber mode on a stack and sets it to 'off'
#### pushnoclobber
```{shell}
pushnoclobber
```
Saves the current noclobber mode on a stack and sets it to 'on'
#### popclobber
```{shell}
popclobber
```
Restores the last pushed noclobber mode
#### popnoclobber
```{shell}
popnoclobber
```
Alias for the `popclobber` function. Using one of the both commands `popnoclobber` or `popclobber` leads to the same action, restoring the last pushed noclober mode
----------------------------------------------------------
## download
### Activating the module
```{shell}
> source $LECABASHHOME/lecabashlib.sh
> include download
```
### Functions provided:
#### download
```{shell}
download [USERNAME] [PASSWORD]
```
Downloads the file specified by `URL`.
If specifed the second (`USERNAME`) and third (`PASSWORD`) parametters allow
to indicate a login and password for a protected connection
#### downloadandcheck
```{shell}
downloadandcheck [USERNAME] [PASSWORD]
```
Downloads the file specified by `URL` and check file integrity.
The MD5 checksum file URL is indicated using the `MD5URL` parametters.
You must specified a destination filename to store the downloaded data
using the `DESTINATION` parametter. The MD5 file is downloaded under the
name DESTINATION.md5
If specifed the fourth (`USERNAME`) and fifth (`PASSWORD`) parametters allow
to indicate a login and password for a protected connection
On error the function has a return status set to *1*, *0* otherwise.
#### setmaxretry
```{shell}
setmaxretry
```
If downloading failed the downloadandcheck function can retry to download
the file several times before a complete failure. This function allows to
define the maximum of time the downloadandcheck tries to redownload before
exiting in error.
----------------------------------------------------------
## ifs
### Activating the module
```{shell}
> source $LECABASHHOME/lecabashlib.sh
> include ifs
```
### Functions provided:
#### pushifs
```{shell}
pushifs
```
#### popifs
```{shell}
popifs
```
----------------------------------------------------------
## lecaluke
The lecaluke module provides a set of variable defining emplacement
where LECA ressources are stored on the LUKE cluster.
### Activating the module
```{shell}
> source $LECABASHHOME/lecabashlib.sh
> include lecaluke
```
### Functions provided:
#### latesttaxonomy
```{shell}
latesttaxonomy
```
### Defined variables
#### LECA_ENVIRONEMENT
#### LOCK_DIR
#### DATA_DIR
#### BIODATA_DIR
#### TAXONOMY_DIR
#### TREMBL_DIR
#### SWISSPROT_DIR
----------------------------------------------------------
## logging
The *logging* module define a set of function allowing to log on the standard error
or into a file messages.
All the log will be done on file descriptor 3
By default file descriptor 3 is redirected to stderr (2)
By default the logging level is set to `WARNING`.
Therefore only `WARNING` and `ERROR` messages will be actually logged.
### Activating the module
```{shell}
> source $LECABASHHOME/lecabashlib.sh
> include logging
```
### Functions provided:
#### logdebug
```{shell}
logdebug
```
Writes `MESSAGE` as a debug level log to the current log file.
#### loginfo
```{shell}
loginfo
```
Writes `MESSAGE` as a info level log to the current log file.
#### logerror
```{shell}
logerror
```
Writes `MESSAGE` as a error level log to the current log file.
#### logwarning
```{shell}
logwarning
```
Writes `MESSAGE` as a warning level log to the current log file.
#### setloglevel
```{shell}
setloglevel
```
Set the current logging level to the level specified by `LEVEL`.
Level is `DEBUG`, `INFO`, `WARNING` or `ERROR`.
A log is recorded only when it is submitted with a level
greater or equal to the current logging level.
#### openlogfile
```{shell}
openlogfile
```
Redirected all logging to the file specified by `FILENAME`.
If the file already exists, new logs are appened at the end of the file.
If the file does not exist it is created
#### closelogfile
```{shell}
closelogfile
```
Closes the current logfile and redirect the logging to stderr.
----------------------------------------------------------
## mutex
### Activating the module
```{shell}
> source $LECABASHHOME/lecabashlib.sh
> include mutex
```
### Functions provided:
#### getlock
```{shell}
getlock [global]
```
#### releaselock
```{shell}
releaselock [global]
```
#### getsemaphore
```{shell}
getsemaphore [global]
```
#### releasesemaphore
```{shell}
releasesemaphore [global]
```
#### releaseoldlock
```{shell}
releaseoldlock [MINUTES]
```
### Variable provided
#### LOCK_DIR
#### LECA_LOCK_DELAY
#### LECA_LOCK_MAXRETRY
----------------------------------------------------------
## sets
### Activating the module
```{shell}
> source $LECABASHHOME/lecabashlib.sh
> include sets
```
### Functions provided:
#### newset
```{shell}
newset
```
#### setsize
```{shell}
setsize
```
#### setaddvalue
```{shell}
setsize
```
#### setdelvalue
```{shell}
setdelvalue
```
#### setcontains
```{shell}
setcontains
```
#### setunion
```{shell}
setunion
```
#### setintersec
```{shell}
setintersec
```
----------------------------------------------------------
## signal
### Activating the module
```{shell}
> source $LECABASHHOME/lecabashlib.sh
> include signal
```
### Functions provided:
#### registertrap
```{shell}
registertrap
```
#### run
```{shell}
run
```
----------------------------------------------------------
## stacks
### Activating the module
```{shell}
> source $LECABASHHOME/lecabashlib.sh
> include stacks
```
### Functions provided:
#### newstack
```{shell}
newstack
```
Creates a new stack named `STACKNAME`.
#### stacksize
```{shell}
stacksize
```
Returns the count of element stored in the stack.
#### pushvalue
```{shell}
pushvalue
```
Adds the value VALUE at the end of the stack `STACKNAME`.
#### popvalue
```{shell}
popvalue
```
Pops out the last pushed value of the stack and store it into the `VARIABLE`.
If the stack is already empty the function returns nothing
and the return status is set to *1* instead of *0* usually.
----------------------------------------------------------
## tempdir
### Activating the module
```{shell}
> source $LECABASHHOME/lecabashlib.sh
> include tempdir
```
### Functions provided:
#### availabledisk
```{shell}
availabledisk
```
#### registertmpdir
```{shell}
registertmpdir
```
#### getbasetmpdir
```{shell}
getbasetmpdir
```
#### tempdirectory
```{shell}
tempdirectory [MINSIZE]
```
----------------------------------------------------------
## timeout
### Activating the module
```{shell}
> source $LECABASHHOME/lecabashlib.sh
> include timeout
```
### Functions provided:
#### timeoutcmd
```{shell}
timeoutcmd
```
----------------------------------------------------------
## path
### Activating the module
> source $LECABASHHOME/lecabashlib.sh
> include path
### Functions provided:
#### relative2absolute
relative2absolute
#### absolute2relative
```bash
absolute2relative
```
----------------------------------------------------------
## irods
The *irods* module define a set of function wrapping the classical `iput` and
`iget` commands.
### Activating the module
```{shell}
> source $LECABASHHOME/lecabashlib.sh
> include irods
```
### Functions provided:
#### isetressource
```{shell}
isetresource
```
Set the default resource used by `iput` to store data to `RESOURCE`.
----------------------------------------------------------
```{shell}
iresourceexists
```
Function returning an error status according if the specified iRods
resource exists or not.
- Returns an error status set to 0 if the resource exists,
- Returns an error status set to 1 otherwise.
ex:
```{shell}
if iresourceexists $ipath ; then
echo $ipath exists
else
echo $ipath is absent
fi
```
----------------------------------------------------------
#### igetwithmd5
```{shell}
igetwithmd5 [LOCAL_DEST]
```
Gets an iRods resource and check if the uploaded file is compatible with the
MD5 checksum stored on iRods to. The MD5 file must have the same name than the
downloaded resource with the `.md5` extension added.
The `LOCAL_DEST` parameter is optional and without it the downloaded file is
saved in the current working directory.
The function download the file until the MD5 check is ok or the maximum retrial
count is reached.
`igetwithmd5` is not taking care of protecting is access by a lock or a semaphore.
## xml
### Activating the module
```{shell}
> source $LECABASHHOME/lecabashlib.sh
> include xml
```
### Functions provided:
#### XML_header
```{shell}
XML_header
```
#### XML_push
```{shell}
XML_push
```
#### XML_pop
```{shell}
XML_pop
```
#### XML_tag_data
```{shell}
XML_tag_data
```
#### XML_tag_attr_data
```{shell}
XML_tag_attr_data --
```
#### XML_empty_tag
```{shell}
XML_empty_tag
```
#### XML_data
```{shell}
XML_data
```
atexit.sh 0000664 0000000 0000000 00000000617 13444221025 0027535 0 ustar 00root root 0000000 0000000 LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84
# LECA Bash library
#
# The LECA bash library provides a set of function used for helping
# development of bash script mainly to write job script on the luke
# cluster
#
# The files from the LECA Bash library must be sourced from your main script
#
#
include logging
logdebug "Load atexit package"
include signal
function registeratexit() {
registertrap EXIT "${*}"
registertrap ERR "${*}"
}
clobber.sh 0000664 0000000 0000000 00000003705 13444221025 0027650 0 ustar 00root root 0000000 0000000 LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84
# LECA Bash library
#
# The LECA bash library provides a set of function used for helping
# development of bash script mainly to write job script on the luke
# cluster
#
# The files from the LECA Bash library must be sourced from your main script
#
#
# Manages the clobber/noclobber property of the bash shell
# ========================================================
#
# When the noclobber mode is on you cannot substitute an existing file by a
# empty one using a unix redirection.
#
# Functions provided:
#
# - setnoclobber
# Sets the noclobber mode on.
# You cannot erase an existing file by a redirection
#
# - setclobber
# Sets the noclobber mode off.
# You can erase an existing file by a redirection
#
# - getnoclobber
# Returns the noclobber status as a string
# - on: the noclobber mode is on
# - off: the noclobber mode is off
#
# - pushclobber
# Saves the current noclobber mode on a stack and sets it to 'off'
#
# - pushnoclobber
# Saves the current noclobber mode on a stack and sets it to 'on'
#
# - popclobber
# Restores the last pushed noclobber mode
#
# - popnoclobber
# Alias for the popclobber function
#
include logging
logdebug "Load clobber package"
include stacks
newstack __LECABASHLIB_CLOBBERSTACK__
function setnoclobber() {
set -o noclobber
}
function setclobber() {
set +o noclobber
}
function getnoclobber() {
set -o | awk '($1 ~ /noclobber/) {print $2}'
}
function pushclobber() {
pushvalue __LECABASHLIB_CLOBBERSTACK__ $(getnoclobber)
setclobber
}
function pushnoclobber() {
pushvalue __LECABASHLIB_CLOBBERSTACK__ $(getnoclobber)
setnoclobber
}
function popclobber() {
local state=0
popvalue __LECABASHLIB_CLOBBERSTACK__ state
if [[ "$?" == "0" ]]; then
if [[ "${state}" == "on" ]]; then
setnoclobber
else
setclobber
fi
else
return 1
fi
return 0
}
function popnoclobber() {
popclobber
return $?
}
download.sh 0000664 0000000 0000000 00000007212 13444221025 0030044 0 ustar 00root root 0000000 0000000 LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84 #
# LECA Bash library
#
# The LECA bash library provides a set of function used for helping
# development of bash script mainly to write job script on the luke
# cluster
#
# The files from the LECA Bash library must be sourced from your main script
#
#
# Provides functions to facilitate downloading of files
# =====================================================
#
# Provided function:
#
# - download [USERNAME] [PASSWORD]
# Downloads the file specified by URL.
# If specifed the second (USERNAME) and third (PASSWORD) parametters allow
# to indicate a login and password for a protected connection
#
# - downloadandcheck [USERNAME] [PASSWORD]
# Downloads the file specified by URL and check file integrity.
# The MD5 checksum file URL is indicated using the MD5URL parametters.
# You must specified a destination filename to store the downloaded data
# using the DESTINATION parametter. The MD5 file is downloaded under the
# name DESTINATION.md5
# If specifed the fourth (USERNAME) and fifth (PASSWORD) parametters allow
# to indicate a login and password for a protected connection
#
# On error the function has a return status set to 1, 0 otherwise.
#
# - setmaxretry
# If downloading failed the downloadandcheck function can retry to download
# the file several times before a complete failure. This function allows to
# define the maximum of time the downloadandcheck tries to redownload before
# exiting in error
#
#
include logging
include ifs
logdebug "Load download package"
if ! which curl; then
if module 2> /dev/null; then
module load curl
module load openssl
else
logerror "No curl command available"
fi
fi
if ! which md5; then
if ! which md5sum; then
logerror "No md5 commands available"
else
LECABASHLIB_MD5SUM=md5sum
fi
else
LECABASHLIB_MD5SUM=md5
fi
CURL="curl -L"
LECA_MAX_RETRY=3
function download() {
pushifs
logdebug "Function called with $# arguments"
logdebug "$@"
local URL="${1}"
shift
local LINK="${CURL} ${URL}"
if [[ ! -z $1 && -z $2 ]]; then
logdebug "Download with username ${1}"
local LINK="${CURL} --user ${1} ${URL}"
shift
fi
if [[ ! -z $1 && ! -z $2 ]]; then
logdebug "Download with username ${1} and password ${2}"
local LINK="${CURL} --user ${1}:${2} ${URL}"
shift
shift
fi
loginfo "Downloading URL : ${URL}"
${LINK}
loginfo "URL : ${URL} -> Done."
popifs
}
function setmaxretry() {
LECA_MAX_RETRY="$1"
}
function downloadandcheck() {
local URL="${1}"
shift
local MD5="${1}"
shift
local TARGETFILE="${1}"
shift
if [[ ! -z "${1}" ]]; then
local DOWLOADUSER="${1}"
shift
fi
if [[ ! -z "${1}" ]]; then
local PASSWORD="${1}"
shift
fi
local RETRY=0
local MD5_BAD=1
while (( MD5_BAD > 0 )) && (( RETRY < LECA_MAX_RETRY )); do
download "${URL}" "${DOWLOADUSER}" "${PASSWORD}" > "${TARGETFILE}"
download "${MD5}" "${DOWLOADUSER}" "${PASSWORD}" > "${TARGETFILE}.md5"
MD5LOCAL=$(${LECABASHLIB_MD5SUM} "${TARGETFILE}" | awk '{print $1}')
MD5ORIGI=$(awk '{print $1}' "${TARGETFILE}.md5")
if [[ "$MD5LOCAL" == "$MD5ORIGI" ]]; then
MD5_BAD=0
else
MD5_BAD=1
fi
RETRY=$((RETRY+1))
if (( MD5_BAD > 0 )); then
logwarning "The two MD5 are different : $MD5LOCAL and $MD5ORIGI"
fi
done
if (( MD5_BAD > 0 )); then
logerror "The two MD5 are different after $RETRY retries: "
logerror " $MD5LOCAL and $MD5ORIGI"
return 1
else
loginfo "${TARGETFILE} downloaded"
loginfo " and checked with MD5 $MD5ORIGI"
return 0
fi
}
LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84/ifs.sh0000664 0000000 0000000 00000001466 13444221025 0027102 0 ustar 00root root 0000000 0000000 #
# LECA Bash library
#
# The LECA bash library provides a set of function used for helping
# development of bash script mainly to write job script on the luke
# cluster
#
# The files from the LECA Bash library must be sourced from your main script
#
include stacks
newstack LECABASH_IFS_STACK
function pushifs() {
if [[ -z "${IFS}" ]]; then
pushvalue LECABASH_IFS_STACK "@@NULL@@"
else
local v=$(echo -n "$IFS" | od -b | head -n +1 | sed 's/[0-9]* //' | sed 's/ /\\/g' | sed 's/^/\\/')
pushvalue LECABASH_IFS_STACK "$v"
fi
if [[ -z "$1" ]]; then
unset IFS
else
IFS="${1}"
fi
}
function popifs() {
local v
v=$(popvalue LECABASH_IFS_STACK v)
if [[ "$?"!="0" ]]; then
if [[ "$v"=="@@NULL@@" ]]; then
unset IFS
else
IFS=$(eval "echo -n \$'$x'")
fi
else
return 1
fi
return 0
} irods.sh 0000664 0000000 0000000 00000007506 13444221025 0027363 0 ustar 00root root 0000000 0000000 LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84
# LECA Bash library
#
# The LECA bash library provides a set of function used for helping
# development of bash script mainly to write job script on the luke
# cluster
#
# The files from the LECA Bash library must be sourced from your main script
#
#
include logging
logdebug "Load irods package"
LECABASHLIB_MAXTRIAL="5"
#
# Look for the iRods commands on the system
#
if ! which iget 2>&1 > /dev/null ; then
if module 2> /dev/null ; then
loginfo "Loading the iRods module"
module load irods
fi
fi
if ! which iget 2>&1 > /dev/null ; then
logerror "No iRods commands available"
fi
#
# Switch between the secure and the none secure iCommands
#
# --> if the bash function secure_iget is define we use it
# otherwise we use the classical iget
#
if type secure_iget 1> /dev/null; then
LECABASHLIB_IGET="secure_iget"
loginfo "Activating secure icommand for iget"
else
LECABASHLIB_IGET="iget"
fi
#
# Same thing for iput
#
if type secure_iput 1> /dev/null; then
LECABASHLIB_IPUT="secure_iput"
loginfo "Activating secure icommand for iput"
else
LECABASHLIB_IPUT="iput"
fi
#
# Checks between md5sum and md5 is the command to run
# for computing a MD5 checksum
#
if ! which md5 2>&1 > /dev/null ; then
if ! which md5sum 2>&1 > /dev/null ; then
logerror "No md5 commands available"
else
LECABASHLIB_MD5SUM=md5sum
fi
else
LECABASHLIB_MD5SUM=md5
fi
#
# isetsecure
#
function isetsecure() {
LECABASHLIB_IGET=$( echo $LECABASHLIB_IGET | sed "s/^iget/secure_iget/" )
LECABASHLIB_IPUT=$( echo $LECABASHLIB_IPUT | sed "s/^iput/secure_iput/" )
loginfo "Activating secure icommand"
}
#
# isetsecure
#
function iunsetsecure() {
LECABASHLIB_IGET=$( echo $LECABASHLIB_IGET | sed "s/^secure_iget/iget/" )
LECABASHLIB_IPUT=$( echo $LECABASHLIB_IPUT | sed "s/^secure_iput/iput/" )
loginfo "Desactivating secure icommand"
}
#
# isetresource :
#
function isetresource() {
if [[ ! -z "${1}" ]]; then
local IRESOURCE="${1}"
LECABASHLIB_IPUT="iput -R ${IRESOURCE}"
else
if type secure_iput 1> /dev/null; then
LECABASHLIB_IPUT="secure_iput"
else
LECABASHLIB_IPUT="iput"
fi
fi
}
function isetmaxtrial() {
if [[ ! -z "${1}" ]]; then
LECABASHLIB_MAXTRIAL=$(( $1 + 0 ))
if (( LECABASHLIB_MAXTRIAL )) ; then
logwarning "Max trails set to a no-sens value reset to 5"
LECABASHLIB_MAXTRIAL="5"
fi
else
LECABASHLIB_MAXTRIAL="5"
fi
}
function iresourceexists() {
local rep=1
ils "$1" 2> /dev/null >/dev/null
if (( $? == 0 )) ; then
logdebug "iRods resource : $1 exists"
rep=0
else
logdebug "iRods resource : $1 absents"
fi
return $rep
}
function igetwithmd5() {
local SOURCE=$1
shift
if [[ ! -z "${1}" ]]; then
local TARGET=$1
else
local TARGET=$(basename $SOURCE)
fi
if ! iresourceexists "$SOURCE" ; then
logerror "The requested iRods resource does not exit : $SOURCE"
return 1
fi
local TRIAL=0
local LMD5="XXXXXX"
local IMD5="YYYYYY"
local IROD_STATUS=1
while [[ "${LMD5}" != "${IMD5}" ]] && (($TRIAL < $LECABASHLIB_MAXTRIAL)); do
TRIAL=$((TRIAL+1))
"${LECABASHLIB_IGET}" "${SOURCE}" "${TARGET}"
HAS_MD5=0
"${LECABASHLIB_IGET}" "${SOURCE}.md5" "${TARGET}.md5" && HAS_MD5=1
if (( HAS_MD5 == 1 ))
then
LMD5=$(${LECABASHLIB_MD5SUM} ${TARGET} | awk '{print $1}')
IMD5=$(cat ${TARGET}.md5 | awk '{print $1}')
else
logwarning "no MD5 available on iRods"
IMD5="NO-MD5"
LMD5="NO-MD5"
fi
if [[ "${LMD5}" != "${IMD5}" ]] && (($TRIAL < $LECABASHLIB_MAXTRIAL)); then
logwarning "MD5 doesn't match; re-load file from iRods"
fi
done
rm -f "${TARGET}.md5"
if [[ "${LMD5}" != "${IMD5}" ]]; then
logerror "MD5 doesn't match; re-load file from iRods"
return 1
fi
return 0
}
function iputwithmd5() {
echo Not yet implemented
}
lecabashlib.sh 0000664 0000000 0000000 00000004376 13444221025 0030476 0 ustar 00root root 0000000 0000000 LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84 # LECA Bash library
#
# The LECA bash library provides a set of function used for helping
# development of bash script mainly to write job script on the luke
# cluster
#
# The files from the LECA Bash library must be sourced from your main script
#
#
if [[ -z "${LECALIB_UTIL_SH}" ]]; then
LECALIB_UTIL_SH=1
LECABASHLIB_RELOADING=0
if [[ -z "$LECABASHLIB_PATH" ]] ; then
export LECABASHLIB_PATH=""
fi
THIS_DIR="$(dirname ${BASH_SOURCE[0]})"
source "${THIS_DIR}/lecabashlib.sh"
function abspath() {
local P=$1
echo "$(cd "$(dirname "${P}")" && pwd -P)/$(basename "${P}")"
}
LECALIB_DIR=$(abspath "${THIS_DIR}")
function upper() {
echo $1 | tr "a-z" "A-Z"
}
function lower() {
echo $1 | tr "A-Z" "a-z"
}
function indirect() {
eval echo \$${1}
}
function include() {
local MODULE=$(upper $1)
local LOADED_MODULE_VAR="LECALIB_${MODULE}_SH"
local LOADED_MODULE=$(indirect $LOADED_MODULE_VAR)
local found=""
for path in $(echo $LECABASHLIB_PATH | sed 's/:/ /g') ; do
if [[ -z "$found" && \
( -z "${LOADED_MODULE}" || \
"$LECABASHLIB_RELOADING" == 1 ) && \
-f "${path}/${1}.sh" ]] ; then
source "${path}/${1}.sh"
eval $LOADED_MODULE_VAR=1
found=1
fi
done
if [[ -z "$found" && \
( -z "${LOADED_MODULE}" || \
"$LECABASHLIB_RELOADING" == 1 ) && \
-f "${LECALIB_DIR}/${1}.sh" ]] ; then
source "${LECALIB_DIR}/${1}.sh"
eval $LOADED_MODULE_VAR=1
found=1
fi
if (( found == 1 )) ; then
if (( LECABASHLIB_RELOADING == 1 )) ; then
logdebug "Module $1 reloaded..."
else
logdebug "Module $1 loaded..."
fi
else
if [[ -z "${LOADED_MODULE}" ]] ; then
logerror "Cannot load module $1"
fi
fi
}
function reload() {
LECABASHLIB_RELOADING=1
include "${1}"
LECABASHLIB_RELOADING=0
}
function onluke() {
[[ $(hostname) =~ ^luke[0-9]* ]]
}
function onfroggy() {
[[ $(hostname) =~ ^frog ]]
}
function ondahu() {
[[ $(hostname) =~ ^dahu[0-9] ]]
}
function isinteractiveshell() {
case "$-" in
*i*) (( 1 == 1 )) ;;
*) (( 1 == 0 )) ;;
esac
}
function pushd () {
command pushd "$@" > /dev/null
}
function popd () {
command popd "$@" > /dev/null
}
include logging
fi
lecaluke.sh 0000664 0000000 0000000 00000003767 13444221025 0030035 0 ustar 00root root 0000000 0000000 LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84 #
# LECA Bash library
#
# The LECA bash library provides a set of function used for helping
# development of bash script mainly to write job script on the luke
# cluster
#
# The files from the LECA Bash library must be sourced from your main script
#
#
# Provides a set of variables relative to the LECA environement
# =============================================================
#
# The lecaluke module provides a set of variable defining emplacement
# where LECA ressources are stored on the LUKE cluster.
include logging
logdebug "Load lecaluke package"
include tempdir
if onluke || ondahu ; then
logdebug "Script run on the LUKE/DAHU cluster"
## Source the ciment & leca environment:
#. /bettik/LECA/ENVIRONMENT/env.bash
# Register scratch_dir as place where to create temp directory
if [[ ! -z "$LOCAL_SCRATCH_DIR" ]] ; then
registertmpdir $LOCAL_SCRATCH_DIR
registertmpdir $SHARED_SCRATCH_DIR
fi
# Where is located the LECA_ENVIRONEMENT
LECA_ENVIRONEMENT=/bettik/LECA/ENVIRONMENT
# Load the LECA envoronement
. ${LECA_ENVIRONEMENT}/etc/bashrc
# Lock files are stored in a common place
LOCK_DIR="${LECA_ENVIRONEMENT}/locks"
# All the data shared among users can be stored here
DATA_DIR="${LECA_ENVIRONEMENT}/data"
# All the molecular public databases downloaded for users on the luke cluster
# will be downloaded here
BIODATA_DIR="${DATA_DIR}/biodatabase"
# Main directory for the NCBI taxonomy
TAXONOMY_DIR="${BIODATA_DIR}/taxonomy"
TREMBL_DIR="${BIODATA_DIR}/trembl"
SWISSPROT_DIR="${BIODATA_DIR}/swissprot"
function latest_taxonomy() {
echo "${TAXONOMY_DIR}/$(ls -ltr "${BIODATA_DIR}/taxonomy" | awk '/^d/ {print $NF}' | tail -1)"
}
else
logwarning Script is not running on the LUKE cluster
if onfroggy ; then
logdebug Script run on the FROGGY cluster
# Register scratch_dir as place where to create temp directory
registertmpdir $LOCAL_SCRATCH_DIR
registertmpdir $SHARED_SCRATCH_DIR
else
logwarning Script is not running on the FROGGY cluster
fi
fi
logging.sh 0000664 0000000 0000000 00000004743 13444221025 0027671 0 ustar 00root root 0000000 0000000 LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84 #
# LECA Bash library
#
# The LECA bash library provides a set of function used for helping
# development of bash script mainly to write job script on the luke
# cluster
#
# The files from the LECA Bash library must be sourced from your main script
#
#
# Logging facilities for bash
# ===========================
#
# Provides the following functions:
#
# openlogfile
# Redirected all logging to the file specified by FILENAME.
# If the file already exists, new logs are appened at the end of the file.
# If the file does not exist it is created
#
# closelogfile
# Closes the current logfile and redirect the logging to stderr.
#
# logdebug
# Writes message as a debug level log to the current log file.
#
# loginfo
# Writes message as an info level log to the current log file.
#
# logwarning
# Writes message as a warning level log to the current log file.
#
# logerror
# Writes message as an error level log to the current log file.
#
# setloglevel
# Set the current logging level to the level specified by LEVEL.
# Level is DEBUG, INFO, WARNING or ERROR.
# A log is recorded only when it is submitted with a level
# greater or equal to the current logging level.
#
# All the log will be done on file descriptor 3
# By default file descriptor 3 is redirected to stderr (2)
# By default the logging level is set to WARNING.
# Therefore only WARNING and ERROR messages will be actually logged.
LOG_DEBUG_LEVEL=1
LOG_INFO_LEVEL=2
LOG_WARNING_LEVEL=3
LOG_ERROR_LEVEL=4
LOG_LEVEL=2
exec 3>&2
#####
#
# The logging function
function logdebug() {
if (( LOG_LEVEL <= LOG_DEBUG_LEVEL )); then
echo `date +'%Y-%m-%d %H:%M:%S'` "[DEBUG ] $(hostname).$$ -- $*" 1>&3
fi
}
function loginfo() {
if (( LOG_LEVEL <= LOG_INFO_LEVEL )); then
echo `date +'%Y-%m-%d %H:%M:%S'` "[INFO ] $(hostname).$$ -- $*" 1>&3
fi
}
function logerror() {
if (( LOG_LEVEL <= LOG_ERROR_LEVEL )); then
echo `date +'%Y-%m-%d %H:%M:%S'` "[ERROR ] $(hostname).$$ -- $*" 1>&3
fi
}
function logwarning() {
if (( LOG_LEVEL <= LOG_WARNING_LEVEL )); then
echo `date +'%Y-%m-%d %H:%M:%S'` "[WARNING] $(hostname).$$ -- $*" 1>&3
fi
}
function setloglevel () {
LOG_LEVEL=$(indirect "LOG_${1}_LEVEL")
loginfo "Logging level set to : ${1} ($LOG_LEVEL)"
}
function openlogfile() {
exec 3>> "$1"
LOGFILE="$1"
}
function closelogfile() {
if [[ ! -z "${LOGFILE}" ]]; then
exec 3>&-
exec 3>&2
LOGFILE=""
fi
}
logdebug "Load logging package"
mutex.sh 0000664 0000000 0000000 00000011224 13444221025 0027375 0 ustar 00root root 0000000 0000000 LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84
# LECA Bash library
#
# The LECA bash library provides a set of function used for helping
# development of bash script mainly to write job script on the luke
# cluster
#
# The files from the LECA Bash library must be sourced from your main script
#
#
include logging
logdebug "Load mutex package"
if [[ -z "$LOCK_DIR" ]] ; then
LOCK_DIR="${HOME}/lecalock"
fi
# Create the lockdir if it does not exist
if [[ ! -d "${LOCK_DIR}" ]]; then
mkdir -p "${LOCK_DIR}"
chmod a+rwxt "${LOCK_DIR}"
fi
include clobber
LECA_LOCK_DELAY=2
LECA_LOCK_MAXRETRY=0
function __lockfile__() {
echo "${LOCK_DIR}/__${1}__.lecalock"
}
function __locktag__() {
echo "$(hostname).$$"
}
function trytogetlock() {
local lname="$1"
shift
local mode="user"
logdebug "Try to get lock ${lname}"
if [[ "${1}" == "global" ]]; then
mode="global"
fi
if [[ "${mode}" == "global" ]]; then
name=$(__lockfile__ "${lname}")
else
name=$(__lockfile__ "${lname}.$(whoami)")
fi
local TAG=$(__locktag__)
local retry=0
local notgetlock=1
pushnoclobber
echo "${TAG}" 2>/dev/null 1> "${name}"
notgetlock=$?
popnoclobber
if (( notgetlock > 0 )); then
if [[ $(cat "${name}" 2> /dev/null) == "${TAG}" ]]; then
notgetlock=0
fi
fi
if (( notgetlock == 0 )); then
logdebug "Succeed to get lock ${lname}"
fi
if (( notgetlock > 0 )); then
return $notgetlock
else
chmod a+w "${name}"
return 0
fi
}
function getlock() {
local lname="$1"
shift
local mode="user"
logdebug "Try to get lock ${lname}"
if [[ "${1}" == "global" ]]; then
mode="global"
fi
if [[ "${mode}" == "global" ]]; then
name=$(__lockfile__ "${lname}")
else
name=$(__lockfile__ "${lname}.$(whoami)")
fi
local TAG=$(__locktag__)
local retry=0
local notgetlock=1
while (( notgetlock > 0 && ( LECA_LOCK_MAXRETRY == 0 || retry > LECA_LOCK_MAXRETRY) )); do
pushnoclobber
echo "${TAG}" 2>/dev/null 1> "${name}"
notgetlock=$?
popnoclobber
if (( notgetlock > 0 )); then
if [[ $(cat "${name}" 2> /dev/null) == "${TAG}" ]]; then
notgetlock=0
fi
fi
if (( notgetlock > 0 )); then
logdebug "Failed to get lock ${lname}"
sleep "${LECA_LOCK_DELAY}"
retry=$((retry + 1))
fi
done
if (( notgetlock > 0 )); then
return $notgetlock
else
logdebug "Succeed to get lock ${lname}"
chmod a+w "${name}"
return 0
fi
}
function releaselock() {
local lname="$1"
shift
local mode="user"
logdebug "Try to release lock ${lname}"
if [[ "${1}" == "global" ]]; then
mode="global"
fi
if [[ "${mode}" == "global" ]]; then
name=$(__lockfile__ "${lname}")
else
name=$(__lockfile__ "${lname}.$(whoami)")
fi
local TAG=$(__locktag__)
local LOCK=""
if [[ -f "${name}" ]]; then
LOCK=$(cat "${name}" 2> /dev/null)
else
return 0
fi
if [[ "${LOCK}" == "${TAG}" ]]; then
rm -f "${name}"
logdebug "Lock ${lname} released"
return 0
fi
return 1
}
function getsemaphore() {
local semname="$1"
shift
local maxcount="$1"
shift
local name=""
local mode="user"
if [[ "${1}" == "global" ]]; then
mode="global"
fi
local TAG=$(__locktag__)
local retry=0
local notgetlock=1
while (( notgetlock > 0 && ( LECA_LOCK_MAXRETRY == 0 || retry > LECA_LOCK_MAXRETRY) )); do
local i=0
while (( notgetlock > 0 )) && (( i < maxcount )) ; do
if [[ "${mode}" == "global" ]]; then
name=$(__lockfile__ "${semname}.@${i}")
else
name=$(__lockfile__ "${semname}.$(whoami).@${i}")
fi
pushnoclobber
echo "${TAG}" 2>/dev/null 1> "${name}"
notgetlock=$?
popnoclobber
if (( notgetlock > 0 )); then
i=$((i + 1))
fi
done
if (( notgetlock > 0 )); then
loginfo "Failed to get semaphore $semname"
sleep "${LECA_LOCK_DELAY}"
retry=$((retry + 1))
fi
done
if (( notgetlock > 0 )); then
return $notgetlock
else
chmod a+w "${name}"
return 0
fi
}
function releasesemaphore() {
local name="$1"
shift
local mode="user"
if [[ "${1}" == "global" ]]; then
mode="global"
fi
if [[ "${mode}" == "global" ]]; then
name=$(__lockfile__ "${name}.@*")
else
name=$(__lockfile__ "${name}.$(whoami).@*")
fi
toremove=$(ls -tr $name 2> /dev/null | head -1)
if [[ ! -z "$toremove" ]] ; then
rm -f "$toremove"
return 0
fi
return 1
}
function releaseoldlock() {
local minutes=10
if [[ ! -z "$1" ]]; then
minutes="$1"
fi
for lock in $(find "${LOCK_DIR}" -type f -cmin "+${minutes}" -print); do
rm "${lock}"
loginfo "releasing old lock: ${lock}"
done
}
path.sh 0000664 0000000 0000000 00000003377 13444221025 0027201 0 ustar 00root root 0000000 0000000 LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84 # LECA Bash library
#
# The LECA bash library provides a set of function used for helping
# development of bash script mainly to write job script on the luke
# cluster
#
# The files from the LECA Bash library must be sourced from your main script
#
#
include logging
logdebug "Load path package"
relative2absolute(){
local thePath
if [[ ! "$1" =~ ^/ ]];then
thePath="$PWD/$1"
else
thePath="$1"
fi
echo "$thePath"|(
IFS=/
read -a parr
declare -a outp
for i in "${parr[@]}";do
case "$i" in
''|.) continue ;;
..)
len=${#outp[@]}
if ((len==0));then
continue
else
unset outp[$((len-1))]
fi
;;
*)
len=${#outp[@]}
outp[$len]="$i"
;;
esac
done
echo /"${outp[*]}"
)
}
function absolute2relative() {
# both $1 and $2 are absolute paths beginning with /
# returns relative path to $2/$target from $1/$source
source=$1
target=$2
common_part=$source # for now
result="" # for now
while [[ "${target#$common_part}" == "${target}" ]]; do
# no match, means that candidate common part is not correct
# go up one level (reduce common part)
common_part="$(dirname $common_part)"
# and record that we went back, with correct / handling
if [[ -z $result ]]; then
result=".."
else
result="../$result"
fi
done
if [[ $common_part == "/" ]]; then
# special case for root (no common path)
result="$result/"
fi
# since we now have identified the common part,
# compute the non-common part
forward_part="${target#$common_part}"
# and now stick all parts together
if [[ -n $result ]] && [[ -n $forward_part ]]; then
result="$result$forward_part"
elif [[ -n $forward_part ]]; then
# extra slash removal
result="${forward_part:1}"
fi
echo $result
}
sets.sh 0000664 0000000 0000000 00000002504 13444221025 0027212 0 ustar 00root root 0000000 0000000 LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84
# LECA Bash library
#
# The LECA bash library provides a set of function used for helping
# development of bash script mainly to write job script on the luke
# cluster
#
# The files from the LECA Bash library must be sourced from your main script
#
#
include logging
include ifs
logdebug "Load sets package"
function newset() {
eval declare -a "${1}"
}
function setsize() {
eval "echo \${#${1}[@]}"
}
function setaddvalue() {
local S="${1}"
local V="${2}"
eval $S[$(setsize $S)]=$V
pushifs $'\n'
eval "$S=(\$(echo \"\${$S[*]}\" | sort -u))"
popifs
}
function setdelvalue() {
local S="${1}"
local V="${2}"
pushifs $'\n'
eval "$S=(\$(echo \"\${$S[*]}\" | grep -v \"$V\"))"
popifs
}
function setcontains() {
local S="${1}"
local V="${2}"
pushifs $'\n'
eval "echo \"\${$S[*]}\" | grep -q \"$V\""
popifs
local status=$?
return $status
}
function setunion() {
local S="${1}"
local S1="${2}"
local S2="${3}"
pushifs $'\n'
eval "$S=(\$((echo \"\${$S1[*]}\";echo \"\${$S2[*]}\") | sort -u))"
popifs
}
function setintersec() {
local S="${1}"
local S1="${2}"
local S2="${3}"
pushifs $'\n'
eval "$S=(\$((echo \"\${$S1[*]}\";echo \"\${$S2[*]}\") | \
sort | \
uniq -c | \
awk '(\$1==2)' | \
sed 's/^ *2 //'))"
popifs
}
signal.sh 0000664 0000000 0000000 00000007371 13444221025 0027520 0 ustar 00root root 0000000 0000000 LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84 #
# LECA Bash library
#
# The LECA bash library provides a set of function used for helping
# development of bash script mainly to write job script on the luke
# cluster
#
# The files from the LECA Bash library must be sourced from your main script
#
# For inheritance of the ERR trapping to ON
# Which is not the default behaviour
set -o errtrace
include logging
logdebug "Load trap package"
include stacks
__LECABASH__trap_signal_list__() {
echo $(kill -l \
| sed -E $'s/[ \t]+/@/g' \
| tr '@' '\n' \
| grep '^SIG' \
| sed 's/SIG//') EXIT ERR
}
__LECABASH__trap_signal_code__() {
local signal=$1
echo $(kill -l \
| sed -E $'s/[ \t]+/@/g' \
| sed -E 's/\)@/ /g' \
| tr '@' '\n' \
| grep "SIG${signal}" \
| awk '{print $1}') \
|| echo 0
}
__LECABASH__signal_trap_stack_name__() {
local signal="$1"
local stackname="__LECABASH__signal_${signal}_trap_stack__"
echo $stackname
}
__LECABASH__trap_function__() {
local exitcode="$?"
local signal="$1"
local stackname="$(__LECABASH__signal_trap_stack_name__ ${signal})"
local code="$(__LECABASH__trap_signal_code__ $signal)"
logdebug "Signal ${signal} trapped"
if [[ $(stacksize $stackname) > 0 ]]; then
while popvalue "$stackname" cmd ; do
logdebug "Running ${signal} command : $cmd"
eval "$cmd" \
|| logdebug "Command: '$cmd' generates an error"
done
logdebug "Commands registered on signal $signal run."
fi
if [[ "$signal" != "EXIT" ]]; then
exit "$((128 + code))"
else
exit "$exitcode"
fi
}
__LECABASH__contains__() {
local e match="$1"
shift
for e in "$@"; do
[[ "$e" == "$match" ]] && return 0
done
return 1
}
#
# Check if the signal is already traped by the LECABashLib
#
__LECABASH__istrapregistred__() {
local signal="$1"
local registred=$(trap -p "$signal" \
| grep '__LECABASH__trap_function__' \
| wc -l)
if (( registred == 0 )) ; then
return 1
else
return 0
fi
}
function __LECABASH__registered_trap__() {
local signal="$1"
trap -p "$signal" \
| awk '{$NF=""; \
split($0,parts,"--"); \
print parts[2]}' \
| sed -E 's/^[ '\'']+//' \
| sed -E 's/'\'' +$//'
}
function __LECABASH__kill_running_command__() {
local signal=$1
local pid=$2
loginfo "Sending signal ${signal} to process ${pid}"
kill -s ${signal} ${pid}
}
function registertrap() {
local signal=$1
shift
local cmd="${*}"
local stackname="$(__LECABASH__signal_trap_stack_name__ ${signal})"
if ! __LECABASH__istrapregistred__ "$signal" ; then
newstack $stackname
local oldcmd=$(__LECABASH__registered_trap__ "$signal")
if [[ oldcmd != "" ]] ; then
logdebug "Save previous trap function for signal $signal"
pushvalue "$stackname" "${oldcmd}"
fi
logdebug "Register trap for signal $signal"
trap "__LECABASH__trap_function__ $signal" "$signal"
fi
logdebug "Register new command on $signal : ${cmd}"
pushvalue "$stackname" "${cmd}"
}
function run() {
local signal=$1
shift
local signalto=$1
shift
local stackname="$(__LECABASH__signal_trap_stack_name__ ${signal})"
eval ${*} &
fpid=$!
registertrap ${signal} __LECABASH__kill_running_command__ ${signalto} ${fpid}
killid=$(( $(stacksize "$stackname") - 1 ))
while [ -e /proc/$fpid ]
do
sleep 1
done
logdebug "Remove kill action on $fpid for $signal signal"
eval "${stackname}[${killid}]='sleep 0'"
}
function signalSpy() {
for s in $(__LECABASH__trap_signal_list__) ; do
registertrap $s loginfo Signal $s has been emited
done
} stacks.sh 0000664 0000000 0000000 00000003331 13444221025 0027523 0 ustar 00root root 0000000 0000000 LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84
# LECA Bash library
#
# The LECA bash library provides a set of function used for helping
# development of bash script mainly to write job script on the luke
# cluster
#
# The files from the LECA Bash library must be sourced from your main script
#
#
# Provides function for manipulating a stack of values
# ====================================================
#
# Provides function:
#
# - newstack
# Creates a new stack named STACKNAME
#
# - stacksize
# Returns the count of element stored in the stack
#
# - pushvalue
# Adds the value VALUE at the end of the stack STACKNAME
#
# - popvalue
# Pops out the last pushed value of the stack.
# If the stack is already empty the function returns nothing
# and the return status is set to 1 instead of 0 usually
#
include logging
logdebug "Load stacks package"
function newstack() {
logdebug "New stack ${1} created"
eval declare -a "${1}"
}
function stacksize() {
eval "echo \${#${1}[@]}"
}
function pushvalue() {
logdebug "New value pushed on stack ${1}"
p="${1}[$(stacksize ${1})]=\"${2}\""
eval "$p"
}
function popvalue() {
local __popvalue_STACK="${1}"
shift
logdebug "New value poped from stack ${__popvalue_STACK}"
if [[ ! -z "${1}" ]]; then
local __popvalue_COMMAND="${1}="
else
local __popvalue_COMMAND="echo "
fi
local __popvalue_s=$(stacksize ${__popvalue_STACK})
if (( __popvalue_s == 0 )); then
return 1
fi
local __popvalue_valcmd="${__popvalue_COMMAND}\${${__popvalue_STACK}[\$(( __popvalue_s - 1 ))]}"
eval $__popvalue_valcmd
__popvalue_valcmd="unset ${__popvalue_STACK}[\$(( __popvalue_s - 1 ))]"
eval $__popvalue_valcmd
return 0
}
tempdir.sh 0000664 0000000 0000000 00000005073 13444221025 0027704 0 ustar 00root root 0000000 0000000 LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84
# LECA Bash library
#
# The LECA bash library provides a set of function used for helping
# development of bash script mainly to write job script on the luke
# cluster
#
# The files from the LECA Bash library must be sourced from your main script
#
#
include logging
logdebug "Load tempdir package"
include ifs
include stacks
include atexit
newstack __LECABASHLIB_BASETMPDIRSTACK__
newstack __LECABASHLIB_TMPDIRSTACK__
__LECABASHLIB_TMPBASENAME__="__tmp__$(whoami).${$}__lecabashlib__.XXXXX"
function __remove_tmp__() {
loginfo "Cleaning temporary directories"
while popvalue __LECABASHLIB_TMPDIRSTACK__ directory ; do
loginfo "Removing tempdir : $directory"
rm -rf "$directory"
done
}
registeratexit __remove_tmp__
function availabledisk() {
local FILENAME="${1}"
pushifs $'\n'
local lines=( $(df -k -P "${FILENAME}") )
pushifs ' '
local fields=(${lines[0]})
local values=(${lines[1]})
popifs
popifs
nfield=${#fields[@]}
i=0
while (( i < nfield )) && [[ "$(lower ${fields[$i]})" != "available" ]] ; do
i=$(( i + 1 ))
done
if (( i < nfield )) ; then
size=$(( values[i] / 1024 / 1024 ))
echo $size
return 0
else
return 1
fi
}
function registertmpdir() {
pushvalue __LECABASHLIB_BASETMPDIRSTACK__ "${1}"
}
function getbasetmpdir() {
echo "${__LECABASHLIB_BASETMPDIRSTACK__[*]}"
}
function tempdirectory() {
local __tempdirectory_minsize="0"
if [[ ! -z "${1}" ]]; then
local __tempdirectory_COMMAND="${1}="
else
local __tempdirectory_COMMAND="echo "
fi
shift
if [[ "$(stacksize __LECABASHLIB_BASETMPDIRSTACK__)" == "0" ]]; then
if [[ ! -z "$TMPDIR" ]] ; then
registertmpdir "$TMPDIR"
else
mkdir -p "$HOME/tmp"
registertmpdir "$HOME/tmp"
fi
fi
if [[ ! -z "${1}" ]] ; then
__tempdirectory_minsize="${1}"
fi
local __tempdirectory_nbase=$(stacksize __LECABASHLIB_BASETMPDIRSTACK__)
local __tempdirectory_i=0
while (( __tempdirectory_i < __tempdirectory_nbase )) && \
(( $(availabledisk "${__LECABASHLIB_BASETMPDIRSTACK__[$i]}") < __tempdirectory_minsize )) ; do
__tempdirectory_i=$(( __tempdirectory_i + 1 ))
done
if (( __tempdirectory_i >= __tempdirectory_nbase )) ; then
return 1
fi
local __tempdirectory_basedir="${__LECABASHLIB_BASETMPDIRSTACK__[$__tempdirectory_i]}"
local __tempdirectory_directory=$(mktemp -d "${__tempdirectory_basedir%/}/${__LECABASHLIB_TMPBASENAME__}")
pushvalue __LECABASHLIB_TMPDIRSTACK__ "$__tempdirectory_directory"
local __tempdirectory_valcmd="${__tempdirectory_COMMAND}${__tempdirectory_directory}"
eval $__tempdirectory_valcmd
}
timeout.sh 0000664 0000000 0000000 00000001551 13444221025 0027723 0 ustar 00root root 0000000 0000000 LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84 #
# LECA Bash library
#
# The LECA bash library provides a set of function used for helping
# development of bash script mainly to write job script on the luke
# cluster
#
# The files from the LECA Bash library must be sourced from your main script
#
include logging
logdebug "Load timeout package"
function timeoutcmd() {
local seconde=$1
shift
$* &
local mainpid=$!
sleep $seconde &
local sleeppid=$!
local nproc=$(ps $mainpid $sleeppid | tail -n +2 | wc -l)
while (( nproc > 1 )) ; do
sleep 1
nproc=$(ps $mainpid $sleeppid | tail -n +2 | wc -l)
done
local timealive=$(ps $sleeppid | tail -n +2 | wc -l)
if (( timealive > 0 )) ; then
kill -9 $sleeppid
else
if (( $(ps $mainpid | tail -n +2 | wc -l) > 0 )) ; then
kill -9 $mainpid
logwarning "Timeout after ${seconde}s on command : $*"
return 1
fi
fi
} LECABashLib-37f67e5096816ca93582a03b4f351b02deefeb84-37f67e5096816ca93582a03b4f351b02deefeb84/xml.sh0000664 0000000 0000000 00000004101 13444221025 0027106 0 ustar 00root root 0000000 0000000 #
# LECA Bash library
#
# The LECA bash library provides a set of function used for helping
# development of bash script mainly to write job script on the luke
# cluster
#
# The files from the LECA Bash library must be sourced from your main script
#
include logging
logdebug "Load XML package"
include stacks
######
#
# XML formating function
#
newstack __LECABASH__markup__
function __LECABASH__XML_pad__() {
local pad=$(printf '%0.1s' " "{1..60})
local padlength=$(( $1 * 2 ))
printf '%*.*s' 0 "$padlength" "$pad"
}
function XML_header() {
echo ''
}
function XML_push() {
local i=0
local k
local l
local tag=$1
shift
local attribs=( $(echo "$*") )
__LECABASH__XML_pad__ $(stacksize __LECABASH__markup__)
echo -n "<${tag}"
local n=${#attribs[@]}
n=$((n/2))
logdebug "XML_push ${tag} : $n attributes specified"
if (( n > 0 )) ; then
for (( i=0; i"
pushvalue __LECABASH__markup__ "${tag}"
}
function XML_pop() {
local tag=""
popvalue __LECABASH__markup__ tag
__LECABASH__XML_pad__ $(stacksize __LECABASH__markup__)
echo "${tag}>"
}
function XML_tag_data() {
local tag=$1
shift
__LECABASH__XML_pad__ $(stacksize __LECABASH__markup__)
echo "<${tag}>$*${tag}>"
}
function XML_tag_attr_data() {
local i=0
local k
local l
local tag=$1
shift
local attribs=( $(echo "$*") )
__LECABASH__XML_pad__ $(stacksize __LECABASH__markup__)
echo -n "<${tag}"
local n=${#attribs[@]}
((n/=2))
if (( n > 0 )) ; then
for (( i=0; i$*${tag}>"
}
function XML_empty_tag() {
local tag=$1
shift
__LECABASH__XML_pad__ $(stacksize __LECABASH__markup__)
echo "<${tag}/>"
}
function XML_data() {
__LECABASH__XML_pad__ $(stacksize __LECABASH__markup__)
echo "$*"
}