From 49432240402ac604773941035d38120eb6c9b36f Mon Sep 17 00:00:00 2001 From: Rob Frawley 2nd Date: Sat, 21 Nov 2020 05:22:17 -0500 Subject: [PATCH 1/2] replace installation script with bash version that performs a more robust installation operation --- install.bash | 329 +++++++++++++++++++++++++++++++++++++++++++++++++++ install.sh | 28 ----- 2 files changed, 329 insertions(+), 28 deletions(-) create mode 100755 install.bash delete mode 100755 install.sh diff --git a/install.bash b/install.bash new file mode 100755 index 00000000..bdbc367a --- /dev/null +++ b/install.bash @@ -0,0 +1,329 @@ +#!/bin/bash + +## +## This file is part of the `powerline/fonts` project. +## +## (c) Rob Frawley 2nd +## +## For the full copyright and license information, please view the LICENSE.md +## file that was distributed with this source code. +## + + +# +# output text using printf-style arguments +# + +function out_text() { + printf -- "${@}" +} + + +# +# output the number of newline passed on argument (defaults to 1) +# + +function out_nl_n() { + for i in $(seq 1 "${1:-1}"); do out_text '\n'; done +} + + +# +# output info line of text +# + +function out_info() { + 1>&2 out_text "[FONT] ${1}" "${@:2}" + 1>&2 out_nl_n +} + + +# +# output info line of text +# + +function out_fail() { + 1>&2 out_text "[FAIL] ${1}" "${@:2}" + 1>&2 out_nl_n +} + + +# +# escape path separators for regular expression +# +function get_path_escape_seps() { + sed 's/\//\\\//g' <<< "${1}" +} + + +# +# escape path separators for regular expression +# +function get_path_double_seps_rm() { + sed 's/\/\//\//g' <<< "${1}" +} + + +# +# escape path separators for regular expression +# +function get_file_replace_spaces() { + sed 's/ /-/g' <<< "${1}" +} + + +# +# resolve a path (expanding path and dereferencing symbolic links) using the most accurate method available +# + +function get_real_path() { + local inpt_path="${1}" + local full_path="$( + cd "${inpt_path}" 2> /dev/null && \ + pwd 2> /dev/null + )" + local real_path="$( + readlink -e "${full_path:-${inpt_path}}" 2> /dev/null || \ + realpath -e "${full_path:-${inpt_path}}" 2> /dev/null + )" + + out_text "${real_path:-${full_path:-${inpt_path}}}" +} + + +# +# resolve the real directory path of this script +# + +function get_self_path() { + get_real_path "$(dirname "${BASH_SOURCE[0]}")" +} + + +# +# call sudo with custom password prompt +# + +function get_sudo_prompt_text() { + local -a msg_args=("${@}") + + if [[ ${#msg_args[@]} -eq 0 ]]; then + msg_args+=("complete this operation") + fi + + out_text "[SUDO] To %s privileges must be escalating to \"%%U\" by entering the password for \"%%p\": " "$(out_text "${@}")" +} + + +# +# create the passed path (resorting to sudo if required) +# + +function make_path_reqd() { + local reqd_path="${1}" + + mkdir -p "${reqd_path}" 2> /dev/null || \ + sudo -p "$(get_sudo_prompt_text 'create the new path "%s"' "${reqd_path}")" mkdir -p "${reqd_path}" + + if [[ ! -d "${reqd_path}" ]]; then + out_fail 'Could not create required path "%s". Exiting...' "${reqd_path}" + exit 1 + fi +} + + +# +# copy the origin file to the target file (as assigned by the first and second arguments) +# + +function copy_file_req() { + local origin_file="${1}" + local target_file="${2}" + local caller_opts='--remove-destination --dereference --no-target-directory' + + cp ${caller_opts} "${origin_file}" "${target_file}" 2> /dev/null || \ + sudo -p "$(get_sudo_prompt_text 'copy the new file "%s"' "${target_file}")" cp ${caller_opts} "${origin_file}" "${target_file}" + + if [[ ! -f "${target_file}" ]]; then + out_fail 'Could not copy font file "%s" to "%s"!' "${origin_file}" "${target_file}" + return 1 + fi +} + + +# +# return the first path that exists in argument list passed (defaulting to returning the first argument if none exist) +# + +function get_existing_or_first_path() { + local -a path_list=("${@}") + local path_retn="${1}" + + for p in "${path_list[@]}"; do + if [[ -d ${p} ]] && [[ -w ${p} ]]; then + path_retn="${p}" + break + fi + done + + path_retn="$(get_path_double_seps_rm "${path_retn}")" + + if [[ ! -e "${path_retn}" ]]; then + make_path_reqd "${path_retn}" + fi + + out_text "${path_retn}" +} + + +# +# resolve the font installation/target path (for osx systems, re: darwin) +# + +function get_target_path_osx() { + get_existing_or_first_path "${HOME}/Library/Fonts" +} + + +# +# resolve the font installation/target path (for nix systems, re: linux) +# + +function get_target_path_nix() { + get_existing_or_first_path "${HOME}/.fonts" "${HOME}/.local/share/fonts" +} + + +# +# resolve the font installation/target path +# + +function get_target_path() { + if [[ -n ${INSTALL_FONT_ROOT_PATH} ]]; then + out_text "$(get_path_double_seps_rm "$(eval printf -- "${INSTALL_FONT_ROOT_PATH}")")" + return + fi + + case "$(uname)" in + Darwin) get_target_path_osx || return 1 ;; + Linux) get_target_path_nix || return 1 ;; + esac +} + + +# +# resolve the font type (truetype, opentype, etc) using the file extension (for double-extension types) +# + +function try_get_double_font_file_type_desc() { + local file_extn="$(basename "${1}")" + + case "$(grep -oE '(\.[^\.]+)?\.[^\.]+$' <<< "${file_extn}" 2> /dev/null)" in + .pcf.gz) out_text 'pcf' ;; + esac +} + + +# +# resolve the font type (truetype, opentype, etc) using the file extension +# + +function get_font_file_type_desc() { + local file_name="$(basename "${1}")" + + case ".${file_name##*.}" in + .ttf ) out_text 'truetype' ;; + .otf ) out_text 'opentype' ;; + * ) out_text "$(try_get_double_font_file_type_desc "${file_name}")" ;; + esac +} + + +# +# resolve the font family using the file path +# + +function get_font_file_faml_desc() { + local font_path="${1/$(get_path_escape_seps "${2:-}")/}" + + grep -oE '[^\/]+' <<< "$( + grep -oE '^\/?[^\/]+' <<< "${font_path}" 2> /dev/null + )" 2> /dev/null +} + + +# +# perform the font file installation +# + +function do_install_font_file() { + local font_target_inpt_path="${1}" + local font_source_full_path="${2}" + local self_script_full_path="${3}" + local font_source_base_path="$(dirname "${font_source_full_path}")" + local font_source_file_name="$(basename "${font_source_full_path}")" + local font_source_font_faml="$(get_font_file_faml_desc "${font_source_full_path}" "${self_script_full_path}")" + local font_source_font_type="$(get_font_file_type_desc "${font_source_full_path}")" + local font_target_file_name="$(get_file_replace_spaces "${font_source_file_name}")" + local font_target_root_path="$(get_path_double_seps_rm "${font_target_inpt_path}/${font_source_font_type}/${font_source_font_faml}")" + local font_target_full_path="$(get_path_double_seps_rm "${font_target_root_path}/${font_target_file_name}")" + + out_text '[font] family => "%s"\n type => "%s"\n origin => "%s"\n target => "%s"\n action => "copying"\n result => ' \ + "${font_source_font_faml}" \ + "${font_source_font_type}" \ + "${font_source_full_path}" \ + "${font_target_full_path}" + + if [[ ! -d ${font_target_root_path} ]]; then + make_path_reqd "${font_target_root_path}" + fi + + if copy_file_req "${font_source_full_path}" "${font_target_full_path}"; then + out_text '"successfully completed"' + else + out_text '"failure encountered"' + fi + + out_nl_n 2 +} + + +# +# perform the font installation for the passed font type filter +# + +function do_install_font_sets() { + local root_dest="${1}" + local font_type="${2:-*}" + local base_path="$(get_self_path)" + + find "${base_path}" \( \ + \( -iname "${font_type}*.[ot]tf" -or -iname "${font_type}*.pcf.gz" \) -or \ + \( -ipath "*${font_type}*/*.[ot]tf" -or -ipath "*${font_type}*/*.pcf.gz" \) \ + \) -type f -print0 | \ + while IFS= read -r -d '' font_file; do + do_install_font_file "${root_dest}" "${font_file}" "${base_path}" || break + done +} + + +# +# main function loops over passed font type filters, passing the target root path and font type to function +# + +function main() { + local font_types=("${@}") + local root_fdest + + if ! root_fdest="$(get_target_path)"; then + out_fail 'Could not resolve target font path for your system. This is most likely permissions related. Exiting...\n' + exit 1 + fi + + for t in "${font_types[@]:-*}"; do + do_install_font_sets "${root_fdest}" "${t}" + done +} + +# call main function to start! +main "${@}" diff --git a/install.sh b/install.sh deleted file mode 100755 index eab1ccd0..00000000 --- a/install.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh - -# Set source and target directories -powerline_fonts_dir="$( cd "$( dirname "$0" )" && pwd )" - -# if an argument is given it is used to select which fonts to install -prefix="$1" - -if test "$(uname)" = "Darwin" ; then - # MacOS - font_dir="$HOME/Library/Fonts" -else - # Linux - font_dir="$HOME/.local/share/fonts" - mkdir -p $font_dir -fi - -# Copy all fonts to user fonts directory -echo "Copying fonts..." -find "$powerline_fonts_dir" \( -name "$prefix*.[ot]tf" -or -name "$prefix*.pcf.gz" \) -type f -print0 | xargs -0 -n1 -I % cp "%" "$font_dir/" - -# Reset font cache on Linux -if which fc-cache >/dev/null 2>&1 ; then - echo "Resetting font cache, this may take a moment..." - fc-cache -f "$font_dir" -fi - -echo "Powerline fonts installed to $font_dir" From 03d8843f66181a40d7f737d91f98d8b2ba29c887 Mon Sep 17 00:00:00 2001 From: Rob Frawley 2nd Date: Sat, 21 Nov 2020 06:50:05 -0500 Subject: [PATCH 2/2] fix missing error redirection on find command --- install.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.bash b/install.bash index bdbc367a..758f9fb9 100755 --- a/install.bash +++ b/install.bash @@ -300,7 +300,7 @@ function do_install_font_sets() { find "${base_path}" \( \ \( -iname "${font_type}*.[ot]tf" -or -iname "${font_type}*.pcf.gz" \) -or \ \( -ipath "*${font_type}*/*.[ot]tf" -or -ipath "*${font_type}*/*.pcf.gz" \) \ - \) -type f -print0 | \ + \) -type f -print0 2> /dev/null | \ while IFS= read -r -d '' font_file; do do_install_font_file "${root_dest}" "${font_file}" "${base_path}" || break done