Checkout SVN con dialog e Bash

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
Condividi:
Subscribe
Notificami
1 Comment
Newest
Oldest Most Voted
Inline Feedbacks
View all comments