Compare commits
171 Commits
Author | SHA1 | Date |
---|---|---|
Jephté Clain | 914de961eb | |
Jephté Clain | 6e83cdb819 | |
Jephté Clain | 10d013d3ff | |
Jephté Clain | 4a7e4cac68 | |
Jephté Clain | 0ac99051c1 | |
Jephté Clain | eec8925934 | |
Jephté Clain | f0280596a8 | |
Jephté Clain | 92827bf0c1 | |
Jephté Clain | c4afe0b21e | |
Jephté Clain | 09b68a9335 | |
Jephté Clain | 3badf2c1bb | |
Jephté Clain | 48e0011790 | |
Jephté Clain | b763066f8a | |
Jephté Clain | bb7428d80a | |
Jephté Clain | 8b7dab9905 | |
Jephté Clain | 7e8901a7f6 | |
Jephté Clain | 438b63f8e0 | |
Jephté Clain | d923ec8940 | |
Jephté Clain | 756b61586e | |
Jephté Clain | 6dcf9e8fed | |
Jephté Clain | 5000baa6a1 | |
Jephté Clain | 2adaaf5d1e | |
Jephté Clain | 1bc0534780 | |
Jephté Clain | 3bbcdd1f8b | |
Jephté Clain | 2e6c8219df | |
Jephté Clain | f465b3b175 | |
Jephté Clain | 94e4af7012 | |
Jephté Clain | 5a5f0e9c93 | |
Jephté Clain | d68cf2b052 | |
Jephté Clain | 73432809ad | |
Jephté Clain | 54ec7e7d94 | |
Jephté Clain | 13de7abd40 | |
Jephté Clain | a8d8acaa3c | |
Jephté Clain | b8c9e7d334 | |
Jephté Clain | c1bd66d91b | |
Jephté Clain | a590cd1c17 | |
Jephté Clain | 416d0a44d4 | |
Jephté Clain | d2d77bca0b | |
Jephté Clain | fa8fd6e7c3 | |
Jephté Clain | 350622997c | |
Jephté Clain | ae96d97566 | |
Jephté Clain | 6755323cc5 | |
Jephté Clain | 08a1ce49c5 | |
Jephté Clain | 286fce6cca | |
Jephté Clain | cd09a07cda | |
Jephté Clain | ac4b03dff7 | |
Jephté Clain | 455f658243 | |
Jephté Clain | 42253c963e | |
Jephté Clain | 44e0a784ca | |
Jephté Clain | a78d93e510 | |
Jephté Clain | 5e095a5579 | |
Jephté Clain | c2408f768f | |
Jephté Clain | c8aee44c2a | |
Jephté Clain | 006964df45 | |
Jephté Clain | e78becb92a | |
Jephté Clain | 1e481044eb | |
Jephté Clain | 34f48d4714 | |
Jephté Clain | f94db2a69d | |
Jephté Clain | f42dcb978a | |
Jephté Clain | cbe26be1dc | |
Jephté Clain | badf5e109c | |
Jephté Clain | 5460903a9f | |
Jephté Clain | 451b2768e6 | |
Jephté Clain | fa2dffdfbe | |
Jephté Clain | ff1fe2c103 | |
Jephté Clain | 2f1f401846 | |
Jephté Clain | aa4fae3b97 | |
Jephté Clain | 037faa4786 | |
Jephté Clain | b8241a2994 | |
Jephté Clain | fa7eeb0237 | |
Jephté Clain | 171a6703db | |
Jephté Clain | df391263d4 | |
Jephté Clain | 5d9495b1ac | |
Jephté Clain | 9b0a98acc3 | |
Jephté Clain | b12949d3ea | |
Jephté Clain | f572282784 | |
Jephté Clain | da641d87ae | |
Jephté Clain | bc14f4b4ca | |
Jephté Clain | a02d25f8d1 | |
Jephté Clain | 55bcbacb7c | |
Jephté Clain | 0673acfc3a | |
Jephté Clain | c838581ac2 | |
Jephté Clain | 635e513a8b | |
Jephté Clain | 2ca4332063 | |
Jephté Clain | e79e74d379 | |
Jephté Clain | ce9e9e5d02 | |
Jephté Clain | 75de50f5d8 | |
Jephté Clain | c470c00c34 | |
Jephté Clain | 739aed8f5e | |
Jephté Clain | e34adce260 | |
Jephté Clain | 01ed9758d5 | |
Jephté Clain | eead65706d | |
Jephté Clain | 0a868dd179 | |
Jephté Clain | 52f54e1751 | |
Jephté Clain | ba33c7815f | |
Jephté Clain | f659f293cb | |
Jephté Clain | 7cbddf02a3 | |
Jephté Clain | 12344f7b14 | |
Jephté Clain | e723f9bd3e | |
Jephté Clain | 3f47c40a0e | |
Jephté Clain | 9fea3c603b | |
Jephté Clain | b7586b92d0 | |
Jephté Clain | b8f3614d0a | |
Jephté Clain | dc5c078213 | |
Jephté Clain | e4518ebe81 | |
Jephté Clain | 5988637a41 | |
Jephté Clain | 4b60232dfb | |
Jephté Clain | 41f217fd76 | |
Jephté Clain | 537263216e | |
Jephté Clain | 3734e0b3c7 | |
Jephté Clain | a9ce46da89 | |
Jephté Clain | d5cae312cc | |
Jephté Clain | 6f6aad9c05 | |
Jephté Clain | 4a16469559 | |
Jephté Clain | 71035b2b59 | |
Jephté Clain | 2964153e54 | |
Jephté Clain | 48d2c4aabf | |
Jephté Clain | dd9a8e8256 | |
Jephté Clain | 3f357c9d45 | |
Jephté Clain | b4de22cc74 | |
Jephté Clain | a5d1485ecf | |
Jephté Clain | 506fbb1390 | |
Jephté Clain | 255a68315a | |
Jephté Clain | b817ad6c98 | |
Jephté Clain | 080ccc4f4d | |
Jephté Clain | 43b7b046fa | |
Jephté Clain | 8cf225ea1e | |
Jephté Clain | 3def66748b | |
Jephté Clain | d7323d7d45 | |
Jephté Clain | 69f3ab76b1 | |
Jephté Clain | 04e25b5700 | |
Jephté Clain | d44937132a | |
Jephté Clain | 3fc5f05f5d | |
Jephté Clain | 2b10acacb2 | |
Jephté Clain | 5afd3f6666 | |
Jephté Clain | 42b18bf663 | |
Jephté Clain | ae65a36505 | |
Jephté Clain | 0009fe55d5 | |
Jephté Clain | 2b90be29f8 | |
Jephté Clain | b605477c54 | |
Jephté Clain | 5760be32e4 | |
Jephté Clain | 633b554547 | |
Jephté Clain | af332ea961 | |
Jephté Clain | a1f88e9d38 | |
Jephté Clain | 7cac433cbc | |
Jephté Clain | e978d18fc8 | |
Jephté Clain | 861d39974f | |
Jephté Clain | 1d53f41ef4 | |
Jephté Clain | 1aee701fef | |
Jephté Clain | 4a0006724e | |
Jephté Clain | 2e037cfa68 | |
Jephté Clain | f4fa9fa28c | |
Jephté Clain | 19ca7cfbd3 | |
Jephté Clain | 6e088c51a2 | |
Jephté Clain | 2e8d0ac010 | |
Jephté Clain | 5f15e1ea8c | |
Jephté Clain | b6a95259a7 | |
Jephté Clain | 4b15b8f600 | |
Jephté Clain | f9f16ee0f1 | |
Jephté Clain | 375dbc5042 | |
Jephté Clain | bfb184be58 | |
Jephté Clain | e9bbc93a96 | |
Jephté Clain | 65446a33b4 | |
Jephté Clain | ce5b166f59 | |
Jephté Clain | 9f0d97fc0a | |
Jephté Clain | e47fa53336 | |
Jephté Clain | 9f06ffa6f4 | |
Jephté Clain | 5c2dd610ef | |
Jephté Clain | 8d55a931d2 | |
Jephté Clain | 5d86f60b11 | |
Jephté Clain | eba69bea41 |
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +1,4 @@
|
||||||
# -*- coding: utf-8 mode: yaml -*- vim:sw=2:sts=2:et:ai:si:sta:fenc=utf-8
|
# -*- coding: utf-8 mode: yaml -*- vim:sw=2:sts=2:et:ai:si:sta:fenc=utf-8
|
||||||
composer_php_min: '7.3'
|
|
||||||
composer_php_max: '8.0'
|
|
||||||
composer_registry: pubdocker.univ-reunion.fr
|
|
||||||
composer_image: image/phpbuilder:d10
|
|
||||||
require:
|
require:
|
||||||
branch:
|
branch:
|
||||||
master:
|
master:
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Editor-based HTTP Client requests
|
|
||||||
/httpRequests/
|
|
||||||
# Datasource local storage ignored files
|
|
||||||
/dataSources/
|
|
||||||
/dataSources.local.xml
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Codeception">
|
||||||
|
<option name="configurations">
|
||||||
|
<list>
|
||||||
|
<Configuration>
|
||||||
|
<option name="path" value="$PROJECT_DIR$/tests" />
|
||||||
|
</Configuration>
|
||||||
|
<Configuration>
|
||||||
|
<option name="path" value="$PROJECT_DIR$/tests" />
|
||||||
|
</Configuration>
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -2,8 +2,8 @@
|
||||||
<module type="WEB_MODULE" version="4">
|
<module type="WEB_MODULE" version="4">
|
||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/php/src_base" isTestSource="false" packagePrefix="nulib\" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/php/tests" isTestSource="true" packagePrefix="nulib\" />
|
<sourceFolder url="file://$MODULE_DIR$/php/tests" isTestSource="true" packagePrefix="nulib\" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/php/src" isTestSource="false" packagePrefix="nulib\" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor" />
|
<excludeFolder url="file://$MODULE_DIR$/vendor" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
|
|
|
@ -12,39 +12,39 @@
|
||||||
</component>
|
</component>
|
||||||
<component name="PhpIncludePathManager">
|
<component name="PhpIncludePathManager">
|
||||||
<include_path>
|
<include_path>
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/composer" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
|
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
|
||||||
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
||||||
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
|
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
|
||||||
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/resource-operations" />
|
<path value="$PROJECT_DIR$/vendor/sebastian/resource-operations" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/nulib/tests" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit" />
|
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit" />
|
||||||
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
|
|
||||||
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
|
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
|
||||||
<path value="$PROJECT_DIR$/vendor/mur/tests" />
|
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
|
||||||
</include_path>
|
</include_path>
|
||||||
</component>
|
</component>
|
||||||
<component name="PhpProjectSharedConfiguration" php_language_level="7.3" />
|
<component name="PhpProjectSharedConfiguration" php_language_level="7.4" />
|
||||||
<component name="PhpStanOptionsConfiguration">
|
<component name="PhpStanOptionsConfiguration">
|
||||||
<option name="transferred" value="true" />
|
<option name="transferred" value="true" />
|
||||||
</component>
|
</component>
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="PHPSpec">
|
||||||
|
<suites>
|
||||||
|
<PhpSpecSuiteConfiguration>
|
||||||
|
<option name="myPath" value="$PROJECT_DIR$" />
|
||||||
|
</PhpSpecSuiteConfiguration>
|
||||||
|
<PhpSpecSuiteConfiguration>
|
||||||
|
<option name="myPath" value="$PROJECT_DIR$" />
|
||||||
|
</PhpSpecSuiteConfiguration>
|
||||||
|
</suites>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="PHPUnit">
|
||||||
|
<option name="directories">
|
||||||
|
<list>
|
||||||
|
<option value="$PROJECT_DIR$/tests" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -2,6 +2,5 @@
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="" vcs="Git" />
|
<mapping directory="" vcs="Git" />
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
|
@ -0,0 +1,8 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
|
||||||
|
# Chemin vers runphp, e.g sbin/runphp
|
||||||
|
RUNPHP=
|
||||||
|
|
||||||
|
# Si RUNPHP n'est pas défini, les variables suivantes peuvent être définies
|
||||||
|
DIST=d11
|
||||||
|
#REGISTRY=pubdocker.univ-reunion.fr
|
|
@ -0,0 +1,30 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
# Utiliser 'udir --help-vars' pour une description de la signification des
|
||||||
|
# variables suivantes:
|
||||||
|
udir_desc="librairies de base pour scripts bash, awk, php, python"
|
||||||
|
udir_note=""
|
||||||
|
udir_types=(uinst)
|
||||||
|
uinc=release
|
||||||
|
uinc_options=()
|
||||||
|
uinc_args=()
|
||||||
|
preconfig_scripts=()
|
||||||
|
configure_variables=(dest)
|
||||||
|
configure_dest_for=(lib/profile.d/nulib)
|
||||||
|
config_scripts=(lib/uinst/conf)
|
||||||
|
install_profiles=true
|
||||||
|
profiledir=lib/profile.d
|
||||||
|
bashrcdir=lib/bashrc.d
|
||||||
|
defaultdir=lib/default
|
||||||
|
workdir_rsync_options=()
|
||||||
|
workdir_excludes=()
|
||||||
|
workdir_includes=()
|
||||||
|
copy_files=true
|
||||||
|
destdir=/opt
|
||||||
|
destdir_override_userhost=
|
||||||
|
destdir_ssh=
|
||||||
|
destdir_force_remote=
|
||||||
|
srcdir=.
|
||||||
|
files=()
|
||||||
|
owner=root:
|
||||||
|
modes=(u=rwX,g=rX,o=rX)
|
||||||
|
root_scripts=(lib/uinst/rootconf)
|
|
@ -0,0 +1,15 @@
|
||||||
|
# nulib
|
||||||
|
|
||||||
|
* runners
|
||||||
|
* [ ] rnlphp -- lancer un programme php avec la bonne version (+docker le cas échéant)
|
||||||
|
* [ ] utilisable en shebang
|
||||||
|
* [ ] utilisable en tant que lien: lance `../php/bin/$MYNAME.php`
|
||||||
|
* [ ] frontend pour composer
|
||||||
|
* [ ] rnljava -- lancer un programme java avec la bonne version (+docker le cas échéant)
|
||||||
|
* [ ] frontend pour maven
|
||||||
|
* [ ] rnlawk -- lancer un script awk
|
||||||
|
* [ ] rnlpy3 -- lancer un script python3
|
||||||
|
* [ ] rnlsh -- lancer un shell avec les librairies bash / lancer un script
|
||||||
|
* MYTRUEDIR, MYTRUENAME, MYTRUESELF -- résoudre les liens symboliques
|
||||||
|
|
||||||
|
-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary
|
|
@ -0,0 +1,157 @@
|
||||||
|
# -*- coding: utf-8 mode: awk -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
|
||||||
|
function mkindices(values, indices, i, j) {
|
||||||
|
array_new(indices)
|
||||||
|
j = 1
|
||||||
|
for (i in values) {
|
||||||
|
indices[j++] = int(i)
|
||||||
|
}
|
||||||
|
return asort(indices)
|
||||||
|
}
|
||||||
|
function array_new(dest) {
|
||||||
|
dest[0] = 0 # forcer awk à considérer dest comme un tableau
|
||||||
|
delete dest
|
||||||
|
}
|
||||||
|
function array_newsize(dest, size, i) {
|
||||||
|
dest[0] = 0 # forcer awk à considérer dest comme un tableau
|
||||||
|
delete dest
|
||||||
|
size = int(size)
|
||||||
|
for (i = 1; i <= size; i++) {
|
||||||
|
dest[i] = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function array_len(values, count, i) {
|
||||||
|
# length(array) a un bug sur awk 3.1.5
|
||||||
|
# cette version est plus lente mais fonctionne toujours
|
||||||
|
count = 0
|
||||||
|
for (i in values) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
function array_copy(dest, src, count, indices, i) {
|
||||||
|
array_new(dest)
|
||||||
|
count = mkindices(src, indices)
|
||||||
|
for (i = 1; i <= count; i++) {
|
||||||
|
dest[indices[i]] = src[indices[i]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function array_getlastindex(src, count, indices) {
|
||||||
|
count = mkindices(src, indices)
|
||||||
|
if (count == 0) return 0
|
||||||
|
return indices[count]
|
||||||
|
}
|
||||||
|
function array_add(dest, value, lastindex) {
|
||||||
|
lastindex = array_getlastindex(dest)
|
||||||
|
dest[lastindex + 1] = value
|
||||||
|
}
|
||||||
|
function array_deli(dest, i, l) {
|
||||||
|
i = int(i)
|
||||||
|
if (i == 0) return
|
||||||
|
l = array_len(dest)
|
||||||
|
while (i < l) {
|
||||||
|
dest[i] = dest[i + 1]
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
delete dest[l]
|
||||||
|
}
|
||||||
|
function array_del(dest, value, ignoreCase, i) {
|
||||||
|
do {
|
||||||
|
i = key_index(value, dest, ignoreCase)
|
||||||
|
if (i != 0) array_deli(dest, i)
|
||||||
|
} while (i != 0)
|
||||||
|
}
|
||||||
|
function array_extend(dest, src, count, lastindex, indices, i) {
|
||||||
|
lastindex = array_getlastindex(dest)
|
||||||
|
count = mkindices(src, indices)
|
||||||
|
for (i = 1; i <= count; i++) {
|
||||||
|
dest[lastindex + i] = src[indices[i]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function array_fill(dest, i) {
|
||||||
|
array_new(dest)
|
||||||
|
for (i = 1; i <= NF; i++) {
|
||||||
|
dest[i] = $i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function array_getline(src, count, indices, i, j) {
|
||||||
|
$0 = ""
|
||||||
|
count = mkindices(src, indices)
|
||||||
|
for (i = 1; i <= count; i++) {
|
||||||
|
j = indices[i]
|
||||||
|
$j = src[j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function array_appendline(src, count, indices, i, nf, j) {
|
||||||
|
count = mkindices(src, indices)
|
||||||
|
nf = NF
|
||||||
|
for (i = 1; i <= count; i++) {
|
||||||
|
j = nf + indices[i]
|
||||||
|
$j = src[indices[i]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function in_array(value, values, ignoreCase, i) {
|
||||||
|
if (ignoreCase) {
|
||||||
|
value = tolower(value)
|
||||||
|
for (i in values) {
|
||||||
|
if (tolower(values[i]) == value) return 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i in values) {
|
||||||
|
if (values[i] == value) return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
function key_index(value, values, ignoreCase, i) {
|
||||||
|
if (ignoreCase) {
|
||||||
|
value = tolower(value)
|
||||||
|
for (i in values) {
|
||||||
|
if (tolower(values[i]) == value) return int(i)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i in values) {
|
||||||
|
if (values[i] == value) return int(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
function array2s(values, prefix, sep, suffix, noindices, first, i, s) {
|
||||||
|
if (!prefix) prefix = "["
|
||||||
|
if (!sep) sep = ", "
|
||||||
|
if (!suffix) suffix = "]"
|
||||||
|
s = prefix
|
||||||
|
first = 1
|
||||||
|
for (i in values) {
|
||||||
|
if (first) first = 0
|
||||||
|
else s = s sep
|
||||||
|
if (!noindices) s = s "[" i "]="
|
||||||
|
s = s values[i]
|
||||||
|
}
|
||||||
|
s = s suffix
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
function array2so(values, prefix, sep, suffix, noindices, count, indices, i, s) {
|
||||||
|
if (!prefix) prefix = "["
|
||||||
|
if (!sep) sep = ", "
|
||||||
|
if (!suffix) suffix = "]"
|
||||||
|
s = prefix
|
||||||
|
count = mkindices(values, indices)
|
||||||
|
for (i = 1; i <= count; i++) {
|
||||||
|
if (i > 1) s = s sep
|
||||||
|
if (!noindices) s = s "[" indices[i] "]="
|
||||||
|
s = s values[indices[i]]
|
||||||
|
}
|
||||||
|
s = s suffix
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
function array_join(values, sep, prefix, suffix, count, indices, i, s) {
|
||||||
|
s = prefix
|
||||||
|
count = mkindices(values, indices)
|
||||||
|
for (i = 1; i <= count; i++) {
|
||||||
|
if (i > 1) s = s sep
|
||||||
|
s = s values[indices[i]]
|
||||||
|
}
|
||||||
|
s = s suffix
|
||||||
|
return s
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
# -*- coding: utf-8 mode: awk -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
@include "base.core.awk"
|
||||||
|
@include "base.array.awk"
|
||||||
|
@include "base.date.awk"
|
||||||
|
@include "base.tools.awk"
|
|
@ -0,0 +1,141 @@
|
||||||
|
# -*- coding: utf-8 mode: awk -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
|
||||||
|
function num(s) {
|
||||||
|
if (s ~ /^[0-9]+$/) return int(s)
|
||||||
|
else return s
|
||||||
|
}
|
||||||
|
function ord(s, i) {
|
||||||
|
s = substr(s, 1, 1)
|
||||||
|
i = index(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", s)
|
||||||
|
if (i != 0) i += 32 - 1
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
function hex(i, s) {
|
||||||
|
s = sprintf("%x", i)
|
||||||
|
if (length(s) < 2) s = "0" s
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
function qhtml(s) {
|
||||||
|
gsub(/&/, "\\&", s)
|
||||||
|
gsub(/"/, "\\"", s)
|
||||||
|
gsub(/>/, "\\>", s)
|
||||||
|
gsub(/</, "\\<", s)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
function unquote_html(s) {
|
||||||
|
gsub(/</, "<", s)
|
||||||
|
gsub(/>/, ">", s)
|
||||||
|
gsub(/"/, "\"", s)
|
||||||
|
gsub(/&/, "\\&", s)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
function qawk(s) {
|
||||||
|
gsub(/\\/, "\\\\", s)
|
||||||
|
gsub(/"/, "\\\"", s)
|
||||||
|
gsub(/\n/, "\\n", s)
|
||||||
|
return "\"" s "\""
|
||||||
|
}
|
||||||
|
function qval(s) {
|
||||||
|
gsub(/'/, "'\\''", s)
|
||||||
|
return "'" s "'"
|
||||||
|
}
|
||||||
|
function sqval(s) {
|
||||||
|
return " " qval(s)
|
||||||
|
}
|
||||||
|
function qvals( i, line) {
|
||||||
|
line = ""
|
||||||
|
for (i = 1; i <= NF; i++) {
|
||||||
|
if (i > 1) line = line " "
|
||||||
|
line = line qval($i)
|
||||||
|
}
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
function sqvals() {
|
||||||
|
return " " qvals()
|
||||||
|
}
|
||||||
|
function qarr(values, prefix, i, count, line) {
|
||||||
|
line = prefix
|
||||||
|
count = array_len(values)
|
||||||
|
for (i = 1; i <= count; i++) {
|
||||||
|
if (i > 1 || line != "") line = line " "
|
||||||
|
line = line qval(values[i])
|
||||||
|
}
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
function qregexp(s) {
|
||||||
|
gsub(/[[\\.^$*+?()|{]/, "\\\\&", s)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
function qsubrepl(s) {
|
||||||
|
gsub(/\\/, "\\\\", s)
|
||||||
|
gsub(/&/, "\\\\&", s)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
function qgrep(s) {
|
||||||
|
gsub(/[[\\.^$*]/, "\\\\&", s)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
function qegrep(s) {
|
||||||
|
gsub(/[[\\.^$*+?()|{]/, "\\\\&", s)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
function qsql(s, suffix) {
|
||||||
|
gsub(/'/, "''", s)
|
||||||
|
return "'" s "'" (suffix != ""? " " suffix: "")
|
||||||
|
}
|
||||||
|
function cqsql(s, suffix) {
|
||||||
|
return "," qsql(s, suffix)
|
||||||
|
}
|
||||||
|
function unquote_mysqlcsv(s) {
|
||||||
|
gsub(/\\n/, "\n", s)
|
||||||
|
gsub(/\\t/, "\t", s)
|
||||||
|
gsub(/\\0/, "\0", s)
|
||||||
|
gsub(/\\\\/, "\\", s)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
function sval(s) {
|
||||||
|
if (s == "") return s
|
||||||
|
else return " " s
|
||||||
|
}
|
||||||
|
function cval(s, suffix) {
|
||||||
|
suffix = suffix != ""? " " suffix: ""
|
||||||
|
if (s == "") return s
|
||||||
|
else return "," s suffix
|
||||||
|
}
|
||||||
|
|
||||||
|
function printto(s, output) {
|
||||||
|
if (output == "") {
|
||||||
|
print s
|
||||||
|
} else if (output ~ /^>>/) {
|
||||||
|
sub(/^>>/, "", output)
|
||||||
|
print s >>output
|
||||||
|
} else if (output ~ /^>/) {
|
||||||
|
sub(/^>/, "", output)
|
||||||
|
print s >output
|
||||||
|
} else if (output ~ /^\|&/) {
|
||||||
|
sub(/^\|&/, "", output)
|
||||||
|
print s |&output
|
||||||
|
} else if (output ~ /^\|/) {
|
||||||
|
sub(/^\|/, "", output)
|
||||||
|
print s |output
|
||||||
|
} else {
|
||||||
|
print s >output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function find_line(input, field, value, orig, line) {
|
||||||
|
orig = $0
|
||||||
|
line = ""
|
||||||
|
while ((getline <input) > 0) {
|
||||||
|
if ($field == value) {
|
||||||
|
line = $0
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(input)
|
||||||
|
$0 = orig
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
function merge_line(input, field, key, line) {
|
||||||
|
line = find_line(input, field, $key)
|
||||||
|
if (line != "") $0 = $0 FS line
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
# -*- coding: utf-8 mode: awk -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
|
||||||
|
function date__parse_fr(date, parts, y, m, d) {
|
||||||
|
if (match(date, /([0-9][0-9]?)\/([0-9][0-9]?)\/([0-9][0-9][0-9][0-9])/, parts)) {
|
||||||
|
y = int(parts[3])
|
||||||
|
m = int(parts[2])
|
||||||
|
d = int(parts[1])
|
||||||
|
return mktime(sprintf("%04i %02i %02i 00 00 00 +0400", y, m, d))
|
||||||
|
} else if (match(date, /([0-9][0-9]?)\/([0-9][0-9]?)\/([0-9][0-9])/, parts)) {
|
||||||
|
basey = int(strftime("%Y")); basey = basey - basey % 100
|
||||||
|
y = basey + int(parts[3])
|
||||||
|
m = int(parts[2])
|
||||||
|
d = int(parts[1])
|
||||||
|
return mktime(sprintf("%04i %02i %02i 00 00 00 +0400", y, m, d))
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
function date__parse_mysql(date, parts, y, m, d) {
|
||||||
|
if (match(date, /([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])/, parts)) {
|
||||||
|
y = int(parts[1])
|
||||||
|
m = int(parts[2])
|
||||||
|
d = int(parts[3])
|
||||||
|
return mktime(sprintf("%04i %02i %02i 00 00 00 +0400", y, m, d))
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
function date__parse_any(date, serial) {
|
||||||
|
serial = date__parse_fr(date)
|
||||||
|
if (serial == -1) serial = date__parse_mysql(date)
|
||||||
|
return serial
|
||||||
|
}
|
||||||
|
function date_serial(date) {
|
||||||
|
return date__parse_any(date)
|
||||||
|
}
|
||||||
|
function date_parse(date, serial) {
|
||||||
|
serial = date__parse_any(date)
|
||||||
|
if (serial == -1) return date
|
||||||
|
return strftime("%d/%m/%Y", serial)
|
||||||
|
}
|
||||||
|
function date_monday(date, serial, dow) {
|
||||||
|
serial = date__parse_any(date)
|
||||||
|
if (serial == -1) return date
|
||||||
|
dow = strftime("%u", serial)
|
||||||
|
serial -= (dow - 1) * 86400
|
||||||
|
return strftime("%d/%m/%Y", serial)
|
||||||
|
}
|
||||||
|
function date_add(date, nbdays, serial) {
|
||||||
|
serial = date__parse_any(date)
|
||||||
|
if (serial == -1) return date
|
||||||
|
serial += nbdays * 86400
|
||||||
|
return strftime("%d/%m/%Y", serial)
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
BEGIN {
|
||||||
|
srand()
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_random_password( password, max, LETTERS) {
|
||||||
|
LETTERS = "AZERTYUIOPQSDFGHJKLMWXCVBNazertyuiopqsdfghjklmwxcvbn0123456789"
|
||||||
|
max = length(LETTERS)
|
||||||
|
password = ""
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
password = password substr(LETTERS, int(rand() * max), 1)
|
||||||
|
}
|
||||||
|
return password
|
||||||
|
}
|
||||||
|
|
||||||
|
function should_generate_password() {
|
||||||
|
return $0 ~ /XXXRANDOMXXX/
|
||||||
|
}
|
||||||
|
function generate_password() {
|
||||||
|
sub(/XXXRANDOMXXX/, get_random_password())
|
||||||
|
}
|
|
@ -0,0 +1,201 @@
|
||||||
|
# -*- coding: utf-8 mode: awk -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
@include "base.core.awk"
|
||||||
|
@include "base.array.awk"
|
||||||
|
|
||||||
|
function csv__parse_quoted(line, destl, colsep, qchar, echar, pos, tmpl, nextc, resl) {
|
||||||
|
line = substr(line, 2)
|
||||||
|
resl = ""
|
||||||
|
while (1) {
|
||||||
|
pos = index(line, qchar)
|
||||||
|
if (pos == 0) {
|
||||||
|
# chaine mal terminee
|
||||||
|
resl = resl line
|
||||||
|
destl[0] = ""
|
||||||
|
destl[1] = 0
|
||||||
|
return resl
|
||||||
|
}
|
||||||
|
if (echar != "" && pos > 1) {
|
||||||
|
# tenir compte du fait qu"un caratère peut être mis en échappement
|
||||||
|
prevc = substr(line, pos - 1, 1)
|
||||||
|
quotec = substr(line, pos, 1)
|
||||||
|
nextc = substr(line, pos + 1, 1)
|
||||||
|
if (prevc == echar) {
|
||||||
|
# qchar en échappement
|
||||||
|
tmpl = substr(line, 1, pos - 2)
|
||||||
|
resl = resl tmpl quotec
|
||||||
|
line = substr(line, pos + 1)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tmpl = substr(line, 1, pos - 1)
|
||||||
|
if (nextc == colsep || nextc == "") {
|
||||||
|
# fin de champ ou fin de ligne
|
||||||
|
resl = resl tmpl
|
||||||
|
destl[0] = substr(line, pos + 2)
|
||||||
|
destl[1] = nextc == colsep
|
||||||
|
return resl
|
||||||
|
} else {
|
||||||
|
# erreur de syntaxe: guillemet non mis en échappement
|
||||||
|
# ignorer cette erreur et prendre le guillemet quand meme
|
||||||
|
resl = resl tmpl quotec
|
||||||
|
line = substr(line, pos + 1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# pas d"échappement pour qchar. il est éventuellement doublé
|
||||||
|
tmpl = substr(line, 1, pos - 1)
|
||||||
|
quotec = substr(line, pos, 1)
|
||||||
|
nextc = substr(line, pos + 1, 1)
|
||||||
|
if (nextc == colsep || nextc == "") {
|
||||||
|
# fin de champ ou fin de ligne
|
||||||
|
resl = resl tmpl
|
||||||
|
destl[0] = substr(line, pos + 2)
|
||||||
|
destl[1] = nextc == colsep
|
||||||
|
return resl
|
||||||
|
} else if (nextc == qchar) {
|
||||||
|
# qchar en echappement
|
||||||
|
resl = resl tmpl quotec
|
||||||
|
line = substr(line, pos + 2)
|
||||||
|
} else {
|
||||||
|
# erreur de syntaxe: guillemet non mis en échappement
|
||||||
|
# ignorer cette erreur et prendre le guillemet quand meme
|
||||||
|
resl = resl tmpl quotec
|
||||||
|
line = substr(line, pos + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function csv__parse_unquoted(line, destl, colsep, qchar, echar, pos) {
|
||||||
|
pos = index(line, colsep)
|
||||||
|
if (pos == 0) {
|
||||||
|
destl[0] = ""
|
||||||
|
destl[1] = 0
|
||||||
|
return line
|
||||||
|
} else {
|
||||||
|
destl[0] = substr(line, pos + 1)
|
||||||
|
destl[1] = 1
|
||||||
|
return substr(line, 1, pos - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function csv__array_parse(fields, line, nbfields, colsep, qchar, echar, shouldparse, destl, i) {
|
||||||
|
array_new(fields)
|
||||||
|
array_new(destl)
|
||||||
|
i = 1
|
||||||
|
shouldparse = 0
|
||||||
|
# shouldparse permet de gérer le cas où un champ vide est en fin de ligne.
|
||||||
|
# en effet, après "," il faut toujours parser, même si line==""
|
||||||
|
while (shouldparse || line != "") {
|
||||||
|
if (index(line, qchar) == 1) {
|
||||||
|
value = csv__parse_quoted(line, destl, colsep, qchar, echar)
|
||||||
|
line = destl[0]
|
||||||
|
shouldparse = destl[1]
|
||||||
|
} else {
|
||||||
|
value = csv__parse_unquoted(line, destl, colsep, qchar, echar)
|
||||||
|
line = destl[0]
|
||||||
|
shouldparse = destl[1]
|
||||||
|
}
|
||||||
|
fields[i] = value
|
||||||
|
i = i + 1
|
||||||
|
}
|
||||||
|
if (nbfields) {
|
||||||
|
nbfields = int(nbfields)
|
||||||
|
i = array_len(fields)
|
||||||
|
while (i < nbfields) {
|
||||||
|
i++
|
||||||
|
fields[i] = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array_len(fields)
|
||||||
|
}
|
||||||
|
BEGIN {
|
||||||
|
DEFAULT_COLSEP = ","
|
||||||
|
DEFAULT_QCHAR = "\""
|
||||||
|
DEFAULT_ECHAR = ""
|
||||||
|
}
|
||||||
|
function array_parsecsv2(fields, line, nbfields, colsep, qchar, echar) {
|
||||||
|
return csv__array_parse(fields, line, nbfields, colsep, qchar, echar)
|
||||||
|
}
|
||||||
|
function array_parsecsv(fields, line, nbfields, colsep, qchar, echar) {
|
||||||
|
if (colsep == "") colsep = DEFAULT_COLSEP
|
||||||
|
if (qchar == "") qchar = DEFAULT_QCHAR
|
||||||
|
if (echar == "") echar = DEFAULT_ECHAR
|
||||||
|
return csv__array_parse(fields, line, nbfields, colsep, qchar, echar)
|
||||||
|
}
|
||||||
|
function parsecsv(line, fields) {
|
||||||
|
array_parsecsv(fields, line)
|
||||||
|
array_getline(fields)
|
||||||
|
return NF
|
||||||
|
}
|
||||||
|
function getlinecsv(file, fields) {
|
||||||
|
if (file) {
|
||||||
|
getline <file
|
||||||
|
} else {
|
||||||
|
getline
|
||||||
|
}
|
||||||
|
return parsecsv($0)
|
||||||
|
}
|
||||||
|
function csv__should_quote(s) {
|
||||||
|
if (s ~ /^[[:blank:][:cntrl:][:space:]]/) return 1
|
||||||
|
if (s ~ /[[:blank:][:cntrl:][:space:]]$/) return 1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
function array_formatcsv2(fields, colsep, mvsep, qchar, echar, count, indices, line, i, value) {
|
||||||
|
line = ""
|
||||||
|
count = mkindices(fields, indices)
|
||||||
|
for (i = 1; i <= count; i++) {
|
||||||
|
value = fields[indices[i]]
|
||||||
|
if (i > 1) line = line colsep
|
||||||
|
if (qchar != "" && index(value, qchar) != 0) {
|
||||||
|
if (echar != "") gsub(qchar, quote_subrepl(echar) "&", value);
|
||||||
|
else gsub(qchar, "&&", value);
|
||||||
|
}
|
||||||
|
if (qchar != "" && (index(value, mvsep) != 0 || index(value, colsep) != 0 || index(value, qchar) != 0 || csv__should_quote(value))) {
|
||||||
|
line = line qchar value qchar
|
||||||
|
} else {
|
||||||
|
line = line value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
function array_formatcsv(fields) {
|
||||||
|
return array_formatcsv2(fields, ",", ";", "\"", "")
|
||||||
|
}
|
||||||
|
function array_printcsv(fields, output) {
|
||||||
|
printto(array_formatcsv(fields), output)
|
||||||
|
}
|
||||||
|
function get_formatcsv( fields) {
|
||||||
|
array_fill(fields)
|
||||||
|
return array_formatcsv(fields)
|
||||||
|
}
|
||||||
|
function formatcsv() {
|
||||||
|
$0 = get_formatcsv()
|
||||||
|
}
|
||||||
|
function printcsv(output, fields) {
|
||||||
|
array_fill(fields)
|
||||||
|
array_printcsv(fields, output)
|
||||||
|
}
|
||||||
|
function array_findcsv(fields, input, field, value, nbfields, orig, found, i) {
|
||||||
|
array_new(orig)
|
||||||
|
array_fill(orig)
|
||||||
|
array_new(fields)
|
||||||
|
found = 0
|
||||||
|
while ((getline <input) > 0) {
|
||||||
|
array_parsecsv(fields, $0, nbfields)
|
||||||
|
if (fields[field] == value) {
|
||||||
|
found = 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(input)
|
||||||
|
array_getline(orig)
|
||||||
|
if (!found) {
|
||||||
|
delete fields
|
||||||
|
if (nbfields) {
|
||||||
|
nbfields = int(nbfields)
|
||||||
|
i = array_len(fields)
|
||||||
|
while (i < nbfields) {
|
||||||
|
i++
|
||||||
|
fields[i] = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
# -*- coding: utf-8 mode: awk -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
|
||||||
|
function base64__and(var, x, l_res, l_i) {
|
||||||
|
l_res = 0
|
||||||
|
for (l_i = 0; l_i < 8; l_i++) {
|
||||||
|
if (var%2 == 1 && x%2 == 1) l_res = l_res/2 + 128
|
||||||
|
else l_res /= 2
|
||||||
|
var = int(var/2)
|
||||||
|
x = int(x/2)
|
||||||
|
}
|
||||||
|
return l_res
|
||||||
|
}
|
||||||
|
# Rotate bytevalue left x times
|
||||||
|
function base64__lshift(var, x) {
|
||||||
|
while(x > 0) {
|
||||||
|
var *= 2
|
||||||
|
x--
|
||||||
|
}
|
||||||
|
return var
|
||||||
|
}
|
||||||
|
# Rotate bytevalue right x times
|
||||||
|
function base64__rshift(var, x) {
|
||||||
|
while(x > 0) {
|
||||||
|
var = int(var/2)
|
||||||
|
x--
|
||||||
|
}
|
||||||
|
return var
|
||||||
|
}
|
||||||
|
BEGIN {
|
||||||
|
BASE64__BYTES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||||
|
}
|
||||||
|
function b64decode(src, result, base1, base2, base3, base4) {
|
||||||
|
result = ""
|
||||||
|
while (length(src) > 0) {
|
||||||
|
# Specify byte values
|
||||||
|
base1 = substr(src, 1, 1)
|
||||||
|
base2 = substr(src, 2, 1)
|
||||||
|
base3 = substr(src, 3, 1); if (base3 == "") base3 = "="
|
||||||
|
base4 = substr(src, 4, 1); if (base4 == "") base4 = "="
|
||||||
|
# Now find numerical position in BASE64 string
|
||||||
|
byte1 = index(BASE64__BYTES, base1) - 1
|
||||||
|
if (byte1 < 0) byte1 = 0
|
||||||
|
byte2 = index(BASE64__BYTES, base2) - 1
|
||||||
|
if (byte2 < 0) byte2 = 0
|
||||||
|
byte3 = index(BASE64__BYTES, base3) - 1
|
||||||
|
if (byte3 < 0) byte3 = 0
|
||||||
|
byte4 = index(BASE64__BYTES, base4) - 1
|
||||||
|
if (byte4 < 0) byte4 = 0
|
||||||
|
# Reconstruct ASCII string
|
||||||
|
result = result sprintf( "%c", base64__lshift(base64__and(byte1, 63), 2) + base64__rshift(base64__and(byte2, 48), 4) )
|
||||||
|
if (base3 != "=") result = result sprintf( "%c", base64__lshift(base64__and(byte2, 15), 4) + base64__rshift(base64__and(byte3, 60), 2) )
|
||||||
|
if (base4 != "=") result = result sprintf( "%c", base64__lshift(base64__and(byte3, 3), 6) + byte4 )
|
||||||
|
# Decrease incoming string with 4
|
||||||
|
src = substr(src, 5)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
# nulib/bash
|
||||||
|
|
||||||
|
## template
|
||||||
|
|
||||||
|
* [x] pour tout fichier source `.file.template`, considérer avant
|
||||||
|
`file.template.local` s'il existe, ce qui permet à un utilisateur de
|
||||||
|
remplacer le modèle livré.
|
||||||
|
cela a-t-il du sens de supporter aussi file.dist.local? vu que ça ne sert
|
||||||
|
qu'une seule fois? ça ne mange pas de pain...
|
||||||
|
|
||||||
|
## args
|
||||||
|
|
||||||
|
* [x] support des couples d'options --option et --no-option qui mettent à jour
|
||||||
|
tous les deux la variables option. ceci:
|
||||||
|
~~~
|
||||||
|
--option .
|
||||||
|
--no-option .
|
||||||
|
~~~
|
||||||
|
est équivalent à ceci:
|
||||||
|
~~~
|
||||||
|
--option '$inc@ option'
|
||||||
|
--no-option '$dec@ option'
|
||||||
|
~~~
|
||||||
|
dec@ est une nouvelle fonction qui décrémente et remplace par une chaine vide
|
||||||
|
quand on arrive à zéro
|
||||||
|
* [x] args: support des noms d'argument pour améliorer l'affichage de l'aide.
|
||||||
|
par exemple la définition
|
||||||
|
~~~
|
||||||
|
-f:file,--input input= "spécifier le fichier en entrée"
|
||||||
|
~~~
|
||||||
|
donnera cette aide:
|
||||||
|
~~~
|
||||||
|
-f, --input FILE
|
||||||
|
spécifier le fichier
|
||||||
|
~~~
|
||||||
|
* [ ] args: après le support des noms d'arguments, ajouter la génération
|
||||||
|
automatique de l'auto-complétion basée sur ces informations. certains noms
|
||||||
|
seraient normalisés: `file` pour un fichier, `dir` pour un répertoire, `env`
|
||||||
|
pour une variable d'environnement, etc.
|
||||||
|
on pourrait même considérer mettre des patterns pour la sélection, e.g
|
||||||
|
~~~
|
||||||
|
"-C,--config:file:*.conf *.cnf" input= "spécifier le fichier de configuration"
|
||||||
|
~~~
|
||||||
|
|
||||||
|
-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary
|
|
@ -0,0 +1,4 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: TEMPLATE "DESCRIPTION"
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
|
||||||
|
function __esection() {
|
||||||
|
local -a lines
|
||||||
|
local lsep prefix="$(__edate)$(__eindent0)"
|
||||||
|
local length="${COLUMNS:-80}"
|
||||||
|
setx lsep=__complete "$prefix" "$length" -
|
||||||
|
|
||||||
|
tooenc "$COULEUR_BLEUE$lsep$COULEUR_NORMALE"
|
||||||
|
[ -n "$*" ] || return 0
|
||||||
|
length=$((length - 1))
|
||||||
|
setx -a lines=echo "$1"
|
||||||
|
for line in "${lines[@]}"; do
|
||||||
|
setx line=__complete "$prefix- $line" "$length"
|
||||||
|
tooenc "$COULEUR_BLEUE$line-$COULEUR_NORMALE"
|
||||||
|
done
|
||||||
|
tooenc "$COULEUR_BLEUE$lsep$COULEUR_NORMALE"
|
||||||
|
}
|
||||||
|
function __etitle() {
|
||||||
|
local -a lines; local maxlen=0
|
||||||
|
local prefix="$(__edate)$(__eindent0)"
|
||||||
|
|
||||||
|
setx -a lines=echo "$1"
|
||||||
|
for line in "${lines[@]}"; do
|
||||||
|
[ ${#line} -gt $maxlen ] && maxlen=${#line}
|
||||||
|
tooenc "${prefix}${COULEUR_BLEUE}T $line$COULEUR_NORMALE"
|
||||||
|
done
|
||||||
|
maxlen=$((maxlen + 2))
|
||||||
|
tooenc "${prefix}${COULEUR_BLEUE}T$(__complete "" $maxlen -)${COULEUR_NORMALE}"
|
||||||
|
}
|
||||||
|
function __edesc() {
|
||||||
|
local -a lines
|
||||||
|
local prefix="$(__edate)$(__eindent0)"
|
||||||
|
|
||||||
|
setx -a lines=echo "$1"
|
||||||
|
for line in "${lines[@]}"; do
|
||||||
|
tooenc "${prefix}${COULEUR_BLEUE}>${COULEUR_NORMALE} $line"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
function __ebanner() {
|
||||||
|
local -a lines
|
||||||
|
local lsep prefix="$(__edate)$(__eindent0)"
|
||||||
|
local length="${COLUMNS:-80}"
|
||||||
|
setx lsep=__complete "$prefix" "$length" =
|
||||||
|
|
||||||
|
tooenc "$COULEUR_ROUGE$lsep"
|
||||||
|
length=$((length - 1))
|
||||||
|
setx -a lines=echo "$1"
|
||||||
|
for line in "" "${lines[@]}" ""; do
|
||||||
|
setx line=__complete "$prefix= $line" "$length"
|
||||||
|
tooenc "$line="
|
||||||
|
done
|
||||||
|
tooenc "$lsep$COULEUR_NORMALE"
|
||||||
|
}
|
||||||
|
function __eimportant() { tooenc "$(__edate)$(__eindent0)${COULEUR_ROUGE}!${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
function __eattention() { tooenc "$(__edate)$(__eindent0)${COULEUR_JAUNE}*${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
function __eerror() { tooenc "$(__edate)$(__eindent0)${COULEUR_ROUGE}E${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
function __ewarn() { tooenc "$(__edate)$(__eindent0)${COULEUR_JAUNE}W${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
function __enote() { tooenc "$(__edate)$(__eindent0)${COULEUR_VERTE}N${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
function __einfo() { tooenc "$(__edate)$(__eindent0)${COULEUR_BLEUE}I${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
function __edebug() { tooenc "$(__edate)$(__eindent0)${COULEUR_BLANCHE}D${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
|
||||||
|
function __estep() { tooenc "$(__edate)$(__eindent0)${COULEUR_BLANCHE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
function __estepe() { tooenc "$(__edate)$(__eindent0)${COULEUR_ROUGE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
function __estepw() { tooenc "$(__edate)$(__eindent0)${COULEUR_JAUNE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
function __estepn() { tooenc "$(__edate)$(__eindent0)${COULEUR_VERTE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
function __estepi() { tooenc "$(__edate)$(__eindent0)${COULEUR_BLEUE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
function __estep_() { tooenc_ "$(__edate)$(__eindent0)${COULEUR_BLANCHE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
function __estepe_() { tooenc_ "$(__edate)$(__eindent0)${COULEUR_ROUGE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
function __estepw_() { tooenc_ "$(__edate)$(__eindent0)${COULEUR_JAUNE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
function __estepn_() { tooenc_ "$(__edate)$(__eindent0)${COULEUR_VERTE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
function __estepi_() { tooenc_ "$(__edate)$(__eindent0)${COULEUR_BLEUE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
|
||||||
|
function __action() { tooenc "$(__edate)$(__eindent0)${COULEUR_BLANCHE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
function __asuccess() { tooenc "$(__edate)$(__eindent0)${COULEUR_VERTE}✔${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
function __afailure() { tooenc "$(__edate)$(__eindent0)${COULEUR_ROUGE}✘${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
|
||||||
|
function __adone() { tooenc "$(__edate)$(__eindent0)$(__eindent "$1")"; }
|
|
@ -0,0 +1,66 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
|
||||||
|
function __esection() {
|
||||||
|
local -a lines
|
||||||
|
local lsep prefix="$(__edate)$(__eindent0)"
|
||||||
|
local length="${COLUMNS:-80}"
|
||||||
|
setx lsep=__complete "$prefix" "$length" -
|
||||||
|
|
||||||
|
tooenc "$lsep"
|
||||||
|
[ -n "$*" ] || return 0
|
||||||
|
length=$((length - 1))
|
||||||
|
setx -a lines=echo "$1"
|
||||||
|
for line in "${lines[@]}"; do
|
||||||
|
setx line=__complete "$prefix- $line" "$length"
|
||||||
|
tooenc "$line-"
|
||||||
|
done
|
||||||
|
tooenc "$lsep"
|
||||||
|
}
|
||||||
|
function __etitle() {
|
||||||
|
local p="TITLE: " i=" "
|
||||||
|
tooenc "$(__edate)$(__eindent0)${p}$(__eindent "$1" "$i")"
|
||||||
|
}
|
||||||
|
function __edesc() {
|
||||||
|
local p="DESC: " i=" "
|
||||||
|
tooenc "$(__edate)$(__eindent0)${p}$(__eindent "$1" "$i")"
|
||||||
|
}
|
||||||
|
function __ebanner() {
|
||||||
|
local -a lines
|
||||||
|
local lsep prefix="$(__edate)$(__eindent0)"
|
||||||
|
local length="${COLUMNS:-80}"
|
||||||
|
setx lsep=__complete "$prefix" "$length" =
|
||||||
|
|
||||||
|
tooenc "$lsep"
|
||||||
|
length=$((length - 1))
|
||||||
|
setx -a lines=echo "$1"
|
||||||
|
for line in "" "${lines[@]}" ""; do
|
||||||
|
setx line=__complete "$prefix= $line" "$length"
|
||||||
|
tooenc "$line="
|
||||||
|
done
|
||||||
|
tooenc "$lsep"
|
||||||
|
}
|
||||||
|
function __eimportant() { tooenc "$(__edate)$(__eindent0)IMPORTANT! $(__eindent "$1" " ")"; }
|
||||||
|
function __eattention() { tooenc "$(__edate)$(__eindent0)ATTENTION! $(__eindent "$1" " ")"; }
|
||||||
|
function __eerror() { tooenc "$(__edate)$(__eindent0)ERROR: $(__eindent "$1" " ")"; }
|
||||||
|
function __ewarn() { tooenc "$(__edate)$(__eindent0)WARNING: $(__eindent "$1" " ")"; }
|
||||||
|
function __enote() { tooenc "$(__edate)$(__eindent0)NOTE: $(__eindent "$1" " ")"; }
|
||||||
|
function __einfo() { tooenc "$(__edate)$(__eindent0)INFO: $(__eindent "$1" " ")"; }
|
||||||
|
function __edebug() { tooenc "$(__edate)$(__eindent0)DEBUG: $(__eindent "$1" " ")"; }
|
||||||
|
function __eecho() { tooenc "$(__edate)$(__eindent0)$(__eindent "$1")"; }
|
||||||
|
function __eecho_() { tooenc_ "$(__edate)$(__eindent0)$(__eindent "$1")"; }
|
||||||
|
|
||||||
|
function __estep() { tooenc "$(__edate)$(__eindent0). $(__eindent "$1" " ")"; }
|
||||||
|
function __estepe() { tooenc "$(__edate)$(__eindent0).E $(__eindent "$1" " ")"; }
|
||||||
|
function __estepw() { tooenc "$(__edate)$(__eindent0).W $(__eindent "$1" " ")"; }
|
||||||
|
function __estepn() { tooenc "$(__edate)$(__eindent0).N $(__eindent "$1" " ")"; }
|
||||||
|
function __estepi() { tooenc "$(__edate)$(__eindent0).I $(__eindent "$1" " ")"; }
|
||||||
|
function __estep_() { tooenc_ "$(__edate)$(__eindent0). $(__eindent "$1" " ")"; }
|
||||||
|
function __estepe_() { tooenc_ "$(__edate)$(__eindent0).E $(__eindent "$1" " ")"; }
|
||||||
|
function __estepw_() { tooenc_ "$(__edate)$(__eindent0).W $(__eindent "$1" " ")"; }
|
||||||
|
function __estepn_() { tooenc_ "$(__edate)$(__eindent0).N $(__eindent "$1" " ")"; }
|
||||||
|
function __estepi_() { tooenc_ "$(__edate)$(__eindent0).I $(__eindent "$1" " ")"; }
|
||||||
|
|
||||||
|
function __action() { tooenc "$(__edate)$(__eindent0)ACTION: $(__eindent "$1" " ")"; }
|
||||||
|
function __asuccess() { tooenc "$(__edate)$(__eindent0)(OK) $(__eindent "$1" " ")"; }
|
||||||
|
function __afailure() { tooenc "$(__edate)$(__eindent0)(KO) $(__eindent "$1" " ")"; }
|
||||||
|
function __adone() { tooenc "$(__edate)$(__eindent0)$(__eindent "$1")"; }
|
|
@ -0,0 +1,486 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: base.args "Fonctions de base: analyse d'arguments"
|
||||||
|
|
||||||
|
function: local_args "Afficher des commandes pour rendre locales des variables utilisées par parse_args()
|
||||||
|
|
||||||
|
Cela permet d'utiliser parse_args() à l'intérieur d'une fonction."
|
||||||
|
function local_args() {
|
||||||
|
echo "local -a args"
|
||||||
|
echo "local NULIB_ARGS_ONERROR_RETURN=1"
|
||||||
|
echo "local NULIB_VERBOSITY=\"\$NULIB_VERBOSITY\""
|
||||||
|
echo "local NULIB_INTERACTION=\"\$NULIB_INTERACTION\""
|
||||||
|
}
|
||||||
|
|
||||||
|
function: parse_args "Analyser les arguments de la ligne de commande à partir des définitions du tableau args
|
||||||
|
|
||||||
|
Cette fonction s'utilise ainsi:
|
||||||
|
~~~"'
|
||||||
|
args=(
|
||||||
|
[desc]
|
||||||
|
[usage]
|
||||||
|
[+|-]
|
||||||
|
-o,--longopt action [optdesc]
|
||||||
|
-a:,--mandarg: action [optdesc]
|
||||||
|
-b::,--optarg:: action [optdesc]
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
~~~'"
|
||||||
|
|
||||||
|
au retour de la fonction, args contient les arguments qui n'ont pas été traités
|
||||||
|
automatiquement.
|
||||||
|
|
||||||
|
les options --help et --help++ sont automatiquement gérées. avec --help, seules
|
||||||
|
les options standards sont affichées. --help++ affiche toutes les options. les
|
||||||
|
descriptions sont utilisées pour l'affichage de l'aide. une option avancée est
|
||||||
|
identifiée par une description qui commence par ++
|
||||||
|
|
||||||
|
desc
|
||||||
|
: description de l'objet du script ou de la fonction. cette valeur est
|
||||||
|
facultative
|
||||||
|
|
||||||
|
usage
|
||||||
|
: description des arguments du script, sans le nom du script. par exemple la
|
||||||
|
valeur '[options] FILE' générera le texte d'aide suivant:
|
||||||
|
~~~
|
||||||
|
USAGE
|
||||||
|
\$MYNAME [options] FILE
|
||||||
|
~~~
|
||||||
|
Peut contenir autant de lignes que nécessaire. Chaque ligne est préfixée du
|
||||||
|
nom du script, jusqu'à la première ligne vide. Ensuite, les lignes sont
|
||||||
|
affichées telles quelles.
|
||||||
|
Le premier espace est ignoré, ce qui permet de spécifier des USAGEs avec une
|
||||||
|
option, e.g ' -c VALUE'
|
||||||
|
|
||||||
|
+|-
|
||||||
|
: méthode d'analyse des arguments.
|
||||||
|
* Par défaut, les options sont valides n'importe où sur la ligne de commande.
|
||||||
|
* Avec '+', l'analyse s'arrête au premier argument qui n'est pas une option.
|
||||||
|
* Avec '-', les options sont valides n'importe où sur la ligne de commande,
|
||||||
|
mais les arguments ne sont pas réordonnés, et apparaissent dans l'ordre de
|
||||||
|
leur mention. IMPORTANT: dans ce cas, aucun argument ni option n'est traité,
|
||||||
|
c'est à la charge de l'utilisateur. Au retour de la fonction, args contient
|
||||||
|
l'ensemble des arguments tels qu'analysés par getopt
|
||||||
|
|
||||||
|
-o, --longopt
|
||||||
|
: option sans argument
|
||||||
|
|
||||||
|
-a:, --mandarg:
|
||||||
|
: option avec argument obligatoire
|
||||||
|
|
||||||
|
l'option peut être suivi d'une valeur qui décrit l'argument attendu e.g
|
||||||
|
-a:file pour un fichier. cette valeur est mise en majuscule lors de
|
||||||
|
l'affichage de l'aide. pour le moment, cette valeur n'est pas signifiante.
|
||||||
|
|
||||||
|
-b::, --optarg::
|
||||||
|
: option avec argument facultatif
|
||||||
|
|
||||||
|
l'option peut être suivi d'une valeur qui décrit l'argument attendu e.g
|
||||||
|
-b::file pour un fichier. cette valeur est mise en majuscule lors de
|
||||||
|
l'affichage de l'aide. pour le moment, cette valeur n'est pas signifiante.
|
||||||
|
|
||||||
|
action
|
||||||
|
: action à effectuer si cette option est utilisée. plusieurs syntaxes sont valides:
|
||||||
|
* 'NAME' met à jour la variable en fonction du type d'argument: l'incrémenter
|
||||||
|
pour une option sans argument, lui donner la valeur spécifiée pour une
|
||||||
|
option avec argument, ajouter la valeur spécifiée au tableau si l'option est
|
||||||
|
spécifiée plusieurs fois.
|
||||||
|
la valeur spéciale '.' calcule une valeur de NAME en fonction du nom de
|
||||||
|
l'option la plus longue. par exemple, les deux définitions suivantes sont
|
||||||
|
équivalentes:
|
||||||
|
~~~
|
||||||
|
-o,--short,--very-long .
|
||||||
|
-o,--short,--very-long very_long
|
||||||
|
~~~
|
||||||
|
De plus, la valeur spéciale '.' traite les options de la forme --no-opt
|
||||||
|
comme l'inverse des option --opt. par exemple, les deux définitions
|
||||||
|
suivantes sont équivalentes:
|
||||||
|
~~~
|
||||||
|
--opt . --no-opt .
|
||||||
|
--opt opt --no-opt '\$dec@ opt'
|
||||||
|
~~~
|
||||||
|
* 'NAME=VALUE' pour une option sans argument, forcer la valeur spécifiée; pour
|
||||||
|
une option avec argument, prendre la valeur spécifiée comme valeur par
|
||||||
|
défaut si la valeur de l'option est vide
|
||||||
|
* '\$CMD' CMD est évalué avec eval *dès* que l'option est rencontrée.
|
||||||
|
les valeurs suivantes sont initialisées:
|
||||||
|
* option_ est l'option utilisée, e.g --long-opt
|
||||||
|
* value_ est la valeur de l'option
|
||||||
|
les fonctions suivantes sont définies:
|
||||||
|
* 'inc@ NAME' incrémente la variable NAME -- c'est le comportement de set@ si
|
||||||
|
l'option est sans argument
|
||||||
|
* 'dec@ NAME' décrémente la variable NAME, et la rend vide quand le compte
|
||||||
|
arrive à zéro
|
||||||
|
* 'res@ NAME VALUE' initialise la variable NAME avec la valeur de l'option (ou
|
||||||
|
VALUE si la valeur de l'option est vide) -- c'est le comportement de set@
|
||||||
|
si l'option prend un argument
|
||||||
|
* 'add@ NAME VALUE' ajoute la valeur de l'option (ou VALUE si la valeur de
|
||||||
|
l'option est vide) au tableau NAME.
|
||||||
|
* 'set@ NAME' met à jour la variable NAME en fonction de la définition de
|
||||||
|
l'option (avec ou sans argument, ajout ou non à un tableau)
|
||||||
|
|
||||||
|
optdesc
|
||||||
|
: description de l'option. cette valeur est facultative. si la description
|
||||||
|
commence par ++, c'est une option avancée qui n'est pas affichée par défaut."
|
||||||
|
function parse_args() {
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
local __r=
|
||||||
|
local __DIE='[ -n "$NULIB_ARGS_ONERROR_RETURN" ] && return 1 || die'
|
||||||
|
|
||||||
|
if ! is_array args; then
|
||||||
|
eerror "Invalid args definition: args must be defined"
|
||||||
|
__r=1
|
||||||
|
fi
|
||||||
|
# distinguer les descriptions des définition d'arguments
|
||||||
|
local __USAGE __DESC
|
||||||
|
local -a __DEFS __ARGS
|
||||||
|
__ARGS=("$@")
|
||||||
|
set -- "${args[@]}"
|
||||||
|
[ "${1#-}" == "$1" ] && { __DESC="$1"; shift; }
|
||||||
|
[ "${1#-}" == "$1" ] && { __USAGE="$1"; shift; }
|
||||||
|
if [ -n "$__r" ]; then
|
||||||
|
:
|
||||||
|
elif [ $# -gt 0 -a "$1" != "+" -a "${1#-}" == "$1" ]; then
|
||||||
|
eerror "Invalid args definition: third arg must be an option"
|
||||||
|
__r=1
|
||||||
|
else
|
||||||
|
__DEFS=("$@")
|
||||||
|
__parse_args || __r=1
|
||||||
|
fi
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
if [ -n "$__r" ]; then
|
||||||
|
eval "$__DIE"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
function __parse_args() {
|
||||||
|
## tout d'abord, construire la liste des options
|
||||||
|
local __AUTOH=1 __AUTOHELP=1 # faut-il gérer automatiquement l'affichage de l'aide?
|
||||||
|
local __AUTOD=1 __AUTODEBUG=1 # faut-il rajouter les options -D et --debug
|
||||||
|
local __ADVHELP # y a-t-il des options avancées?
|
||||||
|
local __popt __sopts __lopts
|
||||||
|
local -a __defs
|
||||||
|
set -- "${__DEFS[@]}"
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
+) __popt="$1"; shift; continue;;
|
||||||
|
-) __popt="$1"; shift; continue;;
|
||||||
|
-*) IFS=, read -a __defs <<<"$1"; shift;;
|
||||||
|
*) eerror "Invalid arg definition: expected option, got '$1'"; eval "$__DIE";;
|
||||||
|
esac
|
||||||
|
# est-ce que l'option prend un argument?
|
||||||
|
local __def __witharg __valdesc
|
||||||
|
__witharg=
|
||||||
|
for __def in "${__defs[@]}"; do
|
||||||
|
if [ "${__def%::*}" != "$__def" ]; then
|
||||||
|
[ "$__witharg" != : ] && __witharg=::
|
||||||
|
elif [ "${__def%:*}" != "$__def" ]; then
|
||||||
|
__witharg=:
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# définitions __sopts et __lopts
|
||||||
|
for __def in "${__defs[@]}"; do
|
||||||
|
__def="${__def%%:*}"
|
||||||
|
if [[ "$__def" == --* ]]; then
|
||||||
|
# --longopt
|
||||||
|
__def="${__def#--}"
|
||||||
|
__lopts="$__lopts${__lopts:+,}$__def$__witharg"
|
||||||
|
elif [[ "$__def" == -* ]] && [ ${#__def} -eq 2 ]; then
|
||||||
|
# -o
|
||||||
|
__def="${__def#-}"
|
||||||
|
__sopts="$__sopts$__def$__witharg"
|
||||||
|
[ "$__def" == h ] && __AUTOH=
|
||||||
|
[ "$__def" == D ] && __AUTOD=
|
||||||
|
else
|
||||||
|
# -longopt ou longopt
|
||||||
|
__def="${__def#-}"
|
||||||
|
__lopts="$__lopts${__lopts:+,}$__def$__witharg"
|
||||||
|
fi
|
||||||
|
[ "$__def" == help -o "$__def" == help++ ] && __AUTOHELP=
|
||||||
|
[ "$__def" == debug ] && __AUTODEBUG=
|
||||||
|
done
|
||||||
|
# sauter l'action
|
||||||
|
shift
|
||||||
|
# sauter la description le cas échéant
|
||||||
|
if [ "${1#-}" == "$1" ]; then
|
||||||
|
[ "${1#++}" != "$1" ] && __ADVHELP=1
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
[ -n "$__AUTOH" ] && __sopts="${__sopts}h"
|
||||||
|
[ -n "$__AUTOHELP" ] && __lopts="$__lopts${__lopts:+,}help,help++"
|
||||||
|
[ -n "$__AUTOD" ] && __sopts="${__sopts}D"
|
||||||
|
[ -n "$__AUTODEBUG" ] && __lopts="$__lopts${__lopts:+,}debug"
|
||||||
|
|
||||||
|
__sopts="$__popt$__sopts"
|
||||||
|
local -a __getopt_args
|
||||||
|
__getopt_args=(-n "$MYNAME" ${__sopts:+-o "$__sopts"} ${__lopts:+-l "$__lopts"} -- "${__ARGS[@]}")
|
||||||
|
|
||||||
|
## puis analyser et normaliser les arguments
|
||||||
|
if args="$(getopt -q "${__getopt_args[@]}")"; then
|
||||||
|
eval "set -- $args"
|
||||||
|
else
|
||||||
|
# relancer pour avoir le message d'erreur
|
||||||
|
LANG=C getopt "${__getopt_args[@]}" 2>&1 1>/dev/null
|
||||||
|
eval "$__DIE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
## puis traiter les options
|
||||||
|
local __defname __resvalue __decvalue __defvalue __add __action option_ name_ value_
|
||||||
|
function inc@() {
|
||||||
|
eval "[ -n \"\$$1\" ] || let $1=0"
|
||||||
|
eval "let $1=$1+1"
|
||||||
|
}
|
||||||
|
function dec@() {
|
||||||
|
eval "[ -n \"\$$1\" ] && let $1=$1-1"
|
||||||
|
eval "[ \"\$$1\" == 0 ] && $1="
|
||||||
|
}
|
||||||
|
function res@() {
|
||||||
|
local __value="${value_:-$2}"
|
||||||
|
eval "$1=\"\$__value\""
|
||||||
|
}
|
||||||
|
function add@() {
|
||||||
|
local __value="${value_:-$2}"
|
||||||
|
eval "$1+=(\"\$__value\")"
|
||||||
|
}
|
||||||
|
function set@() {
|
||||||
|
if [ -n "$__resvalue" ]; then
|
||||||
|
res@ "$@"
|
||||||
|
elif [ -n "$__witharg" ]; then
|
||||||
|
if is_array "$1"; then
|
||||||
|
add@ "$@"
|
||||||
|
elif ! is_defined "$1"; then
|
||||||
|
# première occurrence: variable
|
||||||
|
res@ "$@"
|
||||||
|
else
|
||||||
|
# deuxième occurence: tableau
|
||||||
|
[ -z "${!1}" ] && eval "$1=()"
|
||||||
|
add@ "$@"
|
||||||
|
fi
|
||||||
|
elif [ -n "$__decvalue" ]; then
|
||||||
|
dec@ "$@"
|
||||||
|
else
|
||||||
|
inc@ "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
function showhelp@() {
|
||||||
|
local help="$MYNAME" showadv="$1"
|
||||||
|
if [ -n "$__DESC" ]; then
|
||||||
|
help="$help: $__DESC"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local first usage nl=$'\n'
|
||||||
|
local prefix=" $MYNAME "
|
||||||
|
local usages="${__USAGE# }"
|
||||||
|
[ -n "$usages" ] || usages="[options]"
|
||||||
|
help="$help
|
||||||
|
|
||||||
|
USAGE"
|
||||||
|
first=1
|
||||||
|
while [ -n "$usages" ]; do
|
||||||
|
usage="${usages%%$nl*}"
|
||||||
|
if [ "$usage" != "$usages" ]; then
|
||||||
|
usages="${usages#*$nl}"
|
||||||
|
else
|
||||||
|
usages=
|
||||||
|
fi
|
||||||
|
if [ -n "$first" ]; then
|
||||||
|
first=
|
||||||
|
[ -z "$usage" ] && continue
|
||||||
|
else
|
||||||
|
[ -z "$usage" ] && prefix=
|
||||||
|
fi
|
||||||
|
help="$help
|
||||||
|
$prefix$usage"
|
||||||
|
done
|
||||||
|
|
||||||
|
set -- "${__DEFS[@]}"
|
||||||
|
first=1
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
+) shift; continue;;
|
||||||
|
-) shift; continue;;
|
||||||
|
-*) IFS=, read -a __defs <<<"$1"; shift;;
|
||||||
|
esac
|
||||||
|
if [ -n "$first" ]; then
|
||||||
|
first=
|
||||||
|
help="$help${nl}${nl}OPTIONS"
|
||||||
|
if [ -n "$__AUTOHELP" -a -n "$__ADVHELP" ]; then
|
||||||
|
help="$help
|
||||||
|
--help++
|
||||||
|
Afficher l'aide avancée"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
# est-ce que l'option prend un argument?
|
||||||
|
__witharg=
|
||||||
|
__valdesc=value
|
||||||
|
for __def in "${__defs[@]}"; do
|
||||||
|
if [ "${__def%::*}" != "$__def" ]; then
|
||||||
|
[ "$__witharg" != : ] && __witharg=::
|
||||||
|
[ -n "${__def#*::}" ] && __valdesc="[${__def#*::}]"
|
||||||
|
elif [ "${__def%:*}" != "$__def" ]; then
|
||||||
|
__witharg=:
|
||||||
|
[ -n "${__def#*:}" ] && __valdesc="${__def#*:}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# description de l'option
|
||||||
|
local first=1 thelp tdesc
|
||||||
|
for __def in "${__defs[@]}"; do
|
||||||
|
__def="${__def%%:*}"
|
||||||
|
if [[ "$__def" == --* ]]; then
|
||||||
|
: # --longopt
|
||||||
|
elif [[ "$__def" == -* ]] && [ ${#__def} -eq 2 ]; then
|
||||||
|
: # -o
|
||||||
|
else
|
||||||
|
# -longopt ou longopt
|
||||||
|
__def="--${__def#-}"
|
||||||
|
fi
|
||||||
|
if [ -n "$first" ]; then
|
||||||
|
first=
|
||||||
|
thelp="${nl} "
|
||||||
|
else
|
||||||
|
thelp="$thelp, "
|
||||||
|
fi
|
||||||
|
thelp="$thelp$__def"
|
||||||
|
done
|
||||||
|
[ -n "$__witharg" ] && thelp="$thelp ${__valdesc^^}"
|
||||||
|
# sauter l'action
|
||||||
|
shift
|
||||||
|
# prendre la description le cas échéant
|
||||||
|
if [ "${1#-}" == "$1" ]; then
|
||||||
|
tdesc="$1"
|
||||||
|
if [ "${tdesc#++}" != "$tdesc" ]; then
|
||||||
|
# option avancée
|
||||||
|
if [ -n "$showadv" ]; then
|
||||||
|
tdesc="${tdesc#++}"
|
||||||
|
else
|
||||||
|
thelp=
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
[ -n "$thelp" ] && thelp="$thelp${nl} ${tdesc//$nl/$nl }"
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
[ -n "$thelp" ] && help="$help$thelp"
|
||||||
|
done
|
||||||
|
uecho "$help"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
if [ "$__popt" != - ]; then
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
if [ "$1" == -- ]; then
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
[[ "$1" == -* ]] || break
|
||||||
|
option_="$1"; shift
|
||||||
|
__parse_opt "$option_"
|
||||||
|
if [ -n "$__witharg" ]; then
|
||||||
|
# l'option prend un argument
|
||||||
|
value_="$1"; shift
|
||||||
|
else
|
||||||
|
# l'option ne prend pas d'argument
|
||||||
|
value_=
|
||||||
|
fi
|
||||||
|
eval "$__action"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
unset -f inc@ res@ add@ set@ showhelp@
|
||||||
|
args=("$@")
|
||||||
|
}
|
||||||
|
function __parse_opt() {
|
||||||
|
# $1 est l'option spécifiée
|
||||||
|
local option_="$1"
|
||||||
|
set -- "${__DEFS[@]}"
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
+) shift; continue;;
|
||||||
|
-) shift; continue;;
|
||||||
|
-*) IFS=, read -a __defs <<<"$1"; shift;;
|
||||||
|
esac
|
||||||
|
# est-ce que l'option prend un argument?
|
||||||
|
__witharg=
|
||||||
|
for __def in "${__defs[@]}"; do
|
||||||
|
if [ "${__def%::*}" != "$__def" ]; then
|
||||||
|
[ "$__witharg" != : ] && __witharg=::
|
||||||
|
elif [ "${__def%:*}" != "$__def" ]; then
|
||||||
|
__witharg=:
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# nom le plus long
|
||||||
|
__defname=
|
||||||
|
local __found=
|
||||||
|
for __def in "${__defs[@]}"; do
|
||||||
|
__def="${__def%%:*}"
|
||||||
|
[ "$__def" == "$option_" ] && __found=1
|
||||||
|
if [[ "$__def" == --* ]]; then
|
||||||
|
# --longopt
|
||||||
|
__def="${__def#--}"
|
||||||
|
[ ${#__def} -gt ${#__defname} ] && __defname="$__def"
|
||||||
|
elif [[ "$__def" == -* ]] && [ ${#__def} -eq 2 ]; then
|
||||||
|
# -o
|
||||||
|
__def="${__def#-}"
|
||||||
|
[ ${#__def} -gt ${#__defname} ] && __defname="$__def"
|
||||||
|
else
|
||||||
|
# -longopt ou longopt
|
||||||
|
__def="${__def#-}"
|
||||||
|
[ ${#__def} -gt ${#__defname} ] && __defname="$__def"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
__defname="${__defname//-/_}"
|
||||||
|
# analyser l'action
|
||||||
|
__decvalue=
|
||||||
|
if [ "${1#\$}" != "$1" ]; then
|
||||||
|
name_="$__defname"
|
||||||
|
__resvalue=
|
||||||
|
__defvalue=
|
||||||
|
__action="${1#\$}"
|
||||||
|
else
|
||||||
|
if [ "$1" == . ]; then
|
||||||
|
name_="$__defname"
|
||||||
|
__resvalue=
|
||||||
|
__defvalue=
|
||||||
|
if [ "${name_#no_}" != "$name_" ]; then
|
||||||
|
name_="${name_#no_}"
|
||||||
|
__decvalue=1
|
||||||
|
fi
|
||||||
|
elif [[ "$1" == *=* ]]; then
|
||||||
|
name_="${1%%=*}"
|
||||||
|
__resvalue=1
|
||||||
|
__defvalue="${1#*=}"
|
||||||
|
else
|
||||||
|
name_="$1"
|
||||||
|
__resvalue=
|
||||||
|
__defvalue=
|
||||||
|
fi
|
||||||
|
__action="$(qvals set@ "$name_" "$__defvalue")"
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
# sauter la description le cas échéant
|
||||||
|
[ "${1#-}" == "$1" ] && shift
|
||||||
|
|
||||||
|
[ -n "$__found" ] && return 0
|
||||||
|
done
|
||||||
|
if [ -n "$__AUTOH" -a "$option_" == -h ]; then
|
||||||
|
__action="showhelp@"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [ -n "$__AUTOHELP" ]; then
|
||||||
|
if [ "$option_" == --help ]; then
|
||||||
|
__action="showhelp@"
|
||||||
|
return 0
|
||||||
|
elif [ "$option_" == --help++ ]; then
|
||||||
|
__action="showhelp@ ++"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ -n "$__AUTOD" -a "$option_" == -D ]; then
|
||||||
|
__action=set_debug
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [ -n "$__AUTODEBUG" -a "$option_" == --debug ]; then
|
||||||
|
__action=set_debug
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
# ici, l'option n'a pas été trouvée, on ne devrait pas arriver ici
|
||||||
|
eerror "Unexpected option '$option_'"; eval "$__DIE"
|
||||||
|
}
|
|
@ -0,0 +1,360 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: base.array "Fonctions de base: gestion des variables tableaux"
|
||||||
|
|
||||||
|
function: array_count "retourner le nombre d'éléments du tableau \$1"
|
||||||
|
function array_count() {
|
||||||
|
eval "echo \${#$1[*]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_isempty "tester si le tableau \$1 est vide"
|
||||||
|
function array_isempty() {
|
||||||
|
eval "[ \${#$1[*]} -eq 0 ]"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_new "créer un tableau vide dans la variable \$1"
|
||||||
|
function array_new() {
|
||||||
|
eval "$1=()"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_copy "copier le contenu du tableau \$2 dans le tableau \$1"
|
||||||
|
function array_copy() {
|
||||||
|
eval "$1=(\"\${$2[@]}\")"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_add "ajouter les valeurs \$2..@ à la fin du tableau \$1"
|
||||||
|
function array_add() {
|
||||||
|
local __aa_a="$1"; shift
|
||||||
|
eval "$__aa_a+=(\"\$@\")"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_ins "insérer les valeurs \$2..@ au début du tableau \$1"
|
||||||
|
function array_ins() {
|
||||||
|
local __aa_a="$1"; shift
|
||||||
|
eval "$__aa_a=(\"\$@\" \"\${$__aa_a[@]}\")"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_del "supprimer *les* valeurs \$2 du tableau \$1"
|
||||||
|
function array_del() {
|
||||||
|
local __ad_v
|
||||||
|
local -a __ad_vs
|
||||||
|
eval '
|
||||||
|
for __ad_v in "${'"$1"'[@]}"; do
|
||||||
|
if [ "$__ad_v" != "$2" ]; then
|
||||||
|
__ad_vs=("${__ad_vs[@]}" "$__ad_v")
|
||||||
|
fi
|
||||||
|
done'
|
||||||
|
array_copy "$1" __ad_vs
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_addu "ajouter la valeur \$2 au tableau \$1, si la valeur n'y est pas déjà
|
||||||
|
|
||||||
|
Retourner vrai si la valeur a été ajoutée"
|
||||||
|
function array_addu() {
|
||||||
|
local __as_v
|
||||||
|
eval '
|
||||||
|
for __as_v in "${'"$1"'[@]}"; do
|
||||||
|
[ "$__as_v" == "$2" ] && return 1
|
||||||
|
done'
|
||||||
|
array_add "$1" "$2"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_insu "insérer la valeur \$2 au début du tableau tableau \$1, si la valeur n'y est pas déjà
|
||||||
|
|
||||||
|
Retourner vrai si la valeur a été ajoutée."
|
||||||
|
function array_insu() {
|
||||||
|
local __as_v
|
||||||
|
eval '
|
||||||
|
for __as_v in "${'"$1"'[@]}"; do
|
||||||
|
[ "$__as_v" == "$2" ] && return 1
|
||||||
|
done'
|
||||||
|
array_ins "$1" "$2"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_fillrange "Initialiser le tableau \$1 avec les nombres de \$2(=1) à \$3(=10) avec un step de \$4(=1)"
|
||||||
|
function array_fillrange() {
|
||||||
|
local -a __af_vs
|
||||||
|
local __af_i="${2:-1}" __af_to="${3:-10}" __af_step="${4:-1}"
|
||||||
|
while [ "$__af_i" -le "$__af_to" ]; do
|
||||||
|
__af_vs=("${__af_vs[@]}" "$__af_i")
|
||||||
|
__af_i=$(($__af_i + $__af_step))
|
||||||
|
done
|
||||||
|
array_copy "$1" __af_vs
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_eq "tester l'égalité des tableaux \$1 et \$2"
|
||||||
|
function array_eq() {
|
||||||
|
local -a __ae_a1 __ae_a2
|
||||||
|
array_copy __ae_a1 "$1"
|
||||||
|
array_copy __ae_a2 "$2"
|
||||||
|
[ ${#__ae_a1[*]} -eq ${#__ae_a2[*]} ] || return 1
|
||||||
|
local __ae_v __ae_i=0
|
||||||
|
for __ae_v in "${__ae_a1[@]}"; do
|
||||||
|
[ "$__ae_v" == "${__ae_a2[$__ae_i]}" ] || return 1
|
||||||
|
__ae_i=$(($__ae_i + 1))
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_contains "tester si le tableau \$1 contient la valeur \$2"
|
||||||
|
function array_contains() {
|
||||||
|
local __ac_v
|
||||||
|
eval '
|
||||||
|
for __ac_v in "${'"$1"'[@]}"; do
|
||||||
|
[ "$__ac_v" == "$2" ] && return 0
|
||||||
|
done'
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_icontains "tester si le tableau \$1 contient la valeur \$2, sans tenir compte de la casse"
|
||||||
|
function array_icontains() {
|
||||||
|
local __ac_v
|
||||||
|
eval '
|
||||||
|
for __ac_v in "${'"$1"'[@]}"; do
|
||||||
|
[ "${__ac_v,,} == "${2,,}" ] && return 0
|
||||||
|
done'
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_find "si le tableau \$1 contient la valeur \$2, afficher l'index de la valeur. Si le tableau \$3 est spécifié, afficher la valeur à l'index dans ce tableau"
|
||||||
|
function array_find() {
|
||||||
|
local __af_i __af_v
|
||||||
|
__af_i=0
|
||||||
|
eval '
|
||||||
|
for __af_v in "${'"$1"'[@]}"; do
|
||||||
|
if [ "$__af_v" == "$2" ]; then
|
||||||
|
if [ -n "$3" ]; then
|
||||||
|
recho "${'"$3"'[$__af_i]}"
|
||||||
|
else
|
||||||
|
echo "$__af_i"
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
__af_i=$(($__af_i + 1))
|
||||||
|
done'
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_reverse "Inverser l'ordre des élément du tableau \$1"
|
||||||
|
function array_reverse() {
|
||||||
|
local -a __ar_vs
|
||||||
|
local __ar_v
|
||||||
|
array_copy __ar_vs "$1"
|
||||||
|
array_new "$1"
|
||||||
|
for __ar_v in "${__ar_vs[@]}"; do
|
||||||
|
array_ins "$1" "$__ar_v"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_replace "dans le tableau \$1, remplacer toutes les occurences de \$2 par \$3..*"
|
||||||
|
function array_replace() {
|
||||||
|
local __ar_sn="$1"; shift
|
||||||
|
local __ar_f="$1"; shift
|
||||||
|
local -a __ar_s __ar_d
|
||||||
|
local __ar_v
|
||||||
|
array_copy __ar_s "$__ar_sn"
|
||||||
|
for __ar_v in "${__ar_s[@]}"; do
|
||||||
|
if [ "$__ar_v" == "$__ar_f" ]; then
|
||||||
|
__ar_d=("${__ar_d[@]}" "$@")
|
||||||
|
else
|
||||||
|
__ar_d=("${__ar_d[@]}" "$__ar_v")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
array_copy "$__ar_sn" __ar_d
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_each "Pour chacune des valeurs ITEM du tableau \$1, appeler la fonction \$2 avec les arguments (\$3..@ ITEM)"
|
||||||
|
function array_each() {
|
||||||
|
local __ae_v
|
||||||
|
local -a __ae_a
|
||||||
|
array_copy __ae_a "$1"; shift
|
||||||
|
for __ae_v in "${__ae_a[@]}"; do
|
||||||
|
"$@" "$__ae_v"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_map "Pour chacune des valeurs ITEM du tableau \$1, appeler la fonction \$2 avec les arguments (\$3..@ ITEM), et remplacer la valeur par le résultat de la fonction"
|
||||||
|
function array_map() {
|
||||||
|
local __am_v
|
||||||
|
local -a __am_a __am_vs
|
||||||
|
local __am_an="$1"; shift
|
||||||
|
local __am_f="$1"; shift
|
||||||
|
array_copy __am_a "$__am_an"
|
||||||
|
for __am_v in "${__am_a[@]}"; do
|
||||||
|
__am_vs=("${__am_vs[@]}" "$("$__am_f" "$@" "$__am_v")")
|
||||||
|
done
|
||||||
|
array_copy "$__am_an" __am_vs
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_first "afficher la première valeur du tableau \$1"
|
||||||
|
function array_first() {
|
||||||
|
eval "recho \"\${$1[@]:0:1}\""
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_last "afficher la dernière valeur du tableau \$1"
|
||||||
|
function array_last() {
|
||||||
|
eval "recho \"\${$1[@]: -1:1}\""
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_copy_firsts "copier toutes les valeurs du tableau \$2(=\$1) dans le tableau \$1, excepté la dernière"
|
||||||
|
function array_copy_firsts() {
|
||||||
|
eval "$1=(\"\${${2:-$1}[@]:0:\$((\${#${2:-$1}[@]}-1))}\")"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_copy_lasts "copier toutes les valeurs du tableau \$2(=\$1) dans le tableau \$1, excepté la première"
|
||||||
|
function array_copy_lasts() {
|
||||||
|
eval "$1=(\"\${${2:-$1}[@]:1}\")"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_extend "ajouter le contenu du tableau \$2 au tableau \$1"
|
||||||
|
function array_extend() {
|
||||||
|
eval "$1=(\"\${$1[@]}\" \"\${$2[@]}\")"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_extendu "ajouter chacune des valeurs du tableau \$2 au tableau \$1, si ces valeurs n'y sont pas déjà
|
||||||
|
|
||||||
|
Retourner vrai si au moins une valeur a été ajoutée"
|
||||||
|
function array_extendu() {
|
||||||
|
local __ae_v __ae_s=1
|
||||||
|
eval '
|
||||||
|
for __ae_v in "${'"$2"'[@]}"; do
|
||||||
|
array_addu "$1" "$__ae_v" && __ae_s=0
|
||||||
|
done'
|
||||||
|
return "$__ae_s"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_extend_firsts "ajouter toutes les valeurs du tableau \$2 dans le tableau \$1, excepté la dernière"
|
||||||
|
function array_extend_firsts() {
|
||||||
|
eval "$1=(\"\${$1[@]}\" \"\${$2[@]:0:\$((\${#$2[@]}-1))}\")"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_extend_lasts "ajouter toutes les valeurs du tableau \$2 dans le tableau \$1, excepté la première"
|
||||||
|
function array_extend_lasts() {
|
||||||
|
eval "$1=(\"\${$1[@]}\" \"\${$2[@]:1}\")"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_xsplit "créer le tableau \$1 avec chaque élément de \$2 (un ensemble d'éléments séparés par \$3, qui vaut ':' par défaut)"
|
||||||
|
function array_xsplit() {
|
||||||
|
eval "$1=($(recho_ "$2" | lawk -v RS="${3:-:}" '
|
||||||
|
{
|
||||||
|
gsub(/'\''/, "'\'\\\\\'\''")
|
||||||
|
print "'\''" $0 "'\''"
|
||||||
|
}'))" #"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_xsplitc "variante de array_xsplit() où le séparateur est ',' par défaut"
|
||||||
|
function array_xsplitc() {
|
||||||
|
array_xsplit "$1" "$2" "${3:-,}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_split "créer le tableau \$1 avec chaque élément de \$2 (un ensemble d'éléments séparés par \$3, qui vaut ':' par défaut)
|
||||||
|
|
||||||
|
Les éléments vides sont ignorés. par exemple \"a::b\" est équivalent à \"a:b\""
|
||||||
|
function array_split() {
|
||||||
|
eval "$1=($(recho_ "$2" | lawk -v RS="${3:-:}" '
|
||||||
|
/^$/ { next }
|
||||||
|
{
|
||||||
|
gsub(/'\''/, "'\'\\\\\'\''")
|
||||||
|
print "'\''" $0 "'\''"
|
||||||
|
}'))" #"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_splitc "variante de array_split() où le séparateur est ',' par défaut"
|
||||||
|
function array_splitc() {
|
||||||
|
array_split "$1" "$2" "${3:-,}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_xsplitl "créer le tableau \$1 avec chaque ligne de \$2"
|
||||||
|
function array_xsplitl() {
|
||||||
|
eval "$1=($(recho_ "$2" | nl2lf | lawk '
|
||||||
|
{
|
||||||
|
gsub(/'\''/, "'\'\\\\\'\''")
|
||||||
|
print "'\''" $0 "'\''"
|
||||||
|
}'))" #"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_splitl "créer le tableau \$1 avec chaque ligne de \$2
|
||||||
|
|
||||||
|
Les lignes vides sont ignorés."
|
||||||
|
function array_splitl() {
|
||||||
|
eval "$1=($(recho_ "$2" | nl2lf | lawk '
|
||||||
|
/^$/ { next }
|
||||||
|
{
|
||||||
|
gsub(/'\''/, "'\'\\\\\'\''")
|
||||||
|
print "'\''" $0 "'\''"
|
||||||
|
}'))" #"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_join "afficher le contenu du tableau \$1 sous forme d'une liste de valeurs séparées par \$2 (qui vaut ':' par défaut)
|
||||||
|
|
||||||
|
* Si \$1==\"@\", alors les éléments du tableaux sont les arguments de la fonction à partir de \$3
|
||||||
|
* Si \$1!=\"@\" et que le tableau est vide, afficher \$3
|
||||||
|
* Si \$1!=\"@\", \$4 et \$5 sont des préfixes et suffixes à rajouter à chaque élément"
|
||||||
|
function array_join() {
|
||||||
|
local __aj_an __aj_l __aj_j __aj_s="${2:-:}" __aj_pf __aj_sf
|
||||||
|
if [ "$1" == "@" ]; then
|
||||||
|
__aj_an="\$@"
|
||||||
|
shift; shift
|
||||||
|
else
|
||||||
|
__aj_an="\${$1[@]}"
|
||||||
|
__aj_pf="$4"
|
||||||
|
__aj_sf="$5"
|
||||||
|
fi
|
||||||
|
eval '
|
||||||
|
for __aj_l in "'"$__aj_an"'"; do
|
||||||
|
__aj_j="${__aj_j:+$__aj_j'"$__aj_s"'}$__aj_pf$__aj_l$__aj_sf"
|
||||||
|
done'
|
||||||
|
if [ -n "$__aj_j" ]; then
|
||||||
|
recho "$__aj_j"
|
||||||
|
elif [ "$__aj_an" != "\$@" -a -n "$3" ]; then
|
||||||
|
recho "$3"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_joinc "afficher les éléments du tableau \$1 séparés par ','"
|
||||||
|
function array_joinc() {
|
||||||
|
array_join "$1" , "$2" "$3" "$4"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_joinl "afficher les éléments du tableau \$1 à raison d'un élément par ligne"
|
||||||
|
function array_joinl() {
|
||||||
|
array_join "$1" "
|
||||||
|
" "$2" "$3" "$4"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_mapjoin "map le tableau \$1 avec la fonction \$2, puis afficher le résultat en séparant chaque élément par \$3
|
||||||
|
|
||||||
|
Les arguments et la sémantique sont les mêmes que pour array_join() en
|
||||||
|
tenant compte de l'argument supplémentaire \$2 qui est la fonction pour
|
||||||
|
array_map() (les autres arguments sont décalés en conséquence)"
|
||||||
|
function array_mapjoin() {
|
||||||
|
local __amj_src="$1" __amj_func="$2" __amj_sep="$3"
|
||||||
|
shift; shift; shift
|
||||||
|
if [ "$__amj_src" == "@" ]; then
|
||||||
|
local -a __amj_tmpsrc
|
||||||
|
__amj_tmpsrc=("$@")
|
||||||
|
__amj_src=__amj_tmpsrc
|
||||||
|
set --
|
||||||
|
fi
|
||||||
|
local -a __amj_tmp
|
||||||
|
array_copy __amj_tmp "$__amj_src"
|
||||||
|
array_map __amj_tmp "$__amj_func"
|
||||||
|
array_join __amj_tmp "$__amj_sep" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_fix_paths "Corriger les valeurs du tableau \$1. Les valeurs contenant le séparateur \$2(=':') sont séparées en plusieurs valeurs.
|
||||||
|
|
||||||
|
Par exemple avec le tableau input=(a b:c), le résultat est input=(a b c)"
|
||||||
|
function array_fix_paths() {
|
||||||
|
local __afp_an="$1" __afp_s="${2:-:}"
|
||||||
|
local -a __afp_vs
|
||||||
|
local __afp_v
|
||||||
|
array_copy __afp_vs "$__afp_an"
|
||||||
|
array_new "$__afp_an"
|
||||||
|
for __afp_v in "${__afp_vs[@]}"; do
|
||||||
|
array_split __afp_v "$__afp_v" "$__afp_s"
|
||||||
|
array_extend "$__afp_an" __afp_v
|
||||||
|
done
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: base.bool "Fonctions de base: valeurs booléennes"
|
||||||
|
|
||||||
|
function: is_yes 'retourner vrai si $1 est une valeur "oui"'
|
||||||
|
function is_yes() {
|
||||||
|
case "${1,,}" in
|
||||||
|
o|oui|y|yes|v|vrai|t|true|on) return 0;;
|
||||||
|
esac
|
||||||
|
isnum "$1" && [ "$1" -ne 0 ] && return 0
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function: is_no 'retourner vrai si $1 est une valeur "non"'
|
||||||
|
function is_no() {
|
||||||
|
case "${1,,}" in
|
||||||
|
n|non|no|f|faux|false|off) return 0;;
|
||||||
|
esac
|
||||||
|
isnum "$1" && [ "$1" -eq 0 ] && return 0
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function: normyesval 'remplacer les valeurs des variables $1..* par la valeur normalisée de leur valeur "oui"'
|
||||||
|
function normyesval() {
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
is_yes "${!1}" && _setv "$1" 1 || _setv "$1" ""
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function: setb 'Lancer la commande $2..@ en supprimant la sortie standard. Si la commande
|
||||||
|
retourne vrai, assigner la valeur 1 à la variable $1. Sinon, lui assigner la
|
||||||
|
valeur ""
|
||||||
|
note: en principe, la syntaxe est "setb var cmd args...". cependant, la
|
||||||
|
syntaxe "setb var=cmd args..." est supportée aussi'
|
||||||
|
function setb() {
|
||||||
|
local __s_var="$1"; shift
|
||||||
|
if [[ "$__s_var" == *=* ]]; then
|
||||||
|
set -- "${__s_var#*=}" "$@"
|
||||||
|
__s_var="${__s_var%%=*}"
|
||||||
|
fi
|
||||||
|
local __s_r
|
||||||
|
if "$@" >/dev/null; then
|
||||||
|
eval "$__s_var=1"
|
||||||
|
else
|
||||||
|
__s_r=$?
|
||||||
|
eval "$__s_var="
|
||||||
|
return $__s_r
|
||||||
|
fi
|
||||||
|
}
|
|
@ -0,0 +1,458 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: base.core "Fonctions de base: fondement"
|
||||||
|
|
||||||
|
function: echo_ "afficher la valeur \$* sans passer à la ligne"
|
||||||
|
function echo_() { echo -n "$*"; }
|
||||||
|
|
||||||
|
function: recho "afficher une valeur brute.
|
||||||
|
|
||||||
|
contrairement à la commande echo, ne reconnaitre aucune option (i.e. -e, -E, -n
|
||||||
|
ne sont pas signifiants)"
|
||||||
|
function recho() {
|
||||||
|
if [[ "${1:0:2}" == -[eEn] ]]; then
|
||||||
|
local first="${1:1}"; shift
|
||||||
|
echo -n -
|
||||||
|
echo "$first" "$@"
|
||||||
|
else
|
||||||
|
echo "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: recho_ "afficher une valeur brute, sans passer à la ligne.
|
||||||
|
|
||||||
|
contrairement à la commande echo, ne reconnaitre aucune option (i.e. -e, -E, -n
|
||||||
|
ne sont pas signifiants)"
|
||||||
|
function recho_() {
|
||||||
|
if [[ "${1:0:2}" == -[eEn] ]]; then
|
||||||
|
local first="${1:1}"; shift
|
||||||
|
echo -n -
|
||||||
|
echo -n "$first" "$@"
|
||||||
|
else
|
||||||
|
echo -n "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: _qval "Dans la chaine \$*, remplacer:
|
||||||
|
~~~
|
||||||
|
\\ par \\\\
|
||||||
|
\" par \\\"
|
||||||
|
\$ par \\\$
|
||||||
|
\` par \\\`
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Cela permet de quoter une chaine à mettre entre guillements.
|
||||||
|
|
||||||
|
note: la protection de ! n'est pas effectuée, parce que le comportement du shell
|
||||||
|
est incohérent entre le shell interactif et les scripts. Pour une version plus
|
||||||
|
robuste, il est nécessaire d'utiliser un programme externe tel que sed ou awk"
|
||||||
|
function _qval() {
|
||||||
|
local s="$*"
|
||||||
|
s="${s//\\/\\\\}"
|
||||||
|
s="${s//\"/\\\"}"
|
||||||
|
s="${s//\$/\\\$}"
|
||||||
|
s="${s//\`/\\\`}"
|
||||||
|
recho_ "$s"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: should_quote "Tester si la chaine \$* doit être mise entre quotes"
|
||||||
|
function should_quote() {
|
||||||
|
# pour optimiser, toujours mettre entre quotes si plusieurs arguments sont
|
||||||
|
# spécifiés ou si on spécifie une chaine vide ou de plus de 80 caractères
|
||||||
|
[ $# -eq 0 -o $# -gt 1 -o ${#1} -eq 0 -o ${#1} -gt 80 ] && return 0
|
||||||
|
# sinon, tester si la chaine contient des caractères spéciaux
|
||||||
|
local s="$*"
|
||||||
|
s="${s//[a-zA-Z0-9]/}"
|
||||||
|
s="${s//,/}"
|
||||||
|
s="${s//./}"
|
||||||
|
s="${s//+/}"
|
||||||
|
s="${s//\//}"
|
||||||
|
s="${s//-/}"
|
||||||
|
s="${s//_/}"
|
||||||
|
s="${s//=/}"
|
||||||
|
[ -n "$s" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
function: qval "Afficher la chaine \$* quotée avec \""
|
||||||
|
function qval() {
|
||||||
|
echo -n \"
|
||||||
|
_qval "$@"
|
||||||
|
echo \"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: qvalm "Afficher la chaine \$* quotée si nécessaire avec \""
|
||||||
|
function qvalm() {
|
||||||
|
if should_quote "$@"; then
|
||||||
|
echo -n \"
|
||||||
|
_qval "$@"
|
||||||
|
echo \"
|
||||||
|
else
|
||||||
|
recho "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: qvalr "Afficher la chaine \$* quotée si nécessaire avec \", sauf si elle est vide"
|
||||||
|
function qvalr() {
|
||||||
|
if [ -z "$*" ]; then
|
||||||
|
:
|
||||||
|
elif should_quote "$@"; then
|
||||||
|
echo -n \"
|
||||||
|
_qval "$@"
|
||||||
|
echo \"
|
||||||
|
else
|
||||||
|
recho "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: qvals "Afficher chaque argument de cette fonction quotée le cas échéant avec \", chaque valeur étant séparée par un espace"
|
||||||
|
function qvals() {
|
||||||
|
local arg first=1
|
||||||
|
for arg in "$@"; do
|
||||||
|
[ -z "$first" ] && echo -n " "
|
||||||
|
if should_quote "$arg"; then
|
||||||
|
echo -n \"
|
||||||
|
_qval "$arg"
|
||||||
|
echo -n \"
|
||||||
|
else
|
||||||
|
recho_ "$arg"
|
||||||
|
fi
|
||||||
|
first=
|
||||||
|
done
|
||||||
|
[ -z "$first" ] && echo
|
||||||
|
}
|
||||||
|
|
||||||
|
function: qwc "Dans la chaine \$*, remplacer:
|
||||||
|
~~~
|
||||||
|
\\ par \\\\
|
||||||
|
\" par \\\"
|
||||||
|
\$ par \\\$
|
||||||
|
\` par \\\`
|
||||||
|
~~~
|
||||||
|
puis quoter la chaine avec \", sauf les wildcards *, ? et [class]
|
||||||
|
|
||||||
|
Cela permet de quoter une chaine permettant de glober des fichiers, e.g
|
||||||
|
~~~
|
||||||
|
eval \"ls \$(qwc \"\$value\")\"
|
||||||
|
~~~
|
||||||
|
|
||||||
|
note: la protection de ! n'est pas effectuée, parce que le comportement du shell
|
||||||
|
est incohérent entre le shell interactif et les scripts. Pour une version plus
|
||||||
|
robuste, il est nécessaire d'utiliser un programme externe tel que sed ou awk"
|
||||||
|
function qwc() {
|
||||||
|
local s="$*"
|
||||||
|
s="${s//\\/\\\\}"
|
||||||
|
s="${s//\"/\\\"}"
|
||||||
|
s="${s//\$/\\\$}"
|
||||||
|
s="${s//\`/\\\`}"
|
||||||
|
local r a b c
|
||||||
|
while [ -n "$s" ]; do
|
||||||
|
a=; b=; c=
|
||||||
|
a=; [[ "$s" == *\** ]] && { a="${s%%\**}"; a=${#a}; }
|
||||||
|
b=; [[ "$s" == *\?* ]] && { b="${s%%\?*}"; b=${#b}; }
|
||||||
|
c=; [[ "$s" == *\[* ]] && { c="${s%%\[*}"; c=${#c}; }
|
||||||
|
if [ -z "$a" -a -z "$b" -a -z "$c" ]; then
|
||||||
|
r="$r\"$s\""
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if [ -n "$a" ]; then
|
||||||
|
[ -n "$b" ] && [ $a -lt $b ] && b=
|
||||||
|
[ -n "$c" ] && [ $a -lt $c ] && c=
|
||||||
|
fi
|
||||||
|
if [ -n "$b" ]; then
|
||||||
|
[ -n "$a" ] && [ $b -lt $a ] && a=
|
||||||
|
[ -n "$c" ] && [ $b -lt $c ] && c=
|
||||||
|
fi
|
||||||
|
if [ -n "$c" ]; then
|
||||||
|
[ -n "$a" ] && [ $c -lt $a ] && a=
|
||||||
|
[ -n "$b" ] && [ $c -lt $b ] && b=
|
||||||
|
fi
|
||||||
|
if [ -n "$a" ]; then # PREFIX*
|
||||||
|
a="${s%%\**}"
|
||||||
|
s="${s#*\*}"
|
||||||
|
[ -n "$a" ] && r="$r\"$a\""
|
||||||
|
r="$r*"
|
||||||
|
elif [ -n "$b" ]; then # PREFIX?
|
||||||
|
a="${s%%\?*}"
|
||||||
|
s="${s#*\?}"
|
||||||
|
[ -n "$a" ] && r="$r\"$a\""
|
||||||
|
r="$r?"
|
||||||
|
elif [ -n "$c" ]; then # PREFIX[class]
|
||||||
|
a="${s%%\[*}"
|
||||||
|
b="${s#*\[}"; b="${b%%\]*}"
|
||||||
|
s="${s:$((${#a} + ${#b} + 2))}"
|
||||||
|
[ -n "$a" ] && r="$r\"$a\""
|
||||||
|
r="$r[$b]"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
recho_ "$r"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: qlines "Traiter chaque ligne de l'entrée standard pour en faire des chaines quotées avec '"
|
||||||
|
function qlines() {
|
||||||
|
sed "s/'/'\\\\''/g; s/.*/'&'/g"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: setv "initialiser la variable \$1 avec la valeur \$2..*
|
||||||
|
|
||||||
|
note: en principe, la syntaxe est 'setv var values...'. cependant, la syntaxe 'setv var=values...' est supportée aussi"
|
||||||
|
function setv() {
|
||||||
|
local s__var="$1"; shift
|
||||||
|
if [[ "$s__var" == *=* ]]; then
|
||||||
|
set -- "${s__var#*=}" "$@"
|
||||||
|
s__var="${s__var%%=*}"
|
||||||
|
fi
|
||||||
|
eval "$s__var=\"\$*\""
|
||||||
|
}
|
||||||
|
|
||||||
|
function: _setv "Comme la fonction setv() mais ne supporte que la syntaxe '_setv var values...'
|
||||||
|
|
||||||
|
Cette fonction est légèrement plus rapide que setv()"
|
||||||
|
function _setv() {
|
||||||
|
local s__var="$1"; shift
|
||||||
|
eval "$s__var=\"\$*\""
|
||||||
|
}
|
||||||
|
|
||||||
|
function: echo_setv "Afficher la commande qui serait lancée par setv \"\$@\""
|
||||||
|
function echo_setv() {
|
||||||
|
local s__var="$1"; shift
|
||||||
|
if [[ "$s__var" == *=* ]]; then
|
||||||
|
set -- "${s__var#*=}" "$@"
|
||||||
|
s__var="${s__var%%=*}"
|
||||||
|
fi
|
||||||
|
echo "$s__var=$(qvalr "$*")"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: echo_setv2 "Afficher la commande qui recrée la variable \$1.
|
||||||
|
|
||||||
|
Equivalent à
|
||||||
|
~~~
|
||||||
|
echo_setv \"\$1=\${!1}\"
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Si d'autres arguments que le nom de la variable sont spécifiés, cette fonction
|
||||||
|
se comporte comme echo_setv()"
|
||||||
|
function echo_setv2() {
|
||||||
|
local s__var="$1"; shift
|
||||||
|
if [[ "$s__var" == *=* ]]; then
|
||||||
|
set -- "${s__var#*=}" "$@"
|
||||||
|
s__var="${s__var%%=*}"
|
||||||
|
fi
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
echo_setv "$s__var" "${!s__var}"
|
||||||
|
else
|
||||||
|
echo_setv "$s__var" "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: seta "initialiser le tableau \$1 avec les valeurs \$2..@
|
||||||
|
|
||||||
|
note: en principe, la syntaxe est 'seta array values...'. cependant, la syntaxe
|
||||||
|
'seta array=values...' est supportée aussi"
|
||||||
|
function seta() {
|
||||||
|
local s__array="$1"; shift
|
||||||
|
if [[ "$s__array" == *=* ]]; then
|
||||||
|
set -- "${s__array#*=}" "$@"
|
||||||
|
s__array="${s__array%%=*}"
|
||||||
|
fi
|
||||||
|
eval "$s__array=(\"\$@\")"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: _seta "Comme la fonction seta() mais ne supporte que la syntaxe '_seta array values...'
|
||||||
|
|
||||||
|
Cette fonction est légèrement plus rapide que seta()"
|
||||||
|
function _seta() {
|
||||||
|
local s__array="$1"; shift
|
||||||
|
eval "$s__array=(\"\$@\")"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: echo_seta "Afficher la commande qui serait lancée par seta \"\$@\""
|
||||||
|
function echo_seta() {
|
||||||
|
local s__var="$1"; shift
|
||||||
|
if [[ "$s__var" == *=* ]]; then
|
||||||
|
set -- "${s__var#*=}" "$@"
|
||||||
|
s__var="${s__var%%=*}"
|
||||||
|
fi
|
||||||
|
echo "$s__var=($(qvals "$@"))"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: echo_seta2 "Afficher la commande qui recrée le tableau \$1
|
||||||
|
|
||||||
|
Si d'autres arguments que le nom de tableau sont spécifiés, cette fonction se
|
||||||
|
comporte comme echo_seta()"
|
||||||
|
function echo_seta2() {
|
||||||
|
local s__var="$1"; shift
|
||||||
|
if [[ "$s__var" == *=* ]]; then
|
||||||
|
set -- "${s__var#*=}" "$@"
|
||||||
|
s__var="${s__var%%=*}"
|
||||||
|
elif [ $# -eq 0 ]; then
|
||||||
|
eval "set -- \"\${$s__var[@]}\""
|
||||||
|
fi
|
||||||
|
echo "$s__var=($(qvals "$@"))"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: setx "Initialiser une variable avec le résultat d'une commande
|
||||||
|
|
||||||
|
* syntaxe 1: initialiser la variable \$1 avec le résultat de la commande \"\$2..@\"
|
||||||
|
~~~
|
||||||
|
setx var cmd
|
||||||
|
~~~
|
||||||
|
note: en principe, la syntaxe est 'setx var cmd args...'. cependant, la syntaxe
|
||||||
|
'setx var=cmd args...' est supportée aussi
|
||||||
|
|
||||||
|
* syntaxe 2: initialiser le tableau \$1 avec le résultat de la commande
|
||||||
|
\"\$2..@\", chaque ligne du résultat étant un élément du tableau
|
||||||
|
~~~
|
||||||
|
setx -a array cmd
|
||||||
|
~~~
|
||||||
|
note: en principe, la syntaxe est 'setx -a array cmd args...'. cependant, la
|
||||||
|
syntaxe 'setx -a array=cmd args...' est supportée aussi"
|
||||||
|
function setx() {
|
||||||
|
if [ "$1" == -a ]; then
|
||||||
|
shift
|
||||||
|
local s__array="$1"; shift
|
||||||
|
if [[ "$s__array" == *=* ]]; then
|
||||||
|
set -- "${s__array#*=}" "$@"
|
||||||
|
s__array="${s__array%%=*}"
|
||||||
|
fi
|
||||||
|
eval "$s__array=($("$@" | qlines))"
|
||||||
|
else
|
||||||
|
local s__var="$1"; shift
|
||||||
|
if [[ "$s__var" == *=* ]]; then
|
||||||
|
set -- "${s__var#*=}" "$@"
|
||||||
|
s__var="${s__var%%=*}"
|
||||||
|
fi
|
||||||
|
eval "$s__var="'"$("$@")"'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: _setvx "Comme la fonction setx() mais ne supporte que l'initialisation d'une variable scalaire avec la syntaxe '_setvx var cmd args...' pour gagner (un peu) en rapidité d'exécution."
|
||||||
|
function _setvx() {
|
||||||
|
local s__var="$1"; shift
|
||||||
|
eval "$s__var="'"$("$@")"'
|
||||||
|
}
|
||||||
|
|
||||||
|
function: _setax "Comme la fonction setx() mais ne supporte que l'initialisation d'un tableau avec la syntaxe '_setax array cmd args...' pour gagner (un peu) en rapidité d'exécution."
|
||||||
|
function _setax() {
|
||||||
|
local s__array="$1"; shift
|
||||||
|
eval "$s__array=($("$@" | qlines))"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: is_defined "tester si la variable \$1 est définie"
|
||||||
|
function is_defined() {
|
||||||
|
[ -n "$(declare -p "$1" 2>/dev/null)" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
function: is_array "tester si la variable \$1 est un tableau"
|
||||||
|
function is_array() {
|
||||||
|
[[ "$(declare -p "$1" 2>/dev/null)" =~ declare\ -[^\ ]*a[^\ ]*\ ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_local "afficher les commandes pour faire une copie dans la variable locale \$1 du tableau \$2"
|
||||||
|
function array_local() {
|
||||||
|
if [ "$1" == "$2" ]; then
|
||||||
|
declare -p "$1" 2>/dev/null || echo "local -a $1"
|
||||||
|
else
|
||||||
|
echo "local -a $1; $1=(\"\${$2[@]}\")"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: upvar "Implémentation de upvar() de http://www.fvue.nl/wiki/Bash:_Passing_variables_by_reference
|
||||||
|
|
||||||
|
USAGE
|
||||||
|
~~~
|
||||||
|
local varname && upvar varname values...
|
||||||
|
~~~
|
||||||
|
* @param varname Variable name to assign value to
|
||||||
|
* @param values Value(s) to assign. If multiple values (> 1), an array is
|
||||||
|
assigned, otherwise a single value is assigned."
|
||||||
|
function upvar() {
|
||||||
|
if unset -v "$1"; then
|
||||||
|
if [ $# -lt 2 ]; then
|
||||||
|
eval "$1=\"\$2\""
|
||||||
|
else
|
||||||
|
eval "$1=(\"\${@:2}\")"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: array_upvar "Comme upvar() mais force la création d'un tableau, même s'il y a que 0 ou 1 argument"
|
||||||
|
function array_upvar() {
|
||||||
|
unset -v "$1" && eval "$1=(\"\${@:2}\")"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: upvars "Implémentation modifiée de upvars() de http://www.fvue.nl/wiki/Bash:_Passing_variables_by_reference
|
||||||
|
|
||||||
|
Par rapport à l'original, il n'est plus nécessaire de préfixer une variable
|
||||||
|
scalaire avec -v, et -a peut être spécifié sans argument.
|
||||||
|
|
||||||
|
USAGE
|
||||||
|
~~~
|
||||||
|
local varnames... && upvars [varname value | -aN varname values...]...
|
||||||
|
~~~
|
||||||
|
* @param -a assigns remaining values to varname as array
|
||||||
|
* @param -aN assigns next N values to varname as array. Returns 1 if wrong
|
||||||
|
number of options occurs"
|
||||||
|
function upvars() {
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
-a)
|
||||||
|
unset -v "$2" && eval "$2=(\"\${@:3}\")"
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
-a*)
|
||||||
|
unset -v "$2" && eval "$2=(\"\${@:3:${1#-a}}\")"
|
||||||
|
shift $((${1#-a} + 2)) || return 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
unset -v "$1" && eval "$1=\"\$2\""
|
||||||
|
shift; shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function: set_debug "Passer en mode DEBUG"
|
||||||
|
function set_debug() {
|
||||||
|
export NULIB_DEBUG=1
|
||||||
|
}
|
||||||
|
|
||||||
|
function: is_debug "Tester si on est en mode DEBUG"
|
||||||
|
function is_debug() {
|
||||||
|
[ -n "$NULIB_DEBUG" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
function: lawk "Lancer GNUawk avec la librairie 'base'"
|
||||||
|
function lawk() {
|
||||||
|
gawk -i base.awk "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: cawk "Lancer GNUawk avec LANG=C et la librairie 'base'
|
||||||
|
|
||||||
|
Le fait de forcer la valeur de LANG permet d'éviter les problèmes avec la locale"
|
||||||
|
function cawk() {
|
||||||
|
LANG=C gawk -i base.awk "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: lsort "Lancer sort avec support de la locale courante"
|
||||||
|
function: csort "Lancer sort avec LANG=C pour désactiver le support de la locale
|
||||||
|
|
||||||
|
Avec LANG!=C, sort utilise les règles de la locale pour le tri, et par
|
||||||
|
exemple, avec LANG=fr_FR.UTF-8, la locale indique que les ponctuations doivent
|
||||||
|
être ignorées."
|
||||||
|
function lsort() { sort "$@"; }
|
||||||
|
function csort() { LANG=C sort "$@"; }
|
||||||
|
|
||||||
|
function: lgrep "Lancer grep avec support de la locale courante"
|
||||||
|
function: cgrep "Lancer grep avec LANG=C pour désactiver le support de la locale"
|
||||||
|
function lgrep() { grep "$@"; }
|
||||||
|
function cgrep() { LANG=C grep "$@"; }
|
||||||
|
|
||||||
|
function: lsed "Lancer sed avec support de la locale courante"
|
||||||
|
function: csed "Lancer sed avec LANG=C pour désactiver le support de la locale"
|
||||||
|
function lsed() { sed "$@"; }
|
||||||
|
function csed() { LANG=C sed "$@"; }
|
||||||
|
|
||||||
|
function: ldiff "Lancer diff avec support de la locale courante"
|
||||||
|
function: cdiff "Lancer diff avec LANG=C pour désactiver le support de la locale"
|
||||||
|
function ldiff() { diff "$@"; }
|
||||||
|
function cdiff() { LANG=C diff "$@"; }
|
|
@ -0,0 +1,53 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: base.init "Fonctions de base: initialiser l'environnement"
|
||||||
|
|
||||||
|
if [ -z "$NULIB_NO_INIT_ENV" ]; then
|
||||||
|
# Emplacement du script courant
|
||||||
|
if [ "$0" == "-bash" ]; then
|
||||||
|
MYNAME=
|
||||||
|
MYDIR=
|
||||||
|
MYSELF=
|
||||||
|
elif [ ! -f "$0" -a -f "${0#-}" ]; then
|
||||||
|
MYNAME="$(basename -- "${0#-}")"
|
||||||
|
MYDIR="$(dirname -- "${0#-}")"
|
||||||
|
MYDIR="$(cd "$MYDIR"; pwd)"
|
||||||
|
MYSELF="$MYDIR/$MYNAME"
|
||||||
|
else
|
||||||
|
MYNAME="$(basename -- "$0")"
|
||||||
|
MYDIR="$(dirname -- "$0")"
|
||||||
|
MYDIR="$(cd "$MYDIR"; pwd)"
|
||||||
|
MYSELF="$MYDIR/$MYNAME"
|
||||||
|
fi
|
||||||
|
[ -n "$NULIBDIR" ] || NULIBDIR="$MYDIR"
|
||||||
|
|
||||||
|
# Repertoire temporaire
|
||||||
|
[ -z "$TMPDIR" -a -d "$HOME/tmp" ] && TMPDIR="$HOME/tmp"
|
||||||
|
[ -z "$TMPDIR" ] && TMPDIR="${TMP:-${TEMP:-/tmp}}"
|
||||||
|
export TMPDIR
|
||||||
|
|
||||||
|
# User
|
||||||
|
[ -z "$USER" -a -n "$LOGNAME" ] && export USER="$LOGNAME"
|
||||||
|
|
||||||
|
# Le fichier nulibrc doit être chargé systématiquement
|
||||||
|
[ -f /etc/debian_chroot ] && NULIB_CHROOT=1
|
||||||
|
[ -f /etc/nulibrc ] && . /etc/nulibrc
|
||||||
|
[ -f ~/.nulibrc ] && . ~/.nulibrc
|
||||||
|
|
||||||
|
# Type de système sur lequel tourne le script
|
||||||
|
UNAME_SYSTEM=`uname -s`
|
||||||
|
[ "${UNAME_SYSTEM#CYGWIN}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Cygwin
|
||||||
|
[ "${UNAME_SYSTEM#MINGW32}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Mingw
|
||||||
|
UNAME_MACHINE=`uname -m`
|
||||||
|
if [ -n "$NULIB_CHROOT" ]; then
|
||||||
|
# Dans un chroot, il est possible de forcer les valeurs
|
||||||
|
[ -n "$NULIB_UNAME_SYSTEM" ] && eval "UNAME_SYSTEM=$NULIB_UNAME_SYSTEM"
|
||||||
|
[ -n "$NULIB_UNAME_MACHINE" ] && eval "UNAME_MACHINE=$NULIB_UNAME_MACHINE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Nom d'hôte respectivement avec et sans domaine
|
||||||
|
# contrairement à $HOSTNAME, cette valeur peut être spécifiée, comme par ruinst
|
||||||
|
[ -n "$MYHOST" ] || MYHOST="$HOSTNAME"
|
||||||
|
[ -n "$MYHOSTNAME" ] || MYHOSTNAME="${HOSTNAME%%.*}"
|
||||||
|
export MYHOST MYHOSTNAME
|
||||||
|
fi
|
|
@ -0,0 +1,581 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: base.input "Fonctions de base: saisie"
|
||||||
|
|
||||||
|
function toienc() {
|
||||||
|
# $1 étant une variable contenant une chaine encodée dans l'encoding d'entrée $2
|
||||||
|
# (qui vaut par défaut $NULIB_INPUT_ENCODING), transformer cette chaine en
|
||||||
|
# utf-8
|
||||||
|
local __var="$1" __from="${2:-$NULIB_INPUT_ENCODING}"
|
||||||
|
if [ "$__from" != "NULIB__UTF8" ]; then
|
||||||
|
_setv "$__var" "$(iconv -f "$__from" -t utf-8 <<<"${!__var}")"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function uread() {
|
||||||
|
# Lire une valeur sur stdin et la placer dans la variable $1. On assume que la
|
||||||
|
# valeur en entrée est encodée dans $NULIB_INPUT_ENCODING
|
||||||
|
[ $# -gt 0 ] || set -- REPLY
|
||||||
|
local __var
|
||||||
|
read "$@"
|
||||||
|
for __var in "$@"; do
|
||||||
|
[ -z "$__var" -o "${__var:0:1}" == "-" ] && continue # ignorer les options
|
||||||
|
toienc "$__var"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_interaction() { :;}
|
||||||
|
function is_interaction() { return 1; }
|
||||||
|
function check_interaction() { return 0; }
|
||||||
|
function get_interaction_option() { :;}
|
||||||
|
|
||||||
|
function ask_yesno() {
|
||||||
|
# Afficher le message $1 suivi de [oN] ou [On] suivant que $2 vaut O ou N, puis
|
||||||
|
# lire la réponse. Retourner 0 si la réponse est vrai, 1 sinon.
|
||||||
|
# Si $1 est une option, elle est utilisée avec check_interaction pour savoir si
|
||||||
|
# on est en mode interactif ou non. A ce moment-là, les valeurs sont décalées
|
||||||
|
# ($2=message, $3=default)
|
||||||
|
# Si $2 vaut C, la valeur par défaut est N si on est interactif, O sinon
|
||||||
|
# Si $2 vaut X, la valeur par défaut est O si on est interactif, N sinon
|
||||||
|
local interactive=1
|
||||||
|
if [[ "$1" == -* ]]; then
|
||||||
|
if [ "$1" != -- ]; then
|
||||||
|
check_interaction "$1" || interactive=
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
else
|
||||||
|
check_interaction -c || interactive=
|
||||||
|
fi
|
||||||
|
local default="${2:-N}"
|
||||||
|
if [ "$default" == "C" ]; then
|
||||||
|
[ -n "$interactive" ] && default=N || default=O
|
||||||
|
elif [ "$default" == "X" ]; then
|
||||||
|
[ -n "$interactive" ] && default=O || default=N
|
||||||
|
fi
|
||||||
|
if [ -n "$interactive" ]; then
|
||||||
|
local message="$1"
|
||||||
|
local prompt="[oN]"
|
||||||
|
local r
|
||||||
|
is_yes "$default" && prompt="[On]"
|
||||||
|
if [ -n "$message" ]; then
|
||||||
|
__eecho_ "$message" 1>&2
|
||||||
|
else
|
||||||
|
__eecho_ "Voulez-vous continuer?" 1>&2
|
||||||
|
fi
|
||||||
|
tooenc_ " $prompt " 1>&2
|
||||||
|
uread r
|
||||||
|
is_yes "${r:-$default}"
|
||||||
|
else
|
||||||
|
is_yes "$default"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function ask_any() {
|
||||||
|
# Afficher le message $1 suivi du texte "[$2]" (qui vaut par défaut +Oq), puis
|
||||||
|
# lire la réponse. Les lettres de la chaine de format $2 sont numérotées de 0 à
|
||||||
|
# $((${#2} - 1)). Le code de retour est le numéro de la lettre qui a été
|
||||||
|
# sélectionnée. Cette fonction est une généralisation de ask_yesno() pour
|
||||||
|
# n'importe quel ensemble de lettres.
|
||||||
|
# La première lettre en majuscule est la lettre sélectionnée par défaut.
|
||||||
|
# La lettre O matche toutes les lettres qui signifient oui: o, y, 1, v, t
|
||||||
|
# La lettre N matche toutes les lettres qui signifient non: n, f, 0
|
||||||
|
# Il y a des raccourcis:
|
||||||
|
# +O --> On
|
||||||
|
# +N --> oN
|
||||||
|
# +C --> oN si on est en mode interactif, On sinon
|
||||||
|
# +X --> On si on est en mode interactifn oN sinon
|
||||||
|
# Si $1 est une option, elle est utilisée avec check_interaction pour savoir si
|
||||||
|
# on est en mode interactif ou non. A ce moment-là, les valeurs sont décalées
|
||||||
|
# ($2=message, $3=format)
|
||||||
|
local interactive=1
|
||||||
|
if [[ "$1" == -* ]]; then
|
||||||
|
if [ "$1" != -- ]; then
|
||||||
|
check_interaction "$1" || interactive=
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
else
|
||||||
|
check_interaction -c || interactive=
|
||||||
|
fi
|
||||||
|
local format="${2:-+Oq}"
|
||||||
|
format="${format/+O/On}"
|
||||||
|
format="${format/+N/oN}"
|
||||||
|
if [ -n "$interactive" ]; then
|
||||||
|
format="${format/+C/oN}"
|
||||||
|
format="${format/+X/On}"
|
||||||
|
else
|
||||||
|
format="${format/+C/On}"
|
||||||
|
format="${format/+X/oN}"
|
||||||
|
fi
|
||||||
|
local i count="${#format}"
|
||||||
|
|
||||||
|
if [ -n "$interactive" ]; then
|
||||||
|
local message="${1:-Voulez-vous continuer?}"
|
||||||
|
local prompt="[$format]"
|
||||||
|
local r f lf defi
|
||||||
|
while true; do
|
||||||
|
__eecho_ "$message $prompt " 1>&2
|
||||||
|
uread r
|
||||||
|
r="$(strlower "${r:0:1}")"
|
||||||
|
i=0; defi=
|
||||||
|
while [ $i -lt $count ]; do
|
||||||
|
f="${format:$i:1}"
|
||||||
|
lf="$(strlower "$f")"
|
||||||
|
[ "$r" == "$lf" ] && return $i
|
||||||
|
if [ -z "$defi" ]; then
|
||||||
|
[ -z "${f/[A-Z]/}" ] && defi="$i"
|
||||||
|
fi
|
||||||
|
if [ "$lf" == o ]; then
|
||||||
|
case "$r" in o|y|1|v|t) return $i;; esac
|
||||||
|
elif [ "$lf" == n ]; then
|
||||||
|
case "$r" in n|f|0) return $i;; esac
|
||||||
|
fi
|
||||||
|
i=$(($i + 1))
|
||||||
|
done
|
||||||
|
[ -z "$r" ] && return ${defi:-0}
|
||||||
|
done
|
||||||
|
else
|
||||||
|
i=0
|
||||||
|
while [ $i -lt $count ]; do
|
||||||
|
f="${format:$i:1}"
|
||||||
|
[ -z "${f/[A-Z]/}" ] && return $i
|
||||||
|
i=$(($i + 1))
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function read_value() {
|
||||||
|
# Afficher le message $1 suivi de la valeur par défaut [$3] si elle est non
|
||||||
|
# vide, puis lire la valeur donnée par l'utilisateur. Cette valeur doit être non
|
||||||
|
# vide si $4(=O) est vrai. La valeur saisie est placée dans la variable
|
||||||
|
# $2(=value)
|
||||||
|
# Si $1 est une option, elle est utilisée avec check_interaction pour savoir si
|
||||||
|
# on est en mode interactif ou non. A ce moment-là, les valeurs sont décalées
|
||||||
|
# ($2=message, $3=variable, $4=default, $5=required)
|
||||||
|
# En mode non interactif, c'est la valeur par défaut qui est sélectionnée. Si
|
||||||
|
# l'utilisateur requière que la valeur soit non vide et que la valeur par défaut
|
||||||
|
# est vide, afficher un message d'erreur et retourner faux
|
||||||
|
# read_password() est comme read_value(), mais la valeur saisie n'est pas
|
||||||
|
# affichée, ce qui la rend appropriée pour la lecture d'un mot de passe.
|
||||||
|
local -a __rv_opts; local __rv_readline=1 __rv_showdef=1 __rv_nl=
|
||||||
|
__rv_opts=()
|
||||||
|
[ -n "$NULIB_NO_READLINE" ] && __rv_readline=
|
||||||
|
__rv_read "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
function read_password() {
|
||||||
|
local -a __rv_opts __rv_readline= __rv_showdef= __rv_nl=1
|
||||||
|
__rv_opts=(-s)
|
||||||
|
__rv_read "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
function __rv_read() {
|
||||||
|
local __rv_int=1
|
||||||
|
if [[ "$1" == -* ]]; then
|
||||||
|
if [ "$1" != -- ]; then
|
||||||
|
check_interaction "$1" || __rv_int=
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
else
|
||||||
|
check_interaction -c || __rv_int=
|
||||||
|
fi
|
||||||
|
local __rv_msg="$1" __rv_v="${2:-value}" __rv_d="$3" __rv_re="${4:-O}"
|
||||||
|
if [ -z "$__rv_int" ]; then
|
||||||
|
# En mode non interactif, retourner la valeur par défaut
|
||||||
|
if is_yes "$__rv_re" && [ -z "$__rv_d" ]; then
|
||||||
|
eerror "La valeur par défaut de $__rv_v doit être non vide"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_setv "$__rv_v" "$__rv_d"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local __rv_r
|
||||||
|
while true; do
|
||||||
|
if [ -n "$__rv_msg" ]; then
|
||||||
|
__eecho_ "$__rv_msg" 1>&2
|
||||||
|
else
|
||||||
|
__eecho_ "Entrez la valeur" 1>&2
|
||||||
|
fi
|
||||||
|
if [ -n "$__rv_readline" ]; then
|
||||||
|
tooenc_ ": " 1>&2
|
||||||
|
uread -e ${__rv_d:+-i"$__rv_d"} "${__rv_opts[@]}" __rv_r
|
||||||
|
else
|
||||||
|
if [ -n "$__rv_d" ]; then
|
||||||
|
if [ -n "$__rv_showdef" ]; then
|
||||||
|
tooenc_ " [$__rv_d]" 1>&2
|
||||||
|
else
|
||||||
|
tooenc_ " [****]" 1>&2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
tooenc_ ": " 1>&2
|
||||||
|
uread "${__rv_opts[@]}" __rv_r
|
||||||
|
[ -n "$__rv_nl" ] && echo
|
||||||
|
fi
|
||||||
|
__rv_r="${__rv_r:-$__rv_d}"
|
||||||
|
if [ -n "$__rv_r" ] || ! is_yes "$__rv_re"; then
|
||||||
|
_setv "$__rv_v" "$__rv_r"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function simple_menu() {
|
||||||
|
# Afficher un menu simple dont les éléments sont les valeurs du tableau
|
||||||
|
# $2(=options). L'option choisie est placée dans la variable $1(=option)
|
||||||
|
# -t TITLE: spécifier le titre du menu
|
||||||
|
# -m YOUR_CHOICE: spécifier le message d'invite pour la sélection de l'option
|
||||||
|
# -d DEFAULT: spécifier l'option par défaut. Par défaut, prendre la valeur
|
||||||
|
# actuelle de la variable $1(=option)
|
||||||
|
eval "$(local_args)"
|
||||||
|
local __sm_title= __sm_yourchoice= __sm_default=
|
||||||
|
args=(
|
||||||
|
-t:,--title __sm_title=
|
||||||
|
-m:,--prompt __sm_yourchoice=
|
||||||
|
-d:,--default __sm_default=
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
local __sm_option_var="${1:-option}" __sm_options_var="${2:-options}"
|
||||||
|
local __sm_option __sm_options
|
||||||
|
__sm_options="$__sm_options_var[*]"
|
||||||
|
if [ -z "${!__sm_options}" ]; then
|
||||||
|
eerror "Le tableau $__sm_options_var doit être non vide"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
[ -z "$__sm_default" ] && __sm_default="${!__sm_option_var}"
|
||||||
|
|
||||||
|
array_copy __sm_options "$__sm_options_var"
|
||||||
|
local __sm_c=0 __sm_i __sm_choice
|
||||||
|
while true; do
|
||||||
|
if [ "$__sm_c" == "0" ]; then
|
||||||
|
# Afficher le menu
|
||||||
|
[ -n "$__sm_title" ] && __eecho "=== $__sm_title ===" 1>&2
|
||||||
|
__sm_i=1
|
||||||
|
for __sm_option in "${__sm_options[@]}"; do
|
||||||
|
if [ "$__sm_option" == "$__sm_default" ]; then
|
||||||
|
__eecho "$__sm_i*- $__sm_option" 1>&2
|
||||||
|
else
|
||||||
|
__eecho "$__sm_i - $__sm_option" 1>&2
|
||||||
|
fi
|
||||||
|
let __sm_i=$__sm_i+1
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Afficher les choix
|
||||||
|
if [ -n "$__sm_yourchoice" ]; then
|
||||||
|
__eecho_ "$__sm_yourchoice" 1>&2
|
||||||
|
else
|
||||||
|
__eecho_ "Entrez le numéro de l'option choisie" 1>&2
|
||||||
|
fi
|
||||||
|
tooenc_ ": " 1>&2
|
||||||
|
uread __sm_choice
|
||||||
|
|
||||||
|
# Valeur par défaut
|
||||||
|
if [ -z "$__sm_choice" -a -n "$__sm_default" ]; then
|
||||||
|
__sm_option="$__sm_default"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
# Vérifier la saisie
|
||||||
|
if [ -n "$__sm_choice" -a -z "${__sm_choice//[0-9]/}" ]; then
|
||||||
|
if [ "$__sm_choice" -gt 0 -a "$__sm_choice" -le "${#__sm_options[*]}" ]; then
|
||||||
|
__sm_option="${__sm_options[$(($__sm_choice - 1))]}"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
eerror "Numéro d'option incorrect"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
eerror "Vous devez saisir le numéro de l'option choisie"
|
||||||
|
fi
|
||||||
|
|
||||||
|
let __sm_c=$__sm_c+1
|
||||||
|
if [ "$__sm_c" -eq 5 ]; then
|
||||||
|
# sauter une ligne toutes les 4 tentatives
|
||||||
|
tooenc "" 1>&2
|
||||||
|
__sm_c=0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
_setv "$__sm_option_var" "$__sm_option"
|
||||||
|
}
|
||||||
|
|
||||||
|
function actions_menu() {
|
||||||
|
# Afficher un menu dont les éléments sont les valeurs du tableau $4(=options),
|
||||||
|
# et une liste d'actions tirées du tableau $3(=actions). L'option choisie est
|
||||||
|
# placée dans la variable $2(=option). L'action choisie est placée dans la
|
||||||
|
# variable $1(=action)
|
||||||
|
# Un choix est saisi sous la forme [action]num_option
|
||||||
|
# -t TITLE: spécifier le titre du menu
|
||||||
|
# -m OPT_YOUR_CHOICE: spécifier le message d'invite pour la sélection de
|
||||||
|
# l'action et de l'option
|
||||||
|
# -M ACT_YOUR_CHOICE: spécifier le message d'invite dans le cas où aucune option
|
||||||
|
# n'est disponible. Dans ce cas, seules les actions vides sont possibles.
|
||||||
|
# -e VOID_ACTION: spécifier qu'une action est vide, c'est à dire qu'elle ne
|
||||||
|
# requière pas d'être associée à une option. Par défaut, la dernière action
|
||||||
|
# est classée dans cette catégorie puisque c'est l'action "quitter"
|
||||||
|
# -d DEFAULT_ACTION: choisir l'action par défaut. par défaut, c'est la première
|
||||||
|
# action.
|
||||||
|
# -q QUIT_ACTION: choisir l'option "quitter" qui provoque la sortie du menu sans
|
||||||
|
# choix. par défaut, c'est la dernière action.
|
||||||
|
# -o DEFAULT_OPTION: choisir l'option par défaut. par défaut, prendre la valeur
|
||||||
|
# actuelle de la variable $2(=option)
|
||||||
|
eval "$(local_args)"
|
||||||
|
local -a __am_action_descs __am_options __am_void_actions
|
||||||
|
local __am_tmp __am_select_action __am_select_option __am_title __am_optyc __am_actyc
|
||||||
|
local __am_default_action=auto __am_quit_action=auto
|
||||||
|
local __am_default_option=
|
||||||
|
args=(
|
||||||
|
-t:,--title __am_title=
|
||||||
|
-m:,--prompt __am_optyc=
|
||||||
|
-M:,--no-prompt __am_actyc=
|
||||||
|
-e: __am_void_actions
|
||||||
|
-d: __am_default_action=
|
||||||
|
-q: __am_quit_action=
|
||||||
|
-o: __am_default_option=
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
__am_tmp="${1:-action}"; __am_select_action="${!__am_tmp}"
|
||||||
|
__am_tmp="${2:-option}"; __am_select_option="${!__am_tmp}"
|
||||||
|
[ -n "$__am_default_option" ] && __am_select_option="$__am_default_option"
|
||||||
|
array_copy __am_action_descs "${3:-actions}"
|
||||||
|
array_copy __am_options "${4:-options}"
|
||||||
|
|
||||||
|
eerror_unless [ ${#__am_action_descs[*]} -gt 0 ] "Vous devez spécifier le tableau des actions" || return
|
||||||
|
__actions_menu || return 1
|
||||||
|
_setv "${1:-action}" "$__am_select_action"
|
||||||
|
_setv "${2:-option}" "$__am_select_option"
|
||||||
|
}
|
||||||
|
|
||||||
|
function __actions_menu() {
|
||||||
|
local title="$__am_title"
|
||||||
|
local optyc="$__am_optyc" actyc="$__am_actyc"
|
||||||
|
local default_action="$__am_default_action"
|
||||||
|
local quit_action="$__am_quit_action"
|
||||||
|
local select_action="$__am_select_action"
|
||||||
|
local select_option="$__am_select_option"
|
||||||
|
local -a action_descs options void_actions
|
||||||
|
array_copy action_descs __am_action_descs
|
||||||
|
array_copy options __am_options
|
||||||
|
array_copy void_actions __am_void_actions
|
||||||
|
|
||||||
|
# Calculer la liste des actions valides
|
||||||
|
local no_options
|
||||||
|
array_isempty options && no_options=1
|
||||||
|
|
||||||
|
local -a actions
|
||||||
|
local tmp action name
|
||||||
|
for tmp in "${action_descs[@]}"; do
|
||||||
|
splitfsep2 "$tmp" : action name
|
||||||
|
[ -n "$action" ] || action="${name:0:1}"
|
||||||
|
action="$(strlower "$action")"
|
||||||
|
array_addu actions "$action"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Calculer l'action par défaut
|
||||||
|
if [ "$default_action" == auto ]; then
|
||||||
|
# si action par défaut non spécifiée, alors prendre la première action
|
||||||
|
default_action="$select_action"
|
||||||
|
if [ -n "$default_action" ]; then
|
||||||
|
array_contains actions "$default_action" || default_action=
|
||||||
|
fi
|
||||||
|
[ -n "$default_action" ] || default_action="${actions[0]}"
|
||||||
|
fi
|
||||||
|
default_action="${default_action:0:1}"
|
||||||
|
default_action="$(strlower "$default_action")"
|
||||||
|
|
||||||
|
# Calculer l'action quitter par défaut
|
||||||
|
if [ "$quit_action" == auto ]; then
|
||||||
|
# si action par défaut non spécifiée, alors prendre la dernière action,
|
||||||
|
# s'il y a au moins 2 actions
|
||||||
|
if [ ${#actions[*]} -gt 1 ]; then
|
||||||
|
quit_action="${actions[@]:$((-1)):1}"
|
||||||
|
array_addu void_actions "$quit_action"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
quit_action="${quit_action:0:1}"
|
||||||
|
quit_action="$(strlower "$quit_action")"
|
||||||
|
|
||||||
|
# Calculer la ligne des actions à afficher
|
||||||
|
local action_title
|
||||||
|
for tmp in "${action_descs[@]}"; do
|
||||||
|
splitfsep2 "$tmp" : action name
|
||||||
|
[ -n "$action" ] || action="${name:0:1}"
|
||||||
|
[ -n "$name" ] || name="$action"
|
||||||
|
action="$(strlower "$action")"
|
||||||
|
if [ -n "$no_options" ]; then
|
||||||
|
if ! array_contains void_actions "$action"; then
|
||||||
|
array_del actions "$action"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
[ "$action" == "$default_action" ] && name="$name*"
|
||||||
|
action_title="${action_title:+$action_title/}$name"
|
||||||
|
done
|
||||||
|
if [ -n "$default_action" ]; then
|
||||||
|
# si action par défaut invalide, alors pas d'action par défaut
|
||||||
|
array_contains actions "$default_action" || default_action=
|
||||||
|
fi
|
||||||
|
if [ -n "$quit_action" ]; then
|
||||||
|
# si action quitter invalide, alors pas d'action quitter
|
||||||
|
array_contains actions "$quit_action" || quit_action=
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Type de menu
|
||||||
|
if [ -n "$no_options" ]; then
|
||||||
|
if array_isempty void_actions; then
|
||||||
|
eerror "Aucune option n'est définie. Il faut définir le tableau des actions vides"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
__void_actions_menu
|
||||||
|
else
|
||||||
|
__options_actions_menu
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function __void_actions_menu() {
|
||||||
|
local c=0 choice
|
||||||
|
while true; do
|
||||||
|
if [ $c -eq 0 ]; then
|
||||||
|
[ -n "$title" ] && __etitle "$title" 1>&2
|
||||||
|
__eecho_ "=== Actions disponibles: " 1>&2
|
||||||
|
tooenc "$action_title" 1>&2
|
||||||
|
fi
|
||||||
|
if [ -n "$actyc" ]; then
|
||||||
|
__eecho_ "$actyc" 1>&2
|
||||||
|
elif [ -n "$optyc" ]; then
|
||||||
|
__eecho_ "$optyc" 1>&2
|
||||||
|
else
|
||||||
|
__eecho_ "Entrez l'action à effectuer" 1>&2
|
||||||
|
fi
|
||||||
|
tooenc_ ": " 1>&2
|
||||||
|
uread choice
|
||||||
|
if [ -z "$choice" -a -n "$default_action" ]; then
|
||||||
|
select_action="$default_action"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
# vérifier la saisie
|
||||||
|
choice="${choice:0:1}"
|
||||||
|
choice="$(strlower "$choice")"
|
||||||
|
if array_contains actions "$choice"; then
|
||||||
|
select_action="$choice"
|
||||||
|
break
|
||||||
|
elif [ -n "$choice" ]; then
|
||||||
|
eerror "$choice: action incorrecte"
|
||||||
|
else
|
||||||
|
eerror "vous devez saisir l'action à effectuer"
|
||||||
|
fi
|
||||||
|
let c=$c+1
|
||||||
|
if [ $c -eq 5 ]; then
|
||||||
|
# sauter une ligne toutes les 4 tentatives
|
||||||
|
tooenc "" 1>&2
|
||||||
|
c=0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
__am_select_action="$select_action"
|
||||||
|
__am_select_option=
|
||||||
|
}
|
||||||
|
|
||||||
|
function __options_actions_menu() {
|
||||||
|
local c=0 option choice action option
|
||||||
|
while true; do
|
||||||
|
if [ $c -eq 0 ]; then
|
||||||
|
[ -n "$title" ] && __etitle "$title" 1>&2
|
||||||
|
i=1
|
||||||
|
for option in "${options[@]}"; do
|
||||||
|
if [ "$option" == "$select_option" ]; then
|
||||||
|
tooenc "$i*- $option" 1>&2
|
||||||
|
else
|
||||||
|
tooenc "$i - $option" 1>&2
|
||||||
|
fi
|
||||||
|
let i=$i+1
|
||||||
|
done
|
||||||
|
__estepn_ "Actions disponibles: " 1>&2
|
||||||
|
tooenc "$action_title" 1>&2
|
||||||
|
fi
|
||||||
|
if [ -n "$optyc" ]; then
|
||||||
|
__eecho_ "$optyc" 1>&2
|
||||||
|
else
|
||||||
|
__eecho_ "Entrez l'action et le numéro de l'option choisie" 1>&2
|
||||||
|
fi
|
||||||
|
tooenc_ ": " 1>&2
|
||||||
|
uread choice
|
||||||
|
|
||||||
|
# vérifier la saisie
|
||||||
|
if [ -z "$choice" -a -n "$default_action" ]; then
|
||||||
|
action="$default_action"
|
||||||
|
if array_contains void_actions "$action"; then
|
||||||
|
select_action="$action"
|
||||||
|
select_option=
|
||||||
|
break
|
||||||
|
elif [ -n "$select_option" ]; then
|
||||||
|
select_action="$action"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
action="${choice:0:1}"
|
||||||
|
action="$(strlower "$action")"
|
||||||
|
if array_contains actions "$action"; then
|
||||||
|
# on commence par un code d'action valide. cool :-)
|
||||||
|
if array_contains void_actions "$action"; then
|
||||||
|
select_action="$action"
|
||||||
|
select_option=
|
||||||
|
break
|
||||||
|
else
|
||||||
|
option="${choice:1}"
|
||||||
|
option="${option// /}"
|
||||||
|
if [ -z "$option" -a -n "$select_option" ]; then
|
||||||
|
select_action="$action"
|
||||||
|
break
|
||||||
|
elif [ -z "$option" ]; then
|
||||||
|
eerror "vous devez saisir le numéro de l'option"
|
||||||
|
elif isnum "$option"; then
|
||||||
|
if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
|
||||||
|
select_action="$action"
|
||||||
|
select_option="${options[$(($option - 1))]}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
eerror "$option: numéro d'option incorrecte"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
elif isnum "$choice"; then
|
||||||
|
# on a simplement donné un numéro d'option
|
||||||
|
action="$default_action"
|
||||||
|
if [ -n "$action" ]; then
|
||||||
|
if array_contains void_actions "$action"; then
|
||||||
|
select_action="$action"
|
||||||
|
select_option=
|
||||||
|
break
|
||||||
|
else
|
||||||
|
option="${choice// /}"
|
||||||
|
if [ -z "$option" ]; then
|
||||||
|
eerror "vous devez saisir le numéro de l'option"
|
||||||
|
elif isnum "$option"; then
|
||||||
|
if [ $option -gt 0 -a $option -le ${#options[*]} ]; then
|
||||||
|
select_action="$action"
|
||||||
|
select_option="${options[$(($option - 1))]}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
eerror "$option: numéro d'option incorrecte"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
eerror "Vous devez spécifier l'action à effectuer"
|
||||||
|
fi
|
||||||
|
elif [ -n "$choice" ]; then
|
||||||
|
eerror "$choice: action et/ou option incorrecte"
|
||||||
|
else
|
||||||
|
eerror "vous devez saisir l'action à effectuer"
|
||||||
|
fi
|
||||||
|
let c=$c+1
|
||||||
|
if [ $c -eq 5 ]; then
|
||||||
|
# sauter une ligne toutes les 4 tentatives
|
||||||
|
tooenc "" 1>&2
|
||||||
|
c=0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
__am_select_action="$select_action"
|
||||||
|
__am_select_option="$select_option"
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: base.num "Fonctions de base: gestion des valeurs numériques"
|
||||||
|
|
||||||
|
function: isnum 'retourner vrai si $1 est une valeur numérique entière (positive ou négative)'
|
||||||
|
function isnum() {
|
||||||
|
[ ${#1} -gt 0 ] || return 1
|
||||||
|
local v="${1#-}"
|
||||||
|
[ ${#v} -gt 0 ] || return 1
|
||||||
|
v="${v//[0-9]/}"
|
||||||
|
[ -z "$v" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
function: ispnum 'retourner vrai si $1 est une valeur numérique entière positive'
|
||||||
|
function ispnum() {
|
||||||
|
[ ${#1} -gt 0 ] || return 1
|
||||||
|
[ -z "${1//[0-9]/}" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
function: isrnum 'retourner vrai si $1 est une valeur numérique réelle (positive ou négative)
|
||||||
|
le séparateur décimal peut être . ou ,'
|
||||||
|
function isrnum() {
|
||||||
|
[ ${#1} -gt 0 ] || return 1
|
||||||
|
local v="${1#-}"
|
||||||
|
[ ${#v} -gt 0 ] || return 1
|
||||||
|
v="${v//./}"
|
||||||
|
v="${v//,/}"
|
||||||
|
v="${v//[0-9]/}"
|
||||||
|
[ -z "$v" ]
|
||||||
|
}
|
|
@ -0,0 +1,601 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: base.output "Fonctions de base: affichage"
|
||||||
|
nulib__load: _output_vanilla
|
||||||
|
|
||||||
|
NULIB__TAB=$'\t'
|
||||||
|
NULIB__LATIN1=iso-8859-1
|
||||||
|
NULIB__LATIN9=iso-8859-15
|
||||||
|
NULIB__UTF8=utf-8
|
||||||
|
|
||||||
|
[ -n "$LANG" ] || export LANG=fr_FR.UTF-8
|
||||||
|
if [ ! -x "$(which iconv 2>/dev/null)" ]; then
|
||||||
|
function iconv() { cat; }
|
||||||
|
fi
|
||||||
|
|
||||||
|
function nulib__lang_encoding() {
|
||||||
|
case "${LANG,,}" in
|
||||||
|
*@euro) echo "iso-8859-15";;
|
||||||
|
*.utf-8|*.utf8) echo "utf-8";;
|
||||||
|
*) echo "iso-8859-1";;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
function nulib__norm_encoding() {
|
||||||
|
local enc="${1,,}"
|
||||||
|
enc="${enc//[-_]/}"
|
||||||
|
case "$enc" in
|
||||||
|
latin|latin1|iso8859|iso88591|8859|88591) echo "iso-8859-1";;
|
||||||
|
latin9|iso885915|885915) echo "iso-8859-15";;
|
||||||
|
utf|utf8) echo "utf-8";;
|
||||||
|
*) echo "$1";;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
function nulib__init_encoding() {
|
||||||
|
local default_encoding="$(nulib__lang_encoding)"
|
||||||
|
[ -n "$default_encoding" ] || default_encoding=utf-8
|
||||||
|
[ -n "$NULIB_OUTPUT_ENCODING" ] || NULIB_OUTPUT_ENCODING="$default_encoding"
|
||||||
|
NULIB_OUTPUT_ENCODING="$(nulib__norm_encoding "$NULIB_OUTPUT_ENCODING")"
|
||||||
|
[ -n "$NULIB_INPUT_ENCODING" ] || NULIB_INPUT_ENCODING="$NULIB_OUTPUT_ENCODING"
|
||||||
|
NULIB_INPUT_ENCODING="$(nulib__norm_encoding "$NULIB_INPUT_ENCODING")"
|
||||||
|
}
|
||||||
|
[ -n "$NULIB_LANG" -a -z "$LANG" ] && export NULIB_LANG LANG="$NULIB_LANG"
|
||||||
|
nulib__init_encoding
|
||||||
|
|
||||||
|
function noerror() {
|
||||||
|
# lancer la commande "$@" et masquer son code de retour
|
||||||
|
[ $# -gt 0 ] || set :
|
||||||
|
"$@" || return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function noout() {
|
||||||
|
# lancer la commande "$@" en supprimant sa sortie standard
|
||||||
|
[ $# -gt 0 ] || return 0
|
||||||
|
"$@" >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
function noerr() {
|
||||||
|
# lancer la commande "$@" en supprimant sa sortie d'erreur
|
||||||
|
[ $# -gt 0 ] || return 0
|
||||||
|
"$@" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
function isatty() {
|
||||||
|
# tester si STDOUT n'est pas une redirection
|
||||||
|
tty -s <&1
|
||||||
|
}
|
||||||
|
|
||||||
|
function in_isatty() {
|
||||||
|
# tester si STDIN n'est pas une redirection
|
||||||
|
tty -s
|
||||||
|
}
|
||||||
|
|
||||||
|
function out_isatty() {
|
||||||
|
# tester si STDOUT n'est pas une redirection. identique à isatty()
|
||||||
|
tty -s <&1
|
||||||
|
}
|
||||||
|
|
||||||
|
function err_isatty() {
|
||||||
|
# tester si STDERR n'est pas une redirection
|
||||||
|
tty -s <&2
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
function tooenc() {
|
||||||
|
# $1 étant une chaine encodée en utf-8, l'afficher dans l'encoding de sortie $2
|
||||||
|
# qui vaut par défaut $NULIB_OUTPUT_ENCODING
|
||||||
|
local value="$1" to="${2:-$NULIB_OUTPUT_ENCODING}"
|
||||||
|
if [ "$to" == "$NULIB__UTF8" ]; then
|
||||||
|
recho "$value"
|
||||||
|
else
|
||||||
|
iconv -f -utf-8 -t "$to" <<<"$value"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
function uecho() { tooenc "$*"; }
|
||||||
|
|
||||||
|
function tooenc_() {
|
||||||
|
# $1 étant une chaine encodée en utf-8, l'afficher sans passer à la ligne dans
|
||||||
|
# l'encoding de sortie $2 qui vaut par défaut $NULIB_OUTPUT_ENCODING
|
||||||
|
local value="$1" to="${2:-$NULIB_OUTPUT_ENCODING}"
|
||||||
|
if [ "$to" == "$NULIB__UTF8" ]; then
|
||||||
|
recho_ "$value"
|
||||||
|
else
|
||||||
|
recho_ "$value" | iconv -f utf-8 -t "$to"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
function uecho_() { tooenc_ "$*"; }
|
||||||
|
|
||||||
|
export NULIB_QUIETLOG
|
||||||
|
export NULIB__TMPLOG
|
||||||
|
function: quietc "\
|
||||||
|
N'afficher la sortie de la commande \$@ que si on est en mode DEBUG ou si elle se termine en erreur"
|
||||||
|
function quietc() {
|
||||||
|
local r
|
||||||
|
[ -z "$NULIB__TMPLOG" ] && ac_set_tmpfile NULIB__TMPLOG
|
||||||
|
"$@" >&"$NULIB__TMPLOG"; r=$?
|
||||||
|
[ -n "$NULIB_QUIETLOG" ] && cat "$NULIB__TMPLOG" >>"$NULIB_QUIETLOG"
|
||||||
|
[ $r -ne 0 -o -n "$NULIB_DEBUG" ] && cat "$NULIB__TMPLOG"
|
||||||
|
return $r
|
||||||
|
}
|
||||||
|
|
||||||
|
function: quietc_logto "\
|
||||||
|
Si quietc est utilisé, sauvegarder quand même la sortie dans le fichier \$1
|
||||||
|
|
||||||
|
Utiliser l'option -a pour ajouter au fichier au lieu de l'écraser e.g
|
||||||
|
quietc_logto -a path/to/logfile
|
||||||
|
|
||||||
|
Tous les autres arguments sont du contenu ajoutés au fichier, e.g
|
||||||
|
quietc_logto -a path/to/logfile \"\\
|
||||||
|
================================================================================
|
||||||
|
= \$(date +%F-%T)\""
|
||||||
|
function quietc_logto() {
|
||||||
|
local append
|
||||||
|
if [ "$1" == -a ]; then
|
||||||
|
shift
|
||||||
|
append=1
|
||||||
|
fi
|
||||||
|
NULIB_QUIETLOG="$1"; shift
|
||||||
|
[ -n "$NULIB_QUIETLOG" ] || return
|
||||||
|
if [ -z "$append" ]; then
|
||||||
|
>"$NULIB_QUIETLOG"
|
||||||
|
fi
|
||||||
|
if [ $# -gt 0 ]; then
|
||||||
|
echo "$*" >>"$NULIB_QUIETLOG"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: quietc_echo "Ajouter \$* dans le fichier mentionné par quietc_logto() le cas échéant"
|
||||||
|
function quietc_echo() {
|
||||||
|
if [ -n "$NULIB_QUIETLOG" ]; then
|
||||||
|
echo "$*" >>"$NULIB_QUIETLOG"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# faut-il dater les messages des fonctions e* et action?
|
||||||
|
# Faire NULIB_ELOG_DATE=1 en début de script pour activer cette fonctionnalité
|
||||||
|
# faut-il rajouter aussi le nom du script? (nécessite NULIB_ELOG_DATE)
|
||||||
|
# Faire NULIB_ELOG_MYNAME=1 en début de script pour activer cette fonctionnalité
|
||||||
|
export NULIB_ELOG_DATE NULIB_ELOG_MYNAME
|
||||||
|
function __edate() {
|
||||||
|
[ -n "$NULIB_ELOG_DATE" ] || return
|
||||||
|
local prefix="$(date +"[%F %T.%N] ")"
|
||||||
|
[ -n "$NULIB_ELOG_MYNAME" ] && prefix="$prefix$MYNAME "
|
||||||
|
echo "$prefix"
|
||||||
|
}
|
||||||
|
|
||||||
|
export NULIB_ELOG_OVERWRITE
|
||||||
|
function __set_no_colors() { :; }
|
||||||
|
function elogto() {
|
||||||
|
# Activer NULIB_ELOG_DATE et rediriger STDOUT et STDERR vers le fichier $1
|
||||||
|
# Si deux fichiers sont spécifiés, rediriger STDOUT vers $1 et STDERR vers $2
|
||||||
|
# Si aucun fichier n'est spécifié, ne pas faire de redirection
|
||||||
|
# Si la redirection est activée, forcer l'utilisation de l'encoding UTF8
|
||||||
|
# Si NULIB_ELOG_OVERWRITE=1, alors le fichier en sortie est écrasé. Sinon, les
|
||||||
|
# lignes en sortie lui sont ajoutées
|
||||||
|
NULIB_ELOG_DATE=1
|
||||||
|
NULIB_ELOG_MYNAME=1
|
||||||
|
if [ -n "$1" -a -n "$2" ]; then
|
||||||
|
LANG=fr_FR.UTF8
|
||||||
|
NULIB_OUTPUT_ENCODING="$NULIB__UTF8"
|
||||||
|
__set_no_colors 1
|
||||||
|
if [ -n "$NULIB_ELOG_OVERWRITE" ]; then
|
||||||
|
exec >"$1" 2>"$2"
|
||||||
|
else
|
||||||
|
exec >>"$1" 2>>"$2"
|
||||||
|
fi
|
||||||
|
elif [ -n "$1" ]; then
|
||||||
|
LANG=fr_FR.UTF8
|
||||||
|
NULIB_OUTPUT_ENCODING="$NULIB__UTF8"
|
||||||
|
__set_no_colors 1
|
||||||
|
if [ -n "$NULIB_ELOG_OVERWRITE" ]; then
|
||||||
|
exec >"$1" 2>&1
|
||||||
|
else
|
||||||
|
exec >>"$1" 2>&1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# variables utilisées pour l'affichage indenté des messages et des titres
|
||||||
|
# NULIB__ESTACK est la liste des invocations de 'etitle' et 'action' en cours
|
||||||
|
export NULIB__ESTACK NULIB__INDENT=
|
||||||
|
function __eindent0() {
|
||||||
|
# afficher le nombre d'espaces correspondant à l'indentation
|
||||||
|
local indent="${NULIB__ESTACK//?/ }"
|
||||||
|
indent="${indent% }$NULIB__INDENT"
|
||||||
|
[ -n "$indent" ] && echo "$indent"
|
||||||
|
}
|
||||||
|
function __eindent() {
|
||||||
|
# indenter les lignes de $1, sauf la première
|
||||||
|
local -a lines; local line first=1
|
||||||
|
local indent="$(__eindent0)$2"
|
||||||
|
setx -a lines=echo "$1"
|
||||||
|
for line in "${lines[@]}"; do
|
||||||
|
if [ -n "$first" ]; then
|
||||||
|
recho "$line"
|
||||||
|
first=
|
||||||
|
else
|
||||||
|
recho "$indent$line"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function __complete() {
|
||||||
|
# compléter $1 avec $3 jusqu'à obtenir une taille de $2 caractères
|
||||||
|
local columns="${COLUMNS:-80}"
|
||||||
|
local line="$1" maxi="${2:-$columns}" sep="${3:- }"
|
||||||
|
while [ ${#line} -lt $maxi ]; do
|
||||||
|
line="$line$sep"
|
||||||
|
done
|
||||||
|
echo "$line"
|
||||||
|
}
|
||||||
|
|
||||||
|
PRETTYOPTS=()
|
||||||
|
function set_verbosity() { :;}
|
||||||
|
function check_verbosity() { return 0; }
|
||||||
|
function get_verbosity_option() { :;}
|
||||||
|
|
||||||
|
# tester respectivement si on doit afficher les messages d'erreur,
|
||||||
|
# d'avertissement, d'information, de debug
|
||||||
|
function show_error() { return 0; }
|
||||||
|
function show_warn() { return 0; }
|
||||||
|
function show_info() { return 0; }
|
||||||
|
function show_verbose() { return 0; }
|
||||||
|
function show_debug() { [ -n "$DEBUG" ]; }
|
||||||
|
|
||||||
|
# note: toutes les fonctions d'affichage e* écrivent sur stderr
|
||||||
|
|
||||||
|
function esection() {
|
||||||
|
# Afficher une section. Toutes les indentations sont remises à zéro
|
||||||
|
show_info || return
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
NULIB__ESTACK=
|
||||||
|
__esection "$*" 1>&2
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
}
|
||||||
|
|
||||||
|
function etitle() {
|
||||||
|
# Afficher le titre $1. Le contenu sous des titres imbriqués est affiché
|
||||||
|
# indenté.
|
||||||
|
# - si $2..$* est spécifié, c'est une commande qui est lancée dans le contexte
|
||||||
|
# du titre, ensuite le titre est automatiquement terminé
|
||||||
|
# - sinon il faut terminer le titre explicitement avec eend
|
||||||
|
local title="$1"; shift
|
||||||
|
# etitle
|
||||||
|
NULIB__ESTACK="$NULIB__ESTACK:t"
|
||||||
|
if show_info; then
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
__etitle "$title" 1>&2
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
fi
|
||||||
|
# commande
|
||||||
|
local r=0
|
||||||
|
if [ $# -gt 0 ]; then
|
||||||
|
"$@"; r=$?
|
||||||
|
eend
|
||||||
|
fi
|
||||||
|
return $r
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function eend() {
|
||||||
|
# Terminer un titre
|
||||||
|
if [ "${NULIB__ESTACK%:t}" != "$NULIB__ESTACK" ]; then
|
||||||
|
NULIB__ESTACK="${NULIB__ESTACK%:t}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function edesc() {
|
||||||
|
# Afficher une description sous le titre courant
|
||||||
|
show_info || return
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
__edesc "$*" 1>&2
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
}
|
||||||
|
|
||||||
|
function ebanner() {
|
||||||
|
# Afficher un message très important encadré, puis attendre 5 secondes
|
||||||
|
show_error || return
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
__ebanner "$*" 1>&2
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
sleep 5
|
||||||
|
}
|
||||||
|
|
||||||
|
function eimportant() {
|
||||||
|
# Afficher un message très important
|
||||||
|
show_error || return
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
__eimportant "$*" 1>&2
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
}
|
||||||
|
function qimportant() { eimportant "$*"; quietc_echo "IMPORTANT: $*"; }
|
||||||
|
|
||||||
|
function eattention() {
|
||||||
|
# Afficher un message important
|
||||||
|
show_warn || return
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
__eattention "$*" 1>&2
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
}
|
||||||
|
function qattention() { eattention "$*"; quietc_echo "ATTENTION: $*"; }
|
||||||
|
|
||||||
|
function eerror() {
|
||||||
|
# Afficher un message d'erreur
|
||||||
|
show_error || return
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
__eerror "$*" 1>&2
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
}
|
||||||
|
function qerror() { eerror "$*"; quietc_echo "ERROR: $*"; }
|
||||||
|
|
||||||
|
function eerror_unless() {
|
||||||
|
# Afficher $1 avec eerror() si la commande $2..@ retourne FAUX. dans tous les cas, retourner le code de retour de la commande.
|
||||||
|
local msg="$1"; shift
|
||||||
|
local r=1
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
[ -n "$msg" ] && eerror "$msg"
|
||||||
|
else
|
||||||
|
"$@"; r=$?
|
||||||
|
if [ $r -ne 0 -a -n "$msg" ]; then
|
||||||
|
eerror "$msg"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return $r
|
||||||
|
}
|
||||||
|
|
||||||
|
function eerror_if() {
|
||||||
|
# Afficher $1 avec eerror() si la commande $2..@ retourne VRAI. dans tous les cas, retourner le code de retour de la commande.
|
||||||
|
local msg="$1"; shift
|
||||||
|
local r=0
|
||||||
|
if [ $# -gt 0 ]; then
|
||||||
|
"$@"; r=$?
|
||||||
|
if [ $r -eq 0 -a -n "$msg" ]; then
|
||||||
|
eerror "$msg"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return $r
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_die_return() {
|
||||||
|
NULIB__DIE="return 1"
|
||||||
|
}
|
||||||
|
function die() {
|
||||||
|
[ $# -gt 0 ] && eerror "$@"
|
||||||
|
local die="${NULIB__DIE:-exit 1}"
|
||||||
|
eval "$die" || return
|
||||||
|
}
|
||||||
|
|
||||||
|
function die_with {
|
||||||
|
[ $# -gt 0 ] && eerror "$1"
|
||||||
|
shift
|
||||||
|
[ $# -gt 0 ] && "$@"
|
||||||
|
local die="${NULIB__DIE:-exit 1}"
|
||||||
|
eval "$die" || return
|
||||||
|
}
|
||||||
|
|
||||||
|
function die_unless() {
|
||||||
|
# Afficher $1 et quitter le script avec die() si la commande $2..@ retourne FAUX
|
||||||
|
local msg="$1"; shift
|
||||||
|
local die="${NULIB__DIE:-exit 1}"
|
||||||
|
local r=1
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
[ -n "$msg" ] && eerror "$msg"
|
||||||
|
else
|
||||||
|
"$@"; r=$?
|
||||||
|
if [ $r -ne 0 -a -n "$msg" ]; then
|
||||||
|
eerror "$msg"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ $r -ne 0 ]; then
|
||||||
|
eval "${die% *} $r" || return $r
|
||||||
|
fi
|
||||||
|
return $r
|
||||||
|
}
|
||||||
|
|
||||||
|
function die_if() {
|
||||||
|
# Afficher $1 et quitter le script avec die() si la commande $2..@ retourne VRAI. sinon, retourner le code de retour de la commande
|
||||||
|
local msg="$1"; shift
|
||||||
|
local die="${NULIB__DIE:-exit 1}"
|
||||||
|
local r=0
|
||||||
|
if [ $# -gt 0 ]; then
|
||||||
|
"$@"; r=$?
|
||||||
|
if [ $r -eq 0 -a -n "$msg" ]; then
|
||||||
|
eerror "$msg"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ $r -eq 0 ]; then
|
||||||
|
eval "${die% *} $r" || return $r
|
||||||
|
fi
|
||||||
|
return $r
|
||||||
|
}
|
||||||
|
|
||||||
|
function exit_with {
|
||||||
|
if [ $# -gt 0 ]; then "$@"; fi
|
||||||
|
exit $?
|
||||||
|
}
|
||||||
|
|
||||||
|
function ewarn() {
|
||||||
|
# Afficher un message d'avertissement
|
||||||
|
show_warn || return
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
__ewarn "$*" 1>&2
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
}
|
||||||
|
function qwarn() { ewarn "$*"; quietc_echo "WARN: $*"; }
|
||||||
|
|
||||||
|
function enote() {
|
||||||
|
# Afficher un message d'information de même niveau qu'un avertissement
|
||||||
|
show_info || return
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
__enote "$*" 1>&2
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
}
|
||||||
|
function qnote() { enote "$*"; quietc_echo "NOTE: $*"; }
|
||||||
|
|
||||||
|
function einfo() {
|
||||||
|
# Afficher un message d'information
|
||||||
|
show_info || return
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
__einfo "$*" 1>&2
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
}
|
||||||
|
function qinfo() { einfo "$*"; quietc_echo "INFO: $*"; }
|
||||||
|
|
||||||
|
function eecho() {
|
||||||
|
# Afficher un message d'information sans préfixe
|
||||||
|
show_info || return
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
__eecho "$*" 1>&2
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
}
|
||||||
|
function qecho() { eecho "$*"; quietc_echo "$*"; }
|
||||||
|
|
||||||
|
function eecho_() {
|
||||||
|
show_info || return
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
__eecho_ "$*" 1>&2
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
}
|
||||||
|
|
||||||
|
function trace() {
|
||||||
|
# Afficher la commande $1..@, la lancer, puis afficher son code d'erreur si une
|
||||||
|
# erreur se produit
|
||||||
|
local r cmd="$(qvals "$@")"
|
||||||
|
show_info && { __eecho "\$ $cmd" 1>&2; }
|
||||||
|
"$@"; r=$?
|
||||||
|
if [ $r -ne 0 ]; then
|
||||||
|
if show_info; then
|
||||||
|
__eecho "^ [EC #$r]" 1>&2
|
||||||
|
elif show_error; then
|
||||||
|
__eecho "^ $cmd [EC #$r]" 1>&2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return $r
|
||||||
|
}
|
||||||
|
|
||||||
|
function trace_error() {
|
||||||
|
# Lancer la commande $1..@, puis afficher son code d'erreur si une erreur se
|
||||||
|
# produit. La différence avec trace() est que la commande n'est affichée que si
|
||||||
|
# une erreur se produit.
|
||||||
|
local r
|
||||||
|
"$@"; r=$?
|
||||||
|
if [ $r -ne 0 ]; then
|
||||||
|
local cmd="$(qvals "$@")"
|
||||||
|
if show_error; then
|
||||||
|
__eecho "^ $cmd [EC #$r]" 1>&2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return $r
|
||||||
|
}
|
||||||
|
|
||||||
|
function edebug() {
|
||||||
|
# Afficher un message de debug
|
||||||
|
show_debug || return
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
__edebug "$*" 1>&2
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Afficher la description d'une opération. Cette fonction est particulièrement
|
||||||
|
# appropriée dans le contexte d'un etitle.
|
||||||
|
# Les variantes e (error), w (warning), n (note), i (info) permettent d'afficher
|
||||||
|
# des couleurs différentes, mais toutes sont du niveau info.
|
||||||
|
function estep() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estep "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; }
|
||||||
|
function estepe() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estepe "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; }
|
||||||
|
function estepw() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estepw "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; }
|
||||||
|
function estepn() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estepn "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; }
|
||||||
|
function estepi() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estepi "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; }
|
||||||
|
function estep_() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estep_ "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; }
|
||||||
|
function estepe_() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estepe_ "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; }
|
||||||
|
function estepw_() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estepw_ "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; }
|
||||||
|
function estepn_() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estepn_ "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; }
|
||||||
|
function estepi_() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estepi_ "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; }
|
||||||
|
|
||||||
|
function qstep() { estep "$*"; quietc_echo "* $*"; }
|
||||||
|
|
||||||
|
function action() {
|
||||||
|
# commencer l'action $1
|
||||||
|
# - si $2..$* est spécifié, c'est une commande qui est lancée dans le contexte
|
||||||
|
# de l'action, ensuite l'action est terminée en succès ou en échec suivant le
|
||||||
|
# code de retour. ne pas afficher la sortie de la commande comme avec quietc()
|
||||||
|
# - sinon il faut terminer le titre explicitement avec eend
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
local action="$1"; shift
|
||||||
|
local r=0
|
||||||
|
if [ $# -gt 0 ]; then
|
||||||
|
[ -z "$NULIB__TMPLOG" ] && ac_set_tmpfile NULIB__TMPLOG
|
||||||
|
[ -n "$action" ] && quietc_echo "$(__edate) ACTION: $action:"
|
||||||
|
"$@" >&"$NULIB__TMPLOG"; r=$?
|
||||||
|
[ -n "$NULIB_QUIETLOG" ] && cat "$NULIB__TMPLOG" >>"$NULIB_QUIETLOG"
|
||||||
|
if [ $r -ne 0 -o -n "$NULIB_DEBUG" ]; then
|
||||||
|
NULIB__ESTACK="$NULIB__ESTACK:a"
|
||||||
|
[ -n "$action" ] && action="$action:"
|
||||||
|
__action "$action" 1>&2
|
||||||
|
cat "$NULIB__TMPLOG"
|
||||||
|
aresult $r
|
||||||
|
else
|
||||||
|
if [ $r -eq 0 ]; then
|
||||||
|
[ -n "$action" ] || action="succès"
|
||||||
|
__asuccess "$action" 1>&2
|
||||||
|
else
|
||||||
|
[ -n "$action" ] || action="échec"
|
||||||
|
__afailure "$action" 1>&2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
NULIB__ESTACK="$NULIB__ESTACK:a"
|
||||||
|
[ -n "$action" ] && action="$action:"
|
||||||
|
__action "$action" 1>&2
|
||||||
|
fi
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
return $r
|
||||||
|
}
|
||||||
|
|
||||||
|
function asuccess() {
|
||||||
|
# terminer l'action en cours avec le message de succès $*
|
||||||
|
[ "${NULIB__ESTACK%:a}" != "$NULIB__ESTACK" ] || return
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
[ -n "$*" ] || set -- "succès"
|
||||||
|
NULIB__INDENT=" " __asuccess "$*" 1>&2
|
||||||
|
NULIB__ESTACK="${NULIB__ESTACK%:a}"
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
function afailure() {
|
||||||
|
# terminer l'action en cours avec le message d'échec $*
|
||||||
|
[ "${NULIB__ESTACK%:a}" != "$NULIB__ESTACK" ] || return
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
[ -n "$*" ] || set -- "échec"
|
||||||
|
NULIB__INDENT=" " __afailure "$*" 1>&2
|
||||||
|
NULIB__ESTACK="${NULIB__ESTACK%:a}"
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
function aresult() {
|
||||||
|
# terminer l'action en cours avec un message de succès ou d'échec $2..* en
|
||||||
|
# fonction du code de retour $1 (0=succès, sinon échec)
|
||||||
|
[ "${NULIB__ESTACK%:a}" != "$NULIB__ESTACK" ] || return
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
local r="${1:-0}"; shift
|
||||||
|
if [ "$r" == 0 ]; then
|
||||||
|
[ -n "$*" ] || set -- "succès"
|
||||||
|
NULIB__INDENT=" " __asuccess "$*" 1>&2
|
||||||
|
else
|
||||||
|
[ -n "$*" ] || set -- "échec"
|
||||||
|
NULIB__INDENT=" " __afailure "$*" 1>&2
|
||||||
|
fi
|
||||||
|
NULIB__ESTACK="${NULIB__ESTACK%:a}"
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
return $r
|
||||||
|
}
|
||||||
|
function adone() {
|
||||||
|
# terminer l'action en cours avec le message neutre $*
|
||||||
|
[ "${NULIB__ESTACK%:a}" != "$NULIB__ESTACK" ] || return
|
||||||
|
eval "$NULIB__DISABLE_SET_X"
|
||||||
|
[ -n "$*" ] && NULIB__INDENT=" " __adone "$*" 1>&2
|
||||||
|
NULIB__ESTACK="${NULIB__ESTACK%:a}"
|
||||||
|
eval "$NULIB__ENABLE_SET_X"
|
||||||
|
return 0
|
||||||
|
}
|
|
@ -0,0 +1,304 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: base.path "Fonctions de base: gestion des chemins et des fichiers"
|
||||||
|
|
||||||
|
function: in_path "tester l'existence d'un programme dans le PATH"
|
||||||
|
function in_path() {
|
||||||
|
[ -n "$1" -a -x "$(which "$1" 2>/dev/null)" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
function: delpath "supprimer le chemin \$1 de \$2(=PATH)"
|
||||||
|
function delpath() {
|
||||||
|
local _qdir="${1//\//\\/}"
|
||||||
|
eval "export ${2:-PATH}; ${2:-PATH}"'="${'"${2:-PATH}"'#$1:}"; '"${2:-PATH}"'="${'"${2:-PATH}"'%:$1}"; '"${2:-PATH}"'="${'"${2:-PATH}"'//:$_qdir:/:}"; [ "$'"${2:-PATH}"'" == "$1" ] && '"${2:-PATH}"'='
|
||||||
|
}
|
||||||
|
|
||||||
|
function: addpath "Ajouter le chemin \$1 à la fin, dans \$2(=PATH), s'il n'y existe pas déjà"
|
||||||
|
function addpath() {
|
||||||
|
local _qdir="${1//\//\\/}"
|
||||||
|
eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="${'"${2:-PATH}"':+$'"${2:-PATH}"':}$1"'
|
||||||
|
}
|
||||||
|
|
||||||
|
function: inspathm "Ajouter le chemin \$1 au début, dans \$2(=PATH), s'il n'y existe pas déjà"
|
||||||
|
function inspathm() {
|
||||||
|
local _qdir="${1//\//\\/}"
|
||||||
|
eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="$1${'"${2:-PATH}"':+:$'"${2:-PATH}"'}"'
|
||||||
|
}
|
||||||
|
|
||||||
|
function: inspath "S'assurer que le chemin \$1 est au début de \$2(=PATH)"
|
||||||
|
function inspath() {
|
||||||
|
delpath "$@"
|
||||||
|
inspathm "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: push_cwd "enregistrer le répertoire courant dans la variable \$2(=cwd) et se placer dans le répertoire \$1"
|
||||||
|
function push_cwd() {
|
||||||
|
eval "${2:-cwd}"'="$(pwd)"'
|
||||||
|
cd "$1"
|
||||||
|
}
|
||||||
|
function: pop_cwd "se placer dans le répertoire \${!\$2}(=\$cwd) puis retourner le code d'erreur \$1(=0)"
|
||||||
|
function pop_cwd() {
|
||||||
|
eval 'cd "$'"${2:-cwd}"'"'
|
||||||
|
return "${1:-0}"
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## fichiers temporaires
|
||||||
|
|
||||||
|
function: mktempf "générer un fichier temporaire et retourner son nom"
|
||||||
|
function mktempf() {
|
||||||
|
mktemp "${1:-"$TMPDIR/tmp.XXXXXX"}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: mktempd "générer un répertoire temporaire et retourner son nom"
|
||||||
|
function mktempd() {
|
||||||
|
mktemp -d "${1:-"$TMPDIR/tmp.XXXXXX"}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function ac__forgetall() { NULIB__AC_FILES=(); }
|
||||||
|
ac__forgetall
|
||||||
|
function ac__trap() {
|
||||||
|
local file
|
||||||
|
for file in "${NULIB__AC_FILES[@]}"; do
|
||||||
|
[ -e "$file" ] && rm -rf "$file" 2>/dev/null
|
||||||
|
done
|
||||||
|
ac__forgetall
|
||||||
|
}
|
||||||
|
trap ac__trap 1 3 15 EXIT
|
||||||
|
|
||||||
|
function: autoclean "\
|
||||||
|
Ajouter les fichiers spécifiés à la liste des fichiers à supprimer à la fin du
|
||||||
|
programme"
|
||||||
|
function autoclean() {
|
||||||
|
local file
|
||||||
|
for file in "$@"; do
|
||||||
|
[ -n "$file" ] && NULIB__AC_FILES=("${NULIB__AC_FILES[@]}" "$file")
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function: ac_cleanall "\
|
||||||
|
Supprimer *tous* les fichiers temporaires gérés par autoclean tout de suite."
|
||||||
|
function ac_cleanall() {
|
||||||
|
ac__trap
|
||||||
|
}
|
||||||
|
|
||||||
|
function: ac_clean "\
|
||||||
|
Supprimer les fichier temporaires \$1..@ si et seulement s'ils ont été générés
|
||||||
|
par ac_set_tmpfile() ou ac_set_tmpdir()"
|
||||||
|
function ac_clean() {
|
||||||
|
local file acfile found
|
||||||
|
local -a acfiles
|
||||||
|
for acfile in "${NULIB__AC_FILES[@]}"; do
|
||||||
|
found=
|
||||||
|
for file in "$@"; do
|
||||||
|
if [ "$file" == "$acfile" ]; then
|
||||||
|
found=1
|
||||||
|
[ -e "$file" ] && rm -rf "$file" 2>/dev/null
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
[ -z "$found" ] && acfiles=("${acfiles[@]}" "$acfile")
|
||||||
|
done
|
||||||
|
NULIB__AC_FILES=("${acfiles[@]}")
|
||||||
|
}
|
||||||
|
|
||||||
|
function: ac_set_tmpfile "\
|
||||||
|
Créer un fichier temporaire avec le motif \$2, l'ajouter à la liste des
|
||||||
|
fichiers à supprimer en fin de programme, et mettre sa valeur dans la
|
||||||
|
variable \$1
|
||||||
|
|
||||||
|
En mode debug, si (\$5 est vide ou \${!5} est une valeur vraie), et si \$3 n'est
|
||||||
|
pas vide, prendre ce fichier au lieu de générer un nouveau fichier temporaire.
|
||||||
|
Si \$4==keep, ne pas écraser le fichier \$3 s'il existe."
|
||||||
|
function ac_set_tmpfile() {
|
||||||
|
local se__d
|
||||||
|
if is_debug; then
|
||||||
|
if [ -n "$5" ]; then
|
||||||
|
is_yes "${!5}" && se__d=1
|
||||||
|
else
|
||||||
|
se__d=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ -n "$se__d" -a -n "$3" ]; then
|
||||||
|
_setv "$1" "$3"
|
||||||
|
[ -f "$3" -a "$4" == keep ] || >"$3"
|
||||||
|
else
|
||||||
|
local se__t="$(mktempf "$2")"
|
||||||
|
autoclean "$se__t"
|
||||||
|
_setv "$1" "$se__t"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: ac_set_tmpdir "\
|
||||||
|
Créer un répertoire temporaire avec le motif \$2, l'ajouter à la liste des
|
||||||
|
fichiers à supprimer en fin de programme, et mettre sa valeur dans la
|
||||||
|
variable \$1
|
||||||
|
|
||||||
|
En mode debug, si (\$4 est vide ou \${!4} est une valeur vraie), et si \$3 n'est
|
||||||
|
pas vide, prendre ce nom de répertoire au lieu de créer un nouveau répertoire
|
||||||
|
temporaire"
|
||||||
|
function ac_set_tmpdir() {
|
||||||
|
local sr__d
|
||||||
|
if is_debug; then
|
||||||
|
if [ -n "$4" ]; then
|
||||||
|
is_yes "${!4}" && sr__d=1
|
||||||
|
else
|
||||||
|
sr__d=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ -n "$sr__d" -a -n "$3" ]; then
|
||||||
|
_setv "$1" "$3"
|
||||||
|
mkdir -p "$3"
|
||||||
|
else
|
||||||
|
local sr__t="$(mktempd "$2")"
|
||||||
|
autoclean "$sr__t"
|
||||||
|
_setv "$1" "$sr__t"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
## manipulation de chemins
|
||||||
|
|
||||||
|
#XXX repris tel quel depuis nutools, à migrer
|
||||||
|
|
||||||
|
function normpath() {
|
||||||
|
# normaliser le chemin $1, qui est soit absolu, soit relatif à $2 (qui vaut
|
||||||
|
# $(pwd) par défaut)
|
||||||
|
local -a parts
|
||||||
|
local part ap
|
||||||
|
IFS=/ read -a parts <<<"$1"
|
||||||
|
if [ "${1#/}" != "$1" ]; then
|
||||||
|
ap=/
|
||||||
|
elif [ -n "$2" ]; then
|
||||||
|
ap="$2"
|
||||||
|
else
|
||||||
|
ap="$(pwd)"
|
||||||
|
fi
|
||||||
|
for part in "${parts[@]}"; do
|
||||||
|
if [ "$part" == "." ]; then
|
||||||
|
continue
|
||||||
|
elif [ "$part" == ".." ]; then
|
||||||
|
ap="${ap%/*}"
|
||||||
|
[ -n "$ap" ] || ap=/
|
||||||
|
else
|
||||||
|
[ "$ap" != "/" ] && ap="$ap/"
|
||||||
|
ap="$ap$part"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "$ap"
|
||||||
|
}
|
||||||
|
function __normpath() {
|
||||||
|
# normaliser dans les cas simple le chemin absolu $1. sinon retourner 1.
|
||||||
|
# cette fonction est utilisée par abspath()
|
||||||
|
if [ -d "$1" ]; then
|
||||||
|
if [ -x "$1" ]; then
|
||||||
|
# le cas le plus simple: un répertoire dans lequel on peut entrer
|
||||||
|
(cd "$1"; pwd)
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
elif [ -f "$1" ]; then
|
||||||
|
local dn="$(dirname -- "$1")" bn="$(basename -- "$1")"
|
||||||
|
if [ -x "$dn" ]; then
|
||||||
|
# autre cas simple: un fichier situé dans un répertoire dans lequel
|
||||||
|
# on peut entrer
|
||||||
|
(cd "$dn"; echo "$(pwd)/$bn")
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
function abspath() {
|
||||||
|
# Retourner un chemin absolu vers $1. Si $2 est non nul et si $1 est un chemin
|
||||||
|
# relatif, alors $1 est exprimé par rapport à $2, sinon il est exprimé par
|
||||||
|
# rapport au répertoire courant.
|
||||||
|
# Si le chemin n'existe pas, il n'est PAS normalisé. Sinon, les meilleurs
|
||||||
|
# efforts sont faits pour normaliser le chemin.
|
||||||
|
local ap="$1"
|
||||||
|
if [ "${ap#/}" != "$ap" ]; then
|
||||||
|
# chemin absolu. on peut ignorer $2
|
||||||
|
__normpath "$ap" && return
|
||||||
|
else
|
||||||
|
# chemin relatif. il faut exprimer le chemin par rapport à $2
|
||||||
|
local cwd
|
||||||
|
if [ -n "$2" ]; then
|
||||||
|
cwd="$(abspath "$2")"
|
||||||
|
else
|
||||||
|
cwd="$(pwd)"
|
||||||
|
fi
|
||||||
|
ap="$cwd/$ap"
|
||||||
|
__normpath "$ap" && return
|
||||||
|
fi
|
||||||
|
# dans les cas spéciaux, il faut calculer "manuellement" le répertoire absolu
|
||||||
|
normpath "$ap"
|
||||||
|
}
|
||||||
|
|
||||||
|
function ppath() {
|
||||||
|
# Dans un chemin *absolu*, remplacer "$HOME" par "~" et "$(pwd)/" par "", afin
|
||||||
|
# que le chemin soit plus facile à lire. Le répertoire courant est spécifié par
|
||||||
|
# $2 ou $(pwd) si $2 est vide
|
||||||
|
local path="$1" cwd="$2"
|
||||||
|
|
||||||
|
path="$(abspath "$path")" # essayer de normaliser le chemin
|
||||||
|
[ -n "$cwd" ] || cwd="$(pwd)"
|
||||||
|
|
||||||
|
[ "$path" == "$cwd" ] && path="."
|
||||||
|
[ "$cwd" != "/" -a "$cwd" != "$HOME" ] && path="${path#$cwd/}"
|
||||||
|
[ "${path#$HOME/}" != "$path" ] && path="~${path#$HOME}"
|
||||||
|
|
||||||
|
echo "$path"
|
||||||
|
}
|
||||||
|
function ppath2() {
|
||||||
|
# Comme ppath() mais afficher '.' comme '. ($dirname)' pour la joliesse
|
||||||
|
local path="$1" cwd="$2"
|
||||||
|
|
||||||
|
path="$(abspath "$path")" # essayer de normaliser le chemin
|
||||||
|
[ -n "$cwd" ] || cwd="$(pwd)"
|
||||||
|
|
||||||
|
if [ "$path" == "$cwd" ]; then
|
||||||
|
path=". ($(basename -- "$path"))"
|
||||||
|
else
|
||||||
|
[ "$cwd" != "/" -a "$cwd" != "$HOME" ] && path="${path#$cwd/}"
|
||||||
|
[ "${path#$HOME/}" != "$path" ] && path="~${path#$HOME}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$path"
|
||||||
|
}
|
||||||
|
|
||||||
|
function relpath() {
|
||||||
|
# Afficher le chemin relatif de $1 par rapport à $2. Si $2 n'est pas spécifié,
|
||||||
|
# on prend le répertoire courant. Si $1 ou $2 ne sont pas des chemins absolus,
|
||||||
|
# il sont transformés en chemins absolus par rapport à $3. Si $1==$2, retourner
|
||||||
|
# une chaine vide
|
||||||
|
local p="$(abspath "$1" "$3")" cwd="$2"
|
||||||
|
if [ -z "$cwd" ]; then
|
||||||
|
cwd="$(pwd)"
|
||||||
|
else
|
||||||
|
cwd="$(abspath "$cwd" "$3")"
|
||||||
|
fi
|
||||||
|
if [ "$p" == "$cwd" ]; then
|
||||||
|
echo ""
|
||||||
|
elif [ "${p#$cwd/}" != "$p" ]; then
|
||||||
|
echo "${p#$cwd/}"
|
||||||
|
else
|
||||||
|
local rp
|
||||||
|
while [ -n "$cwd" -a "${p#$cwd/}" == "$p" ]; do
|
||||||
|
rp="${rp:+$rp/}.."
|
||||||
|
cwd="${cwd%/*}"
|
||||||
|
done
|
||||||
|
rp="$rp/${p#$cwd/}"
|
||||||
|
# ${rp%//} traite le cas $1==/
|
||||||
|
echo "${rp%//}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
function relpathx() {
|
||||||
|
# Comme relpath, mais pour un chemin vers un exécutable qu'il faut lancer:
|
||||||
|
# s'assurer qu'il y a une spécification de chemin, e.g. ./script
|
||||||
|
local p="$(relpath "$@")"
|
||||||
|
if [ -z "$p" ]; then
|
||||||
|
echo .
|
||||||
|
elif [ "${p#../}" != "$p" -o "${p#./}" != "$p" ]; then
|
||||||
|
echo "$p"
|
||||||
|
else
|
||||||
|
echo "./$p"
|
||||||
|
fi
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
# shim pour les fonctions de nulib.sh au cas où ce module n'est pas chargée
|
||||||
|
if [ -z "$NULIBDIR" -o "$NULIBDIR" != "$NULIBINIT" ]; then
|
||||||
|
function module:() { :; }
|
||||||
|
function function:() { :; }
|
||||||
|
function require:() { :; }
|
||||||
|
fi
|
||||||
|
##@include base.init.sh
|
||||||
|
##@include base.core.sh
|
||||||
|
##@include base.str.sh
|
||||||
|
##@include base.num.sh
|
||||||
|
##@include base.bool.sh
|
||||||
|
##@include base.array.sh
|
||||||
|
##@include base.split.sh
|
||||||
|
##@include base.path.sh
|
||||||
|
##@include base.args.sh
|
||||||
|
##@include base.tools.sh
|
||||||
|
##@include base.input.sh
|
||||||
|
##@include base.output.sh
|
||||||
|
module: base "Chargement de tous les modules base.*"
|
||||||
|
require: base.init base.core base.str base.num base.bool base.array base.split base.path base.args base.tools base.input base.output
|
|
@ -0,0 +1,188 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: base.split "Fonctions de base: analyse et découpage de valeurs"
|
||||||
|
|
||||||
|
function: splitfsep "\
|
||||||
|
Découper \$1 de la forme first[SEPsecond] entre first, qui est placé dans la
|
||||||
|
variable \$3(=first) et second, qui est placée dans la variable \$4(=second). \$2
|
||||||
|
est la valeur SEP. Le découpage est faite sur la *première* occurence de SEP."
|
||||||
|
function splitfsep() {
|
||||||
|
if [[ "$1" == *"$2"* ]]; then
|
||||||
|
setv "${3:-first}" "${1%%$2*}"
|
||||||
|
setv "${4:-second}" "${1#*$2}"
|
||||||
|
else
|
||||||
|
setv "${3:-first}" "$1"
|
||||||
|
setv "${4:-second}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: splitfsep2 "\
|
||||||
|
Découper \$1 de la forme [firstSEP]second entre first, qui est placé dans la
|
||||||
|
variable \$3(=first) et second, qui est placée dans la variable \$4(=second). \$2
|
||||||
|
est la valeur SEP. Le découpage est faite sur la *première* occurence de SEP."
|
||||||
|
function splitfsep2() {
|
||||||
|
if [[ "$1" == *"$2"* ]]; then
|
||||||
|
setv "${3:-first}" "${1%%$2*}"
|
||||||
|
setv "${4:-second}" "${1#*$2}"
|
||||||
|
else
|
||||||
|
setv "${3:-first}"
|
||||||
|
setv "${4:-second}" "$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: splitlsep "\
|
||||||
|
Découper \$1 de la forme first[SEPsecond] entre first, qui est placé dans la
|
||||||
|
variable \$3(=first) et second, qui est placée dans la variable \$4(=second). \$2
|
||||||
|
est la valeur SEP. Le découpage est faite sur la *dernière* occurence de SEP."
|
||||||
|
function splitlsep() {
|
||||||
|
if [[ "$1" == *"$2"* ]]; then
|
||||||
|
setv "${3:-first}" "${1%$2*}"
|
||||||
|
setv "${4:-second}" "${1##*$2}"
|
||||||
|
else
|
||||||
|
setv "${3:-first}" "$1"
|
||||||
|
setv "${4:-second}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: splitlsep2 "\
|
||||||
|
Découper \$1 de la forme [firstSEP]second entre first, qui est placé dans la
|
||||||
|
variable \$3(=first) et second, qui est placée dans la variable \$4(=second). \$2
|
||||||
|
est la valeur SEP. Le découpage est faite sur la *dernière* occurence de SEP."
|
||||||
|
function splitlsep2() {
|
||||||
|
if [[ "$1" == *"$2"* ]]; then
|
||||||
|
setv "${3:-first}" "${1%$2*}"
|
||||||
|
setv "${4:-second}" "${1##*$2}"
|
||||||
|
else
|
||||||
|
setv "${3:-first}"
|
||||||
|
setv "${4:-second}" "$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: splitvar "\
|
||||||
|
Découper \$1 de la forme name[=value] entre le nom, qui est placé dans la
|
||||||
|
variable \$2(=name) et la valeur, qui est placée dans la variable \$3(=value)"
|
||||||
|
function splitvar() {
|
||||||
|
splitfsep "$1" = "${2:-name}" "${3:-value}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: splitpath "\
|
||||||
|
Découper \$1 de la forme [dir/]name entre le répertoire, qui est placé dans la
|
||||||
|
variable \$2(=dir), et le nom du fichier, qui est placé dans la variable
|
||||||
|
\$3(=name)"
|
||||||
|
function splitpath() {
|
||||||
|
splitlsep2 "$1" / "${2:-dir}" "${3:-name}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: splitname "\
|
||||||
|
Découper \$1 de la forme basename[.ext] entre le nom de base du fichier, qui
|
||||||
|
est placé dans la variable \$2(=basename) et l'extension, qui est placée dans
|
||||||
|
la variable \$3(=ext)
|
||||||
|
|
||||||
|
Attention, si \$1 est un chemin, le résultat risque d'être faussé. Par exemple,
|
||||||
|
'splitname a.b/c' ne donne pas le résultat escompté."
|
||||||
|
function splitname() {
|
||||||
|
splitlsep "$1" . "${2:-basename}" "${3:-ext}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: splithost "\
|
||||||
|
Découper \$1 de la forme hostname[.domain] entre le nom d'hôte, qui est placé
|
||||||
|
dans la variable \$2(=hostname) et le domaine, qui est placée dans la variable
|
||||||
|
\$3(=domain)"
|
||||||
|
function splithost() {
|
||||||
|
splitfsep "$1" . "${2:-hostname}" "${3:-domain}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: splituserhost "\
|
||||||
|
Découper \$1 de la forme [user@]host entre le nom de l'utilisateur, qui est placé
|
||||||
|
dans la variable \$2(=user) et le nom d'hôte, qui est placée dans la variable
|
||||||
|
\$3(=host)"
|
||||||
|
function splituserhost() {
|
||||||
|
splitfsep2 "$1" @ "${2:-user}" "${3:-host}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: splitpair "\
|
||||||
|
Découper \$1 de la forme first[:second] entre la première valeur, qui est placé
|
||||||
|
dans la variable \$2(=src) et la deuxième valeur, qui est placée dans la variable
|
||||||
|
\$3(=dest)"
|
||||||
|
function splitpair() {
|
||||||
|
splitfsep "$1" : "${2:-src}" "${3:-dest}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: splitproxy "\
|
||||||
|
Découper \$1 de la forme http://[user:password@]host[:port]/ entre les valeurs
|
||||||
|
\$2(=host), \$3(=port), \$4(=user), \$5(=password)
|
||||||
|
|
||||||
|
S'il n'est pas spécifié, port vaut 3128 par défaut"
|
||||||
|
function splitproxy() {
|
||||||
|
local sy__tmp sy__host sy__port sy__creds sy__user sy__password
|
||||||
|
|
||||||
|
sy__tmp="${1#http://}"
|
||||||
|
if [[ "$sy__tmp" == *@* ]]; then
|
||||||
|
sy__creds="${sy__tmp%%@*}"
|
||||||
|
sy__tmp="${sy__tmp#${sy__creds}@}"
|
||||||
|
splitpair "$sy__creds" sy__user sy__password
|
||||||
|
fi
|
||||||
|
sy__tmp="${sy__tmp%%/*}"
|
||||||
|
splitpair "$sy__tmp" sy__host sy__port
|
||||||
|
[ -n "$sy__port" ] || sy__port=3128
|
||||||
|
|
||||||
|
setv "${2:-host}" "$sy__host"
|
||||||
|
setv "${3:-port}" "$sy__port"
|
||||||
|
setv "${4:-user}" "$sy__user"
|
||||||
|
setv "${5:-password}" "$sy__password"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: spliturl "\
|
||||||
|
Découper \$1 de la forme scheme://[user:password@]host[:port]/path entre les
|
||||||
|
valeurs \$2(=scheme), \$3(=user), \$4(=password), \$5(=host), \$6(=port), \$7(=path)
|
||||||
|
|
||||||
|
S'il n'est pas spécifié, port vaut 80 pour http, 443 pour https, 21 pour ftp"
|
||||||
|
function spliturl() {
|
||||||
|
local sl__tmp sl__scheme sl__creds sl__user sl__password sl__host sl__port sl__path
|
||||||
|
|
||||||
|
sl__scheme="${1%%:*}"
|
||||||
|
sl__tmp="${1#${sl__scheme}://}"
|
||||||
|
if [[ "$sl__tmp" == */* ]]; then
|
||||||
|
sl__path="${sl__tmp#*/}"
|
||||||
|
sl__tmp="${sl__tmp%%/*}"
|
||||||
|
fi
|
||||||
|
if [[ "$sl__tmp" == *@* ]]; then
|
||||||
|
sl__creds="${sl__tmp%%@*}"
|
||||||
|
sl__tmp="${sl__tmp#${sl__creds}@}"
|
||||||
|
splitpair "$sl__creds" sl__user sl__password
|
||||||
|
fi
|
||||||
|
splitpair "$sl__tmp" sl__host sl__port
|
||||||
|
if [ -z "$sl__port" ]; then
|
||||||
|
[ "$sl__scheme" == "http" ] && sl__port=80
|
||||||
|
[ "$sl__scheme" == "https" ] && sl__port=443
|
||||||
|
[ "$sl__scheme" == "ftp" ] && sl__port=21
|
||||||
|
fi
|
||||||
|
|
||||||
|
setv "${2:-scheme}" "$sl__scheme"
|
||||||
|
setv "${3:-user}" "$sl__user"
|
||||||
|
setv "${4:-password}" "$sl__password"
|
||||||
|
setv "${5:-host}" "$sl__host"
|
||||||
|
setv "${6:-port}" "$sl__port"
|
||||||
|
setv "${7:-path}" "$sl__path"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: splitwcs "\
|
||||||
|
Découper un nom de chemin \$1 entre la partie sans wildcards, qui est placée dans
|
||||||
|
la variables \$2(=basedir), et la partie avec wildcards, qui est placée dans la
|
||||||
|
variable \$3(=filespec)"
|
||||||
|
function splitwcs() {
|
||||||
|
local ss__p="$1"
|
||||||
|
local ss__dd="${2:-basedir}" ss__df="${3:-filespec}" ss__part ss__d ss__f
|
||||||
|
local -a ss__parts
|
||||||
|
array_split ss__parts "$ss__p" "/"
|
||||||
|
for ss__part in "${ss__parts[@]}"; do
|
||||||
|
if [[ "$ss__part" == *\** ]] || [[ "$ss__part" == *\?* ]] || [ -n "$ss__f" ]; then
|
||||||
|
ss__f="${ss__f:+$ss__f/}$ss__part"
|
||||||
|
else
|
||||||
|
ss__d="${ss__d:+$ss__d/}$ss__part"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
[ "${ss__p#/}" != "$ss__p" ] && ss__d="/$ss__d"
|
||||||
|
_setv "$ss__dd" "$ss__d"
|
||||||
|
_setv "$ss__df" "$ss__f"
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: base.str "Fonctions de base: gestion des valeurs chaines"
|
||||||
|
|
||||||
|
function: strmid "Afficher la plage \$1 de la valeur \$2..*
|
||||||
|
|
||||||
|
La plage peut être d'une des formes 'start', '[start]:length'. Si start est
|
||||||
|
négatif, le compte est effectué à partir de la fin de la chaine. Si length est
|
||||||
|
négatif, il est rajouté à la longueur de la chaine à partir de start"
|
||||||
|
function strmid() {
|
||||||
|
local range="$1"; shift
|
||||||
|
local str="$*"
|
||||||
|
if [[ "$range" == *:-* ]]; then
|
||||||
|
local max=${#str}
|
||||||
|
[ $max -eq 0 ] && return
|
||||||
|
local start="${range%%:*}"
|
||||||
|
[ -n "$start" ] || start=0
|
||||||
|
while [ "$start" -lt 0 ]; do
|
||||||
|
start=$(($max$start))
|
||||||
|
done
|
||||||
|
max=$(($max-$start))
|
||||||
|
local length="${range#*:}"
|
||||||
|
while [ "$length" -lt 0 ]; do
|
||||||
|
length=$(($max$length))
|
||||||
|
done
|
||||||
|
range="$start:$length"
|
||||||
|
fi
|
||||||
|
eval 'echo "${str:'" $range"'}"'
|
||||||
|
}
|
||||||
|
|
||||||
|
function: strrepl "Remplacer dans la valeur \$3..* le motif \$1 par la chaine \$2
|
||||||
|
|
||||||
|
\$1 peut commencer par l'un des caractères /, #, % pour indiquer le type de recherche"
|
||||||
|
function strrepl() {
|
||||||
|
local pattern="$1"; shift
|
||||||
|
local repl="$1"; shift
|
||||||
|
local str="$*"
|
||||||
|
local cmd='echo "${str/'
|
||||||
|
if [ "${pattern#/}" != "$pattern" ]; then
|
||||||
|
pattern="${pattern#/}"
|
||||||
|
cmd="$cmd/"
|
||||||
|
elif [ "${pattern#\#}" != "$pattern" ]; then
|
||||||
|
pattern="${pattern#\#}"
|
||||||
|
cmd="$cmd#"
|
||||||
|
elif [ "${pattern#%}" != "$pattern" ]; then
|
||||||
|
pattern="${pattern#%}"
|
||||||
|
cmd="$cmd%"
|
||||||
|
fi
|
||||||
|
cmd="$cmd"'$pattern/$repl}"'
|
||||||
|
eval "$cmd"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: strlcomp "transformer dans le flux en entrée en UTF-8 certains caractères en leur équivalent transformable en latin1.
|
||||||
|
|
||||||
|
si cette fonction est appelée avec des arguments, prendre \$* comme valeur du flux en entrée."
|
||||||
|
function strlcomp() {
|
||||||
|
if [ $# -gt 0 ]; then strlcomp <<<"$*"
|
||||||
|
else LANG=fr_FR.UTF-8 sed $'
|
||||||
|
s/[\xE2\x80\x90\xE2\x80\x91\xE2\x80\x92\xE2\x80\x93\xE2\x80\x94\xE2\x80\x95]/-/g
|
||||||
|
s/[‘’]/\x27/g
|
||||||
|
s/[«»“”]/"/g
|
||||||
|
s/[\xC2\xA0\xE2\x80\x87\xE2\x80\xAF\xE2\x81\xA0]/ /g
|
||||||
|
s/[\xE2\x80\xA6]/.../g
|
||||||
|
s/[œ]/oe/g
|
||||||
|
s/[Œ]/OE/g
|
||||||
|
s/[æ]/ae/g
|
||||||
|
s/[Æ]/AE/g
|
||||||
|
s/a\xCC\x80/à/g
|
||||||
|
s/e\xCC\x81/é/g; s/e\xCC\x80/è/g; s/e\xCC\x82/ê/g; s/e\xCC\x88/ë/g
|
||||||
|
s/i\xCC\x88/ï/g; s/i\xCC\x82/î/g
|
||||||
|
s/o\xCC\x82/ô/g; s/o\xCC\x88/ö/g
|
||||||
|
s/u\xCC\x88/ü/g; s/u\xCC\x82/û/g
|
||||||
|
s/c\xCC\xA7/ç/g
|
||||||
|
s/A\xCC\x80/À/g
|
||||||
|
s/E\xCC\x81/É/g; s/E\xCC\x80/È/g; s/E\xCC\x82/Ê/g; s/E\xCC\x88/Ë/g
|
||||||
|
s/I\xCC\x88/Ï/g; s/I\xCC\x82/Î/g
|
||||||
|
s/O\xCC\x82/Ô/g; s/O\xCC\x88/Ö/g
|
||||||
|
s/U\xCC\x88/Ü/g; s/U\xCC\x82/Û/g
|
||||||
|
s/C\xCC\xA7/Ç/g
|
||||||
|
'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: strnacc "supprimer les accents dans le flux en entrée en UTF-8
|
||||||
|
|
||||||
|
si cette fonction est appelée avec des arguments, prendre \$* comme valeur du flux en entrée."
|
||||||
|
function strnacc() {
|
||||||
|
if [ $# -gt 0 ]; then strnacc <<<"$*"
|
||||||
|
else LANG=fr_FR.UTF-8 sed '
|
||||||
|
s/[à]/a/g
|
||||||
|
s/[éèêë]/e/g
|
||||||
|
s/[ïî]/i/g
|
||||||
|
s/[ôö]/o/g
|
||||||
|
s/[üû]/u/g
|
||||||
|
s/[ç]/c/g
|
||||||
|
s/[À]/A/g
|
||||||
|
s/[ÉÈÊË]/E/g
|
||||||
|
s/[ÏÎ]/I/g
|
||||||
|
s/[ÔÖ]/O/g
|
||||||
|
s/[ÜÛ]/U/g
|
||||||
|
s/[Ç]/C/g
|
||||||
|
'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: stripnl "Supprimer dans le flux en entrée les caractères de fin de ligne
|
||||||
|
|
||||||
|
si cette fonction est appelée avec des arguments, prendre \$* comme valeur du flux en entrée."
|
||||||
|
function stripnl() {
|
||||||
|
if [ $# -gt 0 ]; then stripnl <<<"$*"
|
||||||
|
else tr -d '\r\n'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: nl2lf "transformer dans le flux en entrée les fins de ligne en LF
|
||||||
|
|
||||||
|
si cette fonction est appelée avec des arguments, prendre \$* comme valeur du flux en entrée."
|
||||||
|
function nl2lf() {
|
||||||
|
if [ $# -gt 0 ]; then nl2lf <<<"$*"
|
||||||
|
else lawk 'BEGIN {RS="\r|\r\n|\n"} {print}'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: nl2crlf "transformer dans le flux en entrée les fins de ligne en CRLF
|
||||||
|
|
||||||
|
si cette fonction est appelée avec des arguments, prendre \$* comme valeur du flux en entrée."
|
||||||
|
function nl2crlf() {
|
||||||
|
if [ $# -gt 0 ]; then nl2crlf <<<"$*"
|
||||||
|
else lawk 'BEGIN {RS="\r|\r\n|\n"} {print $0 "\r"}'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: nl2cr "transformer dans le flux en entrée les fins de ligne en CR
|
||||||
|
|
||||||
|
si cette fonction est appelée avec des arguments, prendre \$* comme valeur du flux en entrée."
|
||||||
|
function nl2cr() {
|
||||||
|
if [ $# -gt 0 ]; then nl2cr <<<"$*"
|
||||||
|
else lawk 'BEGIN {RS="\r|\r\n|\n"; ORS=""} {print $0 "\r"}'
|
||||||
|
fi
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: base.tools "Fonctions de base: outils divers"
|
||||||
|
|
||||||
|
function: mkdirof 'Créer le répertoire correspondant au fichier $1'
|
||||||
|
function mkdirof() {
|
||||||
|
mkdir -p "$(dirname -- "$1")"
|
||||||
|
}
|
||||||
|
|
||||||
|
function __la_cmd() {
|
||||||
|
[ $# -gt 0 ] || set '*'
|
||||||
|
local arg
|
||||||
|
local cmd="/bin/ls -1d"
|
||||||
|
for arg in "$@"; do
|
||||||
|
arg="$(qwc "$arg")"
|
||||||
|
cmd="$cmd $arg"
|
||||||
|
done
|
||||||
|
cmd="$cmd 2>/dev/null"
|
||||||
|
echo "$cmd"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: ls_all 'Lister les fichiers ou répertoires du répertoire $1, un par ligne
|
||||||
|
Les répertoires . et .. sont enlevés de la liste
|
||||||
|
$1=un répertoire dont le contenu doit être listé
|
||||||
|
$2..@=un ensemble de patterns pour le listage
|
||||||
|
|
||||||
|
Seuls les noms des fichiers sont listés. Utiliser l'\''option -p pour inclure
|
||||||
|
les chemins'
|
||||||
|
function ls_all() {
|
||||||
|
local withp f b
|
||||||
|
if [ "$1" == -p ]; then withp=1; shift; fi
|
||||||
|
b="${1:-.}"; shift
|
||||||
|
|
||||||
|
(
|
||||||
|
cd "$b" || exit
|
||||||
|
eval "$(__la_cmd "$@")" | while read f; do
|
||||||
|
[ "$f" == "." -o "$f" == ".." ] && continue
|
||||||
|
recho "${withp:+$b/}$f"
|
||||||
|
done
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function: ls_files 'Lister les fichiers du répertoire $1, un par ligne
|
||||||
|
$1=un répertoire dont le contenu doit être listé.
|
||||||
|
$2..@=un ensemble de patterns pour le listage
|
||||||
|
|
||||||
|
Seuls les noms des fichiers sont listés. Utiliser l'\''option -p pour inclure
|
||||||
|
les chemins'
|
||||||
|
function ls_files() {
|
||||||
|
local withp f b
|
||||||
|
if [ "$1" == -p ]; then withp=1; shift; fi
|
||||||
|
b="${1:-.}"; shift
|
||||||
|
|
||||||
|
(
|
||||||
|
cd "$b" || exit
|
||||||
|
eval "$(__la_cmd "$@")" | while read f; do
|
||||||
|
[ -f "$f" ] && recho "${withp:+$b/}$f"
|
||||||
|
done
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function: ls_dirs 'Lister les répertoires du répertoire $1, un par ligne
|
||||||
|
Les répertoires . et .. sont enlevés de la liste
|
||||||
|
$1=un répertoire dont le contenu doit être listé.
|
||||||
|
$2..@=un ensemble de patterns pour le listage
|
||||||
|
|
||||||
|
Seuls les noms des répertoires sont listés. Utiliser l'\''option -p pour
|
||||||
|
inclure les chemins'
|
||||||
|
function ls_dirs() {
|
||||||
|
local withp f b
|
||||||
|
if [ "$1" == -p ]; then withp=1; shift; fi
|
||||||
|
b="${1:-.}"; shift
|
||||||
|
|
||||||
|
(
|
||||||
|
cd "$b" || exit
|
||||||
|
eval "$(__la_cmd "$@")" | while read f; do
|
||||||
|
[ "$f" == "." -o "$f" == ".." ] && continue
|
||||||
|
[ -d "$f" ] && recho "${withp:+$b/}$f"
|
||||||
|
done
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function: quietgrep "tester la présence d'un pattern dans un fichier en mode silencieux"
|
||||||
|
function quietgrep() { grep -q "$@" 2>/dev/null; }
|
||||||
|
|
||||||
|
function: testsame "tester si deux fichiers sont identiques en mode silencieux"
|
||||||
|
function testsame() { diff -q "$@" >&/dev/null; }
|
||||||
|
|
||||||
|
function: testdiff "tester si deux fichiers sont différents en mode silencieux"
|
||||||
|
function testdiff() { ! diff -q "$@" >&/dev/null; }
|
||||||
|
|
||||||
|
function: should_update "faut-il mettre à jour le \$1 qui est construit à partir de \$2..@"
|
||||||
|
function should_update() {
|
||||||
|
local dest="$1"; shift
|
||||||
|
local source
|
||||||
|
for source in "$@"; do
|
||||||
|
[ -f "$source" ] || continue
|
||||||
|
[ "$source" -nt "$dest" ] && return 0
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: donk.build "construire des images docker"
|
||||||
|
require: donk.common
|
|
@ -0,0 +1,3 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: donk.common "fonctions communes"
|
|
@ -0,0 +1,41 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: donk.help "aide de donk"
|
||||||
|
|
||||||
|
DONK_VALID_ACTIONS=(
|
||||||
|
dump:d
|
||||||
|
build:b
|
||||||
|
clean:k
|
||||||
|
)
|
||||||
|
dump_SUMMARY="afficher les valeurs des variables et ce que ferait l'action build"
|
||||||
|
build_SUMMARY="construire les images"
|
||||||
|
clean_SUMMARY="nettoyer le projet des fichiers créés avec 'copy gitignore=', en utilisant la commande 'git clean -dX'"
|
||||||
|
|
||||||
|
DONK_HELP_SECTIONS=(
|
||||||
|
base:b
|
||||||
|
reference:ref:r
|
||||||
|
)
|
||||||
|
|
||||||
|
function donk_help() {
|
||||||
|
:
|
||||||
|
}
|
||||||
|
|
||||||
|
function _donk_show_actions() {
|
||||||
|
local action summary
|
||||||
|
echo "
|
||||||
|
ACTIONS"
|
||||||
|
for action in "${DONK_VALID_ACTIONS[@]}"; do
|
||||||
|
IFS=: read -a action <<<"$action"; action="${action[0]}"
|
||||||
|
summary="${action}_SUMMARY"; summary="${!summary}"
|
||||||
|
echo "\
|
||||||
|
$action
|
||||||
|
$summary"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function _donk_show_help() {
|
||||||
|
if [ -z "$value_" ]; then showhelp@
|
||||||
|
else donk_help "$value_"
|
||||||
|
fi
|
||||||
|
exit $?
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: fndate "gestion de fichiers dont le nom contient la date"
|
||||||
|
|
||||||
|
function: fndate_verifix "\
|
||||||
|
corriger le chemin \$1 pour ajouter le cas échéant une date au nom du fichier
|
||||||
|
le fichier n'existe peut-être pas au moment où cette fonction est appelée
|
||||||
|
\$2 est l'extension finale du fichier, à ignorer si elle est présente
|
||||||
|
(elle n'est cependant pas ajoutée si elle n'est pas présente)
|
||||||
|
\$3 est la date à sélectionner (par défaut c'est la date du jour)
|
||||||
|
|
||||||
|
XXX à implémenter:
|
||||||
|
- gestion de la date
|
||||||
|
- ajout d'un suffixe .N le cas échéant (i.e YYMMDD.NN)
|
||||||
|
"
|
||||||
|
function fndate_verifix() {
|
||||||
|
local dir filename ext date
|
||||||
|
if [[ "$1" == */* ]]; then
|
||||||
|
dir="$(dirname -- "$1")"
|
||||||
|
filename="$(basename -- "$1")"
|
||||||
|
else
|
||||||
|
dir=
|
||||||
|
filename="$1"
|
||||||
|
fi
|
||||||
|
ext="$2"
|
||||||
|
if [ -n "$ext" ]; then
|
||||||
|
ext=".${2#.}"
|
||||||
|
if [ "${filename%$ext}" != "$filename" ]; then
|
||||||
|
filename="${filename%$ext}"
|
||||||
|
else
|
||||||
|
ext=
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
date="$3"
|
||||||
|
[ -n "$date" ] || date="$(date +%y%m%d)"
|
||||||
|
|
||||||
|
case "$filename" in
|
||||||
|
~~-*) filename="$date-${filename#~~-}";;
|
||||||
|
~~*) filename="$date-${filename#~~}";;
|
||||||
|
*-~~) filename="${filename%-~~}-$date";;
|
||||||
|
*~~) filename="${filename%~~}-$date";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "${dir:+$dir/}$filename$ext"
|
||||||
|
}
|
|
@ -0,0 +1,217 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
##@require nulib.sh
|
||||||
|
##@require base
|
||||||
|
module: git "Fonctions pour faciliter l'utilisation de git"
|
||||||
|
require: nulib base
|
||||||
|
|
||||||
|
function: git_geturl ""
|
||||||
|
function git_geturl() {
|
||||||
|
git config --get remote.origin.url
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_have_annex ""
|
||||||
|
function git_have_annex() {
|
||||||
|
[ -n "$(git config --get annex.uuid)" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
NULIB_GIT_FUNCTIONS=(
|
||||||
|
git_check_gitvcs git_ensure_gitvcs
|
||||||
|
git_list_branches git_list_rbranches
|
||||||
|
git_have_branch git_have_rbranch
|
||||||
|
git_get_branch git_is_branch
|
||||||
|
git_have_remote git_track_branch
|
||||||
|
git_check_cleancheckout git_ensure_cleancheckout
|
||||||
|
git_is_ancestor git_should_ff git_should_push
|
||||||
|
git_is_merged
|
||||||
|
)
|
||||||
|
NULIB_GIT_FUNCTIONS_MAP=(
|
||||||
|
cg:git_check_gitvcs eg:git_ensure_gitvcs
|
||||||
|
lbs:git_list_branches rbs:git_list_rbranches
|
||||||
|
hlb:git_have_branch hrb:git_have_rbranch
|
||||||
|
gb:git_get_branch ib:git_is_branch
|
||||||
|
hr:git_have_remote tb:git_track_branch
|
||||||
|
cc:git_check_cleancheckout ec:git_ensure_cleancheckout
|
||||||
|
ia:git_is_ancestor sff:git_should_ff spu:git_should_push
|
||||||
|
im:git_is_merged
|
||||||
|
)
|
||||||
|
|
||||||
|
function: git_check_gitvcs ""
|
||||||
|
function git_check_gitvcs() {
|
||||||
|
git rev-parse --show-toplevel >&/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_ensure_gitvcs ""
|
||||||
|
function git_ensure_gitvcs() {
|
||||||
|
git_check_gitvcs || edie "Ce n'est pas un dépôt git" || return
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_list_branches ""
|
||||||
|
function git_list_branches() {
|
||||||
|
git for-each-ref refs/heads/ --format='%(refname:short)' | csort
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_list_rbranches ""
|
||||||
|
function git_list_rbranches() {
|
||||||
|
git for-each-ref "refs/remotes/${1:-origin}/" --format='%(refname:short)' | csort
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_list_pbranches "lister les branches locales et celles qui existent dans l'origine \$1(=origin) et qui pourraient devenir une branche locale avec la commande git checkout -b"
|
||||||
|
function git_list_pbranches() {
|
||||||
|
local prefix="${1:-origin}/"
|
||||||
|
{
|
||||||
|
git for-each-ref refs/heads/ --format='%(refname:short)'
|
||||||
|
git for-each-ref "refs/remotes/$prefix" --format='%(refname:short)' | grep -F "$prefix" | cut -c $((${#prefix} + 1))-
|
||||||
|
} | grep -vF HEAD | csort -u
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_have_branch ""
|
||||||
|
function git_have_branch() {
|
||||||
|
git_list_branches | grep -qF "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_have_rbranch ""
|
||||||
|
function git_have_rbranch() {
|
||||||
|
git_list_rbranches "${2:-origin}" | grep -qF "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_get_branch ""
|
||||||
|
function git_get_branch() {
|
||||||
|
git rev-parse --abbrev-ref HEAD 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_get_branch_remote ""
|
||||||
|
function git_get_branch_remote() {
|
||||||
|
local branch="$1"
|
||||||
|
[ -n "$branch" ] || branch="$(git_get_branch)"
|
||||||
|
[ -n "$branch" ] || return
|
||||||
|
git config --get "branch.$branch.remote"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_get_branch_merge ""
|
||||||
|
function git_get_branch_merge() {
|
||||||
|
local branch="$1"
|
||||||
|
[ -n "$branch" ] || branch="$(git_get_branch)"
|
||||||
|
[ -n "$branch" ] || return
|
||||||
|
git config --get "branch.$branch.merge"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_get_branch_rbranch ""
|
||||||
|
function git_get_branch_rbranch() {
|
||||||
|
local branch="$1" remote="$2" merge
|
||||||
|
[ -n "$branch" ] || branch="$(git_get_branch)"
|
||||||
|
[ -n "$branch" ] || return
|
||||||
|
[ -n "$remote" ] || remote="$(git_get_branch_remote "$branch")"
|
||||||
|
[ -n "$remote" ] || return
|
||||||
|
merge="$(git_get_branch_merge "$branch")"
|
||||||
|
[ -n "$merge" ] || return
|
||||||
|
echo "refs/remotes/$remote/${merge#refs/heads/}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_is_branch ""
|
||||||
|
function git_is_branch() {
|
||||||
|
[ "$(git_get_branch)" == "${1:-master}" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_have_remote ""
|
||||||
|
function git_have_remote() {
|
||||||
|
[ -n "$(git config --get remote.${1:-origin}.url)" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_track_branch ""
|
||||||
|
function git_track_branch() {
|
||||||
|
local branch="$1" origin="${2:-origin}"
|
||||||
|
[ -n "$branch" ] || return
|
||||||
|
git_have_remote "$origin" || return
|
||||||
|
[ "$(git config --get branch.$branch.remote)" == "$origin" ] && return
|
||||||
|
if git_have_rbranch "$branch" "$origin"; then
|
||||||
|
if git_have_branch "$branch"; then
|
||||||
|
git branch -u "$origin/$branch" "$branch"
|
||||||
|
else
|
||||||
|
git branch -t "$branch" "$origin/$branch"
|
||||||
|
fi
|
||||||
|
elif git_have_branch "$branch"; then
|
||||||
|
git push -u "$origin" "$branch" || return
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_ensure_branch "
|
||||||
|
@return 0 si la branche a été créée, 1 si elle existait déjà, 2 en cas d'erreur"
|
||||||
|
function git_ensure_branch() {
|
||||||
|
local branch="$1" source="${2:-master}" origin="${3:-origin}"
|
||||||
|
[ -n "$branch" ] || return 2
|
||||||
|
git_have_branch "$branch" && return 1
|
||||||
|
if git_have_rbranch "$branch" "$origin"; then
|
||||||
|
# une branche du même nom existe dans l'origine. faire une copie de cette branche
|
||||||
|
git branch -t "$branch" "$origin/$branch" || return 2
|
||||||
|
else
|
||||||
|
# créer une nouvelle branche du nom spécifié
|
||||||
|
git_have_branch "$source" || return 2
|
||||||
|
git branch "$branch" "$source" || return 2
|
||||||
|
if [ -z "$NULIB_GIT_OFFLINE" ]; then
|
||||||
|
git_have_remote "$origin" && git_track_branch "$branch" "$origin"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_check_cleancheckout "vérifier qu'il n'y a pas de modification locales dans le dépôt correspondant au répertoire courant."
|
||||||
|
function git_check_cleancheckout() {
|
||||||
|
[ -z "$(git status --porcelain 2>/dev/null)" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_ensure_cleancheckout ""
|
||||||
|
function git_ensure_cleancheckout() {
|
||||||
|
git_check_cleancheckout ||
|
||||||
|
edie "Vous avez des modifications locales. Enregistrez ces modifications avant de continuer" || return
|
||||||
|
}
|
||||||
|
|
||||||
|
function git__init_ff() {
|
||||||
|
o="${3:-origin}"
|
||||||
|
b="$1" s="${2:-refs/remotes/$o/$1}"
|
||||||
|
b="$(git rev-parse --verify --quiet "$b")" || return 1
|
||||||
|
s="$(git rev-parse --verify --quiet "$s")" || return 1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
function git__can_ff() {
|
||||||
|
[ "$1" == "$(git merge-base "$1" "$2")" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_is_ancestor "vérifier que la branche \$1 est un ancêtre direct de la branche \$2, qui vaut par défaut refs/remotes/\${3:-origin}/\$1
|
||||||
|
note: cette fonction retourne vrai si \$1 et \$2 identifient le même commit"
|
||||||
|
function git_is_ancestor() {
|
||||||
|
local o b s; git__init_ff "$@" || return
|
||||||
|
git__can_ff "$b" "$s"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_should_ff "vérifier si la branche \$1 devrait être fast-forwardée à partir de la branche d'origine \$2, qui vaut par défaut refs/remotes/\${3:-origin}/\$1
|
||||||
|
note: cette fonction est similaire à git_is_ancestor(), mais retourne false si \$1 et \$2 identifient le même commit"
|
||||||
|
function git_should_ff() {
|
||||||
|
local o b s; git__init_ff "$@" || return
|
||||||
|
[ "$b" != "$s" ] || return 1
|
||||||
|
git__can_ff "$b" "$s"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_should_push "vérifier si la branche \$1 devrait être poussée vers la branche de même nom dans l'origine \$2(=origin), parce que l'origin peut-être fast-forwardée à partir de cette branche."
|
||||||
|
function git_should_push() {
|
||||||
|
git_should_ff "refs/remotes/${2:-origin}/$1" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_fast_forward "vérifier que la branche courante est bien \$1, puis tester s'il faut la fast-forwarder à partir de la branche d'origine \$2, puis le faire si c'est nécessaire. la branche d'origine \$2 vaut par défaut refs/remotes/origin/\$1"
|
||||||
|
function git_fast_forward() {
|
||||||
|
local o b s; git__init_ff "$@" || return
|
||||||
|
[ "$b" != "$s" ] || return 1
|
||||||
|
local head="$(git rev-parse HEAD)"
|
||||||
|
[ "$head" == "$b" ] || return 1
|
||||||
|
git__can_ff "$b" "$s" || return 1
|
||||||
|
git merge --ff-only "$s"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: git_is_merged "vérifier que les branches \$1 et \$2 ont un ancêtre commun, et que la branche \$1 a été complètement fusionnée dans la branche destination \$2"
|
||||||
|
function git_is_merged() {
|
||||||
|
local b="$1" d="$2"
|
||||||
|
b="$(git rev-parse --verify --quiet "$b")" || return 1
|
||||||
|
d="$(git rev-parse --verify --quiet "$d")" || return 1
|
||||||
|
[ -n "$(git merge-base "$b" "$d")" ] || return 1
|
||||||
|
[ -z "$(git rev-list "$d..$b")" ]
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
../../load.sh
|
|
@ -0,0 +1,194 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: pretty "Affichage en couleur"
|
||||||
|
require: base
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Gestion des couleurs
|
||||||
|
|
||||||
|
function __get_color() {
|
||||||
|
[ -z "$*" ] && set RESET
|
||||||
|
echo_ $'\e['
|
||||||
|
local sep
|
||||||
|
while [ -n "$1" ]; do
|
||||||
|
[ -n "$sep" ] && echo_ ";"
|
||||||
|
case "$1" in
|
||||||
|
z|RESET) echo_ "0";;
|
||||||
|
o|BLACK) echo_ "30";;
|
||||||
|
r|RED) echo_ "31";;
|
||||||
|
g|GREEN) echo_ "32";;
|
||||||
|
y|YELLOW) echo_ "33";;
|
||||||
|
b|BLUE) echo_ "34";;
|
||||||
|
m|MAGENTA) echo_ "35";;
|
||||||
|
c|CYAN) echo_ "36";;
|
||||||
|
w|WHITE) echo_ "37";;
|
||||||
|
DEFAULT) echo_ "39";;
|
||||||
|
O|BLACK_BG) echo_ "40";;
|
||||||
|
R|RED_BG) echo_ "41";;
|
||||||
|
G|GREEN_BG) echo_ "42";;
|
||||||
|
Y|YELLOW_BG) echo_ "43";;
|
||||||
|
B|BLUE_BG) echo_ "44";;
|
||||||
|
M|MAGENTA_BG) echo_ "45";;
|
||||||
|
C|CYAN_BG) echo_ "46";;
|
||||||
|
W|WHITE_BG) echo_ "47";;
|
||||||
|
DEFAULT_BG) echo_ "49";;
|
||||||
|
@|BOLD) echo_ "1";;
|
||||||
|
-|FAINT) echo_ "2";;
|
||||||
|
_|UNDERLINED) echo_ "4";;
|
||||||
|
~|REVERSE) echo_ "7";;
|
||||||
|
n|NORMAL) echo_ "22";;
|
||||||
|
esac
|
||||||
|
sep=1
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
echo_ "m"
|
||||||
|
}
|
||||||
|
function get_color() {
|
||||||
|
[ -n "$NO_COLORS" ] && return
|
||||||
|
__get_color "$@"
|
||||||
|
}
|
||||||
|
function __set_no_colors() {
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
if [ -n "$NULIB_NO_COLORS" ]; then NO_COLORS=1
|
||||||
|
elif out_isatty && err_isatty; then NO_COLORS=
|
||||||
|
else NO_COLORS=1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
is_yes "$1" && NO_COLORS=1 || NO_COLORS=
|
||||||
|
fi
|
||||||
|
|
||||||
|
COULEUR_ROUGE="$(get_color RED BOLD)"
|
||||||
|
COULEUR_VERTE="$(get_color GREEN BOLD)"
|
||||||
|
COULEUR_JAUNE="$(get_color YELLOW BOLD)"
|
||||||
|
COULEUR_BLEUE="$(get_color BLUE BOLD)"
|
||||||
|
COULEUR_BLANCHE="$(get_color WHITE BOLD)"
|
||||||
|
COULEUR_NORMALE="$(get_color RESET)"
|
||||||
|
if [ -n "$NO_COLORS" ]; then
|
||||||
|
nulib__load: _output_vanilla
|
||||||
|
else
|
||||||
|
nulib__load: _output_color
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
__set_no_colors
|
||||||
|
|
||||||
|
# 5=afficher les messages de debug; 4=afficher les message verbeux;
|
||||||
|
# 3=afficher les message informatifs; 2=afficher les warnings et les notes;
|
||||||
|
# 1=afficher les erreurs; 0=ne rien afficher
|
||||||
|
export __verbosity
|
||||||
|
[ -z "$__verbosity" ] && __verbosity=3
|
||||||
|
function set_verbosity() {
|
||||||
|
[ -z "$__verbosity" ] && __verbosity=3
|
||||||
|
case "$1" in
|
||||||
|
-Q|--very-quiet) __verbosity=0;;
|
||||||
|
-q|--quiet) [ "$__verbosity" -gt 0 ] && let __verbosity=$__verbosity-1;;
|
||||||
|
-v|--verbose) [ "$__verbosity" -lt 5 ] && let __verbosity=$__verbosity+1;;
|
||||||
|
-c|--default) __verbosity=3;;
|
||||||
|
-D|--debug) __verbosity=5; DEBUG=1;;
|
||||||
|
*) return 1;;
|
||||||
|
esac
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
# 3=interaction maximale; 2=interaction par défaut
|
||||||
|
# 1= interaction minimale; 0=pas d'interaction
|
||||||
|
export __interaction
|
||||||
|
[ -z "$__interaction" ] && __interaction=2
|
||||||
|
function set_interaction() {
|
||||||
|
[ -z "$__interaction" ] && __interaction=2
|
||||||
|
case "$1" in
|
||||||
|
-b|--batch) __interaction=0;;
|
||||||
|
-y|--automatic) [ "$__interaction" -gt 0 ] && let __interaction=$__interaction-1;;
|
||||||
|
-i|--interactive) [ "$__interaction" -lt 3 ] && let __interaction=$__interaction+1;;
|
||||||
|
-c|--default) __interaction=2;;
|
||||||
|
*) return 1;;
|
||||||
|
esac
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Variable à inclure pour lancer automatiquement set_verbosity et
|
||||||
|
# set_interaction en fonction des arguments de la ligne de commande. A utiliser
|
||||||
|
# de cette manière:
|
||||||
|
# parse_opts ... "${PRETTYOPTS[@]}" @ args -- ...
|
||||||
|
PRETTYOPTS=(
|
||||||
|
-L:,--log-to: '$elogto $value_'
|
||||||
|
-Q,--very-quiet,-q,--quiet,-v,--verbose,-D,--debug '$set_verbosity $option_'
|
||||||
|
-b,--batch,-y,--automatic,-i,--interactive '$set_interaction $option_'
|
||||||
|
)
|
||||||
|
|
||||||
|
function show_error() { [ "$__verbosity" -ge 1 ]; }
|
||||||
|
function show_warn() { [ "$__verbosity" -ge 2 ]; }
|
||||||
|
function show_info() { [ "$__verbosity" -ge 3 ]; }
|
||||||
|
function show_verbose() { [ "$__verbosity" -ge 4 ]; }
|
||||||
|
function show_debug() { [ -n "$DEBUG" -o "$__verbosity" -ge 5 ]; }
|
||||||
|
|
||||||
|
# Vérifier le niveau de verbosité actuel par rapport à l'argument. $1 peut valoir:
|
||||||
|
# -Q retourner true si on peut afficher les messages d'erreur
|
||||||
|
# -q retourner true si on peut afficher les messages d'avertissement
|
||||||
|
# -c retourner true si on peut afficher les message normaux
|
||||||
|
# -v retourner true si on peut afficher les messages verbeux
|
||||||
|
# -D retourner true si on peut afficher les messages de debug
|
||||||
|
function check_verbosity() {
|
||||||
|
case "$1" in
|
||||||
|
-Q|--very-quiet) [ "$__verbosity" -ge 1 ];;
|
||||||
|
-q|--quiet) [ "$__verbosity" -ge 2 ];;
|
||||||
|
-c|--default) [ "$__verbosity" -ge 3 ];;
|
||||||
|
-v|--verbose) [ "$__verbosity" -ge 4 ];;
|
||||||
|
-D|--debug) [ -n "$DEBUG" -o "$__verbosity" -ge 5 ];;
|
||||||
|
*) return 0;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
# Retourner l'option correspondant au niveau de verbosité actuel
|
||||||
|
function get_verbosity_option() {
|
||||||
|
case "$__verbosity" in
|
||||||
|
0) echo --very-quiet;;
|
||||||
|
1) echo --quiet --quiet;;
|
||||||
|
2) echo --quiet;;
|
||||||
|
4) echo --verbose;;
|
||||||
|
5) echo --debug;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Vérifier le niveau d'interaction autorisé par rapport à l'argument. Par
|
||||||
|
# exemple, 'check_interaction -y' signifie "Il ne faut interagir avec
|
||||||
|
# l'utilisateur qu'à partir du niveau d'interaction -y. Suis-je dans les
|
||||||
|
# condition voulues pour autoriser l'interaction?"
|
||||||
|
# $1 peut valoir:
|
||||||
|
# -b retourner true
|
||||||
|
# -y retourner true si on est au moins en interaction minimale
|
||||||
|
# -c retourner true si on est au moins en interaction normale
|
||||||
|
# -i retourner true si on est au moins en interaction maximale
|
||||||
|
function check_interaction() {
|
||||||
|
case "$1" in
|
||||||
|
-b|--batch) return 0;;
|
||||||
|
-y|--automatic) [ -n "$__interaction" -a "$__interaction" -ge 1 ];;
|
||||||
|
-c|--default) [ -n "$__interaction" -a "$__interaction" -ge 2 ];;
|
||||||
|
-i|--interactive) [ -n "$__interaction" -a "$__interaction" -ge 3 ];;
|
||||||
|
*) return 0;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
# Vérifier le niveau d'interaction dans lequel on se trouve actuellement. $1
|
||||||
|
# peut valoir:
|
||||||
|
# -b retourner true si l'une des options -b ou -yy a été spécifiée
|
||||||
|
# -Y retourner true si l'une des options -b, -yy, ou -y a été spécifiée
|
||||||
|
# -y retourner true si l'option -y a été spécifiée
|
||||||
|
# -c retourner true si aucune option n'a été spécifiée
|
||||||
|
# -i retourner true si l'option -i a été spécifiée
|
||||||
|
# -C retourner true si aucune option ou l'option -i ont été spécifiés
|
||||||
|
function is_interaction() {
|
||||||
|
case "$1" in
|
||||||
|
-b|--batch) [ -n "$__interaction" -a "$__interaction" -eq 0 ];;
|
||||||
|
-Y) [ -n "$__interaction" -a "$__interaction" -le 1 ];;
|
||||||
|
-y|--automatic) [ -n "$__interaction" -a "$__interaction" -eq 1 ];;
|
||||||
|
-c|--default) [ -n "$__interaction" -a "$__interaction" -eq 2 ];;
|
||||||
|
-i|--interactive) [ -n "$__interaction" -a "$__interaction" -eq 3 ];;
|
||||||
|
-C) [ -n "$__interaction" -a "$__interaction" -ge 2 ];;
|
||||||
|
*) return 1;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
# Retourner l'option correspondant au niveau d'interaction actuel
|
||||||
|
function get_interaction_option() {
|
||||||
|
case "$__interaction" in
|
||||||
|
0) echo --batch;;
|
||||||
|
1) echo --automatic;;
|
||||||
|
3) echo --interactive;;
|
||||||
|
esac
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: sysinfos "Informations sur le système courant"
|
||||||
|
require: base
|
|
@ -0,0 +1,225 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: template "Mise à jour de templates à partir de modèles"
|
||||||
|
|
||||||
|
function: template_locals "\
|
||||||
|
Afficher les variables qui doivent être locales
|
||||||
|
|
||||||
|
Utiliser de cette façon:
|
||||||
|
~~~
|
||||||
|
eval \$(template_locals)
|
||||||
|
~~~"
|
||||||
|
function template_locals() {
|
||||||
|
echo "local -a userfiles; local updated"
|
||||||
|
}
|
||||||
|
|
||||||
|
function: template_copy_replace "\
|
||||||
|
Copier \$1 vers \$2 de façon inconditionnelle
|
||||||
|
|
||||||
|
Si \$2 n'est pas spécifié, on assume que \$1 est de la forme '.file.ext'
|
||||||
|
et \$2 vaudra alors 'file'
|
||||||
|
|
||||||
|
si un fichier \${2#.}.local existe, prendre ce fichier à la place comme source
|
||||||
|
|
||||||
|
Ajouter file au tableau userfiles"
|
||||||
|
function template_copy_replace() {
|
||||||
|
local src="$1" dest="$2"
|
||||||
|
local srcdir srcname lsrcname
|
||||||
|
setx srcdir=dirname "$src"
|
||||||
|
setx srcname=basename "$src"
|
||||||
|
if [ -z "$dest" ]; then
|
||||||
|
dest="${srcname#.}"
|
||||||
|
dest="${dest%.*}"
|
||||||
|
dest="$srcdir/$dest"
|
||||||
|
fi
|
||||||
|
|
||||||
|
lsrcname="${srcname#.}.local"
|
||||||
|
[ -e "$srcdir/$lsrcname" ] && src="$srcdir/$lsrcname"
|
||||||
|
|
||||||
|
userfiles+=("$dest")
|
||||||
|
cp -P "$src" "$dest"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function: template_copy_missing "\
|
||||||
|
Copier \$1 vers \$2 si ce fichier n'existe pas déjà
|
||||||
|
|
||||||
|
Si \$2 n'est pas spécifié, on assume que \$1 est de la forme '.file.ext'
|
||||||
|
et \$2 vaudra alors 'file'
|
||||||
|
|
||||||
|
si un fichier \${2#.}.local existe, prendre ce fichier à la place comme source
|
||||||
|
|
||||||
|
Ajouter file au tableau userfiles"
|
||||||
|
function template_copy_missing() {
|
||||||
|
local src="$1" dest="$2"
|
||||||
|
local srcdir srcname lsrcname
|
||||||
|
setx srcdir=dirname "$src"
|
||||||
|
setx srcname=basename "$src"
|
||||||
|
if [ -z "$dest" ]; then
|
||||||
|
dest="${srcname#.}"
|
||||||
|
dest="${dest%.*}"
|
||||||
|
dest="$srcdir/$dest"
|
||||||
|
fi
|
||||||
|
|
||||||
|
userfiles+=("$dest")
|
||||||
|
if [ ! -e "$dest" ]; then
|
||||||
|
lsrcname="${srcname#.}.local"
|
||||||
|
[ -e "$srcdir/$lsrcname" ] && src="$srcdir/$lsrcname"
|
||||||
|
|
||||||
|
cp -P "$src" "$dest"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function: template_dump_vars "\
|
||||||
|
Lister les variables mentionnées dans les fichiers \$@
|
||||||
|
|
||||||
|
Seules sont prises en compte les variables dont le nom est de la forme
|
||||||
|
[A-Z][A-Za-z_]*
|
||||||
|
|
||||||
|
Cette fonction est utilisée par template_source_envs(). Elle utilise la
|
||||||
|
fonction outil _template_dump_vars() qui peut être redéfinie si nécessaire."
|
||||||
|
function template_dump_vars() {
|
||||||
|
_template_dump_vars "$@"
|
||||||
|
}
|
||||||
|
function _template_dump_vars() {
|
||||||
|
[ $# -gt 0 ] || return 0
|
||||||
|
cat "$@" |
|
||||||
|
grep -E '^[A-Z][A-Za-z_]*=' |
|
||||||
|
sed 's/=.*//' |
|
||||||
|
sort -u
|
||||||
|
}
|
||||||
|
|
||||||
|
function: template_source_envs "\
|
||||||
|
Cette fonction doit être implémentée par l'utilisateur et doit:
|
||||||
|
- initialiser le tableau template_vars qui donne la liste des variables scalaires
|
||||||
|
- initialiser te tableau template_lists qui donne la liste des variables listes
|
||||||
|
- charger ces variables depuis les fichiers \$@
|
||||||
|
|
||||||
|
Cette fonction utilise la fonction outil _template_source_envs() qui peut être
|
||||||
|
redéfinie si nécessaire."
|
||||||
|
function template_source_envs() {
|
||||||
|
_template_source_envs "$@"
|
||||||
|
}
|
||||||
|
function _template_source_envs() {
|
||||||
|
local e_
|
||||||
|
for e_ in "$@"; do
|
||||||
|
[ -f "$e_" ] && source "$e_"
|
||||||
|
done
|
||||||
|
setx -a template_vars=template_dump_vars "$@"
|
||||||
|
template_lists=()
|
||||||
|
}
|
||||||
|
|
||||||
|
function: template_resolve_scripts "\
|
||||||
|
Générer le script awk \$1 et le script sed \$2 qui remplacent dans les fichiers
|
||||||
|
destination les marqueurs @@VAR@@ par la valeur de la variable \$VAR
|
||||||
|
correspondante
|
||||||
|
|
||||||
|
Les fichiers \$3..@ contiennent les valeurs des variables
|
||||||
|
|
||||||
|
Les marqueurs supportés sont les suivants et sont évalués dans cet ordre:
|
||||||
|
- XXXRANDOMXXX remplacer cette valeur par une chaine de 16 caractères au hasard
|
||||||
|
- @@FOR:VARS@@ VARS étant une liste de valeurs séparées par des espaces:
|
||||||
|
dupliquer la ligne autant de fois qu'il y a de valeurs dans \$VARS
|
||||||
|
dans chaque ligne, remplacer les occurrences de @@VAR@@ par la valeur
|
||||||
|
de l'itération courante
|
||||||
|
- #@@IF:VAR@@ afficher la ligne si VAR est non vide, supprimer la ligne sinon
|
||||||
|
- #@@UL:VAR@@ afficher la ligne si VAR est vide, supprimer la ligne sinon
|
||||||
|
- #@@if:VAR@@
|
||||||
|
- #@@ul:VAR@@ variantes qui ne suppriment pas la ligne mais sont remplacées par #
|
||||||
|
- @@VAR:-string@@ remplacer par 'string' si VAR a une valeur vide ou n'est pas défini, \$VAR sinon
|
||||||
|
- @@VAR:+string@@ remplacer par 'string' si VAR est défini a une valeur non vide
|
||||||
|
"
|
||||||
|
function template_generate_scripts() {
|
||||||
|
local awkscript="$1"; shift
|
||||||
|
local sedscript="$1"; shift
|
||||||
|
(
|
||||||
|
template_source_envs "$@"
|
||||||
|
|
||||||
|
NL=$'\n'
|
||||||
|
# random, for
|
||||||
|
exec >"$awkscript"
|
||||||
|
echo '@include "base.tools.awk"'
|
||||||
|
echo 'BEGIN {'
|
||||||
|
for list in "${template_lists[@]}"; do
|
||||||
|
items="${!list}"; read -a items <<<"${items//
|
||||||
|
/ }"
|
||||||
|
let i=0
|
||||||
|
echo " $list[0] = 0; delete $list"
|
||||||
|
for item in "${items[@]}"; do
|
||||||
|
item="${item//\\/\\\\}"
|
||||||
|
item="${item//\"/\\\"}"
|
||||||
|
echo " $list[$i] = \"$item\""
|
||||||
|
let i=i+1
|
||||||
|
done
|
||||||
|
done
|
||||||
|
echo '}'
|
||||||
|
echo '{ if (should_generate_password()) { generate_password() } }'
|
||||||
|
for list in "${template_lists[@]}"; do
|
||||||
|
items="${!list}"; read -a items <<<"${items//
|
||||||
|
/ }"
|
||||||
|
echo "/@@FOR:$list@@/ {"
|
||||||
|
if [ ${#items[*]} -gt 0 ]; then
|
||||||
|
if [ "${list%S}" != "$list" ]; then item="${list%S}"
|
||||||
|
elif [ "${list%s}" != "$list" ]; then item="${list%s}"
|
||||||
|
else item="$list"
|
||||||
|
fi
|
||||||
|
echo " sub(/@@FOR:$list@@/, \"\")"
|
||||||
|
echo " for (i in $list) {"
|
||||||
|
echo " print gensub(/@@$item@@/, $list[i], \"g\")"
|
||||||
|
echo " }"
|
||||||
|
fi
|
||||||
|
echo " next"
|
||||||
|
echo "}"
|
||||||
|
done
|
||||||
|
echo '{ print }'
|
||||||
|
|
||||||
|
# if, ul, var
|
||||||
|
exec >"$sedscript"
|
||||||
|
for var in "${template_vars[@]}"; do
|
||||||
|
value="${!var}"
|
||||||
|
value="${value//\//\\\/}"
|
||||||
|
value="${value//[/\\[}"
|
||||||
|
value="${value//\*/\\\*}"
|
||||||
|
value="${value//$NL/\\n}"
|
||||||
|
if [ -n "$value" ]; then
|
||||||
|
echo "s/#@@IF:${var}@@//g"
|
||||||
|
echo "s/#@@if:${var}@@//g"
|
||||||
|
echo "/#@@UL:${var}@@/d"
|
||||||
|
echo "s/#@@ul:${var}@@/#/g"
|
||||||
|
echo "s/@@${var}:-([^@]*)@@/${value}/g"
|
||||||
|
echo "s/@@${var}:+([^@]*)@@/\\1/g"
|
||||||
|
else
|
||||||
|
echo "/#@@IF:${var}@@/d"
|
||||||
|
echo "s/#@@if:${var}@@/#/g"
|
||||||
|
echo "s/#@@UL:${var}@@//g"
|
||||||
|
echo "s/#@@ul:${var}@@//g"
|
||||||
|
echo "s/@@${var}:-([^@]*)@@/\\1/g"
|
||||||
|
echo "s/@@${var}:+([^@]*)@@//g"
|
||||||
|
fi
|
||||||
|
echo "s/@@${var}@@/${value}/g"
|
||||||
|
done
|
||||||
|
)
|
||||||
|
#etitle "awkscript" cat "$awkscript"
|
||||||
|
#etitle "sedscript" cat "$sedscript"
|
||||||
|
}
|
||||||
|
|
||||||
|
function template_process_userfiles() {
|
||||||
|
local awkscript sedscript workfile userfile
|
||||||
|
ac_set_tmpfile awkscript
|
||||||
|
ac_set_tmpfile sedscript
|
||||||
|
template_generate_scripts "$awkscript" "$sedscript" "$@"
|
||||||
|
|
||||||
|
ac_set_tmpfile workfile
|
||||||
|
for userfile in "${userfiles[@]}"; do
|
||||||
|
if cat "$userfile" | awk -f "$awkscript" | sed -rf "$sedscript" >"$workfile"; then
|
||||||
|
if testdiff "$workfile" "$userfile"; then
|
||||||
|
# n'écrire le fichier que s'il a changé
|
||||||
|
cat "$workfile" >"$userfile"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
ac_clean "$awkscript" "$sedscript" "$workfile"
|
||||||
|
}
|
|
@ -0,0 +1,160 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
##@cooked nocomments
|
||||||
|
module: tests "tests unitaires"
|
||||||
|
require: base
|
||||||
|
|
||||||
|
function tests__get_line() {
|
||||||
|
# obtenir le nom du script depuis lequel les fonctions de ce module ont été
|
||||||
|
# appelées
|
||||||
|
local mysource="${BASH_SOURCE[0]}"
|
||||||
|
local i=1
|
||||||
|
while [ "${BASH_SOURCE[$i]}" == "$mysource" ]; do
|
||||||
|
let i=i+1
|
||||||
|
done
|
||||||
|
echo "${BASH_SOURCE[$i]}:${BASH_LINENO[$((i-1))]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function tests__set_message() {
|
||||||
|
if [ "$1" == -m ]; then
|
||||||
|
message="$2"
|
||||||
|
return 2
|
||||||
|
elif [[ "$1" == -m* ]]; then
|
||||||
|
message="${1#-m}"
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function: assert_ok "faire un test unitaire. la syntaxe est
|
||||||
|
assert_ok [-m message] cmd
|
||||||
|
la commande doit retourner vrai pour que le test soit réussi"
|
||||||
|
function assert_ok() {
|
||||||
|
local message; tests__set_message "$@" || shift $?
|
||||||
|
"$@" && return 0
|
||||||
|
|
||||||
|
[ -n "$message" ] && message="$message: "
|
||||||
|
message="${message}test failed at $(tests__get_line)"
|
||||||
|
die "$message"
|
||||||
|
}
|
||||||
|
function assert() { assert_ok "$@"; }
|
||||||
|
|
||||||
|
function: assert_ko "faire un test unitaire. la syntaxe est
|
||||||
|
assert_ko [-m message] cmd
|
||||||
|
la commande doit retourner faux pour que le test soit réussi"
|
||||||
|
function assert_ko() {
|
||||||
|
local message; tests__set_message "$@" || shift $?
|
||||||
|
"$@" || return 0
|
||||||
|
|
||||||
|
[ -n "$message" ] && message="$message: "
|
||||||
|
message="${message}test failed at $(tests__get_line)"
|
||||||
|
die "$message"
|
||||||
|
}
|
||||||
|
|
||||||
|
function tests__assert() {
|
||||||
|
local message="$1"; shift
|
||||||
|
"assert_${1#assert_}" -m "$message" "${@:2}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert_n() {
|
||||||
|
local message; tests__set_message "$@" || shift $?
|
||||||
|
[ -n "$message" ] || message="$2"
|
||||||
|
[ -n "$message" ] || message="value is empty"
|
||||||
|
tests__assert "$message" ok [ -n "$1" ]
|
||||||
|
}
|
||||||
|
function assert_z() {
|
||||||
|
local message; tests__set_message "$@" || shift $?
|
||||||
|
[ -n "$message" ] || message="$2"
|
||||||
|
[ -n "$message" ] || message="value is not empty"
|
||||||
|
tests__assert "$message" ok [ -z "$1" ]
|
||||||
|
}
|
||||||
|
function assert_same() {
|
||||||
|
local message; tests__set_message "$@" || shift $?
|
||||||
|
[ -n "$message" ] || message="$3"
|
||||||
|
[ -n "$message" ] || message="'$1' and '$2' are different"
|
||||||
|
tests__assert "$message" ok [ "$1" == "$2" ]
|
||||||
|
}
|
||||||
|
function assert_diff() {
|
||||||
|
local message; tests__set_message "$@" || shift $?
|
||||||
|
[ -n "$message" ] || message="$3"
|
||||||
|
[ -n "$message" ] || message="'$1' and '$2' are the same"
|
||||||
|
tests__assert "$message" ok [ "$1" != "$2" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert_eq() {
|
||||||
|
local message; tests__set_message "$@" || shift $?
|
||||||
|
[ -n "$message" ] || message="$3"
|
||||||
|
[ -n "$message" ] || message="'$1' and '$2' are not equals"
|
||||||
|
tests__assert "'$1' must be a number" ok isnum "$1"
|
||||||
|
tests__assert "$message" ok [ "$1" -eq "$2" ]
|
||||||
|
}
|
||||||
|
function assert_ne() {
|
||||||
|
local message; tests__set_message "$@" || shift $?
|
||||||
|
[ -n "$message" ] || message="$3"
|
||||||
|
[ -n "$message" ] || message="'$1' and '$2' are equals"
|
||||||
|
tests__assert "'$1' must be a number" ok isnum "$1"
|
||||||
|
tests__assert "$message" ok [ "$1" -ne "$2" ]
|
||||||
|
}
|
||||||
|
function assert_gt() {
|
||||||
|
local message; tests__set_message "$@" || shift $?
|
||||||
|
[ -n "$message" ] || message="$3"
|
||||||
|
[ -n "$message" ] || message="'$1' is not greater than '$2'"
|
||||||
|
tests__assert "'$1' must be a number" ok isnum "$1"
|
||||||
|
tests__assert "$message" ok [ "$1" -gt "$2" ]
|
||||||
|
}
|
||||||
|
function assert_ge() {
|
||||||
|
local message; tests__set_message "$@" || shift $?
|
||||||
|
[ -n "$message" ] || message="$3"
|
||||||
|
[ -n "$message" ] || message="'$1' is not greater than or equals to '$2'"
|
||||||
|
tests__assert "'$1' must be a number" ok isnum "$1"
|
||||||
|
tests__assert "$message" ok [ "$1" -ge "$2" ]
|
||||||
|
}
|
||||||
|
function assert_lt() {
|
||||||
|
local message; tests__set_message "$@" || shift $?
|
||||||
|
[ -n "$message" ] || message="$3"
|
||||||
|
[ -n "$message" ] || message="'$1' is not less than '$2'"
|
||||||
|
tests__assert "'$1' must be a number" ok isnum "$1"
|
||||||
|
tests__assert "$message" ok [ "$1" -lt "$2" ]
|
||||||
|
}
|
||||||
|
function assert_le() {
|
||||||
|
local message; tests__set_message "$@" || shift $?
|
||||||
|
[ -n "$message" ] || message="$3"
|
||||||
|
[ -n "$message" ] || message="'$1' is not less than or equals to '$2'"
|
||||||
|
tests__assert "'$1' must be a number" ok isnum "$1"
|
||||||
|
tests__assert "$message" ok [ "$1" -le "$2" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert_is_defined() {
|
||||||
|
local message; tests__set_message "$@" || shift $?
|
||||||
|
[ -n "$message" ] || message="$2"
|
||||||
|
[ -n "$message" ] || message="'$1' is not defined"
|
||||||
|
tests__assert "$message" ok is_defined "$1"
|
||||||
|
}
|
||||||
|
function assert_not_defined() {
|
||||||
|
local message; tests__set_message "$@" || shift $?
|
||||||
|
[ -n "$message" ] || message="$2"
|
||||||
|
[ -n "$message" ] || message="'$1' is defined"
|
||||||
|
tests__assert "$message" ko is_defined "$1"
|
||||||
|
}
|
||||||
|
function assert_is_array() {
|
||||||
|
local message; tests__set_message "$@" || shift $?
|
||||||
|
[ -n "$message" ] || message="$2"
|
||||||
|
[ -n "$message" ] || message="'$1' is not an array"
|
||||||
|
tests__assert "$message" ok is_array "$1"
|
||||||
|
}
|
||||||
|
function assert_not_array() {
|
||||||
|
local message; tests__set_message "$@" || shift $?
|
||||||
|
[ -n "$message" ] || message="$2"
|
||||||
|
[ -n "$message" ] || message="'$1' is an array"
|
||||||
|
tests__assert "$message" ko is_array "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert_array_same() {
|
||||||
|
local message; tests__set_message "$@" || shift $?
|
||||||
|
[ -n "$message" ] || message="'$1' is not an array or not equals to (${*:2})"
|
||||||
|
|
||||||
|
assert_is_array "$1" "$message"
|
||||||
|
eval "actual=\"\$(qvals \"\${$1[@]}\")\""; shift
|
||||||
|
eval "expected=\"\$(qvals \"\$@\")\""
|
||||||
|
assert_same "$actual" "$expected" "$message"
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
/template-dest.txt
|
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
PROFILES vaut prod test
|
||||||
|
c'est à dire, si on fait un par ligne:
|
||||||
|
- prod
|
||||||
|
- test
|
||||||
|
---
|
||||||
|
PASSWORD is vaeRL6ADYKmWndEA
|
||||||
|
---
|
||||||
|
hosts:
|
||||||
|
- first
|
||||||
|
- second
|
||||||
|
---
|
||||||
|
---
|
||||||
|
IF valeur
|
||||||
|
if valeur
|
||||||
|
#ul valeur
|
||||||
|
---
|
||||||
|
#if
|
||||||
|
UL
|
||||||
|
ul
|
||||||
|
---
|
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
PROFILES vaut @@PROFILES@@
|
||||||
|
c'est à dire, si on fait un par ligne:
|
||||||
|
@@FOR:PROFILES@@- @@PROFILE@@
|
||||||
|
---
|
||||||
|
PASSWORD is XXXRANDOMXXX
|
||||||
|
---
|
||||||
|
#@@IF:HOSTS@@hosts:
|
||||||
|
@@FOR:HOSTS@@- @@HOST@@
|
||||||
|
---
|
||||||
|
#@@IF:VALUES@@values:
|
||||||
|
@@FOR:VALUES@@- @@VALUE@@
|
||||||
|
---
|
||||||
|
#@@IF:PLEIN@@IF @@PLEIN@@
|
||||||
|
#@@if:PLEIN@@if @@PLEIN@@
|
||||||
|
#@@UL:PLEIN@@UL @@PLEIN@@
|
||||||
|
#@@ul:PLEIN@@ul @@PLEIN@@
|
||||||
|
---
|
||||||
|
#@@IF:VIDE@@IF @@VIDE@@
|
||||||
|
#@@if:VIDE@@if @@VIDE@@
|
||||||
|
#@@UL:VIDE@@UL @@VIDE@@
|
||||||
|
#@@ul:VIDE@@ul @@VIDE@@
|
||||||
|
---
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
|
||||||
|
echo "\
|
||||||
|
source ./_template-values.env
|
||||||
|
template_vars=(
|
||||||
|
PROFILES
|
||||||
|
PASSWORD
|
||||||
|
HOSTS
|
||||||
|
VALUES
|
||||||
|
PLEIN
|
||||||
|
VIDE
|
||||||
|
)
|
||||||
|
template_lists=(
|
||||||
|
PROFILES
|
||||||
|
HOSTS
|
||||||
|
VALUES
|
||||||
|
)
|
||||||
|
"
|
|
@ -0,0 +1,12 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
|
||||||
|
PROFILES="prod test"
|
||||||
|
|
||||||
|
HOSTS="
|
||||||
|
first
|
||||||
|
second
|
||||||
|
"
|
||||||
|
VALUES=
|
||||||
|
|
||||||
|
PLEIN=valeur
|
||||||
|
VIDE=
|
|
@ -0,0 +1,17 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../src/nulib.sh" || exit 1
|
||||||
|
#NULIB_NO_DISABLE_SET_X=1
|
||||||
|
|
||||||
|
args=(
|
||||||
|
"tester autodebug"
|
||||||
|
#-D x=1 "désactiver l'option automatique -D"
|
||||||
|
#--debug x=1 "désactiver l'option automatique --debug"
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
if is_debug; then
|
||||||
|
echo "on est en mode debug"
|
||||||
|
else
|
||||||
|
echo "on n'est pas en mode debug, relancer avec -D ou --debug"
|
||||||
|
fi
|
|
@ -0,0 +1,40 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../src/nulib.sh" || exit 1
|
||||||
|
#NULIB_NO_DISABLE_SET_X=1
|
||||||
|
|
||||||
|
args=("tester l'affichage de l'aide")
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
s|std)
|
||||||
|
# NB: seul l'affichage standard est disponible...
|
||||||
|
args+=(
|
||||||
|
-h,--help,--hstd '$showhelp@' "afficher l'aide de base"
|
||||||
|
)
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
a|adv)
|
||||||
|
# NB: seul l'affichage avancé est disponible...
|
||||||
|
args+=(
|
||||||
|
-H,--help++,--hadv '$showhelp@ ++' "afficher l'aide avancée"
|
||||||
|
)
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
sa|std+adv)
|
||||||
|
args+=(
|
||||||
|
-h,--help,--hstd '$showhelp@' "afficher l'aide de base"
|
||||||
|
-H,--help++,--hadv '$showhelp@ ++' "afficher l'aide avancée"
|
||||||
|
)
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
args+=(
|
||||||
|
-a,--std . "cette option apparait dans les options standards"
|
||||||
|
-b,--adv . "++cette option apparait dans les options avancées"
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
enote "lancer le script
|
||||||
|
- avec --help pour afficher les options standards uniquement
|
||||||
|
- avec --help++ pour afficher toutes les options"
|
|
@ -0,0 +1,187 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../src/nulib.sh" || exit 1
|
||||||
|
require: tests
|
||||||
|
#NULIB_NO_DISABLE_SET_X=1
|
||||||
|
|
||||||
|
function pa() {
|
||||||
|
unset count fixed mopt dmopt oopt doopt autoinc autoval a1 a2 a3 a4
|
||||||
|
count=
|
||||||
|
fixed=
|
||||||
|
efixed=1
|
||||||
|
mopt=
|
||||||
|
dmopt=
|
||||||
|
oopt=
|
||||||
|
doopt=
|
||||||
|
autoinc=
|
||||||
|
autoval=
|
||||||
|
unset a1
|
||||||
|
a2=()
|
||||||
|
a3=
|
||||||
|
a4=x
|
||||||
|
args=(
|
||||||
|
"tester la gestion des arguments"
|
||||||
|
-o,--eopt count "incrémenter count"
|
||||||
|
-f,--fixed fixed=42 "spécifier fixed"
|
||||||
|
-e,--efixed efixed= "spécifier efixed"
|
||||||
|
-a:,--mopt mopt= "spécifier mopt"
|
||||||
|
-A:,--dmopt dmopt=default "spécifier dmopt"
|
||||||
|
-b::,--oopt oopt= "spécifier oopt"
|
||||||
|
-B::,--doopt doopt=default "spécifier doopt"
|
||||||
|
-n,--autoinc . "incrémenter autoinc"
|
||||||
|
-N,--no-autoinc . "décrémenter autoinc"
|
||||||
|
-v:,--autoval . "spécifier autoval"
|
||||||
|
-x: a1 "autoadd a1 qui n'est pas défini"
|
||||||
|
-y: a2 "autoadd a2 qui est défini à ()"
|
||||||
|
-z: a3 "autoadd a3 qui est défini à vide"
|
||||||
|
-t: a4 "autoadd a4 qui est défini à une valeur non vide"
|
||||||
|
-s,--sans-arg '$echo "sans_arg option=$option_, name=$name_, value=$value_"'
|
||||||
|
-S::,--avec-arg '$echo "avec_arg option=$option_, name=$name_, value=$value_"'
|
||||||
|
)
|
||||||
|
parse_args "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
pa
|
||||||
|
assert_z "$count"
|
||||||
|
assert_z "$fixed"
|
||||||
|
assert_eq "$efixed" 1
|
||||||
|
assert_z "$mopt"
|
||||||
|
assert_z "$dmopt"
|
||||||
|
assert_z "$oopt"
|
||||||
|
assert_z "$doopt"
|
||||||
|
assert_z "$autoinc"
|
||||||
|
assert_z "$autoval"
|
||||||
|
assert_not_defined a1
|
||||||
|
assert_is_array a2
|
||||||
|
assert_not_array a3
|
||||||
|
assert_z "$a3"
|
||||||
|
assert_not_array a4
|
||||||
|
assert_same x "$a4"
|
||||||
|
assert_eq "${#args[*]}" 0
|
||||||
|
|
||||||
|
pa -o
|
||||||
|
assert_eq "$count" 1
|
||||||
|
pa -oo
|
||||||
|
assert_eq "$count" 2
|
||||||
|
pa -ooo
|
||||||
|
assert_eq "$count" 3
|
||||||
|
|
||||||
|
pa -f
|
||||||
|
assert_eq "$fixed" 42
|
||||||
|
pa -ff
|
||||||
|
assert_eq "$fixed" 42
|
||||||
|
pa -fff
|
||||||
|
assert_eq "$fixed" 42
|
||||||
|
|
||||||
|
assert_same "$efixed" "1"
|
||||||
|
pa -e
|
||||||
|
assert_same "$efixed" ""
|
||||||
|
pa -ee
|
||||||
|
assert_same "$efixed" ""
|
||||||
|
pa -eee
|
||||||
|
assert_same "$efixed" ""
|
||||||
|
|
||||||
|
pa -a ""
|
||||||
|
assert_not_array mopt
|
||||||
|
assert_same "$mopt" ""
|
||||||
|
pa -a abc
|
||||||
|
assert_not_array mopt
|
||||||
|
assert_same "$mopt" abc
|
||||||
|
pa -a abc -a xyz
|
||||||
|
assert_not_array mopt
|
||||||
|
assert_same "$mopt" xyz
|
||||||
|
|
||||||
|
pa -A ""
|
||||||
|
assert_not_array dmopt
|
||||||
|
assert_same "$dmopt" default
|
||||||
|
pa -A abc
|
||||||
|
assert_not_array dmopt
|
||||||
|
assert_same "$dmopt" abc
|
||||||
|
pa -A abc -A xyz
|
||||||
|
assert_not_array dmopt
|
||||||
|
assert_same "$dmopt" xyz
|
||||||
|
|
||||||
|
pa -b
|
||||||
|
assert_not_array oopt
|
||||||
|
assert_same "$oopt" ""
|
||||||
|
pa -babc
|
||||||
|
assert_not_array oopt
|
||||||
|
assert_same "$oopt" abc
|
||||||
|
pa -babc -bxyz
|
||||||
|
assert_not_array oopt
|
||||||
|
assert_same "$oopt" xyz
|
||||||
|
|
||||||
|
pa -B
|
||||||
|
assert_not_array doopt
|
||||||
|
assert_same "$doopt" default
|
||||||
|
pa -Babc
|
||||||
|
assert_not_array doopt
|
||||||
|
assert_same "$doopt" abc
|
||||||
|
pa -Babc -Bxyz
|
||||||
|
assert_not_array doopt
|
||||||
|
assert_same "$doopt" xyz
|
||||||
|
|
||||||
|
pa -n
|
||||||
|
assert_eq "$autoinc" 1
|
||||||
|
pa -nn
|
||||||
|
assert_eq "$autoinc" 2
|
||||||
|
pa -nnn
|
||||||
|
assert_eq "$autoinc" 3
|
||||||
|
|
||||||
|
pa -nN
|
||||||
|
assert_z "$autoinc"
|
||||||
|
pa -nnN
|
||||||
|
assert_eq "$autoinc" 1
|
||||||
|
pa -nnnNN
|
||||||
|
assert_eq "$autoinc" 1
|
||||||
|
|
||||||
|
pa -v ""
|
||||||
|
assert_is_array autoval
|
||||||
|
assert_array_same autoval ""
|
||||||
|
pa -v abc
|
||||||
|
assert_is_array autoval
|
||||||
|
assert_array_same autoval abc
|
||||||
|
pa -v abc -v xyz
|
||||||
|
assert_is_array autoval
|
||||||
|
assert_array_same autoval abc xyz
|
||||||
|
|
||||||
|
pa -xa
|
||||||
|
assert_not_array a1
|
||||||
|
assert_same "$a1" a
|
||||||
|
pa -xa -xb
|
||||||
|
assert_is_array a1
|
||||||
|
assert_array_same a1 a b
|
||||||
|
|
||||||
|
pa -ya
|
||||||
|
assert_is_array a2
|
||||||
|
assert_array_same a2 a
|
||||||
|
pa -ya -yb
|
||||||
|
assert_is_array a2
|
||||||
|
assert_array_same a2 a b
|
||||||
|
|
||||||
|
pa -za
|
||||||
|
assert_is_array a3
|
||||||
|
assert_array_same a3 a
|
||||||
|
pa -za -zb
|
||||||
|
assert_is_array a3
|
||||||
|
assert_array_same a3 a b
|
||||||
|
|
||||||
|
pa -ta
|
||||||
|
assert_is_array a4
|
||||||
|
assert_array_same a4 x a
|
||||||
|
pa -ta -tb
|
||||||
|
assert_is_array a4
|
||||||
|
assert_array_same a4 x a b
|
||||||
|
|
||||||
|
assert_same "$(pa -s)" "sans_arg option=-s, name=sans_arg, value="
|
||||||
|
assert_same "$(pa --sans-arg)" "sans_arg option=--sans-arg, name=sans_arg, value="
|
||||||
|
|
||||||
|
assert_same "$(pa -S)" "avec_arg option=-S, name=avec_arg, value="
|
||||||
|
assert_same "$(pa -Sx)" "avec_arg option=-S, name=avec_arg, value=x"
|
||||||
|
assert_same "$(pa --avec-arg)" "avec_arg option=--avec-arg, name=avec_arg, value="
|
||||||
|
assert_same "$(pa --avec-arg=x)" "avec_arg option=--avec-arg, name=avec_arg, value=x"
|
||||||
|
|
||||||
|
pa x
|
||||||
|
assert_array_same args x
|
||||||
|
|
||||||
|
enote "tests successful"
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../src/nulib.sh" || exit 1
|
||||||
|
#NULIB_NO_DISABLE_SET_X=1
|
||||||
|
|
||||||
|
args=(
|
||||||
|
"tester l'affichage de l'aide"
|
||||||
|
-f:,--input input= "spécifier le fichier en entrée
|
||||||
|
il est possible de spécifier aussi un répertoire auquel cas un fichier par défaut est chargé
|
||||||
|
nb: l'aide pour cette option doit faire 3 lignes indentées"
|
||||||
|
-a,--std . "cette option apparait dans les options standards"
|
||||||
|
-b,--adv . "++cette option apparait dans les options avancées"
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
enote "lancer le script
|
||||||
|
- avec --help pour afficher les options standards uniquement
|
||||||
|
- avec --help++ pour afficher toutes les options"
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../src/nulib.sh" || exit 1
|
||||||
|
#NULIB_NO_DISABLE_SET_X=1
|
||||||
|
|
||||||
|
args=(
|
||||||
|
"tester diverses fonctions de saisie"
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
choices=(first second third)
|
||||||
|
choice=
|
||||||
|
simple_menu -t "choix sans valeur par défaut" -m "le prompt" choice choices
|
||||||
|
enote "vous avez choisi choice=$choice"
|
||||||
|
|
||||||
|
choice=second
|
||||||
|
simple_menu -t "choix avec valeur par défaut" -m "le prompt" choice choices
|
||||||
|
enote "vous avez choisi choice=$choice"
|
|
@ -0,0 +1,169 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../src/nulib.sh" || exit 1
|
||||||
|
#NULIB_NO_DISABLE_SET_X=1
|
||||||
|
|
||||||
|
Multiline=
|
||||||
|
Banner=
|
||||||
|
args=(
|
||||||
|
"afficher divers messages avec les fonctions e*"
|
||||||
|
-D,--debug '$set_debug'
|
||||||
|
-d,--date NULIB_ELOG_DATE=1
|
||||||
|
-m,--myname NULIB_ELOG_MYNAME=1
|
||||||
|
-n,--nc,--no-color '$__set_no_colors 1'
|
||||||
|
--ml Multiline=1
|
||||||
|
-b Banner=1
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
if [ -n "$Multiline" ]; then
|
||||||
|
############################################################################
|
||||||
|
[ -n "$Banner" ] && ebanner $'multi-line\nbanner'
|
||||||
|
|
||||||
|
esection $'multi-line\nsection'
|
||||||
|
etitle $'multi-line\ntitle'
|
||||||
|
etitle $'another\ntitle'
|
||||||
|
edesc $'multi-line\ndesc'
|
||||||
|
|
||||||
|
[ -n "$Banner" ] && ebanner $'multi-line\nbanner'
|
||||||
|
eimportant $'multi-line\nimportant'
|
||||||
|
eattention $'multi-line\nattention'
|
||||||
|
eerror $'multi-line\nerror'
|
||||||
|
ewarn $'multi-line\nwarn'
|
||||||
|
enote $'multi-line\nnote'
|
||||||
|
einfo $'multi-line\ninfo'
|
||||||
|
eecho $'multi-line\necho'
|
||||||
|
edebug $'multi-line\ndebug'
|
||||||
|
|
||||||
|
action $'multi-line\naction'
|
||||||
|
asuccess
|
||||||
|
|
||||||
|
action $'multi-line\naction'
|
||||||
|
estep $'multi-line\nstep'
|
||||||
|
afailure
|
||||||
|
|
||||||
|
action $'multi-line\naction'
|
||||||
|
estep $'multi-line\nstep'
|
||||||
|
asuccess $'multi-line\nsuccess'
|
||||||
|
|
||||||
|
action $'multi-line\naction'
|
||||||
|
estep $'multi-line\nstep'
|
||||||
|
adone $'multi-line\nneutral'
|
||||||
|
|
||||||
|
eend
|
||||||
|
eend
|
||||||
|
|
||||||
|
else
|
||||||
|
############################################################################
|
||||||
|
[ -n "$Banner" ] && ebanner "banner"
|
||||||
|
eimportant "important"
|
||||||
|
eattention "attention"
|
||||||
|
eerror "error"
|
||||||
|
ewarn "warn"
|
||||||
|
enote "note"
|
||||||
|
einfo "info"
|
||||||
|
eecho "echo"
|
||||||
|
edebug "debug"
|
||||||
|
|
||||||
|
estep "step"
|
||||||
|
estepe "stepe"
|
||||||
|
estepw "stepw"
|
||||||
|
estepn "stepn"
|
||||||
|
estepi "stepi"
|
||||||
|
|
||||||
|
esection "section"
|
||||||
|
eecho "content"
|
||||||
|
|
||||||
|
etitle "title0"
|
||||||
|
etitle "title1"
|
||||||
|
eecho "print under title1"
|
||||||
|
eend
|
||||||
|
eecho "print under title0"
|
||||||
|
eend
|
||||||
|
|
||||||
|
edesc "action avec step"
|
||||||
|
action "action avec step"
|
||||||
|
estep "step"
|
||||||
|
asuccess "action success"
|
||||||
|
|
||||||
|
action "action avec step"
|
||||||
|
estep "step"
|
||||||
|
afailure "action failure"
|
||||||
|
|
||||||
|
action "action avec step"
|
||||||
|
estep "step"
|
||||||
|
adone "action neutral"
|
||||||
|
|
||||||
|
edesc "actions sans step"
|
||||||
|
action "action sans step"
|
||||||
|
asuccess "action success"
|
||||||
|
|
||||||
|
action "action sans step"
|
||||||
|
afailure "action failure"
|
||||||
|
|
||||||
|
action "action sans step"
|
||||||
|
adone "action neutral"
|
||||||
|
|
||||||
|
edesc "actions imbriquées"
|
||||||
|
action "action0"
|
||||||
|
action "action1"
|
||||||
|
action "action2"
|
||||||
|
asuccess "action2 success"
|
||||||
|
asuccess "action1 success"
|
||||||
|
asuccess "action0 success"
|
||||||
|
|
||||||
|
edesc "action avec step, sans messages"
|
||||||
|
action "action avec step, sans messages, success"
|
||||||
|
estep "step"
|
||||||
|
asuccess
|
||||||
|
|
||||||
|
action "action avec step, sans messages, failure"
|
||||||
|
estep "step"
|
||||||
|
afailure
|
||||||
|
|
||||||
|
action "action avec step, sans messages, done"
|
||||||
|
estep "step"
|
||||||
|
adone
|
||||||
|
|
||||||
|
edesc "action sans step, sans messages"
|
||||||
|
action "action sans step, sans messages, success"
|
||||||
|
asuccess
|
||||||
|
|
||||||
|
action "action sans step, sans messages, failure"
|
||||||
|
afailure
|
||||||
|
|
||||||
|
action "action sans step, sans messages, done"
|
||||||
|
adone
|
||||||
|
|
||||||
|
edesc "actions imbriquées, sans messages"
|
||||||
|
action "action0"
|
||||||
|
action "action1"
|
||||||
|
action "action2"
|
||||||
|
asuccess
|
||||||
|
asuccess
|
||||||
|
asuccess
|
||||||
|
|
||||||
|
function vtrue() {
|
||||||
|
echo "commande qui se termine avec succès"
|
||||||
|
}
|
||||||
|
function vfalse() {
|
||||||
|
echo "commande qui se termine en échec"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
edesc "action avec commande"
|
||||||
|
action "commande true" vtrue
|
||||||
|
action "commande false" vfalse
|
||||||
|
|
||||||
|
edesc "action avec commande et aresult sans message"
|
||||||
|
action "commande true"
|
||||||
|
vtrue; aresult $?
|
||||||
|
action "commande false"
|
||||||
|
vfalse; aresult $?
|
||||||
|
|
||||||
|
edesc "action avec commande et aresult"
|
||||||
|
action "commande true"
|
||||||
|
vtrue; aresult $? "résultat de la commande"
|
||||||
|
action "commande false"
|
||||||
|
vfalse; aresult $? "résultat de la commande"
|
||||||
|
fi
|
|
@ -0,0 +1,29 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../src/nulib.sh" || exit 1
|
||||||
|
require: template
|
||||||
|
#NULIB_NO_DISABLE_SET_X=1
|
||||||
|
|
||||||
|
args=(
|
||||||
|
"description"
|
||||||
|
#"usage"
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
function template__source_envs() {
|
||||||
|
eval "$("$MYDIR/_template-source_envs")"
|
||||||
|
}
|
||||||
|
|
||||||
|
cd "$MYDIR"
|
||||||
|
#template_generate_scripts \
|
||||||
|
# /tmp/awkscript /tmp/sedscript \
|
||||||
|
# template_values.env
|
||||||
|
#
|
||||||
|
#for i in awk sed; do
|
||||||
|
# etitle "$i" cat "/tmp/${i}script"
|
||||||
|
#done
|
||||||
|
|
||||||
|
template_copy_replace _template-source.txt _template-dest.txt
|
||||||
|
template_process_userfiles _template_values.env
|
||||||
|
|
||||||
|
cat _template-dest.txt
|
|
@ -0,0 +1,28 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../load.sh" || exit 1
|
||||||
|
|
||||||
|
force=
|
||||||
|
args=(
|
||||||
|
"Construire toutes les images supportées de runphp"
|
||||||
|
#"usage"
|
||||||
|
-f,--force force=1 "Créer les images même si elles existent déjà"
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
export RUNPHP_STANDALONE="$NULIBDIR"
|
||||||
|
export RUNPHP_PROJDIR=
|
||||||
|
export RUNPHP_REGISTRY=
|
||||||
|
export RUNPHP_DIST=
|
||||||
|
export RUNPHP_BUILD_FLAVOUR=
|
||||||
|
|
||||||
|
runphp=("$MYDIR/../runphp/runphp" --bs)
|
||||||
|
[ -z "$force" ] && runphp+=(--ue)
|
||||||
|
|
||||||
|
for RUNPHP_DIST in d12 d11; do
|
||||||
|
for RUNPHP_BUILD_FLAVOUR in +ic ""; do
|
||||||
|
etitle "$RUNPHP_DIST$RUNPHP_BUILD_FLAVOUR"
|
||||||
|
"${runphp[@]}"
|
||||||
|
eend
|
||||||
|
done
|
||||||
|
done
|
|
@ -0,0 +1,69 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
NULIB_NO_IMPORT_DEFAULTS=1
|
||||||
|
source "$(dirname -- "$0")/../load.sh" || exit 1
|
||||||
|
|
||||||
|
LIST_FUNCS=
|
||||||
|
SHOW_MODULE=
|
||||||
|
SHOW_FUNCS=()
|
||||||
|
function nulib__define_functions() {
|
||||||
|
function nulib_check_loaded() {
|
||||||
|
local module
|
||||||
|
for module in "${NULIB_LOADED_MODULES[@]}"; do
|
||||||
|
[ "$module" == "$1" ] && return 0
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
function module:() {
|
||||||
|
if [ -n "$LIST_FUNCS" ]; then
|
||||||
|
esection "@$1: $2"
|
||||||
|
fi
|
||||||
|
local module
|
||||||
|
SHOW_MODULE=
|
||||||
|
for module in "${SHOW_FUNCS[@]}"; do
|
||||||
|
if [ "$module" == "@$1" ]; then
|
||||||
|
SHOW_MODULE=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
NULIB_MODULE="$1"
|
||||||
|
if ! nulib_check_loaded "$1"; then
|
||||||
|
NULIB_LOADED_MODULES+=("$1")
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
function function:() {
|
||||||
|
if [ -n "$LIST_FUNCS" ]; then
|
||||||
|
eecho "$1"
|
||||||
|
elif [ -n "$SHOW_MODULE" ]; then
|
||||||
|
eecho "$COULEUR_BLEUE>>> $1 <<<$COULEUR_NORMALE"
|
||||||
|
eecho "$2"
|
||||||
|
else
|
||||||
|
local func
|
||||||
|
for func in "${SHOW_FUNCS[@]}"; do
|
||||||
|
if [ "$func" == "$1" ]; then
|
||||||
|
esection "$1"
|
||||||
|
eecho "$2"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
require: DEFAULTS
|
||||||
|
|
||||||
|
modules=()
|
||||||
|
args=(
|
||||||
|
"afficher l'aide d'une fonction nulib"
|
||||||
|
"FUNCTIONS|@MODULES..."
|
||||||
|
-m:,--module: modules "charger des modules supplémentaires"
|
||||||
|
-l,--list LIST_FUNCS=1 "lister les fonctions pour lesquelles une aide existe"
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
for func in "$@"; do
|
||||||
|
SHOW_FUNCS+=("$func")
|
||||||
|
done
|
||||||
|
|
||||||
|
NULIB_LOADED_MODULES=(nulib)
|
||||||
|
require: DEFAULTS
|
||||||
|
for module in "${modules[@]}"; do
|
||||||
|
require: "$module"
|
||||||
|
done
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../load.sh" || exit 1
|
||||||
|
|
||||||
|
force_reload=
|
||||||
|
args=(
|
||||||
|
"lancer un shell avec les fonctions de nulib préchargées"
|
||||||
|
-r,--force-reload force_reload=1 "forcer le rechargement des modules"
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
ac_set_tmpfile bashrc
|
||||||
|
echo >"$bashrc" "\
|
||||||
|
if ! grep -q '/etc/bash.bashrc' /etc/profile; then
|
||||||
|
[ -f /etc/bash.bashrc ] && source /etc/bash.bashrc
|
||||||
|
fi
|
||||||
|
if ! grep -q '~/.bashrc' ~/.bash_profile; then
|
||||||
|
[ -f ~/.bashrc ] && source ~/.bashrc
|
||||||
|
fi
|
||||||
|
[ -f /etc/profile ] && source /etc/profile
|
||||||
|
[ -f ~/.bash_profile ] && source ~/.bash_profile
|
||||||
|
|
||||||
|
# Modifier le PATH. Ajouter aussi le chemin vers les uapps python
|
||||||
|
PATH=$(qval "$NULIBDIR/bin:$PATH")
|
||||||
|
|
||||||
|
if [ -n '$DEFAULT_PS1' ]; then
|
||||||
|
DEFAULT_PS1=$(qval "[nlshell] $DEFAULT_PS1")
|
||||||
|
else
|
||||||
|
if [ -z '$PS1' ]; then
|
||||||
|
PS1='\\u@\\h \\w \\$ '
|
||||||
|
fi
|
||||||
|
PS1=\"[nlshell] \$PS1\"
|
||||||
|
fi
|
||||||
|
|
||||||
|
$(qvals source "$NULIBDIR/load.sh")
|
||||||
|
NULIB_FORCE_RELOAD=$(qval "$force_reload")"
|
||||||
|
|
||||||
|
"$SHELL" --rcfile "$bashrc" -i -- "$@"
|
|
@ -0,0 +1,61 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../load.sh" || exit 1
|
||||||
|
require: git
|
||||||
|
|
||||||
|
function git_status() {
|
||||||
|
local status r cwd
|
||||||
|
status="$(git status "$@" 2>&1)"; r=$?
|
||||||
|
if [ -n "$status" ]; then
|
||||||
|
setx cwd=ppath2 "$(pwd)" "$OrigCwd"
|
||||||
|
etitle "$cwd"
|
||||||
|
if [ $r -eq 0 ]; then
|
||||||
|
echo "$status"
|
||||||
|
else
|
||||||
|
eerror "$status"
|
||||||
|
fi
|
||||||
|
eend
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
chdir=
|
||||||
|
all=
|
||||||
|
args=(
|
||||||
|
"afficher l'état du dépôt"
|
||||||
|
"[-d chdir] [-a patterns...]
|
||||||
|
|
||||||
|
Si l'option -a est utilisée, ce script accepte comme arguments une liste de patterns permettant de filtrer les répertoires concernés"
|
||||||
|
-d:,--chdir:BASEDIR chdir= "répertoire dans lequel se placer avant de lancer les opérations"
|
||||||
|
-a,--all all=1 "faire l'opération sur tous les sous-répertoires de BASEDIR qui sont des dépôts git"
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
setx OrigCwd=pwd
|
||||||
|
if [ -n "$chdir" ]; then
|
||||||
|
cd "$chdir" || die
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$all" ]; then
|
||||||
|
# liste de sous répertoires
|
||||||
|
if [ $# -gt 0 ]; then
|
||||||
|
# si on a une liste de patterns, l'utiliser
|
||||||
|
setx -a dirs=ls_dirs . "$@"
|
||||||
|
else
|
||||||
|
dirs=()
|
||||||
|
for dir in */.git; do
|
||||||
|
[ -d "$dir" ] || continue
|
||||||
|
dirs+=("${dir%/.git}")
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
setx cwd=pwd
|
||||||
|
for dir in "${dirs[@]}"; do
|
||||||
|
cd "$dir" || die
|
||||||
|
git_status --porcelain
|
||||||
|
cd "$cwd"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
# répertoire courant uniquement
|
||||||
|
args=()
|
||||||
|
isatty || args+=(--porcelain)
|
||||||
|
git_status "${args[@]}"
|
||||||
|
fi
|
89
bin/runphp
89
bin/runphp
|
@ -1,52 +1,51 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
MYDIR="$(dirname -- "$0")"; MYNAME="$(basename -- "$0")"
|
source "$(dirname -- "$0")/../load.sh" || exit 1
|
||||||
function die() { echo 1>&2 "ERROR: $*"; exit 1; }
|
|
||||||
|
|
||||||
case "$MYNAME" in
|
owd="$(pwd)"
|
||||||
runphp) ;;
|
PROJDIR=
|
||||||
composer)
|
while true; do
|
||||||
if [ -f "$MYDIR/composer.phar" ]; then
|
cwd="$(pwd)"
|
||||||
set -- "$MYDIR/composer.phar" "$@"
|
if [ -f .runphp.conf ]; then
|
||||||
elif [ -f "$MYDIR/../sbin/composer.phar" ]; then
|
PROJDIR="$cwd"
|
||||||
set -- "$MYDIR/../sbin/composer.phar" "$@"
|
break
|
||||||
elif [ -f "/usr/bin/composer" ]; then
|
elif [ -f composer.json ]; then
|
||||||
set -- "/usr/bin/composer" "$@"
|
PROJDIR="$cwd"
|
||||||
else
|
break
|
||||||
set -- "" "$@"
|
|
||||||
fi
|
fi
|
||||||
;;
|
if [ "$cwd" == "$HOME" -o "$cwd" == / ]; then
|
||||||
*) die "$MYNAME: nom de script invalide";;
|
cd "$owd"
|
||||||
esac
|
break
|
||||||
|
fi
|
||||||
function runphp_help() {
|
cd ..
|
||||||
echo "$MYNAME: lance un programme PHP en sélectionnant une version en particulier
|
|
||||||
|
|
||||||
USAGE
|
|
||||||
$MYNAME [options] <SCRIPT.php> [args...]
|
|
||||||
|
|
||||||
OPTIONS
|
|
||||||
-s, --min PHP_MIN
|
|
||||||
-m, --max PHP_MAX
|
|
||||||
-i, --image IMAGE"
|
|
||||||
}
|
|
||||||
|
|
||||||
SOPTS=+smi
|
|
||||||
LOPTS=help,php-min,min,php-max,max,image
|
|
||||||
args="$(getopt -n runphp -o "$SOPTS" -l "$LOPTS" -- "$@")" || exit 1; eval "set -- $args"
|
|
||||||
|
|
||||||
while [ $# -gt 0 ]; do
|
|
||||||
case "$1" in
|
|
||||||
--) shift; break;;
|
|
||||||
--help) runphp_help; exit 0;;
|
|
||||||
*) die "$1: option non configurée";;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
done
|
||||||
|
|
||||||
script="$1"; shift
|
if [ -z "$PROJDIR" ]; then
|
||||||
[ -n "$script" ] || die "vous devez spécifier le script à lancer"
|
# s'il n'y a pas de projet, --bs est l'action par défaut
|
||||||
[ -f "$script" ] || die "$script: script introuvable"
|
[ $# -gt 0 ] || set -- --bs
|
||||||
|
elif [ "$MYNAME" == composer ]; then
|
||||||
|
set -- composer "$@"
|
||||||
|
else
|
||||||
|
case "$1" in
|
||||||
|
*.php|*.phar) set -- php "$@";;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
scriptdir="$(dirname -- "$script")"
|
if [ -n "$PROJDIR" ]; then
|
||||||
scritname="$(basename -- "$script")"
|
export RUNPHP_STANDALONE=
|
||||||
|
RUNPHP=; DIST=; REGISTRY=
|
||||||
|
if [ -f "$PROJDIR/.runphp.conf" ]; then
|
||||||
|
source "$PROJDIR/.runphp.conf"
|
||||||
|
[ -n "$RUNPHP" ] && exec "$PROJDIR/$RUNPHP" "$@"
|
||||||
|
elif [ -f "$PROJDIR/sbin/runphp" ]; then
|
||||||
|
exec "$PROJDIR/sbin/runphp" "$@"
|
||||||
|
elif [ -f "$PROJDIR/runphp" ]; then
|
||||||
|
exec "$PROJDIR/runphp" "$@"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
export RUNPHP_STANDALONE="$NULIBDIR"
|
||||||
|
export RUNPHP_PROJDIR="$PROJDIR"
|
||||||
|
export RUNPHP_REGISTRY="$REGISTRY"
|
||||||
|
export RUNPHP_DIST="$DIST"
|
||||||
|
exec "$MYDIR/../runphp/runphp" "$@"
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../load.sh" || exit 1
|
||||||
|
require: fndate
|
||||||
|
|
||||||
|
: ${EDITOR:=vim}
|
||||||
|
|
||||||
|
autoext=1
|
||||||
|
args=(
|
||||||
|
"créer un nouveau fichier .markdown"
|
||||||
|
"<files...>"
|
||||||
|
-j,--no-autoext autoext= "ne pas rajouter l'extension .yaml ni .yml"
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
[ $# -gt 0 ] || die "vous devez spécifier les noms des fichiers à créer"
|
||||||
|
|
||||||
|
for file in "$@"; do
|
||||||
|
setx file=fndate_verifix "$file" .md
|
||||||
|
setx filename=basename -- "$file"
|
||||||
|
if [[ "$filename" == *.* ]]; then
|
||||||
|
: # y'a déjà une extension, ne rien faire
|
||||||
|
elif [ -z "$autoext" ]; then
|
||||||
|
: # ne pas rajouter d'extension
|
||||||
|
elif [ -f "$file.markdown" ]; then
|
||||||
|
file="$file.markdown"
|
||||||
|
else
|
||||||
|
file="$file.md"
|
||||||
|
fi
|
||||||
|
[ -e "$file" ] && die "$file: fichier existant"
|
||||||
|
estep "Création de $file"
|
||||||
|
|
||||||
|
echo -n >"$file" "\
|
||||||
|
|
||||||
|
|
||||||
|
-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary"
|
||||||
|
"$EDITOR" "$file"
|
||||||
|
done
|
|
@ -0,0 +1,56 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../load.sh" || exit 1
|
||||||
|
require: fndate
|
||||||
|
|
||||||
|
: ${EDITOR:=vim}
|
||||||
|
|
||||||
|
executable=1
|
||||||
|
autoext=1
|
||||||
|
args=(
|
||||||
|
"créer un nouveau fichier .sh"
|
||||||
|
"<files...>"
|
||||||
|
-x,--exec executable=1 "créer un script exécutable"
|
||||||
|
-n,--no-exec executable= "créer un fichier non exécutable"
|
||||||
|
-j,--no-autoext autoext= "ne pas rajouter l'extension .sh"
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
[ $# -gt 0 ] || die "vous devez spécifier les noms des fichiers à créer"
|
||||||
|
|
||||||
|
for file in "$@"; do
|
||||||
|
setx file=fndate_verifix "$file" .sh
|
||||||
|
setx filename=basename -- "$file"
|
||||||
|
if [[ "$filename" == *.* ]]; then
|
||||||
|
: # y'a déjà une extension, ne rien faire
|
||||||
|
elif [ -z "$autoext" ]; then
|
||||||
|
: # ne pas rajouter d'extension
|
||||||
|
else
|
||||||
|
file="$file.sh"
|
||||||
|
fi
|
||||||
|
[ -e "$file" ] && die "$file: fichier existant"
|
||||||
|
estep "Création de $file"
|
||||||
|
|
||||||
|
if [ -n "$executable" ]; then
|
||||||
|
cat >"$file" <<EOF
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source /etc/nulib.sh || exit 1
|
||||||
|
|
||||||
|
args=(
|
||||||
|
"description"
|
||||||
|
#"usage"
|
||||||
|
)
|
||||||
|
parse_args "\$@"; set -- "\${args[@]}"
|
||||||
|
|
||||||
|
EOF
|
||||||
|
chmod +x "$file"
|
||||||
|
"$EDITOR" +6 "$file"
|
||||||
|
else
|
||||||
|
cat >"$file" <<EOF
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
|
||||||
|
EOF
|
||||||
|
"$EDITOR" +2 "$file"
|
||||||
|
fi
|
||||||
|
done
|
|
@ -0,0 +1,40 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../load.sh" || exit 1
|
||||||
|
require: fndate
|
||||||
|
|
||||||
|
: ${EDITOR:=vim}
|
||||||
|
|
||||||
|
autoext=1
|
||||||
|
args=(
|
||||||
|
"créer un nouveau fichier .sql"
|
||||||
|
"<files...>"
|
||||||
|
-j,--no-autoext autoext= "ne pas rajouter l'extension .sql"
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
[ $# -gt 0 ] || die "vous devez spécifier les noms des fichiers à créer"
|
||||||
|
|
||||||
|
for file in "$@"; do
|
||||||
|
setx file=fndate_verifix "$file" .sql
|
||||||
|
setx filename=basename -- "$file"
|
||||||
|
if [[ "$filename" == *.* ]]; then
|
||||||
|
: # y'a déjà une extension, ne rien faire
|
||||||
|
elif [ -z "$autoext" ]; then
|
||||||
|
: # ne pas rajouter d'extension
|
||||||
|
else
|
||||||
|
file="$file.sql"
|
||||||
|
fi
|
||||||
|
[ -e "$file" ] && die "$file: fichier existant"
|
||||||
|
estep "Création de $file"
|
||||||
|
|
||||||
|
cat >"$file" <<EOF
|
||||||
|
-- -*- coding: utf-8 mode: sql -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=$encoding
|
||||||
|
-- @database xxx
|
||||||
|
|
||||||
|
start transaction;
|
||||||
|
|
||||||
|
commit;
|
||||||
|
EOF
|
||||||
|
"$EDITOR" +2 "$file"
|
||||||
|
done
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../load.sh" || exit 1
|
||||||
|
require: fndate
|
||||||
|
|
||||||
|
: ${EDITOR:=vim}
|
||||||
|
|
||||||
|
autoext=1
|
||||||
|
args=(
|
||||||
|
"créer un nouveau fichier .yaml"
|
||||||
|
"<files...>"
|
||||||
|
-j,--no-autoext autoext= "ne pas rajouter l'extension .yaml ni .yml"
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
[ $# -gt 0 ] || die "vous devez spécifier les noms des fichiers à créer"
|
||||||
|
|
||||||
|
for file in "$@"; do
|
||||||
|
setx file=fndate_verifix "$file" .yml
|
||||||
|
setx filename=basename -- "$file"
|
||||||
|
if [[ "$filename" == *.* ]]; then
|
||||||
|
: # y'a déjà une extension, ne rien faire
|
||||||
|
elif [ -z "$autoext" ]; then
|
||||||
|
: # ne pas rajouter d'extension
|
||||||
|
elif [ -f "$file.yaml" ]; then
|
||||||
|
file="$file.yaml"
|
||||||
|
else
|
||||||
|
file="$file.yml"
|
||||||
|
fi
|
||||||
|
[ -e "$file" ] && die "$file: fichier existant"
|
||||||
|
estep "Création de $file"
|
||||||
|
|
||||||
|
echo >"$file" "\
|
||||||
|
# -*- coding: utf-8 mode: yaml -*- vim:sw=2:sts=2:et:ai:si:sta:fenc=utf-8
|
||||||
|
|
||||||
|
"
|
||||||
|
"$EDITOR" +3 "$file"
|
||||||
|
done
|
|
@ -0,0 +1,25 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../load.sh" || exit 1
|
||||||
|
require: donk.help
|
||||||
|
|
||||||
|
# par défaut, c'est l'action build
|
||||||
|
case "$1" in
|
||||||
|
-h*|--help|--help=*|--help++) ;;
|
||||||
|
-*) set -- build "$@";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
args=(
|
||||||
|
"construire des images docker"
|
||||||
|
"ACTION [options]
|
||||||
|
$(_donk_show_actions)"
|
||||||
|
+
|
||||||
|
-h::section,--help '$_donk_show_help' "Afficher l'aide de la section spécifiée.
|
||||||
|
Les sections valides sont: ${DONK_HELP_SECTIONS[*]%%:*}"
|
||||||
|
--help++ '$_donk_show_help' "++Afficher l'aide"
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
action="$1"; shift
|
||||||
|
require: "donk.$action" || die
|
||||||
|
"donk_$action" "$@"
|
|
@ -0,0 +1,30 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../load.sh" || exit 1
|
||||||
|
require: git
|
||||||
|
|
||||||
|
projdir=
|
||||||
|
remote=
|
||||||
|
what=auto
|
||||||
|
push=auto
|
||||||
|
clobber=ask
|
||||||
|
args=(
|
||||||
|
"\
|
||||||
|
valider les modifications locales
|
||||||
|
|
||||||
|
si la branche courante est une branche wip, écraser les modifications distantes éventuelles après un avertissement.
|
||||||
|
sinon, ne mettre à jour la branche locale qu'en mode fast-forward"
|
||||||
|
"MESSAGE [FILES...]"
|
||||||
|
-d:,--projdir projdir= "spécifier le projet dans lequel faire la mise à jour"
|
||||||
|
-o:,--remote remote= "spécifier le remote depuis lequel faire le fetch et vers lequel pousser les modifications"
|
||||||
|
--auto what=auto "calculer les modifications à valider: soit les fichiers mentionnés, soit ceux de l'index, soit les fichiers modifiés. c'est l'option par défaut"
|
||||||
|
-a,--all what=all "valider les modifications sur les fichiers modifiés uniquement"
|
||||||
|
-A,--all-new what=new "valider les modifications sur les fichiers modifiés et rajouter aussi les nouveaux fichiers"
|
||||||
|
--current push=auto "pousser les modifications sur la branche courante après validation. c'est l'option par défaut"
|
||||||
|
-p,--push push=1 "pousser les modifications de toutes les branches après la validation"
|
||||||
|
-l,--no-push push= "ne pas pousser les modifications après la validation"
|
||||||
|
--clobber clobber=1 "écraser les modifications distantes si la branche courante est une branche wip"
|
||||||
|
-n,--no-clobber clobber= "ne jamais écraser les modifications distantes, même si la branche courante est une branche wip"
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../load.sh" || exit 1
|
||||||
|
require: git
|
||||||
|
|
||||||
|
projdir=
|
||||||
|
remote=
|
||||||
|
clobber=ask
|
||||||
|
args=(
|
||||||
|
"\
|
||||||
|
pousser les modifications locales
|
||||||
|
|
||||||
|
si la branche courante est une branche wip, écraser les modifications distantes éventuelles après un avertissement.
|
||||||
|
sinon, ne mettre à jour la branche locale qu'en mode fast-forward"
|
||||||
|
"MESSAGE [FILES...]"
|
||||||
|
-d:,--projdir projdir= "spécifier le projet dans lequel faire la mise à jour"
|
||||||
|
-o:,--remote remote= "spécifier le remote depuis lequel faire le fetch et vers lequel pousser les modifications"
|
||||||
|
--clobber clobber=1 "écraser les modifications distantes si la branche courante est une branche wip"
|
||||||
|
-n,--no-clobber clobber= "ne jamais écraser les modifications distantes, même si la branche courante est une branche wip"
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../load.sh" || exit 1
|
||||||
|
require: git
|
||||||
|
|
||||||
|
function _git_update() {
|
||||||
|
local branch
|
||||||
|
local -a prbranches crbranches dbranches
|
||||||
|
|
||||||
|
setx -a prbranches=git_list_rbranches
|
||||||
|
git fetch -p "$@" || return
|
||||||
|
setx -a crbranches=git_list_rbranches
|
||||||
|
|
||||||
|
# vérifier s'il y a des branches distantes qui ont été supprimées
|
||||||
|
for branch in "${prbranches[@]}"; do
|
||||||
|
if ! array_contains crbranches "$branch"; then
|
||||||
|
array_add dbranches "${branch#*/}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ ${#dbranches[*]} -gt 0 ]; then
|
||||||
|
setx -a branches=git_list_branches
|
||||||
|
setx branch=git_get_branch
|
||||||
|
|
||||||
|
eimportant "One or more distant branches where deleted"
|
||||||
|
if git_check_cleancheckout; then
|
||||||
|
einfo "Delete the obsolete local branches with these commands:"
|
||||||
|
else
|
||||||
|
ewarn "Take care of uncommitted local changes first"
|
||||||
|
einfo "Then delete the obsolete local branches with these commands:"
|
||||||
|
fi
|
||||||
|
if array_contains dbranches "$branch"; then
|
||||||
|
# si la branche courante est l'une des branches à supprimer, il faut
|
||||||
|
# basculer vers develop ou master
|
||||||
|
local swto
|
||||||
|
if [ -z "$swto" ] && array_contains branches develop && ! array_contains dbranches develop; then
|
||||||
|
swto=develop
|
||||||
|
fi
|
||||||
|
if [ -z "$swto" ] && array_contains branches master && ! array_contains dbranches master; then
|
||||||
|
swto=master
|
||||||
|
fi
|
||||||
|
[ -n "$swto" ] && qvals git checkout "$swto"
|
||||||
|
fi
|
||||||
|
qvals git branch -D "${dbranches[@]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# intégrer les modifications des branches locales
|
||||||
|
if ! git_check_cleancheckout; then
|
||||||
|
setx branch=git_get_branch
|
||||||
|
setx remote=git_get_branch_remote "$branch"
|
||||||
|
setx rbranch=git_get_branch_rbranch "$branch" "$remote"
|
||||||
|
pbranch="${rbranch#refs/remotes/}"
|
||||||
|
if git merge -q --ff-only "$rbranch"; then
|
||||||
|
enote "There are uncommitted local changes: only CURRENT branch were updated"
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
setx -a branches=git_list_branches
|
||||||
|
restore_branch=
|
||||||
|
for branch in "${branches[@]}"; do
|
||||||
|
setx remote=git_get_branch_remote "$branch"
|
||||||
|
setx rbranch=git_get_branch_rbranch "$branch" "$remote"
|
||||||
|
pbranch="${rbranch#refs/remotes/}"
|
||||||
|
[ -n "$remote" -a -n "$rbranch" ] || continue
|
||||||
|
if git_is_ancestor "$branch" "$rbranch"; then
|
||||||
|
if git_should_ff "$branch" "$rbranch"; then
|
||||||
|
einfo "Fast-forwarding $branch -> $pbranch"
|
||||||
|
git checkout -q "$branch"
|
||||||
|
git merge -q --ff-only "$rbranch"
|
||||||
|
restore_branch=1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "$branch" == "$orig_branch" ]; then
|
||||||
|
echo "* Cannot fast-forward CURRENT branch $branch from $pbranch
|
||||||
|
Try to merge manually with: git merge $pbranch"
|
||||||
|
else
|
||||||
|
echo "* Cannot fast-forward local branch $branch from $pbranch
|
||||||
|
You can merge manually with: git checkout $branch; git merge $pbranch"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
[ -n "$restore_branch" ] && git checkout -q "$orig_branch"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function git_update() {
|
||||||
|
local cwd r
|
||||||
|
setx cwd=ppath2 "$(pwd)" "$OrigCwd"
|
||||||
|
etitle "$cwd"
|
||||||
|
_git_update "$@"; r=$?
|
||||||
|
eend
|
||||||
|
return $r
|
||||||
|
}
|
||||||
|
|
||||||
|
chdir=
|
||||||
|
all=
|
||||||
|
Remote=
|
||||||
|
Autoff=1
|
||||||
|
Reset=ask
|
||||||
|
args=(
|
||||||
|
"\
|
||||||
|
mettre à jour les branches locales
|
||||||
|
|
||||||
|
si la branche courante est une branche wip, écraser les modifications locales éventuelles après un avertissement.
|
||||||
|
sinon, ne mettre à jour la branche locale qu'en mode fast-forward"
|
||||||
|
#"usage"
|
||||||
|
-d:,--chdir:BASEDIR chdir= "répertoire dans lequel se placer avant de lancer les opérations"
|
||||||
|
-a,--all all=1 "faire l'opération sur tous les sous-répertoires de BASEDIR qui sont des dépôts git"
|
||||||
|
-o:,--remote Remote= "spécifier le remote depuis lequel faire le fetch"
|
||||||
|
--autoff Autoff=1 "s'il n'y a pas de modifications locales, faire un fast-forward de toutes les branches traquées. c'est l'option par défaut."
|
||||||
|
-l,--no-autoff Autoff= "ne pas faire de fast-forward automatique des branches traquées. seule la branche courante est mise à jour"
|
||||||
|
--reset Reset=1 "écraser les modifications locales si la branche courante est une branche wip"
|
||||||
|
-n,--no-reset Reset= "ne jamais écraser les modifications locales, même si la branche courante est une branche wip"
|
||||||
|
)
|
||||||
|
parse_args "$@"; set -- "${args[@]}"
|
||||||
|
|
||||||
|
|
||||||
|
setx OrigCwd=pwd
|
||||||
|
if [ -n "$chdir" ]; then
|
||||||
|
cd "$chdir" || die
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$all" ]; then
|
||||||
|
# liste de sous répertoires
|
||||||
|
if [ $# -gt 0 ]; then
|
||||||
|
# si on a une liste de patterns, l'utiliser
|
||||||
|
setx -a dirs=ls_dirs . "$@"
|
||||||
|
else
|
||||||
|
dirs=()
|
||||||
|
for dir in */.git; do
|
||||||
|
[ -d "$dir" ] || continue
|
||||||
|
dirs+=("${dir%/.git}")
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
setx cwd=pwd
|
||||||
|
for dir in "${dirs[@]}"; do
|
||||||
|
cd "$dir" || die
|
||||||
|
git_update || die
|
||||||
|
cd "$cwd"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
# répertoire courant uniquement
|
||||||
|
args=()
|
||||||
|
isatty || args+=(--porcelain)
|
||||||
|
git_update "${args[@]}"
|
||||||
|
fi
|
|
@ -9,14 +9,17 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.3"
|
"php": "^7.4"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"nulib/tests": "7.3"
|
"nulib/tests": "7.4",
|
||||||
|
"ext-posix": "*",
|
||||||
|
"ext-pcntl": "*",
|
||||||
|
"ext-curl": "*"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"nulib\\": "php/src_base"
|
"nulib\\": "php/src"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload-dev": {
|
"autoload-dev": {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "a83db90dff9c8a1e44abc608738042c3",
|
"content-hash": "356c1dcfe9eee39e9e6eadff4f63cdfe",
|
||||||
"packages": [],
|
"packages": [],
|
||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
{
|
{
|
||||||
|
@ -79,16 +79,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "myclabs/deep-copy",
|
"name": "myclabs/deep-copy",
|
||||||
"version": "1.11.1",
|
"version": "1.12.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||||
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
|
"reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
|
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
|
||||||
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
|
"reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -96,11 +96,12 @@
|
||||||
},
|
},
|
||||||
"conflict": {
|
"conflict": {
|
||||||
"doctrine/collections": "<1.6.8",
|
"doctrine/collections": "<1.6.8",
|
||||||
"doctrine/common": "<2.13.3 || >=3,<3.2.2"
|
"doctrine/common": "<2.13.3 || >=3 <3.2.2"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"doctrine/collections": "^1.6.8",
|
"doctrine/collections": "^1.6.8",
|
||||||
"doctrine/common": "^2.13.3 || ^3.2.2",
|
"doctrine/common": "^2.13.3 || ^3.2.2",
|
||||||
|
"phpspec/prophecy": "^1.10",
|
||||||
"phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
|
"phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
|
@ -126,7 +127,7 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
|
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -134,29 +135,31 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-03-08T13:26:56+00:00"
|
"time": "2024-06-12T14:39:25+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "nikic/php-parser",
|
"name": "nikic/php-parser",
|
||||||
"version": "v4.17.1",
|
"version": "v5.3.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||||
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d"
|
"reference": "8eea230464783aa9671db8eea6f8c6ac5285794b"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
|
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b",
|
||||||
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
|
"reference": "8eea230464783aa9671db8eea6f8c6ac5285794b",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
"ext-ctype": "*",
|
||||||
|
"ext-json": "*",
|
||||||
"ext-tokenizer": "*",
|
"ext-tokenizer": "*",
|
||||||
"php": ">=7.0"
|
"php": ">=7.4"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"ircmaxell/php-yacc": "^0.0.7",
|
"ircmaxell/php-yacc": "^0.0.7",
|
||||||
"phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
|
"phpunit/phpunit": "^9.0"
|
||||||
},
|
},
|
||||||
"bin": [
|
"bin": [
|
||||||
"bin/php-parse"
|
"bin/php-parse"
|
||||||
|
@ -164,7 +167,7 @@
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "4.9-dev"
|
"dev-master": "5.0-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
@ -188,17 +191,17 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1"
|
"source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1"
|
||||||
},
|
},
|
||||||
"time": "2023-08-13T19:53:39+00:00"
|
"time": "2024-10-08T18:51:32+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "nulib/tests",
|
"name": "nulib/tests",
|
||||||
"version": "7.3",
|
"version": "7.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.univ-reunion.fr/sda-php/nulib-tests.git",
|
"url": "https://git.univ-reunion.fr/sda-php/nulib-tests.git",
|
||||||
"reference": "8902035bef6ddfe9864675a00844dd14872f6d13"
|
"reference": "6ce8257560b42e8fb3eea03eba84d3877c9648ca"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.3",
|
"php": ">=7.3",
|
||||||
|
@ -207,12 +210,12 @@
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"mur\\tests\\": "src"
|
"nulib\\tests\\": "src"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload-dev": {
|
"autoload-dev": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"mur\\tests\\": "tests"
|
"nulib\\tests\\": "tests"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"authors": [
|
"authors": [
|
||||||
|
@ -222,24 +225,25 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "fonctions et classes pour les tests",
|
"description": "fonctions et classes pour les tests",
|
||||||
"time": "2023-10-01T11:57:55+00:00"
|
"time": "2024-03-26T10:56:17+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phar-io/manifest",
|
"name": "phar-io/manifest",
|
||||||
"version": "2.0.3",
|
"version": "2.0.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phar-io/manifest.git",
|
"url": "https://github.com/phar-io/manifest.git",
|
||||||
"reference": "97803eca37d319dfa7826cc2437fc020857acb53"
|
"reference": "54750ef60c58e43759730615a392c31c80e23176"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53",
|
"url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
|
||||||
"reference": "97803eca37d319dfa7826cc2437fc020857acb53",
|
"reference": "54750ef60c58e43759730615a392c31c80e23176",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
|
"ext-libxml": "*",
|
||||||
"ext-phar": "*",
|
"ext-phar": "*",
|
||||||
"ext-xmlwriter": "*",
|
"ext-xmlwriter": "*",
|
||||||
"phar-io/version": "^3.0.1",
|
"phar-io/version": "^3.0.1",
|
||||||
|
@ -280,9 +284,15 @@
|
||||||
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
|
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/phar-io/manifest/issues",
|
"issues": "https://github.com/phar-io/manifest/issues",
|
||||||
"source": "https://github.com/phar-io/manifest/tree/2.0.3"
|
"source": "https://github.com/phar-io/manifest/tree/2.0.4"
|
||||||
},
|
},
|
||||||
"time": "2021-07-20T11:28:43+00:00"
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/theseer",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-03-03T12:33:53+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phar-io/version",
|
"name": "phar-io/version",
|
||||||
|
@ -337,35 +347,35 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-code-coverage",
|
"name": "phpunit/php-code-coverage",
|
||||||
"version": "9.2.29",
|
"version": "9.2.32",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||||
"reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76"
|
"reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5",
|
||||||
"reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76",
|
"reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
"ext-libxml": "*",
|
"ext-libxml": "*",
|
||||||
"ext-xmlwriter": "*",
|
"ext-xmlwriter": "*",
|
||||||
"nikic/php-parser": "^4.15",
|
"nikic/php-parser": "^4.19.1 || ^5.1.0",
|
||||||
"php": ">=7.3",
|
"php": ">=7.3",
|
||||||
"phpunit/php-file-iterator": "^3.0.3",
|
"phpunit/php-file-iterator": "^3.0.6",
|
||||||
"phpunit/php-text-template": "^2.0.2",
|
"phpunit/php-text-template": "^2.0.4",
|
||||||
"sebastian/code-unit-reverse-lookup": "^2.0.2",
|
"sebastian/code-unit-reverse-lookup": "^2.0.3",
|
||||||
"sebastian/complexity": "^2.0",
|
"sebastian/complexity": "^2.0.3",
|
||||||
"sebastian/environment": "^5.1.2",
|
"sebastian/environment": "^5.1.5",
|
||||||
"sebastian/lines-of-code": "^1.0.3",
|
"sebastian/lines-of-code": "^1.0.4",
|
||||||
"sebastian/version": "^3.0.1",
|
"sebastian/version": "^3.0.2",
|
||||||
"theseer/tokenizer": "^1.2.0"
|
"theseer/tokenizer": "^1.2.3"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^9.3"
|
"phpunit/phpunit": "^9.6"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-pcov": "PHP extension that provides line coverage",
|
"ext-pcov": "PHP extension that provides line coverage",
|
||||||
|
@ -374,7 +384,7 @@
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "9.2-dev"
|
"dev-main": "9.2.x-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
@ -403,7 +413,7 @@
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29"
|
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -411,7 +421,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-09-19T04:57:46+00:00"
|
"time": "2024-08-22T04:23:01+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-file-iterator",
|
"name": "phpunit/php-file-iterator",
|
||||||
|
@ -656,45 +666,45 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/phpunit",
|
"name": "phpunit/phpunit",
|
||||||
"version": "9.6.13",
|
"version": "9.6.21",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||||
"reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be"
|
"reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be",
|
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa",
|
||||||
"reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be",
|
"reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"doctrine/instantiator": "^1.3.1 || ^2",
|
"doctrine/instantiator": "^1.5.0 || ^2",
|
||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-libxml": "*",
|
"ext-libxml": "*",
|
||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
"ext-xml": "*",
|
"ext-xml": "*",
|
||||||
"ext-xmlwriter": "*",
|
"ext-xmlwriter": "*",
|
||||||
"myclabs/deep-copy": "^1.10.1",
|
"myclabs/deep-copy": "^1.12.0",
|
||||||
"phar-io/manifest": "^2.0.3",
|
"phar-io/manifest": "^2.0.4",
|
||||||
"phar-io/version": "^3.0.2",
|
"phar-io/version": "^3.2.1",
|
||||||
"php": ">=7.3",
|
"php": ">=7.3",
|
||||||
"phpunit/php-code-coverage": "^9.2.28",
|
"phpunit/php-code-coverage": "^9.2.32",
|
||||||
"phpunit/php-file-iterator": "^3.0.5",
|
"phpunit/php-file-iterator": "^3.0.6",
|
||||||
"phpunit/php-invoker": "^3.1.1",
|
"phpunit/php-invoker": "^3.1.1",
|
||||||
"phpunit/php-text-template": "^2.0.3",
|
"phpunit/php-text-template": "^2.0.4",
|
||||||
"phpunit/php-timer": "^5.0.2",
|
"phpunit/php-timer": "^5.0.3",
|
||||||
"sebastian/cli-parser": "^1.0.1",
|
"sebastian/cli-parser": "^1.0.2",
|
||||||
"sebastian/code-unit": "^1.0.6",
|
"sebastian/code-unit": "^1.0.8",
|
||||||
"sebastian/comparator": "^4.0.8",
|
"sebastian/comparator": "^4.0.8",
|
||||||
"sebastian/diff": "^4.0.3",
|
"sebastian/diff": "^4.0.6",
|
||||||
"sebastian/environment": "^5.1.3",
|
"sebastian/environment": "^5.1.5",
|
||||||
"sebastian/exporter": "^4.0.5",
|
"sebastian/exporter": "^4.0.6",
|
||||||
"sebastian/global-state": "^5.0.1",
|
"sebastian/global-state": "^5.0.7",
|
||||||
"sebastian/object-enumerator": "^4.0.3",
|
"sebastian/object-enumerator": "^4.0.4",
|
||||||
"sebastian/resource-operations": "^3.0.3",
|
"sebastian/resource-operations": "^3.0.4",
|
||||||
"sebastian/type": "^3.2",
|
"sebastian/type": "^3.2.1",
|
||||||
"sebastian/version": "^3.0.2"
|
"sebastian/version": "^3.0.2"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
|
@ -739,7 +749,7 @@
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13"
|
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.21"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -755,20 +765,20 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-09-19T05:39:22+00:00"
|
"time": "2024-09-19T10:50:18+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/cli-parser",
|
"name": "sebastian/cli-parser",
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/cli-parser.git",
|
"url": "https://github.com/sebastianbergmann/cli-parser.git",
|
||||||
"reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2"
|
"reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2",
|
"url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
|
||||||
"reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2",
|
"reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -803,7 +813,7 @@
|
||||||
"homepage": "https://github.com/sebastianbergmann/cli-parser",
|
"homepage": "https://github.com/sebastianbergmann/cli-parser",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/cli-parser/issues",
|
"issues": "https://github.com/sebastianbergmann/cli-parser/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1"
|
"source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -811,7 +821,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2020-09-28T06:08:49+00:00"
|
"time": "2024-03-02T06:27:43+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/code-unit",
|
"name": "sebastian/code-unit",
|
||||||
|
@ -1000,20 +1010,20 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/complexity",
|
"name": "sebastian/complexity",
|
||||||
"version": "2.0.2",
|
"version": "2.0.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/complexity.git",
|
"url": "https://github.com/sebastianbergmann/complexity.git",
|
||||||
"reference": "739b35e53379900cc9ac327b2147867b8b6efd88"
|
"reference": "25f207c40d62b8b7aa32f5ab026c53561964053a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88",
|
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a",
|
||||||
"reference": "739b35e53379900cc9ac327b2147867b8b6efd88",
|
"reference": "25f207c40d62b8b7aa32f5ab026c53561964053a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"nikic/php-parser": "^4.7",
|
"nikic/php-parser": "^4.18 || ^5.0",
|
||||||
"php": ">=7.3"
|
"php": ">=7.3"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
@ -1045,7 +1055,7 @@
|
||||||
"homepage": "https://github.com/sebastianbergmann/complexity",
|
"homepage": "https://github.com/sebastianbergmann/complexity",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/complexity/issues",
|
"issues": "https://github.com/sebastianbergmann/complexity/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2"
|
"source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -1053,20 +1063,20 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2020-10-26T15:52:27+00:00"
|
"time": "2023-12-22T06:19:30+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/diff",
|
"name": "sebastian/diff",
|
||||||
"version": "4.0.5",
|
"version": "4.0.6",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/diff.git",
|
"url": "https://github.com/sebastianbergmann/diff.git",
|
||||||
"reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131"
|
"reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
|
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc",
|
||||||
"reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
|
"reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -1111,7 +1121,7 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/diff/issues",
|
"issues": "https://github.com/sebastianbergmann/diff/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/diff/tree/4.0.5"
|
"source": "https://github.com/sebastianbergmann/diff/tree/4.0.6"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -1119,7 +1129,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-05-07T05:35:17+00:00"
|
"time": "2024-03-02T06:30:58+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/environment",
|
"name": "sebastian/environment",
|
||||||
|
@ -1186,16 +1196,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/exporter",
|
"name": "sebastian/exporter",
|
||||||
"version": "4.0.5",
|
"version": "4.0.6",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/exporter.git",
|
"url": "https://github.com/sebastianbergmann/exporter.git",
|
||||||
"reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d"
|
"reference": "78c00df8f170e02473b682df15bfcdacc3d32d72"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
|
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72",
|
||||||
"reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
|
"reference": "78c00df8f170e02473b682df15bfcdacc3d32d72",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -1251,7 +1261,7 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/exporter/issues",
|
"issues": "https://github.com/sebastianbergmann/exporter/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5"
|
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -1259,20 +1269,20 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2022-09-14T06:03:37+00:00"
|
"time": "2024-03-02T06:33:00+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/global-state",
|
"name": "sebastian/global-state",
|
||||||
"version": "5.0.6",
|
"version": "5.0.7",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/global-state.git",
|
"url": "https://github.com/sebastianbergmann/global-state.git",
|
||||||
"reference": "bde739e7565280bda77be70044ac1047bc007e34"
|
"reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34",
|
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
|
||||||
"reference": "bde739e7565280bda77be70044ac1047bc007e34",
|
"reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -1315,7 +1325,7 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/global-state/issues",
|
"issues": "https://github.com/sebastianbergmann/global-state/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6"
|
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -1323,24 +1333,24 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-08-02T09:26:13+00:00"
|
"time": "2024-03-02T06:35:11+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/lines-of-code",
|
"name": "sebastian/lines-of-code",
|
||||||
"version": "1.0.3",
|
"version": "1.0.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/lines-of-code.git",
|
"url": "https://github.com/sebastianbergmann/lines-of-code.git",
|
||||||
"reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc"
|
"reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc",
|
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5",
|
||||||
"reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc",
|
"reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"nikic/php-parser": "^4.6",
|
"nikic/php-parser": "^4.18 || ^5.0",
|
||||||
"php": ">=7.3"
|
"php": ">=7.3"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
@ -1372,7 +1382,7 @@
|
||||||
"homepage": "https://github.com/sebastianbergmann/lines-of-code",
|
"homepage": "https://github.com/sebastianbergmann/lines-of-code",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
|
"issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3"
|
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -1380,7 +1390,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2020-11-28T06:42:11+00:00"
|
"time": "2023-12-22T06:20:34+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/object-enumerator",
|
"name": "sebastian/object-enumerator",
|
||||||
|
@ -1559,16 +1569,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/resource-operations",
|
"name": "sebastian/resource-operations",
|
||||||
"version": "3.0.3",
|
"version": "3.0.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/resource-operations.git",
|
"url": "https://github.com/sebastianbergmann/resource-operations.git",
|
||||||
"reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8"
|
"reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
|
"url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
|
||||||
"reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
|
"reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -1580,7 +1590,7 @@
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "3.0-dev"
|
"dev-main": "3.0-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
@ -1601,8 +1611,7 @@
|
||||||
"description": "Provides a list of PHP built-in functions that operate on resources",
|
"description": "Provides a list of PHP built-in functions that operate on resources",
|
||||||
"homepage": "https://www.github.com/sebastianbergmann/resource-operations",
|
"homepage": "https://www.github.com/sebastianbergmann/resource-operations",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/resource-operations/issues",
|
"source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4"
|
||||||
"source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3"
|
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -1610,7 +1619,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2020-09-28T06:45:17+00:00"
|
"time": "2024-03-14T16:00:52+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/type",
|
"name": "sebastian/type",
|
||||||
|
@ -1723,16 +1732,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "theseer/tokenizer",
|
"name": "theseer/tokenizer",
|
||||||
"version": "1.2.1",
|
"version": "1.2.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/theseer/tokenizer.git",
|
"url": "https://github.com/theseer/tokenizer.git",
|
||||||
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e"
|
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e",
|
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
|
||||||
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e",
|
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -1761,7 +1770,7 @@
|
||||||
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/theseer/tokenizer/issues",
|
"issues": "https://github.com/theseer/tokenizer/issues",
|
||||||
"source": "https://github.com/theseer/tokenizer/tree/1.2.1"
|
"source": "https://github.com/theseer/tokenizer/tree/1.2.3"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -1769,7 +1778,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-07-28T10:34:58+00:00"
|
"time": "2024-03-03T12:36:25+00:00"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
|
@ -1778,8 +1787,12 @@
|
||||||
"prefer-stable": false,
|
"prefer-stable": false,
|
||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
"platform": {
|
"platform": {
|
||||||
"php": ">=7.3"
|
"php": "^7.4"
|
||||||
},
|
},
|
||||||
"platform-dev": [],
|
"platform-dev": {
|
||||||
"plugin-api-version": "2.6.0"
|
"ext-posix": "*",
|
||||||
|
"ext-pcntl": "*",
|
||||||
|
"ext-curl": "*"
|
||||||
|
},
|
||||||
|
"plugin-api-version": "2.2.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
# -*- coding: utf-8 mode: dockerfile -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
ARG NDIST=12
|
||||||
|
ARG REGISTRY=pubdocker.univ-reunion.fr
|
||||||
|
|
||||||
|
FROM $REGISTRY/src/base AS base
|
||||||
|
FROM $REGISTRY/src/php AS php
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
FROM debian:${NDIST}-slim AS builder
|
||||||
|
ARG APT_MIRROR SEC_MIRROR APT_PROXY TIMEZONE
|
||||||
|
ENV APT_MIRROR=$APT_MIRROR SEC_MIRROR=$SEC_MIRROR APT_PROXY=$APT_PROXY TIMEZONE=$TIMEZONE
|
||||||
|
|
||||||
|
COPY --from=base /g/ /g/
|
||||||
|
COPY --from=base /src/ /src/
|
||||||
|
RUN /g/build core lite _builder
|
||||||
|
RUN /g/build _su-exec_builder
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
FROM debian:${NDIST}-slim
|
||||||
|
ARG APT_MIRROR SEC_MIRROR APT_PROXY TIMEZONE
|
||||||
|
ENV APT_MIRROR=$APT_MIRROR SEC_MIRROR=$SEC_MIRROR APT_PROXY=$APT_PROXY TIMEZONE=$TIMEZONE
|
||||||
|
|
||||||
|
COPY --from=base /g/ /g/
|
||||||
|
COPY --from=builder /src/su-exec/su-exec /g/
|
||||||
|
RUN /g/build
|
||||||
|
|
||||||
|
COPY --from=php /g/ /g/
|
||||||
|
RUN /g/build -a @adminer
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
ENTRYPOINT ["/g/entrypoint"]
|
|
@ -0,0 +1,40 @@
|
||||||
|
# -*- coding: utf-8 mode: dockerfile -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
ARG NDIST=12
|
||||||
|
ARG REGISTRY=pubdocker.univ-reunion.fr
|
||||||
|
|
||||||
|
FROM $REGISTRY/src/base AS base
|
||||||
|
FROM $REGISTRY/src/instantclient AS instantclient
|
||||||
|
FROM $REGISTRY/src/php AS php
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
FROM debian:${NDIST}-slim AS builder
|
||||||
|
ARG APT_MIRROR SEC_MIRROR APT_PROXY TIMEZONE
|
||||||
|
ENV APT_MIRROR=$APT_MIRROR SEC_MIRROR=$SEC_MIRROR APT_PROXY=$APT_PROXY TIMEZONE=$TIMEZONE
|
||||||
|
|
||||||
|
COPY --from=base /g/ /g/
|
||||||
|
COPY --from=base /src/ /src/
|
||||||
|
RUN /g/build core lite _builder
|
||||||
|
RUN /g/build _su-exec_builder
|
||||||
|
|
||||||
|
COPY --from=instantclient /g/ /g/
|
||||||
|
COPY --from=instantclient /src/ /src/
|
||||||
|
RUN /g/build _instantclient_builder
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
FROM debian:${NDIST}-slim
|
||||||
|
ARG APT_MIRROR SEC_MIRROR APT_PROXY TIMEZONE
|
||||||
|
ENV APT_MIRROR=$APT_MIRROR SEC_MIRROR=$SEC_MIRROR APT_PROXY=$APT_PROXY TIMEZONE=$TIMEZONE
|
||||||
|
|
||||||
|
COPY --from=base /g/ /g/
|
||||||
|
COPY --from=builder /src/su-exec/su-exec /g/
|
||||||
|
RUN /g/build
|
||||||
|
|
||||||
|
COPY --from=php /g/ /g/
|
||||||
|
RUN /g/build -a @adminer
|
||||||
|
|
||||||
|
COPY --from=instantclient /g/ /g/
|
||||||
|
COPY --from=builder /opt/oracle/ /opt/oracle/
|
||||||
|
RUN /g/build instantclient
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
ENTRYPOINT ["/g/entrypoint"]
|
|
@ -0,0 +1,19 @@
|
||||||
|
# -*- coding: utf-8 mode: dockerfile -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
ARG REGISTRY=pubdocker.univ-reunion.fr
|
||||||
|
FROM $REGISTRY/src/base AS base
|
||||||
|
FROM $REGISTRY/src/mariadb AS mariadb
|
||||||
|
FROM $REGISTRY/src/legacytools AS legacytools
|
||||||
|
|
||||||
|
FROM mariadb:10
|
||||||
|
ARG APT_PROXY TIMEZONE
|
||||||
|
ENV APT_PROXY=$APT_PROXY TIMEZONE=$TIMEZONE
|
||||||
|
|
||||||
|
COPY --from=base /g/ /g/
|
||||||
|
COPY --from=mariadb /g/ /g/
|
||||||
|
RUN /g/build -a @base @mariadb
|
||||||
|
|
||||||
|
COPY --from=legacytools /g/ /g/
|
||||||
|
RUN /g/build nutools servertools
|
||||||
|
|
||||||
|
EXPOSE 3306
|
||||||
|
ENTRYPOINT ["/g/entrypoint"]
|
|
@ -0,0 +1,31 @@
|
||||||
|
# -*- coding: utf-8 mode: dockerfile -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
ARG NDIST=12
|
||||||
|
ARG REGISTRY=pubdocker.univ-reunion.fr
|
||||||
|
|
||||||
|
FROM $REGISTRY/src/base AS base
|
||||||
|
FROM $REGISTRY/src/php AS php
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
FROM debian:${NDIST}-slim AS builder
|
||||||
|
ARG APT_MIRROR SEC_MIRROR APT_PROXY TIMEZONE
|
||||||
|
ENV APT_MIRROR=$APT_MIRROR SEC_MIRROR=$SEC_MIRROR APT_PROXY=$APT_PROXY TIMEZONE=$TIMEZONE
|
||||||
|
|
||||||
|
COPY --from=base /g/ /g/
|
||||||
|
COPY --from=base /src/ /src/
|
||||||
|
RUN /g/build core lite _builder
|
||||||
|
RUN /g/build _su-exec_builder
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
FROM debian:${NDIST}-slim
|
||||||
|
ARG APT_MIRROR SEC_MIRROR APT_PROXY TIMEZONE
|
||||||
|
ENV APT_MIRROR=$APT_MIRROR SEC_MIRROR=$SEC_MIRROR APT_PROXY=$APT_PROXY TIMEZONE=$TIMEZONE
|
||||||
|
|
||||||
|
COPY --from=base /g/ /g/
|
||||||
|
COPY --from=builder /src/su-exec/su-exec /g/
|
||||||
|
RUN /g/build
|
||||||
|
|
||||||
|
COPY --from=php /g/ /g/
|
||||||
|
RUN /g/build -a @apache-php-cas php-utils
|
||||||
|
|
||||||
|
EXPOSE 80 443
|
||||||
|
ENTRYPOINT ["/g/entrypoint"]
|
|
@ -0,0 +1,44 @@
|
||||||
|
# -*- coding: utf-8 mode: dockerfile -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
ARG NDIST=12
|
||||||
|
ARG REGISTRY=pubdocker.univ-reunion.fr
|
||||||
|
|
||||||
|
FROM $REGISTRY/src/base AS base
|
||||||
|
FROM $REGISTRY/src/legacytools AS legacytools
|
||||||
|
FROM $REGISTRY/src/instantclient AS instantclient
|
||||||
|
FROM $REGISTRY/src/php AS php
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
FROM debian:${NDIST}-slim AS builder
|
||||||
|
ARG APT_MIRROR SEC_MIRROR APT_PROXY TIMEZONE
|
||||||
|
ENV APT_MIRROR=$APT_MIRROR SEC_MIRROR=$SEC_MIRROR APT_PROXY=$APT_PROXY TIMEZONE=$TIMEZONE
|
||||||
|
|
||||||
|
COPY --from=base /g/ /g/
|
||||||
|
COPY --from=base /src/ /src/
|
||||||
|
RUN /g/build core lite _builder
|
||||||
|
RUN /g/build _su-exec_builder
|
||||||
|
|
||||||
|
COPY --from=instantclient /g/ /g/
|
||||||
|
COPY --from=instantclient /src/ /src/
|
||||||
|
RUN /g/build _instantclient_builder
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
FROM debian:${NDIST}-slim
|
||||||
|
ARG APT_MIRROR SEC_MIRROR APT_PROXY TIMEZONE
|
||||||
|
ENV APT_MIRROR=$APT_MIRROR SEC_MIRROR=$SEC_MIRROR APT_PROXY=$APT_PROXY TIMEZONE=$TIMEZONE
|
||||||
|
|
||||||
|
COPY --from=base /g/ /g/
|
||||||
|
COPY --from=builder /src/su-exec/su-exec /g/
|
||||||
|
RUN /g/build
|
||||||
|
|
||||||
|
COPY --from=legacytools /g/ /g/
|
||||||
|
RUN /g/build nutools
|
||||||
|
|
||||||
|
COPY --from=php /g/ /g/
|
||||||
|
RUN /g/build -a @apache-php-cas php-utils
|
||||||
|
|
||||||
|
COPY --from=instantclient /g/ /g/
|
||||||
|
COPY --from=builder /opt/oracle/ /opt/oracle/
|
||||||
|
RUN /g/build instantclient
|
||||||
|
|
||||||
|
EXPOSE 80 443
|
||||||
|
ENTRYPOINT ["/g/entrypoint"]
|
|
@ -0,0 +1,30 @@
|
||||||
|
# -*- coding: utf-8 mode: dockerfile -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
ARG NDIST=12
|
||||||
|
ARG REGISTRY=pubdocker.univ-reunion.fr
|
||||||
|
|
||||||
|
FROM $REGISTRY/src/base AS base
|
||||||
|
FROM $REGISTRY/src/php AS php
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
FROM debian:${NDIST}-slim AS builder
|
||||||
|
ARG APT_MIRROR SEC_MIRROR APT_PROXY TIMEZONE
|
||||||
|
ENV APT_MIRROR=$APT_MIRROR SEC_MIRROR=$SEC_MIRROR APT_PROXY=$APT_PROXY TIMEZONE=$TIMEZONE
|
||||||
|
|
||||||
|
COPY --from=base /g/ /g/
|
||||||
|
COPY --from=base /src/ /src/
|
||||||
|
RUN /g/build core lite _builder
|
||||||
|
RUN /g/build _su-exec_builder
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
FROM debian:${NDIST}-slim
|
||||||
|
ARG APT_MIRROR SEC_MIRROR APT_PROXY TIMEZONE
|
||||||
|
ENV APT_MIRROR=$APT_MIRROR SEC_MIRROR=$SEC_MIRROR APT_PROXY=$APT_PROXY TIMEZONE=$TIMEZONE
|
||||||
|
|
||||||
|
COPY --from=base /g/ /g/
|
||||||
|
COPY --from=builder /src/su-exec/su-exec /g/
|
||||||
|
RUN /g/build
|
||||||
|
|
||||||
|
COPY --from=php /g/ /g/
|
||||||
|
RUN /g/build @php-cli php-utils
|
||||||
|
|
||||||
|
ENTRYPOINT ["/g/entrypoint"]
|
|
@ -0,0 +1,43 @@
|
||||||
|
# -*- coding: utf-8 mode: dockerfile -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
ARG NDIST=12
|
||||||
|
ARG REGISTRY=pubdocker.univ-reunion.fr
|
||||||
|
|
||||||
|
FROM $REGISTRY/src/base AS base
|
||||||
|
FROM $REGISTRY/src/legacytools AS legacytools
|
||||||
|
FROM $REGISTRY/src/instantclient AS instantclient
|
||||||
|
FROM $REGISTRY/src/php AS php
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
FROM debian:${NDIST}-slim AS builder
|
||||||
|
ARG APT_MIRROR SEC_MIRROR APT_PROXY TIMEZONE
|
||||||
|
ENV APT_MIRROR=$APT_MIRROR SEC_MIRROR=$SEC_MIRROR APT_PROXY=$APT_PROXY TIMEZONE=$TIMEZONE
|
||||||
|
|
||||||
|
COPY --from=base /g/ /g/
|
||||||
|
COPY --from=base /src/ /src/
|
||||||
|
RUN /g/build core lite _builder
|
||||||
|
RUN /g/build _su-exec_builder
|
||||||
|
|
||||||
|
COPY --from=instantclient /g/ /g/
|
||||||
|
COPY --from=instantclient /src/ /src/
|
||||||
|
RUN /g/build _instantclient_builder
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
FROM debian:${NDIST}-slim
|
||||||
|
ARG APT_MIRROR SEC_MIRROR APT_PROXY TIMEZONE
|
||||||
|
ENV APT_MIRROR=$APT_MIRROR SEC_MIRROR=$SEC_MIRROR APT_PROXY=$APT_PROXY TIMEZONE=$TIMEZONE
|
||||||
|
|
||||||
|
COPY --from=base /g/ /g/
|
||||||
|
COPY --from=builder /src/su-exec/su-exec /g/
|
||||||
|
RUN /g/build
|
||||||
|
|
||||||
|
COPY --from=legacytools /g/ /g/
|
||||||
|
RUN /g/build nutools
|
||||||
|
|
||||||
|
COPY --from=php /g/ /g/
|
||||||
|
RUN /g/build @php-cli php-utils
|
||||||
|
|
||||||
|
COPY --from=instantclient /g/ /g/
|
||||||
|
COPY --from=builder /opt/oracle/ /opt/oracle/
|
||||||
|
RUN /g/build instantclient
|
||||||
|
|
||||||
|
ENTRYPOINT ["/g/entrypoint"]
|
|
@ -0,0 +1,16 @@
|
||||||
|
# -*- coding: utf-8 mode: dockerfile -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
ARG REGISTRY=pubdocker.univ-reunion.fr
|
||||||
|
FROM $REGISTRY/src/base AS base
|
||||||
|
FROM $REGISTRY/src/postgres AS postgres
|
||||||
|
|
||||||
|
FROM postgres:15-bookworm
|
||||||
|
ARG APT_PROXY TIMEZONE
|
||||||
|
ENV APT_PROXY=$APT_PROXY TIMEZONE=$TIMEZONE
|
||||||
|
|
||||||
|
COPY --from=base /g/ /g/
|
||||||
|
COPY --from=postgres /g/ /g/
|
||||||
|
RUN /g/build -a @base @postgres
|
||||||
|
RUN /g/pkg i @ssl @git
|
||||||
|
|
||||||
|
EXPOSE 5432
|
||||||
|
ENTRYPOINT ["/g/entrypoint"]
|
|
@ -0,0 +1,2 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
__uaddpath "@@dest@@/bin" PATH
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
source "$(dirname -- "$0")/../load.sh" || exit 1
|
||||||
|
|
||||||
|
[ "$(id -u)" -eq 0 ] || die "Ce script doit être lancé avec les droits root"
|
||||||
|
|
||||||
|
cd "$MYDIR/.."
|
||||||
|
[ -n "$1" ] && dest="$1" || dest="$(pwd)"
|
||||||
|
|
||||||
|
estep "Maj /etc/nulib.sh"
|
||||||
|
sed "s|@@""dest""@@|$dest|g" load.sh >/etc/nulib.sh
|
|
@ -0,0 +1,6 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
|
||||||
|
source "$@" || exit 1
|
||||||
|
|
||||||
|
# supprimer les fichiers de VCS
|
||||||
|
rm -rf "$srcdir/.git"
|
|
@ -0,0 +1,5 @@
|
||||||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
|
||||||
|
source "$@" || exit 1
|
||||||
|
|
||||||
|
"$srcdir/lib/setup.sh" "$dest"
|
|
@ -0,0 +1,182 @@
|
||||||
|
##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||||
|
## Charger nulib et rendre disponible les modules bash, awk, php et python
|
||||||
|
##@cooked nocomments
|
||||||
|
# Ce fichier doit être sourcé en premier. Si ce fichier n'est pas sourcé, alors
|
||||||
|
# le répertoire nulib doit être disponible dans le répertoire du script qui
|
||||||
|
# inclue ce fichier.
|
||||||
|
# Une fois ce fichier sourcé, les autres modules peuvent être importés avec
|
||||||
|
# require:() e.g.
|
||||||
|
# source /etc/nulib.sh || exit 1
|
||||||
|
# require: other_modules
|
||||||
|
# ou pour une copie locale de nulib:
|
||||||
|
# source "$(dirname "$0")/nulib/load.sh" || exit 1
|
||||||
|
# require: other_modules
|
||||||
|
|
||||||
|
# vérifier version minimum de bash
|
||||||
|
if [ "x$BASH" = "x" ]; then
|
||||||
|
echo "ERROR: nulib: this script requires bash"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
function eerror() { echo "ERROR: $*" 1>&2; }
|
||||||
|
function die() { [ $# -gt 0 ] && eerror "$*"; exit 1; }
|
||||||
|
function edie() { [ $# -gt 0 ] && eerror "$*"; return 1; }
|
||||||
|
function delpath() { local _qdir="${1//\//\\/}"; eval "export ${2:-PATH}; ${2:-PATH}"'="${'"${2:-PATH}"'#$1:}"; '"${2:-PATH}"'="${'"${2:-PATH}"'%:$1}"; '"${2:-PATH}"'="${'"${2:-PATH}"'//:$_qdir:/:}"; [ "$'"${2:-PATH}"'" == "$1" ] && '"${2:-PATH}"'='; }
|
||||||
|
function addpath() { local _qdir="${1//\//\\/}"; eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="${'"${2:-PATH}"':+$'"${2:-PATH}"':}$1"'; }
|
||||||
|
function inspathm() { local _qdir="${1//\//\\/}"; eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="$1${'"${2:-PATH}"':+:$'"${2:-PATH}"'}"'; }
|
||||||
|
function inspath() { delpath "$@"; inspathm "$@"; }
|
||||||
|
|
||||||
|
if [ ${BASH_VERSINFO[0]} -ge 5 -o \( ${BASH_VERSINFO[0]} -eq 4 -a ${BASH_VERSINFO[1]} -ge 1 \) ]; then :
|
||||||
|
elif [ -n "$NULIB_IGNORE_BASH_VERSION" ]; then :
|
||||||
|
else die "nulib: bash 4.1+ is required"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Calculer emplacement de nulib
|
||||||
|
NULIBDIR="@@dest@@"
|
||||||
|
if [ "$NULIBDIR" = "@@""dest""@@" ]; then
|
||||||
|
# La valeur "@@"dest"@@" n'est remplacée que dans la copie de ce script
|
||||||
|
# faite dans /etc. Sinon, il faut toujours faire le calcul. Cela permet de
|
||||||
|
# déplacer la librairie n'importe où sur le disque, ce qui est
|
||||||
|
# particulièrement intéressant quand on fait du déploiement.
|
||||||
|
NULIBDIR="${BASH_SOURCE[0]}"
|
||||||
|
if [ -f "$NULIBDIR" -a "$(basename -- "$NULIBDIR")" == load.sh ]; then
|
||||||
|
# Fichier sourcé depuis nulib/
|
||||||
|
NULIB_SOURCED=1
|
||||||
|
NULIBDIR="$(dirname -- "$NULIBDIR")"
|
||||||
|
elif [ -f "$NULIBDIR" -a "$(basename -- "$NULIBDIR")" == nulib.sh ]; then
|
||||||
|
# Fichier sourcé depuis nulib/bash/src
|
||||||
|
NULIB_SOURCED=1
|
||||||
|
NULIBDIR="$(dirname -- "$NULIBDIR")/../.."
|
||||||
|
else
|
||||||
|
# Fichier non sourcé. Tout exprimer par rapport au script courant
|
||||||
|
NULIB_SOURCED=
|
||||||
|
NULIBDIR="$(dirname -- "$0")"
|
||||||
|
if [ -d "$NULIBDIR/nulib" ]; then
|
||||||
|
NULIBDIR="$NULIBDIR/nulib"
|
||||||
|
elif [ -d "$NULIBDIR/lib/nulib" ]; then
|
||||||
|
NULIBDIR="$NULIBDIR/lib/nulib"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
elif [ "${BASH_SOURCE[0]}" = /etc/nulib.sh ]; then
|
||||||
|
# Fichier chargé depuis /etc/nulib.sh
|
||||||
|
NULIB_SOURCED=1
|
||||||
|
fi
|
||||||
|
NULIBDIR="$(cd "$NULIBDIR" 2>/dev/null; pwd)"
|
||||||
|
NULIBDIRS=("$NULIBDIR/bash/src")
|
||||||
|
|
||||||
|
# marqueur pour vérifier que nulib a réellement été chargé. il faut avoir $NULIBINIT == $NULIBDIR
|
||||||
|
# utilisé par le module base qui doit pouvoir être inclus indépendamment
|
||||||
|
NULIBINIT="$NULIBDIR"
|
||||||
|
|
||||||
|
## Modules bash
|
||||||
|
NULIB_LOADED_MODULES=(nulib)
|
||||||
|
NULIB_DEFAULT_MODULES=(base pretty sysinfos)
|
||||||
|
|
||||||
|
# Si cette variable est non vide, require: recharge toujours le module, même
|
||||||
|
# s'il a déjà été chargé. Cette valeur n'est pas transitive: il faut toujours
|
||||||
|
# recharger explicitement tous les modules désirés
|
||||||
|
NULIB_FORCE_RELOAD=
|
||||||
|
|
||||||
|
function nulib__define_functions() {
|
||||||
|
function nulib_check_loaded() {
|
||||||
|
local module
|
||||||
|
for module in "${NULIB_LOADED_MODULES[@]}"; do
|
||||||
|
[ "$module" == "$1" ] && return 0
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
function module:() {
|
||||||
|
NULIB_MODULE="$1"
|
||||||
|
if ! nulib_check_loaded "$1"; then
|
||||||
|
NULIB_LOADED_MODULES+=("$1")
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
function function:() {
|
||||||
|
:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function nulib__load:() {
|
||||||
|
local nl__module nl__nulibdir nl__found
|
||||||
|
[ $# -gt 0 ] || set DEFAULTS
|
||||||
|
|
||||||
|
for nl__module in "$@"; do
|
||||||
|
nl__found=
|
||||||
|
for nl__nulibdir in "${NULIBDIRS[@]}"; do
|
||||||
|
if [ -f "$nl__nulibdir/$nl__module.sh" ]; then
|
||||||
|
source "$nl__nulibdir/$nl__module.sh" || die
|
||||||
|
nl__found=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
[ -n "$nl__found" ] || die "nulib: unable to find module $nl__module in (${NULIBDIRS[*]})"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
function nulib__require:() {
|
||||||
|
local nr__module nr__nulibdir nr__found
|
||||||
|
[ $# -gt 0 ] || set DEFAULTS
|
||||||
|
|
||||||
|
# sauvegarder valeurs globales
|
||||||
|
local nr__orig_module="$NULIB_MODULE"
|
||||||
|
NULIB_MODULE=
|
||||||
|
|
||||||
|
# garder une copie de la valeur originale et casser la transitivité
|
||||||
|
local nr__force_reload="$NULIB_FORCE_RELOAD"
|
||||||
|
local NULIB_FORCE_RELOAD
|
||||||
|
|
||||||
|
for nr__module in "$@"; do
|
||||||
|
nr__found=
|
||||||
|
for nr__nulibdir in "${NULIBDIRS[@]}"; do
|
||||||
|
if [ -f "$nr__nulibdir/$nr__module.sh" ]; then
|
||||||
|
nr__found=1
|
||||||
|
if [ -n "$nr__force_reload" ] || ! nulib_check_loaded "$nr__module"; then
|
||||||
|
NULIB_LOADED_MODULES+=("$nr__module")
|
||||||
|
source "$nr__nulibdir/$nr__module.sh" || die
|
||||||
|
fi
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ -z "$nr__found" -a "$nr__module" == DEFAULTS ]; then
|
||||||
|
for nr__module in "${NULIB_DEFAULT_MODULES[@]}"; do
|
||||||
|
if [ -f "$nr__nulibdir/$nr__module.sh" ]; then
|
||||||
|
nr__found=1
|
||||||
|
if [ -n "$nr__force_reload" ] || ! nulib_check_loaded "$nr__module"; then
|
||||||
|
NULIB_LOADED_MODULES+=("$nr__module")
|
||||||
|
source "$nr__nulibdir/$nr__module.sh" || die
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
[ -n "$nr__found" ] || die "nulib: unable to find module $nr__module in (${NULIBDIRS[*]})"
|
||||||
|
done
|
||||||
|
|
||||||
|
# restaurer valeurs globales
|
||||||
|
NULIB_MODULE="$nr__orig_module"
|
||||||
|
}
|
||||||
|
|
||||||
|
# désactiver set -x
|
||||||
|
NULIB__DISABLE_SET_X='local NULIB__SET_X; [ -z "$NULIB_NO_DISABLE_SET_X" ] && [[ $- == *x* ]] && { set +x; NULIB__SET_X=1; }'
|
||||||
|
NULIB__ENABLE_SET_X='[ -n "$NULIB__SET_X" ] && set -x'
|
||||||
|
# désactiver set -x de manière réentrante
|
||||||
|
NULIB__RDISABLE_SET_X='[ -z "$NULIB_NO_DISABLE_SET_X" ] && [[ $- == *x* ]] && { set +x; local NULIB_REQUIRE_SET_X=1; }; if [ -n "$NULIB_REQUIRE_SET_X" ]; then [ -n "$NULIB_REQUIRE_SET_X_RL1" ] || local NULIB_REQUIRE_SET_X_RL1; local NULIB_REQUIRE_SET_X_RL2=$RANDOM; [ -n "$NULIB_REQUIRE_SET_X_RL1" ] || NULIB_REQUIRE_SET_X_RL1=$NULIB_REQUIRE_SET_X_RL2; fi'
|
||||||
|
NULIB__RENABLE_SET_X='[ -n "$NULIB_REQUIRE_SET_X" -a "$NULIB_REQUIRE_SET_X_RL1" == "$NULIB_REQUIRE_SET_X_RL2" ] && set -x'
|
||||||
|
|
||||||
|
function require:() {
|
||||||
|
eval "$NULIB__RDISABLE_SET_X"
|
||||||
|
nulib__define_functions
|
||||||
|
nulib__require: "$@"
|
||||||
|
eval "$NULIB__RENABLE_SET_X"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
## Autres modules
|
||||||
|
[ -d "$NULIBDIR/awk/src" ] && inspath "$NULIBDIR/awk/src" AWKPATH; export AWKPATH
|
||||||
|
[ -d "$NULIBDIR/python3/src" ] && inspath "$NULIBDIR/python3/src" PYTHONPATH; export PYTHONPATH
|
||||||
|
|
||||||
|
## Auto import DEFAULTS
|
||||||
|
nulib__define_functions
|
||||||
|
if [ -n "$NULIB_SOURCED" -a -z "$NULIB_NO_IMPORT_DEFAULTS" ]; then
|
||||||
|
require: DEFAULTS
|
||||||
|
fi
|
|
@ -0,0 +1,216 @@
|
||||||
|
<?php
|
||||||
|
namespace nulib;
|
||||||
|
|
||||||
|
use Traversable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class A: gestion de tableaux ou d'instances de {@link IArrayWrapper}
|
||||||
|
*
|
||||||
|
* contrairement à {@link cl}, les méthodes de cette classes sont plutôt conçues
|
||||||
|
* pour modifier le tableau en place
|
||||||
|
*/
|
||||||
|
class A {
|
||||||
|
/**
|
||||||
|
* s'assurer que $array est un array non null. retourner true si $array n'a
|
||||||
|
* pas été modifié (s'il était déjà un array), false sinon.
|
||||||
|
*/
|
||||||
|
static final function ensure_array(&$array): bool {
|
||||||
|
if (is_array($array)) return true;
|
||||||
|
if ($array instanceof IArrayWrapper) $array = $array->wrappedArray();
|
||||||
|
if ($array === null || $array === false) $array = [];
|
||||||
|
elseif ($array instanceof Traversable) $array = cl::all($array);
|
||||||
|
else $array = [$array];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* s'assurer que $array est un array s'il est non null. retourner true si
|
||||||
|
* $array n'a pas été modifié (s'il était déjà un array ou s'il valait null).
|
||||||
|
*/
|
||||||
|
static final function ensure_narray(&$array): bool {
|
||||||
|
if ($array instanceof IArrayWrapper) $array = $array->wrappedArray();
|
||||||
|
if ($array === null || is_array($array)) return true;
|
||||||
|
if ($array === false) $array = [];
|
||||||
|
elseif ($array instanceof Traversable) $array = cl::all($array);
|
||||||
|
else $array = [$array];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* s'assurer que $array est un tableau de $size éléments, en complétant avec
|
||||||
|
* des occurrences de $default si nécessaire
|
||||||
|
*
|
||||||
|
* @return bool true si le tableau a été modifié, false sinon
|
||||||
|
*/
|
||||||
|
static final function ensure_size(?array &$array, int $size, $default=null): bool {
|
||||||
|
$modified = false;
|
||||||
|
if ($array === null) {
|
||||||
|
$array = [];
|
||||||
|
$modified = true;
|
||||||
|
}
|
||||||
|
if ($size < 0) return $modified;
|
||||||
|
$count = count($array);
|
||||||
|
if ($count == $size) return $modified;
|
||||||
|
if ($count < $size) {
|
||||||
|
# agrandir le tableau
|
||||||
|
while ($count++ < $size) {
|
||||||
|
$array[] = $default;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
# rétrécir le tableau
|
||||||
|
$tmparray = [];
|
||||||
|
foreach ($array as $key => $value) {
|
||||||
|
if ($size-- == 0) break;
|
||||||
|
$tmparray[$key] = $value;
|
||||||
|
}
|
||||||
|
$array = $tmparray;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function merge(&$dest, ...$merges): void {
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
$dest = cl::merge($dest, ...$merges);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function merge2(&$dest, ...$merges): void {
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
$dest = cl::merge2($dest, ...$merges);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function select(&$dest, ?array $mappings, bool $inverse=false): void {
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
$dest = cl::select($dest, $mappings, $inverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function selectm(&$dest, ?array $mappings, ?array $merge=null): void {
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
$dest = cl::selectm($dest, $mappings, $merge);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function mselect(&$dest, ?array $merge, ?array $mappings): void {
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
$dest = cl::mselect($dest, $merge, $mappings);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function pselect(&$dest, ?array $pkeys): void {
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
$dest = cl::pselect($dest, $pkeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function pselectm(&$dest, ?array $pkeys, ?array $merge=null): void {
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
$dest = cl::pselectm($dest, $pkeys, $merge);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function mpselect(&$dest, ?array $merge, ?array $pkeys): void {
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
$dest = cl::mpselect($dest, $merge, $pkeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function set_nn(&$dest, $key, $value) {
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
if ($value !== null) {
|
||||||
|
if ($key === null) $dest[] = $value;
|
||||||
|
else $dest[$key] = $value;
|
||||||
|
}
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function append_nn(&$dest, $value) {
|
||||||
|
return self::set_nn($dest, null, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function set_nz(&$dest, $key, $value) {
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
if ($value !== null && $value !== false) {
|
||||||
|
if ($key === null) $dest[] = $value;
|
||||||
|
else $dest[$key] = $value;
|
||||||
|
}
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function append_nz(&$dest, $value) {
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
return self::set_nz($dest, null, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function prepend_nn(&$dest, $value) {
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
if ($value !== null) {
|
||||||
|
if ($dest === null) $dest = [];
|
||||||
|
array_unshift($dest, $value);
|
||||||
|
}
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function prepend_nz(&$dest, $value) {
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
if ($value !== null && $value !== false) {
|
||||||
|
if ($dest === null) $dest = [];
|
||||||
|
array_unshift($dest, $value);
|
||||||
|
}
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function replace_nx(&$dest, $key, $value) {
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
if ($dest !== null && !array_key_exists($key, $dest)) {
|
||||||
|
return $dest[$key] = $value;
|
||||||
|
} else {
|
||||||
|
return $dest[$key] ?? null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function replace_n(&$dest, $key, $value) {
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
$pvalue = $dest[$key] ?? null;
|
||||||
|
if ($pvalue === null) $dest[$key] = $value;
|
||||||
|
return $pvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function replace_z(&$dest, $key, $value) {
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
$pvalue = $dest[$key] ?? null;
|
||||||
|
if ($pvalue === null || $pvalue === false) $dest[$key] = $value;
|
||||||
|
return $pvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function pop(&$dest, $key, $default=null) {
|
||||||
|
if ($dest === null) return $default;
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
if ($key === null) return array_pop($dest);
|
||||||
|
$value = $dest[$key] ?? $default;
|
||||||
|
unset($dest[$key]);
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function popx(&$dest, ?array $keys): array {
|
||||||
|
$values = [];
|
||||||
|
if ($dest === null) return $values;
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
if ($keys === null) return $values;
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
$values[$key] = self::pop($dest, $key);
|
||||||
|
}
|
||||||
|
return $values;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function filter_if(&$dest, callable $cond): void {
|
||||||
|
self::ensure_narray($dest);
|
||||||
|
$dest = cl::filter_if($dest, $cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function filter_z($dest): void { self::filter_if($dest, [cv::class, "z"]);}
|
||||||
|
static final function filter_nz($dest): void { self::filter_if($dest, [cv::class, "nz"]);}
|
||||||
|
static final function filter_n($dest): void { self::filter_if($dest, [cv::class, "n"]);}
|
||||||
|
static final function filter_nn($dest): void { self::filter_if($dest, [cv::class, "nn"]);}
|
||||||
|
static final function filter_t($dest): void { self::filter_if($dest, [cv::class, "t"]);}
|
||||||
|
static final function filter_f($dest): void { self::filter_if($dest, [cv::class, "f"]);}
|
||||||
|
static final function filter_pt($dest): void { self::filter_if($dest, [cv::class, "pt"]);}
|
||||||
|
static final function filter_pf($dest): void { self::filter_if($dest, [cv::class, "pf"]);}
|
||||||
|
static final function filter_equals($dest, $value): void { self::filter_if($dest, cv::equals($value)); }
|
||||||
|
static final function filter_not_equals($dest, $value): void { self::filter_if($dest, cv::not_equals($value)); }
|
||||||
|
static final function filter_same($dest, $value): void { self::filter_if($dest, cv::same($value)); }
|
||||||
|
static final function filter_not_same($dest, $value): void { self::filter_if($dest, cv::not_same($value)); }
|
||||||
|
}
|
|
@ -1,13 +1,18 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nulib;
|
namespace nulib;
|
||||||
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class AccessException: indiquer que la resource ou l'objet auquel on veut
|
* Class AccessException: indiquer que la resource ou l'objet auquel on veut
|
||||||
* accéder n'est pas accessible. il s'agit donc d'une erreur de l'utilisateur
|
* accéder n'est pas accessible. il s'agit donc d'une erreur de l'utilisateur
|
||||||
*/
|
*/
|
||||||
class AccessException extends Exception {
|
class AccessException extends UserException {
|
||||||
|
static final function read_only(?string $dest=null, ?string $prefix=null): self {
|
||||||
|
if ($prefix) $prefix = "$prefix: ";
|
||||||
|
if ($dest === null) $dest = "this property";
|
||||||
|
$message = "$dest is read-only";
|
||||||
|
return new static($prefix.$message);
|
||||||
|
}
|
||||||
|
|
||||||
static final function immutable_object(?string $dest=null, ?string $prefix=null): self {
|
static final function immutable_object(?string $dest=null, ?string $prefix=null): self {
|
||||||
if ($prefix) $prefix = "$prefix: ";
|
if ($prefix) $prefix = "$prefix: ";
|
||||||
if ($dest === null) $dest = "this object";
|
if ($dest === null) $dest = "this object";
|
|
@ -0,0 +1,101 @@
|
||||||
|
<?php
|
||||||
|
namespace nulib;
|
||||||
|
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ExceptionShadow: une classe qui capture les informations d'une
|
||||||
|
* exception afin de pouvoir les sérialiser
|
||||||
|
*/
|
||||||
|
class ExceptionShadow {
|
||||||
|
protected static function extract_trace(array $trace): array {
|
||||||
|
$frames = [];
|
||||||
|
foreach ($trace as $frame) {
|
||||||
|
$file = cl::get($frame, "file");
|
||||||
|
$line = cl::get($frame, "line");
|
||||||
|
$class = cl::get($frame, "class");
|
||||||
|
$function = cl::get($frame, "function");
|
||||||
|
$type = cl::get($frame, "type");
|
||||||
|
$frames[] = [
|
||||||
|
"file" => $file,
|
||||||
|
"line" => $line,
|
||||||
|
"class" => $class,
|
||||||
|
"object" => null,
|
||||||
|
"type" => $type,
|
||||||
|
"function" => $function,
|
||||||
|
"args" => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
function __construct(Throwable $exception) {
|
||||||
|
$this->class = get_class($exception);
|
||||||
|
$this->message = $exception->getMessage();
|
||||||
|
$this->code = $exception->getCode();
|
||||||
|
$this->file = $exception->getFile();
|
||||||
|
$this->line = $exception->getLine();
|
||||||
|
$this->trace = self::extract_trace($exception->getTrace());
|
||||||
|
$previous = $exception->getPrevious();
|
||||||
|
if ($previous !== null) $this->previous = new static($previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $class;
|
||||||
|
|
||||||
|
function getClass(): string {
|
||||||
|
return $this->class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $message;
|
||||||
|
|
||||||
|
function getMessage(): string {
|
||||||
|
return $this->message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var mixed */
|
||||||
|
protected $code;
|
||||||
|
|
||||||
|
function getCode() {
|
||||||
|
return $this->code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $file;
|
||||||
|
|
||||||
|
function getFile(): string {
|
||||||
|
return $this->file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
protected $line;
|
||||||
|
|
||||||
|
function getLine(): int {
|
||||||
|
return $this->line;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
protected $trace;
|
||||||
|
|
||||||
|
function getTrace(): array {
|
||||||
|
return $this->trace;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTraceAsString(): string {
|
||||||
|
$lines = [];
|
||||||
|
foreach ($this->trace as $index => $frame) {
|
||||||
|
$lines[] = "#$index $frame[file]($frame[line]): $frame[class]$frame[type]$frame[function]()";
|
||||||
|
}
|
||||||
|
$index++;
|
||||||
|
$lines[] = "#$index {main}";
|
||||||
|
return implode("\n", $lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var ExceptionShadow */
|
||||||
|
protected $previous;
|
||||||
|
|
||||||
|
function getPrevious(): ?ExceptionShadow {
|
||||||
|
return $this->previous;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
namespace nulib;
|
||||||
|
|
||||||
|
use Error;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ExitException: une exception qui indique que l'application souhaite
|
||||||
|
* quitter normalement, avec éventuellement un code d'erreur.
|
||||||
|
*/
|
||||||
|
class ExitError extends Error {
|
||||||
|
function __construct(int $exitcode=0, $userMessage=null, Throwable $previous=null) {
|
||||||
|
parent::__construct(null, $exitcode, $previous);
|
||||||
|
$this->userMessage = $userMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isError(): bool {
|
||||||
|
return $this->getCode() !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var ?string */
|
||||||
|
protected $userMessage;
|
||||||
|
|
||||||
|
function haveMessage(): bool {
|
||||||
|
return $this->userMessage !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUserMessage(): ?string {
|
||||||
|
return $this->userMessage;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
namespace nulib;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface IArrayWrapper: un objet qui encapsule un array auquel on peut
|
||||||
|
* accéder
|
||||||
|
*/
|
||||||
|
interface IArrayWrapper {
|
||||||
|
/** retourne une référence sur l'array encapsulé */
|
||||||
|
function &wrappedArray(): ?array;
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
namespace nulib;
|
||||||
|
|
||||||
|
use RuntimeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class NoMoreDataException: indiquer que plus aucune donnée n'est disponible
|
||||||
|
*/
|
||||||
|
class NoMoreDataException extends RuntimeException {
|
||||||
|
}
|
|
@ -1,13 +1,13 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nulib;
|
namespace nulib;
|
||||||
|
|
||||||
use Exception;
|
use LogicException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class StateException: indiquer que l'état dans lequel on se trouve est
|
* Class StateException: indiquer que l'état dans lequel on se trouve est
|
||||||
* inattendu: il s'agit donc d'un bug
|
* inattendu: il s'agit donc d'un bug
|
||||||
*/
|
*/
|
||||||
class StateException extends Exception {
|
class StateException extends LogicException {
|
||||||
static final function not_implemented(?string $method=null, ?string $prefix=null): self {
|
static final function not_implemented(?string $method=null, ?string $prefix=null): self {
|
||||||
if ($method === null) $method = "this method";
|
if ($method === null) $method = "this method";
|
||||||
$message = "$method is not implemented";
|
$message = "$method is not implemented";
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
namespace nulib;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class StopException: une exception qui par convention est envoyée à un
|
||||||
|
* générateur pour indiquer qu'il doit s'arrêter "proprement". cela peut être
|
||||||
|
* utilisé pour implémenter des itérateur "closeable"
|
||||||
|
*/
|
||||||
|
class StopException extends Exception {
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
<?php
|
||||||
|
namespace nulib;
|
||||||
|
|
||||||
|
use RuntimeException;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class UserException: une exception qui peut en plus contenir un message
|
||||||
|
* utilisateur
|
||||||
|
*/
|
||||||
|
class UserException extends RuntimeException {
|
||||||
|
/** @param Throwable|ExceptionShadow $e */
|
||||||
|
static function get_user_message($e): ?string {
|
||||||
|
if ($e instanceof self) return $e->getUserMessage();
|
||||||
|
else return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param Throwable|ExceptionShadow $e */
|
||||||
|
static final function get_user_summary($e): string {
|
||||||
|
$parts = [];
|
||||||
|
$first = true;
|
||||||
|
while ($e !== null) {
|
||||||
|
$message = self::get_user_message($e);
|
||||||
|
if (!$message) $message = "(no message)";
|
||||||
|
if ($first) $first = false;
|
||||||
|
else $parts[] = "caused by ";
|
||||||
|
$parts[] = get_class($e) . ": " . $message;
|
||||||
|
$e = $e->getPrevious();
|
||||||
|
}
|
||||||
|
return implode(", ", $parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param Throwable|ExceptionShadow $e */
|
||||||
|
static function get_message($e): ?string {
|
||||||
|
$message = $e->getMessage();
|
||||||
|
if (!$message && $e instanceof self) $message = $e->getUserMessage();
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param Throwable|ExceptionShadow $e */
|
||||||
|
static final function get_summary($e): string {
|
||||||
|
$parts = [];
|
||||||
|
$first = true;
|
||||||
|
while ($e !== null) {
|
||||||
|
$message = self::get_message($e);
|
||||||
|
if (!$message) $message = "(no message)";
|
||||||
|
if ($first) $first = false;
|
||||||
|
else $parts[] = "caused by ";
|
||||||
|
if ($e instanceof ExceptionShadow) $class = $e->getClass();
|
||||||
|
else $class = get_class($e);
|
||||||
|
$parts[] = "$class: $message";
|
||||||
|
$e = $e->getPrevious();
|
||||||
|
}
|
||||||
|
return implode(", ", $parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param Throwable|ExceptionShadow $e */
|
||||||
|
static final function get_traceback($e): string {
|
||||||
|
$tbs = [];
|
||||||
|
$previous = false;
|
||||||
|
while ($e !== null) {
|
||||||
|
if (!$previous) {
|
||||||
|
$efile = $e->getFile();
|
||||||
|
$eline = $e->getLine();
|
||||||
|
$tbs[] = "at $efile($eline)";
|
||||||
|
} else {
|
||||||
|
$tbs[] = "~~ caused by: " . self::get_summary($e);
|
||||||
|
}
|
||||||
|
$tbs[] = $e->getTraceAsString();
|
||||||
|
$e = $e->getPrevious();
|
||||||
|
$previous = true;
|
||||||
|
#XXX il faudrait ne pas réinclure les lignes communes aux exceptions qui
|
||||||
|
# ont déjà été affichées
|
||||||
|
}
|
||||||
|
return implode("\n", $tbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
function __construct($userMessage, $techMessage=null, $code=0, ?Throwable $previous=null) {
|
||||||
|
$this->userMessage = $userMessage;
|
||||||
|
if ($techMessage === null) $techMessage = $userMessage;
|
||||||
|
parent::__construct($techMessage, $code, $previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var ?string */
|
||||||
|
protected $userMessage;
|
||||||
|
|
||||||
|
function getUserMessage(): ?string {
|
||||||
|
return $this->userMessage;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
<?php
|
||||||
|
namespace nulib;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ValueException: indiquer qu'une valeur est invalide
|
||||||
|
*/
|
||||||
|
class ValueException extends UserException {
|
||||||
|
private static function value($value): string {
|
||||||
|
if (is_object($value)) {
|
||||||
|
return "<".get_class($value).">";
|
||||||
|
} elseif (is_array($value)) {
|
||||||
|
$values = $value;
|
||||||
|
$parts = [];
|
||||||
|
$index = 0;
|
||||||
|
foreach ($values as $key => $value) {
|
||||||
|
if ($key === $index) {
|
||||||
|
$index++;
|
||||||
|
$parts[] = self::value($value);
|
||||||
|
} else {
|
||||||
|
$parts[] = "$key=>".self::value($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "[" . implode(", ", $parts) . "]";
|
||||||
|
} elseif (is_string($value)) {
|
||||||
|
return $value;
|
||||||
|
} else {
|
||||||
|
return var_export($value, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function message($value, ?string $message, ?string $kind, ?string $prefix, ?string $suffix): string {
|
||||||
|
if ($kind === null) $kind = "value";
|
||||||
|
if ($message === null) $message = "$kind$suffix";
|
||||||
|
if ($value !== null) {
|
||||||
|
$value = self::value($value);
|
||||||
|
if ($prefix) $prefix = "$prefix: $value";
|
||||||
|
else $prefix = $value;
|
||||||
|
}
|
||||||
|
if ($prefix) $prefix = "$prefix: ";
|
||||||
|
return $prefix.$message;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function null(?string $kind=null, ?string $prefix=null, ?string $message=null): self {
|
||||||
|
return new static(self::message(null, $message, $kind, $prefix, " should not be null"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function invalid_kind($value=null, ?string $kind=null, ?string $prefix=null, ?string $message=null): self {
|
||||||
|
return new static(self::message($value, $message, $kind, $prefix, " is invalid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function invalid_key($value, ?string $prefix=null, ?string $message=null): self {
|
||||||
|
return self::invalid_kind($value, "key", $prefix, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function invalid_value($value, ?string $prefix=null, ?string $message=null): self {
|
||||||
|
return self::invalid_kind($value, "value", $prefix, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function invalid_type($value, string $expected_type): self {
|
||||||
|
return new static(self::message($value, null, "type", null, " is invalid, expected $expected_type"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function invalid_class($class, string $expected_class): self {
|
||||||
|
if (is_object($class)) $class = get_class($class);
|
||||||
|
return new static(self::message($class, null, "class", null, " is invalid, expected $expected_class"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static final function forbidden($value=null, ?string $kind=null, ?string $prefix=null, ?string $message=null): self {
|
||||||
|
return new static(self::message($value, $message, $kind, $prefix, " is forbidden"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
<?php
|
||||||
|
namespace nulib\app;
|
||||||
|
|
||||||
|
use nulib\cl;
|
||||||
|
use nulib\file\SharedFile;
|
||||||
|
use nulib\output\msg;
|
||||||
|
use nulib\php\time\DateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class LockFile: une classe qui permet à une application de verrouiller
|
||||||
|
* certaines actions
|
||||||
|
*/
|
||||||
|
class LockFile {
|
||||||
|
const NAME = null;
|
||||||
|
|
||||||
|
const TITLE = null;
|
||||||
|
|
||||||
|
function __construct($file, ?string $name=null, ?string $title=null) {
|
||||||
|
$this->file = new SharedFile($file);
|
||||||
|
$this->name = $name ?? static::NAME;
|
||||||
|
$this->title = $title ?? static::TITLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var SharedFile */
|
||||||
|
protected $file;
|
||||||
|
|
||||||
|
/** @var ?string */
|
||||||
|
protected $name;
|
||||||
|
|
||||||
|
/** @var ?string */
|
||||||
|
protected $title;
|
||||||
|
|
||||||
|
protected function initData(): array {
|
||||||
|
return [
|
||||||
|
"name" => $this->name,
|
||||||
|
"title" => $this->title,
|
||||||
|
"locked" => false,
|
||||||
|
"date_lock" => null,
|
||||||
|
"date_release" => null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function read(bool $close=true): array {
|
||||||
|
$data = $this->file->unserialize(null, $close);
|
||||||
|
if (!is_array($data)) $data = $this->initData();
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isLocked(?array &$data=null): bool {
|
||||||
|
$data = $this->read();
|
||||||
|
return $data["locked"];
|
||||||
|
}
|
||||||
|
|
||||||
|
function warnIfLocked(?array $data=null): bool {
|
||||||
|
if ($data === null) $data = $this->read();
|
||||||
|
if ($data["locked"]) {
|
||||||
|
msg::warning("$data[name]: possède le verrou depuis $data[date_lock] -- $data[title]");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function lock(?array &$data=null): bool {
|
||||||
|
$file = $this->file;
|
||||||
|
$data = $this->read(false);
|
||||||
|
if ($data["locked"]) {
|
||||||
|
$file->close();
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
$file->ftruncate();
|
||||||
|
$file->serialize(cl::merge($data, [
|
||||||
|
"locked" => true,
|
||||||
|
"date_lock" => new DateTime(),
|
||||||
|
"date_release" => null,
|
||||||
|
]));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function release(?array &$data=null): void {
|
||||||
|
$file = $this->file;
|
||||||
|
$data = $this->read(false);
|
||||||
|
$file->ftruncate();
|
||||||
|
$file->serialize(cl::merge($data, [
|
||||||
|
"locked" => false,
|
||||||
|
"date_release" => new DateTime(),
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,354 @@
|
||||||
|
<?php
|
||||||
|
namespace nulib\app;
|
||||||
|
|
||||||
|
use nulib\cl;
|
||||||
|
use nulib\file\SharedFile;
|
||||||
|
use nulib\os\path;
|
||||||
|
use nulib\output\msg;
|
||||||
|
use nulib\php\time\DateTime;
|
||||||
|
use nulib\str;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class RunFile: une classe permettant de suivre le fonctionnement d'une
|
||||||
|
* application qui tourne en tâche de fond
|
||||||
|
*/
|
||||||
|
class RunFile {
|
||||||
|
const RUN_EXT = ".run";
|
||||||
|
const LOCK_EXT = ".lock";
|
||||||
|
|
||||||
|
const NAME = null;
|
||||||
|
|
||||||
|
function __construct(?string $name, string $file, ?string $logfile=null) {
|
||||||
|
$file = path::ensure_ext($file, self::RUN_EXT);
|
||||||
|
$this->name = $name ?? static::NAME;
|
||||||
|
$this->file = new SharedFile($file);
|
||||||
|
$this->logfile = $logfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ?string $name;
|
||||||
|
|
||||||
|
protected SharedFile $file;
|
||||||
|
|
||||||
|
protected ?string $logfile;
|
||||||
|
|
||||||
|
function getLogfile(): ?string {
|
||||||
|
return $this->logfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function merge(array $data, array $merge): array {
|
||||||
|
return cl::merge($data, [
|
||||||
|
"serial" => $data["serial"] + 1,
|
||||||
|
], $merge);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function initData(bool $forStart=true): array {
|
||||||
|
if ($forStart) {
|
||||||
|
$pid = posix_getpid();
|
||||||
|
$dateStart = new DateTime();
|
||||||
|
} else {
|
||||||
|
$pid = $dateStart = null;
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
"name" => $this->name,
|
||||||
|
"id" => bin2hex(random_bytes(16)),
|
||||||
|
"pg_pid" => null,
|
||||||
|
"pid" => $pid,
|
||||||
|
"serial" => 0,
|
||||||
|
# lock
|
||||||
|
"locked" => false,
|
||||||
|
"date_lock" => null,
|
||||||
|
"date_release" => null,
|
||||||
|
# run
|
||||||
|
"logfile" => $this->logfile,
|
||||||
|
"date_start" => $dateStart,
|
||||||
|
"date_stop" => null,
|
||||||
|
"exitcode" => null,
|
||||||
|
"is_done" => null,
|
||||||
|
# action
|
||||||
|
"action" => null,
|
||||||
|
"action_date_start" => null,
|
||||||
|
"action_current_step" => null,
|
||||||
|
"action_max_step" => null,
|
||||||
|
"action_date_step" => null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function read(): array {
|
||||||
|
$data = $this->file->unserialize();
|
||||||
|
if (!is_array($data)) $data = $this->initData(false);
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function willWrite(): array {
|
||||||
|
$file = $this->file;
|
||||||
|
$file->lockWrite();
|
||||||
|
$data = $file->unserialize(null, false, true);
|
||||||
|
if (!is_array($data)) {
|
||||||
|
$data = $this->initData(false);
|
||||||
|
$file->ftruncate();
|
||||||
|
$file->serialize($data, false, true);
|
||||||
|
}
|
||||||
|
return [$file, $data];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function serialize(SharedFile $file, array $data, ?array $merge=null): void {
|
||||||
|
$file->ftruncate();
|
||||||
|
$file->serialize(self::merge($data, $merge), true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function update(callable $func): void {
|
||||||
|
/** @var SharedFile$file */
|
||||||
|
[$file, $data] = $this->willWrite();
|
||||||
|
$merge = call_user_func($func, $data);
|
||||||
|
if ($merge !== null && $merge !== false) {
|
||||||
|
$this->serialize($file, $data, $merge);
|
||||||
|
} else {
|
||||||
|
$file->cancelWrite();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function haveWorked(int $serial, ?int &$currentSerial=null, ?array $data=null): bool {
|
||||||
|
$data ??= $this->read();
|
||||||
|
$currentSerial = $data["serial"];
|
||||||
|
return $serial !== $currentSerial;
|
||||||
|
}
|
||||||
|
|
||||||
|
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# verrouillage par défaut
|
||||||
|
|
||||||
|
function isLocked(?array &$data=null): bool {
|
||||||
|
$data = $this->read();
|
||||||
|
return $data["locked"];
|
||||||
|
}
|
||||||
|
|
||||||
|
function warnIfLocked(?array $data=null): bool {
|
||||||
|
$data ??= $this->read();
|
||||||
|
if ($data["locked"]) {
|
||||||
|
msg::warning("$data[name]: possède le verrou depuis $data[date_lock]");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function lock(): bool {
|
||||||
|
$this->update(function ($data) use (&$locked) {
|
||||||
|
if ($data["locked"]) {
|
||||||
|
$locked = false;
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
$locked = true;
|
||||||
|
return [
|
||||||
|
"locked" => true,
|
||||||
|
"date_lock" => new DateTime(),
|
||||||
|
"date_release" => null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return $locked;
|
||||||
|
}
|
||||||
|
|
||||||
|
function release(): void {
|
||||||
|
$this->update(function ($data) {
|
||||||
|
return [
|
||||||
|
"locked" => false,
|
||||||
|
"date_release" => new DateTime(),
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# cycle de vie de l'application
|
||||||
|
|
||||||
|
/**
|
||||||
|
* indiquer que l'application démarre. l'état est entièrement réinitialisé,
|
||||||
|
* sauf le PID du leader qui est laissé en l'état
|
||||||
|
*/
|
||||||
|
function wfStart(): void {
|
||||||
|
$this->update(function (array $data) {
|
||||||
|
return cl::merge($this->initData(), [
|
||||||
|
"pg_pid" => $data["pg_pid"],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** tester si l'application a déjà été démarrée au moins une fois */
|
||||||
|
function wasStarted(?array $data=null): bool {
|
||||||
|
$data ??= $this->read();
|
||||||
|
return $data["date_start"] !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** tester si l'application est démarrée et non arrêtée */
|
||||||
|
function isStarted(?array $data=null): bool {
|
||||||
|
$data ??= $this->read();
|
||||||
|
return $data["date_start"] !== null && $data["date_stop"] === null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vérifier si l'application marquée comme démarrée tourne réellement
|
||||||
|
*/
|
||||||
|
function isRunning(?array $data=null): bool {
|
||||||
|
$data ??= $this->read();
|
||||||
|
if ($data["date_start"] === null) return false;
|
||||||
|
if ($data["date_stop"] !== null) return false;
|
||||||
|
if (!posix_kill($data["pid"], 0)) {
|
||||||
|
switch (posix_get_last_error()) {
|
||||||
|
case 1: #PCNTL_EPERM:
|
||||||
|
# process auquel on n'a pas accès?! est-ce un autre process qui a
|
||||||
|
# réutilisé le PID?
|
||||||
|
return false;
|
||||||
|
case 3: #PCNTL_ESRCH:
|
||||||
|
# process inexistant
|
||||||
|
return false;
|
||||||
|
case 22: #PCNTL_EINVAL:
|
||||||
|
# ne devrait pas se produire
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# process existant auquel on a accès
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** indiquer que l'application s'arrête */
|
||||||
|
function wfStop(): void {
|
||||||
|
$this->update(function (array $data) {
|
||||||
|
return ["date_stop" => new DateTime()];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** tester si l'application est déjà été stoppée au moins une fois */
|
||||||
|
function wasStopped(?array $data=null): bool {
|
||||||
|
$data ??= $this->read();
|
||||||
|
return $data["date_stop"] !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** tester si l'application a été démarrée puis arrêtée */
|
||||||
|
function isStopped(?array $data=null): bool {
|
||||||
|
$data ??= $this->read();
|
||||||
|
return $data["date_start"] !== null && $data["date_stop"] !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** après l'arrêt de l'application, mettre à jour le code de retour */
|
||||||
|
function wfStopped(int $exitcode): void {
|
||||||
|
$this->update(function (array $data) use ($exitcode) {
|
||||||
|
return [
|
||||||
|
"pg_pid" => null,
|
||||||
|
"date_stop" => $data["date_stop"] ?? new DateTime(),
|
||||||
|
"exitcode" => $exitcode,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* comme {@link self::isStopped()} mais ne renvoie true qu'une seule fois si
|
||||||
|
* $updateDone==true
|
||||||
|
*/
|
||||||
|
function isDone(?array &$data=null, bool $updateDone=true): bool {
|
||||||
|
$done = false;
|
||||||
|
$this->update(function (array $ldata) use (&$done, &$data, $updateDone) {
|
||||||
|
$data = $ldata;
|
||||||
|
if ($data["date_start"] === null || $data["date_stop"] === null || $data["is_done"]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$done = true;
|
||||||
|
if ($updateDone) return ["is_done" => $done];
|
||||||
|
else return null;
|
||||||
|
});
|
||||||
|
return $done;
|
||||||
|
}
|
||||||
|
|
||||||
|
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# gestion des actions
|
||||||
|
|
||||||
|
/** indiquer le début d'une action */
|
||||||
|
function action(?string $title, ?int $maxSteps=null): void {
|
||||||
|
$this->update(function (array $data) use ($title, $maxSteps) {
|
||||||
|
return [
|
||||||
|
"action" => $title,
|
||||||
|
"action_date_start" => new DateTime(),
|
||||||
|
"action_max_step" => $maxSteps,
|
||||||
|
"action_current_step" => 0,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** indiquer qu'une étape est franchie dans l'action en cours */
|
||||||
|
function step(int $nbSteps=1): void {
|
||||||
|
$this->update(function (array $data) use ($nbSteps) {
|
||||||
|
return [
|
||||||
|
"action_date_step" => new DateTime(),
|
||||||
|
"action_current_step" => $data["action_current_step"] + $nbSteps,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# Divers
|
||||||
|
|
||||||
|
function getLockFile(?string $name=null, ?string $title=null): LockFile {
|
||||||
|
$ext = self::LOCK_EXT;
|
||||||
|
if ($name !== null) $ext = ".$name$ext";
|
||||||
|
$file = path::ensure_ext($this->file->getFile(), $ext, self::RUN_EXT);
|
||||||
|
$name = str::join("/", [$this->name, $name]);
|
||||||
|
return new LockFile($file, $name, $title);
|
||||||
|
}
|
||||||
|
|
||||||
|
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# Gestionnaire de tâches (tm_*)
|
||||||
|
|
||||||
|
/** démarrer un groupe de process dont le process courant est le leader */
|
||||||
|
function tm_startPg(): void {
|
||||||
|
$this->update(function (array $data) {
|
||||||
|
posix_setsid();
|
||||||
|
return [
|
||||||
|
"pg_pid" => posix_getpid(),
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vérifier si on est dans le cas où la tâche devrait tourner mais en réalité
|
||||||
|
* ce n'est pas le cas
|
||||||
|
*/
|
||||||
|
function tm_isUndead(?int $pid=null): bool {
|
||||||
|
$data = $this->read();
|
||||||
|
if ($data["date_start"] === null) return false;
|
||||||
|
if ($data["date_stop"] !== null) return false;
|
||||||
|
$pid ??= $data["pid"];
|
||||||
|
if (!posix_kill($pid, 0)) {
|
||||||
|
switch (posix_get_last_error()) {
|
||||||
|
case 1: #PCNTL_EPERM:
|
||||||
|
# process auquel on n'a pas accès?! est-ce un autre process qui a
|
||||||
|
# réutilisé le PID?
|
||||||
|
return false;
|
||||||
|
case 3: #PCNTL_ESRCH:
|
||||||
|
# process inexistant
|
||||||
|
return true;
|
||||||
|
case 22: #PCNTL_EINVAL:
|
||||||
|
# ne devrait pas se produire
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# process existant auquel on a accès
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tm_isReapable(): bool {
|
||||||
|
$data = $this->read();
|
||||||
|
return $data["date_stop"] !== null && $data["exitcode"] === null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** marquer la tâche comme terminée */
|
||||||
|
function tm_reap(?int $pid=null): void {
|
||||||
|
$data = $this->read();
|
||||||
|
$pid ??= $data["pid"];
|
||||||
|
pcntl_waitpid($pid, $status);
|
||||||
|
$exitcode = pcntl_wifexited($status)? pcntl_wexitstatus($status): 127;
|
||||||
|
$this->update(function (array $data) use ($exitcode) {
|
||||||
|
return [
|
||||||
|
"pg_pid" => null,
|
||||||
|
"date_stop" => $data["date_stop"] ?? new DateTime(),
|
||||||
|
"exitcode" => $data["exitcode"] ?? $exitcode,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,136 @@
|
||||||
|
<?php
|
||||||
|
namespace nulib\app;
|
||||||
|
|
||||||
|
use nulib\cl;
|
||||||
|
use nulib\file\TmpfileWriter;
|
||||||
|
use nulib\os\path;
|
||||||
|
use nulib\os\proc\Cmd;
|
||||||
|
use nulib\output\msg;
|
||||||
|
use nulib\StateException;
|
||||||
|
use nulib\str;
|
||||||
|
use nulib\wip\app\app;
|
||||||
|
|
||||||
|
class launcher {
|
||||||
|
/**
|
||||||
|
* transformer une liste d'argument de la forme
|
||||||
|
* - ["myArg" => $value] devient ["--my-arg", "$value"]
|
||||||
|
* - ["myOpt" => true] devient ["--my-opt"]
|
||||||
|
* - ["myOpt" => false] est momis
|
||||||
|
* - les valeurs séquentielles sont prises telles quelles
|
||||||
|
*/
|
||||||
|
static function verifix_args(array $args): array {
|
||||||
|
if (!cl::is_list($args)) {
|
||||||
|
$fixedArgs = [];
|
||||||
|
$index = 0;
|
||||||
|
foreach ($args as $arg => $value) {
|
||||||
|
if ($arg === $index) {
|
||||||
|
$index++;
|
||||||
|
$fixedArgs[] = $value;
|
||||||
|
continue;
|
||||||
|
} elseif ($value === false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$arg = str::us2camel($arg);
|
||||||
|
$arg = str::camel2us($arg, false, "-");
|
||||||
|
$arg = str_replace("_", "-", $arg);
|
||||||
|
$fixedArgs[] = "--$arg";
|
||||||
|
if ($value !== true) $fixedArgs[] = "$value";
|
||||||
|
}
|
||||||
|
$args = $fixedArgs;
|
||||||
|
}
|
||||||
|
# corriger le chemin de l'application pour qu'il soit absolu et normalisé
|
||||||
|
$args[0] = path::abspath($args[0]);
|
||||||
|
return $args;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function launch(string $appClass, array $args): int {
|
||||||
|
$app = app::get();
|
||||||
|
$vendorBindir = $app->getVendorbindir();
|
||||||
|
$launch_php = "$vendorBindir/_launch.php";
|
||||||
|
if (!file_exists($launch_php)) {
|
||||||
|
$launch_php = __DIR__."/../../lib/_launch.php";
|
||||||
|
}
|
||||||
|
$tmpfile = new TmpfileWriter();
|
||||||
|
$tmpfile->keep()->serialize($app->getParams());
|
||||||
|
|
||||||
|
$args = self::verifix_args($args);
|
||||||
|
$cmd = new Cmd([
|
||||||
|
$launch_php,
|
||||||
|
"--internal-use", $tmpfile->getFile(),
|
||||||
|
$appClass, "--", ...$args,
|
||||||
|
]);
|
||||||
|
$cmd->addRedir("both", "/tmp/nulib_app_launcher-launch.log");
|
||||||
|
$cmd->passthru($exitcode);
|
||||||
|
|
||||||
|
# attendre un peu que la commande aie le temps de s'initialiser
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
$tmpfile->close();
|
||||||
|
return $exitcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function _start(array $args, Runfile $runfile): bool {
|
||||||
|
if ($runfile->warnIfLocked()) return false;
|
||||||
|
$pid = pcntl_fork();
|
||||||
|
if ($pid == -1) {
|
||||||
|
# parent, impossible de forker
|
||||||
|
throw new StateException("unable to fork");
|
||||||
|
} elseif ($pid) {
|
||||||
|
# parent, fork ok
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
## child, fork ok
|
||||||
|
# Créer un groupe de process, pour pouvoir tuer tous les enfants en même temps
|
||||||
|
$runfile->tm_startPg();
|
||||||
|
$logfile = $runfile->getLogfile() ?? "/tmp/nulib_app_launcher-_start.log";
|
||||||
|
$pid = posix_getpid();
|
||||||
|
$exitcode = -776;
|
||||||
|
try {
|
||||||
|
# puis lancer la commande
|
||||||
|
$cmd = new Cmd($args);
|
||||||
|
$cmd->addSource("/g/init.env");
|
||||||
|
$cmd->addRedir("both", $logfile, true);
|
||||||
|
msg::debug("$pid: launching\n".$cmd->getCmd());
|
||||||
|
$cmd->fork_exec($exitcode);
|
||||||
|
msg::debug("$pid: exitcode=$exitcode");
|
||||||
|
return true;
|
||||||
|
} finally {
|
||||||
|
$runfile->wfStopped($exitcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static function _stop(Runfile $runfile): void {
|
||||||
|
$data = $runfile->read();
|
||||||
|
$pid = $data["pg_pid"];
|
||||||
|
if ($pid === null) {
|
||||||
|
msg::warning("$data[name]: groupe de process inconnu");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
msg::action("kill $pid");
|
||||||
|
if (!posix_kill(-$pid, SIGKILL)) {
|
||||||
|
switch (posix_get_last_error()) {
|
||||||
|
case PCNTL_ESRCH:
|
||||||
|
msg::afailure("process inexistant");
|
||||||
|
break;
|
||||||
|
case PCNTL_EPERM:
|
||||||
|
msg::afailure("process non accessible");
|
||||||
|
break;
|
||||||
|
case PCNTL_EINVAL:
|
||||||
|
msg::afailure("signal invalide");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$timeout = 10;
|
||||||
|
while ($runfile->tm_isUndead($pid)) {
|
||||||
|
sleep(1);
|
||||||
|
if (--$timeout == 0) {
|
||||||
|
msg::afailure("impossible d'arrêter la tâche");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$runfile->wfStopped(-778);
|
||||||
|
msg::asuccess();
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,50 +2,111 @@
|
||||||
namespace nulib;
|
namespace nulib;
|
||||||
|
|
||||||
use ArrayAccess;
|
use ArrayAccess;
|
||||||
|
use nulib\php\func;
|
||||||
use Traversable;
|
use Traversable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class cl: gestion de tableau de valeurs scalaires
|
* Class cl: gestion de tableaux ou d'instances de {@link ArrayAccess} le cas
|
||||||
|
* échéant
|
||||||
|
*
|
||||||
|
* contrairement à {@link A}, les méthodes de cette classes sont plutôt conçues
|
||||||
|
* pour retourner un nouveau tableau
|
||||||
*/
|
*/
|
||||||
class cl {
|
class cl {
|
||||||
|
/**
|
||||||
|
* retourner un array avec les éléments retournés par l'itérateur. les clés
|
||||||
|
* numériques sont réordonnées, les clés chaine sont laissées en l'état
|
||||||
|
*/
|
||||||
|
static final function all(?iterable $iterable): array {
|
||||||
|
if ($iterable === null) return [];
|
||||||
|
if (is_array($iterable)) return $iterable;
|
||||||
|
$array = [];
|
||||||
|
foreach ($iterable as $key => $value) {
|
||||||
|
if (is_int($key)) $array[] = $value;
|
||||||
|
else $array[$key] = $value;
|
||||||
|
}
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retourner la première valeur de $array ou $default si le tableau est null
|
||||||
|
* ou vide
|
||||||
|
*/
|
||||||
|
static final function first(?iterable $iterable, $default=null) {
|
||||||
|
if (is_array($iterable)) {
|
||||||
|
$key = array_key_first($iterable);
|
||||||
|
if ($key === null) return $default;
|
||||||
|
return $iterable[$key];
|
||||||
|
}
|
||||||
|
if (is_iterable($iterable)) {
|
||||||
|
foreach ($iterable as $value) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retourner la dernière valeur de $array ou $default si le tableau est null
|
||||||
|
* ou vide
|
||||||
|
*/
|
||||||
|
static final function last(?iterable $iterable, $default=null) {
|
||||||
|
if (is_array($iterable)) {
|
||||||
|
$key = array_key_last($iterable);
|
||||||
|
if ($key === null) return $default;
|
||||||
|
return $iterable[$key];
|
||||||
|
}
|
||||||
|
$value = $default;
|
||||||
|
if (is_iterable($iterable)) {
|
||||||
|
foreach ($iterable as $value) {
|
||||||
|
# parcourir tout l'iterateur pour avoir le dernier élément
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
/** retourner un array non null à partir de $array */
|
/** retourner un array non null à partir de $array */
|
||||||
static final function with($array): array {
|
static final function with($array): array {
|
||||||
|
if ($array instanceof IArrayWrapper) $array = $array->wrappedArray();
|
||||||
if (is_array($array)) return $array;
|
if (is_array($array)) return $array;
|
||||||
elseif ($array === null || $array === false) return [];
|
elseif ($array === null || $array === false) return [];
|
||||||
elseif ($array instanceof Traversable) return iterator_to_array($array);
|
elseif ($array instanceof Traversable) return self::all($array);
|
||||||
else return [$array];
|
else return [$array];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** retourner un array à partir de $array, ou null */
|
/** retourner un array à partir de $array, ou null */
|
||||||
static final function withn($array): ?array {
|
static final function withn($array): ?array {
|
||||||
|
if ($array instanceof IArrayWrapper) $array = $array->wrappedArray();
|
||||||
if (is_array($array)) return $array;
|
if (is_array($array)) return $array;
|
||||||
elseif ($array === null || $array === false) return null;
|
elseif ($array === null || $array === false) return null;
|
||||||
elseif ($array instanceof Traversable) return iterator_to_array($array);
|
elseif ($array instanceof Traversable) return self::all($array);
|
||||||
else return [$array];
|
else return [$array];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** tester si $array a au moins une clé numérique */
|
||||||
* s'assurer que $array est un array non null. retourner true si $array n'a
|
static final function have_num_keys(?array $array): bool {
|
||||||
* pas été modifié (s'il était déjà un array), false sinon.
|
if ($array === null) return false;
|
||||||
*/
|
foreach ($array as $key => $value) {
|
||||||
static final function ensure_array(&$array): bool {
|
if (is_int($key)) return true;
|
||||||
if (is_array($array)) return true;
|
}
|
||||||
elseif ($array === null || $array === false) $array = [];
|
|
||||||
elseif ($array instanceof Traversable) $array = iterator_to_array($array);
|
|
||||||
else $array = [$array];
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* s'assurer que $array est un array s'il est non null. retourner true si
|
* tester si $array est une liste, c'est à dire un tableau non null avec
|
||||||
* $array n'a pas été modifié (s'il était déjà un array ou s'il valait null).
|
* uniquement des clés numériques séquentielles commençant à zéro
|
||||||
|
*
|
||||||
|
* NB: is_list(null) === false
|
||||||
|
* et is_list([]) === true
|
||||||
*/
|
*/
|
||||||
static final function ensure_narray(&$array): bool {
|
static final function is_list(?array $array): bool {
|
||||||
if ($array === null || is_array($array)) return true;
|
if ($array === null) return false;
|
||||||
elseif ($array === false) $array = [];
|
$index = -1;
|
||||||
elseif ($array instanceof Traversable) $array = iterator_to_array($array);
|
foreach ($array as $key => $value) {
|
||||||
else $array = [$array];
|
++$index;
|
||||||
return false;
|
if ($key !== $index) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,6 +137,128 @@ class cl {
|
||||||
return $default;
|
return $default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retourner un tableau construit à partir des clés de $keys
|
||||||
|
* - [$to => $from] --> $dest[$to] = self::get($array, $from)
|
||||||
|
* - [$to => null] --> $dest[$to] = null
|
||||||
|
* - [$to => false] --> NOP
|
||||||
|
* - [$to] --> $dest[$to] = self::get($array, $to)
|
||||||
|
* - [null] --> $dest[] = null
|
||||||
|
* - [false] --> NOP
|
||||||
|
*
|
||||||
|
* Si $inverse===true, le mapping est inversé:
|
||||||
|
* - [$to => $from] --> $dest[$from] = self::get($array, $to)
|
||||||
|
* - [$to => null] --> $dest[$to] = self::get($array, $to)
|
||||||
|
* - [$to => false] --> NOP
|
||||||
|
* - [$to] --> $dest[$to] = self::get($array, $to)
|
||||||
|
* - [null] --> NOP (XXX que faire dans ce cas?)
|
||||||
|
* - [false] --> NOP
|
||||||
|
*
|
||||||
|
* notez que l'ordre est inversé par rapport à {@link self::rekey()} qui
|
||||||
|
* attend des mappings [$from => $to], alors que cette méthode attend des
|
||||||
|
* mappings [$to => $from]
|
||||||
|
*/
|
||||||
|
static final function select($array, ?array $mappings, bool $inverse=false): array {
|
||||||
|
$dest = [];
|
||||||
|
$index = 0;
|
||||||
|
if (!$inverse) {
|
||||||
|
foreach ($mappings as $to => $from) {
|
||||||
|
if ($to === $index) {
|
||||||
|
$index++;
|
||||||
|
$to = $from;
|
||||||
|
if ($to === false) continue;
|
||||||
|
elseif ($to === null) $dest[] = null;
|
||||||
|
else $dest[$to] = self::get($array, $to);
|
||||||
|
} elseif ($from === false) {
|
||||||
|
continue;
|
||||||
|
} elseif ($from === null) {
|
||||||
|
$dest[$to] = null;
|
||||||
|
} else {
|
||||||
|
$dest[$to] = self::get($array, $from);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach ($mappings as $to => $from) {
|
||||||
|
if ($to === $index) {
|
||||||
|
$index++;
|
||||||
|
$to = $from;
|
||||||
|
if ($to === false) continue;
|
||||||
|
elseif ($to === null) continue;
|
||||||
|
else $dest[$to] = self::get($array, $to);
|
||||||
|
} elseif ($from === false) {
|
||||||
|
continue;
|
||||||
|
} elseif ($from === null) {
|
||||||
|
$dest[$to] = self::get($array, $to);
|
||||||
|
} else {
|
||||||
|
$dest[$from] = self::get($array, $to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* obtenir la liste des clés finalement obtenues après l'appel à
|
||||||
|
* {@link self::select()} avec le mapping spécifié
|
||||||
|
*/
|
||||||
|
static final function selected_keys(?array $mappings): array {
|
||||||
|
if ($mappings === null) return [];
|
||||||
|
$keys = [];
|
||||||
|
$index = 0;
|
||||||
|
foreach ($mappings as $to => $from) {
|
||||||
|
if ($to === $index) {
|
||||||
|
if ($from === false) continue;
|
||||||
|
elseif ($from === null) $keys[] = $index;
|
||||||
|
else $keys[] = $from;
|
||||||
|
$index++;
|
||||||
|
} elseif ($from === false) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
$keys[] = $to;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* méthode de convenance qui sélectionne certaines clés de $array avec
|
||||||
|
* {@link self::select()} puis merge le tableau $merge au résultat.
|
||||||
|
*/
|
||||||
|
static final function selectm($array, ?array $mappings, ?array $merge=null): array {
|
||||||
|
return cl::merge(self::select($array, $mappings), $merge);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* méthode de convenance qui merge $merge dans $array puis sélectionne
|
||||||
|
* certaines clés avec {@link self::select()}
|
||||||
|
*/
|
||||||
|
static final function mselect($array, ?array $merge, ?array $mappings): array {
|
||||||
|
return self::select(cl::merge($array, $merge), $mappings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* construire un sous-ensemble du tableau $array en sélectionnant les clés de
|
||||||
|
* $includes qui ne sont pas mentionnées dans $excludes.
|
||||||
|
*
|
||||||
|
* - si $includes===null && $excludes===null, retourner le tableau inchangé
|
||||||
|
* - si $includes vaut null, prendre toutes les clés
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static final function xselect($array, ?array $includes, ?array $excludes=null): ?array {
|
||||||
|
if ($array === null) return null;
|
||||||
|
$array = self::withn($array);
|
||||||
|
if ($includes === null && $excludes === null) return $array;
|
||||||
|
if ($includes === null) $includes = array_keys($array);
|
||||||
|
if ($excludes === null) $excludes = [];
|
||||||
|
$result = [];
|
||||||
|
foreach ($array as $key => $value) {
|
||||||
|
if (!in_array($key, $includes)) continue;
|
||||||
|
if (in_array($key, $excludes)) continue;
|
||||||
|
$result[$key] = $value;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* si $array est un array ou une instance de ArrayAccess, créer ou modifier
|
* si $array est un array ou une instance de ArrayAccess, créer ou modifier
|
||||||
* l'élément dont la clé est $key
|
* l'élément dont la clé est $key
|
||||||
|
@ -119,29 +302,63 @@ class cl {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fusionner tous les tableaux spécifiés. Les valeurs null sont ignorées.
|
* Fusionner tous les tableaux spécifiés. Les valeurs null sont ignorées.
|
||||||
|
* IMPORTANT: les clés numériques sont réordonnées.
|
||||||
* Retourner null si aucun tableau n'est fourni ou s'ils étaient tous null.
|
* Retourner null si aucun tableau n'est fourni ou s'ils étaient tous null.
|
||||||
*/
|
*/
|
||||||
static final function merge(...$arrays): ?array {
|
static final function merge(...$arrays): ?array {
|
||||||
$merges = [];
|
$merges = [];
|
||||||
foreach ($arrays as $array) {
|
foreach ($arrays as $array) {
|
||||||
self::ensure_narray($array);
|
A::ensure_narray($array);
|
||||||
if ($array !== null) $merges[] = $array;
|
if ($array !== null) $merges[] = $array;
|
||||||
}
|
}
|
||||||
return $merges? array_merge(...$merges): null;
|
return $merges? array_merge(...$merges): null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fusionner tous les tableaux spécifiés. Les valeurs null sont ignorées.
|
||||||
|
* IMPORTANT: les clés numériques NE SONT PAS réordonnées.
|
||||||
|
* Retourner null si aucun tableau n'est fourni ou s'ils étaient tous null.
|
||||||
|
*/
|
||||||
|
static final function merge2(...$arrays): ?array {
|
||||||
|
$merged = null;
|
||||||
|
foreach ($arrays as $array) {
|
||||||
|
foreach (self::with($array) as $key => $value) {
|
||||||
|
$merged[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $merged;
|
||||||
|
}
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
static final function map(callable $callback, ?iterable $array): array {
|
||||||
|
$result = [];
|
||||||
|
if ($array !== null) {
|
||||||
|
$ctx = func::_prepare($callback);
|
||||||
|
foreach ($array as $key => $value) {
|
||||||
|
$result[$key] = func::_call($ctx, [$value, $key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vérifier que le chemin $keys existe dans le tableau $array
|
* vérifier que le chemin $keys existe dans le tableau $array
|
||||||
*
|
*
|
||||||
* si $keys est vide ou null, retourner true
|
* si $pkey est vide ou null, retourner true
|
||||||
*/
|
*/
|
||||||
static final function phas($array, $pkey): bool {
|
static final function phas($array, $pkey): bool {
|
||||||
if ($pkey !== null && !is_array($pkey)) {
|
# optimisations
|
||||||
|
if ($pkey === null || $pkey === []) {
|
||||||
|
return true;
|
||||||
|
} elseif (is_int($pkey) || (is_string($pkey) && strpos($pkey, ".") === false)) {
|
||||||
|
return self::has($array, $pkey);
|
||||||
|
} elseif (!is_array($pkey)) {
|
||||||
$pkey = explode(".", strval($pkey));
|
$pkey = explode(".", strval($pkey));
|
||||||
}
|
}
|
||||||
if ($pkey === null || $pkey === []) return true;
|
# phas
|
||||||
$first = true;
|
$first = true;
|
||||||
foreach($pkey as $key) {
|
foreach($pkey as $key) {
|
||||||
if ($key === "" && $first) {
|
if ($key === "" && $first) {
|
||||||
|
@ -174,13 +391,18 @@ class cl {
|
||||||
/**
|
/**
|
||||||
* obtenir la valeur correspondant au chemin $keys dans $array
|
* obtenir la valeur correspondant au chemin $keys dans $array
|
||||||
*
|
*
|
||||||
* si $keys est vide ou null, retourner $default
|
* si $pkey est vide ou null, retourner $default
|
||||||
*/
|
*/
|
||||||
static final function pget($array, $pkey, $default=null) {
|
static final function pget($array, $pkey, $default=null) {
|
||||||
if ($pkey !== null && !is_array($pkey)) {
|
# optimisations
|
||||||
|
if ($pkey === null || $pkey === []) return $default;
|
||||||
|
elseif ($pkey === "") return $array;
|
||||||
|
elseif (is_int($pkey) || (is_string($pkey) && strpos($pkey, ".") === false)) {
|
||||||
|
return self::get($array, $pkey, $default);
|
||||||
|
} elseif (!is_array($pkey)) {
|
||||||
$pkey = explode(".", strval($pkey));
|
$pkey = explode(".", strval($pkey));
|
||||||
}
|
}
|
||||||
if ($pkey === null || $pkey === []) return true;
|
# pget
|
||||||
$value = $array;
|
$value = $array;
|
||||||
$first = true;
|
$first = true;
|
||||||
foreach($pkey as $key) {
|
foreach($pkey as $key) {
|
||||||
|
@ -211,25 +433,78 @@ class cl {
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retourner un tableau construit à partir des chemins de clé de $pkeys
|
||||||
|
* ces chemins peuvent être exprimés de plusieurs façon:
|
||||||
|
* - [$key => $pkey] --> $dest[$key] = self::pget($array, $pkey)
|
||||||
|
* - [$key => null] --> $dest[$key] = null
|
||||||
|
* - [$pkey] --> $dest[$key] = self::pget($array, $pkey)
|
||||||
|
* avec $key = implode("__", $pkey))
|
||||||
|
* - [null] --> $dest[] = null
|
||||||
|
* - [false] --> NOP
|
||||||
|
*/
|
||||||
|
static final function pselect($array, ?array $pkeys): array {
|
||||||
|
$dest = [];
|
||||||
|
$index = 0;
|
||||||
|
foreach ($pkeys as $key => $pkey) {
|
||||||
|
if ($key === $index) {
|
||||||
|
$index++;
|
||||||
|
if ($pkey === null) continue;
|
||||||
|
$value = self::pget($array, $pkey);
|
||||||
|
if (!is_array($pkey)) $pkey = explode(".", strval($pkey));
|
||||||
|
$key = implode("__", $pkey);
|
||||||
|
} elseif ($pkey === null) {
|
||||||
|
$value = null;
|
||||||
|
} else {
|
||||||
|
$value = self::pget($array, $pkey);
|
||||||
|
}
|
||||||
|
$dest[$key] = $value;
|
||||||
|
}
|
||||||
|
return $dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* méthode de convenance qui sélectionne certaines clés de $array avec
|
||||||
|
* {@link self::pselect()} puis merge le tableau $merge au résultat.
|
||||||
|
*/
|
||||||
|
static final function pselectm($array, ?array $pkeys, ?array $merge=null): array {
|
||||||
|
return cl::merge(self::pselect($array, $pkeys), $merge);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* méthode de convenance qui merge $merge dans $array puis sélectionne
|
||||||
|
* certaines clés avec {@link self::pselect()}
|
||||||
|
*/
|
||||||
|
static final function mpselect($array, ?array $merge, ?array $mappings): array {
|
||||||
|
return self::pselect(cl::merge($array, $merge), $mappings);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* modifier la valeur au chemin de clé $keys dans le tableau $array
|
* modifier la valeur au chemin de clé $keys dans le tableau $array
|
||||||
*
|
*
|
||||||
* utiliser la clé "" (chaine vide) en dernière position pour rajouter à la fin, e.g
|
* utiliser la clé "" (chaine vide) en dernière position pour rajouter à la fin, e.g
|
||||||
* - _pset($array, [""], $value) est équivalent à $array[] = $value
|
* - pset($array, [""], $value) est équivalent à $array[] = $value
|
||||||
* - _pset($array, ["a", "b", ""], $value) est équivalent à $array["a"]["b"][] = $value
|
* - pset($array, ["a", "b", ""], $value) est équivalent à $array["a"]["b"][] = $value
|
||||||
* la clé "" n'a pas de propriété particulière quand elle n'est pas en dernière position
|
* la clé "" n'a pas de propriété particulière quand elle n'est pas en dernière position
|
||||||
*
|
*
|
||||||
* si $keys est vide ou null, $array est remplacé par $value
|
* si $pkey est vide ou null, $array est remplacé par $value
|
||||||
*/
|
*/
|
||||||
static final function pset(&$array, $pkey, $value): void {
|
static final function pset(&$array, $pkey, $value): void {
|
||||||
if ($pkey !== null && !is_array($pkey)) {
|
# optimisations
|
||||||
$pkey = explode(".", strval($pkey));
|
|
||||||
}
|
|
||||||
if ($pkey === null || $pkey === []) {
|
if ($pkey === null || $pkey === []) {
|
||||||
$array = $value;
|
$array = $value;
|
||||||
return;
|
return;
|
||||||
|
} elseif ($pkey === "") {
|
||||||
|
$array[] = $value;
|
||||||
|
return;
|
||||||
|
} elseif (is_int($pkey) || (is_string($pkey) && strpos($pkey, ".") === false)) {
|
||||||
|
self::set($array, $pkey, $value);
|
||||||
|
return;
|
||||||
|
} elseif (!is_array($pkey)) {
|
||||||
|
$pkey = explode(".", strval($pkey));
|
||||||
}
|
}
|
||||||
self::ensure_array($array);
|
# pset
|
||||||
|
A::ensure_array($array);
|
||||||
$current =& $array;
|
$current =& $array;
|
||||||
$key = null;
|
$key = null;
|
||||||
$last = count($pkey) - 1;
|
$last = count($pkey) - 1;
|
||||||
|
@ -245,7 +520,7 @@ class cl {
|
||||||
$current = [$current];
|
$current = [$current];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self::ensure_array($current[$key]);
|
A::ensure_array($current[$key]);
|
||||||
$current =& $current[$key];
|
$current =& $current[$key];
|
||||||
}
|
}
|
||||||
$i++;
|
$i++;
|
||||||
|
@ -262,28 +537,27 @@ class cl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* supprimer la valeur au chemin $keys fourni sous forme de tableau
|
|
||||||
*/
|
|
||||||
static final function pdel_a(&$array, ?array $pkey): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* supprimer la valeur au chemin de clé $keys dans $array
|
* supprimer la valeur au chemin de clé $keys dans $array
|
||||||
*
|
*
|
||||||
* si $array vaut null ou false, sa valeur est inchangée.
|
* si $array vaut null ou false, sa valeur est inchangée.
|
||||||
* si $keys est vide ou null, $array devient null
|
* si $pkey est vide ou null, $array devient null
|
||||||
*/
|
*/
|
||||||
static final function pdel(&$array, $pkey): void {
|
static final function pdel(&$array, $pkey): void {
|
||||||
if ($array === false || $array === null) return;
|
# optimisations
|
||||||
if ($pkey !== null && !is_array($pkey)) {
|
if ($array === null || $array === false) {
|
||||||
$pkey = explode(".", strval($pkey));
|
return;
|
||||||
}
|
} elseif ($pkey === null || $pkey === []) {
|
||||||
if ($pkey === null || $pkey === []) {
|
|
||||||
$array = null;
|
$array = null;
|
||||||
return;
|
return;
|
||||||
|
} elseif (is_int($pkey) || (is_string($pkey) && strpos($pkey, ".") === false)) {
|
||||||
|
self::del($array, $pkey);
|
||||||
|
return;
|
||||||
|
} elseif (!is_array($pkey)) {
|
||||||
|
$pkey = explode(".", strval($pkey));
|
||||||
}
|
}
|
||||||
self::ensure_array($array);
|
# pdel
|
||||||
|
A::ensure_array($array);
|
||||||
$current =& $array;
|
$current =& $array;
|
||||||
$key = null;
|
$key = null;
|
||||||
$last = count($pkey) - 1;
|
$last = count($pkey) - 1;
|
||||||
|
@ -322,9 +596,12 @@ class cl {
|
||||||
/**
|
/**
|
||||||
* retourner le tableau $array en "renommant" les clés selon le tableau
|
* retourner le tableau $array en "renommant" les clés selon le tableau
|
||||||
* $mappings qui contient des associations de la forme [$from => $to]
|
* $mappings qui contient des associations de la forme [$from => $to]
|
||||||
|
*
|
||||||
|
* Si $inverse===true, renommer dans le sens $to => $from
|
||||||
*/
|
*/
|
||||||
static function rekey(?array $array, ?array $mappings): ?array {
|
static function rekey(?array $array, ?array $mappings, bool $inverse=false): ?array {
|
||||||
if ($array === null || $mappings === null) return $array;
|
if ($array === null || $mappings === null) return $array;
|
||||||
|
if ($inverse) $mappings = array_flip($mappings);
|
||||||
$mapped = [];
|
$mapped = [];
|
||||||
foreach ($array as $key => $value) {
|
foreach ($array as $key => $value) {
|
||||||
if (array_key_exists($key, $mappings)) $key = $mappings[$key];
|
if (array_key_exists($key, $mappings)) $key = $mappings[$key];
|
||||||
|
@ -333,6 +610,19 @@ class cl {
|
||||||
return $mapped;
|
return $mapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* indiquer si {@link self::rekey()} modifierai le tableau indiqué (s'il y a
|
||||||
|
* des modifications à faire)
|
||||||
|
*/
|
||||||
|
static function would_rekey(?array $array, ?array $mappings, bool $inverse=false): bool {
|
||||||
|
if ($array === null || $mappings === null) return false;
|
||||||
|
if ($inverse) $mappings = array_flip($mappings);
|
||||||
|
foreach ($array as $key => $value) {
|
||||||
|
if (array_key_exists($key, $mappings)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
||||||
/** tester si tous les éléments du tableau satisfont la condition */
|
/** tester si tous les éléments du tableau satisfont la condition */
|
||||||
|
@ -445,10 +735,10 @@ class cl {
|
||||||
static final function compare(array $keys): callable {
|
static final function compare(array $keys): callable {
|
||||||
return function ($a, $b) use ($keys) {
|
return function ($a, $b) use ($keys) {
|
||||||
foreach ($keys as $key) {
|
foreach ($keys as $key) {
|
||||||
if (cstr::del_prefix($key, "+")) $w = 1;
|
if (str::del_prefix($key, "+")) $w = 1;
|
||||||
elseif (cstr::del_prefix($key, "-")) $w = -1;
|
elseif (str::del_prefix($key, "-")) $w = -1;
|
||||||
elseif (cstr::del_suffix($key, "|asc")) $w = 1;
|
elseif (str::del_suffix($key, "|asc")) $w = 1;
|
||||||
elseif (cstr::del_suffix($key, "|desc")) $w = -1;
|
elseif (str::del_suffix($key, "|desc")) $w = -1;
|
||||||
else $w = 1;
|
else $w = 1;
|
||||||
if ($c = $w * cv::compare(cl::get($a, $key), cl::get($b, $key))) {
|
if ($c = $w * cv::compare(cl::get($a, $key), cl::get($b, $key))) {
|
||||||
return $c;
|
return $c;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue