- install.py / uninstall.py: full Python installer for Linux, macOS, Windows
- detect_platform.py: shared Inkscape config path detection
- Windows config path: %APPDATA%\inkscape (native/winget/scoop) or
%LOCALAPPDATA%\Packages\org.inkscape.Inkscape* (MS Store)
- Windows desktop: Start Menu .lnk via PowerShell WScript.Shell COM object
- macOS: XDG / ~/Library/Application Support detection, no desktop step
- install.sh / uninstall.sh: reduced to one-line exec python3 wrappers
- eliminates SC1091 (source not followed) and SC2155 (declare+assign)
- scripts/detect_platform.sh: export INKSCAPE_CONFIG / INKSCAPE_INSTALL_METHOD
- fixes SC2034 (variables appear unused to shellcheck)
- assets/illuscape.ico: pre-rendered 16/32/48/64/128/256px ICO (ImageMagick)
- tests/test_install.py: pytest integration tests replacing test_install.bats
- cross-platform fake inkscape injected via PATH
- 12 tests covering backup, palettes, templates, prefs, uninstall restore
- ci.yml: add windows-latest matrix leg; shellcheck/inkscape Linux-only;
bats removed in favour of pytest integration tests; 27 tests total
151 lines
5.3 KiB
Python
151 lines
5.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Illuscape uninstaller — cross-platform (Linux, Windows, macOS).
|
|
|
|
Usage:
|
|
python3 uninstall.py
|
|
./uninstall.sh (Linux / macOS)
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import platform
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
SCRIPT_DIR = Path(__file__).parent
|
|
sys.path.insert(0, str(SCRIPT_DIR / "scripts"))
|
|
|
|
from detect_platform import detect_config # noqa: E402
|
|
|
|
ICON_SIZES = (16, 32, 48, 64, 128, 256, 512)
|
|
|
|
# All files installed by install.py, keyed by subdirectory
|
|
_INSTALLED_FILES: dict[str, list[str]] = {
|
|
"keys": [
|
|
"illustrator-cc.xml",
|
|
"illustrator-cs6.xml",
|
|
],
|
|
"palettes": [
|
|
"Illustrator-Defaults.gpl",
|
|
"Illustrator-Grays.gpl",
|
|
"Illustrator-Earth.gpl",
|
|
],
|
|
"templates": [
|
|
"Letter.svg",
|
|
"A4.svg",
|
|
"Web-1920x1080.svg",
|
|
"Web-1280x720.svg",
|
|
"Print-CMYK-Letter.svg",
|
|
"Print-CMYK-A4.svg",
|
|
],
|
|
"symbols": [
|
|
"illuscape-common.svg",
|
|
],
|
|
"splashscreens": [
|
|
"illuscape-splash.png",
|
|
],
|
|
}
|
|
|
|
|
|
# ── Backup discovery ──────────────────────────────────────────────────────────
|
|
|
|
def find_backup(config_path: Path) -> Path | None:
|
|
"""Return the most recent illuscape backup directory, or None."""
|
|
backups = sorted(config_path.parent.glob(config_path.name + ".bak-illuscape-*"))
|
|
return backups[-1] if backups else None
|
|
|
|
|
|
# ── Restore ───────────────────────────────────────────────────────────────────
|
|
|
|
def restore_prefs(backup: Path, config_path: Path) -> None:
|
|
"""Copy preferences.xml back from the backup directory."""
|
|
src = backup / "preferences.xml"
|
|
dst = config_path / "preferences.xml"
|
|
if src.exists():
|
|
shutil.copy2(src, dst)
|
|
print(f"→ preferences.xml restored from: {backup}")
|
|
else:
|
|
print("⚠ No preferences.xml in backup — skipping restore")
|
|
|
|
|
|
# ── File removal ──────────────────────────────────────────────────────────────
|
|
|
|
def remove_files(config_path: Path) -> None:
|
|
"""Delete all files that install.py placed in the Inkscape config dir."""
|
|
for subdir, names in _INSTALLED_FILES.items():
|
|
for name in names:
|
|
(config_path / subdir / name).unlink(missing_ok=True)
|
|
(config_path / "illuscape.ico").unlink(missing_ok=True)
|
|
print("→ Illuscape config files removed")
|
|
|
|
|
|
# ── Desktop cleanup ───────────────────────────────────────────────────────────
|
|
|
|
def remove_desktop(install_method: str) -> None:
|
|
"""Remove the desktop launcher / Start Menu shortcut for the current platform."""
|
|
system = platform.system()
|
|
if system == "Linux" and install_method == "native":
|
|
_remove_linux_desktop()
|
|
elif system == "Windows":
|
|
_remove_windows_desktop()
|
|
|
|
|
|
def _remove_linux_desktop() -> None:
|
|
lnk = Path.home() / ".local/share/applications/org.inkscape.Inkscape.desktop"
|
|
lnk.unlink(missing_ok=True)
|
|
for size in ICON_SIZES:
|
|
icon = (
|
|
Path.home()
|
|
/ f".local/share/icons/hicolor/{size}x{size}/apps/illuscape.png"
|
|
)
|
|
icon.unlink(missing_ok=True)
|
|
app_dir = Path.home() / ".local/share/applications"
|
|
subprocess.run(["update-desktop-database", str(app_dir)], capture_output=True)
|
|
print("→ Desktop launcher removed")
|
|
|
|
|
|
def _remove_windows_desktop() -> None:
|
|
lnk = (
|
|
Path(os.environ.get("APPDATA", ""))
|
|
/ "Microsoft/Windows/Start Menu/Programs/Illuscape.lnk"
|
|
)
|
|
lnk.unlink(missing_ok=True)
|
|
print("→ Start Menu shortcut removed")
|
|
|
|
|
|
# ── Main ──────────────────────────────────────────────────────────────────────
|
|
|
|
def main() -> None:
|
|
print("╔══════════════════════════════╗")
|
|
print("║ Illuscape Uninstaller ║")
|
|
print("╚══════════════════════════════╝")
|
|
print()
|
|
|
|
config_path, install_method = detect_config()
|
|
print(f"→ Inkscape config: {config_path} ({install_method})")
|
|
|
|
backup = find_backup(config_path)
|
|
if backup is None:
|
|
print(f"⚠ No Illuscape backup found at {config_path}.bak-illuscape-*")
|
|
print(" Cannot restore original preferences.xml automatically.")
|
|
print(" Removing only Illuscape-installed files.")
|
|
else:
|
|
restore_prefs(backup, config_path)
|
|
|
|
remove_files(config_path)
|
|
remove_desktop(install_method)
|
|
|
|
print()
|
|
print("✓ Illuscape uninstalled.")
|
|
print()
|
|
print(" Note: Your Inkscape preferences may have changed since Illuscape was")
|
|
print(" installed. If anything looks wrong, review:")
|
|
print(f" {config_path}/preferences.xml")
|
|
print()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|