# This runs in a new shell readonly -i PRINTLEVEL=${1} readonly ACTION=${2} MODULE=${3} DIR=${4} URL=${5} REV=${7} CLEAR_LINE=<%= clear_line %> readonly TEMP=.zdegit_${RANDOM} readonly TARBALL_TARGET=${DIR}/${TEMP}_tarball.tar.gz INFO_TARGET=${DIR}/.zdegit print_error() { print -u2 -PR ${CLEAR_LINE}"%F{red}<%= error %>%B${MODULE}:%b ${1}%f"${2:+$'\n'${(F):- ${(f)^2}}} } print_okay() { if (( PRINTLEVEL > 0 )); then local -r log=${2:+$'\n'${(F):- ${(f)^2}}} if [[ -e ${DIR}/.gitmodules ]]; then print -u2 -PR ${CLEAR_LINE}"%F{yellow}<%= warn %>%B${MODULE}:%b ${(C)1}. Module contains git submodules, which are not supported by Zim's degit and were not ${1}.%f"${log} else print -PR ${CLEAR_LINE}"<%= okay %>%B${MODULE}:%b ${(C)1}"${log} fi fi } download_tarball() { setopt LOCAL_OPTIONS EXTENDED_GLOB local host repo if [[ ${URL} =~ <%= url_regex %> ]]; then host=${match[3]} repo=${match[4]%.git} fi if [[ ${host} != github.com || -z ${repo} ]]; then print_error "${URL} is not a valid GitHub URL. Will not try to ${ACTION}." return 1 fi local -r headers_target=${DIR}/${TEMP}_headers { local info_header header etag if [[ -r ${INFO_TARGET} ]]; then local -r info=("${(@f)"$(<${INFO_TARGET})"}") if [[ ${URL} != ${info[1]} ]]; then print_error "URL does not match. Expected ${URL}. Will not try to ${ACTION}." return 1 fi # Previous REV is in line 2, reserved for future use. info_header=${info[3]} fi local -r tarball_url=https://api.github.com/repos/${repo}/tarball/${REV} if (( ${+commands[curl]} )); then if ! ERR=$(command curl -fsSL ${info_header:+-H} ${info_header} -o ${TARBALL_TARGET} -D ${headers_target} ${tarball_url} 2>&1); then print_error "Error downloading ${tarball_url} with curl" ${ERR} return 1 fi else # wget returns 8 when 304 Not Modified, so we cannot use wget's error codes command wget -q ${info_header:+--header=${info_header}} -O ${TARBALL_TARGET} -S ${tarball_url} 2>${headers_target} fi local -i http_code while IFS= read -r header; do header=${${header## ##}%%$'\r'##} if [[ ${header} == HTTP/* ]]; then http_code=${${(s: :)header}[2]} elif [[ ${${(L)header%%:*}%% ##} == 'etag' ]]; then etag=${${header#*:}## ##} fi done < ${headers_target} if (( http_code == 304 )); then # Not Modified command rm -f ${TARBALL_TARGET} 2>/dev/null return 0 elif (( http_code != 200 )); then print_error "Error downloading ${tarball_url}, HTTP code ${http_code}" return 1 fi if [[ -z ${etag} ]]; then print_error "Error downloading ${tarball_url}, no ETag header found in response" return 1 fi if ! print -R ${URL}$'\n'${REV}$'\n'"If-None-Match: ${etag}" >! ${INFO_TARGET} 2>/dev/null; then print_error "Error creating or updating ${INFO_TARGET}" return 1 fi } always { command rm -f ${headers_target} 2>/dev/null } } untar_tarball() { if ! ERR=$(command tar -C ${1} --strip=1 -xzf ${TARBALL_TARGET} 2>&1); then print_error "Error extracting ${TARBALL_TARGET}" ${ERR} return 1 fi } create_dir() { if ! ERR=$(command mkdir -p ${1} 2>&1); then print_error "Error creating ${1}" ${ERR} return 1 fi } () { case ${ACTION} in install) { create_dir ${DIR} && download_tarball && untar_tarball ${DIR} && print_okay installed } always { # return 1 does not change ${TRY_BLOCK_ERROR}, only changes ${?} (( TRY_BLOCK_ERROR = ? )) command rm -f ${TARBALL_TARGET} 2>/dev/null if (( TRY_BLOCK_ERROR )); then command rm -rf ${DIR} 2>/dev/null fi } ;; update) if [[ -r ${DIR}/.zim_degit_info ]] command mv -f ${DIR}/.zim_degit_info ${INFO_TARGET} if [[ ! -r ${INFO_TARGET} ]]; then print_error "Module was not installed using Zim's degit. Will not try to update. You can disable this with the zmodule option -z|--frozen." return 1 fi local -r dir_new=${DIR}${TEMP} { download_tarball || return 1 if [[ ! -e ${TARBALL_TARGET} ]]; then if (( PRINTLEVEL > 0 )) print -PR ${CLEAR_LINE}"<%= okay %>%B${MODULE}:%b Already up to date" return 0 fi create_dir ${dir_new} && untar_tarball ${dir_new} || return 1 if (( ${+commands[diff]} )); then LOG=$(command diff -x '.zdegit*' -x '*.zwc' -x '*.zwc.old' -qr ${DIR} ${dir_new} 2>/dev/null) LOG=${${LOG//${dir_new}/new}//${DIR}/old} fi if ! ERR=$({ command cp -f ${INFO_TARGET} ${dir_new} && \ command rm -rf ${DIR} && command mv -f ${dir_new} ${DIR} } 2>&1); then print_error "Error updating ${DIR}" ${ERR} return 1 fi print_okay updated ${LOG} } always { command rm -f ${TARBALL_TARGET} 2>/dev/null command rm -rf ${dir_new} 2>/dev/null } ;; esac }