59e2356f5c
Daily ff subcommands never updated the repo; only `ff update` did. Add a pouch-style interval auto-update at the ff entry (default 24h), skip dirty/fail/timeout without aborting the current command, and cover the skip/pull cases with a fish regression.
373 lines
11 KiB
Fish
373 lines
11 KiB
Fish
# Fast commands management
|
|
|
|
function _ff_config_file
|
|
echo ~/.config/ff/config
|
|
end
|
|
|
|
function _ff_state_file
|
|
echo ~/.local/share/ff/state
|
|
end
|
|
|
|
function _ff_config_value --argument-names key default
|
|
set -l file (_ff_config_file)
|
|
if not test -f $file
|
|
echo $default
|
|
return
|
|
end
|
|
set -l found
|
|
for line in (cat $file)
|
|
set line (string trim -- $line)
|
|
if test -z "$line"; or string match -q '#*' -- $line
|
|
continue
|
|
end
|
|
if string match -q -- "$key=*" $line
|
|
set found (string split -m 1 -- '=' $line)[2]
|
|
end
|
|
end
|
|
if test -n "$found"
|
|
echo (string trim -- $found)
|
|
else
|
|
echo $default
|
|
end
|
|
end
|
|
|
|
function _ff_parse_interval --argument-names raw
|
|
set -l text (string trim -- (string lower -- $raw))
|
|
if test -z "$text"
|
|
echo 86400
|
|
return
|
|
end
|
|
if string match -qr '^[0-9]+$' -- $text
|
|
echo $text
|
|
return
|
|
end
|
|
set -l unit (string sub -s -1 $text)
|
|
set -l amount (string sub -e -1 $text)
|
|
if not string match -qr '^[0-9]+$' -- $amount
|
|
echo 86400
|
|
return
|
|
end
|
|
switch $unit
|
|
case s
|
|
echo $amount
|
|
case m
|
|
math $amount '*' 60
|
|
case h
|
|
math $amount '*' 3600
|
|
case d
|
|
math $amount '*' 86400
|
|
case '*'
|
|
echo 86400
|
|
end
|
|
end
|
|
|
|
function _ff_env_no_auto_update
|
|
if not set -q FF_NO_AUTO_UPDATE
|
|
return 1
|
|
end
|
|
switch (string lower -- (string trim -- $FF_NO_AUTO_UPDATE))
|
|
case 1 true yes on
|
|
return 0
|
|
case '*'
|
|
return 1
|
|
end
|
|
end
|
|
|
|
function _ff_auto_update_enabled
|
|
switch (string lower -- (_ff_config_value enabled true))
|
|
case 0 false no off
|
|
return 1
|
|
case '*'
|
|
return 0
|
|
end
|
|
end
|
|
|
|
function _ff_record_auto_update
|
|
set -l file (_ff_state_file)
|
|
mkdir -p (dirname $file)
|
|
or return
|
|
echo "last_auto_update="(date +%s) >$file
|
|
end
|
|
|
|
function _ff_last_auto_update
|
|
set -l file (_ff_state_file)
|
|
if not test -f $file
|
|
echo 0
|
|
return
|
|
end
|
|
set -l val 0
|
|
for line in (cat $file)
|
|
if string match -q 'last_auto_update=*' -- $line
|
|
set val (string split -m 1 -- '=' $line)[2]
|
|
end
|
|
end
|
|
if string match -qr '^[0-9]+$' -- (string trim -- $val)
|
|
echo (string trim -- $val)
|
|
else
|
|
echo 0
|
|
end
|
|
end
|
|
|
|
function _ff_interval_elapsed --argument-names interval
|
|
if test "$interval" -le 0
|
|
return 0
|
|
end
|
|
set -l last (_ff_last_auto_update)
|
|
if test "$last" -eq 0
|
|
return 0
|
|
end
|
|
set -l now (date +%s)
|
|
test (math $now - $last) -ge $interval
|
|
end
|
|
|
|
function _ff_reload
|
|
for __f in ~/.dotfile/fish/functions/*.fish
|
|
if test -f $__f
|
|
functions -e (basename $__f .fish) 2>/dev/null
|
|
end
|
|
end
|
|
source ~/.config/fish/config.fish
|
|
# fish 对已加载过的 autoload 函数不会在 functions -e 后重新加载,
|
|
# 必须显式 source 一遍,否则函数(含 ff 自身)会丢失
|
|
for __f in ~/.dotfile/fish/functions/*.fish
|
|
if test -f $__f
|
|
source $__f
|
|
end
|
|
end
|
|
set -e __f
|
|
end
|
|
|
|
# 自动 git pull ~/.dotfile。失败/跳过不得打断当前 ff 子命令。
|
|
# 返回: 0 有更新, 1 失败或脏树, 2 静默跳过, 3 已是最新
|
|
function _ff_auto_update_try_pull
|
|
set -l dir ~/.dotfile
|
|
if not test -d $dir
|
|
return 2
|
|
end
|
|
if not git -C $dir rev-parse --is-inside-work-tree >/dev/null 2>&1
|
|
return 2
|
|
end
|
|
set -l porcelain (git -C $dir status --porcelain 2>/dev/null)
|
|
if test -n "$porcelain"
|
|
echo "[ff] 自动更新已跳过: 工作区不干净" >&2
|
|
return 1
|
|
end
|
|
|
|
set -l before (git -C $dir rev-parse HEAD 2>/dev/null)
|
|
set -lx GIT_TERMINAL_PROMPT 0
|
|
set -l st 0
|
|
if command -q timeout
|
|
command timeout 20 git -C $dir pull --ff-only origin main >/dev/null 2>&1
|
|
set st $status
|
|
else
|
|
git -C $dir pull --ff-only origin main >/dev/null 2>&1
|
|
set st $status
|
|
end
|
|
if test $st -eq 124
|
|
echo "[ff] 自动更新失败,已跳过: git 超时" >&2
|
|
return 1
|
|
end
|
|
if test $st -ne 0
|
|
echo "[ff] 自动更新失败,已跳过" >&2
|
|
return 1
|
|
end
|
|
set -l after (git -C $dir rev-parse HEAD 2>/dev/null)
|
|
if test -n "$before" -a -n "$after" -a "$before" != "$after"
|
|
echo "[ff] 已自动更新 dotfile" >&2
|
|
return 0
|
|
end
|
|
return 3
|
|
end
|
|
|
|
function _ff_maybe_auto_update --argument-names command no_auto_flag
|
|
if test "$no_auto_flag" = 1
|
|
return
|
|
end
|
|
if _ff_env_no_auto_update
|
|
return
|
|
end
|
|
# 显式 ff update 自己拉,这里不要再拉一遍
|
|
if test "$command" = update
|
|
return
|
|
end
|
|
if not _ff_auto_update_enabled
|
|
return
|
|
end
|
|
set -l interval (_ff_parse_interval (_ff_config_value interval 24h))
|
|
if not _ff_interval_elapsed $interval
|
|
return
|
|
end
|
|
|
|
_ff_auto_update_try_pull
|
|
set -l st $status
|
|
if test $st -eq 2
|
|
return
|
|
end
|
|
_ff_record_auto_update
|
|
if test $st -eq 0
|
|
_ff_reload
|
|
end
|
|
end
|
|
|
|
function ff
|
|
# 定义命令和描述(格式:命令|描述)
|
|
set -l commands \
|
|
"reload|Reload fish configuration" \
|
|
"edit|Edit custom fish configuration" \
|
|
"fish|Change to fish config directory" \
|
|
"dotfile|Change to dotfile directory" \
|
|
"pon|Enable proxy (proxy on)" \
|
|
"poff|Disable proxy (proxy off)" \
|
|
"pst|Show proxy status" \
|
|
"make|Run dotfile Makefile commands" \
|
|
"script|Run script from script directory" \
|
|
"s|Alias for script" \
|
|
"update|Update dotfile now (git pull + reload); also auto every 24h" \
|
|
"region|Toggle or set CN_REGION (mirror/proxy region)" \
|
|
"ssh|SSH init, copy key + add host config, or copy config to remote" \
|
|
"dirsize|Show directory sizes (du wrapper)" \
|
|
"pouch|Clone and install pouch to ~/.pouch" \
|
|
"help|Show this help message"
|
|
|
|
set -l no_auto 0
|
|
set -l args
|
|
set -l past_command 0
|
|
for a in $argv
|
|
if test $past_command -eq 0; and test "$a" = "--no-auto-update"
|
|
set no_auto 1
|
|
continue
|
|
end
|
|
set past_command 1
|
|
set -a args $a
|
|
end
|
|
set argv $args
|
|
|
|
_ff_maybe_auto_update "$argv[1]" $no_auto
|
|
|
|
# 确保 execute-script 可用(在 fish 自动加载前手动引入一次)
|
|
if not functions -q execute-script
|
|
set -l execute_script_path ~/.dotfile/fish/functions/execute-script.fish
|
|
if test -f $execute_script_path
|
|
source $execute_script_path
|
|
end
|
|
end
|
|
|
|
switch $argv[1]
|
|
case reload
|
|
# autoload 会缓存函数定义,先清掉 dotfile 里的函数再重载
|
|
_ff_reload
|
|
echo "Fish configuration reloaded!"
|
|
case edit
|
|
vim ~/.config/fish/custom.fish
|
|
case fish
|
|
cd ~/.config/fish/
|
|
case dotfile
|
|
cd ~/.dotfile
|
|
case pon
|
|
set -gx https_proxy http://127.0.0.1:7890
|
|
set -gx http_proxy http://127.0.0.1:7890
|
|
set -gx all_proxy socks5://127.0.0.1:7890
|
|
echo "✓ Proxy enabled"
|
|
export | grep -i proxy
|
|
case poff
|
|
set -e http_proxy
|
|
set -e https_proxy
|
|
set -e ftp_proxy
|
|
set -e all_proxy
|
|
set -e HTTP_PROXY
|
|
set -e HTTPS_PROXY
|
|
set -e FTP_PROXY
|
|
set -e ALL_PROXY
|
|
echo "✓ Proxy disabled"
|
|
export | grep -i proxy
|
|
case pst
|
|
export | grep -i proxy
|
|
case make
|
|
# 切换到 dotfile 目录执行脚本管理 makefile
|
|
set -l dotfile_dir ~/.dotfile
|
|
if test -d $dotfile_dir
|
|
make -f $dotfile_dir/Makefile.scripts -C $dotfile_dir $argv[2..-1]
|
|
else
|
|
echo "Error: Dotfile directory not found at $dotfile_dir"
|
|
end
|
|
case script s
|
|
if not functions -q execute-script
|
|
source ~/.dotfile/fish/functions/execute-script.fish
|
|
end
|
|
execute-script $argv[2..-1]
|
|
case help
|
|
echo "Usage: ff <command>"
|
|
echo ""
|
|
echo "Commands:"
|
|
# 自动生成帮助信息
|
|
for cmd in $commands
|
|
set -l parts (string split '|' $cmd)
|
|
printf " %-10s %s\n" $parts[1] $parts[2]
|
|
end
|
|
echo ""
|
|
echo "Auto-update: ordinary ff commands git-pull ~/.dotfile every 24h (default on)."
|
|
echo " Config: ~/.config/ff/config (enabled=true, interval=24h)"
|
|
echo " Skip: FF_NO_AUTO_UPDATE=1 or ff --no-auto-update <cmd>"
|
|
case update
|
|
set -l dotfile_dir ~/.dotfile
|
|
if not test -d $dotfile_dir
|
|
echo "Error: Dotfile directory not found at $dotfile_dir"
|
|
return 1
|
|
end
|
|
set -l prev_dir (pwd)
|
|
cd $dotfile_dir
|
|
if git pull origin main
|
|
_ff_record_auto_update
|
|
cd $prev_dir
|
|
echo "Reloading fish configuration..."
|
|
ff reload
|
|
else
|
|
cd $prev_dir
|
|
echo "Error: git pull failed, skip reload"
|
|
return 1
|
|
end
|
|
case ssh
|
|
# 每次都重新 source,避免 autoload 缓存旧定义
|
|
source ~/.dotfile/fish/functions/ff-ssh.fish
|
|
ff_ssh $argv[2..-1]
|
|
case dirsize
|
|
set -l script_path ~/.dotfile/script/dirsize.sh
|
|
if test -f $script_path
|
|
bash $script_path $argv[2..-1]
|
|
else
|
|
echo "Error: dirsize script not found at $script_path"
|
|
return 1
|
|
end
|
|
case pouch
|
|
set -l script_path ~/.dotfile/script/pouch-install.sh
|
|
if test -f $script_path
|
|
bash $script_path $argv[2..-1]
|
|
else
|
|
echo "Error: pouch-install script not found at $script_path"
|
|
return 1
|
|
end
|
|
case region
|
|
if not functions -q region_toggle
|
|
source ~/.dotfile/fish/functions/region.fish
|
|
end
|
|
set -l sub toggle
|
|
if test (count $argv) -ge 2
|
|
set sub $argv[2]
|
|
end
|
|
switch $sub
|
|
case toggle
|
|
region_toggle
|
|
case '*'
|
|
echo "Usage: ff region [toggle]"
|
|
echo "Unknown subcommand: $sub"
|
|
end
|
|
case '*'
|
|
if test -z "$argv[1]"
|
|
echo "Error: No command specified"
|
|
else
|
|
echo "Error: Unknown command '$argv[1]'"
|
|
end
|
|
echo "Run 'ff help' for usage information"
|
|
end
|
|
end
|