@codebend3r/che 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +424 -0
- package/bin/che.py +869 -0
- package/bin/commands.py +872 -0
- package/bin/drives/eject-all-drives.py +203 -0
- package/bin/drives/mount-all-drives.py +140 -0
- package/bin/drives/ping-nas.py +242 -0
- package/bin/files/compress-folders.py +188 -0
- package/bin/files/delete-by-ext.py +108 -0
- package/bin/files/delete-empty-folders.py +136 -0
- package/bin/files/delete-smb-files.py +105 -0
- package/bin/files/files-under-size.py +132 -0
- package/bin/files/find-largest-files.py +102 -0
- package/bin/files/make-alpha-dir.py +63 -0
- package/bin/git/all-actions.py +545 -0
- package/bin/git/checkout-my-branches.py +147 -0
- package/bin/git/clean-stale-branches.py +161 -0
- package/bin/git/prune-worktrees.py +143 -0
- package/bin/git/sync-all-branches.py +368 -0
- package/bin/git/update-local-branches.py +195 -0
- package/bin/install.py +1515 -0
- package/bin/shellgen.py +782 -0
- package/bin/system/btop-launch.py +114 -0
- package/bin/system/update-brew.py +146 -0
- package/bin/tui.py +648 -0
- package/bin/utils.py +836 -0
- package/bin/video/delete-duplicate-videos.py +313 -0
- package/bin/video/detect-green-magenta-videos.py +268 -0
- package/bin/video/find-movie-by-year.py +84 -0
- package/bin/video/find-video-mkv-issues.py +242 -0
- package/bin/video/fix-codecs.py +209 -0
- package/bin/video/largest-tv-shows.py +175 -0
- package/bin/video/remove-metadata.py +126 -0
- package/bin/video/rename-video-file.py +329 -0
- package/bin/video/scan-videos-audio-language.py +110 -0
- package/bin/video/show-codecs.py +111 -0
- package/bin/video/validate-video-files.py +114 -0
- package/bin/video/video-list.py +120 -0
- package/package.json +54 -0
- package/shell/che.bash +382 -0
- package/shell/che.fish +282 -0
- package/shell/che.zsh +389 -0
- package/shell/completions/_che +146 -0
- package/shell/completions/che.bash +107 -0
- package/shell/completions/che.fish +371 -0
package/shell/che.fish
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
# che 1.0.0 - generated file, do not edit.
|
|
2
|
+
#
|
|
3
|
+
# Generated from bin/commands.py by `che install`.
|
|
4
|
+
# To change a wrapper, edit that manifest and run `che install` again.
|
|
5
|
+
|
|
6
|
+
if not set -q CHE_HOME
|
|
7
|
+
set -l __che_dir (dirname (status --current-filename))/..
|
|
8
|
+
if type -q path
|
|
9
|
+
set -gx CHE_HOME (path resolve $__che_dir)
|
|
10
|
+
else
|
|
11
|
+
set -gx CHE_HOME $__che_dir
|
|
12
|
+
end
|
|
13
|
+
set -e __che_dir
|
|
14
|
+
end
|
|
15
|
+
set -gx CHE_BIN "$CHE_HOME/bin"
|
|
16
|
+
if not set -q CHE_PYTHON
|
|
17
|
+
set -gx CHE_PYTHON python3
|
|
18
|
+
end
|
|
19
|
+
set -gx SHELL_FUNCTIONS_BIN "$CHE_BIN"
|
|
20
|
+
|
|
21
|
+
# Play a wrapper's completion sound, then return the status it was given.
|
|
22
|
+
function che_notify --description 'che: completion sound'
|
|
23
|
+
set -l code 0
|
|
24
|
+
if set -q argv[2]
|
|
25
|
+
set code $argv[2]
|
|
26
|
+
end
|
|
27
|
+
if test "$CHE_SOUNDS" != "0"
|
|
28
|
+
if type -q "playsound-$argv[1]"
|
|
29
|
+
"playsound-$argv[1]" >/dev/null 2>&1
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
return $code
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
function che --description 'che: shell helpers dispatcher'
|
|
36
|
+
if test (count $argv) -eq 0
|
|
37
|
+
"$CHE_PYTHON" "$CHE_BIN/che.py"
|
|
38
|
+
else
|
|
39
|
+
"$CHE_PYTHON" "$CHE_BIN/che.py" $argv
|
|
40
|
+
che_notify 7 $status
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# --------------------------------------------------------------------------
|
|
45
|
+
# Git - Branch hygiene, worktrees and GitHub Actions
|
|
46
|
+
# --------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
function all-actions --description 'GitHub Actions status for every open PR you authored'
|
|
49
|
+
"$CHE_PYTHON" "$CHE_BIN/git/all-actions.py" $argv
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
function all-actions-watch --description 'Same as all-actions, refreshed on an interval'
|
|
53
|
+
"$CHE_PYTHON" "$CHE_BIN/git/all-actions.py" --watch $argv
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
function checkout-my-branches --description 'Check out recent remote branches you authored that aren\'t local yet'
|
|
57
|
+
"$CHE_PYTHON" "$CHE_BIN/git/checkout-my-branches.py" $argv
|
|
58
|
+
che_notify 7 $status
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
function clean-stale-branches --description 'Delete local branches whose upstream is gone'
|
|
62
|
+
env DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/git/clean-stale-branches.py" $argv
|
|
63
|
+
che_notify 4 $status
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
function clean-stale-branches-dr --description 'Delete local branches whose upstream is gone (preview only)'
|
|
67
|
+
env DRY_RUN=true "$CHE_PYTHON" "$CHE_BIN/git/clean-stale-branches.py" $argv
|
|
68
|
+
che_notify 7 $status
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
function prune-worktrees --description 'Remove every linked worktree, then prune stale admin records'
|
|
72
|
+
env DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/git/prune-worktrees.py" $argv
|
|
73
|
+
che_notify 4 $status
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
function prune-worktrees-dr --description 'Remove every linked worktree, then prune stale admin records (preview only)'
|
|
77
|
+
env DRY_RUN=true "$CHE_PYTHON" "$CHE_BIN/git/prune-worktrees.py" $argv
|
|
78
|
+
che_notify 7 $status
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
function sync-all-branches --description 'Push every worktree, collapse the pushed ones, then tidy branches'
|
|
82
|
+
env DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/git/sync-all-branches.py" $argv
|
|
83
|
+
che_notify 7 $status
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
function sync-all-branches-dr --description 'Push every worktree, collapse the pushed ones, then tidy branches (preview only)'
|
|
87
|
+
env DRY_RUN=true "$CHE_PYTHON" "$CHE_BIN/git/sync-all-branches.py" $argv
|
|
88
|
+
che_notify 7 $status
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
function update-from-origin --description 'Same as sync-all-branches but never pushes: fetch, collapse, rebase'
|
|
92
|
+
env DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/git/sync-all-branches.py" --no-push $argv
|
|
93
|
+
che_notify 7 $status
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
function update-local-branches --description 'Rebase every local branch that has an upstream onto origin'
|
|
97
|
+
"$CHE_PYTHON" "$CHE_BIN/git/update-local-branches.py" $argv
|
|
98
|
+
che_notify 5 $status
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# --------------------------------------------------------------------------
|
|
102
|
+
# Video - Codecs, renaming, dedupe and metadata
|
|
103
|
+
# --------------------------------------------------------------------------
|
|
104
|
+
|
|
105
|
+
function show-codecs --description 'Report media files outside the Direct Play codec/container set'
|
|
106
|
+
"$CHE_PYTHON" "$CHE_BIN/video/show-codecs.py" $argv
|
|
107
|
+
che_notify 6 $status
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
function fix-codecs --description 'Re-encode media to h265/aac mp4 so it Direct Plays'
|
|
111
|
+
env DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/video/fix-codecs.py" $argv
|
|
112
|
+
che_notify 7 $status
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
function fix-codecs-dr --description 'Re-encode media to h265/aac mp4 so it Direct Plays (preview only)'
|
|
116
|
+
env DRY_RUN=true "$CHE_PYTHON" "$CHE_BIN/video/fix-codecs.py" $argv
|
|
117
|
+
che_notify 7 $status
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
function find-video-mkv-issues --description 'Scan MKV files and estimate Plex direct-play compatibility'
|
|
121
|
+
"$CHE_PYTHON" "$CHE_BIN/video/find-video-mkv-issues.py" $argv
|
|
122
|
+
che_notify 4 $status
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
function validate-video-files --description 'Check .mp4/.mkv files decode by playing one frame with mpv'
|
|
126
|
+
"$CHE_PYTHON" "$CHE_BIN/video/validate-video-files.py" $argv
|
|
127
|
+
che_notify 2 $status
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
function scan-videos-audio-language --description 'Print the audio language tags of every video under a path'
|
|
131
|
+
"$CHE_PYTHON" "$CHE_BIN/video/scan-videos-audio-language.py" $argv
|
|
132
|
+
che_notify 3 $status
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
function remove-metadata --description 'Strip all metadata from video files recursively'
|
|
136
|
+
"$CHE_PYTHON" "$CHE_BIN/video/remove-metadata.py" $argv
|
|
137
|
+
che_notify 4 $status
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
function rename-video-file --description 'Title-case video filenames (and optionally their folders)'
|
|
141
|
+
"$CHE_PYTHON" "$CHE_BIN/video/rename-video-file.py" $argv
|
|
142
|
+
che_notify 5 $status
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
function delete-duplicate-videos --description 'Delete duplicate MKV/MP4 files under a root directory'
|
|
146
|
+
env DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/video/delete-duplicate-videos.py" $argv
|
|
147
|
+
che_notify 6 $status
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
function delete-duplicate-videos-dr --description 'Delete duplicate MKV/MP4 files under a root directory (preview only)'
|
|
151
|
+
env DRY_RUN=true "$CHE_PYTHON" "$CHE_BIN/video/delete-duplicate-videos.py" $argv
|
|
152
|
+
che_notify 6 $status
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
function video-list --description 'List .mp4/.mkv files under a path with human-readable sizes'
|
|
156
|
+
"$CHE_PYTHON" "$CHE_BIN/video/video-list.py" $argv
|
|
157
|
+
che_notify 5 $status
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
function detect-green-magenta-videos --description 'Detect videos with the green/magenta chroma artifact'
|
|
161
|
+
"$CHE_PYTHON" "$CHE_BIN/video/detect-green-magenta-videos.py" $argv
|
|
162
|
+
che_notify 3 $status
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
function find-movie-by-year --description 'Find movie folders whose name ends with "(YYYY)"'
|
|
166
|
+
"$CHE_PYTHON" "$CHE_BIN/video/find-movie-by-year.py" $argv
|
|
167
|
+
che_notify 2 $status
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
function largest-tv-shows --description 'Rank TV show folders in a library by total size on disk'
|
|
171
|
+
"$CHE_PYTHON" "$CHE_BIN/video/largest-tv-shows.py" $argv
|
|
172
|
+
che_notify 2 $status
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# --------------------------------------------------------------------------
|
|
176
|
+
# Files - Delete, compress and inspect by size or extension
|
|
177
|
+
# --------------------------------------------------------------------------
|
|
178
|
+
|
|
179
|
+
function delete-by-ext --description 'Delete files under a path matching a set of extensions'
|
|
180
|
+
env DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/files/delete-by-ext.py" $argv
|
|
181
|
+
che_notify 6 $status
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
function delete-by-ext-dr --description 'Delete files under a path matching a set of extensions (preview only)'
|
|
185
|
+
env DRY_RUN=true "$CHE_PYTHON" "$CHE_BIN/files/delete-by-ext.py" $argv
|
|
186
|
+
che_notify 7 $status
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
function delete-empty-folders --description 'Delete truly-empty directories under a path, cascading upwards'
|
|
190
|
+
env DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/files/delete-empty-folders.py" $argv
|
|
191
|
+
che_notify 6 $status
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
function delete-empty-folders-dr --description 'Delete truly-empty directories under a path, cascading upwards (preview only)'
|
|
195
|
+
env DRY_RUN=true "$CHE_PYTHON" "$CHE_BIN/files/delete-empty-folders.py" $argv
|
|
196
|
+
che_notify 7 $status
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
function delete-smb-files --description 'Delete .smbdelete* files left behind by an SMB share'
|
|
200
|
+
env DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/files/delete-smb-files.py" $argv
|
|
201
|
+
che_notify 6 $status
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
function delete-smb-files-dr --description 'Delete .smbdelete* files left behind by an SMB share (preview only)'
|
|
205
|
+
env DRY_RUN=true "$CHE_PYTHON" "$CHE_BIN/files/delete-smb-files.py" $argv
|
|
206
|
+
che_notify 7 $status
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
function files-under-size --description 'Find video files at or under a size threshold'
|
|
210
|
+
env DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/files/files-under-size.py" $argv
|
|
211
|
+
che_notify 4 $status
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
function files-under-size-dr --description 'Find video files at or under a size threshold (preview only)'
|
|
215
|
+
env DRY_RUN=true "$CHE_PYTHON" "$CHE_BIN/files/files-under-size.py" $argv
|
|
216
|
+
che_notify 7 $status
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
function find-largest-files --description 'List the largest files under a path, biggest first'
|
|
220
|
+
"$CHE_PYTHON" "$CHE_BIN/files/find-largest-files.py" $argv
|
|
221
|
+
che_notify 2 $status
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
function make-alpha-dir --description 'Create \'#\' and A-Z bucket folders under a parent directory'
|
|
225
|
+
"$CHE_PYTHON" "$CHE_BIN/files/make-alpha-dir.py" $argv
|
|
226
|
+
che_notify 4 $status
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
function compress-folders --description 'Zip every immediate subfolder of a path at max compression'
|
|
230
|
+
"$CHE_PYTHON" "$CHE_BIN/files/compress-folders.py" $argv
|
|
231
|
+
che_notify 7 $status
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
function list-permission --description 'Show ownership and mode of a volume under /Volumes'
|
|
235
|
+
command ls -ld "/Volumes/$argv[1]"
|
|
236
|
+
che_notify 7 $status
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# --------------------------------------------------------------------------
|
|
240
|
+
# Drives - Mount, eject and keep-alive for the NAS volumes
|
|
241
|
+
# --------------------------------------------------------------------------
|
|
242
|
+
|
|
243
|
+
function mount-all-drives --description 'Mount all NAS drives over SMB via AppleScript'
|
|
244
|
+
"$CHE_PYTHON" "$CHE_BIN/drives/mount-all-drives.py" $argv
|
|
245
|
+
che_notify 7 $status
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
function eject-all-drives --description 'Eject all NAS volumes from /Volumes'
|
|
249
|
+
"$CHE_PYTHON" "$CHE_BIN/drives/eject-all-drives.py" $argv
|
|
250
|
+
che_notify 7 $status
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
function eject-all-drives-dr --description 'Eject all NAS volumes from /Volumes (preview only)'
|
|
254
|
+
"$CHE_PYTHON" "$CHE_BIN/drives/eject-all-drives.py" --dry-run $argv
|
|
255
|
+
che_notify 7 $status
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
function ping-nas --description 'Keep-alive pinger that remounts a NAS drive that dropped off'
|
|
259
|
+
"$CHE_PYTHON" "$CHE_BIN/drives/ping-nas.py" $argv
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# --------------------------------------------------------------------------
|
|
263
|
+
# System - Homebrew, monitoring and the machine itself
|
|
264
|
+
# --------------------------------------------------------------------------
|
|
265
|
+
|
|
266
|
+
function update-brew --description 'Update Homebrew, upgrade formulae and casks, then clean up'
|
|
267
|
+
"$CHE_PYTHON" "$CHE_BIN/system/update-brew.py" $argv
|
|
268
|
+
che_notify 7 $status
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
function update-brew-dr --description 'Update Homebrew, upgrade formulae and casks, then clean up (preview only)'
|
|
272
|
+
"$CHE_PYTHON" "$CHE_BIN/system/update-brew.py" --dry-run $argv
|
|
273
|
+
che_notify 7 $status
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
function btop --description 'Launch btop with a gruvbox theme matching the macOS appearance'
|
|
277
|
+
"$CHE_PYTHON" "$CHE_BIN/system/btop-launch.py" $argv
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
if test -r "$CHE_HOME/shell/completions/che.fish"
|
|
281
|
+
source "$CHE_HOME/shell/completions/che.fish"
|
|
282
|
+
end
|
package/shell/che.zsh
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
# che 1.0.0 - generated file, do not edit.
|
|
2
|
+
#
|
|
3
|
+
# Generated from bin/commands.py by `che install`.
|
|
4
|
+
# To change a wrapper, edit that manifest and run `che install` again.
|
|
5
|
+
#
|
|
6
|
+
# Source this file (or let the `che install` block in your rc file do it):
|
|
7
|
+
#
|
|
8
|
+
# . ~/Developer/git/che/shell/che.zsh
|
|
9
|
+
#
|
|
10
|
+
# Every wrapper is a shell function, so `type <name>` shows what it runs and
|
|
11
|
+
# `che doctor` can tell you when something it needs is missing.
|
|
12
|
+
|
|
13
|
+
# CHE_HOME is normally exported by the installed rc block. Fall back to this
|
|
14
|
+
# file's own location so a bare `source` of it also works.
|
|
15
|
+
if [ -z "${CHE_HOME:-}" ]; then
|
|
16
|
+
CHE_HOME="${${(%):-%x}:A:h:h}"
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
# Exported, not just set: every wrapper expands "$CHE_BIN", and a shell that
|
|
20
|
+
# replays the *functions* without re-reading this file - a `typeset -f` dump, an
|
|
21
|
+
# environment snapshot, any tool that rebuilds a shell from its exported
|
|
22
|
+
# environment - keeps the functions and drops a plain variable, leaving the
|
|
23
|
+
# wrappers to run "/che.py". CHE_HOME comes in exported by the rc block; this
|
|
24
|
+
# keeps everything derived from it exported too.
|
|
25
|
+
export CHE_BIN="${CHE_HOME}/bin"
|
|
26
|
+
|
|
27
|
+
# Any python3 on PATH by default. `che install` records the interpreter it
|
|
28
|
+
# verified (3.12+) in the rc block, which wins over this.
|
|
29
|
+
: "${CHE_PYTHON:=python3}"
|
|
30
|
+
export CHE_PYTHON
|
|
31
|
+
|
|
32
|
+
# Legacy name from the hand-maintained wrappers, kept so an older snippet in
|
|
33
|
+
# ~/.zshrc that still refers to it keeps resolving.
|
|
34
|
+
export SHELL_FUNCTIONS_BIN="${CHE_BIN}"
|
|
35
|
+
|
|
36
|
+
# Play the completion sound for a wrapper, then return the status it was given.
|
|
37
|
+
#
|
|
38
|
+
# playsound-N is defined outside this repo. Every wrapper used to call it
|
|
39
|
+
# unconditionally, which printed "command not found" on a machine that never
|
|
40
|
+
# had it; here a missing playsound is simply skipped. Set CHE_SOUNDS=0 to
|
|
41
|
+
# silence them all.
|
|
42
|
+
che_notify() {
|
|
43
|
+
if [ "${CHE_SOUNDS:-1}" = "1" ] && command -v "playsound-$1" >/dev/null 2>&1; then
|
|
44
|
+
"playsound-$1" >/dev/null 2>&1
|
|
45
|
+
fi
|
|
46
|
+
return "${2:-0}"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# The dispatcher. `che` with no arguments opens the interactive menu.
|
|
50
|
+
che() {
|
|
51
|
+
if [ "$#" -eq 0 ]; then
|
|
52
|
+
"$CHE_PYTHON" "$CHE_BIN/che.py"
|
|
53
|
+
else
|
|
54
|
+
"$CHE_PYTHON" "$CHE_BIN/che.py" "$@"
|
|
55
|
+
che_notify 7 $?
|
|
56
|
+
fi
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# An alias sharing a name with a wrapper below is fatal, not cosmetic: zsh
|
|
60
|
+
# expands aliases while *parsing*, so `remove-metadata() {` becomes
|
|
61
|
+
# `find ./ -type f …() {` and the parse error aborts the rest of this file -
|
|
62
|
+
# taking every wrapper after it with it.
|
|
63
|
+
#
|
|
64
|
+
# So stash any colliding alias, define the functions, then put it back.
|
|
65
|
+
# Clearing it outright would silently replace a command the user aliased on
|
|
66
|
+
# purpose; restoring it keeps their alias winning at the prompt, exactly as it
|
|
67
|
+
# did before che was installed. `che doctor` reports the collision, and
|
|
68
|
+
# `\name` (backslash) reaches the wrapper without expanding the alias.
|
|
69
|
+
typeset -ga _che_stashed_aliases=()
|
|
70
|
+
|
|
71
|
+
_che_stash_aliases() {
|
|
72
|
+
local name
|
|
73
|
+
for name in "$@"; do
|
|
74
|
+
if [[ -n ${aliases[$name]-} ]]; then
|
|
75
|
+
_che_stashed_aliases+=("${name}=${aliases[$name]}")
|
|
76
|
+
unalias -- "$name"
|
|
77
|
+
fi
|
|
78
|
+
done
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
_che_restore_aliases() {
|
|
82
|
+
local entry
|
|
83
|
+
for entry in "${_che_stashed_aliases[@]}"; do
|
|
84
|
+
alias -- "$entry"
|
|
85
|
+
done
|
|
86
|
+
_che_stashed_aliases=()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
_che_stash_aliases che all-actions all-actions-watch checkout-my-branches \
|
|
90
|
+
clean-stale-branches clean-stale-branches-dr prune-worktrees \
|
|
91
|
+
prune-worktrees-dr sync-all-branches sync-all-branches-dr \
|
|
92
|
+
update-from-origin update-local-branches show-codecs fix-codecs \
|
|
93
|
+
fix-codecs-dr find-video-mkv-issues validate-video-files \
|
|
94
|
+
scan-videos-audio-language remove-metadata rename-video-file \
|
|
95
|
+
delete-duplicate-videos delete-duplicate-videos-dr video-list \
|
|
96
|
+
detect-green-magenta-videos find-movie-by-year largest-tv-shows \
|
|
97
|
+
delete-by-ext delete-by-ext-dr delete-empty-folders \
|
|
98
|
+
delete-empty-folders-dr delete-smb-files delete-smb-files-dr \
|
|
99
|
+
files-under-size files-under-size-dr find-largest-files make-alpha-dir \
|
|
100
|
+
compress-folders list-permission mount-all-drives eject-all-drives \
|
|
101
|
+
eject-all-drives-dr ping-nas update-brew update-brew-dr btop
|
|
102
|
+
|
|
103
|
+
# --------------------------------------------------------------------------
|
|
104
|
+
# Git - Branch hygiene, worktrees and GitHub Actions
|
|
105
|
+
# --------------------------------------------------------------------------
|
|
106
|
+
|
|
107
|
+
# GitHub Actions status for every open PR you authored
|
|
108
|
+
all-actions() {
|
|
109
|
+
"$CHE_PYTHON" "$CHE_BIN/git/all-actions.py" "$@"
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
# Same as all-actions, refreshed on an interval
|
|
113
|
+
all-actions-watch() {
|
|
114
|
+
"$CHE_PYTHON" "$CHE_BIN/git/all-actions.py" --watch "$@"
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
# Check out recent remote branches you authored that aren't local yet
|
|
118
|
+
checkout-my-branches() {
|
|
119
|
+
"$CHE_PYTHON" "$CHE_BIN/git/checkout-my-branches.py" "$@"
|
|
120
|
+
che_notify 7 $?
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
# Delete local branches whose upstream is gone
|
|
124
|
+
clean-stale-branches() {
|
|
125
|
+
DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/git/clean-stale-branches.py" "$@"
|
|
126
|
+
che_notify 4 $?
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
# Delete local branches whose upstream is gone (preview only)
|
|
130
|
+
clean-stale-branches-dr() {
|
|
131
|
+
DRY_RUN=true "$CHE_PYTHON" "$CHE_BIN/git/clean-stale-branches.py" "$@"
|
|
132
|
+
che_notify 7 $?
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
# Remove every linked worktree, then prune stale admin records
|
|
136
|
+
prune-worktrees() {
|
|
137
|
+
DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/git/prune-worktrees.py" "$@"
|
|
138
|
+
che_notify 4 $?
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
# Remove every linked worktree, then prune stale admin records (preview only)
|
|
142
|
+
prune-worktrees-dr() {
|
|
143
|
+
DRY_RUN=true "$CHE_PYTHON" "$CHE_BIN/git/prune-worktrees.py" "$@"
|
|
144
|
+
che_notify 7 $?
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
# Push every worktree, collapse the pushed ones, then tidy branches
|
|
148
|
+
sync-all-branches() {
|
|
149
|
+
DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/git/sync-all-branches.py" "$@"
|
|
150
|
+
che_notify 7 $?
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
# Push every worktree, collapse the pushed ones, then tidy branches (preview only)
|
|
154
|
+
sync-all-branches-dr() {
|
|
155
|
+
DRY_RUN=true "$CHE_PYTHON" "$CHE_BIN/git/sync-all-branches.py" "$@"
|
|
156
|
+
che_notify 7 $?
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
# Same as sync-all-branches but never pushes: fetch, collapse, rebase
|
|
160
|
+
update-from-origin() {
|
|
161
|
+
DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/git/sync-all-branches.py" --no-push "$@"
|
|
162
|
+
che_notify 7 $?
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
# Rebase every local branch that has an upstream onto origin
|
|
166
|
+
update-local-branches() {
|
|
167
|
+
"$CHE_PYTHON" "$CHE_BIN/git/update-local-branches.py" "$@"
|
|
168
|
+
che_notify 5 $?
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
# --------------------------------------------------------------------------
|
|
172
|
+
# Video - Codecs, renaming, dedupe and metadata
|
|
173
|
+
# --------------------------------------------------------------------------
|
|
174
|
+
|
|
175
|
+
# Report media files outside the Direct Play codec/container set
|
|
176
|
+
show-codecs() {
|
|
177
|
+
"$CHE_PYTHON" "$CHE_BIN/video/show-codecs.py" "$@"
|
|
178
|
+
che_notify 6 $?
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
# Re-encode media to h265/aac mp4 so it Direct Plays
|
|
182
|
+
fix-codecs() {
|
|
183
|
+
DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/video/fix-codecs.py" "$@"
|
|
184
|
+
che_notify 7 $?
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
# Re-encode media to h265/aac mp4 so it Direct Plays (preview only)
|
|
188
|
+
fix-codecs-dr() {
|
|
189
|
+
DRY_RUN=true "$CHE_PYTHON" "$CHE_BIN/video/fix-codecs.py" "$@"
|
|
190
|
+
che_notify 7 $?
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
# Scan MKV files and estimate Plex direct-play compatibility
|
|
194
|
+
find-video-mkv-issues() {
|
|
195
|
+
"$CHE_PYTHON" "$CHE_BIN/video/find-video-mkv-issues.py" "$@"
|
|
196
|
+
che_notify 4 $?
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
# Check .mp4/.mkv files decode by playing one frame with mpv
|
|
200
|
+
validate-video-files() {
|
|
201
|
+
"$CHE_PYTHON" "$CHE_BIN/video/validate-video-files.py" "$@"
|
|
202
|
+
che_notify 2 $?
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
# Print the audio language tags of every video under a path
|
|
206
|
+
scan-videos-audio-language() {
|
|
207
|
+
"$CHE_PYTHON" "$CHE_BIN/video/scan-videos-audio-language.py" "$@"
|
|
208
|
+
che_notify 3 $?
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
# Strip all metadata from video files recursively
|
|
212
|
+
remove-metadata() {
|
|
213
|
+
"$CHE_PYTHON" "$CHE_BIN/video/remove-metadata.py" "$@"
|
|
214
|
+
che_notify 4 $?
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
# Title-case video filenames (and optionally their folders)
|
|
218
|
+
rename-video-file() {
|
|
219
|
+
"$CHE_PYTHON" "$CHE_BIN/video/rename-video-file.py" "$@"
|
|
220
|
+
che_notify 5 $?
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
# Delete duplicate MKV/MP4 files under a root directory
|
|
224
|
+
delete-duplicate-videos() {
|
|
225
|
+
DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/video/delete-duplicate-videos.py" "$@"
|
|
226
|
+
che_notify 6 $?
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
# Delete duplicate MKV/MP4 files under a root directory (preview only)
|
|
230
|
+
delete-duplicate-videos-dr() {
|
|
231
|
+
DRY_RUN=true "$CHE_PYTHON" "$CHE_BIN/video/delete-duplicate-videos.py" "$@"
|
|
232
|
+
che_notify 6 $?
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
# List .mp4/.mkv files under a path with human-readable sizes
|
|
236
|
+
video-list() {
|
|
237
|
+
"$CHE_PYTHON" "$CHE_BIN/video/video-list.py" "$@"
|
|
238
|
+
che_notify 5 $?
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
# Detect videos with the green/magenta chroma artifact
|
|
242
|
+
detect-green-magenta-videos() {
|
|
243
|
+
"$CHE_PYTHON" "$CHE_BIN/video/detect-green-magenta-videos.py" "$@"
|
|
244
|
+
che_notify 3 $?
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
# Find movie folders whose name ends with "(YYYY)"
|
|
248
|
+
find-movie-by-year() {
|
|
249
|
+
"$CHE_PYTHON" "$CHE_BIN/video/find-movie-by-year.py" "$@"
|
|
250
|
+
che_notify 2 $?
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
# Rank TV show folders in a library by total size on disk
|
|
254
|
+
largest-tv-shows() {
|
|
255
|
+
"$CHE_PYTHON" "$CHE_BIN/video/largest-tv-shows.py" "$@"
|
|
256
|
+
che_notify 2 $?
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
# --------------------------------------------------------------------------
|
|
260
|
+
# Files - Delete, compress and inspect by size or extension
|
|
261
|
+
# --------------------------------------------------------------------------
|
|
262
|
+
|
|
263
|
+
# Delete files under a path matching a set of extensions
|
|
264
|
+
delete-by-ext() {
|
|
265
|
+
DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/files/delete-by-ext.py" "$@"
|
|
266
|
+
che_notify 6 $?
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
# Delete files under a path matching a set of extensions (preview only)
|
|
270
|
+
delete-by-ext-dr() {
|
|
271
|
+
DRY_RUN=true "$CHE_PYTHON" "$CHE_BIN/files/delete-by-ext.py" "$@"
|
|
272
|
+
che_notify 7 $?
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
# Delete truly-empty directories under a path, cascading upwards
|
|
276
|
+
delete-empty-folders() {
|
|
277
|
+
DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/files/delete-empty-folders.py" "$@"
|
|
278
|
+
che_notify 6 $?
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
# Delete truly-empty directories under a path, cascading upwards (preview only)
|
|
282
|
+
delete-empty-folders-dr() {
|
|
283
|
+
DRY_RUN=true "$CHE_PYTHON" "$CHE_BIN/files/delete-empty-folders.py" "$@"
|
|
284
|
+
che_notify 7 $?
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
# Delete .smbdelete* files left behind by an SMB share
|
|
288
|
+
delete-smb-files() {
|
|
289
|
+
DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/files/delete-smb-files.py" "$@"
|
|
290
|
+
che_notify 6 $?
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
# Delete .smbdelete* files left behind by an SMB share (preview only)
|
|
294
|
+
delete-smb-files-dr() {
|
|
295
|
+
DRY_RUN=true "$CHE_PYTHON" "$CHE_BIN/files/delete-smb-files.py" "$@"
|
|
296
|
+
che_notify 7 $?
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
# Find video files at or under a size threshold
|
|
300
|
+
files-under-size() {
|
|
301
|
+
DRY_RUN=false "$CHE_PYTHON" "$CHE_BIN/files/files-under-size.py" "$@"
|
|
302
|
+
che_notify 4 $?
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
# Find video files at or under a size threshold (preview only)
|
|
306
|
+
files-under-size-dr() {
|
|
307
|
+
DRY_RUN=true "$CHE_PYTHON" "$CHE_BIN/files/files-under-size.py" "$@"
|
|
308
|
+
che_notify 7 $?
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
# List the largest files under a path, biggest first
|
|
312
|
+
find-largest-files() {
|
|
313
|
+
"$CHE_PYTHON" "$CHE_BIN/files/find-largest-files.py" "$@"
|
|
314
|
+
che_notify 2 $?
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
# Create '#' and A-Z bucket folders under a parent directory
|
|
318
|
+
make-alpha-dir() {
|
|
319
|
+
"$CHE_PYTHON" "$CHE_BIN/files/make-alpha-dir.py" "$@"
|
|
320
|
+
che_notify 4 $?
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
# Zip every immediate subfolder of a path at max compression
|
|
324
|
+
compress-folders() {
|
|
325
|
+
"$CHE_PYTHON" "$CHE_BIN/files/compress-folders.py" "$@"
|
|
326
|
+
che_notify 7 $?
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
# Show ownership and mode of a volume under /Volumes
|
|
330
|
+
list-permission() {
|
|
331
|
+
command ls -ld "/Volumes/$1"
|
|
332
|
+
che_notify 7 $?
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
# --------------------------------------------------------------------------
|
|
336
|
+
# Drives - Mount, eject and keep-alive for the NAS volumes
|
|
337
|
+
# --------------------------------------------------------------------------
|
|
338
|
+
|
|
339
|
+
# Mount all NAS drives over SMB via AppleScript
|
|
340
|
+
mount-all-drives() {
|
|
341
|
+
"$CHE_PYTHON" "$CHE_BIN/drives/mount-all-drives.py" "$@"
|
|
342
|
+
che_notify 7 $?
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
# Eject all NAS volumes from /Volumes
|
|
346
|
+
eject-all-drives() {
|
|
347
|
+
"$CHE_PYTHON" "$CHE_BIN/drives/eject-all-drives.py" "$@"
|
|
348
|
+
che_notify 7 $?
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
# Eject all NAS volumes from /Volumes (preview only)
|
|
352
|
+
eject-all-drives-dr() {
|
|
353
|
+
"$CHE_PYTHON" "$CHE_BIN/drives/eject-all-drives.py" --dry-run "$@"
|
|
354
|
+
che_notify 7 $?
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
# Keep-alive pinger that remounts a NAS drive that dropped off
|
|
358
|
+
ping-nas() {
|
|
359
|
+
"$CHE_PYTHON" "$CHE_BIN/drives/ping-nas.py" "$@"
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
# --------------------------------------------------------------------------
|
|
363
|
+
# System - Homebrew, monitoring and the machine itself
|
|
364
|
+
# --------------------------------------------------------------------------
|
|
365
|
+
|
|
366
|
+
# Update Homebrew, upgrade formulae and casks, then clean up
|
|
367
|
+
update-brew() {
|
|
368
|
+
"$CHE_PYTHON" "$CHE_BIN/system/update-brew.py" "$@"
|
|
369
|
+
che_notify 7 $?
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
# Update Homebrew, upgrade formulae and casks, then clean up (preview only)
|
|
373
|
+
update-brew-dr() {
|
|
374
|
+
"$CHE_PYTHON" "$CHE_BIN/system/update-brew.py" --dry-run "$@"
|
|
375
|
+
che_notify 7 $?
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
# Launch btop with a gruvbox theme matching the macOS appearance
|
|
379
|
+
btop() {
|
|
380
|
+
"$CHE_PYTHON" "$CHE_BIN/system/btop-launch.py" "$@"
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
_che_restore_aliases
|
|
384
|
+
|
|
385
|
+
# Completions. compdef only exists once compinit has run; when it has not,
|
|
386
|
+
# skip quietly rather than erroring at shell start.
|
|
387
|
+
if whence -w compdef >/dev/null 2>&1 && [ -r "${CHE_HOME}/shell/completions/_che" ]; then
|
|
388
|
+
. "${CHE_HOME}/shell/completions/_che"
|
|
389
|
+
fi
|