forked from Diagonactic/zconvey
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathzc
198 lines (170 loc) · 6.49 KB
/
zc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
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: zplugin 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