mirror of
https://github.com/zdharma-continuum/zconvey.git
synced 2026-09-10 07:06:21 -04:00
199 lines
6.5 KiB
Bash
199 lines
6.5 KiB
Bash
setopt localoptions extendedglob clobber
|
|
|
|
function __zconvey_usage_zc() {
|
|
__zconvey_pinfo2 "Sends specified commands to given (via ID or NAME) Zsh session"
|
|
__zconvey_pinfo "Usage: zc {-i ID}|{-n NAME} [-q|--quiet] [-v|--verbose] [-h|--help] [-a|--ask] [-r|--raw] COMMAND ARGUMENT ..."
|
|
print -- "-h/--help - this message"
|
|
print -- "-i ID / --id ID - ID (number) of Zsh session"
|
|
print -- "-n NAME / --name NAME - NAME of Zsh session"
|
|
print -- "-q/--quiet - don't output status messages"
|
|
print -- "-v/--verbose - output more status messages"
|
|
print -- "-a/--ask - ask for command (if not provided) and session (etc.)"
|
|
print -r -- "-r/--raw - raw input (for scripts) - a quoted string, e.g. ls \\'a\\ dir\\'"
|
|
}
|
|
|
|
local -A opthash
|
|
zparseopts -D -A opthash h -help q -quiet v -verbose i: -id: n: -name: a -ask r -raw || { __zconvey_usage_zc; return 1; }
|
|
|
|
integer have_id=0 have_name=0 verbose=0 quiet=0 ask=0 raw=0
|
|
local id name
|
|
|
|
# Help
|
|
(( ${+opthash[-h]} + ${+opthash[--help]} )) && { __zconvey_usage_zc; return 0; }
|
|
|
|
# ID
|
|
have_id=$(( ${+opthash[-i]} + ${+opthash[--id]} ))
|
|
(( ${+opthash[-i]} )) && id="${opthash[-i]}"
|
|
(( ${+opthash[--id]} )) && id="${opthash[--id]}"
|
|
|
|
# NAME
|
|
have_name=$(( ${+opthash[-n]} + ${+opthash[--name]} ))
|
|
(( ${+opthash[-n]} )) && name="${opthash[-n]}"
|
|
(( ${+opthash[--name]} )) && name="${opthash[--name]}"
|
|
|
|
# ASK (requests command and/or ID)
|
|
(( ask = ${+opthash[-a]} + ${+opthash[--ask]} ))
|
|
if [ "$ask" = "0" ]; then
|
|
local ask_setting
|
|
zstyle -b ":plugin:zconvey" ask ask_setting || ask_setting="no"
|
|
[ "$ask_setting" = "yes" ] && ask=1 || ask=0
|
|
fi
|
|
|
|
# VERBOSE, QUIET, RAW
|
|
(( verbose = ${+opthash[-v]} + ${+opthash[--verbose]} ))
|
|
(( quiet = ${+opthash[-q]} + ${+opthash[--quiet]} ))
|
|
(( raw = ${+opthash[-r]} + ${+opthash[--raw]} ))
|
|
|
|
if [[ "$have_id" != "0" && "$have_name" != "0" ]]; then
|
|
__zconvey_pinfo "Please supply only one of ID (-i) and NAME (-n)"
|
|
return 1
|
|
fi
|
|
|
|
if [[ "$have_id" != "0" && "$id" != <-> ]]; then
|
|
__zconvey_pinfo "ID must be numeric, 1..100"
|
|
return 1
|
|
fi
|
|
|
|
local cmd
|
|
if (( raw )); then
|
|
cmd="${*}"
|
|
else
|
|
local -a args
|
|
args=( "${(q)@}" )
|
|
|
|
cmd="${args[*]}"
|
|
cmd="${cmd//\\;/;}"
|
|
cmd="${cmd//\\|/|}"
|
|
cmd="${cmd//\\&/&}"
|
|
cmd="${cmd##[[:space:]]#}"
|
|
cmd="${cmd%%[[:space:]]#}"
|
|
fi
|
|
|
|
if [[ -z "$cmd" && "$ask" = "0" ]]; then
|
|
__zconvey_usage_zc
|
|
return 1
|
|
fi
|
|
|
|
if [[ "$have_id" = "0" && "$have_name" = "0" && "$ask" = "0" ]]; then
|
|
__zconvey_pinfo "Either supply target ID/NAME or request Zsh-Select (-a/--ask)"
|
|
return 1
|
|
fi
|
|
|
|
# Resolve name
|
|
if (( $have_name )); then
|
|
__zconvey_resolve_name_to_id "$name"
|
|
local resolved="$REPLY"
|
|
if [ -z "$resolved" ]; then
|
|
echo "Could not find session named: \`$name'"
|
|
return 1
|
|
fi
|
|
|
|
# Store the resolved ID and continue normally,
|
|
# with ID as the main specifier of session
|
|
id="$resolved"
|
|
fi
|
|
|
|
# Resupply missing input if requested
|
|
if (( $ask )); then
|
|
# Supply command?
|
|
if [[ -z "$cmd" ]]; then
|
|
vared -cp "Enter command to send: " cmd
|
|
cmd="${cmd##[[:space:]]#}"
|
|
cmd="${cmd%%[[:space:]]#}"
|
|
if [ -z "$cmd" ]; then
|
|
__zconvey_pinfo "No command enterred, exiting"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
# Supply session?
|
|
if [[ "$have_id" = "0" && "$have_name" = "0" ]]; then
|
|
if ! type zsh-select 2>/dev/null 1>&2; then
|
|
__zconvey_pinfo "Zsh-Select not installed, please install it before using -a/--ask, aborting"
|
|
__zconvey_pinfo "Example installation: zinit load psprint/zsh-select"
|
|
return 1
|
|
else
|
|
export ZSHSELECT_START_IN_SEARCH_MODE=0
|
|
id=`zc-ls | zsh-select`
|
|
if [ -z "$id" ]; then
|
|
__zconvey_pinfo "No selection, exiting"
|
|
return 0
|
|
else
|
|
id="${id//(#b)*ID: ([[:digit:]]#)[^[:digit:]]#*(#e)/$match[1]}"
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ -z "$cmd" ]; then
|
|
__zconvey_pinfo "No command provided, aborting"
|
|
return 1
|
|
fi
|
|
|
|
if [[ "$id" != <-> || "$id" = "0" || "$id" -gt "100" ]]; then
|
|
__zconvey_pinfo "Incorrect sesion ID occured: \`$idx'. ID should be in range 1..100"
|
|
return 1
|
|
fi
|
|
|
|
# Obtain current time stamp
|
|
local ts
|
|
if [ "$ZCONVEY_CONFIG[timestamp_from]" = "datetime" ]; then
|
|
[[ "${+modules}" = 1 && "${modules[zsh/datetime]}" != "loaded" && "${modules[zsh/datetime]}" != "autoloaded" ]] && zmodload zsh/datetime
|
|
[ "${+modules}" = 0 ] && zmodload zsh/datetime
|
|
ts="$EPOCHSECONDS"
|
|
fi
|
|
# Also a fallback
|
|
if [[ "$ZCONVEY_CONFIG[timestamp_from]" = "date" || -z "$ts" || "$ts" = "0" ]]; then
|
|
ts="$( date +%s )"
|
|
fi
|
|
|
|
local fd datafile="${ZCONVEY_IO_DIR}/${id}.io"
|
|
local lockfile="${datafile}.lock"
|
|
{ echo "PID $$ ID $ZCONVEY_ID is sending command" >! "$lockfile"; } 2>/dev/null
|
|
|
|
# 1. Zsh lock with timeout (2 seconds)
|
|
if (( ${ZCONVEY_CONFIG[use_zsystem_flock]} > 0 )); then
|
|
(( ${verbose} )) && print "Will use zsystem flock..."
|
|
if ! zsystem flock -t 2 -f fd "$lockfile"; then
|
|
__zconvey_pinfo2 "Communication channel of session $id is busy, could not send"
|
|
return 1
|
|
fi
|
|
# 2. Provided flock binary (two calls)
|
|
else
|
|
(( ${verbose} )) && print "Will use provided flock..."
|
|
exec {fd}>"$lockfile"
|
|
"${ZCONVEY_REPO_DIR}/myflock/flock" -nx "$fd"
|
|
if [ "$?" = "101" ]; then
|
|
(( ${verbose} )) && print "First attempt failed, will retry..."
|
|
LANG=C sleep 1
|
|
"${ZCONVEY_REPO_DIR}/myflock/flock" -nx "$fd"
|
|
if [ "$?" = "101" ]; then
|
|
__zconvey_pinfo2 "Communication channel of session $id is busy, could not send"
|
|
return 1
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# >> - multiple commands can be accumulated
|
|
print -r -- "$ts $cmd" >>! "$datafile"
|
|
|
|
# Release the lock by closing the lock file
|
|
exec {fd}>&-
|
|
|
|
if (( ${quiet} == 0 )); then
|
|
__zconvey_get_name_of_id "$id"
|
|
if [[ -n "$REPLY" ]]; then
|
|
print "Zconvey successfully sent command to \033[1;32msession $id\033[0m (name: \033[1;32m$REPLY\033[0m)"
|
|
else
|
|
print "Zconvey successfully sent command to \033[1;32msession $id\033[0m"
|
|
fi
|
|
local busyfile="$ZCONVEY_OTHER_DIR/${id}.busy"
|
|
[ -e "$busyfile" ] && print "The session is busy \033[1;33m($(<$busyfile))\033[0m (command will time out after ${ZCONVEY_CONFIG[expire_seconds]}s)"
|
|
|
|
integer is_locked
|
|
__zconvey_is_session_active "$id" && is_locked=1 || is_locked=0
|
|
(( is_locked == 0 )) && print "The session is ABSENT, the command will probably time out (after ${ZCONVEY_CONFIG[expire_seconds]}s)"
|
|
fi
|
|
|
|
# vim:ft=zsh
|