diff --git a/.pman.yml b/.pman.yml new file mode 100644 index 0000000..12513d0 --- /dev/null +++ b/.pman.yml @@ -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 diff --git a/CHANGES.md b/CHANGES.md index e65c7a6..51102c4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,33 @@ +## Release 0.4.0p82 du 14/03/2025-15:24 + +## 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 diff --git a/VERSION.txt b/VERSION.txt index 42045ac..1d0ba9e 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.3.4 +0.4.0 diff --git a/bash/src/_output_color.sh b/bash/src/_output_color.sh index ce0dd77..afe6428 100644 --- a/bash/src/_output_color.sh +++ b/bash/src/_output_color.sh @@ -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")"; } diff --git a/bash/src/_output_vanilla.sh b/bash/src/_output_vanilla.sh index c37509d..cbd466f 100644 --- a/bash/src/_output_vanilla.sh +++ b/bash/src/_output_vanilla.sh @@ -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")"; } diff --git a/bash/src/base.args.sh b/bash/src/base.args.sh index 393a7c5..43e63ae 100644 --- a/bash/src/base.args.sh +++ b/bash/src/base.args.sh @@ -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 } diff --git a/bash/src/base.input.sh b/bash/src/base.input.sh index 9e9acf0..c81fbc8 100644 --- a/bash/src/base.input.sh +++ b/bash/src/base.input.sh @@ -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 diff --git a/bash/src/base.output.sh b/bash/src/base.output.sh index ae51afd..15f2040 100644 --- a/bash/src/base.output.sh +++ b/bash/src/base.output.sh @@ -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() { :;} diff --git a/bash/src/pman.conf.sh b/bash/src/pman.conf.sh index b1aec42..c33874c 100644 --- a/bash/src/pman.conf.sh +++ b/bash/src/pman.conf.sh @@ -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= diff --git a/bash/src/pman.sh b/bash/src/pman.sh index 8c12d1c..f2f5d3d 100644 --- a/bash/src/pman.sh +++ b/bash/src/pman.sh @@ -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 diff --git a/bash/src/pretty.sh b/bash/src/pretty.sh index 2d4f32c..de252fc 100644 --- a/bash/src/pretty.sh +++ b/bash/src/pretty.sh @@ -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 ]; } diff --git a/bash/tests/test-interaction.sh b/bash/tests/test-interaction.sh new file mode 100755 index 0000000..db35861 --- /dev/null +++ b/bash/tests/test-interaction.sh @@ -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" diff --git a/bash/tests/test-output.sh b/bash/tests/test-output.sh index 56a5812..3b369d7 100755 --- a/bash/tests/test-output.sh +++ b/bash/tests/test-output.sh @@ -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' diff --git a/bash/tests/test-verbosity.sh b/bash/tests/test-verbosity.sh new file mode 100755 index 0000000..4b53d8f --- /dev/null +++ b/bash/tests/test-verbosity.sh @@ -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)" diff --git a/bin/_merge82 b/bin/_merge82 index 3c89e35..8a4c2bc 100755 --- a/bin/_merge82 +++ b/bin/_merge82 @@ -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" "$@" diff --git a/bin/_pman-composer_local_deps.php b/bin/_pman-composer_local_deps.php new file mode 100755 index 0000000..badae7b --- /dev/null +++ b/bin/_pman-composer_local_deps.php @@ -0,0 +1,14 @@ +#!/usr/bin/php +getLocalDeps(); +foreach ($deps as $dep => $path) { + echo "$path\n"; +} \ No newline at end of file diff --git a/bin/_pman-composer_select_profile.php b/bin/_pman-composer_select_profile.php new file mode 100755 index 0000000..431259b --- /dev/null +++ b/bin/_pman-composer_select_profile.php @@ -0,0 +1,22 @@ +#!/usr/bin/php +selectProfile($profile, $config); +if (getenv("PMAN_COMPOSER_DEBUG")) { + $composer->print(); +} else { + $composer->write(); +} diff --git a/bin/p b/bin/p index 561d88a..aedfdfc 100755 --- a/bin/p +++ b/bin/p @@ -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) diff --git a/bin/pdev b/bin/pdev index 85106f0..03e827c 100755 --- a/bin/pdev +++ b/bin/pdev @@ -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 < + AFTER_MERGE_ + AFTER_DELETE_ + BEFORE_PUSH_ + AFTER_PUSH_ +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 ;; *) diff --git a/bin/pman b/bin/pman index e97aae6..d4b91a9 100755 --- a/bin/pman +++ b/bin/pman @@ -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" ;; diff --git a/bin/prel b/bin/prel index 28bc0f0..e1af6eb 100755 --- a/bin/prel +++ b/bin/prel @@ -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="$(" + -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 diff --git a/dockerfiles/Dockerfile.php-apache b/dockerfiles/Dockerfile.php-apache index 2a9e467..641de40 100644 --- a/dockerfiles/Dockerfile.php-apache +++ b/dockerfiles/Dockerfile.php-apache @@ -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"] diff --git a/dockerfiles/Dockerfile.php-apache+ic b/dockerfiles/Dockerfile.php-apache+ic index cfbbd61..8907e78 100644 --- a/dockerfiles/Dockerfile.php-apache+ic +++ b/dockerfiles/Dockerfile.php-apache+ic @@ -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/ diff --git a/php/src/cl.php b/php/src/cl.php index 8bb3b37..2397fe9 100644 --- a/php/src/cl.php +++ b/php/src/cl.php @@ -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] diff --git a/php/src/ext/json.php b/php/src/ext/json.php index 68316f8..287a574 100644 --- a/php/src/ext/json.php +++ b/php/src/ext/json.php @@ -2,7 +2,6 @@ namespace nulib\ext; use Exception; -use nulib\ext\json\JsonException; use nulib\file; use nulib\os\IOException; diff --git a/php/src/ref/schema/ref_schema.php b/php/src/ref/schema/ref_schema.php index 9cfa10b..cee4786 100644 --- a/php/src/ref/schema/ref_schema.php +++ b/php/src/ref/schema/ref_schema.php @@ -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"], diff --git a/php/src/ref/schema/ref_types.php b/php/src/ref/schema/ref_types.php index 24973d5..d7ce1d4 100644 --- a/php/src/ref/schema/ref_types.php +++ b/php/src/ref/schema/ref_types.php @@ -6,5 +6,6 @@ class ref_types { "boolean" => "bool", "integer" => "int", "flt" => "float", "double" => "float", "dbl" => "float", + "func" => "callable", "function" => "callable", ]; } diff --git a/php/src/tools/pman/ComposerFile.php b/php/src/tools/pman/ComposerFile.php new file mode 100644 index 0000000..d85a957 --- /dev/null +++ b/php/src/tools/pman/ComposerFile.php @@ -0,0 +1,172 @@ +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"); + } +} diff --git a/php/src/tools/pman/PmanYamlConfigFile.php b/php/src/tools/pman/PmanYamlConfigFile.php new file mode 100644 index 0000000..c0998dd --- /dev/null +++ b/php/src/tools/pman/PmanYamlConfigFile.php @@ -0,0 +1,57 @@ +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); + } +} diff --git a/php/tests/clTest.php b/php/tests/clTest.php new file mode 100644 index 0000000..d2b834f --- /dev/null +++ b/php/tests/clTest.php @@ -0,0 +1,37 @@ + 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], []); + } +} diff --git a/php/tests/php/access/KeyAccessTest.php b/php/tests/php/access/KeyAccessTest.php deleted file mode 100644 index dc5bd4c..0000000 --- a/php/tests/php/access/KeyAccessTest.php +++ /dev/null @@ -1,67 +0,0 @@ - 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)); - } -} diff --git a/php/tests/php/access/ValueAccessTest.php b/php/tests/php/access/ValueAccessTest.php deleted file mode 100644 index a7d08c9..0000000 --- a/php/tests/php/access/ValueAccessTest.php +++ /dev/null @@ -1,70 +0,0 @@ -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)); - } -} diff --git a/php/tests/php/content/cTest.php b/php/tests/php/content/cTest.php deleted file mode 100644 index 2f31b4a..0000000 --- a/php/tests/php/content/cTest.php +++ /dev/null @@ -1,40 +0,0 @@ -")); - self::assertSame("pouet", c::to_string(["pouet"])); - self::assertSame("hello world", c::to_string(["hello", "world"])); - self::assertSame("hello1 world", c::to_string(["hello1", "world"])); - self::assertSame("hello", c::to_string(["hello", ""])); - self::assertSame("world", c::to_string(["", "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.", c::to_string(["hello.", ""])); - - self::assertSame( - "

