2010-08-05 4 views
48

Quiero advertir al usuario si su mensaje de confirmación no sigue un cierto conjunto de pautas, y luego le doy la opción de editar su mensaje de confirmación, ignorar la advertencia o cancelar la confirmación. El problema es que no parece tener acceso a stdin.¿Cómo solicito al usuario desde dentro de un enlace commit-msg?

A continuación es mi archivo de cometer-msg:

function verify_info { 
    if [ -z "$(grep '$2:.*[a-zA-Z]' $1)" ] 
    then 
     echo >&2 $2 information should not be omitted 
     local_editor=`git config --get core.editor` 
     if [ -z "${local_editor}" ] 
     then 
      local_editor=${EDITOR} 
     fi 
     echo "Do you want to" 
     select CHOICE in "edit the commit message" "ignore this warning" "cancel the commit"; do 
      case ${CHOICE} in 
       i*) echo "Warning ignored" 
        ;; 
       e*) ${local_editor} $1 
        verify_info "$1" $2 
        ;; 
       *) echo "CHOICE = ${CHOICE}" 
        exit 1 
        ;; 
      esac 
     done 
    fi 
} 

verify_info "$1" "Scope" 
if [ $# -ne 0 ]; 
then 
    exit $# 
fi 
verify_info "$1" "Affects" 
if [ $# -ne 0 ]; 
then 
    exit $# 
fi 

exit 0 

Aquí está la salida cuando deje la información Ámbito blanco:

Scope information should not be omitted 
Do you want to: 
1) edit the commit message 3) cancel the commit 
2) ignore this warning 
#? 

El mensaje es correcto, pero en realidad no se detiene para la entrada. También intenté usar el comando "leer" más simple, y tiene el mismo problema. Parece que el problema es que en este punto, git tiene el control de stdin y está proporcionando su propia entrada. ¿Cómo puedo solucionar esto?

Actualización: Parece que esto podría ser un duplicado de this question que desafortunadamente parece sugerir que estoy de suerte.

+0

Cuando tiene acceso a un servidor X, puede escaparse a una herramienta gráfica de diálogo. Ugly-but-works – Rudi

+0

En lugar del mensaje de error, simplemente podría proporcionar un mensaje de error informativo, que incluye repetir el comando necesario para ignorar la advertencia. – bstpierre

+0

@btspierre, ese es el enfoque que terminé tomando. Siguiendo el consejo de John Feminella, permití el uso de una variable de entorno para anular la advertencia, y solo hago eco de la advertencia cada vez que se encuentra una mala situación. –

Respuesta

108

Llamar a exec < /dev/tty asigna entrada estándar al teclado. Funciona para mí en un gancho post-commit git:

#!/bin/sh 

echo "[post-commit hook] Commit done!" 

# Allows us to read user input below, assigns stdin to keyboard 
exec < /dev/tty 

while true; do 
    read -p "[post-commit hook] Check for outdated gems? (Y/n) " yn 
    if [ "$yn" = "" ]; then 
    yn='Y' 
    fi 
    case $yn in 
     [Yy]) bundle outdated --pre; break;; 
     [Nn]) exit;; 
     *) echo "Please answer y or n for yes or no.";; 
    esac 
done 
+13

STDIN puede cerrarse nuevamente con 'exec <& -' – Andy

+10

Si está usando Ruby, eso se traduciría a 'STDIN.reopen ('/ dev/tty')'. Cosas increíbles, esta es la verdadera respuesta. –

+2

Esto es increíble, pero puede romperse al comprometerse desde otra herramienta, como un editor. No estoy seguro de cómo evitarlo, pero si alguien tiene una idea, me gustaría escucharla. – Peeja

4

El enganche commit-msg no se ejecuta en un entorno interactivo (como habrá notado).

La única forma de notificar al usuario confiablemente sería escribir un error en stdout, colocar una copia del mensaje de confirmación en un archivo 'BAD_MSG' e indicar al usuario que edite el archivo y 'git commit --file = BAD_MSG'


Si tiene algún control sobre el medio ambiente que podría tener un editor alternativo que es un guión envoltorio que comprueba el mensaje propuesto, y puede reiniciar el editor con un mensaje comentado adicional.

Básicamente, usted ejecuta el editor, verifica el archivo guardado contra sus reglas. y si falla, anteponga su mensaje de advertencia (con # principal) al archivo y reinicie el editor.

Incluso podría permitirles poner una línea '# FORCE = true' en el mensaje que suprimiría la verificación y continuaría.

+3

Intenta llamar a 'exec

+0

Aunque esta es una respuesta bien pensada, se debe aceptar a Eliot ya que él lo demuestra * ¡es * realmente posible! –

+0

El usuario puede omitir los ganchos con '--no-verify', no necesita recurrir a hackers' # FORCE = true'. – fsaintjacques

1

Para hacer select parada para la entrada, también puede tratar de redirigir la stdin de select de /dev/fd/3 (Ver: Read input in bash inside a while loop).

# sample code using a while loop to simulate git consuming stdin 
{ 
echo 'fd 0' | while read -r stdin; do 
    echo "stdin: $stdin" 
    echo "Do you want to" 
    select CHOICE in "edit the commit message" "ignore this warning" "cancel the commit"; do 
     case ${CHOICE} in 
     i*) echo "Warning ignored" 
      ;; 
     e*) echo ${local_editor} $1 
      echo verify_info "$1" $2 
      ;; 
     *) echo "CHOICE = ${CHOICE}" 
      exit 1 
      ;; 
     esac 
    done 0<&3 3<&- 
done 
} 3<&- 3<&0 
0

esto funciona bien cuando se ejecuta git commit desde la línea de comandos. En Windows (no lo he probado en Linux) si usa gitk o git-gui, no podrá solicitarlo porque aparece un error en la línea "exec </dev/tty".

El sollution es llamar git-bash.exe en su gancho:

.git/ganchos/post-commit contiene:

#!/bin/sh 
exec /c/Program\ Files/Git/git-bash.exe /path/to/my_repo/.git/hooks/post-checkout.sh 

la .git/ganchos/post-commit.El archivo sh contiene:

# -------------------------------------------------------- 
# usage: f_askContinue "my question ?" 
function f_askContinue { 
    local myQuestion=$1 

    while true; do 
    read -p "${myQuestion} " -n 1 -r answer 
    case $answer in 
     [Yy]*) printf "\nOK\n"; break;; 
     [Nn]*) printf "\nAbandon\n"; 
        exit;; 
     *) printf "\nAnswer with Yes or No.\n";; 
    esac 
    done 
} 

f_askContinue "Do you want to continue ?" 
echo "This command is executed after the prompt !" 
Cuestiones relacionadas