#!/usr/bin/env bash # manage public directories # WIP # ------------------------------------------------------------------- # #set -x shopt -s extglob #shopt -s failglob # Defaults: the usage should be as simple as throwing some stuff into # ~/pub and running $PROGNAME. DIR=~/pub PROGNAME="${0##*/}" # Usage information / help message. print_usage() { local text read -rd '' text << _EOF ${PROGNAME} - manage public directories usage: ${PROGNAME} [options] [command] [args...] options: -h: print this help message -d: define the public directory path (default ${DIR}) commands: default: if no command is given, ensure the public directory exists and fix it fix: fixes permissions of args, recursing on directories (default is the -d option) add: copies the args into the public directory and fixes them. link: not implemented right now show: not implemented right now bugs and notes: add command does not understand nested directories right now _EOF echo "${text}" } # Parse options. Takes $@, returns a number. # Do shift $number and the $@ becomes just the arguments. parse_options() { local opt local OPTARG local OPTIND while getopts 'hd:' opt do case "${opt}" in h) print_usage exit ;; d) if [[ -d "${OPTARG}" ]] then DIR="${OPTARG}" else echo "${PROGNAME}: ${OPTARG} is not a directory" >&2 exit 31 fi ;; *) echo "internal error" >&2 exit 30 ;; esac done return $(( OPTIND - 1 )) } # Read the command and arguments, dispatch runtime to another functions # in sensible manner. parse_command() { case "${1}" in # The default behaviour: make sure $DIR exists and fix that. ''|'default') ask_user \ 0 \ "$PROGNAME default behaviour: Try to setup $DIR?" || exit 0 if [[ -d "${DIR}" ]] || mkdir "${DIR}" then # I'm being absurdly clever here to save a few cycles. Since # the fix thing just below defaults to fixing $DIR, we just # fall into it using ;& instead of recursing parse_command. : else echo "${PROGNAME}: ${DIR} is not a directory" >&2 exit 41 fi ;& # fix: fix every arg, default to $DIR. 'fix') if [[ -e "${2}" ]] then fix_permissions "${@: 2}" else fix_permissions "${DIR}" fi ;; # add: no defaults, raise error if no args 'add') if [[ -e "${2}" ]] then copy_to_DIR "${@: 2}" else echo "${PROGNAME}: ${1}: no args" >&2 exit 42 fi ;; # * fallback: bad commands go to hell. Could try to guess what to do # if a path is given, but that's a very luxurious feature. *) echo "${PROGNAME}: ${1}: bad command" >&2 exit 40 ;; esac } # Helper function: print args, prompt for a [y/n] and return 0 or 1 # First arg is the default return value, which can be any integer ask_user() { if [[ ! $1 =~ [[:digit:]] ]] then echo "internal error" >&2 exit 21 fi local REPLY local def if (( $1 )); then d='[N/y]'; else d='[Y/n]'; fi echo "${*: 2}" read -res -n 1 -p " $d>> " case "${REPLY,,}" in y) return 0 ;; n) return 1 ;; *) return $1 ;; esac } # ------------------------------------------------------------------- # # Command code goes here. # Fix permissions. Sets: # files to 644, # executable files to 755, # files where path contains 'bin' to 755, # directories to 755 and recurses on them. fix_permissions() { for f do if [[ -f "${f}" ]] then [[ -x "${f}" ]] && chmod 755 "${f}" && continue [[ "${f}" =~ bin ]] && chmod 755 "${f}" && continue chmod 644 "${f}" elif [[ -d "${f}" ]] then chmod 755 "${f}" fix_permissions "${f}"/* fi done } # THIS IS TRASH AND CP IS TRASH copy_to_DIR() { for f do if [[ ! -e "${DIR}"/"${f##*/}" ]] then /bin/cp -r "${f}" "${DIR}/" && fix_permissions "${DIR}"/"${f##*/}" fi done } # ------------------------------------------------------------------- # # Main runtime main() { parse_options "${@}" shift ${?} parse_command "${@}" } main "${@}"