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.