<pman>Intégration de la branche rel74-0.4.0

This commit is contained in:
Jephté Clain 2025-03-14 15:23:41 +04:00
commit 559feda663
46 changed files with 1030 additions and 1131 deletions

8
.pman.yml Normal file
View File

@ -0,0 +1,8 @@
# -*- coding: utf-8 mode: yaml -*- vim:sw=2:sts=2:et:ai:si:sta:fenc=utf-8
composer:
profiles: [ dev, dist ]
dev:
link: true
dist:
link: false

View File

@ -1,9 +1,36 @@
## Release 0.4.0p74 du 14/03/2025-15:23
* `cf9fab5` maj src/php
* `5c5d878` pdev: option --force-merge
* `9723c14` ajout cl::same_keys()
* `5ae3e8b` pdev: ajout --after-merge
* `cfc386d` Revert "prel/pdev: tracer les hooks"
* `d44537a` prel/pdev: tracer les hooks
* `e8abaca` supprimer tests qui sont encore dans nur/ture
* `a3116e5` ajout du schéma
* `0d2ca20` prel/pdev: option --fake
* `bd0da9c` prel/pdev: ajouter les hook BEFORE_*
* `7e05caf` runphp: passer les arguments inchangés à composer
* `9def939` p: support des projets dépendants composer
* `01c65a6` tests verbosity et interaction
* `8e3569a` ne plus utiliser tooenc par défaut. renommer tooenc en uecho
* `ead5b5a` support automatique options verbosity et interaction
* `8825493` pman: tenir compte des branches distantes
* `e129e0a` ajout pwip
* `9a2378b` pman: améliorer l'ergonomie
* `8cfd803` gestion des profils composer
* `d9989c6` supprimer composer.phar puisque c'est fourni par runphp
* `7eb5efb` ajout config .pman.yml
* `92363cd` pman: option --force-create
* `3b379eb` maj doc
* `bbb5559` pman: ajout init pman
* `939f772` pman: support des config standard nommées
## Release 0.3.4p82 du 01/03/2025-06:23
## Release 0.3.4p74 du 01/03/2025-06:22
* `62b9230` pdev: ne pas inscrire delete si cette opération est interdite
## Release 0.3.3p74 du 01/03/2025-06:14
* `2163ea9` pdev/prel: scripts post merge/release
## Release 0.3.2p82 du 28/02/2025-20:30

View File

@ -1 +1 @@
0.3.4
0.4.0

View File

