Created
March 16, 2020 14:31
-
-
Save AlexRNL/8c8d6e012cd677cea8a9af4b153b06e2 to your computer and use it in GitHub Desktop.
Useful shell scripts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Script backup-duplicity.sh | |
| # -------------------------- | |
| # Perform a backup of the current machine using duplicity and synchronize it to a remote machine | |
| # Abort on unset variables | |
| set -o nounset | |
| ## Global variables | |
| # The date & time format for the logs | |
| readonly LOG_DATETIME_FORMAT="%(%FT%T)T" | |
| # Backup root folder | |
| readonly BACKUP_FOLDER="/backups/duplicity" | |
| # The compression format, used in gpg-options | |
| readonly COMPRESSION_FORMAT="bzip2" | |
| # The file to load SSH agent environment | |
| readonly SSH_AGENT_ENV_FILE="${HOME}/.ssh/agent-env.sh" | |
| # rsync command line options | |
| readonly RSYNC_OPT="${RSYNC_OPT:-""} --archive --compress --human-readable --update --info=NAME --ignore-missing-args --delete" | |
| # Script usage | |
| usage () { | |
| printf "Usage: %s [-h] [-v] [-n] -p <PASSPHRASE_FILE> [-s <SECONDARY_COMPUTER>] [-l <FILE>] [-f <FREQ>] [-d <AGE>]\n" "${0##*/}" | |
| printf "\t-h display this message\n" | |
| printf "\t-v dislay more logs (also add more logs to duplicity)\n" | |
| printf "\t-n enable dry-run mode for duplicity and rsync\n" | |
| printf "\t-p <PASSPHRASE_FILE> the file with the passphrase to use to encrypt the backups\n" | |
| printf "\t-s <SECONDARY_COMPUTER> name of the secondary computer (sync backups between them if set)\n" | |
| printf "\t-l <FILE> the file list to backup (see duplicity man for format)\n" | |
| printf "\t-f <FREQ> frequency between full backups, default is '2W' (see duplicity man for format)\n" | |
| printf "\t-d <AGE> age limit for keeping full backups, default is '1M' (see duplicity man for format)\n" | |
| exit 2 | |
| } | |
| # Log only if verbose mode is enabled | |
| verbose () { | |
| if [[ ${VERBOSE:-false} == "true" ]] ; then | |
| log "${*}" | |
| fi | |
| } | |
| # Print dated message | |
| log () { | |
| printf "${LOG_DATETIME_FORMAT} %s\\n" -1 "${*}" 1>&2 | |
| } | |
| # Parse command line arguments | |
| parse_arguments () { | |
| VERBOSE="false" | |
| DRY_RUN="" | |
| SECONDARY_COMPUTER="" | |
| FILE_LIST="" | |
| FULL_BACKUP_FREQ="2W" | |
| DELETE_OLDER_THAN="2M" | |
| while getopts ':hvnp:s:l:f:d:' arg | |
| do | |
| case ${arg} in | |
| v) VERBOSE="true" | |
| ;; | |
| n) DRY_RUN="--dry-run" | |
| ;; | |
| p) PASSPHRASE_FILE="${OPTARG}" | |
| ;; | |
| s) SECONDARY_COMPUTER="${OPTARG}" | |
| ;; | |
| l) FILE_LIST="${OPTARG}" | |
| ;; | |
| f) FULL_BACKUP_FREQ="${OPTARG}" | |
| ;; | |
| d) DELETE_OLDER_THAN="${OPTARG}" | |
| ;; | |
| h) usage | |
| ;; | |
| \?) error "Unknown option-${OPTARG}" | |
| usage | |
| ;; | |
| -) error "Missing argument for option -${OPTARG}" | |
| usage | |
| ;; | |
| *) error "Option -${arg} not implemented" | |
| usage | |
| ;; | |
| esac | |
| done | |
| shift $((OPTIND - 1)) | |
| if [[ ! -r ${PASSPHRASE_FILE:-""} ]] ; then | |
| log "Passphrase file is mandatory" | |
| usage | |
| fi | |
| readonly VERBOSE DRY_RUN FILE_LIST SECONDARY_COMPUTER FULL_BACKUP_FREQ DELETE_OLDER_THAN | |
| } | |
| # Get the log file to use | |
| get_log_file () { | |
| printf "%s/duplicity.log" "${BACKUP_FOLDER}" | |
| } | |
| # Make a new backup with the first argument as the folder to backup, and the second one as the name for the backup subfolder | |
| make_new_backup () { | |
| local verbose_level="notice" | |
| if [[ ${VERBOSE} == "true" ]] ; then | |
| verbose_level="info" | |
| fi | |
| duplicity --full-if-older-than "${FULL_BACKUP_FREQ}" \ | |
| --gpg-options "--compress-algo=${COMPRESSION_FORMAT}" \ | |
| --log-file "$(get_log_file)" \ | |
| --verbosity "${verbose_level}" ${DRY_RUN} \ | |
| ${FILE_LIST:+--include-filelist ${FILE_LIST}} \ | |
| "${1}" "file://${BACKUP_FOLDER}/${2}" | |
| } | |
| # Clean old backups with the first argument as the backup subfolder | |
| clean_old_backup () { | |
| duplicity remove-older-than "${DELETE_OLDER_THAN}" \ | |
| --log-file "$(get_log_file)" \ | |
| --force ${DRY_RUN} \ | |
| "file://${BACKUP_FOLDER}/${1}" | |
| } | |
| # Synchronize backups between computers with the first argument as the current hostname | |
| sync_backups () { | |
| if [[ -z ${SECONDARY_COMPUTER} ]] ; then | |
| log "Skipping synchronization no secondary computer is set" | |
| return | |
| fi | |
| if [[ ${1} == "${SECONDARY_COMPUTER}" ]] ; then | |
| log "Skipping synchronization on secondary computer" | |
| return | |
| fi | |
| # Load SSH agent environment | |
| if [[ -r ${SSH_AGENT_ENV_FILE} ]] ; then | |
| # shellcheck source=/home/alex/.ssh/agent-env.sh | |
| source "${SSH_AGENT_ENV_FILE}" > /dev/null | |
| verbose "successfully loaded ${SSH_AGENT_ENV_FILE}: pid=${SSH_AGENT_PID} sock=${SSH_AUTH_SOCK}" | |
| else | |
| log "rsync may not work as file ${SSH_AGENT_ENV_FILE} could not be found" | |
| fi | |
| log "Synchronize backup of this machine to ${SECONDARY_COMPUTER}" | |
| # shellcheck disable=SC2086 | |
| rsync ${RSYNC_OPT} ${DRY_RUN} "${BACKUP_FOLDER}"/"${1}" "${SECONDARY_COMPUTER}":"${BACKUP_FOLDER}" | |
| log "Synchronize backup of ${SECONDARY_COMPUTER} to this machine" | |
| # shellcheck disable=SC2086 | |
| rsync ${RSYNC_OPT} ${DRY_RUN} "${SECONDARY_COMPUTER}":"${BACKUP_FOLDER}"/"${SECONDARY_COMPUTER}" "${BACKUP_FOLDER}" | |
| } | |
| # Script entry point | |
| main () { | |
| parse_arguments "${@}" | |
| mkdir --parents "${BACKUP_FOLDER}" | |
| log "Starting backups using passphrase from ${PASSPHRASE_FILE}" | |
| PASSPHRASE="$(cat "${PASSPHRASE_FILE}")" | |
| export PASSPHRASE | |
| local hostname | |
| hostname="$(hostname)" | |
| make_new_backup "${HOME}" "${hostname}" | |
| log "${hostname}/${HOME} successfully backed-up!" | |
| log "Rotating backups..." | |
| clean_old_backup "${hostname}" | |
| sync_backups "${hostname}" | |
| } | |
| # Call main function | |
| main "${@}" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Script bash-colors.sh | |
| # ---------------------- | |
| # Display all possible colors (bg, fg, format) with their code | |
| # Script usage | |
| usage () { | |
| printf "Usage: %b%s%b [-h] [-a]\n" "${Color_BBlue}" "${0##*/}" "${Color_Reset}" | |
| printf "\t-h display this message\n" | |
| printf "\t-a display colors on all possible backgrounds\n" | |
| exit 2 | |
| } | |
| # Parse command line arguments | |
| parse_arguments () { | |
| NOT_ALL_BACKGROUND="true" | |
| while getopts ':ha' arg | |
| do | |
| case ${arg} in | |
| a) NOT_ALL_BACKGROUND="false" | |
| ;; | |
| h) usage | |
| ;; | |
| \?) error "Unknown option -${OPTARG}" | |
| usage | |
| ;; | |
| :) error "Missing argument for option -${OPTARG}" | |
| usage | |
| ;; | |
| *) error "Option -${arg} not implemented" | |
| usage | |
| ;; | |
| esac | |
| done | |
| shift $((OPTIND - 1)) | |
| readonly NOT_ALL_BACKGROUND | |
| } | |
| # Triple loop function that print each color combination | |
| print_colors () { | |
| # Background | |
| for clbg in {40..47} {100..107} 49 ; do | |
| # Foreground | |
| for clfg in {30..37} {90..97} 39 ; do | |
| # Formatting | |
| for attr in 0 1 2 4 5 7 ; do | |
| # Print the result | |
| printf "\e[${attr};${clbg};${clfg}m ^[%s;%s;%sm \e[0m" "${attr}" "${clbg}" "${clfg}" | |
| done | |
| printf '\n' | |
| done | |
| if [[ ${NOT_ALL_BACKGROUND} == "true" ]] ; then | |
| break | |
| fi | |
| done | |
| } | |
| # Entry point of the script | |
| main () { | |
| # shellcheck source=/home/alex/Documents/scripts/common.sh | |
| source common.sh | |
| parse_arguments "${@}" | |
| print_colors | |
| return 0 | |
| } | |
| # Calling main function | |
| main "${@}" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # shellcheck disable=SC2148 | |
| # common.sh | |
| # --------- | |
| # Common functions and constants definitions used by several scripts | |
| if [[ -n ${_COMMON_SH_:-""} ]] ; then | |
| return | |
| fi | |
| _COMMON_SH_="common.sh loaded" | |
| # Import colors constants | |
| # shellcheck source=/home/alex/Documents/etc/bash_colors | |
| source "${HOME}/Documents/etc/bash_colors" | |
| ## Set useful script options unless we are in 'no-script' mode | |
| if [[ ${1:-""} != "--no-script" ]] ; then | |
| # Abort if a command exits with nonzero status | |
| set -o errexit | |
| # Abort on unset variables | |
| set -o nounset | |
| # Pipe command fail if one fails | |
| set -o pipefail | |
| fi | |
| ## Logging functions | |
| # The date & time format for the logs | |
| readonly LOG_DATETIME_FORMAT="%(%FT%T)T" | |
| # Lowest log level: only prints if VERBOSE flag is enabled | |
| fine () { | |
| if [[ ${VERBOSE:-false} == "true" ]] ; then | |
| log White "${*}" | |
| fi | |
| } | |
| # Intermediate log level: prints by default (unless SILENT is enabled) | |
| info () { | |
| if [[ ${SILENT:-false} != "true" ]] ; then | |
| log Cyan "${*}" | |
| fi | |
| } | |
| # Higher log level: always prints a colored output | |
| warn () { | |
| log Yellow "${*}" | |
| } | |
| # Highest log level: always prints a colored output | |
| error () { | |
| log Red "${*}" | |
| } | |
| # Generic log function, uses the first argument as the color (name of variable only!), print the remaining argument | |
| # example: `log Red "the ultimate answer is 42"` | |
| log () { | |
| if [[ ${COLORED_LOGS:-false} != "false" ]] ; then | |
| local color="Color_${1}" | |
| local high_color="Color_I${1}" | |
| local time_color=${!color} | |
| local text_color=${!high_color} | |
| local reset_color=${Color_Reset} | |
| fi | |
| shift | |
| printf "${time_color:-}${LOG_DATETIME_FORMAT} ${text_color:-}%s${reset_color:-}\\n" -1 "${*}" 1>&2 | |
| } | |
| ## Git functions | |
| readonly WORKSPACE_DIR="${HOME}/workspace" | |
| # Check if the current folder is a Git repo (print an error and returns 1 if it isn't) | |
| is_git_repo () { | |
| if [[ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" != "true" ]] ; then | |
| error "Directory ${PWD##*/} is not a Git repository" | |
| return 1 | |
| else | |
| fine "Directory ${PWD##*/} is a Git repository" | |
| return 0 | |
| fi | |
| } | |
| # List the repositories (sorted) in the workspace and remove build dirs of QtCreator | |
| list_repo () { | |
| find "${WORKSPACE_DIR}" -mindepth 1 -maxdepth 1 ! -type l | | |
| sort | | |
| grep --invert-match --extended-regexp "^${WORKSPACE_DIR}/build-" | |
| } | |
| # Return the name of the current Git branch | |
| get_git_branch () { | |
| printf "%s" "$(git symbolic-ref --short HEAD)" | |
| } | |
| ## Function for handling the servers accounts configuration file | |
| # Server to account configuration file | |
| readonly SERVER_ACCOUNT_FILE="${HOME}/Documents/etc/servers-accounts" | |
| # Load server to account configuration | |
| # TODO several accounts per servers? | |
| load_server_account_file () { | |
| # Character indicating a comment line in the configuration file | |
| local comment_prefix='#' | |
| # Separator between server & accounts in the configuration file | |
| local config_file_separator='=' | |
| # Declare associative array for the server configuration | |
| declare -gA REMOTE_SERVERS_ACCOUNTS | |
| fine "Load server account file ${SERVER_ACCOUNT_FILE}" | |
| local current_server | |
| local current_account | |
| while IFS=${config_file_separator} read -r current_server current_account; do | |
| # Unless it's a comment, add the line | |
| if [[ -n ${current_server} && | |
| ${current_server:0:${#comment_prefix}} != "${comment_prefix}" ]] ; then | |
| fine "Add account '${current_account}' for server '${current_server}'" | |
| REMOTE_SERVERS_ACCOUNTS[${current_server}]="${current_account}" | |
| fi | |
| done < "${SERVER_ACCOUNT_FILE}" | |
| info "Successfully loaded ${#REMOTE_SERVERS_ACCOUNTS[*]} servers" | |
| export REMOTE_SERVERS_ACCOUNTS | |
| } | |
| # Loads the server account file if needed, check the modification date of the file | |
| load_server_account_file_if_needed () { | |
| local server_conf_modification_date | |
| server_conf_modification_date=$(date -r "${SERVER_ACCOUNT_FILE}" +%s) | |
| if [[ ${server_conf_modification_date} -gt ${SERVER_ACCOUNT_FILE_LAST_RELOAD:-0} || | |
| -z ${REMOTE_SERVERS_ACCOUNTS+} ]] ; then | |
| load_server_account_file | |
| SERVER_ACCOUNT_FILE_LAST_RELOAD=$(date +%s) | |
| export SERVER_ACCOUNT_FILE_LAST_RELOAD | |
| fi | |
| } | |
| ## Miscellaneous functions | |
| # Email recipient | |
| readonly MAIL_RECIPIENT="[email protected]" | |
| # Send summary of operation performed by the script by mail, subject is the first argument | |
| send_mail () { | |
| if [[ ${#} == 0 ]] ; then | |
| error "Need argument to send mail" | |
| return 1 | |
| fi | |
| # Extract subject | |
| local subject=${1} | |
| shift | |
| printf "%s" "${*}" | | |
| mail -s "${subject}" \ | |
| "${MAIL_RECIPIENT}" | |
| return 0 | |
| } | |
| ## For testing purposes | |
| # Function that test various functions provided by this file | |
| test_common () { | |
| local mistake="warning" | |
| error "This is an error" | |
| warn "This is a ${mistake}" | |
| info "Public announcement" | |
| fine "This is fine" | |
| log Black "This is not ok" "1 12 123" | |
| log Red "This is not ok" "1 12 123" | |
| log Green "This is not ok" "1 12 123" | |
| log Yellow "This is not ok" "1 12 123" | |
| log Blue "This is not ok" "1 12 123" | |
| log Purple "This is not ok" "1 12 123" | |
| log Cyan "This is not ok" "1 12 123" | |
| log White "This is not ok" "1 12 123" | |
| info "$(list_repo)" | |
| ( | |
| cd "${HOME}/workspace/trunk" | |
| if is_git_repo ; then | |
| info "Trunk is a Git repo" | |
| else | |
| error "Trunk SHOULD be a Git repo" | |
| fi | |
| ) | |
| ( | |
| cd "${HOME}" | |
| if ! is_git_repo 2>/dev/null ; then | |
| info "${HOME} is not a Git repo" | |
| else | |
| error "${HOME} SHOULD NOT be a Git repo" | |
| fi | |
| ) | |
| info "Except mail not to be sent, as there is not argument provided" | |
| send_mail || true | |
| local content="Hello, World! | |
| This is a test :-)" | |
| send_mail "this is my subject" "${content}" | |
| } | |
| # If script is called with "TEST_COMMON_SCRIPT" call the test method | |
| if [[ ${1:-} == "TEST_COMMON_SCRIPT" ]] ; then | |
| test_common | |
| fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # git-check-all.sh | |
| # ---------------- | |
| # For all Git repositories in ~/workspace, print a summary of what is NOT pushed remotely | |
| # This script counts locally modified files, stashes and un-pushed commits | |
| # Script usage | |
| usage () { | |
| printf "Usage: %b%s%b [-h] [-v]\n" "${Color_BBlue}" "${0##*/}" "${Color_Reset}" | |
| printf "\t-h display this message\n" | |
| printf "\t-v display more logs\n" | |
| printf "\t-f fetch new refs (branches, tags, etc.) from remotes\n" | |
| exit 2 | |
| } | |
| # Parse command line arguments | |
| parse_arguments () { | |
| VERBOSE="false" | |
| FETCH="false" | |
| while getopts ':hvf' arg ; do | |
| case ${arg} in | |
| v) VERBOSE="true" | |
| ;; | |
| f) FETCH="true" | |
| ;; | |
| h) usage | |
| ;; | |
| \?) error "Unknown option -${OPTARG}" | |
| usage | |
| ;; | |
| :) error "Missing argument for option -${OPTARG}" | |
| usage | |
| ;; | |
| *) error "Option -${arg} not implemented" | |
| usage | |
| ;; | |
| esac | |
| done | |
| shift $((OPTIND - 1)) | |
| readonly VERBOSE FETCH | |
| } | |
| # Get the number of stash in the repo | |
| get_nb_stash () { | |
| printf "%d" "$(git stash list | | |
| wc --lines)" | |
| } | |
| # Get the number of dirty files in the repo | |
| get_nb_files () { | |
| printf "%d" "$(git status --porcelain | | |
| wc --lines)" | |
| } | |
| # Get the branch difference with the remote, use the branch specified in the 1st argument, or the current branch if not specified | |
| get_diff_branch () { | |
| # Get diff from a different branch if specified | |
| if [[ -n ${1:-""} ]] ; then | |
| if [[ ${1} == "$(get_git_branch)" ]] ; then | |
| return | |
| fi | |
| git checkout --quiet "${1}" | |
| fi | |
| local git_status_branch | |
| git_status_branch=$(git status --porcelain --branch | | |
| grep --extended-regexp "^##") | |
| local regex="^## .+ \[(.+)\]$" | |
| [[ ${git_status_branch} =~ ${regex} ]] | |
| printf "%s" "${BASH_REMATCH[1]:-""}" | |
| # Back to the original branch | |
| if [[ -n ${1:-""} ]] ; then | |
| git checkout --quiet - | |
| fi | |
| } | |
| # Print the summary of the repo, first argument is branch diff, second is nb of modified files and third the number of stash | |
| print_repo_summary () { | |
| local OLD_IFS=${IFS} | |
| IFS="|" | |
| local summary | |
| local idx=0 | |
| local log_color=${Color_ICyan} | |
| # Write repo name | |
| printf -v summary[$((idx++))] "For repo %b%s%b[%b%s%b]%b:" "${Color_BBlue}" "${PWD##*/}" "${Color_White}" "${Color_Cyan}" "$(get_git_branch)" "${Color_White}" "${log_color}" | |
| # Write branch diff | |
| if [[ -n ${1} ]] ; then | |
| printf -v summary[$((idx++))] "\t%bcommits%b diff with origin: %b%s%b" "${Color_IGreen}" "${log_color}" "${Color_IYellow}" "${1}" "${log_color}" | |
| fi | |
| # Write master branch diff | |
| if [[ -n ${2} ]] ; then | |
| printf -v summary[$((idx++))] "\t%bcommits%b[%bmaster%b] diff with origin: %b%s%b" "${Color_IGreen}" "${log_color}" "${Color_IRed}" "${log_color}" "${Color_IYellow}" "${2}" "${log_color}" | |
| fi | |
| # Write file diff | |
| if [[ ${3} != 0 ]] ; then | |
| printf -v summary[$((idx++))] "\tmodified %bfiles%b in workspace: %b%d%b" "${Color_IGreen}" "${log_color}" "${Color_IYellow}" "${3}" "${log_color}" | |
| fi | |
| # Write stash number | |
| if [[ ${4} != 0 ]] ; then | |
| printf -v summary[$((idx++))] "\tnumber of %bstash%b: %b%s%b" "${Color_IGreen}" "${log_color}" "${Color_IYellow}" "${4}" "${log_color}" | |
| fi | |
| # Print all lines of summary | |
| for line in ${summary[*]} ; do | |
| info "${line}" | |
| done | |
| IFS=${OLD_IFS} | |
| } | |
| # Print a full status for the current Git repository | |
| check_repo () { | |
| if ! is_git_repo >/dev/null 2>&1 ; then | |
| return 0 | |
| fi | |
| if [[ ${FETCH} == "true" ]] ; then | |
| git fetch --quiet 2>/dev/null | |
| if [[ ${?} != 0 ]] ; then | |
| error "Could not fetch refs from remote of repository ${PWD##*/}" | |
| return 1 | |
| fi | |
| fi | |
| fine "Processing repository ${PWD##*/}, on branch $(get_git_branch)" | |
| local nb_stash nb_file diff_branch diff_master_branch | |
| nb_stash=$(get_nb_stash) | |
| nb_file=$(get_nb_files) | |
| diff_branch=$(get_diff_branch) | |
| diff_master_branch=$(get_diff_branch "master") | |
| if [[ -z ${diff_branch} | |
| && -z ${diff_master_branch} | |
| && ${nb_file} == 0 | |
| && ${nb_stash} == 0 ]] ; then | |
| return 0 | |
| fi | |
| print_repo_summary "${diff_branch}" "${diff_master_branch}" "${nb_file}" "${nb_stash}" | |
| return 1 | |
| } | |
| # Script entry point | |
| main () { | |
| # shellcheck source=/home/alex/Documents/scripts/common.sh | |
| source common.sh | |
| parse_arguments "${@}" | |
| for dir in $(list_repo) ; do | |
| if ! cd "${dir}" ; then | |
| error "Could not go into '${dir}'" | |
| continue | |
| fi | |
| if ! check_repo ; then | |
| printf "\n" | |
| fi | |
| done | |
| return 0 | |
| } | |
| # Call main function | |
| main "${@}" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Script git-rename.sh | |
| # -------------------- | |
| # Script that rename a Git branch, locally and remotely | |
| # Script usage | |
| usage () { | |
| printf "Usage: %b%s%b [-h] [-v] [-n] new-branch-name\n" "${Color_BBlue}" "${0##*/}" "${Color_Reset}" | |
| printf "\t-h display this message\n" | |
| printf "\t-v display more logs\n" | |
| printf "\t-n dry-run, do not rename the branch\n" | |
| exit 2 | |
| } | |
| # Parse command line argumments | |
| parse_arguments () { | |
| VERBOSE="false" | |
| DRY_RUN="false" | |
| while getopts ':hvn' arg ; do | |
| case ${arg} in | |
| v) VERBOSE="true" | |
| ;; | |
| n) DRY_RUN="true" | |
| ;; | |
| h) usage | |
| ;; | |
| \?) error "Unknown option -${OPTARG}" | |
| usage | |
| ;; | |
| :) error "Missing argument for option -${OPTARG}" | |
| usage | |
| ;; | |
| *) error "Option -${arg} not implemented" | |
| usage | |
| ;; | |
| esac | |
| done | |
| shift $((OPTIND - 1)) | |
| if [[ -z ${1:-""} ]] ; then | |
| error "Please provide a name for the new branch" | |
| usage | |
| fi | |
| NEW_NAME=${1} | |
| readonly VERBOSE DRY_RUN NEW_NAME | |
| } | |
| # Check if the provided argument is a valid Git branch name | |
| is_valid_name () { | |
| if ! git check-ref-format --branch "${1}" >/dev/null 2>&1 ; then | |
| error "${1} is not a valid name for a Git branch" | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| # Rename current branch to the first argument | |
| git_rename () { | |
| local old_branch | |
| old_branch=$(git rev-parse --abbrev-ref HEAD) | |
| fine "Renaming branch ${old_branch} to ${1}..." | |
| if [[ ${DRY_RUN} == "false" ]] ; then | |
| if ! (git branch -m "${1}" && \ | |
| git push origin :"${old_branch}" "${1}" && \ | |
| git push origin --set-upstream "${1}") ; then | |
| warn "Failed to rename branch ${old_branch} to ${1}" | |
| return 1 | |
| else | |
| info "Successfully rename branch ${old_branch} to ${1}" | |
| return 0 | |
| fi | |
| else | |
| warn "... DRY RUN ... would have renamed ${old_branch} to ${1}" | |
| return 0 | |
| fi | |
| } | |
| # Script entry point | |
| main () { | |
| # shellcheck source=/home/alex/Documents/scripts/common.sh | |
| source common.sh | |
| parse_arguments "${@}" | |
| if ! is_git_repo ; then | |
| return 1 | |
| fi | |
| if ! is_valid_name "${NEW_NAME}" ; then | |
| return 1 | |
| fi | |
| git_rename "${NEW_NAME}" | |
| } | |
| # Call main function | |
| main "${@}" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # git-stl.sh | |
| # ---------- | |
| # For current Git repository, list the current modified files by last modification date | |
| # Global variables | |
| # Date display format | |
| readonly DATE_DISPLAY_FORMAT="%Ta %Td %Tb %TY %TH:%TM:%.2TS" | |
| # Script usage | |
| usage () { | |
| printf "Usage: %b%s%b [-h] [-v]\n" "${Color_BBlue}" "${0##*/}" "${Color_Reset}" | |
| printf "\t-h display this message\n" | |
| printf "\t-v display more logs\n" | |
| exit 2 | |
| } | |
| # Parse command line arguments | |
| parse_arguments () { | |
| VERBOSE="false" | |
| while getopts ':hv' arg | |
| do | |
| case "${arg}" in | |
| v) VERBOSE="true" | |
| ;; | |
| h) usage | |
| ;; | |
| \?) error "Unknown option -${OPTARG}" | |
| usage | |
| ;; | |
| :) error "Missing argument for option -${OPTARG}" | |
| usage | |
| ;; | |
| *) error "Option -${arg} not implemented" | |
| usage | |
| ;; | |
| esac | |
| done | |
| shift $((OPTIND - 1)) | |
| readonly VERBOSE | |
| } | |
| # Get the list of modified files in the repository | |
| get_modified_files () { | |
| git status --porcelain --untracked-files=all | | |
| grep '^.[?M]' | | |
| sed 's/^.. //' | |
| } | |
| # Get the modified files relative to the current directory | |
| get_modified_files_relative () { | |
| local git_root | |
| git_root=$(git rev-parse --show-toplevel) | |
| for file in $(get_modified_files) | |
| do | |
| realpath --relative-to . "${git_root}/${file}" | |
| done | |
| } | |
| # Print the modified files in the repository sorted by last modified date | |
| print_modified_files () { | |
| local files | |
| files=( $(get_modified_files_relative) ) | |
| find "${files[@]}" -printf "%T@\t${DATE_DISPLAY_FORMAT}\t%p\n" | | |
| sort --numeric | | |
| cut --field 2- | | |
| column -t | |
| } | |
| # Script entry point | |
| main () { | |
| # shellcheck source=/home/alex/Documents/scripts/common.sh | |
| source common.sh | |
| parse_arguments "${@}" | |
| if ! is_git_repo ; then | |
| return 1 | |
| fi | |
| print_modified_files | |
| return 0 | |
| } | |
| # Call main function | |
| main "${@}" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Script git-tag-rev.sh | |
| # --------------------- | |
| # Script that parses each commit message and verifiy that there are no missing | |
| # tags for commit with message (<llvm-module> v<version>). Propose to add tags | |
| # if there are missing. | |
| # Note that this script is operating in DRY-RUN mode by default (flag '-x' to switch). | |
| # Script usage | |
| usage () { | |
| printf "Usage: %b%s%b [-h] [-v] [-m] [-f] [-a] [-x] [-t]\n" "${Color_BBlue}" "${0##*/}" "${Color_Reset}" | |
| printf "\t-h display this message\n" | |
| printf "\t-v display more logs\n" | |
| printf "\t-q display less logs\n" | |
| printf "\t-m enable multi-repo mode (i.e. in which, a repo has a single module)\n" | |
| printf "\t-f find module in repository history (useful in mono-repo mode i.e. no '-m' option)\n" | |
| printf "\t-a process all reachable commits, not just the 'main branch'\n" | |
| printf "\t-x disable dry run mode %b(will modify current repository)%b\n" "${Color_BYellow}" "${Color_Reset}" | |
| printf "\t-t automatically add tag on found commits\n" | |
| exit 2 | |
| } | |
| # Parse command line arguments | |
| parse_arguments () { | |
| VERBOSE="false" | |
| SILENT="false" | |
| MODE="monorepo" | |
| FIND_MODULES="false" | |
| ALL_COMMITS="false" | |
| DRY_RUN="true" | |
| AUTOTAG="false" | |
| while getopts ':hvqmfaxt' arg | |
| do | |
| case ${arg} in | |
| v) VERBOSE="true" | |
| ;; | |
| q) SILENT="true" | |
| ;; | |
| m) MODE="multi-repo" | |
| ;; | |
| f) FIND_MODULES="true" | |
| ;; | |
| a) ALL_COMMITS="true" | |
| ;; | |
| x) DRY_RUN="false" | |
| ;; | |
| t) AUTOTAG="true" | |
| ;; | |
| h) usage | |
| ;; | |
| \?) error "Unknown option -${OPTARG}" | |
| usage | |
| ;; | |
| :) error "Missing argument for option -${OPTARG}" | |
| usage | |
| ;; | |
| *) error "Option -${arg} not implemented" | |
| usage | |
| ;; | |
| esac | |
| done | |
| shift $((OPTIND - 1)) | |
| readonly VERBOSE SILENT MODE FIND_MODULES ALL_COMMITS DRY_RUN AUTOTAG | |
| } | |
| # Function that display the first line of the message (i.e. the "subject") of the commit specified by the SHA passed as a parameter | |
| get_commit_subject () { | |
| git show --no-patch --format=%s "${1}" | |
| } | |
| # Function that display the full message (i.e. the "body") of the commit specified by the SHA passed as a parameter | |
| get_commit_message () { | |
| git show --no-patch --format=%B "${1}" | |
| } | |
| # Function that display the tag (if any) of the commit specified by the SHA passed as a parameter | |
| get_commit_tag () { | |
| local status | |
| # shellcheck disable=SC2034 | |
| git describe --tags --exact-match "${1}" 2>/dev/null && | |
| status=$? || | |
| status=$? | |
| } | |
| # Fix known mispelling of llvm modules | |
| get_proper_module () { | |
| local module=${1} | |
| case "${module}" in | |
| tf-backtest-llvm | itf-èbacktest-llvm | itf-backtest) | |
| module="itf-backtest-llvm" | |
| ;; | |
| itf-pbr-orderrequestion) | |
| module="itf-pbr-orderrequest" | |
| ;; | |
| esac | |
| printf "%s" "${module}" | |
| } | |
| # Function that check if the current commit message should be tagged (against a regex) and verify the tag name. | |
| # Tag regex and the commit SHA are expected as parameters. | |
| check_missing_tag () { | |
| local regex subject message tag | |
| regex=${1} | |
| subject=$(get_commit_subject "${2}") | |
| message=$(get_commit_message "${2}") | |
| tag=$(get_commit_tag "${2}") | |
| # Log commit on info if there is a tag | |
| if [[ -z ${tag} ]] ; then | |
| local log_level="fine" | |
| else | |
| local log_level="info" | |
| fi | |
| ${log_level} "Current commit ${2:0:8} ${tag:+"with tag '${tag}' and "}message '${subject}'" | |
| # Parse commit subject with regex | |
| if [[ ! ${subject} =~ ${regex} ]] ; then | |
| # The subject does not match the regex => this revision does not require a tag | |
| fine "Skipped because it does not match the regex" | |
| return | |
| fi | |
| local expected_tag | |
| if [[ ${MODE} != "monorepo" ]] ; then | |
| expected_tag=${BASH_REMATCH[1]} | |
| else | |
| # make a matching table of mispell of modules (see ~/tmp/itf-llvm_modules.txt) | |
| # maybe the regex could be more flexible to capture more potential tags? | |
| expected_tag="$(get_proper_module "${BASH_REMATCH[1]}")_${BASH_REMATCH[2]}" | |
| fi | |
| # Check syntax of message | |
| if [[ -z ${tag} || "${tag}" != "${expected_tag}" ]] ; then | |
| # TODO check if tag is already set on an other commit? | |
| warn "Commit ${2:0:8} was expected to be tagged with '${expected_tag}'${tag:+" (found: ${tag}")}" | |
| log White "Commit message:" | |
| log White "${message}" | |
| maybe_tag_commit "${2}" "${expected_tag}" | |
| fi | |
| } | |
| # Function that may tag a commit with the specified tag (SHA and expected tag are passed as parameters) | |
| maybe_tag_commit () { | |
| local sha=${1} | |
| local tag=${2} | |
| # Check if tag is already set | |
| if git rev-parse "${tag}" > /dev/null 2>&1 ; then | |
| error "Tag ${tag} is already used" | |
| read -s -r -n 1 -p "<Press any key to continue>" | |
| return | |
| fi | |
| # If manual mode, propose to tag the commit | |
| if [[ ${AUTOTAG} == "false" ]] ; then | |
| local prompt | |
| printf -v prompt "Tag commit %b%s%b with tag %b%s%b? (y/n) > " "${Color_IBlue}" "${sha:0:8}" "${Color_Reset}" "${Color_IGreen}" "${tag}" "${Color_Reset}" | |
| read -rp "${prompt}" proceed | |
| fi | |
| if [[ ${AUTOTAG} == "true" || ${proceed} == "y" ]] ; then | |
| local tag_command="git tag ${tag} ${sha}" | |
| warn "Tag set with '${tag_command}'" | |
| if [[ ${DRY_RUN} == "false" ]] ; then | |
| ${tag_command} | |
| fi | |
| fi | |
| } | |
| # Function that display the SHA of the first parent commit of the SHA passed as a parameter | |
| get_commit_parent () { | |
| git rev-list --parents --max-count 1 "${1}" | | |
| cut --delimiter ' ' --only-delimited --fields 2 | |
| } | |
| # Check repo history for missing tags in a repo | |
| check_history () { | |
| # XXX check that current branch is master? | |
| local regex=${1} | |
| local commit_sha='HEAD' | |
| until [[ -z ${commit_sha} ]] ; | |
| do | |
| check_missing_tag "${regex}" "${commit_sha}" | |
| # get the FIRST parent and proceed | |
| commit_sha=$(get_commit_parent ${commit_sha}) | |
| done | |
| } | |
| # Check all commit reachable from current HEAD and verify if a tag is missing | |
| check_all_commits () { | |
| local regex=${1} | |
| for sha in $(git log --format="%h") ; do | |
| check_missing_tag "${regex}" "${sha}" | |
| done | |
| } | |
| # Display modules found using the specified regex | |
| find_modules () { | |
| warn "Number of tags per modules:" | |
| git log --oneline | | |
| grep --extended-regexp "${1}" | | |
| sed --regexp-extended --expression "s/^.*${1}.*$/\1/g" | | |
| sort | | |
| uniq --count | | |
| sort --reverse --numeric-sort | |
| } | |
| # Script entry point | |
| main () { | |
| # shellcheck source=/home/alex/Documents/scripts/common.sh | |
| source common.sh | |
| parse_arguments "${@}" | |
| if ! is_git_repo ; then | |
| return 1 | |
| fi | |
| if [[ ${MODE} != "monorepo" ]] ; then | |
| local regex="\(${PWD##*/} v([0-9\.]+)\)" | |
| else | |
| local regex="\(([a-zA-Z\-]+).*[v ]([0-9\.]+)\)" | |
| if [[ ${FIND_MODULES} == "true" ]] ; then | |
| find_modules "${regex}" | |
| return 0 | |
| fi | |
| fi | |
| if [[ ${ALL_COMMITS} == "true" ]] ; then | |
| check_all_commits "${regex}" | |
| else | |
| check_history "${regex}" | |
| fi | |
| # Propose to push tags? | |
| return 0 | |
| } | |
| # Call main function | |
| main "${@}" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Script next-tram.sh | |
| # ------------------- | |
| # Retrieve and parse Ilevia HTML page with the tramway timetable at Cartelot stop | |
| ## Global variables | |
| # Command line options for wget | |
| readonly WGET_OPTIONS="--quiet --no-check-certificate" | |
| # Temporary directory | |
| readonly TMP_DIR="/tmp/next-tram" | |
| # File with the whole HTML from Ilevia | |
| readonly ILEVIA_HTML="$TMP_DIR/ilevia.html" | |
| # File with the first direction | |
| readonly DIRECTION1="$TMP_DIR/direction1.html" | |
| # File with the second direction | |
| readonly DIRECTION2="$TMP_DIR/direction2.html" | |
| # Script usage | |
| usage () { | |
| printf "Usage: %b%s%b [-h] [-v] [-d]\n" "${Color_BBlue}" "${0##*/}" "${Color_Reset}" | |
| printf "\t-h display this message\n" | |
| printf "\t-v display more logs\n" | |
| printf "\t-d enable debug mode (e.g. does not delete working files)\n" | |
| printf "\t-s indicate the station (Cartelot or Chateau Rouge)\n" | |
| exit 2 | |
| } | |
| # Parse command line arguments | |
| parse_arguments () { | |
| DEBUG="false" | |
| STATION="Cartelot+%%28Wasquehal%%29" | |
| STATION_CODE="2086" | |
| while getopts ':hvds:' arg | |
| do | |
| case ${arg} in | |
| d) DEBUG="true" | |
| ;; | |
| s) case "${OPTARG}" in | |
| "Cartelot") | |
| # nothing to do, default value | |
| ;; | |
| "Chateau Rouge") | |
| STATION="Chateau+Rouge+%%28Marcq-en-Barœul%%29" | |
| STATION_CODE="1126" | |
| ;; | |
| esac | |
| ;; | |
| v) VERBOSE="true" | |
| ;; | |
| h) usage | |
| ;; | |
| \?) error "Unknown option -${OPTARG}" | |
| usage | |
| ;; | |
| :) error "Missing argument for option -${OPTARG}" | |
| usage | |
| ;; | |
| *) error "Option -${arg} not implemented" | |
| usage | |
| ;; | |
| esac | |
| done | |
| shift $((OPTIND - 1)) | |
| readonly DEBUG VERBOSE STATION STATION_CODE | |
| } | |
| # Creates the temporary directory for the HTML files | |
| mk_dir () { | |
| mkdir --parents "${TMP_DIR}" | |
| } | |
| # Download the current timetable (in real-time) from the website | |
| download_timetable () { | |
| printf -v txt "Next stops for tram on the %(%d-%m-%Y at %H:%M)T" | |
| info "${txt}" | |
| # Get the page with the results | |
| local url_format="https://nmp-ihm.ctp.prod.canaltp.fr/fr/load/bvbOLvph/schedule/result/?schedule%%5Bstop_area%%5D%%5Bautocomplete%%5D=${STATION}&schedule%%5Bstop_area%%5D%%5Bautocomplete-hidden%%5D=stop_area%%3ATRA%%3ASA%%3A${STATION_CODE}&schedule%%5Bfrom_datetime%%5D%%5Bdate%%5D=%(%d/%m/%Y)T&schedule%%5Bfrom_datetime%%5D%%5Btime%%5D%%5Bhour%%5D=%(%H)T&schedule%%5Bfrom_datetime%%5D%%5Btime%%5D%%5Bminute%%5D=%(%M)T&line=line%%3ATRA%%3A71" | |
| # shellcheck disable=SC2059 | |
| printf -v url "${url_format}" | |
| fine "Downloading ${url}" | |
| local wget_status | |
| wget ${WGET_OPTIONS} -O ${ILEVIA_HTML} "${url}" && | |
| wget_status=$? || | |
| wget_status=$? | |
| if [[ ${wget_status} -ne 0 ]] ; then | |
| error "wget command exited with code ${wget_status}" | |
| return 1 | |
| fi | |
| } | |
| # Split files for each direction | |
| split_files () { | |
| # File reduced to <table> content | |
| local schedule_table_html="${TMP_DIR}/scheduleTable.html" | |
| info "$(grep --only-matching --max-count 1 --extended-regexp 'Horaire à l.*$' ${ILEVIA_HTML} | | |
| sed "s/'/'/g")" | |
| # Timetable are in an HTML <table> | |
| tr "\n\r" "|" < ${ILEVIA_HTML} \ | |
| | grep --only-matching --extended-regexp --max-count 1 '<table>.*?Direction.*?</table>' \ | |
| | sed --expression 's/|/\n/g' > ${schedule_table_html} | |
| # Split files on 'class="direction-name"' to have one file per direction | |
| local split_line | |
| split_line=$(grep --line-number "class=\"direction-name\"" ${schedule_table_html} \ | |
| | cut --delimiter : --fields 1 \ | |
| | head --lines 2 \ | |
| | tail --lines 1) | |
| fine "Split file ${schedule_table_html} on line ${split_line}" | |
| (head --lines "${split_line}" > ${DIRECTION1}; cat > ${DIRECTION2} ) < ${schedule_table_html} | |
| } | |
| # Print direction and next schedules in each | |
| print_next_tram () { | |
| for file in ${DIRECTION1} ${DIRECTION2} ; do | |
| # Print direction | |
| info "$(grep --extended-regexp --max-count 1 'Gare Lille Flandres' ${file} | | |
| sed --regexp-extended --expression 's/^ +//g ; s/ +$//g')" | |
| # Print next schedules | |
| local next_stops | |
| next_stops=( $(grep --extended-regexp --max-count 2 '([0-9]+ min|[0-9]+h[0-9]+)' ${file} | | |
| sed --regexp-extended --expression 's_<span>([0-9]+ min|[0-9]+h[0-9]+)</span>_\1_g' | | |
| sed --regexp-extended --expression 's/^ +//g ; s/ +$//g') ) | |
| info "${next_stops[@]}" | |
| done | |
| } | |
| # Clean-up HTML files | |
| clean_up () { | |
| if [[ ${DEBUG} != "true" ]] ; then | |
| rm --force --recursive ${TMP_DIR:?'Temp dir to delete is not set'} | |
| fi | |
| } | |
| # Script entry point | |
| main () { | |
| # shellcheck source=/home/alex/Documents/scripts/common.sh | |
| source common.sh | |
| parse_arguments "${@}" | |
| mk_dir | |
| download_timetable | |
| split_files | |
| print_next_tram | |
| clean_up | |
| return 0 | |
| } | |
| # Call main function | |
| main "${@}" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Script remote-session.sh | |
| # ----------------------- | |
| # Automatically connect to specified remote server using the appriate account | |
| # The server to account configuration is read from a file | |
| ## Global variables | |
| # Known accounts to try if server is not configured (TODO read from config file?) | |
| readonly ACCOUNTS=(proorder proinvest devc icingadevc dba alex) | |
| # Script usage | |
| usage () { | |
| printf "Usage: %b%s%b [-h] [-v] [-t] [-a <ACCOUNT>] -s <SERVER>\n" "${Color_BBlue}" "${0##*/}" "${Color_Reset}" | |
| printf "\t-h display this message\n" | |
| printf "\t-v display more logs\n" | |
| printf "\t-q display less logs\n" | |
| printf "\t-t test which accounts are working with the server\n" | |
| printf "\t-a the account to connect to (read from configuration if not specified)\n" | |
| printf "\t-s the server to connect to\n" | |
| exit 2 | |
| } | |
| # Parse command line arguments | |
| parse_arguments () { | |
| VERBOSE="false" | |
| SILENT="false" | |
| TEST_ACCOUNTS="false" | |
| while getopts ':hvqta:s:' arg ; do | |
| case ${arg} in | |
| v) VERBOSE="true" | |
| ;; | |
| q) SILENT="true" | |
| ;; | |
| t) TEST_ACCOUNTS="true" | |
| ;; | |
| a) ACCOUNT=${OPTARG} | |
| ;; | |
| s) SERVER=${OPTARG} | |
| ;; | |
| h) usage | |
| ;; | |
| \?) error "Unknown option -${OPTARG}" | |
| usage | |
| ;; | |
| :) error "Missing argument for option -${OPTARG}" | |
| usage | |
| ;; | |
| *) error "Option -${OPTARG} not implemented" | |
| ;; | |
| esac | |
| done | |
| if [[ -z ${SERVER:-""} ]] ; then | |
| error "Missing mandatory -s parameter" | |
| exit 1 | |
| fi | |
| readonly VERBOSE TEST_ACCOUNTS ACCOUNT SERVER | |
| } | |
| # Load bashrc_remote on the remote host with ssh | |
| ssh_bashrc () { | |
| local remote_bashrc ssh_status | |
| remote_bashrc=$(base64 --wrap 0 < "${HOME}"/Documents/etc/bashrc_remote) | |
| local remote_bashrc_file="/tmp/${USER}_${$}_bashrc" | |
| # Change title of terminal to display the current session | |
| printf "\033]30;%s\007" "${@}" | |
| # shellcheck disable=SC2029 | |
| ssh -t "${@}" "printf \"%s\" \"${remote_bashrc}\" | base64 --decode > ${remote_bashrc_file}; bash --rcfile ${remote_bashrc_file}; rm ${remote_bashrc_file}" && | |
| ssh_status=$? || | |
| ssh_status=$? | |
| # Change the title back to the original configuration | |
| printf "\033]30;%%d : %%n\007" | |
| } | |
| # Connect to remote server | |
| connect_to_remote () { | |
| info "Connecting to ${1}@${SERVER}" | |
| ssh_bashrc "${1}"@"${SERVER}" | |
| info "End of remote session with '${SERVER}'" | |
| } | |
| # Try all accounts for the specified server, print all working accounts | |
| get_working_accounts () { | |
| local working_accounts="" | |
| for account in ${ACCOUNTS[*]} ; do | |
| local ssh_status | |
| # Attempt executing a simple command on the remote server | |
| ssh "${account}"@"${SERVER}" "true" 2>/dev/null && | |
| ssh_status=$? || | |
| ssh_status=$? | |
| if [[ ${ssh_status} == 0 ]] ; then | |
| info "Can connect to '${SERVER}' with account '${account}'" | |
| working_accounts+="${account} " | |
| else | |
| fine "Cannot connect to '${SERVER}' with account '${account}'" | |
| fi | |
| done | |
| printf "%s" "${working_accounts% *}" | |
| } | |
| # Check if the account(s) (the 1st argument) is empty and returns 1 if that is the case | |
| has_account () { | |
| if [[ -z ${1} ]] ; then | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| # Show the list of working account for the specified server and let the user pick the account if several are working | |
| # If the first argument is provided, use it as the working accounts, else call get_working_accounts | |
| # Return 0 and print the selected account on success, if no account found or user selected quit returns 1 | |
| select_working_account () { | |
| PS3="Select account to connect to '${SERVER}' # " | |
| local working_accounts | |
| working_accounts=$(get_working_accounts) | |
| # No working account found/provided | |
| if ! has_account "${working_accounts}" ; then | |
| warn "Could not connect to server '${SERVER}' with accounts ${ACCOUNTS[*]}" | |
| return 1 | |
| fi | |
| # A single account found/provided | |
| if [[ -z ${working_accounts//[^ ]/} ]] ; then | |
| printf "%s" "${working_accounts}" | |
| return 0 | |
| fi | |
| warn "Can connect to '${SERVER}' with accounts '${working_accounts}' ..." | |
| select account in ${working_accounts} "quit" | |
| do | |
| case ${account} in | |
| quit) info "Exiting..." | |
| return 1 | |
| ;; | |
| *) printf "%s" "${account}" | |
| return 0 | |
| ;; | |
| esac | |
| done | |
| } | |
| # Get account for remote server with unknown configuration | |
| get_missing_conf_server () { | |
| warn "No predefined accounts found for server '${SERVER}'" | |
| local account | |
| if ! account=$(select_working_account) ; then | |
| return | |
| fi | |
| maybe_add_conf "${account}" | |
| printf "%s" "${account}" | |
| } | |
| # Prompt user if the new configuration should be added to the file | |
| maybe_add_conf () { | |
| local prompt | |
| local existing_conf=${REMOTE_SERVERS_ACCOUNTS[${SERVER}]:-""} | |
| # Check if already present in file, offer to replace it | |
| if [[ -n ${existing_conf} ]] ; then | |
| if [[ ${1} == "${existing_conf}" ]] ; then | |
| # Do nothing, configuration exists | |
| return | |
| fi | |
| printf -v prompt "Replace existing server configuration %b%s%b@%b%s%b (with default account %b%s%b) in configuration file? (y/n) > " "${Color_IRed}" "${existing_conf}" "${Color_Reset}" "${Color_IGreen}" "${SERVER}" "${Color_Reset}" "${Color_ICyan}" "${1}" "${Color_Reset}" | |
| else | |
| printf -v prompt "Add new server configuration %b%s%b (with default account %b%s%b) in configuration file? (y/n) > " "${Color_IGreen}" "${SERVER}" "${Color_Reset}" "${Color_ICyan}" "${1}" "${Color_Reset}" | |
| fi | |
| read -rp "${prompt}" proceed | |
| if [[ ${proceed} == "y" ]] ; then | |
| if [[ -n ${existing_conf} ]] ; then | |
| warn "Replacing configuration for server '${SERVER}' with '${1}' as the default account configuration" | |
| sed --in-place --regexp-extended --expression "s/^${SERVER}=${existing_conf}\$/${SERVER}=${1}/g" "${SERVER_ACCOUNT_FILE}" | |
| else | |
| warn "Adding server '${SERVER}' with '${1}' as a default account to configuration" | |
| printf "%s=%s\n" "${SERVER}" "${1}" >> "${SERVER_ACCOUNT_FILE}" | |
| fi | |
| fi | |
| } | |
| # Entry point of the script | |
| main () { | |
| # shellcheck source=/home/alex/Documents/scripts/common.sh | |
| source common.sh | |
| parse_arguments "${@}" | |
| load_server_account_file_if_needed | |
| local account=${ACCOUNT:-""} | |
| if [[ ${TEST_ACCOUNTS} == "true" ]] ; then | |
| account=$(select_working_account) | |
| maybe_add_conf "${account}" | |
| else | |
| if [[ -z ${account} ]] ; then | |
| # Check if server is in array | |
| account=${REMOTE_SERVERS_ACCOUNTS[${SERVER}]:-""} | |
| fi | |
| if [[ -z ${account} ]] ; then | |
| account=$(get_missing_conf_server) | |
| fi | |
| fi | |
| # Connect to remote if we have an account | |
| if [[ -n ${account} ]] ; then | |
| connect_to_remote "${account}" | |
| return 0 | |
| else | |
| return 1 | |
| fi | |
| } | |
| # Calling main function | |
| main "${@}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment