Compare commits
No commits in common. "wip" and "master" have entirely different histories.
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,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:
|
||||
branch:
|
||||
master:
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
|
@ -1,15 +0,0 @@
|
|||
<?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">
|
||||
<component name="NewModuleRootManager">
|
||||
<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/src" isTestSource="false" packagePrefix="nulib\" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
|
|
|
@ -12,39 +12,39 @@
|
|||
</component>
|
||||
<component name="PhpIncludePathManager">
|
||||
<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/nikic/php-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
|
||||
<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/resource-operations" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
|
||||
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
|
||||
<path value="$PROJECT_DIR$/vendor/mur/tests" />
|
||||
</include_path>
|
||||
</component>
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="7.4" />
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="7.3" />
|
||||
<component name="PhpStanOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
<?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>
|
|
@ -1,10 +0,0 @@
|
|||
<?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,5 +2,6 @@
|
|||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,8 +0,0 @@
|
|||
# -*- 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
|
30
.udir
30
.udir
|
@ -1,30 +0,0 @@
|
|||
# -*- 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)
|
15
TODO.md
15
TODO.md
|
@ -1,15 +0,0 @@
|
|||
# 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
|
|
@ -1,157 +0,0 @@
|
|||
# -*- 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
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
# -*- 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"
|
|
@ -1,141 +0,0 @@
|
|||
# -*- 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
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
# -*- 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)
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
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())
|
||||
}
|
201
awk/src/csv.awk
201
awk/src/csv.awk
|
@ -1,201 +0,0 @@
|
|||
# -*- 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
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
# -*- 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
|
||||
}
|
45
bash/TODO.md
45
bash/TODO.md
|
@ -1,45 +0,0 @@
|
|||
# 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
|
|
@ -1,4 +0,0 @@
|
|||
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||
##@cooked nocomments
|
||||
module: TEMPLATE "DESCRIPTION"
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
# -*- 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")"; }
|
|
@ -1,66 +0,0 @@
|
|||
# -*- 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")"; }
|
|
@ -1,486 +0,0 @@
|
|||
# -*- 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"
|
||||
}
|
|
@ -1,360 +0,0 @@
|
|||
# -*- 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
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
# -*- 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
|
||||
}
|
|
@ -1,458 +0,0 @@
|
|||
# -*- 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 "$@"; }
|
|
@ -1,53 +0,0 @@
|
|||
# -*- 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
|
|
@ -1,581 +0,0 @@
|
|||
# -*- 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"
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
# -*- 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" ]
|
||||
}
|
|
@ -1,601 +0,0 @@
|
|||
# -*- 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
|
||||
}
|
|
@ -1,304 +0,0 @@
|
|||
# -*- 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
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
# -*- 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
|
|
@ -1,188 +0,0 @@
|
|||
# -*- 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"
|
||||
}
|
|
@ -1,140 +0,0 @@
|
|||
# -*- 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
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
# -*- 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
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
# -*- 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
|
|
@ -1,3 +0,0 @@
|
|||
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||
##@cooked nocomments
|
||||
module: donk.common "fonctions communes"
|
|
@ -1,41 +0,0 @@
|
|||
# -*- 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 $?
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
# -*- 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"
|
||||
}
|
217
bash/src/git.sh
217
bash/src/git.sh
|
@ -1,217 +0,0 @@
|
|||
# -*- 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")" ]
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
../../load.sh
|
|
@ -1,194 +0,0 @@
|
|||
# -*- 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
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
# -*- 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
|
|
@ -1,225 +0,0 @@
|
|||
# -*- 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"
|
||||
}
|
|
@ -1,160 +0,0 @@
|
|||
# -*- 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"
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
/template-dest.txt
|
|
@ -1,21 +0,0 @@
|
|||
---
|
||||
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
|
||||
---
|
|
@ -1,23 +0,0 @@
|
|||
---
|
||||
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@@
|
||||
---
|
|
@ -1,19 +0,0 @@
|
|||
#!/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
|
||||
)
|
||||
"
|
|
@ -1,12 +0,0 @@
|
|||
# -*- 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=
|
|
@ -1,17 +0,0 @@
|
|||
#!/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
|
|
@ -1,40 +0,0 @@
|
|||
#!/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"
|
|
@ -1,187 +0,0 @@
|
|||
#!/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"
|
|
@ -1,18 +0,0 @@
|
|||
#!/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"
|
|
@ -1,18 +0,0 @@
|
|||
#!/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"
|
|
@ -1,169 +0,0 @@
|
|||
#!/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
|
|
@ -1,29 +0,0 @@
|
|||
#!/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
|
|
@ -1,28 +0,0 @@
|
|||
#!/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
|
69
bin/nlman
69
bin/nlman
|
@ -1,69 +0,0 @@
|
|||
#!/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
|
38
bin/nlshell
38
bin/nlshell
|
@ -1,38 +0,0 @@
|
|||
#!/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 -- "$@"
|
61
bin/np
61
bin/np
|
@ -1,61 +0,0 @@
|
|||
#!/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,51 +1,52 @@
|
|||
#!/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
|
||||
MYDIR="$(dirname -- "$0")"; MYNAME="$(basename -- "$0")"
|
||||
function die() { echo 1>&2 "ERROR: $*"; exit 1; }
|
||||
|
||||
owd="$(pwd)"
|
||||
PROJDIR=
|
||||
while true; do
|
||||
cwd="$(pwd)"
|
||||
if [ -f .runphp.conf ]; then
|
||||
PROJDIR="$cwd"
|
||||
break
|
||||
elif [ -f composer.json ]; then
|
||||
PROJDIR="$cwd"
|
||||
break
|
||||
case "$MYNAME" in
|
||||
runphp) ;;
|
||||
composer)
|
||||
if [ -f "$MYDIR/composer.phar" ]; then
|
||||
set -- "$MYDIR/composer.phar" "$@"
|
||||
elif [ -f "$MYDIR/../sbin/composer.phar" ]; then
|
||||
set -- "$MYDIR/../sbin/composer.phar" "$@"
|
||||
elif [ -f "/usr/bin/composer" ]; then
|
||||
set -- "/usr/bin/composer" "$@"
|
||||
else
|
||||
set -- "" "$@"
|
||||
fi
|
||||
if [ "$cwd" == "$HOME" -o "$cwd" == / ]; then
|
||||
cd "$owd"
|
||||
break
|
||||
fi
|
||||
cd ..
|
||||
;;
|
||||
*) die "$MYNAME: nom de script invalide";;
|
||||
esac
|
||||
|
||||
function runphp_help() {
|
||||
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
|
||||
|
||||
if [ -z "$PROJDIR" ]; then
|
||||
# s'il n'y a pas de projet, --bs est l'action par défaut
|
||||
[ $# -gt 0 ] || set -- --bs
|
||||
elif [ "$MYNAME" == composer ]; then
|
||||
set -- composer "$@"
|
||||
else
|
||||
case "$1" in
|
||||
*.php|*.phar) set -- php "$@";;
|
||||
esac
|
||||
fi
|
||||
script="$1"; shift
|
||||
[ -n "$script" ] || die "vous devez spécifier le script à lancer"
|
||||
[ -f "$script" ] || die "$script: script introuvable"
|
||||
|
||||
if [ -n "$PROJDIR" ]; then
|
||||
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" "$@"
|
||||
scriptdir="$(dirname -- "$script")"
|
||||
scritname="$(basename -- "$script")"
|
||||
|
|
38
bin/templ.md
38
bin/templ.md
|
@ -1,38 +0,0 @@
|
|||
#!/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
|
56
bin/templ.sh
56
bin/templ.sh
|
@ -1,56 +0,0 @@
|
|||
#!/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
|
|
@ -1,40 +0,0 @@
|
|||
#!/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
|
|
@ -1,38 +0,0 @@
|
|||
#!/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
|
25
bin_wip/donk
25
bin_wip/donk
|
@ -1,25 +0,0 @@
|
|||
#!/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" "$@"
|
30
bin_wip/npci
30
bin_wip/npci
|
@ -1,30 +0,0 @@
|
|||
#!/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[@]}"
|
||||
|
22
bin_wip/npp
22
bin_wip/npp
|
@ -1,22 +0,0 @@
|
|||
#!/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[@]}"
|
||||
|
147
bin_wip/npu
147
bin_wip/npu
|
@ -1,147 +0,0 @@
|
|||
#!/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,17 +9,14 @@
|
|||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.4"
|
||||
"php": ">=7.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"nulib/tests": "7.4",
|
||||
"ext-posix": "*",
|
||||
"ext-pcntl": "*",
|
||||
"ext-curl": "*"
|
||||
"nulib/tests": "7.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"nulib\\": "php/src"
|
||||
"nulib\\": "php/src_base"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "356c1dcfe9eee39e9e6eadff4f63cdfe",
|
||||
"content-hash": "a83db90dff9c8a1e44abc608738042c3",
|
||||
"packages": [],
|
||||
"packages-dev": [
|
||||
{
|
||||
|
@ -79,16 +79,16 @@
|
|||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.12.0",
|
||||
"version": "1.11.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||
"reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c"
|
||||
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
|
||||
"reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
|
||||
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -96,12 +96,11 @@
|
|||
},
|
||||
"conflict": {
|
||||
"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": {
|
||||
"doctrine/collections": "^1.6.8",
|
||||
"doctrine/common": "^2.13.3 || ^3.2.2",
|
||||
"phpspec/prophecy": "^1.10",
|
||||
"phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
|
||||
},
|
||||
"type": "library",
|
||||
|
@ -127,7 +126,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.0"
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -135,31 +134,29 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-06-12T14:39:25+00:00"
|
||||
"time": "2023-03-08T13:26:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v5.3.1",
|
||||
"version": "v4.17.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "8eea230464783aa9671db8eea6f8c6ac5285794b"
|
||||
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b",
|
||||
"reference": "8eea230464783aa9671db8eea6f8c6ac5285794b",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
|
||||
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-ctype": "*",
|
||||
"ext-json": "*",
|
||||
"ext-tokenizer": "*",
|
||||
"php": ">=7.4"
|
||||
"php": ">=7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ircmaxell/php-yacc": "^0.0.7",
|
||||
"phpunit/phpunit": "^9.0"
|
||||
"phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
|
||||
},
|
||||
"bin": [
|
||||
"bin/php-parse"
|
||||
|
@ -167,7 +164,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.0-dev"
|
||||
"dev-master": "4.9-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -191,17 +188,17 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1"
|
||||
},
|
||||
"time": "2024-10-08T18:51:32+00:00"
|
||||
"time": "2023-08-13T19:53:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nulib/tests",
|
||||
"version": "7.4",
|
||||
"version": "7.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://git.univ-reunion.fr/sda-php/nulib-tests.git",
|
||||
"reference": "6ce8257560b42e8fb3eea03eba84d3877c9648ca"
|
||||
"reference": "8902035bef6ddfe9864675a00844dd14872f6d13"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.3",
|
||||
|
@ -210,12 +207,12 @@
|
|||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"nulib\\tests\\": "src"
|
||||
"mur\\tests\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"nulib\\tests\\": "tests"
|
||||
"mur\\tests\\": "tests"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
|
@ -225,25 +222,24 @@
|
|||
}
|
||||
],
|
||||
"description": "fonctions et classes pour les tests",
|
||||
"time": "2024-03-26T10:56:17+00:00"
|
||||
"time": "2023-10-01T11:57:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/manifest",
|
||||
"version": "2.0.4",
|
||||
"version": "2.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phar-io/manifest.git",
|
||||
"reference": "54750ef60c58e43759730615a392c31c80e23176"
|
||||
"reference": "97803eca37d319dfa7826cc2437fc020857acb53"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
|
||||
"reference": "54750ef60c58e43759730615a392c31c80e23176",
|
||||
"url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53",
|
||||
"reference": "97803eca37d319dfa7826cc2437fc020857acb53",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-phar": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"phar-io/version": "^3.0.1",
|
||||
|
@ -284,15 +280,9 @@
|
|||
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
|
||||
"support": {
|
||||
"issues": "https://github.com/phar-io/manifest/issues",
|
||||
"source": "https://github.com/phar-io/manifest/tree/2.0.4"
|
||||
"source": "https://github.com/phar-io/manifest/tree/2.0.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/theseer",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-03T12:33:53+00:00"
|
||||
"time": "2021-07-20T11:28:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/version",
|
||||
|
@ -347,35 +337,35 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "9.2.32",
|
||||
"version": "9.2.29",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5"
|
||||
"reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5",
|
||||
"reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76",
|
||||
"reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"nikic/php-parser": "^4.19.1 || ^5.1.0",
|
||||
"nikic/php-parser": "^4.15",
|
||||
"php": ">=7.3",
|
||||
"phpunit/php-file-iterator": "^3.0.6",
|
||||
"phpunit/php-text-template": "^2.0.4",
|
||||
"sebastian/code-unit-reverse-lookup": "^2.0.3",
|
||||
"sebastian/complexity": "^2.0.3",
|
||||
"sebastian/environment": "^5.1.5",
|
||||
"sebastian/lines-of-code": "^1.0.4",
|
||||
"sebastian/version": "^3.0.2",
|
||||
"theseer/tokenizer": "^1.2.3"
|
||||
"phpunit/php-file-iterator": "^3.0.3",
|
||||
"phpunit/php-text-template": "^2.0.2",
|
||||
"sebastian/code-unit-reverse-lookup": "^2.0.2",
|
||||
"sebastian/complexity": "^2.0",
|
||||
"sebastian/environment": "^5.1.2",
|
||||
"sebastian/lines-of-code": "^1.0.3",
|
||||
"sebastian/version": "^3.0.1",
|
||||
"theseer/tokenizer": "^1.2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.6"
|
||||
"phpunit/phpunit": "^9.3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-pcov": "PHP extension that provides line coverage",
|
||||
|
@ -384,7 +374,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "9.2.x-dev"
|
||||
"dev-master": "9.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -413,7 +403,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -421,7 +411,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-08-22T04:23:01+00:00"
|
||||
"time": "2023-09-19T04:57:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
|
@ -666,45 +656,45 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "9.6.21",
|
||||
"version": "9.6.13",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa"
|
||||
"reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa",
|
||||
"reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be",
|
||||
"reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/instantiator": "^1.5.0 || ^2",
|
||||
"doctrine/instantiator": "^1.3.1 || ^2",
|
||||
"ext-dom": "*",
|
||||
"ext-json": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-xml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"myclabs/deep-copy": "^1.12.0",
|
||||
"phar-io/manifest": "^2.0.4",
|
||||
"phar-io/version": "^3.2.1",
|
||||
"myclabs/deep-copy": "^1.10.1",
|
||||
"phar-io/manifest": "^2.0.3",
|
||||
"phar-io/version": "^3.0.2",
|
||||
"php": ">=7.3",
|
||||
"phpunit/php-code-coverage": "^9.2.32",
|
||||
"phpunit/php-file-iterator": "^3.0.6",
|
||||
"phpunit/php-code-coverage": "^9.2.28",
|
||||
"phpunit/php-file-iterator": "^3.0.5",
|
||||
"phpunit/php-invoker": "^3.1.1",
|
||||
"phpunit/php-text-template": "^2.0.4",
|
||||
"phpunit/php-timer": "^5.0.3",
|
||||
"sebastian/cli-parser": "^1.0.2",
|
||||
"sebastian/code-unit": "^1.0.8",
|
||||
"phpunit/php-text-template": "^2.0.3",
|
||||
"phpunit/php-timer": "^5.0.2",
|
||||
"sebastian/cli-parser": "^1.0.1",
|
||||
"sebastian/code-unit": "^1.0.6",
|
||||
"sebastian/comparator": "^4.0.8",
|
||||
"sebastian/diff": "^4.0.6",
|
||||
"sebastian/environment": "^5.1.5",
|
||||
"sebastian/exporter": "^4.0.6",
|
||||
"sebastian/global-state": "^5.0.7",
|
||||
"sebastian/object-enumerator": "^4.0.4",
|
||||
"sebastian/resource-operations": "^3.0.4",
|
||||
"sebastian/type": "^3.2.1",
|
||||
"sebastian/diff": "^4.0.3",
|
||||
"sebastian/environment": "^5.1.3",
|
||||
"sebastian/exporter": "^4.0.5",
|
||||
"sebastian/global-state": "^5.0.1",
|
||||
"sebastian/object-enumerator": "^4.0.3",
|
||||
"sebastian/resource-operations": "^3.0.3",
|
||||
"sebastian/type": "^3.2",
|
||||
"sebastian/version": "^3.0.2"
|
||||
},
|
||||
"suggest": {
|
||||
|
@ -749,7 +739,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.21"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -765,20 +755,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-19T10:50:18+00:00"
|
||||
"time": "2023-09-19T05:39:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/cli-parser.git",
|
||||
"reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b"
|
||||
"reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
|
||||
"reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2",
|
||||
"reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -813,7 +803,7 @@
|
|||
"homepage": "https://github.com/sebastianbergmann/cli-parser",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/cli-parser/issues",
|
||||
"source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2"
|
||||
"source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -821,7 +811,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-02T06:27:43+00:00"
|
||||
"time": "2020-09-28T06:08:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/code-unit",
|
||||
|
@ -1010,20 +1000,20 @@
|
|||
},
|
||||
{
|
||||
"name": "sebastian/complexity",
|
||||
"version": "2.0.3",
|
||||
"version": "2.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/complexity.git",
|
||||
"reference": "25f207c40d62b8b7aa32f5ab026c53561964053a"
|
||||
"reference": "739b35e53379900cc9ac327b2147867b8b6efd88"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a",
|
||||
"reference": "25f207c40d62b8b7aa32f5ab026c53561964053a",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88",
|
||||
"reference": "739b35e53379900cc9ac327b2147867b8b6efd88",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"nikic/php-parser": "^4.18 || ^5.0",
|
||||
"nikic/php-parser": "^4.7",
|
||||
"php": ">=7.3"
|
||||
},
|
||||
"require-dev": {
|
||||
|
@ -1055,7 +1045,7 @@
|
|||
"homepage": "https://github.com/sebastianbergmann/complexity",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/complexity/issues",
|
||||
"source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3"
|
||||
"source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1063,20 +1053,20 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-12-22T06:19:30+00:00"
|
||||
"time": "2020-10-26T15:52:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
"version": "4.0.6",
|
||||
"version": "4.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/diff.git",
|
||||
"reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc"
|
||||
"reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc",
|
||||
"reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
|
||||
"reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1121,7 +1111,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/diff/issues",
|
||||
"source": "https://github.com/sebastianbergmann/diff/tree/4.0.6"
|
||||
"source": "https://github.com/sebastianbergmann/diff/tree/4.0.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1129,7 +1119,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-02T06:30:58+00:00"
|
||||
"time": "2023-05-07T05:35:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
|
@ -1196,16 +1186,16 @@
|
|||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
"version": "4.0.6",
|
||||
"version": "4.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/exporter.git",
|
||||
"reference": "78c00df8f170e02473b682df15bfcdacc3d32d72"
|
||||
"reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72",
|
||||
"reference": "78c00df8f170e02473b682df15bfcdacc3d32d72",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
|
||||
"reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1261,7 +1251,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/exporter/issues",
|
||||
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6"
|
||||
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1269,20 +1259,20 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-02T06:33:00+00:00"
|
||||
"time": "2022-09-14T06:03:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/global-state",
|
||||
"version": "5.0.7",
|
||||
"version": "5.0.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/global-state.git",
|
||||
"reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9"
|
||||
"reference": "bde739e7565280bda77be70044ac1047bc007e34"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
|
||||
"reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34",
|
||||
"reference": "bde739e7565280bda77be70044ac1047bc007e34",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1325,7 +1315,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/global-state/issues",
|
||||
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7"
|
||||
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1333,24 +1323,24 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-02T06:35:11+00:00"
|
||||
"time": "2023-08-02T09:26:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/lines-of-code",
|
||||
"version": "1.0.4",
|
||||
"version": "1.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/lines-of-code.git",
|
||||
"reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5"
|
||||
"reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5",
|
||||
"reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc",
|
||||
"reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"nikic/php-parser": "^4.18 || ^5.0",
|
||||
"nikic/php-parser": "^4.6",
|
||||
"php": ">=7.3"
|
||||
},
|
||||
"require-dev": {
|
||||
|
@ -1382,7 +1372,7 @@
|
|||
"homepage": "https://github.com/sebastianbergmann/lines-of-code",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
|
||||
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4"
|
||||
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1390,7 +1380,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-12-22T06:20:34+00:00"
|
||||
"time": "2020-11-28T06:42:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/object-enumerator",
|
||||
|
@ -1569,16 +1559,16 @@
|
|||
},
|
||||
{
|
||||
"name": "sebastian/resource-operations",
|
||||
"version": "3.0.4",
|
||||
"version": "3.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/resource-operations.git",
|
||||
"reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e"
|
||||
"reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
|
||||
"reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
|
||||
"reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1590,7 +1580,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "3.0-dev"
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -1611,7 +1601,8 @@
|
|||
"description": "Provides a list of PHP built-in functions that operate on resources",
|
||||
"homepage": "https://www.github.com/sebastianbergmann/resource-operations",
|
||||
"support": {
|
||||
"source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4"
|
||||
"issues": "https://github.com/sebastianbergmann/resource-operations/issues",
|
||||
"source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1619,7 +1610,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-14T16:00:52+00:00"
|
||||
"time": "2020-09-28T06:45:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/type",
|
||||
|
@ -1732,16 +1723,16 @@
|
|||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
"version": "1.2.3",
|
||||
"version": "1.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/theseer/tokenizer.git",
|
||||
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
|
||||
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
|
||||
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e",
|
||||
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1770,7 +1761,7 @@
|
|||
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
||||
"support": {
|
||||
"issues": "https://github.com/theseer/tokenizer/issues",
|
||||
"source": "https://github.com/theseer/tokenizer/tree/1.2.3"
|
||||
"source": "https://github.com/theseer/tokenizer/tree/1.2.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1778,7 +1769,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-03T12:36:25+00:00"
|
||||
"time": "2021-07-28T10:34:58+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
@ -1787,12 +1778,8 @@
|
|||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": "^7.4"
|
||||
"php": ">=7.3"
|
||||
},
|
||||
"platform-dev": {
|
||||
"ext-posix": "*",
|
||||
"ext-pcntl": "*",
|
||||
"ext-curl": "*"
|
||||
},
|
||||
"plugin-api-version": "2.2.0"
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
# -*- 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"]
|
|
@ -1,40 +0,0 @@
|
|||
# -*- 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"]
|
|
@ -1,19 +0,0 @@
|
|||
# -*- 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"]
|
|
@ -1,31 +0,0 @@
|
|||
# -*- 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"]
|
|
@ -1,44 +0,0 @@
|
|||
# -*- 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"]
|
|
@ -1,30 +0,0 @@
|
|||
# -*- 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"]
|
|
@ -1,43 +0,0 @@
|
|||
# -*- 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"]
|
|
@ -1,16 +0,0 @@
|
|||
# -*- 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"]
|
|
@ -1,2 +0,0 @@
|
|||
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||
__uaddpath "@@dest@@/bin" PATH
|
11
lib/setup.sh
11
lib/setup.sh
|
@ -1,11 +0,0 @@
|
|||
#!/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
|
|
@ -1,6 +0,0 @@
|
|||
# -*- 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"
|
|
@ -1,5 +0,0 @@
|
|||
# -*- 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"
|
182
load.sh
182
load.sh
|
@ -1,182 +0,0 @@
|
|||
##@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
|
216
php/src/A.php
216
php/src/A.php
|
@ -1,216 +0,0 @@
|
|||
<?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,101 +0,0 @@
|
|||
<?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;
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
<?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;
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
<?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;
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
<?php
|
||||
namespace nulib;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Class NoMoreDataException: indiquer que plus aucune donnée n'est disponible
|
||||
*/
|
||||
class NoMoreDataException extends RuntimeException {
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
<?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 {
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
<?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;
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
<?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"));
|
||||
}
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
<?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(),
|
||||
]));
|
||||
}
|
||||
}
|
|
@ -1,354 +0,0 @@
|
|||
<?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,
|
||||
];
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
<?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();
|
||||
}
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
<?php
|
||||
namespace nulib\db;
|
||||
|
||||
use nulib\php\func;
|
||||
use nulib\ValueException;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* Class Capacitor: un objet permettant d'attaquer un canal spécifique d'une
|
||||
* instance de {@link CapacitorStorage}
|
||||
*/
|
||||
class Capacitor implements ITransactor {
|
||||
function __construct(CapacitorStorage $storage, CapacitorChannel $channel, bool $ensureExists=true) {
|
||||
$this->storage = $storage;
|
||||
$this->channel = $channel;
|
||||
$this->channel->setCapacitor($this);
|
||||
if ($ensureExists) $this->ensureExists();
|
||||
}
|
||||
|
||||
/** @var CapacitorStorage */
|
||||
protected $storage;
|
||||
|
||||
function getStorage(): CapacitorStorage {
|
||||
return $this->storage;
|
||||
}
|
||||
|
||||
function db(): IDatabase {
|
||||
return $this->getStorage()->db();
|
||||
}
|
||||
|
||||
/** @var CapacitorChannel */
|
||||
protected $channel;
|
||||
|
||||
function getChannel(): CapacitorChannel {
|
||||
return $this->channel;
|
||||
}
|
||||
|
||||
function getTableName(): string {
|
||||
return $this->getChannel()->getTableName();
|
||||
}
|
||||
|
||||
/** @var CapacitorChannel[] */
|
||||
protected ?array $subChannels = null;
|
||||
|
||||
protected ?array $subManageTransactions = null;
|
||||
|
||||
function willUpdate(...$channels): self {
|
||||
if ($this->subChannels === null) {
|
||||
# désactiver la gestion des transaction sur le channel local aussi
|
||||
$this->subChannels[] = $this->channel;
|
||||
}
|
||||
if ($channels) {
|
||||
foreach ($channels as $channel) {
|
||||
if ($channel instanceof Capacitor) $channel = $channel->getChannel();
|
||||
if ($channel instanceof CapacitorChannel) {
|
||||
$this->subChannels[] = $channel;
|
||||
} else {
|
||||
throw ValueException::invalid_type($channel, CapacitorChannel::class);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
function inTransaction(): bool {
|
||||
return $this->db()->inTransaction();
|
||||
}
|
||||
|
||||
function beginTransaction(?callable $func=null, bool $commit=true): void {
|
||||
$db = $this->db();
|
||||
if ($this->subChannels !== null) {
|
||||
# on gère des subchannels: ne débuter la transaction que si ce n'est déjà fait
|
||||
if ($this->subManageTransactions === null) {
|
||||
foreach ($this->subChannels as $channel) {
|
||||
$name = $channel->getName();
|
||||
$this->subManageTransactions ??= [];
|
||||
if (!array_key_exists($name, $this->subManageTransactions)) {
|
||||
$this->subManageTransactions[$name] = $channel->isManageTransactions();
|
||||
}
|
||||
$channel->setManageTransactions(false);
|
||||
}
|
||||
if (!$db->inTransaction()) $db->beginTransaction();
|
||||
}
|
||||
} elseif (!$db->inTransaction()) {
|
||||
$db->beginTransaction();
|
||||
}
|
||||
if ($func !== null) {
|
||||
$commited = false;
|
||||
try {
|
||||
func::call($func, $this);
|
||||
if ($commit) {
|
||||
$this->commit();
|
||||
$commited = true;
|
||||
}
|
||||
} finally {
|
||||
if ($commit && !$commited) $this->rollback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function beforeEndTransaction(): void {
|
||||
if ($this->subManageTransactions !== null) {
|
||||
foreach ($this->subChannels as $channel) {
|
||||
$name = $channel->getName();
|
||||
$channel->setManageTransactions($this->subManageTransactions[$name]);
|
||||
}
|
||||
$this->subManageTransactions = null;
|
||||
}
|
||||
}
|
||||
|
||||
function commit(): void {
|
||||
$this->beforeEndTransaction();
|
||||
$db = $this->db();
|
||||
if ($db->inTransaction()) $db->commit();
|
||||
}
|
||||
|
||||
function rollback(): void {
|
||||
$this->beforeEndTransaction();
|
||||
$db = $this->db();
|
||||
if ($db->inTransaction()) $db->rollback();
|
||||
}
|
||||
|
||||
function getCreateSql(): string {
|
||||
return $this->storage->_getCreateSql($this->channel);
|
||||
}
|
||||
|
||||
function exists(): bool {
|
||||
return $this->storage->_exists($this->channel);
|
||||
}
|
||||
|
||||
function ensureExists(): void {
|
||||
$this->storage->_ensureExists($this->channel);
|
||||
}
|
||||
|
||||
function reset(bool $recreate=false): void {
|
||||
$this->storage->_reset($this->channel, $recreate);
|
||||
}
|
||||
|
||||
function charge($item, $func=null, ?array $args=null, ?array &$values=null): int {
|
||||
if ($this->subChannels !== null) $this->beginTransaction();
|
||||
return $this->storage->_charge($this->channel, $item, $func, $args, $values);
|
||||
}
|
||||
|
||||
function discharge(bool $reset=true): Traversable {
|
||||
return $this->storage->_discharge($this->channel, $reset);
|
||||
}
|
||||
|
||||
function count($filter=null): int {
|
||||
return $this->storage->_count($this->channel, $filter);
|
||||
}
|
||||
|
||||
function one($filter, ?array $mergeQuery=null): ?array {
|
||||
return $this->storage->_one($this->channel, $filter, $mergeQuery);
|
||||
}
|
||||
|
||||
function all($filter, ?array $mergeQuery=null): Traversable {
|
||||
return $this->storage->_all($this->channel, $filter, $mergeQuery);
|
||||
}
|
||||
|
||||
function each($filter, $func=null, ?array $args=null, ?array $mergeQuery=null, ?int &$nbUpdated=null): int {
|
||||
if ($this->subChannels !== null) $this->beginTransaction();
|
||||
return $this->storage->_each($this->channel, $filter, $func, $args, $mergeQuery, $nbUpdated);
|
||||
}
|
||||
|
||||
function delete($filter, $func=null, ?array $args=null): int {
|
||||
if ($this->subChannels !== null) $this->beginTransaction();
|
||||
return $this->storage->_delete($this->channel, $filter, $func, $args);
|
||||
}
|
||||
|
||||
function close(): void {
|
||||
$this->storage->close();
|
||||
}
|
||||
}
|
|
@ -1,407 +0,0 @@
|
|||
<?php
|
||||
namespace nulib\db;
|
||||
|
||||
use nulib\cl;
|
||||
use nulib\str;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* Class CapacitorChannel: un canal d'une instance de {@link ICapacitor}
|
||||
*/
|
||||
class CapacitorChannel {
|
||||
const NAME = null;
|
||||
|
||||
const TABLE_NAME = null;
|
||||
|
||||
const COLUMN_DEFINITIONS = null;
|
||||
|
||||
const PRIMARY_KEYS = null;
|
||||
|
||||
const MANAGE_TRANSACTIONS = true;
|
||||
|
||||
const EACH_COMMIT_THRESHOLD = 100;
|
||||
|
||||
const USE_CACHE = false;
|
||||
|
||||
static function verifix_name(?string &$name, ?string &$tableName=null): void {
|
||||
if ($name !== null) {
|
||||
$name = strtolower($name);
|
||||
if ($tableName === null) {
|
||||
$tableName = str_replace("-", "_", $tableName) . "_channel";
|
||||
}
|
||||
} else {
|
||||
$name = static::class;
|
||||
if ($name === self::class) {
|
||||
$name = "default";
|
||||
if ($tableName === null) $tableName = "default_channel";
|
||||
} else {
|
||||
$name = preg_replace('/^.*\\\\/', "", $name);
|
||||
$name = preg_replace('/Channel$/', "", $name);
|
||||
$name = lcfirst($name);
|
||||
if ($tableName === null) $tableName = str::camel2us($name);
|
||||
$name = strtolower($name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static function verifix_eachCommitThreshold(?int $eachCommitThreshold): ?int {
|
||||
$eachCommitThreshold ??= static::EACH_COMMIT_THRESHOLD;
|
||||
if ($eachCommitThreshold < 0) $eachCommitThreshold = null;
|
||||
return $eachCommitThreshold;
|
||||
}
|
||||
|
||||
function __construct(?string $name=null, ?int $eachCommitThreshold=null, ?bool $manageTransactions=null) {
|
||||
$name ??= static::NAME;
|
||||
$tableName ??= static::TABLE_NAME;
|
||||
self::verifix_name($name, $tableName);
|
||||
$this->name = $name;
|
||||
$this->tableName = $tableName;
|
||||
$this->manageTransactions = $manageTransactions ?? static::MANAGE_TRANSACTIONS;
|
||||
$this->eachCommitThreshold = self::verifix_eachCommitThreshold($eachCommitThreshold);
|
||||
$this->useCache = static::USE_CACHE;
|
||||
$this->setup = false;
|
||||
$this->created = false;
|
||||
$columnDefinitions = cl::withn(static::COLUMN_DEFINITIONS);
|
||||
$primaryKeys = cl::withn(static::PRIMARY_KEYS);
|
||||
if ($primaryKeys === null && $columnDefinitions !== null) {
|
||||
$index = 0;
|
||||
foreach ($columnDefinitions as $col => $def) {
|
||||
if ($col === $index) {
|
||||
$index++;
|
||||
if (preg_match('/\bprimary\s+key\s+\((.+)\)/i', $def, $ms)) {
|
||||
$primaryKeys = preg_split('/\s*,\s*/', trim($ms[1]));
|
||||
}
|
||||
} else {
|
||||
if (preg_match('/\bprimary\s+key\b/i', $def)) {
|
||||
$primaryKeys[] = $col;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->columnDefinitions = $columnDefinitions;
|
||||
$this->primaryKeys = $primaryKeys;
|
||||
}
|
||||
|
||||
protected string $name;
|
||||
|
||||
function getName(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
protected string $tableName;
|
||||
|
||||
function getTableName(): string {
|
||||
return $this->tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var bool indiquer si les modifications de each doivent être gérées dans
|
||||
* une transaction. si false, l'utilisateur doit lui même gérer la
|
||||
* transaction.
|
||||
*/
|
||||
protected bool $manageTransactions;
|
||||
|
||||
function isManageTransactions(): bool {
|
||||
return $this->manageTransactions;
|
||||
}
|
||||
|
||||
function setManageTransactions(bool $manageTransactions=true): self {
|
||||
$this->manageTransactions = $manageTransactions;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var ?int nombre maximum de modifications dans une transaction avant un
|
||||
* commit automatique dans {@link Capacitor::each()}. Utiliser null pour
|
||||
* désactiver la fonctionnalité.
|
||||
*
|
||||
* ce paramètre n'a d'effet que si $manageTransactions==true
|
||||
*/
|
||||
protected ?int $eachCommitThreshold;
|
||||
|
||||
function getEachCommitThreshold(): ?int {
|
||||
return $this->eachCommitThreshold;
|
||||
}
|
||||
|
||||
function setEachCommitThreshold(?int $eachCommitThreshold=null): self {
|
||||
$this->eachCommitThreshold = self::verifix_eachCommitThreshold($eachCommitThreshold);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var bool faut-il passer par le cache pour les requêtes de all(), each()
|
||||
* et delete()?
|
||||
* ça peut être nécessaire avec MySQL/MariaDB si on utilise les requêtes non
|
||||
* bufférisées, et que la fonction manipule la base de données
|
||||
*/
|
||||
protected bool $useCache;
|
||||
|
||||
function isUseCache(): bool {
|
||||
return $this->useCache;
|
||||
}
|
||||
|
||||
function setUseCache(bool $useCache=true): self {
|
||||
$this->useCache = $useCache;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* initialiser ce channel avant sa première utilisation.
|
||||
*/
|
||||
protected function setup(): void {
|
||||
}
|
||||
|
||||
protected bool $setup;
|
||||
|
||||
function ensureSetup() {
|
||||
if (!$this->setup) {
|
||||
$this->setup();
|
||||
$this->setup = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected bool $created;
|
||||
|
||||
function isCreated(): bool {
|
||||
return $this->created;
|
||||
}
|
||||
|
||||
function setCreated(bool $created=true): void {
|
||||
$this->created = $created;
|
||||
}
|
||||
|
||||
protected ?array $columnDefinitions;
|
||||
|
||||
/**
|
||||
* retourner un ensemble de définitions pour des colonnes supplémentaires à
|
||||
* insérer lors du chargement d'une valeur
|
||||
*
|
||||
* la clé primaire "id_" a pour définition "integer primary key autoincrement".
|
||||
* elle peut être redéfinie, et dans ce cas la valeur à utiliser doit être
|
||||
* retournée par {@link getItemValues()}
|
||||
*
|
||||
* la colonne "item__" contient la valeur sérialisée de l'élément chargé. bien
|
||||
* que ce soit possible techniquement, cette colonne n'a pas à être redéfinie
|
||||
*
|
||||
* les colonnes dont le nom se termine par "_" sont réservées.
|
||||
* les colonnes dont le nom se termine par "__" sont automatiquement sérialisées
|
||||
* lors de l'insertion dans la base de données, et automatiquement désérialisées
|
||||
* avant d'être retournées à l'utilisateur (sans le suffixe "__")
|
||||
*/
|
||||
function getColumnDefinitions(): ?array {
|
||||
return $this->columnDefinitions;
|
||||
}
|
||||
|
||||
protected ?array $primaryKeys;
|
||||
|
||||
function getPrimaryKeys(): ?array {
|
||||
return $this->primaryKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculer les valeurs des colonnes supplémentaires à insérer pour le
|
||||
* chargement de $item. pour une même valeur de $item, la valeur de retour
|
||||
* doit toujours être la même. pour rajouter des valeurs supplémentaires qui
|
||||
* dépendent de l'environnement, il faut plutôt les retournner dans
|
||||
* {@link self::onCreate()} ou {@link self::onUpdate()}
|
||||
*
|
||||
* Cette méthode est utilisée par {@link Capacitor::charge()}. Si la clé
|
||||
* primaire est incluse (il s'agit généralement de "id_"), la ligne
|
||||
* correspondate est mise à jour si elle existe.
|
||||
* Retourner la clé primaire par cette méthode est l'unique moyen de
|
||||
* déclencher une mise à jour plutôt qu'une nouvelle création.
|
||||
*
|
||||
* Retourner [false] pour annuler le chargement
|
||||
*/
|
||||
function getItemValues($item): ?array {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Avant d'utiliser un id pour rechercher dans la base de donnée, corriger sa
|
||||
* valeur le cas échéant.
|
||||
*
|
||||
* Cette fonction assume que la clé primaire n'est pas multiple. Elle n'est
|
||||
* pas utilisée si une clé primaire multiple est définie.
|
||||
*/
|
||||
function verifixId(string &$id): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* retourne true si un nouvel élément ou un élément mis à jour a été chargé.
|
||||
* false si l'élément chargé est identique au précédent.
|
||||
*
|
||||
* cette méthode doit être utilisée dans {@link self::onUpdate()}
|
||||
*/
|
||||
function wasRowModified(array $values, array $pvalues): bool {
|
||||
return $values["item__sum_"] !== $pvalues["item__sum_"];
|
||||
}
|
||||
|
||||
final function serialize($item): ?string {
|
||||
return $item !== null? serialize($item): null;
|
||||
}
|
||||
|
||||
final function unserialize(?string $serial) {
|
||||
return $serial !== null? unserialize($serial): null;
|
||||
}
|
||||
|
||||
const SERIAL_DEFINITION = "mediumtext";
|
||||
const SUM_DEFINITION = "varchar(40)";
|
||||
|
||||
final function sum(?string $serial, $value=null): ?string {
|
||||
if ($serial === null) $serial = $this->serialize($value);
|
||||
return $serial !== null? sha1($serial): null;
|
||||
}
|
||||
|
||||
final function isSerialCol(string &$key): bool {
|
||||
return str::del_suffix($key, "__");
|
||||
}
|
||||
|
||||
final function getSumCols(string $key): array {
|
||||
return ["${key}__", "${key}__sum_"];
|
||||
}
|
||||
|
||||
function getSum(string $key, $value): array {
|
||||
$sumCols = $this->getSumCols($key);
|
||||
$serial = $this->serialize($value);
|
||||
$sum = $this->sum($serial, $value);
|
||||
return array_combine($sumCols, [$serial, $sum]);
|
||||
}
|
||||
|
||||
function wasSumModified(string $key, $value, array $pvalues): bool {
|
||||
$sumCol = $this->getSumCols($key)[1];
|
||||
$sum = $this->sum(null, $value);
|
||||
$psum = $pvalues[$sumCol] ?? $this->sum(null, $pvalues[$key] ?? null);
|
||||
return $sum !== $psum;
|
||||
}
|
||||
|
||||
function _wasSumModified(string $key, array $row, array $prow): bool {
|
||||
$sumCol = $this->getSumCols($key)[1];
|
||||
$sum = $row[$sumCol] ?? null;
|
||||
$psum = $prow[$sumCol] ?? null;
|
||||
return $sum !== $psum;
|
||||
}
|
||||
|
||||
/**
|
||||
* méthode appelée lors du chargement avec {@link Capacitor::charge()} pour
|
||||
* créer un nouvel élément
|
||||
*
|
||||
* @param mixed $item l'élément à charger
|
||||
* @param array $values la ligne à créer, calculée à partir de $item et des
|
||||
* valeurs retournées par {@link getItemValues()}
|
||||
* @return ?array le cas échéant, un tableau non null à merger dans $values et
|
||||
* utilisé pour provisionner la ligne nouvellement créée.
|
||||
* Retourner [false] pour annuler le chargement (la ligne n'est pas créée)
|
||||
*
|
||||
* Si $item est modifié dans cette méthode, il est possible de le retourner
|
||||
* avec la clé "item" pour mettre à jour la ligne correspondante.
|
||||
*
|
||||
* la création ou la mise à jour est uniquement décidée en fonction des
|
||||
* valeurs calculées par {@link self::getItemValues()}. Bien que cette méthode
|
||||
* peut techniquement retourner de nouvelles valeurs pour la clé primaire, ça
|
||||
* risque de créer des doublons
|
||||
*/
|
||||
function onCreate($item, array $values, ?array $alwaysNull): ?array {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* méthode appelée lors du chargement avec {@link Capacitor::charge()} pour
|
||||
* mettre à jour un élément existant
|
||||
*
|
||||
* @param mixed $item l'élément à charger
|
||||
* @param array $values la nouvelle ligne, calculée à partir de $item et
|
||||
* des valeurs retournées par {@link getItemValues()}
|
||||
* @param array $pvalues la précédente ligne, chargée depuis la base de
|
||||
* données
|
||||
* @return ?array null s'il ne faut pas mettre à jour la ligne. sinon, ce
|
||||
* tableau est mergé dans $values puis utilisé pour mettre à jour la ligne
|
||||
* existante
|
||||
* Retourner [false] pour annuler le chargement (la ligne n'est pas mise à
|
||||
* jour)
|
||||
*
|
||||
* - Il est possible de mettre à jour $item en le retourant avec la clé "item"
|
||||
* - La clé primaire (il s'agit généralement de "id_") ne peut pas être
|
||||
* modifiée. si elle est retournée, elle est ignorée
|
||||
*/
|
||||
function onUpdate($item, array $values, array $pvalues): ?array {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* méthode appelée lors du parcours des éléments avec
|
||||
* {@link Capacitor::each()}
|
||||
*
|
||||
* @param mixed $item l'élément courant
|
||||
* @param ?array $values la ligne courante
|
||||
* @return ?array le cas échéant, un tableau non null utilisé pour mettre à
|
||||
* jour la ligne courante
|
||||
*
|
||||
* - Il est possible de mettre à jour $item en le retourant avec la clé "item"
|
||||
* - La clé primaire (il s'agit généralement de "id_") ne peut pas être
|
||||
* modifiée. si elle est retournée, elle est ignorée
|
||||
*/
|
||||
function onEach($item, array $values): ?array {
|
||||
return null;
|
||||
}
|
||||
const onEach = "->".[self::class, "onEach"][1];
|
||||
|
||||
/**
|
||||
* méthode appelée lors du parcours des éléments avec
|
||||
* {@link Capacitor::delete()}
|
||||
*
|
||||
* @param mixed $item l'élément courant
|
||||
* @param ?array $values la ligne courante
|
||||
* @return bool true s'il faut supprimer la ligne, false sinon
|
||||
*/
|
||||
function onDelete($item, array $values): bool {
|
||||
return true;
|
||||
}
|
||||
const onDelete = "->".[self::class, "onDelete"][1];
|
||||
|
||||
#############################################################################
|
||||
# Méthodes déléguées pour des workflows centrés sur le channel
|
||||
|
||||
/**
|
||||
* @var Capacitor|null instance de Capacitor par laquelle cette instance est
|
||||
* utilisée
|
||||
*/
|
||||
protected ?Capacitor $capacitor;
|
||||
|
||||
function getCapacitor(): ?Capacitor {
|
||||
return $this->capacitor;
|
||||
}
|
||||
|
||||
function setCapacitor(Capacitor $capacitor): self {
|
||||
$this->capacitor = $capacitor;
|
||||
return $this;
|
||||
}
|
||||
|
||||
function charge($item, $func=null, ?array $args=null, ?array &$values=null): int {
|
||||
return $this->capacitor->charge($item, $func, $args, $values);
|
||||
}
|
||||
|
||||
function discharge(bool $reset=true): Traversable {
|
||||
return $this->capacitor->discharge($reset);
|
||||
}
|
||||
|
||||
function count($filter=null): int {
|
||||
return $this->capacitor->count($filter);
|
||||
}
|
||||
|
||||
function one($filter, ?array $mergeQuery=null): ?array {
|
||||
return $this->capacitor->one($filter, $mergeQuery);
|
||||
}
|
||||
|
||||
function all($filter, ?array $mergeQuery=null): Traversable {
|
||||
return $this->capacitor->all($filter, $mergeQuery);
|
||||
}
|
||||
|
||||
function each($filter, $func=null, ?array $args=null, ?array $mergeQuery=null, ?int &$nbUpdated=null): int {
|
||||
return $this->capacitor->each($filter, $func, $args, $mergeQuery, $nbUpdated);
|
||||
}
|
||||
|
||||
function delete($filter, $func=null, ?array $args=null): int {
|
||||
return $this->capacitor->delete($filter, $func, $args);
|
||||
}
|
||||
}
|
|
@ -1,624 +0,0 @@
|
|||
<?php
|
||||
namespace nulib\db;
|
||||
|
||||
use nulib\cl;
|
||||
use nulib\db\cache\cache;
|
||||
use nulib\php\func;
|
||||
use nulib\ValueException;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* Class CapacitorStorage: objet permettant d'accumuler des données pour les
|
||||
* réutiliser plus tard
|
||||
*/
|
||||
abstract class CapacitorStorage {
|
||||
abstract function db(): IDatabase;
|
||||
|
||||
/** @var CapacitorChannel[] */
|
||||
protected $channels;
|
||||
|
||||
function addChannel(CapacitorChannel $channel): CapacitorChannel {
|
||||
$this->_create($channel);
|
||||
$this->channels[$channel->getName()] = $channel;
|
||||
return $channel;
|
||||
}
|
||||
|
||||
protected function getChannel(?string $name): CapacitorChannel {
|
||||
CapacitorChannel::verifix_name($name);
|
||||
$channel = $this->channels[$name] ?? null;
|
||||
if ($channel === null) {
|
||||
$channel = $this->addChannel(new CapacitorChannel($name));
|
||||
}
|
||||
return $channel;
|
||||
}
|
||||
|
||||
/** DOIT être défini dans les classes dérivées */
|
||||
const PRIMARY_KEY_DEFINITION = null;
|
||||
|
||||
const COLUMN_DEFINITIONS = [
|
||||
"item__" => CapacitorChannel::SERIAL_DEFINITION,
|
||||
"item__sum_" => CapacitorChannel::SUM_DEFINITION,
|
||||
"created_" => "datetime",
|
||||
"modified_" => "datetime",
|
||||
];
|
||||
|
||||
protected function ColumnDefinitions(CapacitorChannel $channel): array {
|
||||
$definitions = [];
|
||||
if ($channel->getPrimaryKeys() === null) {
|
||||
$definitions[] = static::PRIMARY_KEY_DEFINITION;
|
||||
}
|
||||
$definitions[] = $channel->getColumnDefinitions();
|
||||
$definitions[] = static::COLUMN_DEFINITIONS;
|
||||
# forcer les définitions sans clé à la fin (sqlite requière par exemple que
|
||||
# primary key (columns) soit à la fin)
|
||||
$tmp = cl::merge(...$definitions);
|
||||
$definitions = [];
|
||||
$constraints = [];
|
||||
$index = 0;
|
||||
foreach ($tmp as $col => $def) {
|
||||
if ($col === $index) {
|
||||
$index++;
|
||||
$constraints[] = $def;
|
||||
} else {
|
||||
$definitions[$col] = $def;
|
||||
}
|
||||
}
|
||||
return cl::merge($definitions, $constraints);
|
||||
}
|
||||
|
||||
/** sérialiser les valeurs qui doivent l'être dans $values */
|
||||
protected function serialize(CapacitorChannel $channel, ?array $values): ?array {
|
||||
if ($values === null) return null;
|
||||
$cols = $this->ColumnDefinitions($channel);
|
||||
$index = 0;
|
||||
$row = [];
|
||||
foreach (array_keys($cols) as $col) {
|
||||
$key = $col;
|
||||
if ($key === $index) {
|
||||
$index++;
|
||||
} elseif ($channel->isSerialCol($key)) {
|
||||
[$serialCol, $sumCol] = $channel->getSumCols($key);
|
||||
if (array_key_exists($key, $values)) {
|
||||
$sum = $channel->getSum($key, $values[$key]);
|
||||
$row[$serialCol] = $sum[$serialCol];
|
||||
if (array_key_exists($sumCol, $cols)) {
|
||||
$row[$sumCol] = $sum[$sumCol];
|
||||
}
|
||||
}
|
||||
} elseif (array_key_exists($key, $values)) {
|
||||
$row[$col] = $values[$key];
|
||||
}
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
/** désérialiser les valeurs qui doivent l'être dans $values */
|
||||
protected function unserialize(CapacitorChannel $channel, ?array $row): ?array {
|
||||
if ($row === null) return null;
|
||||
$cols = $this->ColumnDefinitions($channel);
|
||||
$index = 0;
|
||||
$values = [];
|
||||
foreach (array_keys($cols) as $col) {
|
||||
$key = $col;
|
||||
if ($key === $index) {
|
||||
$index++;
|
||||
} elseif (!array_key_exists($col, $row)) {
|
||||
} elseif ($channel->isSerialCol($key)) {
|
||||
$value = $row[$col];
|
||||
if ($value !== null) $value = $channel->unserialize($value);
|
||||
$values[$key] = $value;
|
||||
} else {
|
||||
$values[$key] = $row[$col];
|
||||
}
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
function getPrimaryKeys(CapacitorChannel $channel): array {
|
||||
$primaryKeys = $channel->getPrimaryKeys();
|
||||
if ($primaryKeys === null) $primaryKeys = ["id_"];
|
||||
return $primaryKeys;
|
||||
}
|
||||
|
||||
function getRowIds(CapacitorChannel $channel, ?array $row, ?array &$primaryKeys=null): ?array {
|
||||
$primaryKeys = $this->getPrimaryKeys($channel);
|
||||
$rowIds = cl::select($row, $primaryKeys);
|
||||
if (cl::all_n($rowIds)) return null;
|
||||
else return $rowIds;
|
||||
}
|
||||
|
||||
protected function _createSql(CapacitorChannel $channel): array {
|
||||
$cols = $this->ColumnDefinitions($channel);
|
||||
return [
|
||||
"create table if not exists",
|
||||
"table" => $channel->getTableName(),
|
||||
"cols" => $cols,
|
||||
];
|
||||
}
|
||||
|
||||
protected static function format_sql(CapacitorChannel $channel, string $sql): string {
|
||||
$class = get_class($channel);
|
||||
return <<<EOT
|
||||
-- -*- coding: utf-8 mode: sql -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||
-- autogénéré à partir de $class
|
||||
|
||||
$sql;
|
||||
|
||||
EOT;
|
||||
}
|
||||
|
||||
abstract function _getCreateSql(CapacitorChannel $channel): string;
|
||||
|
||||
/** obtenir la requête SQL utilisée pour créer la table */
|
||||
function getCreateSql(?string $channel): string {
|
||||
return $this->_getCreateSql($this->getChannel($channel));
|
||||
}
|
||||
|
||||
protected function _create(CapacitorChannel $channel): void {
|
||||
$channel->ensureSetup();
|
||||
if (!$channel->isCreated()) {
|
||||
$this->db->exec($this->_createSql($channel));
|
||||
$channel->setCreated();
|
||||
}
|
||||
}
|
||||
|
||||
/** tester si le canal spécifié existe */
|
||||
abstract function _exists(CapacitorChannel $channel): bool;
|
||||
|
||||
function exists(?string $channel): bool {
|
||||
return $this->_exists($this->getChannel($channel));
|
||||
}
|
||||
|
||||
/** s'assurer que le canal spécifié existe */
|
||||
function _ensureExists(CapacitorChannel $channel): void {
|
||||
$this->_create($channel);
|
||||
}
|
||||
|
||||
function ensureExists(?string $channel): void {
|
||||
$this->_ensureExists($this->getChannel($channel));
|
||||
}
|
||||
|
||||
/** supprimer le canal spécifié */
|
||||
function _reset(CapacitorChannel $channel, bool $recreate=false): void {
|
||||
$this->db->exec([
|
||||
"drop table if exists",
|
||||
$channel->getTableName(),
|
||||
]);
|
||||
$channel->setCreated(false);
|
||||
if ($recreate) $this->_ensureExists($channel);
|
||||
}
|
||||
|
||||
function reset(?string $channel, bool $recreate=false): void {
|
||||
$this->_reset($this->getChannel($channel), $recreate);
|
||||
}
|
||||
|
||||
/**
|
||||
* charger une valeur dans le canal
|
||||
*
|
||||
* Après avoir calculé les valeurs des clés supplémentaires
|
||||
* avec {@link CapacitorChannel::getItemValues()}, l'une des deux fonctions
|
||||
* {@link CapacitorChannel::onCreate()} ou {@link CapacitorChannel::onUpdate()}
|
||||
* est appelée en fonction du type d'opération: création ou mise à jour
|
||||
*
|
||||
* Ensuite, si $func !== null, la fonction est appelée avec la signature de
|
||||
* {@link CapacitorChannel::onCreate()} ou {@link CapacitorChannel::onUpdate()}
|
||||
* en fonction du type d'opération: création ou mise à jour
|
||||
*
|
||||
* Dans les deux cas, si la fonction retourne un tableau, il est utilisé pour
|
||||
* modifier les valeurs insérées/mises à jour. De plus, $values obtient la
|
||||
* valeur finale des données insérées/mises à jour
|
||||
*
|
||||
* Si $args est renseigné, il est ajouté aux arguments utilisés pour appeler
|
||||
* les méthodes {@link CapacitorChannel::getItemValues()},
|
||||
* {@link CapacitorChannel::onCreate()} et/ou
|
||||
* {@link CapacitorChannel::onUpdate()}
|
||||
*
|
||||
* @return int 1 si l'objet a été chargé ou mis à jour, 0 s'il existait
|
||||
* déjà à l'identique dans le canal
|
||||
*/
|
||||
function _charge(CapacitorChannel $channel, $item, $func, ?array $args, ?array &$values=null): int {
|
||||
$this->_create($channel);
|
||||
$tableName = $channel->getTableName();
|
||||
$db = $this->db();
|
||||
$args ??= [];
|
||||
|
||||
$initFunc = [$channel, "getItemValues"];
|
||||
$initArgs = $args;
|
||||
func::ensure_func($initFunc, null, $initArgs);
|
||||
$values = func::call($initFunc, $item, ...$initArgs);
|
||||
if ($values === [false]) return 0;
|
||||
|
||||
$row = cl::merge(
|
||||
$channel->getSum("item", $item),
|
||||
$this->serialize($channel, $values));
|
||||
$prow = null;
|
||||
$rowIds = $this->getRowIds($channel, $row, $primaryKeys);
|
||||
if ($rowIds !== null) {
|
||||
# modification
|
||||
$prow = $db->one([
|
||||
"select",
|
||||
"from" => $tableName,
|
||||
"where" => $rowIds,
|
||||
]);
|
||||
}
|
||||
|
||||
$now = date("Y-m-d H:i:s");
|
||||
$insert = null;
|
||||
if ($prow === null) {
|
||||
# création
|
||||
$row = cl::merge($row, [
|
||||
"created_" => $now,
|
||||
"modified_" => $now,
|
||||
]);
|
||||
$insert = true;
|
||||
$initFunc = [$channel, "onCreate"];
|
||||
$initArgs = $args;
|
||||
func::ensure_func($initFunc, null, $initArgs);
|
||||
$values = $this->unserialize($channel, $row);
|
||||
$pvalues = null;
|
||||
} else {
|
||||
# modification
|
||||
# intégrer autant que possible les valeurs de prow dans row, de façon que
|
||||
# l'utilisateur puisse voir clairement ce qui a été modifié
|
||||
if ($channel->_wasSumModified("item", $row, $prow)) {
|
||||
$insert = false;
|
||||
$row = cl::merge($prow, $row, [
|
||||
"modified_" => $now,
|
||||
]);
|
||||
} else {
|
||||
$row = cl::merge($prow, $row);
|
||||
}
|
||||
$initFunc = [$channel, "onUpdate"];
|
||||
$initArgs = $args;
|
||||
func::ensure_func($initFunc, null, $initArgs);
|
||||
$values = $this->unserialize($channel, $row);
|
||||
$pvalues = $this->unserialize($channel, $prow);
|
||||
}
|
||||
|
||||
$updates = func::call($initFunc, $item, $values, $pvalues, ...$initArgs);
|
||||
if ($updates === [false]) return 0;
|
||||
if (is_array($updates) && $updates) {
|
||||
if ($insert === null) $insert = false;
|
||||
if (!array_key_exists("modified_", $updates)) {
|
||||
$updates["modified_"] = $now;
|
||||
}
|
||||
$values = cl::merge($values, $updates);
|
||||
$row = cl::merge($row, $this->serialize($channel, $updates));
|
||||
}
|
||||
|
||||
if ($func !== null) {
|
||||
func::ensure_func($func, $channel, $args);
|
||||
$updates = func::call($func, $item, $values, $pvalues, ...$args);
|
||||
if ($updates === [false]) return 0;
|
||||
if (is_array($updates) && $updates) {
|
||||
if ($insert === null) $insert = false;
|
||||
if (!array_key_exists("modified_", $updates)) {
|
||||
$updates["modified_"] = $now;
|
||||
}
|
||||
$values = cl::merge($values, $updates);
|
||||
$row = cl::merge($row, $this->serialize($channel, $updates));
|
||||
}
|
||||
}
|
||||
|
||||
# aucune modification
|
||||
if ($insert === null) return 0;
|
||||
|
||||
# si on est déjà dans une transaction, désactiver la gestion des transactions
|
||||
$manageTransactions = $channel->isManageTransactions() && !$db->inTransaction();
|
||||
if ($manageTransactions) {
|
||||
$commited = false;
|
||||
$db->beginTransaction();
|
||||
}
|
||||
$nbModified = 0;
|
||||
try {
|
||||
if ($insert) {
|
||||
$id = $db->exec([
|
||||
"insert",
|
||||
"into" => $tableName,
|
||||
"values" => $row,
|
||||
]);
|
||||
if (count($primaryKeys) == 1 && $rowIds === null) {
|
||||
# mettre à jour avec l'id généré
|
||||
$values[$primaryKeys[0]] = $id;
|
||||
}
|
||||
$nbModified = 1;
|
||||
} else {
|
||||
# calculer ce qui a changé pour ne mettre à jour que le nécessaire
|
||||
$updates = [];
|
||||
foreach ($row as $col => $value) {
|
||||
if (array_key_exists($col, $rowIds)) {
|
||||
# ne jamais mettre à jour la clé primaire
|
||||
continue;
|
||||
}
|
||||
$pvalue = $prow[$col] ?? null;
|
||||
if ($value !== ($pvalue)) {
|
||||
$updates[$col] = $value;
|
||||
}
|
||||
}
|
||||
if (count($updates) == 1 && array_key_first($updates) == "modified_") {
|
||||
# si l'unique modification porte sur la date de modification, alors
|
||||
# la ligne n'est pas modifiée. ce cas se présente quand on altère la
|
||||
# valeur de $item
|
||||
$updates = null;
|
||||
}
|
||||
if ($updates) {
|
||||
$db->exec([
|
||||
"update",
|
||||
"table" => $tableName,
|
||||
"values" => $updates,
|
||||
"where" => $rowIds,
|
||||
]);
|
||||
$nbModified = 1;
|
||||
}
|
||||
}
|
||||
if ($manageTransactions) {
|
||||
$db->commit();
|
||||
$commited = true;
|
||||
}
|
||||
return $nbModified;
|
||||
} finally {
|
||||
if ($manageTransactions && !$commited) $db->rollback();
|
||||
}
|
||||
}
|
||||
|
||||
function charge(?string $channel, $item, $func=null, ?array $args=null, ?array &$values=null): int {
|
||||
return $this->_charge($this->getChannel($channel), $item, $func, $args, $values);
|
||||
}
|
||||
|
||||
/** décharger les données du canal spécifié */
|
||||
function _discharge(CapacitorChannel $channel, bool $reset=true): Traversable {
|
||||
$this->_create($channel);
|
||||
$rows = $this->db()->all([
|
||||
"select item__",
|
||||
"from" => $channel->getTableName(),
|
||||
]);
|
||||
foreach ($rows as $row) {
|
||||
yield unserialize($row['item__']);
|
||||
}
|
||||
if ($reset) $this->_reset($channel);
|
||||
}
|
||||
|
||||
function discharge(?string $channel, bool $reset=true): Traversable {
|
||||
return $this->_discharge($this->getChannel($channel), $reset);
|
||||
}
|
||||
|
||||
protected function _convertValue2row(CapacitorChannel $channel, array $filter, array $cols): array {
|
||||
$index = 0;
|
||||
$fixed = [];
|
||||
foreach ($filter as $key => $value) {
|
||||
if ($key === $index) {
|
||||
$index++;
|
||||
if (is_array($value)) {
|
||||
$value = $this->_convertValue2row($channel, $value, $cols);
|
||||
}
|
||||
$fixed[] = $value;
|
||||
} else {
|
||||
$col = "${key}__";
|
||||
if (array_key_exists($col, $cols)) {
|
||||
# colonne sérialisée
|
||||
$fixed[$col] = $channel->serialize($value);
|
||||
} else {
|
||||
$fixed[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $fixed;
|
||||
}
|
||||
|
||||
protected function verifixFilter(CapacitorChannel $channel, &$filter): void {
|
||||
if ($filter !== null && !is_array($filter)) {
|
||||
$primaryKeys = $this->getPrimaryKeys($channel);
|
||||
$id = $filter;
|
||||
$channel->verifixId($id);
|
||||
$filter = [$primaryKeys[0] => $id];
|
||||
}
|
||||
$cols = $this->ColumnDefinitions($channel);
|
||||
if ($filter !== null) {
|
||||
$filter = $this->_convertValue2row($channel, $filter, $cols);
|
||||
}
|
||||
}
|
||||
|
||||
/** indiquer le nombre d'éléments du canal spécifié */
|
||||
function _count(CapacitorChannel $channel, $filter): int {
|
||||
$this->_create($channel);
|
||||
$this->verifixFilter($channel, $filter);
|
||||
return $this->db()->get([
|
||||
"select count(*)",
|
||||
"from" => $channel->getTableName(),
|
||||
"where" => $filter,
|
||||
]);
|
||||
}
|
||||
|
||||
function count(?string $channel, $filter=null): int {
|
||||
return $this->_count($this->getChannel($channel), $filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* obtenir la ligne correspondant au filtre sur le canal spécifié
|
||||
*
|
||||
* si $filter n'est pas un tableau, il est transformé en ["id_" => $filter]
|
||||
*/
|
||||
function _one(CapacitorChannel $channel, $filter, ?array $mergeQuery=null): ?array {
|
||||
if ($filter === null) throw ValueException::null("filter");
|
||||
$this->_create($channel);
|
||||
$this->verifixFilter($channel, $filter);
|
||||
$row = $this->db()->one(cl::merge([
|
||||
"select",
|
||||
"from" => $channel->getTableName(),
|
||||
"where" => $filter,
|
||||
], $mergeQuery));
|
||||
return $this->unserialize($channel, $row);
|
||||
}
|
||||
|
||||
function one(?string $channel, $filter, ?array $mergeQuery=null): ?array {
|
||||
return $this->_one($this->getChannel($channel), $filter, $mergeQuery);
|
||||
}
|
||||
|
||||
private function _allCached(string $id, CapacitorChannel $channel, $filter, ?array $mergeQuery=null): Traversable {
|
||||
$this->_create($channel);
|
||||
$this->verifixFilter($channel, $filter);
|
||||
$rows = $this->db()->all(cl::merge([
|
||||
"select",
|
||||
"from" => $channel->getTableName(),
|
||||
"where" => $filter,
|
||||
], $mergeQuery), null, $this->getPrimaryKeys($channel));
|
||||
if ($channel->isUseCache()) {
|
||||
$cacheIds = [$id, get_class($channel)];
|
||||
cache::get()->resetCached($cacheIds);
|
||||
$rows = cache::new(null, $cacheIds, function() use ($rows) {
|
||||
yield from $rows;
|
||||
});
|
||||
}
|
||||
foreach ($rows as $key => $row) {
|
||||
yield $key => $this->unserialize($channel, $row);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* obtenir les lignes correspondant au filtre sur le canal spécifié
|
||||
*
|
||||
* si $filter n'est pas un tableau, il est transformé en ["id_" => $filter]
|
||||
*/
|
||||
function _all(CapacitorChannel $channel, $filter, ?array $mergeQuery=null): Traversable {
|
||||
return $this->_allCached("all", $channel, $filter, $mergeQuery);
|
||||
}
|
||||
|
||||
function all(?string $channel, $filter, $mergeQuery=null): Traversable {
|
||||
return $this->_all($this->getChannel($channel), $filter, $mergeQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* appeler une fonction pour chaque élément du canal spécifié.
|
||||
*
|
||||
* $filter permet de filtrer parmi les élements chargés
|
||||
*
|
||||
* $func est appelé avec la signature de {@link CapacitorChannel::onEach()}
|
||||
* si la fonction retourne un tableau, il est utilisé pour mettre à jour la
|
||||
* ligne
|
||||
*
|
||||
* @param int $nbUpdated reçoit le nombre de lignes mises à jour
|
||||
* @return int le nombre de lignes parcourues
|
||||
*/
|
||||
function _each(CapacitorChannel $channel, $filter, $func, ?array $args, ?array $mergeQuery=null, ?int &$nbUpdated=null): int {
|
||||
$this->_create($channel);
|
||||
if ($func === null) $func = CapacitorChannel::onEach;
|
||||
func::ensure_func($func, $channel, $args);
|
||||
$onEach = func::_prepare($func);
|
||||
$db = $this->db();
|
||||
# si on est déjà dans une transaction, désactiver la gestion des transactions
|
||||
$manageTransactions = $channel->isManageTransactions() && !$db->inTransaction();
|
||||
if ($manageTransactions) {
|
||||
$commited = false;
|
||||
$db->beginTransaction();
|
||||
$commitThreshold = $channel->getEachCommitThreshold();
|
||||
}
|
||||
$count = 0;
|
||||
$nbUpdated = 0;
|
||||
$tableName = $channel->getTableName();
|
||||
try {
|
||||
$args ??= [];
|
||||
$all = $this->_allCached("each", $channel, $filter, $mergeQuery);
|
||||
foreach ($all as $values) {
|
||||
$rowIds = $this->getRowIds($channel, $values);
|
||||
$updates = func::_call($onEach, [$values["item"], $values, ...$args]);
|
||||
if (is_array($updates) && $updates) {
|
||||
if (!array_key_exists("modified_", $updates)) {
|
||||
$updates["modified_"] = date("Y-m-d H:i:s");
|
||||
}
|
||||
$nbUpdated += $db->exec([
|
||||
"update",
|
||||
"table" => $tableName,
|
||||
"values" => $this->serialize($channel, $updates),
|
||||
"where" => $rowIds,
|
||||
]);
|
||||
if ($manageTransactions && $commitThreshold !== null) {
|
||||
$commitThreshold--;
|
||||
if ($commitThreshold <= 0) {
|
||||
$db->commit();
|
||||
$db->beginTransaction();
|
||||
$commitThreshold = $channel->getEachCommitThreshold();
|
||||
}
|
||||
}
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
if ($manageTransactions) {
|
||||
$db->commit();
|
||||
$commited = true;
|
||||
}
|
||||
return $count;
|
||||
} finally {
|
||||
if ($manageTransactions && !$commited) $db->rollback();
|
||||
}
|
||||
}
|
||||
|
||||
function each(?string $channel, $filter, $func=null, ?array $args=null, ?array $mergeQuery=null, ?int &$nbUpdated=null): int {
|
||||
return $this->_each($this->getChannel($channel), $filter, $func, $args, $mergeQuery, $nbUpdated);
|
||||
}
|
||||
|
||||
/**
|
||||
* supprimer tous les éléments correspondant au filtre et pour lesquels la
|
||||
* fonction retourne une valeur vraie si elle est spécifiée
|
||||
*
|
||||
* $filter permet de filtrer parmi les élements chargés
|
||||
*
|
||||
* $func est appelé avec la signature de {@link CapacitorChannel::onDelete()}
|
||||
* si la fonction retourne un tableau, il est utilisé pour mettre à jour la
|
||||
* ligne
|
||||
*
|
||||
* @return int le nombre de lignes parcourues
|
||||
*/
|
||||
function _delete(CapacitorChannel $channel, $filter, $func, ?array $args): int {
|
||||
$this->_create($channel);
|
||||
if ($func === null) $func = CapacitorChannel::onDelete;
|
||||
func::ensure_func($func, $channel, $args);
|
||||
$onEach = func::_prepare($func);
|
||||
$db = $this->db();
|
||||
# si on est déjà dans une transaction, désactiver la gestion des transactions
|
||||
$manageTransactions = $channel->isManageTransactions() && !$db->inTransaction();
|
||||
if ($manageTransactions) {
|
||||
$commited = false;
|
||||
$db->beginTransaction();
|
||||
$commitThreshold = $channel->getEachCommitThreshold();
|
||||
}
|
||||
$count = 0;
|
||||
$tableName = $channel->getTableName();
|
||||
try {
|
||||
$args ??= [];
|
||||
$all = $this->_allCached("delete", $channel, $filter);
|
||||
foreach ($all as $values) {
|
||||
$rowIds = $this->getRowIds($channel, $values);
|
||||
$delete = boolval(func::_call($onEach, [$values["item"], $values, ...$args]));
|
||||
if ($delete) {
|
||||
$db->exec([
|
||||
"delete",
|
||||
"from" => $tableName,
|
||||
"where" => $rowIds,
|
||||
]);
|
||||
if ($manageTransactions && $commitThreshold !== null) {
|
||||
$commitThreshold--;
|
||||
if ($commitThreshold <= 0) {
|
||||
$db->commit();
|
||||
$db->beginTransaction();
|
||||
$commitThreshold = $channel->getEachCommitThreshold();
|
||||
}
|
||||
}
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
if ($manageTransactions) {
|
||||
$db->commit();
|
||||
$commited = true;
|
||||
}
|
||||
return $count;
|
||||
} finally {
|
||||
if ($manageTransactions && !$commited) $db->rollback();
|
||||
}
|
||||
}
|
||||
|
||||
function delete(?string $channel, $filter, $func=null, ?array $args=null): int {
|
||||
return $this->_delete($this->getChannel($channel), $filter, $func, $args);
|
||||
}
|
||||
|
||||
abstract function close(): void;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue