#!/usr/bin/env sh # Licensed under ArArv2 license: https://files.ari-web.xyz/files/ArAr.ari-archer.LICENSE # Description: manage, switch and template licenses # DEPENDS ON: # general utilities: coreutils [head, awk, ...] # license picker: fzf (optional) # automatic config generation: git (optional) # colours: ncurses (optional) [tput] set -e VERSION='0.8' # Init [ -z "$HOME" ] && HOME="$(eval echo '~')" depend() { command -v -- "$1" >/dev/null || (echo "FATAL: depend(): Dependency '$1' broken" 1>&2 && exit 11); } # Colours (requires ncurses) if [ "$LMGR_COLOURS" != 0 ]; then depend 'tput' RED=$(tput setaf 1) GREEN=$(tput setaf 2) YELLOW=$(tput setaf 3) BRIGHT=$(tput bold) RESET=$(tput sgr0) fi # Aliases alias lless='less -NrIMJ --use-color --incsearch --line-num-width=2' alias ffind='find -L' # Constants LICENSE_DIR="$HOME/.config/licenses" LICENSE_SED='s/^@//' # Utility functions error() { printf " ${RED}*${RESET} %s\n" "$1" 1>&2; } warn() { printf " ${YELLOW}*${RESET} %s\n" "$1" 1>&2; } info() { printf " ${GREEN}*${RESET} %s\n" "$1"; } einfo() { printf " ${BRIGHT}*${RESET} %s\n" "$1"; } check_valid_license() { lic="$(echo "$1" | sed "$LICENSE_SED")" echo "$1" | grep -qi '^@' || (error "License '$lic' is not valid" && exit 9) [ ! -f "$LICENSE_DIR"/"$lic" ] && (error "License '$lic' does not exist" && exit 10) return 0 } sed_escape() { echo "$1" | sed -e 's/[\/&]/\\&/g'; } # Functions list_licenses() { ffind "$LICENSE_DIR" -maxdepth 1 -type f -printf " ${BRIGHT}*${RESET} @%f\n"; } usage() { echo " License manager v$VERSION" echo ' manage, switch and template licenses' echo '' echo " \$AUTHOR_NAME -- '$AUTHOR_NAME'" echo " \$AUTHOR_EMAIL -- '$AUTHOR_EMAIL'" echo " \$AUTHOR_WEBSITE -- '$AUTHOR_WEBSITE'" echo " \$LICENSE_DIR -- '$LICENSE_DIR'" echo '' echo " [ENV=VAL ...] $(basename "$0") " echo '' echo ' -help --help -h show usage' echo ' -list-licenses -l list awailable licenses' echo ' -current-license -c show current active project license' echo ' -pick-license -p pick a license in a FZF menu' echo ' -preview-license -P @license_name preview a license template' echo ' -remove-license -r remove all licenses from the current project' echo " -search-license -s '' search for license" echo ' -template-help -T print help for templating' echo ' -new-template -t create a new license template' echo ' -delete-license -R @license_name ... delete a license from templates' echo ' -new-config -C create a default config overwriting current one' echo ' -check-conflict -k check if current licene(s) are conflicting' echo '' echo " LMGR_COLOURS=0|[1] turn colour on (1) or off (0) [${LMGR_COLOURS:-1}]" } make_new_config() { mkdir -p "$HOME"/.config { echo '#!/usr/bin/env sh' echo "export AUTHOR_NAME='$(git config user.name || echo "${USER}")'" echo "export AUTHOR_EMAIL='$(git config user.email || echo "${USER}@gmail.com")'" echo "export AUTHOR_WEBSITE='https://example.com/'" echo "export LICENSE_DIR='$LICENSE_DIR'" } >"$HOME"/.config/license.conf } show_license() { depend 'head' l_name='LICENSE' [ -f UNLICENSE ] && l_name='UNLICENSE' if [ -f "$l_name" ]; then head -n1 "$l_name" | sed 's/^\s*//; s/\s*$//' else echo 'strong copyright (no license)' fi } check_license_conflict() { if [ -f ./LICENSE ] && [ -f ./UNLICENSE ]; then error 'Licensing conflict: UNLICENSE and LICENSE both found' printf ' Do you either (1) Remove LICENSE or (2) Remove UNLICENSE? [1/2] ' read -r lr case "$lr" in 1) rm LICENSE ;; 2) rm UNLICENSE ;; *) error "'$lr' is not an option" && exit 1 ;; esac || (error 'Could not resolve licensing conflict' && exit 6) fi } get_license() { depend 'cp' check_valid_license "$1" check_license_conflict user_license="$(echo "$1" | sed "$LICENSE_SED")" if [ ! -f "$LICENSE_DIR"/"$user_license" ]; then error "No licence by the name of '$1'" list_licenses error 'Use of of the above' exit 5 elif [ -f ./LICENSE ] || [ -f ./UNLICENSE ]; then info "Found license: $(show_license)" printf ' Switch licenses? [y/n] ' read -r yn [ ! "$yn" = "y" ] && exit fi l_name='LICENSE' [ "$(head -n1 "$LICENSE_DIR"/"$user_license")" = 'UNLICENSE' ] && l_name='UNLICENSE' cp -fiL "$LICENSE_DIR"/"$user_license" "$l_name" sed -i "$l_name" \ -e "s/{{PROJECT_NAME}}/$(sed_escape "$(basename "$PWD")")/g" \ -e "s/{{CURRENT_YEAR}}/$(sed_escape "$(date '+%Y')")/g" \ -e "s/{{AUTHOR_NAME}}/$(sed_escape "$AUTHOR_NAME")/g" \ -e "s/{{AUTHOR_EMAIL}}/$(sed_escape "$AUTHOR_EMAIL")/g" \ -e "s/{{AUTHOR_WEBSITE}}/$(sed_escape "$AUTHOR_WEBSITE")/g" check_license_conflict info "Current license now is set to $(show_license)" } license_picker() { depend 'awk' depend 'fzf' license="$(list_licenses | awk '{ print $2 }' | sed "$LICENSE_SED" | FZF_DEFAULT_OPTS='' fzf --layout=reverse --height=20 --no-mouse -i --preview "cat $LICENSE_DIR/{}" || echo '')" if [ -z "$license" ]; then license_picker return fi get_license "@$license" } search_license() { for lic in $(list_licenses | awk '{ print $2 }' | sed "$LICENSE_SED"); do if echo "$lic $(head -n8 "$LICENSE_DIR"/"$lic")" | grep -iq "$1"; then einfo "@$lic" fi done } remove_license() { rm -f UNLICENSE LICENSE 2>/dev/null || true info "Current license now is set to $(show_license)" } templating_help() { { echo 'Templating' echo '' echo 'To template a license you need to create a file named' echo "the same like you want to refer to your license, let's say \`hello\` in this example" echo "so now create a file called hello in '$LICENSE_DIR/hello'" echo '' echo 'Now you can make your license there, now onto templating' echo '' echo 'The templating "language" is pretty simple, all syntax goes in {{...}}' echo 'So the variables are:' echo ' * {{PROJECT_NAME}} -- The current project name (basename of current directory)' echo ' * {{CURRENT_YEAR}} -- The current year' echo " * {{AUTHOR_NAME}} -- The author's full name" echo " * {{AUTHOR_EMAIL}} -- The author's email" echo " * {{AUTHOR_WEBSITE}} -- The author's website" echo '' echo 'Example of a template: https://raw.githubusercontent.com/TruncatedDinosour/dotfiles-cleaned/gentoo/dotfiles/config/licenses/ArAr2' } | lless } new_template() { printf 'License name/alias (spaces will be removed) -- ' read -r ln [ -z "$ln" ] && ( error 'Cannot leave license name empty' exit 7 ) ln="$LICENSE_DIR/$(echo "$ln" | tr -d ' ' | head -c250)" if [ -f "$ln" ]; then printf 'This license already exists, do you want to overwrite it? [y/n] ' read -r yn [ "$yn" != 'y' ] && exit fi editor="${EDITOR:-}" if [ -z "$editor" ]; then printf 'Editor to open file in -- ' read -r editor fi [ -z "$editor" ] && ( error 'Cannot leave editor empty' exit 8 ) depend "$(basename "$editor" | awk '{print $1}')" set -x $editor "$ln" set +x [ -f "$ln" ] && einfo "License '$(basename "$ln")' saved" } delete_license() { check_valid_license "$1" rm -vi "$LICENSE_DIR"/"$(echo "$1" | sed "$LICENSE_SED")" } new_config() { einfo "This will overwite your config, are you sure you want do do that?" printf ' [y/n] ' read -r yn [ "$yn" != 'y' ] && exit make_new_config info 'New config made and saved' } main() { if [ -f "$HOME/.config/license.conf" ]; then # shellcheck disable=1091 . "$HOME/.config/license.conf" else warn 'No configuration file found. Creating it.' make_new_config exit 4 fi if [ ! -d "$LICENSE_DIR" ]; then # shellcheck disable=2088 warn "'$LICENSE_DIR' does not exist. Creating it." mkdir -p "$LICENSE_DIR" fi [ -z "$1" ] && ( usage exit 1 ) ffind "$LICENSE_DIR" -not -name . -not -path "$LICENSE_DIR" -prune -not -type f -exec rm -R {} + check_license_conflict case "$1" in -help | --help | -h) usage ;; -list-licenses | -l) list_licenses ;; -current-license | -c) einfo "$(show_license)" ;; -pick-license | -p) license_picker ;; -preview-license | -P) check_valid_license "$2" lless "$LICENSE_DIR"/"$(echo "$2" | sed "$LICENSE_SED")" 2>/dev/null || einfo "License $2 not found" ;; -remove-license | -r) remove_license ;; -search-license | -s) search_license "$2" ;; -template-help | -T) templating_help ;; -new-template | -t) new_template ;; -delete-license | -R) tmp_l=0 for lic in "$@"; do if [ "$tmp_l" = 0 ]; then tmp_l=1 continue fi delete_license "$lic" done ;; -new-config | -C) new_config ;; -check-conflict | -k) check_license_conflict ;; @*) check_valid_license "$1" && get_license "$1" ;; *) error "Flag $1 is not known." && usage && exit 2 ;; esac } main "$@"