@ -6,15 +6,15 @@ function __esection() {
local length="${COLUMNS:-80}"
setx lsep=__complete "$prefix" "$length" -
tooenc "$COULEUR_BLEUE$lsep$COULEUR_NORMALE"
recho "$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"
recho "$COULEUR_BLEUE$line-$COULEUR_NORMALE"
done
tooenc "$COULEUR_BLEUE$lsep$COULEUR_NORMALE"
recho "$COULEUR_BLEUE$lsep$COULEUR_NORMALE"
}
function __etitle() {
local -a lines; local maxlen=0
@ -23,10 +23,10 @@ function __etitle() {
setx -a lines=echo "$1"
for line in "${lines[@]}"; do
[ ${#line} -gt $maxlen ] && maxlen=${#line}
tooenc "${prefix}${COULEUR_BLEUE}T $line$COULEUR_NORMALE"
recho "${prefix}${COULEUR_BLEUE}T $line$COULEUR_NORMALE"
done
maxlen=$((maxlen + 2))
tooenc "${prefix}${COULEUR_BLEUE}T$(__complete "" $maxlen -)${COULEUR_NORMALE}"
recho "${prefix}${COULEUR_BLEUE}T$(__complete "" $maxlen -)${COULEUR_NORMALE}"
}
function __edesc() {
local -a lines
@ -34,7 +34,7 @@ function __edesc() {
setx -a lines=echo "$1"
for line in "${lines[@]}"; do
tooenc "${prefix}${COULEUR_BLEUE}>${COULEUR_NORMALE} $line"
recho "${prefix}${COULEUR_BLEUE}>${COULEUR_NORMALE} $line"
done
}
function __ebanner() {
@ -43,35 +43,35 @@ function __ebanner() {
local length="${COLUMNS:-80}"
setx lsep=__complete "$prefix" "$length" =
tooenc "$COULEUR_ROUGE$lsep"
recho "$COULEUR_ROUGE$lsep"
length=$((length - 1))
setx -a lines=echo "$1"
for line in "" "${lines[@]}" ""; do
setx line=__complete "$prefix= $line" "$length"
tooenc "$line="
recho "$line="
done
tooenc "$lsep$COULEUR_NORMALE"
recho "$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 __eimportant() { recho "$(__edate)$(__eindent0)${COULEUR_ROUGE}!${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
function __eattention() { recho "$(__edate)$(__eindent0)${COULEUR_JAUNE}*${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
function __eerror() { recho "$(__edate)$(__eindent0)${COULEUR_ROUGE}E${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
function __ewarn() { recho "$(__edate)$(__eindent0)${COULEUR_JAUNE}W${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
function __enote() { recho "$(__edate)$(__eindent0)${COULEUR_VERTE}N${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
function __einfo() { recho "$(__edate)$(__eindent0)${COULEUR_BLEUE}I${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
function __edebug() { recho "$(__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 __estep() { recho "$(__edate)$(__eindent0)${COULEUR_BLANCHE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
function __estepe() { recho "$(__edate)$(__eindent0)${COULEUR_ROUGE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
function __estepw() { recho "$(__edate)$(__eindent0)${COULEUR_JAUNE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
function __estepn() { recho "$(__edate)$(__eindent0)${COULEUR_VERTE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
function __estepi() { recho "$(__edate)$(__eindent0)${COULEUR_BLEUE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
function __estep_() { recho_ "$(__edate)$(__eindent0)${COULEUR_BLANCHE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
function __estepe_() { recho_ "$(__edate)$(__eindent0)${COULEUR_ROUGE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
function __estepw_() { recho_ "$(__edate)$(__eindent0)${COULEUR_JAUNE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
function __estepn_() { recho_ "$(__edate)$(__eindent0)${COULEUR_VERTE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
function __estepi_() { recho_ "$(__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")"; }
function __action() { recho "$(__edate)$(__eindent0)${COULEUR_BLANCHE}.${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
function __asuccess() { recho "$(__edate)$(__eindent0)${COULEUR_VERTE}${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
function __afailure() { recho "$(__edate)$(__eindent0)${COULEUR_ROUGE}${COULEUR_NORMALE} $(__eindent "$1" " ")"; }
function __adone() { recho "$(__edate)$(__eindent0)$(__eindent "$1")"; }

View File

@ -6,23 +6,23 @@ function __esection() {
local length="${COLUMNS:-80}"
setx lsep=__complete "$prefix" "$length" -
tooenc "$lsep"
recho "$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-"
recho "$line-"
done
tooenc "$lsep"
recho "$lsep"
}
function __etitle() {
local p="TITLE: " i=" "
tooenc "$(__edate)$(__eindent0)${p}$(__eindent "$1" "$i")"
recho "$(__edate)$(__eindent0)${p}$(__eindent "$1" "$i")"
}
function __edesc() {
local p="DESC: " i=" "
tooenc "$(__edate)$(__eindent0)${p}$(__eindent "$1" "$i")"
recho "$(__edate)$(__eindent0)${p}$(__eindent "$1" "$i")"
}
function __ebanner() {
local -a lines
@ -30,37 +30,37 @@ function __ebanner() {
local length="${COLUMNS:-80}"
setx lsep=__complete "$prefix" "$length" =
tooenc "$lsep"
recho "$lsep"
length=$((length - 1))
setx -a lines=echo "$1"
for line in "" "${lines[@]}" ""; do
setx line=__complete "$prefix= $line" "$length"
tooenc "$line="
recho "$line="
done
tooenc "$lsep"
recho "$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 __eimportant() { recho "$(__edate)$(__eindent0)IMPORTANT! $(__eindent "$1" " ")"; }
function __eattention() { recho "$(__edate)$(__eindent0)ATTENTION! $(__eindent "$1" " ")"; }
function __eerror() { recho "$(__edate)$(__eindent0)ERROR: $(__eindent "$1" " ")"; }
function __ewarn() { recho "$(__edate)$(__eindent0)WARNING: $(__eindent "$1" " ")"; }
function __enote() { recho "$(__edate)$(__eindent0)NOTE: $(__eindent "$1" " ")"; }
function __einfo() { recho "$(__edate)$(__eindent0)INFO: $(__eindent "$1" " ")"; }
function __edebug() { recho "$(__edate)$(__eindent0)DEBUG: $(__eindent "$1" " ")"; }
function __eecho() { recho "$(__edate)$(__eindent0)$(__eindent "$1")"; }
function __eecho_() { recho_ "$(__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 __estep() { recho "$(__edate)$(__eindent0). $(__eindent "$1" " ")"; }
function __estepe() { recho "$(__edate)$(__eindent0).E $(__eindent "$1" " ")"; }
function __estepw() { recho "$(__edate)$(__eindent0).W $(__eindent "$1" " ")"; }
function __estepn() { recho "$(__edate)$(__eindent0).N $(__eindent "$1" " ")"; }
function __estepi() { recho "$(__edate)$(__eindent0).I $(__eindent "$1" " ")"; }
function __estep_() { recho_ "$(__edate)$(__eindent0). $(__eindent "$1" " ")"; }
function __estepe_() { recho_ "$(__edate)$(__eindent0).E $(__eindent "$1" " ")"; }
function __estepw_() { recho_ "$(__edate)$(__eindent0).W $(__eindent "$1" " ")"; }
function __estepn_() { recho_ "$(__edate)$(__eindent0).N $(__eindent "$1" " ")"; }
function __estepi_() { recho_ "$(__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")"; }
function __action() { recho "$(__edate)$(__eindent0)ACTION: $(__eindent "$1" " ")"; }
function __asuccess() { recho "$(__edate)$(__eindent0)(OK) $(__eindent "$1" " ")"; }
function __afailure() { recho "$(__edate)$(__eindent0)(KO) $(__eindent "$1" " ")"; }
function __adone() { recho "$(__edate)$(__eindent0)$(__eindent "$1")"; }

View File

@ -124,8 +124,8 @@ optdesc
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"
[ -n "$NULIB_ARGS_ONERROR_RETURN" ] && set_die_return
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"
@ -145,17 +145,33 @@ function parse_args() {
__r=1
else
__DEFS=("$@")
__parse_args || __r=1
__nulib_args_parse_args || __r=1
fi
eval "$NULIB__ENABLE_SET_X"
if [ -n "$__r" ]; then
eval "$__DIE"
die || return
fi
}
function __parse_args() {
function __nulib_args_add_sopt() {
local noauto="$1"; shift
local def
for def in "$@"; do
array_contains "$noauto" "$def" || __sopts="$__sopts$def"
done
}
function __nulib_args_add_lopt() {
local noauto="$1"; shift
local def
for def in "$@"; do
array_contains "$noauto" "$def" || __lopts="$__lopts${__lopts:+,}$def"
done
}
function __nulib_args_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 -a __NOAUTOL __NOAUTOLOGTO # faut-il rajouter les options pour gérer la journalisation?
local -a __NOAUTOV __NOAUTOVERBOSITY # options de verbosité qui ont été définies par l'utilisateur
local -a __NOAUTOI __NOAUTOINTERACTION # options d'interaction qui ont été définies par l'utilisateur
local __ADVHELP # y a-t-il des options avancées?
local __popt __sopts __lopts
local -a __defs
@ -165,10 +181,10 @@ function __parse_args() {
+) __popt="$1"; shift; continue;;
-) __popt="$1"; shift; continue;;
-*) IFS=, read -a __defs <<<"$1"; shift;;
*) eerror "Invalid arg definition: expected option, got '$1'"; eval "$__DIE";;
*) die "Invalid arg definition: expected option, got '$1'" || return;;
esac
# est-ce que l'option prend un argument?
local __def __witharg __valdesc
local __def __longdef __witharg __valdesc
__witharg=
for __def in "${__defs[@]}"; do
if [ "${__def%::*}" != "$__def" ]; then
@ -180,23 +196,36 @@ function __parse_args() {
# définitions __sopts et __lopts
for __def in "${__defs[@]}"; do
__def="${__def%%:*}"
__longdef=
if [[ "$__def" == --* ]]; then
# --longopt
__def="${__def#--}"
__lopts="$__lopts${__lopts:+,}$__def$__witharg"
__longdef=1
elif [[ "$__def" == -* ]] && [ ${#__def} -eq 2 ]; then
# -o
__def="${__def#-}"
__sopts="$__sopts$__def$__witharg"
[ "$__def" == h ] && __AUTOH=
[ "$__def" == D ] && __AUTOD=
case "$__def" in
h) __AUTOH=;;
L) __NOAUTOL+=("-$__def");;
Q|q|v|D) __NOAUTOV+=("-$__def");;
b|y|i) __NOAUTOI+=("-$__def");;
esac
else
# -longopt ou longopt
__def="${__def#-}"
__lopts="$__lopts${__lopts:+,}$__def$__witharg"
__longdef=1
fi
if [ -n "$__longdef" ]; then
case "$__def" in
help|help++) __AUTOHELP=;;
log-to) __NOAUTOLOGTO+=("--$__def");;
very-quiet|quiet|verbose|debug) __NOAUTOVERBOSITY+=("--$__def");;
batch|automatic|interactive) __NOAUTOINTERACTION+=("--$__def");;
esac
fi
[ "$__def" == help -o "$__def" == help++ ] && __AUTOHELP=
[ "$__def" == debug ] && __AUTODEBUG=
done
# sauter l'action
shift
@ -209,8 +238,12 @@ function __parse_args() {
[ -n "$__AUTOH" ] && __sopts="${__sopts}h"
[ -n "$__AUTOHELP" ] && __lopts="$__lopts${__lopts:+,}help,help++"
[ -n "$__AUTOD" ] && __sopts="${__sopts}D"
[ -n "$__AUTODEBUG" ] && __lopts="$__lopts${__lopts:+,}debug"
__nulib_args_add_sopt __NOAUTOL L
__nulib_args_add_lopt __NOAUTOLOGTO log-to
__nulib_args_add_sopt __NOAUTOV Q q v D
__nulib_args_add_lopt __NOAUTOVERBOSITY very-quiet quiet verbose debug
__nulib_args_add_sopt __NOAUTOI b y i
__nulib_args_add_lopt __NOAUTOINTERACTION batch automatic interactive
__sopts="$__popt$__sopts"
local -a __getopt_args
@ -222,7 +255,7 @@ function __parse_args() {
else
# relancer pour avoir le message d'erreur
LANG=C getopt "${__getopt_args[@]}" 2>&1 1>/dev/null
eval "$__DIE"
die || return
fi
## puis traiter les options
@ -373,7 +406,7 @@ $prefix$usage"
fi
[[ "$1" == -* ]] || break
option_="$1"; shift
__parse_opt "$option_"
__nulib_args_parse_opt "$option_"
if [ -n "$__witharg" ]; then
# l'option prend un argument
value_="$1"; shift
@ -387,7 +420,7 @@ $prefix$usage"
unset -f inc@ res@ add@ set@ showhelp@
args=("$@")
}
function __parse_opt() {
function __nulib_args_parse_opt() {
# $1 est l'option spécifiée
local option_="$1"
set -- "${__DEFS[@]}"
@ -460,27 +493,62 @@ function __parse_opt() {
[ -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@ ++"
case "$option_" in
-h)
if [ -n "$__AUTOH" ]; 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
;;
--help)
if [ -n "$__AUTOHELP" ]; then
__action='showhelp@'
return 0
fi
;;
--help++)
if [ -n "$__AUTOHELP" ]; then
__action='showhelp@ ++'
return 0
fi
;;
-L)
if ! array_contains __NOAUTOL "$option_"; then
__action='elogto $value_'
return 0
fi
;;
--log-to)
if ! array_contains __NOAUTOL "$option_"; then
__action='elogto $value_'
return 0
fi
;;
-Q|-q|-v|-D)
if ! array_contains __NOAUTOV "$option_"; then
__action='set_verbosity $option_'
return 0
fi
;;
--very-quiet|--quiet|--verbose|--debug)
if ! array_contains __NOAUTOVERBOSITY "$option_"; then
__action='set_verbosity $option_'
return 0
fi
;;
-b|-y|-i)
if ! array_contains __NOAUTOI "$option_"; then
__action='set_interaction $option_'
return 0
fi
;;
--batch|--automatic|--interactive)
if ! array_contains __NOAUTOINTERACTION "$option_"; then
__action='set_interaction $option_'
return 0
fi
;;
esac
# ici, l'option n'a pas été trouvée, on ne devrait pas arriver ici
eerror "Unexpected option '$option_'"; eval "$__DIE"
die "Unexpected option '$option_'" || return
}

View File

@ -62,7 +62,7 @@ function ask_yesno() {
else
__eecho_ "Voulez-vous continuer?" 1>&2
fi
tooenc_ " $prompt " 1>&2
echo_ " $prompt " 1>&2
uread r
is_yes "${r:-$default}"
else
@ -198,17 +198,17 @@ function __rv_read() {
__eecho_ "Entrez la valeur" 1>&2
fi
if [ -n "$__rv_readline" ]; then
tooenc_ ": " 1>&2
echo_ ": " 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
echo_ " [$__rv_d]" 1>&2
else
tooenc_ " [****]" 1>&2
echo_ " [****]" 1>&2
fi
fi
tooenc_ ": " 1>&2
echo_ ": " 1>&2
uread "${__rv_opts[@]}" __rv_r
[ -n "$__rv_nl" ] && echo
fi
@ -217,6 +217,7 @@ function __rv_read() {
_setv "$__rv_v" "$__rv_r"
return 0
fi
echo
done
}
@ -268,7 +269,7 @@ function simple_menu() {
else
__eecho_ "Entrez le numéro de l'option choisie" 1>&2
fi
tooenc_ ": " 1>&2
echo_ ": " 1>&2
uread __sm_choice
# Valeur par défaut
@ -291,7 +292,7 @@ function simple_menu() {
let __sm_c=$__sm_c+1
if [ "$__sm_c" -eq 5 ]; then
# sauter une ligne toutes les 4 tentatives
tooenc "" 1>&2
echo 1>&2
__sm_c=0
fi
done
@ -438,7 +439,7 @@ function __void_actions_menu() {
if [ $c -eq 0 ]; then
[ -n "$title" ] && __etitle "$title" 1>&2
__eecho_ "=== Actions disponibles: " 1>&2
tooenc "$action_title" 1>&2
recho "$action_title" 1>&2
fi
if [ -n "$actyc" ]; then
__eecho_ "$actyc" 1>&2
@ -447,7 +448,7 @@ function __void_actions_menu() {
else
__eecho_ "Entrez l'action à effectuer" 1>&2
fi
tooenc_ ": " 1>&2
echo_ ": " 1>&2
uread choice
if [ -z "$choice" -a -n "$default_action" ]; then
select_action="$default_action"
@ -468,7 +469,7 @@ function __void_actions_menu() {
let c=$c+1
if [ $c -eq 5 ]; then
# sauter une ligne toutes les 4 tentatives
tooenc "" 1>&2
echo 1>&2
c=0
fi
done
@ -484,21 +485,21 @@ function __options_actions_menu() {
i=1
for option in "${options[@]}"; do
if [ "$option" == "$select_option" ]; then
tooenc "$i*- $option" 1>&2
echo "$i*- $option" 1>&2
else
tooenc "$i - $option" 1>&2
echo "$i - $option" 1>&2
fi
let i=$i+1
done
__estepn_ "Actions disponibles: " 1>&2
tooenc "$action_title" 1>&2
recho "$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
echo_ ": " 1>&2
uread choice
# vérifier la saisie
@ -572,7 +573,7 @@ function __options_actions_menu() {
let c=$c+1
if [ $c -eq 5 ]; then
# sauter une ligne toutes les 4 tentatives
tooenc "" 1>&2
echo "" 1>&2
c=0
fi
done

View File

@ -83,7 +83,7 @@ function err_isatty() {
################################################################################
function tooenc() {
function uecho() {
# $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}"
@ -93,9 +93,8 @@ function tooenc() {
iconv -f -utf-8 -t "$to" <<<"$value"
fi
}
function uecho() { tooenc "$*"; }
function tooenc_() {
function uecho_() {
# $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}"
@ -105,7 +104,6 @@ function tooenc_() {
recho_ "$value" | iconv -f utf-8 -t "$to"
fi
}
function uecho_() { tooenc_ "$*"; }
export NULIB_QUIETLOG
export NULIB__TMPLOG
@ -210,7 +208,7 @@ 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"
setx -a lines=recho "$1"
for line in "${lines[@]}"; do
if [ -n "$first" ]; then
recho "$line"
@ -232,7 +230,11 @@ function __complete() {
}
PRETTYOPTS=()
function set_verbosity() { :;}
function set_verbosity() {
case "$1" in
-D|--debug) NULIB_DEBUG=1;;
esac
}
function check_verbosity() { return 0; }
function get_verbosity_option() { :;}

View File

@ -2,20 +2,13 @@
## configuration par défaut
# branche upstream
UPSTREAM=
# branches de développement
DEVELOP=develop
FEATURE=wip/
# branche de préparation de release
RELEASE=release-
# branche de release
MAIN=master
TAG_PREFIX=
TAG_SUFFIX=
# branche de hotfix
HOTFIX=hotfix-
# branche de distribution
DIST=
# désactiver les releases automatiques?
NOAUTO=

View File

@ -5,15 +5,23 @@
# les branches sont mergées dans cet ordre:
# upstream --> develop --> [release -->] main --> dist
# feature _/ hotfix _/
# branche upstream
UPSTREAM=
# branches de développement
DEVELOP=develop
FEATURE=wip/
# branche de préparation de release
RELEASE=release-
# branche de release
MAIN=master
TAG_PREFIX=
TAG_SUFFIX=
# branche de hotfix
HOTFIX=hotfix-
# branche de distribution
DIST=
# désactiver les releases automatiques?
NOAUTO=
CONFIG_VARS=(
@ -151,6 +159,7 @@ function load_branches() {
local what="${1:-all}"; shift
case "$what" in
all)
[ -n "$Origin" ] || Origin=origin
setx CurrentBranch=git_get_branch
setx -a LocalBranches=git_list_branches
setx -a RemoteBranches=git_list_rbranches "$Origin"
@ -187,12 +196,12 @@ function load_branches() {
ReleaseBranch=
HotfixBranch=
MainBranch=
Dist=Branch
for branch in "${AllBranches[@]}"; do
DistBranch=
for branch in "${LocalBranches[@]}"; do
if [ "$branch" == "$UPSTREAM" ]; then
UpstreamBranch="$branch"
elif [[ "$branch" == "$FEATURE"* ]]; then
FeatureBranch+=("$branch")
FeatureBranches+=("$branch")
elif [ "$branch" == "$DEVELOP" ]; then
DevelopBranch="$branch"
elif [[ "$branch" == "$RELEASE"* ]]; then
@ -210,31 +219,50 @@ function load_branches() {
}
function load_config() {
if [ "${ConfigFile#::}" != "$ConfigFile" ]; then
ConfigFile="$NULIBDIR/bash/src/pman${ConfigFile#::}.conf.sh"
fi
if [ -n "$ConfigFile" ]; then
source "$ConfigFile" || die || return
elif [ -n "$ConfigBranch" ]; then
# c'est le seul cas où ConfigFile reste vide
if ! array_contains LocalBranches "$ConfigBranch"; then
die "$ConfigBranch: branche de configuration introuvable" || return
else
ac_set_tmpfile ConfigFile
git show "$ConfigBranch:.pman.conf" >"$ConfigFile" 2>/dev/null
[ -s "$ConfigFile" ] || die "$ConfigBranch: aucune configuration trouvée sur cette branche" || return
source "$ConfigFile"
local config
ac_set_tmpfile config
git show "$ConfigBranch:.pman.conf" >"$config" 2>/dev/null
[ -s "$config" ] || die "$ConfigBranch: aucune configuration trouvée sur cette branche" || return
source "$config"
fi
elif [ -f .pman.conf ]; then
ConfigFile="$(pwd)/.pman.conf"
source "$ConfigFile"
elif [ -n "${MYNAME#prel}" ]; then
elif [ -n "$1" -a -n "${MYNAME#$1}" ]; then
ConfigFile="$NULIBDIR/bash/src/pman${MYNAME#$1}.conf.sh"
source "$ConfigFile"
else
ConfigFile="$NULIBDIR/bash/src/pman.conf.sh"
fi
# S'assurer que nulib est dans le PATH pour que les scripts utilisateurs
# puissent utiliser les outils fournis
export PATH="$NULIBDIR/bin:$PATH"
}
################################################################################
# Divers
function resolve_should_push() {
local quiet="$1"
ShouldPush=1
if ! git_have_remote "$Origin" && [ -n "$Push" ]; then
[ -n "$quiet" ] || enote "L'option --no-push a été forcée puisque ce dépôt n'a pas d'origine"
ShouldPush=
fi
[ -z "$ShouldPush" ] && Push=
}
function _push_branches() {
[ ${#push_branches[*]} -gt 0 ] || return
[ -n "$Origin" ] || Origin=origin

View File

@ -108,11 +108,17 @@ function set_interaction() {
# set_interaction en fonction des arguments de la ligne de commande. A utiliser
# de cette manière:
# parse_opts ... "${PRETTYOPTS[@]}" @ args -- ...
PRETTYOPTS=(
# NB: ce n'est pas nécessaire, sauf si on veut afficher ces options dans l'aide
LOGTOOPTS=(
-L:,--log-to:LOGFILE '$elogto $value_' "++enregistrer les messages dans le fichier spécifié"
)
VERBOSITYOPTS=(
-Q,--very-quiet,-q,--quiet,-v,--verbose,-D,--debug '$set_verbosity $option_' "++spécifier le niveau de verbiage"
)
INTERACTIONOPTS=(
-b,--batch,-y,--automatic,-i,--interactive '$set_interaction $option_' "++spécifier le niveau d'interaction"
)
PRETTYOPTS=("${LOGTOOPTS[@]}" "${VERBOSITYOPTS[@]}" "${INTERACTIONOPTS[@]}")
function show_error() { [ "$__verbosity" -ge 1 ]; }
function show_warn() { [ "$__verbosity" -ge 2 ]; }

29
bash/tests/test-interaction.sh Executable file
View File

@ -0,0 +1,29 @@
#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
source "$(dirname -- "$0")/../src/nulib.sh" || exit 1
#NULIB_NO_DISABLE_SET_X=1
args=(
"tester diverses fonctions de saisie"
)
parse_args "$@"; set -- "${args[@]}"
estep "inter non auto non"
ask_yesno "oui ou non?" && echo oui || echo non
estep "inter oui auto oui"
ask_yesno "oui ou non?" O && echo oui || echo non
estep "inter non auto non"
ask_yesno "oui ou non?" N && echo oui || echo non
estep "inter non auto oui"
ask_yesno "oui ou non?" C && echo oui || echo non
estep "inter oui auto non"
ask_yesno "oui ou non?" X && echo oui || echo non
estep "valeur par défaut vide"
read_value "valeur" empty "" N; echo "valeur=$empty"
estep "valeur par défaut non vide"
read_value "valeur" default default N; echo "valeur=$default"
estep "valeur requise"
read_value "valeur" required; echo "valeur=$required"

View File

@ -7,7 +7,6 @@ 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'

24
bash/tests/test-verbosity.sh Executable file
View File

@ -0,0 +1,24 @@
#!/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=(
"afficher divers messages avec les fonctions e*"
)
parse_args "$@"; set -- "${args[@]}"
eimportant "important (q)"
eattention "attention (q)"
eerror "error (q)"
ewarn "warn (q)"
enote "note (qv)"
einfo "info (qv)"
eecho "echo (qv)"
edebug "debug (D)"
estep "step (qv)"
estepe "stepe (qv)"
estepw "stepw (qv)"
estepn "stepn (qv)"
estepi "stepi (qv)"

View File

@ -1,4 +1,4 @@
#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
exec "$(dirname -- "$0")/pdev" --tech-merge -Bdev82 dev74 "$@"
exec "$(dirname -- "$0")/pdev" --tech-merge -Bdev82 dev74 -a "git checkout dev74" "$@"

View File

@ -0,0 +1,14 @@
#!/usr/bin/php
<?php
require __DIR__ . "/../vendor/autoload.php";
use nulib\tools\pman\ComposerFile;
use nulib\tools\pman\PmanYamlConfigFile;
use nulib\ValueException;
$composer = new ComposerFile();
$deps = $composer->getLocalDeps();
foreach ($deps as $dep => $path) {
echo "$path\n";
}

View File

@ -0,0 +1,22 @@
#!/usr/bin/php
<?php
require __DIR__ . "/../vendor/autoload.php";
use nulib\tools\pman\ComposerFile;
use nulib\tools\pman\PmanYamlConfigFile;
use nulib\ValueException;
$composer = new ComposerFile();
$config = new PmanYamlConfigFile();
if ($argc <= 1) {
throw new ValueException("Il faut spécifier le profil à sélectionner");
}
$profile = $argv[1];
$composer->selectProfile($profile, $config);
if (getenv("PMAN_COMPOSER_DEBUG")) {
$composer->print();
} else {
$composer->write();
}

34
bin/p
View File

@ -20,8 +20,18 @@ function git_status() {
fi
}
function git_statuses() {
local cwd="$(pwd)" dir
for dir in "$@"; do
cd "$dir" || die
git_status --porcelain
cd "$cwd"
done
}
chdir=
all=
composer=
args=(
"afficher l'état du dépôt"
"[-d chdir] [-a patterns...]
@ -29,6 +39,7 @@ args=(
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"
-r,--composer composer=1 "faire l'opération sur tous les projets composer dépendants"
)
parse_args "$@"; set -- "${args[@]}"
@ -50,16 +61,23 @@ if [ -n "$all" ]; then
dirs+=("${dir%/.git}")
done
fi
setx cwd=pwd
for dir in "${dirs[@]}"; do
cd "$dir" || die
git_status --porcelain
cd "$cwd"
done
git_statuses "${dirs[@]}"
elif [ -n "$composer" ]; then
# projets dépendants
git_ensure_gitvcs
setx toplevel=git_get_toplevel
cd "$toplevel" || die
setx cwd=ppath2 . "$OrigCwd"
[ -f composer.json ] || die "$cwd: ce n'est pas un projet composer"
setx -a dirs="$MYDIR/_pman-composer_local_deps.php"
git_statuses "${dirs[@]}"
else
# répertoire courant uniquement
setx toplevel=git_get_toplevel
[ -n "$toplevel" ] && Cwd="$toplevel"
git_ensure_gitvcs
Cwd="$(git_get_toplevel)"
args=()
isatty || args+=(--porcelain)

127
bin/pdev
View File

@ -25,6 +25,9 @@ function ensure_branches() {
}
function merge_action() {
[ -z "$ShouldPush" ] && enote "\
L'option --no-push a été forcée puisque ce dépôt n'a pas d'origine"
enote "\
Ce script va
- fusionner la branche ${COULEUR_BLEUE}$SrcBranch${COULEUR_NORMALE} dans ${COULEUR_ROUGE}$DestBranch${COULEUR_NORMALE}${Push:+
@ -33,7 +36,7 @@ Ce script va
local script=".git/pman-merge.sh"
local -a push_branches delete_branches
local after
local hook
local comment=
local or_die=" || exit 1"
@ -44,17 +47,22 @@ Ce script va
if [ -n "\$merge" ]; then
esection "Fusionner la branche"
EOF
_mscript_merge_branch
after="AFTER_MERGE_${SrcType^^}"; [ -n "${!after}" ] && _scripta <<EOF
hook="BEFORE_MERGE_${SrcType^^}"; [ -n "${!hook}" ] && _scripta <<EOF
(
${!after}
${!hook}
)$or_die
EOF
_mscript_merge_branch
hook="AFTER_MERGE_${SrcType^^}"; [ -n "${!hook}" ] && _scripta <<EOF
(
${!hook}
)$or_die
EOF
_scripta <<EOF
fi
EOF
if [ -z "$ForbidDelete" ]; then
if [ -n "$ShouldDelete" ]; then
_scripta <<EOF
################################################################################
# delete
@ -62,9 +70,9 @@ if [ -n "\$delete" ]; then
esection "Supprimer la branche"
EOF
_mscript_delete_branch
after="AFTER_DELETE_${SrcType^^}"; [ -n "${!after}" ] && _scripta <<EOF
hook="AFTER_DELETE_${SrcType^^}"; [ -n "${!hook}" ] && _scripta <<EOF
(
${!after}
${!hook}
)$or_die
EOF
_scripta <<EOF
@ -77,6 +85,11 @@ EOF
# push
if [ -n "\$push" ]; then
esection "Pousser les branches"
EOF
hook="BEFORE_PUSH_${DestType^^}"; [ -n "${!hook}" ] && _scripta <<EOF
(
${!hook}
)$or_die
EOF
_script_push_branches
if [ ${#delete_branches[*]} -gt 0 ]; then
@ -85,35 +98,42 @@ EOF
_script_push_branches
_scripta <<<fi
fi
after="AFTER_PUSH_${DestType^^}"; [ -n "${!after}" ] && _scripta <<EOF
hook="AFTER_PUSH_${DestType^^}"; [ -n "${!hook}" ] && _scripta <<EOF
(
${!after}
${!hook}
)$or_die
EOF
_scripta <<EOF
fi
EOF
[ -n "$Delete" -o "$ForbidDelete" ] && Deleted=1 || Deleted=
[ -n "$Push" -o "$CantPush" ] && Pushed=1 || Pushed=
if [ -n "$_NoRunScript" ]; then
einfo "Veuillez consulter le script $script pour le détail des opérations à effectuer"
[ -n "$Delete" -o -z "$ShouldDelete" ] && Deleted=1 || Deleted=
[ -n "$ShouldDelete" -a -n "$Delete" ] && ShouldDelete=
[ -n "$ShouldPush" -a -n "$Push" ] && ShouldPush=
if [ -n "$_Fake" ]; then
cat "$script"
elif ! "$script" merge ${Delete:+delete} ${Push:+push}; then
eimportant "\
Le script $script a été lancé avec les arguments 'merge${Delete:+ delete}${Push:+ push}'
Veuillez le consulter pour le détail des opérations qui n'ont pas pu êtres effectuées"
En cas d'erreur de merge, veuillez corriger les erreurs puis continuer avec
git merge --continue
Sinon, veuillez consulter le script et/ou le relancer
./$script${Delete:+ delete}${Push:+ push}"
die
elif [ -n "$Deleted" -a -n "$Pushed" ]; then
elif [ -n "$Deleted" -a -n "$Push" ]; then
[ -n "$_KeepScript" ] || rm "$script"
[ -n "$AfterMerge" ] && eval "$AfterMerge"
else
local cmd
[ -n "$Deleted" ] || cmd="$cmd
./$script delete"
[ -n "$Pushed" ] || cmd="$cmd
./$script push"
einfo "\
local msg="\
Le script $script a été lancé avec les arguments 'merge${Delete:+ delete}${Push:+ push}'
Veuillez le consulter pour le détail des autres opérations à effectuer$cmd"
Vous pouvez consulter le script et/ou le relancer
./$script${ShouldDelete:+ delete}${ShouldPush:+ push}"
[ -n "$AfterMerge" ] && msg="$msg
Il y a aussi les commandes supplémentaires suivantes:
${AfterMerge//
/
}"
einfo "$msg"
fi
}
@ -125,16 +145,27 @@ chdir=
Origin=
ConfigBranch=
ConfigFile=
_Fake=
_KeepScript=
_NoRunScript=
action=merge
TechMerge=
SquashMsg=
[ -z "$PMAN_NO_PUSH" ] && Push=1 || Push=
[ -z "$PMAN_NO_DELETE" ] && Delete=1 || Delete=
AfterMerge=
args=(
"fusionner la branche source dans la branche destination correspondante"
" [source]"
" [source]
CONFIGURATION
Le fichier .pman.conf contient la configuration des branches. Les variables
supplémentaires suivantes peuvent être définies:
BEFORE_MERGE_<srcType>
AFTER_MERGE_<srcType>
AFTER_DELETE_<srcType>
BEFORE_PUSH_<destType>
AFTER_PUSH_<destType>
srcType et destType pouvant valoir UPSTREAM, DEVELOP, FEATURE, RELEASE, MAIN, HOTFIX, DIST"
-d:,--chdir:BASEDIR chdir= "répertoire dans lequel se placer avant de lancer les opérations"
-O:,--origin Origin= "++\
origine à partir de laquelle les branches distantes sont considérées"
@ -143,8 +174,8 @@ branche à partir de laquelle charger la configuration"
-c:,--config-file:CONFIG ConfigFile= "++\
fichier de configuration des branches. cette option est prioritaire sur --config-branch
par défaut, utiliser le fichier .pman.conf dans le répertoire du dépôt s'il existe"
--fake _Fake=1 "++option non documentée"
--keep-script _KeepScript=1 "++option non documentée"
--no-run-script _NoRunScript=1 "++option non documentée"
-w,--show action=show "\
lister les modifications qui seraient fusionnées dans la branche destination"
-b,--rebase action=rebase "\
@ -167,6 +198,10 @@ ne pas supprimer la branche après la fusion dans la destination"
--delete Delete=1 "++\
supprimer la branche après la fusion dans la destination.
c'est l'option par défaut"
-f,--force-merge ForceMerge=1 "++\
forcer la fusion pour une branche qui devrait être traitée par prel"
-a:,--after-merge AfterMerge= "\
évaluer le script spécifié après une fusion *réussie*"
)
parse_args "$@"; set -- "${args[@]}"
@ -176,13 +211,7 @@ load_branches all
load_config "$MYNAME"
load_branches current "$1"
CantPush=
[ -n "$Origin" ] || Origin=origin
if ! git_have_remote "$Origin" && [ -n "$Push" ]; then
ewarn "L'option --no-push a été forcée puisque ce dépôt n'a pas d'origine"
CantPush=1
fi
[ -n "$CantPush" ] && Push=
resolve_should_push quiet
# puis faire l'action que l'on nous demande
case "$action" in
@ -192,24 +221,26 @@ show)
show_action "$@"
;;
merge)
ForbidDelete=
case "$SrcType" in
develop|release|hotfix)
die "$SrcBranch: cette branche doit être fusionnée dans $DestBranch avec prel"
;;
*)
# n'autoriser la suppression que pour feature
[ "$SrcType" == feature ] || ForbidDelete=1
;;
esac
[ -n "$ForbidDelete" ] && Delete=
git_ensure_cleancheckout
if ! array_contains LocalBranches "$SrcBranch"; then
# si la branche source n'existe pas, la créer
exec "$MYDIR/pman" "$FEATURE${SrcBranch#$FEATURE}"
else
ShouldDelete=1
no_merge_msg="$SrcBranch: cette branche doit être fusionnée dans $DestBranch avec prel"
if [ "$SrcType" == develop ]; then
[ -z "$ForceMerge" ] && die "$no_merge_msg"
[ -n "$AfterMerge" ] || setx AfterMerge=qvals git checkout -q "$SrcBranch"
elif [ "$SrcType" == release -o "$SrcType" == hotfix ]; then
die "$no_merge_msg"
fi
# n'autoriser la suppression que pour feature
[ "$SrcType" == feature ] || ShouldDelete=
[ -z "$ShouldDelete" ] && Delete=
[ -z "$_Fake" ] && git_ensure_cleancheckout
if array_contains LocalBranches "$SrcBranch"; then
ensure_branches
merge_action "$@"
elif array_contains AllBranches "$SrcBranch"; then
enote "$SrcBranch: une branche du même nom existe dans l'origine"
die "$SrcBranch: branche locale introuvable"
else
die "$SrcBranch: branche introuvable"
fi
;;
*)

140
bin/pman
View File

@ -34,16 +34,12 @@ function show_action() {
# Initialisation
################################################################################
function init_repo_action() {
[ ${#LocalBranches[*]} -eq 0 ] || die "Ce dépôt a déjà été initialisé"
local -a push_branches
if [ ! -f .pman.conf ]; then
function _init_config() {
if [ ! -f .pman.conf -o -n "$ForceCreate" ]; then
ac_set_tmpfile config
cp "$ConfigFile" "$config"
"${EDITOR:-nano}" "$config"
[ -s "$config" ] || exit_with ewarn "Initialisation du dépôt annulée"
[ -s "$config" ] || return 1
cp "$config" .pman.conf
if testdiff .pman.conf "$ConfigFile"; then
@ -59,6 +55,15 @@ function init_repo_action() {
.*.swp"
git add .gitignore
fi
return 0
}
function init_repo_action() {
local -a push_branches; local config
[ ${#LocalBranches[*]} -eq 0 ] || die "Ce dépôt a déjà été initialisé"
_init_config || exit_with ewarn "Initialisation du dépôt annulée"
einfo "Création de la branche $MAIN"
git symbolic-ref HEAD "refs/heads/$MAIN"
@ -72,17 +77,55 @@ function init_repo_action() {
_push_branches
}
function init_config_action() {
local -a push_branches; config
[ -f .pman.conf -a -z "$ForceCreate" ] && die "La configuration pman a déjà été initialisée"
resolve_should_push
_init_config || exit_with ewarn "Initialisation de la configuration annulée"
git commit -m "configuration pman"
push_branches+=("$CurrentBranch")
_push_branches
}
function _ensure_main_branch() {
[ -n "$MAIN" ] || die "La branche MAIN n'a pas été définie"
[ -n "$MainBranch" ] || die "$MAIN: cette branche n'existe pas (le dépôt a-t-il été initialisé?)"
}
function checkout_main_action() {
if [ -z "$MainBranch" ]; then
array_contains AllBranches "$MAIN" && exit_with enote "\
$MAIN: une branche du même nom existe dans l'origine
git checkout $MAIN"
_ensure_main_branch
fi
git checkout -q "$MAIN"
}
function _ensure_develop_branch() {
[ -n "$DEVELOP" ] || die "La branche DEVELOP n'a pas été définie"
[ -n "$DevelopBranch" ] || die "$DEVELOP: cette branche n'existe pas (le dépôt a-t-il été initialisé?)"
}
function init_develop_action() {
local -a push_branches
if [ -z "$DevelopBranch" ]; then
[ -n "$DEVELOP" ] || die "La branche DEVELOP n'a pas été définie"
[ -n "$MAIN" ] || die "La branche MAIN n'a pas été définie"
[ -n "$MainBranch" ] || die "$MAIN: cette branche n'existe pas (le dépôt a-t-il été initialisé?)"
array_contains AllBranches "$DEVELOP" && exit_with enote "\
$DEVELOP: une branche du même nom existe dans l'origine
git checkout $DEVELOP"
_ensure_main_branch
_ensure_develop_branch
resolve_should_push
enote "Vous allez créer la branche ${COULEUR_VERTE}$DEVELOP${COULEUR_NORMALE} <-- ${COULEUR_BLEUE}$MAIN${COULEUR_NORMALE}"
ask_yesno "Voulez-vous continuer?" O || die
local -a push_branches
einfo "Création de la branche $DEVELOP"
git checkout -b "$DEVELOP" "$MAIN" || die
push_branches+=("$DEVELOP")
@ -92,17 +135,26 @@ function init_develop_action() {
git checkout -q "$DEVELOP"
}
function _ensure_upstream_branch() {
[ -n "$UPSTREAM" ] || die "La branche UPSTREAM n'a pas été définie"
[ -n "$UpstreamBranch" ] || die "$UPSTREAM: cette branche n'existe pas (le dépôt a-t-il été initialisé?)"
}
function init_upstream_action() {
local -a push_branches; local config
if [ -z "$UpstreamBranch" ]; then
[ -n "$UPSTREAM" ] || die "La branche UPSTREAM n'a pas été définie"
[ -n "$DEVELOP" ] || die "La branche DEVELOP n'a pas été définie"
[ -n "$DevelopBranch" ] || die "$DEVELOP: cette branche n'existe pas (le dépôt a-t-il été initialisé?)"
array_contains AllBranches "$UPSTREAM" && exit_with enote "\
$UPSTREAM: une branche du même nom existe dans l'origine
git checkout $UPSTREAM"
_ensure_develop_branch
_ensure_upstream_branch
resolve_should_push
enote "Vous allez créer la branche ${COULEUR_VERTE}$UPSTREAM${COULEUR_NORMALE}"
ask_yesno "Voulez-vous continuer?" O || die
local -a push_branches; local config
# faire une copie de la configuration actuelle
ac_set_tmpfile config
cp "$ConfigFile" "$config"
@ -128,17 +180,26 @@ function init_upstream_action() {
git checkout -q "$UPSTREAM"
}
function _ensure_dist_branch() {
[ -n "$DIST" ] || die "La branche DIST n'a pas été définie"
[ -n "$DistBranch" ] || die "$DIST: cette branche n'existe pas (le dépôt a-t-il été initialisé?)"
}
function init_dist_action() {
local -a push_branches
if [ -z "$DistBranch" ]; then
[ -n "$DIST" ] || die "La branche DIST n'a pas été définie"
[ -n "$MAIN" ] || die "La branche MAIN n'a pas été définie"
[ -n "$MainBranch" ] || die "$MAIN: cette branche n'existe pas (le dépôt a-t-il été initialisé?)"
array_contains AllBranches "$DIST" && exit_with enote "\
$DIST: une branche du même nom existe dans l'origine
git checkout $DIST"
_ensure_main_branch
_ensure_dist_branch
resolve_should_push
enote "Vous allez créer la branche ${COULEUR_VERTE}$DIST${COULEUR_NORMALE} <-- ${COULEUR_BLEUE}$MAIN${COULEUR_NORMALE}"
ask_yesno "Voulez-vous continuer?" O || die
local -a push_branches
einfo "Création de la branche $DIST"
git checkout -b "$DIST" "$MAIN" || die
push_branches+=("$DIST")
@ -149,18 +210,24 @@ function init_dist_action() {
}
function init_feature_action() {
local branch="${1#$FEATURE}"
[ -n "$branch" ] || die "Vous devez définir la nom de la branche à créer"
local -a push_branches; local branch
[ -n "$FEATURE" ] || die "La branche FEATURE n'a pas été définie"
branch="${1#$FEATURE}"
[ -n "$branch" ] || die "Vous devez spécifier le nom de la branche"
branch="$FEATURE$branch"
if ! array_contains AllBranches "$branch"; then
[ -n "$DEVELOP" ] || die "La branche DEVELOP n'a pas été définie"
[ -n "$DevelopBranch" ] || die "$DEVELOP: cette branche n'existe pas (le dépôt a-t-il été initialisé?)"
if ! array_contains LocalBranches "$branch"; then
array_contains AllBranches "$branch" && exit_with enote "\
$branch: une branche du même nom existe dans l'origine
git checkout $branch"
_ensure_develop_branch
resolve_should_push
enote "Vous allez créer la branche ${COULEUR_VERTE}$branch${COULEUR_NORMALE} <-- ${COULEUR_BLEUE}$DEVELOP${COULEUR_NORMALE}"
ask_yesno "Voulez-vous continuer?" O || die
local -a push_branches
einfo "Création de la branche $branch"
git checkout -b "$branch" "$DEVELOP" || die
push_branches+=("$branch")
@ -174,7 +241,8 @@ function init_action() {
local what="${1:-develop}"; shift
case "$what" in
init|repo|r) init_repo_action "$@";;
main|m) git checkout -q "$MAIN";;
config) init_config_action "$@";;
main|m) checkout_main_action;;
develop|dev|d) init_develop_action "$@";;
upstream|up|u) init_upstream_action "$@";;
dist|x) init_dist_action "$@";;
@ -191,10 +259,11 @@ ConfigBranch=
ConfigFile=
action=init
Origin=
Push=1
[ -z "$PMAN_NO_PUSH" ] && Push=1 || Push=
ForceCreate=
args=(
"gérer un projet git"
"repo|develop|upstream|dist
"repo|config|develop|upstream|dist
INITIALISATION
@ -219,6 +288,8 @@ fichier de configuration des branches. cette option est prioritaire sur --config
par défaut, utiliser le fichier .pman.conf dans le répertoire du dépôt s'il existe"
-w,--show-config action=show "++\
afficher la configuration chargée"
--composer-select-profile action=composer_select_profile "\
sélectionner le profil composer spécifié en argument"
-O:,--origin Origin= "++\
origine vers laquelle pousser les branches"
-n,--no-push Push= "\
@ -226,6 +297,8 @@ ne pas pousser les branches vers leur origine après leur création"
--push Push=1 "++\
pousser les branches vers leur origine après leur création.
c'est l'option par défaut"
-f,--force-create ForceCreate=1 "\
Avec config, forcer la (re)création du fichier .pman.conf"
)
parse_args "$@"; set -- "${args[@]}"
@ -244,6 +317,9 @@ init)
git_ensure_cleancheckout
init_action "$@"
;;
composer_select_profile)
exec "$MYDIR/_pman-$action.php" "$@"
;;
*)
die "$action: action non implémentée"
;;

View File

@ -42,6 +42,11 @@ function create_release_action() {
merge_hotfix_action "$@"; return $?
fi
[ -n "$ManualRelease" ] && ewarn "\
L'option --no-merge a été forcée puisque ce dépôt ne supporte pas les releases automatiques"
[ -z "$ShouldPush" ] && enote "\
L'option --no-push a été forcée puisque ce dépôt n'a pas d'origine"
if [ -z "$Version" -a -n "$CurrentVersion" -a -f VERSION.txt ]; then
Version="$(<VERSION.txt)"
Tag="$TAG_PREFIX$Version$TAG_SUFFIX"
@ -80,6 +85,11 @@ Vous devrez:
# create
if [ -n "\$create" ]; then
esection "Création de la release"
EOF
[ -n "$BEFORE_CREATE_RELEASE" ] && _scripta <<EOF
(
$BEFORE_CREATE_RELEASE
)$or_die
EOF
_rscript_create_release_branch
[ -n "$AFTER_CREATE_RELEASE" ] && _scripta <<EOF
@ -96,6 +106,11 @@ EOF
# merge
if [ -n "\$merge" ]; then
esection "Fusionner la release"
EOF
[ -n "$BEFORE_MERGE_RELEASE" ] && _scripta <<EOF
(
$BEFORE_MERGE_RELEASE
)$or_die
EOF
_rscript_merge_release_branch "$DestBranch" "$Tag"
_rscript_merge_release_branch "$SrcBranch"
@ -114,6 +129,11 @@ EOF
# push
if [ -n "\$push" ]; then
esection "Pousser branches et tags"
EOF
[ -n "$BEFORE_PUSH_RELEASE" ] && _scripta <<EOF
(
$BEFORE_PUSH_RELEASE
)$or_die
EOF
_script_push_branches
_script_push_tags
@ -126,26 +146,25 @@ EOF
fi
EOF
[ -n "$Merge" ] && Merged=1 || Merged=
[ -n "$Push" -o "$CantPush" ] && Pushed=1 || Pushed=
if [ -n "$_NoRunScript" ]; then
einfo "Veuillez consulter le script $script pour le détail des opérations à effectuer"
[ -z "$ManualRelease" -a -n "$Merge" ] && ShouldMerge= || ShouldMerge=1
[ -n "$ShouldPush" -a -n "$Push" ] && ShouldPush=
if [ -n "$_Fake" ]; then
cat "$script"
elif ! "$script" create ${Merge:+merge} ${Push:+push}; then
eimportant "\
Le script $script a été lancé avec les arguments 'create${Merge:+ merge}${Push:+ push}'
Veuillez le consulter pour le détail des opérations qui n'ont pas pu êtres effectuées"
En cas d'erreur de merge, veuillez corriger les erreurs puis continuer avec
git merge --continue
Veuillez aussi consulter le script et/ou le relancer
./$script${Push:+ push}"
die
elif [ -n "$Merged" -a -n "$Pushed" ]; then
elif [ -n "$Merge" -a -n "$Push" ]; then
[ -n "$_KeepScript" ] || rm "$script"
else
local cmd
[ -n "$Merged" ] || cmd="$cmd
./$script merge"
[ -n "$Pushed" ] || cmd="$cmd
./$script push"
einfo "\
Le script $script a été lancé avec les arguments 'create${Merge:+ merge}${Push:+ push}'
Veuillez le consulter pour le détail des autres opérations à effectuer$cmd"
Vous pouvez consulter le script et/ou le relancer
./$script${ShouldMerge:+ merge}${ShouldPush:+ push}"
fi
}
@ -172,8 +191,8 @@ chdir=
Origin=
ConfigBranch=
ConfigFile=
_Fake=
_KeepScript=
_NoRunScript=
action=release
[ -z "$PMAN_NO_MERGE" ] && Merge=1 || Merge=
[ -z "$PMAN_NO_PUSH" ] && Push=1 || Push=
@ -182,7 +201,17 @@ CurrentVersion=
ForceCreate=
args=(
"faire une nouvelle release à partir de la branche source"
" -v VERSION [source]"
" -v VERSION [source]
CONFIGURATION
Le fichier .pman.conf contient la configuration des branches. Les variables
supplémentaires suivantes peuvent être définies:
BEFORE_CREATE_RELEASE
AFTER_CREATE_RELEASE
BEFORE_MERGE_RELEASE
AFTER_MERGE_RELEASE
BEFORE_PUSH_RELEASE
AFTER_PUSH_RELEASE"
-d:,--chdir:BASEDIR chdir= "répertoire dans lequel se placer avant de lancer les opérations"
-O:,--origin Origin= "++\
origine à partir de laquelle les branches distantes sont considérées"
@ -191,8 +220,8 @@ branche à partir de laquelle charger la configuration"
-c:,--config-file:CONFIG ConfigFile= "++\
fichier de configuration des branches. cette option est prioritaire sur --config-branch
par défaut, utiliser le fichier .pman.conf dans le répertoire du dépôt s'il existe"
--fake _Fake=1 "++option non documentée"
--keep-script _KeepScript=1 "++option non documentée"
--no-run-script _NoRunScript=1 "++option non documentée"
-w,--show action=show "\
lister les modifications qui seraient intégrées dans la release"
--release action=release "++\
@ -208,11 +237,11 @@ ne pas pousser les branches vers leur origine après la création de la release"
--push Push=1 "++\
pousser les branches vers leur origine après la création de la release.
c'est l'option par défaut"
-v:,--version Version= "\
-v:,--version:VERSION Version= "\
spécifier la version de la release à créer"
-C,--current-version CurrentVersion=1 "++\
si aucune version n'est spécifiée, prendre la version présente dans le fichier VERSION.txt"
-f:,--force-create ForceCreate= "\
-f,--force-create ForceCreate=1 "\
forcer la création de la release même si le tag correspond à la version existe déjà"
)
parse_args "$@"; set -- "${args[@]}"
@ -223,19 +252,11 @@ load_branches all
load_config "$MYNAME"
load_branches current "$1"; shift
if [ -n "$Merge" -a -n "$NOAUTO" ]; then
ewarn "L'option --no-merge a été forcée puisque ce dépôt ne supporte pas les releases automatiques"
Merge=
fi
[ -n "$Merge" -a -n "$NOAUTO" ] && ManualRelease=1 || ManualRelease=
[ -n "$ManualRelease" ] && Merge=
[ -z "$Merge" ] && Push=
CantPush=
[ -n "$Origin" ] || Origin=origin
if ! git_have_remote "$Origin" && [ -n "$Push" ]; then
ewarn "L'option --no-push a été forcée puisque ce dépôt n'a pas d'origine"
CantPush=1
fi
[ -n "$CantPush" ] && Push=
resolve_should_push quiet
# puis faire l'action que l'on nous demande
case "$action" in
@ -245,7 +266,7 @@ show)
show_action "$@"
;;
release)
git_ensure_cleancheckout
[ -z "$_Fake" ] && git_ensure_cleancheckout
ensure_branches
case "$SrcType" in
release) merge_release_action "$@";;

60
bin/pwip Executable file
View File

@ -0,0 +1,60 @@
#!/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 pman pman.conf
git_cleancheckout_DIRTY="\
Vous avez des modifications locales.
Enregistrez ces modifications avant de créer une nouvelle branche"
chdir=
Origin=
ConfigBranch=
ConfigFile=
[ -z "$PMAN_NO_PUSH" ] && Push=1 || Push=
args=(
"créer une branche de feature"
"<feature>"
-d:,--chdir:BASEDIR chdir= "répertoire dans lequel se placer avant de lancer les opérations"
-O:,--origin Origin= "++\
origine à partir de laquelle les branches distantes sont considérées"
-B:,--config-branch ConfigBranch= "++\
branche à partir de laquelle charger la configuration"
-c:,--config-file:CONFIG ConfigFile= "++\
fichier de configuration des branches. cette option est prioritaire sur --config-branch
par défaut, utiliser le fichier .pman.conf dans le répertoire du dépôt s'il existe"
-n,--no-push Push= "\
ne pas pousser les branches vers leur origine après la fusion"
--push Push=1 "++\
pousser les branches vers leur origine après la fusion.
c'est l'option par défaut"
)
parse_args "$@"; set -- "${args[@]}"
# charger la configuration
ensure_gitdir "$chdir"
load_branches all
load_config "$MYNAME"
load_branches current
branch="$1"
if [ -z "$branch" -a ${#FeatureBranches[*]} -eq 1 ]; then
branch="${FeatureBranches[0]}"
fi
[ -n "$branch" ] || die "Vous devez spécifier la branche à créer"
branch="$FEATURE${branch#$FEATURE}"
resolve_should_push
git_ensure_cleancheckout
if array_contains AllBranches "$branch"; then
git checkout -q "$branch"
else
# si la branche source n'existe pas, la créer
args=(--origin "$Origin")
if [ -n "$ConfigFile" ]; then args+=(--config-file "$ConfigFile")
elif [ -n "$ConfigBranch" ]; then args+=(--config-branch "$ConfigBranch")
fi
[ -z "$Push" ] && args+=(--no-push)
exec "$MYDIR/pman" "${args[@]}" "$branch"
fi

View File

@ -25,7 +25,7 @@ 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
RUN /g/build -a @php-apache-cas php-utils
EXPOSE 80 443
ENTRYPOINT ["/g/entrypoint"]

View File

@ -34,7 +34,7 @@ COPY --from=legacytools /g/ /g/
RUN /g/build nutools
COPY --from=php /g/ /g/
RUN /g/build -a @apache-php-cas php-utils
RUN /g/build -a @php-apache-cas php-utils
COPY --from=instantclient /g/ /g/
COPY --from=builder /opt/oracle/ /opt/oracle/

View File

@ -610,6 +610,42 @@ class cl {
#############################################################################
/**
* tester si $array a en début de tableau les mêmes clés que $ref, et dans le
* même ordre. $array peut avoir d'autres clés, ça n'influe pas sur le résultat
*
* $keys obtient la liste des clés de $ref trouvées, dans l'ordre de $array
* $remainKeys obtient la liste des clés de $array qui ne sont pas dans $ref
* $missingKeys obtient la liste des clés de $ref qui ne sont pas dans $array
*/
static function same_keys(?array $array, ?array $ref, ?array &$keys=null, ?array &$remainKeys=null, ?array &$missingKeys=null): bool {
$keys = [];
$remainKeys = [];
$missingKeys = [];
if ($array === null || $array === []) {
if ($ref === null || $ref === []) return true;
$missingKeys = array_keys($ref);
return false;
} elseif ($ref === null || $ref === []) {
$remainKeys = array_keys($array);
return true;
}
$refKeys = array_keys($ref);
$refCount = count($ref);
$index = 0;
$sameKeys = true;
foreach (array_keys($array) as $key) {
if ($index < $refCount) {
if ($key !== $refKeys[$index]) $sameKeys = false;
$index++;
}
if (array_key_exists($key, $ref)) $keys[] = $key;
else $remainKeys[] = $key;
}
$missingKeys = array_values(array_diff($refKeys, $keys));
return $sameKeys && $index == $refCount;
}
/**
* retourner le tableau $array en "renommant" les clés selon le tableau
* $mappings qui contient des associations de la forme [$from => $to]

View File

@ -2,7 +2,6 @@
namespace nulib\ext;
use Exception;
use nulib\ext\json\JsonException;
use nulib\file;
use nulib\os\IOException;

View File

@ -6,7 +6,7 @@ class ref_schema {
const NATURE_METASCHEMA = [
"nature" => ["string", null, "nature du schéma",
"pkey" => 0,
"allowed_values" => ["assoc", "list", "scalar"],
"allowed_values" => ["scalar", "assoc", "list"],
],
"title" => ["?string", null, "libellé de la valeur"],
"required" => ["bool", false, "la valeur est-elle requise?"],
@ -31,9 +31,10 @@ class ref_schema {
"messages" => ["?array", null, "messages à afficher en cas d'erreur d'analyse"],
"formatter_func" => ["?callable", null, "fonction qui formatte la valeur pour affichage"],
"format" => [null, null, "format à utiliser pour l'affichage"],
"" => ["array", "scalar", "nature du schéma",
"" => ["assoc", "schema" => self::NATURE_METASCHEMA],
"" => ["array", ["scalar"], "nature du schéma",
"schema" => self::NATURE_METASCHEMA,
],
"schema" => ["?array", null, "schéma de la valeur si c'est un array"],
"name" => ["?string", null, "identifiant de la valeur"],
"pkey" => ["?pkey", null, "chemin de clé de la valeur dans un tableau associatif"],
"header" => ["?string", null, "nom de l'en-tête s'il faut présenter cette donnée dans un tableau"],

View File

@ -6,5 +6,6 @@ class ref_types {
"boolean" => "bool",
"integer" => "int",
"flt" => "float", "double" => "float", "dbl" => "float",
"func" => "callable", "function" => "callable",
];
}

View File

@ -0,0 +1,172 @@
<?php
namespace nulib\tools\pman;
use nulib\cl;
use nulib\ext\json;
use nulib\file;
use nulib\os\path;
use nulib\ValueException;
class ComposerFile {
function __construct(string $composerFile=".", bool $ensureExists=true) {
if (is_dir($composerFile)) $composerFile = path::join($composerFile, 'composer.json');
if ($ensureExists && !file_exists($composerFile)) {
$message = path::ppath($composerFile).": fichier introuvable";
throw new ValueException($message);
}
$this->composerFile = $composerFile;
$this->load();
}
protected string $composerFile;
function getComposerFile(): string {
return $this->composerFile;
}
protected ?array $data = null;
protected function load(): array {
if ($this->data === null) {
$this->data = json::load($this->composerFile);
}
return $this->data;
}
function getv(string $pkey="", $default=null) {
return cl::pget($this->data, $pkey, $default);
}
function geta(string $pkey="", ?array $default=[]): ?array {
return cl::withn($this->getv($pkey, $default));
}
function getRequires(): array {
return $this->geta("require");
}
function setRequire(string $dep, string $version): void {
$this->setPkey("require.$dep", $version);
}
function getRequireDevs(): array {
return $this->geta("require-dev");
}
function setRequireDev(string $dep, string $version): void {
$this->setPkey("require-dev.$dep", $version);
}
function getRepositories(): array {
return $this->geta("repositories");
}
function setRepositories(array $repositories): void {
$this->data["repositories"] = $repositories;
}
function setPkey(string $pkey, $value): void {
cl::pset($this->data, $pkey, $value);
}
function delPkey(string $pkey): void {
cl::pdel($this->data, $pkey);
}
const PATHS = [
"nulib/php" => "nulib",
];
function selectProfile(string $profile, PmanYamlConfigFile $config): void {
$config = $config->getProfileConfig($profile);
// corriger les liens
$deps = cl::merge(array_keys($config["require"]), array_keys($config["require-dev"]));
$paths = [];
foreach ($deps as $dep) {
$path = cl::get(self::PATHS, $dep, $dep);
$path = str_replace("/", "-", $path);
$path = "../$path";
$paths[$dep] = $path;
}
if ($config["link"]) {
// Ajouter les liens
$adds = [];
$repositories = $this->getRepositories();
foreach ($deps as $dep) {
$found = false;
foreach ($repositories as $repository) {
if ($repository["type"] === "path" && $repository["url"] === $paths[$dep]) {
$found = true;
break;
}
}
if (!$found) {
$adds[] = [
"type" => "path",
"url" => $paths[$dep],
];
}
}
if ($adds) {
$this->setRepositories(cl::merge($adds, $repositories));
}
} else {
// Supprimer les liens
$dels = [];
$repositories = $this->getRepositories();
foreach ($deps as $dep) {
foreach ($repositories as $key => $repository) {
if ($repository["type"] === "path" && $repository["url"] === $paths[$dep]) {
$dels[] = $key;
break;
}
}
}
if ($dels) {
foreach (array_reverse($dels) as $key) {
unset($repositories[$key]);
}
$this->setRepositories(array_values($repositories));
}
}
// corriger les versions
foreach ($config["require"] as $dep => $version) {
$this->data["require"][$dep] = $version;
}
foreach ($config["require-dev"] as $dep => $version) {
$this->data["require-dev"][$dep] = $version;
}
}
function getLocalDeps(): array {
$deps = cl::merge(array_keys($this->getRequires()), array_keys($this->getRequireDevs()));
$paths = [];
foreach ($deps as $dep) {
$path = cl::get(self::PATHS, $dep, $dep);
$path = str_replace("/", "-", $path);
$path = "../$path";
$paths[$dep] = $path;
}
$repositories = $this->getRepositories();
$localDeps = [];
foreach ($deps as $dep) {
foreach ($repositories as $key => $repository) {
if ($repository["type"] === "path" && $repository["url"] === $paths[$dep]) {
$localDeps[$dep] = $repository["url"];
break;
}
}
}
return $localDeps;
}
function print(): void {
$contents = json::with($this->data, json::INDENT_TABS);
if ($contents) echo "$contents\n";
}
function write(): void {
$contents = json::with($this->data, json::INDENT_TABS);
file::writer($this->composerFile)->putContents("$contents\n");
}
}

View File

@ -0,0 +1,57 @@
<?php
namespace nulib\tools\pman;
use nulib\A;
use nulib\ext\yaml;
use nulib\os\path;
use nulib\ValueException;
class PmanYamlConfigFile {
function __construct(string $configFile=".", bool $ensureExists=true) {
if (is_dir($configFile)) $configFile = path::join($configFile, '.pman.yml');
if ($ensureExists && !file_exists($configFile)) {
$message = path::ppath($configFile).": fichier introuvable";
throw new ValueException($message);
}
$this->configFile = $configFile;
$this->load();
}
protected string $configFile;
function getConfigFile(): string {
return $this->configFile;
}
protected ?array $data = null;
protected function load(): array {
if ($this->data === null) {
$data = yaml::load($this->configFile);
$composer =& $data["composer"];
A::ensure_array($composer);
A::ensure_array($composer["profiles"]);
foreach ($composer["profiles"] as $profileName) {
$profile =& $composer[$profileName];
A::ensure_array($profile);
$profile["link"] = boolval($profile["link"] ?? false);
A::ensure_array($profile["require"]);
A::ensure_array($profile["require-dev"]);
}
$this->data = $data;
}
return $this->data;
}
function getProfileConfig(string $profile): array {
$config = $this->data["composer"][$profile] ?? null;
if ($config === null) {
throw new ValueException("$profile: profil invalide");
}
return $config;
}
function print(): void {
yaml::dump($this->data);
}
}

37
php/tests/clTest.php Normal file
View File

@ -0,0 +1,37 @@
<?php
namespace nulib;
use nulib\tests\TestCase;
class clTest extends TestCase {
function checkKeys(?array $array, ?array $ref, bool $sameKeys, array $expectedKeys, array $expectedRemains, array $expectedMissings): void {
self::assertSame($sameKeys, cl::same_keys($array, $ref, $keys, $remains, $missings), "sameKeys");
self::assertSame($expectedKeys, $keys, "keys");
self::assertSame($expectedRemains, $remains, "remains");
self::assertSame($expectedMissings, $missings, "missings");
}
function test_same_keys() {
$array = ["a" => 42, "b" => "tesxt"]; $arrayKeys = array_keys($array);
$xarray = ["parasite0", "a" => 42, "parasite1", "b" => "tesxt"]; $xarrayKeys = array_keys($array);
$ref = ["a" => "int", "b" => "text"]; $refKeys = array_keys($ref);
$missingArray = ["c" => true]; $missingKeys = array_keys($missingArray);
$missingRef = ["c" => "bool"]; $missingKeys = array_keys($missingRef);
$this->checkKeys(null, null, true, [], [], []);
$this->checkKeys(null, [], true, [], [], []);
$this->checkKeys([], null, true, [], [], []);
$this->checkKeys([], [], true, [], [], []);
$this->checkKeys(null, $ref, false, [], [], $refKeys);
$this->checkKeys([], $ref, false, [], [], $refKeys);
$this->checkKeys($array, null, true, [], $arrayKeys, []);
$this->checkKeys($array, [], true, [], $arrayKeys, []);
$this->checkKeys($array, $ref, true, $arrayKeys, [], []);
$this->checkKeys(cl::merge($array, $missingArray), $ref, true, $arrayKeys, $missingKeys, []);
$this->checkKeys($array, cl::merge($ref, $missingRef), false, $arrayKeys, [], $missingKeys);
$this->checkKeys($xarray, $ref, false, $arrayKeys, [0, 1], []);
}
}

View File

@ -1,67 +0,0 @@
<?php
namespace nulib\php\access;
use nulib\tests\TestCase;
use nulib\wip\php\access\KeyAccess;
use stdClass;
class KeyAccessTest extends TestCase {
function testAccess() {
$default = new stdClass();
$array = ["null" => null, "false" => false, "empty" => ""];
#
$a = new KeyAccess($array, "inexistant");
self::assertFalse($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$a = new KeyAccess($array, "null");
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame(null, $a->get($default));
$a = new KeyAccess($array, "false");
self::assertTrue($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$a = new KeyAccess($array, "empty");
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame("", $a->get($default));
#
$a = new KeyAccess($array, "null", ["allow_null" => false]);
self::assertTrue($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$a = new KeyAccess($array, "null", ["allow_null" => true]);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame(null, $a->get($default));
#
$a = new KeyAccess($array, "false", ["allow_false" => false]);
self::assertTrue($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$a = new KeyAccess($array, "false", ["allow_false" => true]);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame(false, $a->get($default));
#
$a = new KeyAccess($array, "empty", ["allow_empty" => false]);
self::assertTrue($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$a = new KeyAccess($array, "empty", ["allow_empty" => true]);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame("", $a->get($default));
}
}

View File

@ -1,70 +0,0 @@
<?php
namespace nulib\php\access;
use nulib\tests\TestCase;
use nulib\wip\php\access\ValueAccess;
use stdClass;
class ValueAccessTest extends TestCase {
function testAccess() {
$default = new stdClass();
#
$i = null;
$a = new ValueAccess($i);
self::assertFalse($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$i = false;
$a = new ValueAccess($i);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame(false, $a->get($default));
$i = "";
$a = new ValueAccess($i);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame("", $a->get($default));
#
$i = null;
$a = new ValueAccess($i, ["allow_null" => false]);
self::assertFalse($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$i = null;
$a = new ValueAccess($i, ["allow_null" => true]);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame(null, $a->get($default));
#
$i = false;
$a = new ValueAccess($i, ["allow_false" => false]);
self::assertTrue($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$i = false;
$a = new ValueAccess($i, ["allow_false" => true]);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame(false, $a->get($default));
#
$i = "";
$a = new ValueAccess($i, ["allow_empty" => false]);
self::assertTrue($a->exists());
self::assertFalse($a->available());
self::assertSame($default, $a->get($default));
$i = "";
$a = new ValueAccess($i, ["allow_empty" => true]);
self::assertTrue($a->exists());
self::assertTrue($a->available());
self::assertSame("", $a->get($default));
}
}

View File

@ -1,40 +0,0 @@
<?php
namespace nulib\php\content;
use nulib\php\content\impl\html;
use nulib\wip\web\content\v;
use PHPUnit\Framework\TestCase;
class cTest extends TestCase {
function testTo_string() {
self::assertSame("", c::to_string(null));
self::assertSame("", c::to_string(false));
self::assertSame("pouet&lt;q/&gt;", c::to_string("pouet<q/>"));
self::assertSame("pouet<q/>", c::to_string(["pouet<q/>"]));
self::assertSame("hello world", c::to_string(["hello", "world"]));
self::assertSame("hello1 world", c::to_string(["hello1", "world"]));
self::assertSame("hello<world>", c::to_string(["hello", "<world>"]));
self::assertSame("<hello>world", c::to_string(["<hello>", "world"]));
self::assertSame("hello,world", c::to_string(["hello,", "world"]));
self::assertSame("hello&nbsp;world", c::to_string(["hello&nbsp;", "world"]));
self::assertSame("hello. world", c::to_string(["hello.", "world"]));
self::assertSame("hello.<world>", c::to_string(["hello.", "<world>"]));
self::assertSame(
"<h1>title&lt;q/&gt;</h1><p>hello<nq/><span>brave&lt;q/&gt;</span><span>world<nq/></span></p>",
c::to_string([
[html::H1, "title<q/>"],
[html::P, [
"hello<nq/>",
[html::SPAN, "brave<q/>"],
[html::SPAN, ["world<nq/>"]],
]],
]));
}
function testXxx() {
$content = [[v::h1, "hello"]];
self::assertSame("<h1>hello</h1>", c::to_string($content));
}
}

View File

@ -1,10 +0,0 @@
<?php
namespace nulib\php\content\impl;
use nulib\php\content\IContent;
class AContent implements IContent {
function getContent(): iterable {
return ["<span>content</span>"];
}
}

View File

@ -1,10 +0,0 @@
<?php
namespace nulib\php\content\impl;
use nulib\php\content\IPrintable;
class APrintable implements IPrintable {
function print(): void {
echo "<p>printable</p>";
}
}

View File

@ -1,23 +0,0 @@
<?php
namespace nulib\php\content\impl;
use nulib\php\content\c;
use nulib\php\content\IContent;
class ATag implements IContent {
function __construct(string $tag, $content=null) {
$this->tag = $tag;
$this->content = $content;
}
protected $tag;
protected $content;
function getContent(): iterable {
return [
"<$this->tag>",
...c::q($this->content),
"</$this->tag>",
];
}
}

View File

@ -1,14 +0,0 @@
<?php
namespace nulib\php\content\impl;
class html {
const H1 = [self::class, "h1"];
const DIV = [self::class, "div"];
const P = [self::class, "p"];
const SPAN = [self::class, "span"];
static function h1($content) { return new ATag("h1", $content); }
static function div($content) { return new ATag("div", $content); }
static function p($content) { return new ATag("p", $content); }
static function span($content) { return new ATag("span", $content); }
}

View File

@ -1,64 +0,0 @@
<?php
namespace nulib\schema\_scalar;
use nulib\tests\TestCase;
use nulib\wip\schema\_scalar\ScalarSchema;
use nulib\wip\schema\SchemaException;
class ScalarSchemaTest extends TestCase {
const NULL_SCHEMA = [
"type" => [null],
"default" => null,
"title" => null,
"required" => false,
"nullable" => true,
"desc" => null,
"analyzer_func" => null,
"extractor_func" => null,
"parser_func" => null,
"normalizer_func" => null,
"messages" => null,
"formatter_func" => null,
"format" => null,
"" => ["scalar"],
"name" => null,
"pkey" => null,
"header" => null,
"composite" => null,
];
static function schema(array $schema): array {
return array_merge(self::NULL_SCHEMA, $schema);
}
function testNormalize() {
self::assertSame(self::NULL_SCHEMA, ScalarSchema::normalize(null));
self::assertSame(self::NULL_SCHEMA, ScalarSchema::normalize([]));
self::assertSame(self::NULL_SCHEMA, ScalarSchema::normalize([null]));
self::assertException(SchemaException::class, function () {
ScalarSchema::normalize([[]]);
});
self::assertException(SchemaException::class, function () {
ScalarSchema::normalize([[null]]);
});
$string = self::schema(["type" => ["string"], "nullable" => false]);
self::assertSame($string, ScalarSchema::normalize("string"));
self::assertSame($string, ScalarSchema::normalize(["string"]));
$nstring = self::schema(["type" => ["string"]]);
self::assertSame($nstring, ScalarSchema::normalize(["?string"]));
self::assertSame($nstring, ScalarSchema::normalize(["?string|null"]));
self::assertSame($nstring, ScalarSchema::normalize(["string|null"]));
self::assertSame($nstring, ScalarSchema::normalize([["?string", "null"]]));
self::assertSame($nstring, ScalarSchema::normalize([["string", "null"]]));
self::assertSame($nstring, ScalarSchema::normalize([["string", null]]));
$key = self::schema(["type" => ["string", "int"], "nullable" => false]);
self::assertSame($key, ScalarSchema::normalize("string|int"));
$nkey = self::schema(["type" => ["string", "int"], "nullable" => true]);
self::assertSame($nkey, ScalarSchema::normalize("?string|int"));
self::assertSame($nkey, ScalarSchema::normalize("string|?int"));
}
}

View File

@ -1,111 +0,0 @@
<?php
namespace nulib\schema\types;
use Exception;
use nulib\tests\TestCase;
use nulib\schema\_scalar\ScalarValue;
use nulib\schema\Schema;
class boolTest extends TestCase {
function commonTests($destv, &$dest, callable $destvSetter): void {
$destv->set(true);
self::assertSame(true, $destv->get());
self::assertSame(true, $dest);
self::assertSame("Oui", $destv->format());
self::assertSame("Oui", $destv->format("OuiNonNull"));
self::assertSame("O", $destv->format("ON"));
self::assertSame("O", $destv->format("ONN"));
$destv->set(false);
self::assertSame(false, $destv->get());
self::assertSame(false, $dest);
self::assertSame("Non", $destv->format());
self::assertSame("Non", $destv->format("OuiNonNull"));
self::assertSame("N", $destv->format("ON"));
self::assertSame("N", $destv->format("ONN"));
$destv->set("yes");
self::assertSame(true, $destv->get());
$destv->set(" yes ");
self::assertSame(true, $destv->get());
$destv->set("12");
self::assertSame(true, $destv->get());
$destv->set(12);
self::assertSame(true, $destv->get());
$destv->set("no");
self::assertSame(false, $destv->get());
$destv->set(" no ");
self::assertSame(false, $destv->get());
$destv->set("0");
self::assertSame(false, $destv->get());
$destv->set(0);
self::assertSame(false, $destv->get());
$destv->set(12.34);
self::assertSame(true, $destv->get());
self::assertException(Exception::class, $destvSetter("a"));
self::assertException(Exception::class, $destvSetter([]));
self::assertException(Exception::class, $destvSetter(["a"]));
}
function testBool() {
/** @var ScalarValue $destv */
Schema::nv($destv, $dest, null, $schema, "bool");
$destvSetter = function($value) use($destv) {
return function() use($destv, $value) {
$destv->set($value);
};
};
self::assertException(Exception::class, $destvSetter(null));
self::assertException(Exception::class, $destvSetter(""));
self::assertException(Exception::class, $destvSetter(" "));
$this->commonTests($destv, $dest, $destvSetter);
}
function testNbool() {
/** @var ScalarValue $destv */
Schema::nv($destv, $dest, null, $schema, "?bool");
$destvSetter = function($value) use($destv) {
return function() use($destv, $value) {
$destv->set($value);
};
};
$destv->set(null);
self::assertNull($destv->get());
self::assertNull($dest);
self::assertSame("Non", $destv->format());
self::assertSame("", $destv->format("OuiNonNull"));
self::assertSame("N", $destv->format("ON"));
self::assertSame("", $destv->format("ONN"));
$destv->set("");
self::assertNull($destv->get());
self::assertNull($dest);
self::assertSame("Non", $destv->format());
self::assertSame("", $destv->format("OuiNonNull"));
self::assertSame("N", $destv->format("ON"));
self::assertSame("", $destv->format("ONN"));
$destv->set(" ");
self::assertNull($destv->get());
self::assertNull($dest);
self::assertSame("Non", $destv->format());
self::assertSame("", $destv->format("OuiNonNull"));
self::assertSame("N", $destv->format("ON"));
self::assertSame("", $destv->format("ONN"));
$this->commonTests($destv, $dest, $destvSetter);
}
}

View File

@ -1,139 +0,0 @@
<?php
namespace nulib\schema\types;
use Exception;
use nulib\tests\TestCase;
use nulib\schema\_scalar\ScalarValue;
use nulib\schema\Schema;
class floatTest extends TestCase {
function commonTests($destv, &$dest, callable $destvSetter): void {
$destv->set(12);
self::assertSame(12.0, $destv->get());
self::assertSame(12.0, $dest);
self::assertSame("12", $destv->format());
self::assertSame("0012", $destv->format("%04u"));
$destv->set("12");
self::assertSame(12.0, $destv->get());
$destv->set(" 12 ");
self::assertSame(12.0, $destv->get());
$destv->set(12.34);
self::assertSame(12.34, $destv->get());
$destv->set(true);
self::assertSame(1.0, $destv->get());
self::assertException(Exception::class, $destvSetter("a"));
self::assertException(Exception::class, $destvSetter([]));
self::assertException(Exception::class, $destvSetter(["a"]));
}
function testFloat() {
/** @var ScalarValue $destv */
Schema::nv($destv, $dest, null, $schema, "float");
$destvSetter = function($value) use($destv) {
return function() use($destv, $value) {
$destv->set($value);
};
};
self::assertException(Exception::class, $destvSetter(null));
self::assertException(Exception::class, $destvSetter(""));
self::assertException(Exception::class, $destvSetter(" "));
// valeur non requise donc retourne null
$destv->set(false);
self::assertNull($destv->get());
$this->commonTests($destv, $dest, $destvSetter);
}
function testRequiredFloat() {
/** @var ScalarValue $destv */
Schema::nv($destv, $dest, null, $schema, [
"float", null,
"required" => true,
]);
$destvSetter = function($value) use($destv) {
return function() use($destv, $value) {
$destv->set($value);
};
};
self::assertException(Exception::class, $destvSetter(null));
self::assertException(Exception::class, $destvSetter(""));
self::assertException(Exception::class, $destvSetter(" "));
// valeur requise donc lance une exception
self::assertException(Exception::class, $destvSetter(false));
$this->commonTests($destv, $dest, $destvSetter);
}
function testNfloat() {
/** @var ScalarValue $destv */
Schema::nv($destv, $dest, null, $schema, "?float");
$destvSetter = function($value) use($destv) {
return function() use($destv, $value) {
$destv->set($value);
};
};
$destv->set(null);
self::assertNull($destv->get());
self::assertNull($dest);
self::assertSame("", $destv->format());
$destv->set("");
self::assertNull($destv->get());
self::assertNull($dest);
self::assertSame("", $destv->format());
$destv->set(" ");
self::assertNull($destv->get());
self::assertNull($dest);
self::assertSame("", $destv->format());
// valeur non requise donc retourne null
$destv->set(false);
self::assertNull($destv->get());
$this->commonTests($destv, $dest, $destvSetter);
}
function testRequiredNfloat() {
/** @var ScalarValue $destv */
Schema::nv($destv, $dest, null, $schema, [
"?float", null,
"required" => true,
]);
$destvSetter = function($value) use($destv) {
return function() use($destv, $value) {
$destv->set($value);
};
};
$destv->set(null);
self::assertNull($destv->get());
self::assertNull($dest);
self::assertSame("", $destv->format());
$destv->set("");
self::assertNull($destv->get());
self::assertNull($dest);
self::assertSame("", $destv->format());
$destv->set(" ");
self::assertNull($destv->get());
self::assertNull($dest);
self::assertSame("", $destv->format());
// valeur requise donc lance une exception
self::assertException(Exception::class, $destvSetter(false));
$this->commonTests($destv, $dest, $destvSetter);
}
}

View File

@ -1,139 +0,0 @@
<?php
namespace nulib\schema\types;
use Exception;
use nulib\tests\TestCase;
use nulib\schema\_scalar\ScalarValue;
use nulib\schema\Schema;
class intTest extends TestCase {
function commonTests($destv, &$dest, callable $destvSetter): void {
$destv->set(12);
self::assertSame(12, $destv->get());
self::assertSame(12, $dest);
self::assertSame("12", $destv->format());
self::assertSame("0012", $destv->format("%04u"));
$destv->set("12");
self::assertSame(12, $destv->get());
$destv->set(" 12 ");
self::assertSame(12, $destv->get());
$destv->set(12.34);
self::assertSame(12, $destv->get());
$destv->set(true);
self::assertSame(1, $destv->get());
self::assertException(Exception::class, $destvSetter("a"));
self::assertException(Exception::class, $destvSetter([]));
self::assertException(Exception::class, $destvSetter(["a"]));
}
function testInt() {
/** @var ScalarValue $destv */
Schema::nv($destv, $dest, null, $schema, "int");
$destvSetter = function($value) use($destv) {
return function() use($destv, $value) {
$destv->set($value);
};
};
self::assertException(Exception::class, $destvSetter(null));
self::assertException(Exception::class, $destvSetter(""));
self::assertException(Exception::class, $destvSetter(" "));
// valeur non requise donc retourne null
$destv->set(false);
self::assertNull($destv->get());
$this->commonTests($destv, $dest, $destvSetter);
}
function testRequiredInt() {
/** @var ScalarValue $destv */
Schema::nv($destv, $dest, null, $schema, [
"int", null,
"required" => true,
]);
$destvSetter = function($value) use($destv) {
return function() use($destv, $value) {
$destv->set($value);
};
};
self::assertException(Exception::class, $destvSetter(null));
self::assertException(Exception::class, $destvSetter(""));
self::assertException(Exception::class, $destvSetter(" "));
// valeur requise donc lance une exception
self::assertException(Exception::class, $destvSetter(false));
$this->commonTests($destv, $dest, $destvSetter);
}
function testNint() {
/** @var ScalarValue $destv */
Schema::nv($destv, $dest, null, $schema, "?int");
$destvSetter = function($value) use($destv) {
return function() use($destv, $value) {
$destv->set($value);
};
};
$destv->set(null);
self::assertNull($destv->get());
self::assertNull($dest);
self::assertSame("", $destv->format());
$destv->set("");
self::assertNull($destv->get());
self::assertNull($dest);
self::assertSame("", $destv->format());
$destv->set(" ");
self::assertNull($destv->get());
self::assertNull($dest);
self::assertSame("", $destv->format());
// valeur non requise donc retourne null
$destv->set(false);
self::assertNull($destv->get());
$this->commonTests($destv, $dest, $destvSetter);
}
function testRequiredNint() {
/** @var ScalarValue $destv */
Schema::nv($destv, $dest, null, $schema, [
"?int", null,
"required" => true,
]);
$destvSetter = function($value) use($destv) {
return function() use($destv, $value) {
$destv->set($value);
};
};
$destv->set(null);
self::assertNull($destv->get());
self::assertNull($dest);
self::assertSame("", $destv->format());
$destv->set("");
self::assertNull($destv->get());
self::assertNull($dest);
self::assertSame("", $destv->format());
$destv->set(" ");
self::assertNull($destv->get());
self::assertNull($dest);
self::assertSame("", $destv->format());
// valeur requise donc lance une exception
self::assertException(Exception::class, $destvSetter(false));
$this->commonTests($destv, $dest, $destvSetter);
}
}

View File

@ -1,123 +0,0 @@
<?php
namespace nulib\schema\types;
use Exception;
use nulib\tests\TestCase;
use nulib\wip\schema\_scalar\ScalarValue;
use nulib\wip\schema\Schema;
class strTest extends TestCase {
function commonTests($destv, &$dest, callable $destvSetter): void {
$destv->set("");
self::assertSame("", $destv->get());
self::assertSame("", $dest);
$destv->set(" ");
self::assertSame(" ", $destv->get());
self::assertSame(" ", $dest);
$destv->set("a");
self::assertSame("a", $destv->get());
self::assertSame("a", $dest);
$destv->set("12");
self::assertSame("12", $destv->get());
$destv->set(" 12 ");
self::assertSame(" 12 ", $destv->get());
$destv->set(12);
self::assertSame("12", $destv->get());
$destv->set(12.34);
self::assertSame("12.34", $destv->get());
$destv->set(true);
self::assertSame("1", $destv->get());
self::assertException(Exception::class, $destvSetter([]));
self::assertException(Exception::class, $destvSetter(["a"]));
}
function testStr() {
/** @var ScalarValue $destv */
Schema::nv($destv, $dest, null, $schema, "string");
$destvSetter = function($value) use($destv) {
return function() use($destv, $value) {
$destv->set($value);
};
};
self::assertException(Exception::class, $destvSetter(null));
// valeur non requise donc retourne null
$destv->set(false);
self::assertNull($destv->get());
$this->commonTests($destv, $dest, $destvSetter);
}
function testRequiredStr() {
/** @var ScalarValue $destv */
Schema::nv($destv, $dest, null, $schema, [
"string", null,
"required" => true,
]);
$destvSetter = function($value) use($destv) {
return function() use($destv, $value) {
$destv->set($value);
};
};
self::assertException(Exception::class, $destvSetter(null));
// valeur requise donc lance une exception
self::assertException(Exception::class, $destvSetter(false));
$this->commonTests($destv, $dest, $destvSetter);
}
function testNstr() {
/** @var ScalarValue $destv */
Schema::nv($destv, $dest, null, $schema, "?string");
$destvSetter = function($value) use($destv) {
return function() use($destv, $value) {
$destv->set($value);
};
};
$destv->set(null);
self::assertNull($destv->get());
self::assertNull($dest);
self::assertSame("", $destv->format());
// valeur non requise donc retourne null
$destv->set(false);
self::assertNull($destv->get());
$this->commonTests($destv, $dest, $destvSetter);
}
function testRequiredNstr() {
/** @var ScalarValue $destv */
Schema::nv($destv, $dest, null, $schema, [
"?string", null,
"required" => true,
]);
$destvSetter = function($value) use($destv) {
return function() use($destv, $value) {
$destv->set($value);
};
};
$destv->set(null);
self::assertNull($destv->get());
self::assertNull($dest);
self::assertSame("", $destv->format());
// valeur requise donc lance une exception
self::assertException(Exception::class, $destvSetter(false));
$this->commonTests($destv, $dest, $destvSetter);
}
}

View File

@ -1,29 +0,0 @@
<?php
namespace nulib\schema\types;
use nulib\tests\TestCase;
use nulib\schema\_scalar\ScalarValue;
use nulib\schema\Schema;
class unionTest extends TestCase {
function testUnionTypes() {
## l'ordre des types doit être respecté
# string puis int
/** @var ScalarValue $siv */
Schema::nv($siv, $si, null, $sis, "string|int");
$siv->set("12");
self::assertSame("12", $si);
$siv->set(12);
self::assertSame(12, $si);
# int puis string
Schema::nv($isv, $is, null, $iss, "int|string");
$isv->set("12");
self::assertSame("12", $is);
$isv->set(12);
self::assertSame(12, $is);
}
}

View File

@ -455,15 +455,18 @@ OPTIONS
function host_docker_run() {
# lancer une commande avec docker
SOPTS=+w:
LOPTS=help,chdir:,no-use-rslave
args="$(getopt -n "$MYNAME" -o "$SOPTS" -l "$LOPTS" -- "$@")" || exit 1; eval "set -- $args"
if [ "$1" == composer ]; then
: # pas d'analyse d'argument pour composer
else
SOPTS=+w:
LOPTS=help,chdir:,no-use-rslave
args="$(getopt -n "$MYNAME" -o "$SOPTS" -l "$LOPTS" -- "$@")" || exit 1; eval "set -- $args"
while [ $# -gt 0 ]; do
case "$1" in
--) shift; break;;
--help)
eecho "\
while [ $# -gt 0 ]; do
case "$1" in
--) shift; break;;
--help)
eecho "\
runphp: lancer une commande dans un environnement PHP déterminé
USAGE
@ -490,14 +493,15 @@ OPTIONS
aller dans le répertoire spécifié avant de lancer la commande
--no-use-rslave
paramètre montage des volumes"
exit 0
;;
-w|--chdir) shift; Chdir="$1";;
--no-use-rslave) UseRslave=;;
*) die "$1: option non configurée";;
esac
shift
done
exit 0
;;
-w|--chdir) shift; Chdir="$1";;
--no-use-rslave) UseRslave=;;
*) die "$1: option non configurée";;
esac
shift
done
fi
args=(
run -it --rm
@ -573,20 +577,24 @@ function container_exec() {
fi
fi
SOPTS=+w:
LOPTS=chdir:
args="$(getopt -n "$MYNAME" -o "$SOPTS" -l "$LOPTS" -- "$@")" || exit 1; eval "set -- $args"
if [ "$1" == composer ]; then
: # pas d'analyse d'argument pour composer
else
SOPTS=+w:
LOPTS=chdir:
args="$(getopt -n "$MYNAME" -o "$SOPTS" -l "$LOPTS" -- "$@")" || exit 1; eval "set -- $args"
chdir=
action=
while [ $# -gt 0 ]; do
case "$1" in
--) shift; break;;
-w|--chdir) shift; chdir="$1";;
*) die "$1: option non configurée";;
esac
shift
done
chdir=
action=
while [ $# -gt 0 ]; do
case "$1" in
--) shift; break;;
-w|--chdir) shift; chdir="$1";;
*) die "$1: option non configurée";;
esac
shift
done
fi
if [ $# -eq 0 ]; then
die "no command specified"

Binary file not shown.