Ho rivisto un mio vecchio script Bash in modo da usare dialog testuali per guidare e semplificare le operazioni di checkout/switch/delete con un server Subversion (SVN).
Ho colto l’occasione per migliorare le mie conoscenze di scripting Bash (in particolare la sostituzione dei parametri e la redirezione con i file descriptor).
Il comando dialog, mette a disposizione vari tipi di dialog boxes testuali (menubox, messagebox, inputbox etc..) per il nostro terminale. Per interagire con un server SVN useremo il relativo client da riga di comando.
Nel caso non siano già installati nella vostra distribuzione, è sufficiente lanciare il seguente comando: sudo apt install subversion dialog
(per i sistemi Debian-based).
Altro requisito fondamentale è l’uso delle chiavi SSH per l’autenticazione con il vostro server SVN.
E’ il metodo più sicuro e più semplice, ammesso che l’amministratore del vostro server non abbia imposto delle restrizioni all’uso di tale sistema.
Nel caso non aveste generato ancora una coppia chiave pubblica/privata bastano i seguenti comandi per crearla per il proprio utente e per autorizzare il login sicuro sul server SVN remoto:
francesco@miopc:~$ ssh-keygen francesco@miopc:~$ ssh-copy-id francesco@svnserver
Di seguito alcuni screenshot dello script al lavoro:
#! /usr/bin/env bash # Interactive SubVersion Checkout/Switch with Bash dialogs # # Copyright (C) 2020 Francesco Guarnieri # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # Config file (same script's pathname, but with .conf extension) CONF_FILE="${0%.*}.conf" # Consts DLG_OK=0 DLG_CANCEL=1 DLG_DEL=2 DLG_CKT=3 DLG_NEW=4 DLG_ESC=255 BACKTITLE_PREFIX="\Zb\Z3[ESC Exit]\Zn" BACK="../" NEW="NEW" DELETE="Delete" SELECT="Checkout" WARNING=" Warning " REL_URL_PREFIX="Relative URL: ^/" REL_URL_POSTFIX="Repository Root:" REPO_URL="" svn_error=' ' svn_list () { svn_error="" if ! tags="$(svn ls $1 2>&1)" ; then # If there is an error the message is captured in svn_error svn_error=$tags tags="" dialog --colors --backtitle "" --title "$WARNING" --msgbox "$svn_error" 12 70 fi } dialog_items () { svn_list $1 # Redefine tags string as string array tags=($tags) items=($2) local tag='' # Generate array for dialog and strip the / from tags for tag in "${tags[@]}"; do if [[ ${tag: -1} == '/' ]]; then items+=("$tag" "/${tag%/}") else items+=("$tag" " ${tag%/}") fi done } get_retval () { retval=$? if [[ $retval -eq $DLG_ESC ]]; then clear exit 1 fi } # Try to read config file [[ -f $CONF_FILE ]] && source $CONF_FILE # Get Repository url while [[ -n "$svn_error" ]]; do # Inputbox dialog for SVN Repository URL REPO_URL=$(dialog --colors --backtitle "$BACKTITLE_PREFIX" --inputbox "SVN Repository URL:" 0 70 \ $REPO_URL 3>&1 1>&2 2>&3 3>&-) case $? in $DLG_CANCEL|$DLG_ESC) clear exit 1 ;; esac # Remove the last / REPO_URL=${REPO_URL%/} # Try to connect to repository svn_list $REPO_URL done # Write repository url to config file printf "REPO_URL=%s" "$REPO_URL" > "$CONF_FILE" svn_url=$REPO_URL retval=$DLG_NEW while [[ true ]]; do BACKTITLE="${BACKTITLE_PREFIX} $svn_url" # Check if we are at root of repository (empty string is true) [[ $svn_url == $REPO_URL ]] && root='false' || root='' if [[ $root ]]; then command=(dialog --colors --cancel-label "$NEW" --help-button --help-label "$DELETE" --extra-button \ --extra-label "$SELECT" --no-tags --backtitle "$BACKTITLE" --menu "Checkout from:" 0 50 0) dialog_items "$svn_url" else command=(dialog --colors --help-button --help-label "$DELETE" --extra-button --extra-label "$SELECT" \ --notags --backtitle "$BACKTITLE" --menu "Checkout from:" 0 50 0) dialog_items "$svn_url" "${BACK} /${BACK%/}" fi # Show menu dialog if [[ ${#items[@]} -gt 0 ]]; then choice=$("${command[@]}" "${items[@]}" 3>&1 1>&2 2>&3 3>&-) get_retval if [[ $root && $retval -eq $DLG_CANCEL ]]; then retval=$DLG_NEW; fi fi # If it's a file do nothing if [[ -n $choice && $choice == ${choice%/} ]]; then continue; fi case $retval in $DLG_DEL) choice=${choice#*HELP } msg=$(printf "\ZbFrom:\ZB\n%s\Zb\nDelete:\ZB\n%s\n\n\ZbDo you want to continue?\ZB" $svn_url $choice) dialog --colors --no-label "Cancel" --backtitle "$BACKTITLE" --title " DELETE " --yesno "$msg" 10 75 get_retval # Checkout new project if [[ $retval -eq $DLG_OK ]]; then { svn del -m "" $svn_url/$choice } 2>&1 | dialog --colors --backtitle "$BACKTITLE" --title " Output " --programbox 20 75 clear exit 0 fi ;; $DLG_CANCEL) clear exit 1 ;; $DLG_OK) # if special item "BACK", go back if [[ $choice == $BACK ]]; then svn_url=${svn_url%/*}; continue; fi choice=${choice%/} svn_url=$svn_url/$choice # Save current checkout dir if [[ $root ]]; then ckt_dir=$PWD/$choice; fi ;; $DLG_CKT) switch=1 # if special item "BACK", do nothing if [[ $choice == $BACK ]]; then continue; fi choice=${choice%/} if [[ $root ]]; then ckt_dir=$PWD/$choice; fi # Local dir exists and is not empty, maybe we can switch if [[ -d $ckt_dir && $(ls -A $ckt_dir) ]]; then # if svn info exit code is 0, get the output and extract "Relative URL" if rel_url=$(svn info $ckt_dir 2>&1); then rel_url=${rel_url#*$REL_URL_PREFIX} rel_url=${rel_url%$REL_URL_POSTFIX*} my_url=${svn_url#$REPO_URL/} # We can use svn switch, if urls heads match if [[ ${rel_url%%/*} == ${my_url%%/*} ]]; then switch=0 else msg=$(printf "\ZbCannot switch in:\ZB\n%s\n\ZbIs a working copy for:\ZB\n%s" $ckt_dir $rel_url) fi else msg=$(printf "\ZbIs not a working copy. Cannot switch in:\ZB\n%s" $ckt_dir) fi if [[ $switch -eq 1 ]]; then dialog --colors --backtitle "$BACKTITLE" --title "$WARNING" --msgbox "$msg" 8 70 continue fi fi svn_url=$svn_url/$choice if [[ $switch -eq 0 ]]; then msg=$(printf "\ZbFrom:\ZB%s\Zb\nSwitch to url:\ZB\n%s\n\ZbLocal dir:\ZB\n%s\n\n\ZbDo you want to continue?\ZB" $rel_url $svn_url $ckt_dir) dialog --colors --backtitle "$BACKTITLE" --title " Switch project " --yesno "$msg" 11 75 else msg=$(printf "\ZbUrl:\ZB\n%s\n\ZbLocal dir:\ZB\n%s\n\n\ZbDo you want to continue?\ZB" $svn_url $ckt_dir) dialog --colors --backtitle "$BACKTITLE" --title " Checkout project " --yesno "$msg" 10 75 fi get_retval if [[ $retval -eq $DLG_CANCEL ]]; then svn_url=${svn_url%/*} continue fi # Create local checkout dir if not exists [[ ! -d $ckt_dir ]] && mkdir $ckt_dir cd $ckt_dir # Redirect commands output to programbox dialog { if [[ $switch -eq 0 ]]; then svn switch $svn_url else svn co $svn_url $ckt_dir fi } 2>&1 | dialog --colors --backtitle "$BACKTITLE" --title " Output " --programbox 20 75 clear exit 0 ;; $DLG_NEW) choice=$(dialog --colors --backtitle "$BACKTITLE" --inputbox "New project name:" 0 0 3>&1 1>&2 2>&3 3>&-) get_retval if [[ $retval -eq $DLG_CANCEL ]]; then continue; fi choice=${choice%/} # Check if the project already exists in SVN repo if [[ " ${items[@]} " =~ " ${choice}/ " ]]; then msg=$(printf "\n\Zb%s\ZB already exists in repository" $choice) dialog --colors --backtitle "$BACKTITLE" --title "$WARNING" --msgbox "$msg" 7 70 continue fi ckt_dir=$PWD/$choice # Local checkout dir exists and is not empty if [[ -d $ckt_dir && $(ls -A $ckt_dir) ]]; then msg=$(printf "\ZbCheckout directory is not empty:\ZB\n%s" $ckt_dir) dialog --colors --backtitle "$BACKTITLE" --title "$WARNING" --msgbox "$msg" 7 70 continue fi svn_url=$svn_url/$choice msg=$(printf "\ZbUrl:\ZB\n%s\n\ZbLocal dir:\ZB\n%s\n\n\ZbDo you want to continue?\ZB" $svn_url $ckt_dir) dialog --colors --backtitle "$BACKTITLE" --title " Checkout project " --yesno "$msg" 10 75 get_retval if [[ $retval -eq $DLG_CANCEL ]]; then svn_url=${svn_url%/*} continue fi # Create local checkout dir if not exists [[ ! -d $ckt_dir ]] && mkdir $ckt_dir cd $ckt_dir # Redirect commands output to programbox dialog { svn mkdir -m "New remote project: ${name}" $svn_url svn mkdir -m "" $svn_url/branches svn mkdir -m "" $svn_url/tags svn mkdir -m "" $svn_url/trunk svn co $svn_url/trunk $ckt_dir } 2>&1 | dialog --colors --backtitle "$BACKTITLE" --title " Output " --programbox 20 75 clear exit 0 ;; esac done
Ho aggiunto la possibilità di cancellare le directory e corretto un problema con i repository vuoti.