修复bug

This commit is contained in:
LIm1tZz7 committed 2026-10-11 17:32:12 +08:00
1 parent fc9bbc20e4
commit e87c4ee6a8
90 files changed
+3828 -452

No files matched your search

+1 -1
View File
@@ -169,7 +169,7 @@ if (-not $Component) {
# CHUSQL_ADMIN_PASSWORD。口令只经 stdin 传给 csql-bootstrap,不落 settings.toml。
$adminPassword = "$env:CHUSQL_ADMIN_PASSWORD"
if ($Password) { $adminPassword = $Password }
if ($canPrompt) {
if ($canPrompt -and $adminPassword.Length -eq 0) {
Write-Host ''
Write-Host ('The administrator account is "{0}".' -f $RootUser)
while ($true) {
+64 -24
View File
@@ -28,14 +28,13 @@ usage: ./install.sh [--component web|cli|both] [options]
asks (English, y/n), command line client first:
command line client (csql)? default yes [Y/n]
web front end (browser UI)? default no [y/N]
it then asks whether to give the administrator account a
password (default no); that password goes straight into the
it then asks for the administrator password; it goes into the
system catalog and is never written to settings.toml
--interactive ask even when there is no terminal; the answers are
read from stdin (one per line)
--install-dir DIR where to install (default: $HOME/.local/share/chusql)
--data-dir DIR where to keep data (default: <install-dir>/data)
--data-dir DIR where to keep data (default: XDG data directory)
--user NAME administrator name (default: root)
--keep-package do not delete the downloaded/extracted package
--password VALUE password of the administrator account (required when
@@ -132,6 +131,19 @@ case "$self" in
esac
[ -n "$install_dir" ] || install_dir="$HOME/.local/share/chusql"
config_file="${XDG_CONFIG_HOME:-$HOME/.config}/ChuSQL/settings.toml"
if [ "$list_versions" = 'no' ] && [ -f "$config_file" ]; then
requested_data_dir=$data_dir
data_dir=$(awk '/^[[:space:]]*\[storage\]/ { storage=1; next } /^[[:space:]]*\[/ { storage=0 } storage && /^[[:space:]]*data_dir[[:space:]]*=[[:space:]]*"[^"\\]*"[[:space:]]*(#.*)?$/ { sub(/^[^=]*=[[:space:]]*"/, ""); sub(/"[[:space:]]*(#.*)?$/, ""); print; exit }' "$config_file")
[ -n "$data_dir" ] || fail 'existing settings.toml needs an explicit double-quoted storage.data_dir without escapes'
case "$data_dir" in /*) ;; *) data_dir="$install_dir/$data_dir" ;; esac
if [ -n "$requested_data_dir" ]; then
requested_data_dir=$(CDPATH= cd -- "$requested_data_dir" && pwd -P) || fail 'requested data directory does not exist'
existing_data_dir=$(CDPATH= cd -- "$data_dir" && pwd -P) || fail 'configured data directory does not exist'
[ "$requested_data_dir" = "$existing_data_dir" ] ||
fail 'existing settings.toml: edit its data_dir instead of passing a different --data-dir'
fi
fi
[ -n "$data_dir" ] || data_dir="${XDG_DATA_HOME:-$HOME/.local/share}/chusql/data"
log_dir="${XDG_STATE_HOME:-$HOME/.local/state}/chusql/logs"
@@ -213,7 +225,7 @@ if [ "$list_versions" = 'no' ]; then
if [ -n "$password_arg" ]; then
admin_password="$password_arg"
fi
if [ "$can_prompt" = 'yes' ]; then
if [ "$can_prompt" = 'yes' ] && [ -z "$admin_password" ]; then
echo
echo "The administrator account is $root_user."
while :; do
@@ -511,7 +523,7 @@ if [ "$from_source" = 'yes' ]; then
mkdir -p "$pack/bin" "$pack/resources"
cp "$storage_lib" "$pack/bin/"
cp "$src/resources/settings.toml.linux" "$pack/resources/"
cp "$src/scripts/install.sh" "$pack/"
cp "$src/scripts/install.sh" "$src/scripts/uninstall.sh" "$pack/"
for comp in $wanted; do
if [ "$comp" = 'web' ]; then
comp_dir='chusql-web'; front_name='chusql-web'
@@ -626,15 +638,37 @@ if [ "$(uname -s)" = 'Linux' ] && [ "$no_service" = 'no' ]; then
command -v systemctl >/dev/null 2>&1 || fail 'systemd is required; use --no-service to opt out'
command -v loginctl >/dev/null 2>&1 || fail 'loginctl is required for boot autostart'
systemctl --user show-environment >/dev/null || fail 'cannot connect to user systemd; run in a login session or use --no-service'
loginctl enable-linger "$(id -un)" || fail 'cannot enable boot autostart; run sudo loginctl enable-linger for this OS user and retry'
os_user=$(id -un)
linger=$(loginctl show-user "$os_user" -p Linger --value) || fail 'cannot query boot autostart for this OS user'
if [ "$linger" != 'yes' ]; then
loginctl enable-linger "$os_user" || fail 'cannot enable boot autostart; run sudo loginctl enable-linger for this OS user and retry'
fi
use_service='yes'
if [ -f "$service_file" ]; then
systemctl --user stop chusql-server.service || fail 'cannot stop the existing service'
fi
fi
# 停止安装目录中的进程,避免更新运行中的文件。
stop_installed() {
for executable in chusql-web chusql-server; do
for process in /proc/[0-9]*/exe; do
target=$(readlink "$process" 2>/dev/null) || continue
[ "$target" = "$install_dir/bin/$executable" ] || continue
pid=${process#/proc/}; pid=${pid%/exe}
kill "$pid" || fail "cannot stop $executable ($pid)"
attempts=0
while [ -e "$process" ]; do
attempts=$((attempts + 1))
[ "$attempts" -lt 100 ] || fail "timed out stopping $executable ($pid)"
sleep 0.1
done
done
done
}
step 'Installing files'
mkdir -p "$install_dir/bin" "$log_dir" "$data_dir"
install_dir=$(CDPATH= cd -- "$install_dir" && pwd)
install_dir=$(CDPATH= cd -- "$install_dir" && pwd -P)
if [ "$(uname -s)" = Linux ]; then stop_installed; fi
data_dir=$(CDPATH= cd -- "$data_dir" && pwd)
log_dir=$(CDPATH= cd -- "$log_dir" && pwd)
cp "$pack/bin/chusql-server" "$install_dir/bin/"
@@ -657,7 +691,11 @@ if [ "$want_web" = 'yes' ]; then
chmod +x "$install_dir/csql-web.sh"
fi
fi
chmod +x "$install_dir/bin/"* 2>/dev/null || true
chmod +x "$install_dir/bin/"*
if [ -f "$pack/uninstall.sh" ]; then
cp "$pack/uninstall.sh" "$install_dir/"
chmod +x "$install_dir/uninstall.sh"
fi
# ---- 写全局配置 ----
step 'Writing settings.toml'
@@ -666,9 +704,11 @@ config_file="$config_dir/settings.toml"
mkdir -p "$config_dir"
config_dir=$(CDPATH= cd -- "$config_dir" && pwd)
config_file="$config_dir/settings.toml"
sed -e "s|@DATA_DIR@|$(printf '%s' "$data_dir" | sed 's/[\&|]/\\&/g')|g" \
-e "s|@LOG_DIR@|$(printf '%s' "$log_dir" | sed 's/[\&|]/\\&/g')|g" \
"$pack/resources/settings.toml.linux" > "$config_file"
if [ ! -f "$config_file" ]; then
sed -e "s|@DATA_DIR@|$(printf '%s' "$data_dir" | sed 's/[\&|]/\\&/g')|g" \
-e "s|@LOG_DIR@|$(printf '%s' "$log_dir" | sed 's/[\&|]/\\&/g')|g" \
"$pack/resources/settings.toml.linux" > "$config_file"
fi
echo " config file $config_file"
# ---- 引导系统目录 ----
@@ -676,7 +716,7 @@ echo " config file $config_file"
step 'Initializing the administrator identity and preinstalled types'
bootstrap="$install_dir/bin/csql-bootstrap"
[ -n "$admin_password" ] || fail 'the administrator password is required'
printf '%s\n' "$admin_password" | "$bootstrap" --config "$config_file" --user "$root_user" --password-stdin ||
( cd "$install_dir" && printf '%s\n' "$admin_password" | "$bootstrap" --config "$config_file" --user "$root_user" --password-stdin ) ||
fail 'the bootstrap program failed; identities or preinstalled types are not ready'
# ---- 命令入口 ----
@@ -700,17 +740,17 @@ fi
step 'Updating PATH'
profile="$HOME/.profile"
marker='# ChuSQL'
if [ -f "$profile" ] && grep -q "^$marker" "$profile"; then
echo "PATH entry already present in $profile"
else
{
echo ''
echo "$marker"
echo "PATH=\"\$PATH:$install_dir\""
echo "export PATH"
} >> "$profile"
echo "added $install_dir to PATH in $profile (login again or: . \"$profile\")"
if [ -f "$profile" ] && grep -q "^$marker$" "$profile"; then
awk -v m="$marker" 'skip > 0 { skip--; next } $0 == m { skip=2; next } { print }' "$profile" > "$profile.chusql-install"
mv "$profile.chusql-install" "$profile"
fi
{
echo ''
echo "$marker"
echo "PATH=\"\$PATH:$install_dir:$install_dir/bin\""
echo "export PATH"
} >> "$profile"
echo "added $install_dir to PATH in $profile (login again or: . \"$profile\")"
# ---- 删掉安装包 ----
if [ "$keep_package" = 'no' ]; then
@@ -753,7 +793,7 @@ Description=ChuSQL database server
[Service]
Type=simple
WorkingDirectory="$(unit_quote "$install_dir")"
WorkingDirectory=$(printf '%s' "$install_dir" | sed 's/%/%%/g')
ExecStart=:"$(unit_quote "$server_bin")" --config "$(unit_quote "$config_file")" --user "$(unit_quote "$root_user")"
Restart=on-failure
RestartSec=5
@@ -778,7 +818,7 @@ elif [ "$no_start" = 'yes' ]; then
else
step 'Starting the server'
mkdir -p "$log_dir"
nohup "$server_bin" --config "$config_file" --user "$root_user" > "$log_dir/server.log" 2> "$log_dir/server.err.log" &
( cd "$install_dir" && exec nohup "$server_bin" --config "$config_file" --user "$root_user" ) > "$log_dir/server.log" 2> "$log_dir/server.err.log" &
server_pid=$!
sleep 1
if ! kill -0 "$server_pid" 2>/dev/null; then
+215
View File
@@ -0,0 +1,215 @@
#!/usr/bin/env python3
import json
from functools import partial
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
import os
from pathlib import Path
import shutil
import socket
import subprocess
import sys
import tempfile
import threading
import time
# 用真实发行包验证 Linux 安装、更新及卸载,数据与配置隔离在临时目录。
# 执行命令并将失败日志原样输出。
def run(args, env, cwd=None):
result = subprocess.run(args, env=env, cwd=cwd, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, timeout=60)
if result.returncode:
raise RuntimeError(result.stdout)
return result.stdout
# 选择本机空闲端口。
def free_port():
with socket.socket() as sock:
sock.bind(("127.0.0.1", 0))
return sock.getsockname()[1]
# 登录真实服务器并执行 SQL。
def query(port, statements):
with socket.create_connection(("127.0.0.1", port), timeout=5) as sock:
with sock.makefile("rwb") as stream:
answers = []
for request in [{"method": "hello", "protocol": 1},
{"method": "login", "user": "root", "password": "Lifecycle-test-123!"}] + [
{"method": "query", "sql": sql} for sql in statements]:
stream.write(json.dumps(request).encode() + b"\n")
stream.flush()
answer = json.loads(stream.readline())
assert answer["status"] != "error", answer
answers.append(answer)
return answers[2:]
# 等待服务器可接受登录。
def wait_server(port):
deadline = time.monotonic() + 15
while time.monotonic() < deadline:
try:
query(port, [])
return
except (OSError, ValueError):
time.sleep(0.1)
raise RuntimeError("server did not become ready")
# 用真实用户 systemd 验证注册、更新启动和卸载。
def test_systemd(repo, archive, root, env):
systemctl = shutil.which("systemctl")
state = run([systemctl, "--user", "show", "chusql-server.service", "-p", "LoadState"], env)
assert "LoadState=not-found" in state, "existing chusql-server.service: refusing to change it"
runtime_unit = Path(os.environ["XDG_RUNTIME_DIR"]) / "systemd/user/chusql-server.service"
assert not runtime_unit.is_symlink(), "existing runtime service link: refusing to change it"
user = run(["id", "-un"], env).strip()
linger = run(["loginctl", "show-user", user, "-p", "Linger"], env).strip()
home = root / "service-home"
home.mkdir()
env = dict(env, HOME=str(home), XDG_CONFIG_HOME=str(home / ".config"),
XDG_STATE_HOME=str(home / ".local/state"), CHUSQL_ADMIN_PASSWORD="Lifecycle-test-123!")
install = root / "service program"
unit = home / ".config/systemd/user/chusql-server.service"
bridge = root / "service-tools"
bridge.mkdir()
wrapper = bridge / "systemctl"
wrapper.write_text(f'''#!/bin/sh
# 将隔离配置中的单元链接到用户 systemd 的运行目录。
if [ "$*" = '--user daemon-reload' ] && [ -f "$CHUSQL_TEST_UNIT" ]; then
"{systemctl}" --user link --runtime "$CHUSQL_TEST_UNIT" || exit 1
fi
exec "{systemctl}" "$@"
''')
wrapper.chmod(0o755)
env.update(PATH=str(bridge) + ":" + env["PATH"], CHUSQL_TEST_UNIT=str(unit))
installer = ["sh", str(repo / "scripts/install.sh"), "--url", archive,
"--component", "both", "--install-dir", str(install)]
try:
run(installer + ["--data-dir", str(root / "service-data"), "--no-start"], env)
config = home / ".config/ChuSQL/settings.toml"
port = free_port()
config.write_text(config.read_text().replace("port = 7777", f"port = {port}"))
run(installer, env)
wait_server(port)
run([systemctl, "--user", "is-active", "--quiet", "chusql-server.service"], env)
run(["sh", str(install / "uninstall.sh"), "--install-dir", str(install), "--yes"], env)
assert not unit.exists() and not (root / "service-data").exists()
print("PASS real systemd registration, update/start and uninstall", flush=True)
finally:
state = run([systemctl, "--user", "show", "chusql-server.service", "-p", "LoadState"], env)
if "LoadState=loaded" in state:
run([systemctl, "--user", "stop", "chusql-server.service"], env)
user_units = Path(os.environ["HOME"]) / ".config/systemd/user"
for link in [runtime_unit, user_units / "chusql-server.service",
user_units / "default.target.wants/chusql-server.service"]:
if link.is_symlink() and link.resolve() == unit.resolve():
link.unlink()
run([systemctl, "--user", "daemon-reload"], dict(env, CHUSQL_TEST_UNIT="/nonexistent"))
if linger == "Linger=no" and run(["loginctl", "show-user", user, "-p", "Linger"], env).strip() == "Linger=yes":
run(["loginctl", "disable-linger", user], env)
# 用本机发行站验证版本查询、HTTP 下载与校验。
def test_online(repo, archive, root, env):
site = root / "release-site"
api = site / "api/v3/repos/test/ChuSQL/releases"
api.parent.mkdir(parents=True)
api.write_text(json.dumps([{"tag_name": "v-test", "prerelease": False,
"assets": [{"name": "chusql-linux-x86_64.tar.gz"}]}], indent=2))
assets = site / "test/ChuSQL/releases/download/v-test"
assets.mkdir(parents=True)
shutil.copy2(archive, assets / Path(archive).name)
shutil.copy2(archive + ".sha256", assets / (Path(archive).name + ".sha256"))
server = ThreadingHTTPServer(("127.0.0.1", 0), partial(SimpleHTTPRequestHandler, directory=str(site)))
thread = threading.Thread(target=server.serve_forever, daemon=True)
thread.start()
install = root / "online-program"
env = dict(env, CHUSQL_GITHUB_BASE=f"http://127.0.0.1:{server.server_port}")
installer = ["sh", str(repo / "scripts/install.sh"), "--repo", "test/ChuSQL"]
try:
assert "v-test" in run(installer + ["--list-versions"], env)
output = run(installer + ["--component", "cli", "--install-dir", str(install),
"--data-dir", str(root / "online-data"), "--no-service", "--no-start"], env)
assert "checksum" in output and "(ok)" in output
assert (install / "bin/csql").exists() and not (install / "bin/chusql-web").exists()
run(["sh", str(install / "uninstall.sh"), "--install-dir", str(install), "--yes"], env)
assert not (root / "online-data").exists()
print("PASS release API, latest version selection, HTTP download and checksum (local fixture)", flush=True)
finally:
server.shutdown()
server.server_close()
thread.join()
# 在隔离目录验证配置、SQL 数据和卸载保留选项。
def main():
if sys.platform != "linux" or len(sys.argv) not in (2, 3) or (len(sys.argv) == 3 and sys.argv[2] != "--systemd"):
raise SystemExit("usage: python3 scripts/test-linux-lifecycle.py <linux-package.tar.gz> [--systemd]")
archive = str(Path(sys.argv[1]).resolve())
repo = Path(__file__).resolve().parent.parent
(repo / "logs").mkdir(exist_ok=True)
with tempfile.TemporaryDirectory(prefix="linux-lifecycle-", dir=repo / "logs") as temporary:
root = Path(temporary)
home = root / "home"
home.mkdir()
env = dict(os.environ, HOME=str(home), XDG_CONFIG_HOME=str(home / ".config"),
XDG_DATA_HOME=str(home / ".local/share"), XDG_STATE_HOME=str(home / ".local/state"),
CHUSQL_ADMIN_PASSWORD="Lifecycle-test-123!")
env.pop("LD_LIBRARY_PATH", None)
install = root / "program"
data = install / "custom/nested/data"
config = home / ".config/ChuSQL/settings.toml"
installer = ["sh", str(repo / "scripts/install.sh"), "--url", archive,
"--install-dir", str(install), "--component", "both", "--no-service", "--no-start"]
run(installer + ["--data-dir", str(data)], env)
assert (data / "system/catalog.json").is_file()
assert (install / "uninstall.sh").is_file()
assert "@DATA_DIR@" not in config.read_text()
assert run([str(install / "bin/csql-bootstrap"), "--help"], env)
print("PASS clean installation and dynamic library lookup", flush=True)
port = free_port()
settings = config.read_text().replace("port = 7777", f"port = {port}").replace(str(data), "custom/nested/data") + "\n# preserve custom settings\n"
config.write_text(settings)
server = subprocess.Popen([str(install / "bin/chusql-server"), "--config", str(config)],
env=env, cwd=install, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
try:
wait_server(port)
query(port, ["create database lifecycle", "use lifecycle", "create table saved (id int)",
"insert into saved (id) values (42)"])
env["CHUSQL_ADMIN_PASSWORD"] = "Different-update-password-123!"
run(installer, env)
server.wait(timeout=5)
assert config.read_text() == settings
assert (home / ".profile").read_text().count("# ChuSQL\n") == 1
server = subprocess.Popen([str(install / "bin/chusql-server"), "--config", str(config)],
env=env, cwd=install, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
wait_server(port)
result = query(port, ["use lifecycle", "select id from saved"])[-1]
assert result["rowCount"] == 1 and "42" in json.dumps(result["rows"]), result
print("PASS running update preserves configuration, credentials and SQL data", flush=True)
uninstall = ["sh", str(install / "uninstall.sh"), "--install-dir", str(install), "--yes"]
run(uninstall + ["--keep-data", "--keep-config"], env)
server.wait(timeout=5)
assert data.is_dir() and config.read_text() == settings
assert not (install / "bin").exists()
assert "# ChuSQL" not in (home / ".profile").read_text()
print("PASS uninstall stops server and keeps nested data and configuration", flush=True)
run(installer, env)
run(uninstall, env)
assert not install.exists() and not data.exists() and not config.exists()
print("PASS reinstall and full uninstall discover configured data path", flush=True)
finally:
if server.poll() is None:
server.terminate()
server.wait(timeout=10)
test_online(repo, archive, root, env)
if len(sys.argv) == 3:
with tempfile.TemporaryDirectory(prefix="chusql-systemd-") as service_temporary:
test_systemd(repo, archive, Path(service_temporary), env)
if __name__ == "__main__":
main()
+40 -14
View File
@@ -17,7 +17,7 @@ Uninstall ChuSQL (Linux/macOS).
Usage: uninstall.sh [options]
--install-dir DIR program directory (default: $HOME/.local/share/chusql)
--data-dir DIR data directory (default: <install-dir>/data)
--data-dir DIR data directory (default: settings.toml, then XDG data directory)
--keep-data keep the data directory, remove programs only
--keep-config keep settings.toml
--yes do not ask (required when there is no terminal)
@@ -36,6 +36,21 @@ fail() {
stop_by_path() {
target=$1
[ -n "$target" ] || return 0
if [ "$(uname -s)" = Linux ]; then
for process in /proc/[0-9]*/exe; do
executable=$(readlink "$process" 2>/dev/null) || continue
[ "$executable" = "$target" ] || continue
pid=${process#/proc/}; pid=${pid%/exe}
kill "$pid" || fail "cannot stop $target ($pid)"
attempts=0
while [ -e "$process" ]; do
attempts=$((attempts + 1))
[ "$attempts" -lt 100 ] || fail "timed out stopping $target ($pid)"
sleep 0.1
done
done
return 0
fi
pids=$(ps -eo pid=,args= 2>/dev/null |
awk -v t="$target" '{ pid = $1; $1 = ""; sub(/^ +/, ""); if (index($0, t) == 1) print pid }' || true)
[ -n "$pids" ] || return 0
@@ -73,9 +88,27 @@ while [ $# -gt 0 ]; do
done
install_dir=${install_dir:-$HOME/.local/share/chusql}
data_dir=${data_dir:-${XDG_DATA_HOME:-$HOME/.local/share}/chusql/data}
config_dir="${XDG_CONFIG_HOME:-$HOME/.config}/ChuSQL"
config_file="$config_dir/settings.toml"
if [ -z "$data_dir" ] && [ -f "$config_file" ]; then
data_dir=$(awk '/^[[:space:]]*\[storage\]/ { storage=1; next } /^[[:space:]]*\[/ { storage=0 } storage && /^[[:space:]]*data_dir[[:space:]]*=[[:space:]]*"[^"\\]*"[[:space:]]*(#.*)?$/ { sub(/^[^=]*=[[:space:]]*"/, ""); sub(/"[[:space:]]*(#.*)?$/, ""); print; exit }' "$config_file")
[ -n "$data_dir" ] || fail 'settings.toml needs an explicit double-quoted storage.data_dir without escapes; pass --data-dir'
case "$data_dir" in /*) ;; *) data_dir="$install_dir/$data_dir" ;; esac
fi
data_dir=${data_dir:-${XDG_DATA_HOME:-$HOME/.local/share}/chusql/data}
if [ "$(uname -s)" = Linux ]; then
install_dir=$(realpath -m -- "$install_dir")
data_dir=$(realpath -m -- "$data_dir")
else
if [ -d "$install_dir" ]; then install_dir=$(CDPATH= cd -- "$install_dir" && pwd -P); fi
if [ -d "$data_dir" ]; then data_dir=$(CDPATH= cd -- "$data_dir" && pwd -P); fi
fi
case "$install_dir" in /|"$HOME") fail 'refusing to remove the root or home directory' ;; esac
case "$data_dir" in /|"$HOME") fail 'refusing to remove the root or home data directory' ;; esac
case "$install_dir" in "$data_dir"|"$data_dir"/*) fail 'data directory must not contain the installation' ;; esac
for entry in bin static csql csql-web csql-web.sh uninstall.sh; do
case "$data_dir" in "$install_dir/$entry"|"$install_dir/$entry"/*) fail 'data directory overlaps installed program files' ;; esac
done
profile="$HOME/.profile"
if [ "$assume_yes" = 'no' ]; then
@@ -108,23 +141,16 @@ step 'Removing files'
if [ ! -d "$install_dir" ]; then
note "not found: $install_dir"
elif [ "$keep_data" = 'yes' ]; then
for entry in "$install_dir"/*; do
for entry in "$install_dir"/bin "$install_dir"/static "$install_dir"/csql "$install_dir"/csql-web "$install_dir"/csql-web.sh "$install_dir"/uninstall.sh; do
[ -e "$entry" ] || continue
if [ "$entry" = "$data_dir" ]; then
note "kept data: $entry"
continue
fi
rm -rf "$entry"
done
note "kept $install_dir (data only)"
note "kept data: $data_dir"
else
rm -rf "$install_dir"
case "$data_dir" in
"$install_dir" | "$install_dir"/*) ;;
*) rm -rf "$data_dir" ;;
esac
note "removed $install_dir"
fi
if [ "$keep_data" = 'no' ] && [ -d "$data_dir" ]; then rm -rf "$data_dir"; fi
step 'Removing settings.toml'
if [ "$keep_config" = 'yes' ]; then
@@ -139,11 +165,11 @@ step 'Removing the PATH entry'
marker='# ChuSQL'
if [ ! -f "$profile" ]; then
note "no $profile"
elif grep -q "^$marker" "$profile"; then
elif grep -q "^$marker$" "$profile"; then
tmp="$profile.chusql-uninstall"
awk -v m="$marker" '
skip > 0 { skip--; next }
index($0, m) == 1 { skip = 2; next }
$0 == m { skip = 2; next }
{ print }
' "$profile" >"$tmp" && mv "$tmp" "$profile"
note "removed the $marker block from $profile"