title<q/>

hellobrave<q/>world

", - c::to_string([ - [html::H1, "title"], - [html::P, [ - "hello", - [html::SPAN, "brave"], - [html::SPAN, ["world"]], - ]], - ])); - } - - function testXxx() { - $content = [[v::h1, "hello"]]; - self::assertSame("

hello

", c::to_string($content)); - } -} - diff --git a/php/tests/php/content/impl/AContent.php b/php/tests/php/content/impl/AContent.php deleted file mode 100644 index c53c376..0000000 --- a/php/tests/php/content/impl/AContent.php +++ /dev/null @@ -1,10 +0,0 @@ -content"]; - } -} diff --git a/php/tests/php/content/impl/APrintable.php b/php/tests/php/content/impl/APrintable.php deleted file mode 100644 index 7a75c2f..0000000 --- a/php/tests/php/content/impl/APrintable.php +++ /dev/null @@ -1,10 +0,0 @@ -printable

"; - } -} diff --git a/php/tests/php/content/impl/ATag.php b/php/tests/php/content/impl/ATag.php deleted file mode 100644 index b4cc2ed..0000000 --- a/php/tests/php/content/impl/ATag.php +++ /dev/null @@ -1,23 +0,0 @@ -tag = $tag; - $this->content = $content; - } - - protected $tag; - protected $content; - - function getContent(): iterable { - return [ - "<$this->tag>", - ...c::q($this->content), - "tag>", - ]; - } -} diff --git a/php/tests/php/content/impl/html.php b/php/tests/php/content/impl/html.php deleted file mode 100644 index 3567b2e..0000000 --- a/php/tests/php/content/impl/html.php +++ /dev/null @@ -1,14 +0,0 @@ - [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")); - } -} diff --git a/php/tests/schema/types/boolTest.php b/php/tests/schema/types/boolTest.php deleted file mode 100644 index 8f990e3..0000000 --- a/php/tests/schema/types/boolTest.php +++ /dev/null @@ -1,111 +0,0 @@ -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); - } -} diff --git a/php/tests/schema/types/floatTest.php b/php/tests/schema/types/floatTest.php deleted file mode 100644 index 193d407..0000000 --- a/php/tests/schema/types/floatTest.php +++ /dev/null @@ -1,139 +0,0 @@ -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); - } -} diff --git a/php/tests/schema/types/intTest.php b/php/tests/schema/types/intTest.php deleted file mode 100644 index 29de7ce..0000000 --- a/php/tests/schema/types/intTest.php +++ /dev/null @@ -1,139 +0,0 @@ -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); - } -} diff --git a/php/tests/schema/types/strTest.php b/php/tests/schema/types/strTest.php deleted file mode 100644 index 45eda17..0000000 --- a/php/tests/schema/types/strTest.php +++ /dev/null @@ -1,123 +0,0 @@ -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); - } -} diff --git a/php/tests/schema/types/unionTest.php b/php/tests/schema/types/unionTest.php deleted file mode 100644 index c208087..0000000 --- a/php/tests/schema/types/unionTest.php +++ /dev/null @@ -1,29 +0,0 @@ -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); - } -} diff --git a/runphp/runphp b/runphp/runphp index 1a03b5f..4bfe2ed 100755 --- a/runphp/runphp +++ b/runphp/runphp @@ -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" diff --git a/sbin/composer.phar b/sbin/composer.phar deleted file mode 100755 index 7a44c36..0000000 Binary files a/sbin/composer.phar and /dev/null differ