feat: cross-platform installer (Windows port)
- 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
This commit is contained in:
parent
aaeeb49e00
commit
8e245dfe61
9 changed files with 772 additions and 267 deletions
27
.github/workflows/ci.yml
vendored
27
.github/workflows/ci.yml
vendored
|
|
@ -7,10 +7,13 @@ on:
|
|||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-${{ matrix.ubuntu }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
ubuntu: ["22.04", "24.04"]
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
- os: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
@ -20,19 +23,25 @@ jobs:
|
|||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Install test deps
|
||||
- name: Install test deps (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
pip install pytest
|
||||
sudo apt-get install -y bats shellcheck inkscape
|
||||
sudo apt-get install -y shellcheck inkscape
|
||||
|
||||
- name: Python unit tests
|
||||
run: pytest tests/test_merge_prefs.py -v
|
||||
- name: Install test deps (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
run: pip install pytest
|
||||
|
||||
- name: Shellcheck
|
||||
- name: Shellcheck (Linux only)
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
shellcheck install.sh
|
||||
shellcheck uninstall.sh
|
||||
shellcheck scripts/detect_platform.sh
|
||||
|
||||
- name: Bats integration tests
|
||||
run: bats tests/test_install.bats
|
||||
- name: Python unit tests
|
||||
run: pytest tests/test_merge_prefs.py -v
|
||||
|
||||
- name: Python integration tests
|
||||
run: pytest tests/test_install.py -v
|
||||
|
|
|
|||
BIN
assets/illuscape.ico
Normal file
BIN
assets/illuscape.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
288
install.py
Normal file
288
install.py
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Illuscape installer — cross-platform (Linux, Windows, macOS).
|
||||
|
||||
Usage:
|
||||
python3 install.py [--preset=cc|cs6] [--yes]
|
||||
./install.sh [--preset=cc|cs6] [--yes] (Linux / macOS)
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import datetime
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Ensure scripts/ is importable regardless of cwd
|
||||
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)
|
||||
|
||||
|
||||
# ── Dependency check ──────────────────────────────────────────────────────────
|
||||
|
||||
def check_deps(auto_yes: bool) -> None:
|
||||
"""Verify Inkscape is present and meets the minimum version."""
|
||||
if not shutil.which("inkscape"):
|
||||
sys.exit("✗ Inkscape is not installed. Install Inkscape first, then run Illuscape.")
|
||||
|
||||
try:
|
||||
raw = subprocess.run(
|
||||
["inkscape", "--version"],
|
||||
capture_output=True, text=True, timeout=10,
|
||||
).stdout
|
||||
except (FileNotFoundError, subprocess.TimeoutExpired):
|
||||
return # cannot check version — proceed anyway
|
||||
|
||||
match = re.search(r"(\d+)\.(\d+)", raw)
|
||||
if match:
|
||||
major, minor = int(match.group(1)), int(match.group(2))
|
||||
if major < 1 or (major == 1 and minor < 2):
|
||||
version = f"{major}.{minor}"
|
||||
print(f"⚠ Inkscape {version} detected. Illuscape targets Inkscape 1.2+.")
|
||||
print(" Some settings may not apply correctly. Continue anyway? [y/N]")
|
||||
if not auto_yes and input().strip().lower() != "y":
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
# ── Backup ────────────────────────────────────────────────────────────────────
|
||||
|
||||
def backup_config(config_path: Path) -> None:
|
||||
"""Copy the config directory to a timestamped backup; idempotent on repeat runs."""
|
||||
timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
|
||||
backup_dir = Path(str(config_path) + f".bak-illuscape-{timestamp}")
|
||||
|
||||
existing = sorted(config_path.parent.glob(config_path.name + ".bak-illuscape-*"))
|
||||
if existing:
|
||||
print("→ Backup already exists — skipping (idempotent)")
|
||||
return
|
||||
|
||||
if config_path.is_dir():
|
||||
shutil.copytree(config_path, backup_dir)
|
||||
print(f"→ Backed up to: {backup_dir}")
|
||||
else:
|
||||
print("→ No existing config to back up (fresh install)")
|
||||
|
||||
|
||||
# ── Preset selection ──────────────────────────────────────────────────────────
|
||||
|
||||
def choose_preset(preset: str, auto_yes: bool) -> str:
|
||||
"""Prompt the user for CC / CS6 unless preset is already provided."""
|
||||
if preset:
|
||||
return preset
|
||||
|
||||
print()
|
||||
print("Which Illustrator era are you coming from?")
|
||||
print(" [1] CC — current Creative Cloud (default)")
|
||||
print(" [2] CS6 — last perpetual license")
|
||||
print("Choice [1]: ", end="", flush=True)
|
||||
if auto_yes:
|
||||
print("1 (auto)")
|
||||
return "cc"
|
||||
choice = input().strip()
|
||||
return "cs6" if choice == "2" else "cc"
|
||||
|
||||
|
||||
# ── Preferences merge ─────────────────────────────────────────────────────────
|
||||
|
||||
def merge_prefs(config_path: Path, preset: str) -> None:
|
||||
"""Invoke merge_prefs.py to upsert the preferences patch into Inkscape's prefs."""
|
||||
subprocess.run(
|
||||
[
|
||||
sys.executable,
|
||||
str(SCRIPT_DIR / "scripts/merge_prefs.py"),
|
||||
"--prefs", str(config_path / "preferences.xml"),
|
||||
"--patch", str(SCRIPT_DIR / "config/preferences-patch.xml"),
|
||||
"--preset", preset,
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
|
||||
|
||||
# ── Config file copy ──────────────────────────────────────────────────────────
|
||||
|
||||
def copy_files(config_path: Path, preset: str) -> None:
|
||||
"""Copy keys, palettes, templates, and symbols into the Inkscape config dir."""
|
||||
for subdir in ("keys", "palettes", "templates", "symbols", "splashscreens"):
|
||||
(config_path / subdir).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
shutil.copy2(
|
||||
SCRIPT_DIR / f"config/keys/illustrator-{preset}.xml",
|
||||
config_path / "keys/",
|
||||
)
|
||||
for palette in (SCRIPT_DIR / "config/palettes").glob("*.gpl"):
|
||||
shutil.copy2(palette, config_path / "palettes/")
|
||||
for template in (SCRIPT_DIR / "config/templates").glob("*.svg"):
|
||||
shutil.copy2(template, config_path / "templates/")
|
||||
for symbol in (SCRIPT_DIR / "config/symbols").glob("*.svg"):
|
||||
shutil.copy2(symbol, config_path / "symbols/")
|
||||
|
||||
print("→ Config files copied")
|
||||
|
||||
|
||||
# ── Desktop integration ───────────────────────────────────────────────────────
|
||||
|
||||
def install_desktop(config_path: Path, install_method: str) -> None:
|
||||
"""Install a desktop launcher / Start Menu shortcut for the current platform."""
|
||||
system = platform.system()
|
||||
if system == "Linux" and install_method == "native":
|
||||
_install_linux_desktop(config_path)
|
||||
elif system == "Windows":
|
||||
_install_windows_desktop(config_path)
|
||||
# macOS: Inkscape.app handles its own dock icon; no extra step needed.
|
||||
|
||||
|
||||
def _install_linux_desktop(config_path: Path) -> None:
|
||||
app_dir = Path.home() / ".local/share/applications"
|
||||
icon_src = SCRIPT_DIR / "assets/illuscape.svg"
|
||||
splash_src = SCRIPT_DIR / "assets/splash.svg"
|
||||
|
||||
app_dir.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy2(SCRIPT_DIR / "assets/org.inkscape.Inkscape.desktop", app_dir)
|
||||
|
||||
for size in ICON_SIZES:
|
||||
icon_dir = Path.home() / f".local/share/icons/hicolor/{size}x{size}/apps"
|
||||
icon_dir.mkdir(parents=True, exist_ok=True)
|
||||
icon_out = icon_dir / "illuscape.png"
|
||||
if _rsvg_convert(icon_src, icon_out, size, size):
|
||||
continue
|
||||
if _inkscape_export(icon_src, icon_out, size, size):
|
||||
continue
|
||||
print(f"⚠ Could not rasterize icon at {size}px (install rsvg-convert for icons)")
|
||||
|
||||
splash_out = config_path / "splashscreens/illuscape-splash.png"
|
||||
_rsvg_convert(splash_src, splash_out, 600, 400)
|
||||
|
||||
subprocess.run(
|
||||
["update-desktop-database", str(app_dir)],
|
||||
capture_output=True,
|
||||
)
|
||||
print("→ Desktop launcher installed")
|
||||
|
||||
|
||||
def _install_windows_desktop(config_path: Path) -> None:
|
||||
"""
|
||||
Create a Start Menu .lnk shortcut via PowerShell WScript.Shell COM object.
|
||||
The ICO is copied to the config dir so it stays with the config.
|
||||
"""
|
||||
ico_src = SCRIPT_DIR / "assets/illuscape.ico"
|
||||
ico_dst = config_path / "illuscape.ico"
|
||||
|
||||
if ico_src.exists():
|
||||
shutil.copy2(ico_src, ico_dst)
|
||||
|
||||
start_menu = (
|
||||
Path(os.environ.get("APPDATA", ""))
|
||||
/ "Microsoft/Windows/Start Menu/Programs"
|
||||
)
|
||||
lnk_path = start_menu / "Illuscape.lnk"
|
||||
inkscape_exe = shutil.which("inkscape") or "inkscape.exe"
|
||||
|
||||
# Build a PowerShell one-liner using WScript.Shell
|
||||
ps_lines = [
|
||||
"$ws = New-Object -ComObject WScript.Shell",
|
||||
f"$s = $ws.CreateShortcut('{lnk_path}')",
|
||||
f"$s.TargetPath = '{inkscape_exe}'",
|
||||
"$s.Description = 'Inkscape with Illustrator-style config'",
|
||||
]
|
||||
if ico_dst.exists():
|
||||
ps_lines.append(f"$s.IconLocation = '{ico_dst}'")
|
||||
ps_lines.append("$s.Save()")
|
||||
|
||||
try:
|
||||
subprocess.run(
|
||||
["powershell", "-NoProfile", "-Command", "; ".join(ps_lines)],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
print("→ Start Menu shortcut installed")
|
||||
except (FileNotFoundError, subprocess.CalledProcessError) as exc:
|
||||
print(f"⚠ Could not create Start Menu shortcut: {exc}")
|
||||
print(" You can create one manually pointing to inkscape.exe.")
|
||||
|
||||
|
||||
# ── Icon rasterization helpers ────────────────────────────────────────────────
|
||||
|
||||
def _rsvg_convert(src: Path, dst: Path, w: int, h: int) -> bool:
|
||||
"""Rasterize *src* SVG to *dst* PNG using rsvg-convert. Returns True on success."""
|
||||
if not shutil.which("rsvg-convert"):
|
||||
return False
|
||||
result = subprocess.run(
|
||||
["rsvg-convert", "-w", str(w), "-h", str(h), str(src), "-o", str(dst)],
|
||||
capture_output=True,
|
||||
)
|
||||
return result.returncode == 0
|
||||
|
||||
|
||||
def _inkscape_export(src: Path, dst: Path, w: int, h: int) -> bool:
|
||||
"""
|
||||
Rasterize *src* SVG using Inkscape 1.x export flags.
|
||||
(--export-png was removed in Inkscape 1.0)
|
||||
"""
|
||||
result = subprocess.run(
|
||||
[
|
||||
"inkscape",
|
||||
f"--export-filename={dst}",
|
||||
"--export-type=png",
|
||||
f"--export-width={w}",
|
||||
f"--export-height={h}",
|
||||
str(src),
|
||||
],
|
||||
capture_output=True,
|
||||
)
|
||||
return result.returncode == 0
|
||||
|
||||
|
||||
# ── CLI ───────────────────────────────────────────────────────────────────────
|
||||
|
||||
def _parse_args() -> argparse.Namespace:
|
||||
p = argparse.ArgumentParser(description="Illuscape — Inkscape with Illustrator feel")
|
||||
p.add_argument(
|
||||
"--preset",
|
||||
choices=["cc", "cs6"],
|
||||
default="",
|
||||
help="Illustrator shortcut era: cc (default) or cs6",
|
||||
)
|
||||
p.add_argument("--yes", "-y", action="store_true", help="Skip confirmation prompts")
|
||||
return p.parse_args()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = _parse_args()
|
||||
|
||||
print("╔══════════════════════════════╗")
|
||||
print("║ Illuscape Installer ║")
|
||||
print("╚══════════════════════════════╝")
|
||||
print()
|
||||
|
||||
check_deps(args.yes)
|
||||
config_path, install_method = detect_config()
|
||||
print(f"→ Inkscape config: {config_path} ({install_method})")
|
||||
|
||||
backup_config(config_path)
|
||||
preset = choose_preset(args.preset, args.yes)
|
||||
print(f"→ Using preset: {preset}")
|
||||
|
||||
merge_prefs(config_path, preset)
|
||||
copy_files(config_path, preset)
|
||||
install_desktop(config_path, install_method)
|
||||
|
||||
print()
|
||||
print(f"✓ Illuscape installed (preset: {preset})")
|
||||
print()
|
||||
print(" Open Inkscape to start using your Illustrator-style workspace.")
|
||||
print(" To uninstall: python3 uninstall.py (or ./uninstall.sh on Linux/macOS)")
|
||||
print()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
183
install.sh
183
install.sh
|
|
@ -1,185 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
# Illuscape installer
|
||||
# Illuscape installer — thin wrapper around install.py
|
||||
# Usage: ./install.sh [--preset=cc|cs6] [--yes]
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PRESET=""
|
||||
AUTO_YES=0
|
||||
|
||||
# ── Parse args ──────────────────────────────────────────────────────────────
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--preset=cc|--preset=cs6) PRESET="${arg#--preset=}" ;;
|
||||
--yes|-y) AUTO_YES=1 ;;
|
||||
--help|-h)
|
||||
echo "Usage: ./install.sh [--preset=cc|cs6] [--yes]"
|
||||
echo " --preset=cc Illustrator CC shortcuts (default)"
|
||||
echo " --preset=cs6 Illustrator CS6 shortcuts"
|
||||
echo " --yes Skip confirmation prompts"
|
||||
exit 0 ;;
|
||||
*) echo "Unknown argument: $arg"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# ── Check dependencies ───────────────────────────────────────────────────────
|
||||
check_deps() {
|
||||
if ! command -v inkscape &>/dev/null; then
|
||||
echo "✗ Inkscape is not installed. Install Inkscape first, then run Illuscape."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local version
|
||||
version=$(inkscape --version 2>/dev/null | grep -oP '\d+\.\d+' | head -1)
|
||||
local major minor
|
||||
IFS='.' read -r major minor <<< "$version"
|
||||
# Skip version check if regex couldn't match (non-standard version string)
|
||||
if [[ -n "$major" ]] && { (( major < 1 )) || (( major == 1 && minor < 2 )); }; then
|
||||
echo "⚠ Inkscape $version detected. Illuscape targets Inkscape 1.2+."
|
||||
echo " Some settings may not apply correctly. Continue anyway? [y/N]"
|
||||
[[ $AUTO_YES == 1 ]] || { read -r ans; [[ "$ans" =~ ^[Yy]$ ]] || exit 0; }
|
||||
fi
|
||||
|
||||
if ! command -v python3 &>/dev/null; then
|
||||
echo "✗ python3 is required. Install it and try again."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Detect platform ──────────────────────────────────────────────────────────
|
||||
detect_config() {
|
||||
source "$SCRIPT_DIR/scripts/detect_platform.sh"
|
||||
echo "→ Inkscape config: $INKSCAPE_CONFIG ($INKSCAPE_INSTALL_METHOD)"
|
||||
}
|
||||
|
||||
# ── Backup ───────────────────────────────────────────────────────────────────
|
||||
backup_config() {
|
||||
local backup_dir="${INKSCAPE_CONFIG}.bak-illuscape-$(date +%Y%m%d-%H%M%S)"
|
||||
|
||||
# If any illuscape backup already exists, skip (idempotent)
|
||||
if ls "${INKSCAPE_CONFIG}".bak-illuscape-* &>/dev/null; then
|
||||
echo "→ Backup already exists — skipping (idempotent)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -d "$INKSCAPE_CONFIG" ]]; then
|
||||
cp -r "$INKSCAPE_CONFIG" "$backup_dir"
|
||||
echo "→ Backed up to: $backup_dir"
|
||||
else
|
||||
echo "→ No existing config to back up (fresh install)"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Prompt for preset ────────────────────────────────────────────────────────
|
||||
choose_preset() {
|
||||
[[ -n "$PRESET" ]] && return 0
|
||||
echo ""
|
||||
echo "Which Illustrator era are you coming from?"
|
||||
echo " [1] CC — current Creative Cloud (default)"
|
||||
echo " [2] CS6 — last perpetual license"
|
||||
printf "Choice [1]: "
|
||||
if [[ $AUTO_YES == 1 ]]; then
|
||||
echo "1 (auto)"
|
||||
PRESET="cc"
|
||||
return 0
|
||||
fi
|
||||
read -r choice
|
||||
case "${choice:-1}" in
|
||||
2) PRESET="cs6" ;;
|
||||
*) PRESET="cc" ;;
|
||||
esac
|
||||
echo "→ Using preset: $PRESET"
|
||||
}
|
||||
|
||||
# ── Merge preferences ────────────────────────────────────────────────────────
|
||||
merge_prefs() {
|
||||
local prefs_file="$INKSCAPE_CONFIG/preferences.xml"
|
||||
python3 "$SCRIPT_DIR/scripts/merge_prefs.py" \
|
||||
--prefs "$prefs_file" \
|
||||
--patch "$SCRIPT_DIR/config/preferences-patch.xml" \
|
||||
--preset "$PRESET"
|
||||
}
|
||||
|
||||
# ── Copy config files ────────────────────────────────────────────────────────
|
||||
copy_files() {
|
||||
mkdir -p \
|
||||
"$INKSCAPE_CONFIG/keys" \
|
||||
"$INKSCAPE_CONFIG/palettes" \
|
||||
"$INKSCAPE_CONFIG/templates" \
|
||||
"$INKSCAPE_CONFIG/symbols" \
|
||||
"$INKSCAPE_CONFIG/splashscreens"
|
||||
|
||||
cp "$SCRIPT_DIR/config/keys/illustrator-${PRESET}.xml" \
|
||||
"$INKSCAPE_CONFIG/keys/"
|
||||
|
||||
cp "$SCRIPT_DIR/config/palettes/"*.gpl "$INKSCAPE_CONFIG/palettes/"
|
||||
cp "$SCRIPT_DIR/config/templates/"*.svg "$INKSCAPE_CONFIG/templates/"
|
||||
cp "$SCRIPT_DIR/config/symbols/"*.svg "$INKSCAPE_CONFIG/symbols/"
|
||||
|
||||
echo "→ Config files copied"
|
||||
}
|
||||
|
||||
# ── Install desktop launcher + icons (Linux native only) ─────────────────────
|
||||
install_desktop() {
|
||||
[[ "$INKSCAPE_INSTALL_METHOD" != "native" ]] && return 0
|
||||
|
||||
local app_dir="$HOME/.local/share/applications"
|
||||
local icon_src="$SCRIPT_DIR/assets/illuscape.svg"
|
||||
local splash_src="$SCRIPT_DIR/assets/splash.svg"
|
||||
local icon_sizes=(16 32 48 64 128 256 512)
|
||||
|
||||
mkdir -p "$app_dir"
|
||||
cp "$SCRIPT_DIR/assets/org.inkscape.Inkscape.desktop" "$app_dir/"
|
||||
|
||||
# Rasterize icon at each size (prefer rsvg-convert, fall back to Inkscape)
|
||||
for size in "${icon_sizes[@]}"; do
|
||||
local icon_dir="$HOME/.local/share/icons/hicolor/${size}x${size}/apps"
|
||||
mkdir -p "$icon_dir"
|
||||
if command -v rsvg-convert &>/dev/null; then
|
||||
rsvg-convert -w "$size" -h "$size" "$icon_src" \
|
||||
-o "$icon_dir/illuscape.png" 2>/dev/null && continue
|
||||
fi
|
||||
if command -v inkscape &>/dev/null; then
|
||||
# Inkscape 1.x uses --export-filename + --export-type (--export-png removed in 1.0)
|
||||
inkscape --export-filename="$icon_dir/illuscape.png" \
|
||||
--export-type=png \
|
||||
--export-width="$size" --export-height="$size" \
|
||||
"$icon_src" 2>/dev/null && continue
|
||||
fi
|
||||
echo "⚠ Could not rasterize icon at ${size}px (install rsvg-convert for icons)"
|
||||
done
|
||||
|
||||
# Splash screen (600x400)
|
||||
if command -v rsvg-convert &>/dev/null; then
|
||||
rsvg-convert -w 600 -h 400 "$splash_src" \
|
||||
-o "$INKSCAPE_CONFIG/splashscreens/illuscape-splash.png" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
update-desktop-database "$app_dir" 2>/dev/null || true
|
||||
echo "→ Desktop launcher installed"
|
||||
}
|
||||
|
||||
# ── Main ──────────────────────────────────────────────────────────────────────
|
||||
main() {
|
||||
echo "╔══════════════════════════════╗"
|
||||
echo "║ Illuscape Installer ║"
|
||||
echo "╚══════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
check_deps
|
||||
detect_config
|
||||
backup_config
|
||||
choose_preset
|
||||
merge_prefs
|
||||
copy_files
|
||||
install_desktop
|
||||
|
||||
echo ""
|
||||
echo "✓ Illuscape installed (preset: $PRESET)"
|
||||
echo ""
|
||||
echo " Open Inkscape to start using your Illustrator-style workspace."
|
||||
echo " To uninstall: ./uninstall.sh"
|
||||
echo ""
|
||||
}
|
||||
|
||||
main
|
||||
exec python3 "$SCRIPT_DIR/install.py" "$@"
|
||||
|
|
|
|||
82
scripts/detect_platform.py
Normal file
82
scripts/detect_platform.py
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
"""
|
||||
detect_platform.py — Inkscape config-path detection, cross-platform.
|
||||
|
||||
Shared by install.py and uninstall.py.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def _cmd_contains(cmd: list[str], pattern: str) -> bool:
|
||||
"""Run *cmd*; return True if stdout contains *pattern*."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
cmd, capture_output=True, text=True, timeout=5
|
||||
)
|
||||
return pattern in result.stdout
|
||||
except (FileNotFoundError, subprocess.TimeoutExpired):
|
||||
return False
|
||||
|
||||
|
||||
def detect_config() -> tuple[Path, str]:
|
||||
"""
|
||||
Return (inkscape_config_path, install_method).
|
||||
|
||||
install_method is one of: "flatpak", "snap", "native", "store"
|
||||
"""
|
||||
system = platform.system()
|
||||
if system == "Windows":
|
||||
return _detect_windows()
|
||||
if system == "Darwin":
|
||||
return _detect_macos()
|
||||
return _detect_linux()
|
||||
|
||||
|
||||
def _detect_linux() -> tuple[Path, str]:
|
||||
# Flatpak takes priority — most common modern Linux install
|
||||
flatpak_config = Path.home() / ".var/app/org.inkscape.Inkscape/config/inkscape"
|
||||
if flatpak_config.is_dir() or _cmd_contains(
|
||||
["flatpak", "list"], "org.inkscape.Inkscape"
|
||||
):
|
||||
return flatpak_config, "flatpak"
|
||||
|
||||
# Snap
|
||||
snap_config = Path.home() / "snap/inkscape/current/.config/inkscape"
|
||||
if snap_config.is_dir() or _cmd_contains(["snap", "list"], "inkscape"):
|
||||
return snap_config, "snap"
|
||||
|
||||
# Native / XDG
|
||||
xdg = Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config")) / "inkscape"
|
||||
return xdg, "native"
|
||||
|
||||
|
||||
def _detect_macos() -> tuple[Path, str]:
|
||||
# App Bundle (DMG install) stores config under ~/Library/Application Support
|
||||
app_support = (
|
||||
Path.home()
|
||||
/ "Library/Application Support/org.inkscape.Inkscape/config/inkscape"
|
||||
)
|
||||
if app_support.is_dir():
|
||||
return app_support, "native"
|
||||
# Homebrew / XDG fallback
|
||||
xdg = Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config")) / "inkscape"
|
||||
return xdg, "native"
|
||||
|
||||
|
||||
def _detect_windows() -> tuple[Path, str]:
|
||||
# MS Store — glob for the Packages directory
|
||||
local_appdata = os.environ.get("LOCALAPPDATA", "")
|
||||
if local_appdata:
|
||||
packages = Path(local_appdata) / "Packages"
|
||||
if packages.is_dir():
|
||||
matches = list(packages.glob("org.inkscape.Inkscape*"))
|
||||
if matches:
|
||||
return matches[0] / "LocalCache/Roaming/inkscape", "store"
|
||||
|
||||
# Native (winget / Scoop / chocolatey / official installer)
|
||||
appdata = Path(os.environ.get("APPDATA", Path.home() / "AppData/Roaming"))
|
||||
return appdata / "inkscape", "native"
|
||||
|
|
@ -9,23 +9,23 @@ _detect_inkscape_config() {
|
|||
# Flatpak takes priority — most common modern Linux install
|
||||
local flatpak_config="$HOME/.var/app/org.inkscape.Inkscape/config/inkscape"
|
||||
if [[ -d "$flatpak_config" ]] || flatpak list 2>/dev/null | grep -q "org.inkscape.Inkscape"; then
|
||||
INKSCAPE_CONFIG="$flatpak_config"
|
||||
INKSCAPE_INSTALL_METHOD="flatpak"
|
||||
export INKSCAPE_CONFIG="$flatpak_config"
|
||||
export INKSCAPE_INSTALL_METHOD="flatpak"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Snap
|
||||
local snap_config="$HOME/snap/inkscape/current/.config/inkscape"
|
||||
if [[ -d "$snap_config" ]] || snap list 2>/dev/null | grep -q "^inkscape "; then
|
||||
INKSCAPE_CONFIG="$snap_config"
|
||||
INKSCAPE_INSTALL_METHOD="snap"
|
||||
export INKSCAPE_CONFIG="$snap_config"
|
||||
export INKSCAPE_INSTALL_METHOD="snap"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Native / XDG
|
||||
local xdg_config="${XDG_CONFIG_HOME:-$HOME/.config}/inkscape"
|
||||
INKSCAPE_CONFIG="$xdg_config"
|
||||
INKSCAPE_INSTALL_METHOD="native"
|
||||
export INKSCAPE_CONFIG="$xdg_config"
|
||||
export INKSCAPE_INSTALL_METHOD="native"
|
||||
return 0
|
||||
}
|
||||
|
||||
|
|
|
|||
222
tests/test_install.py
Normal file
222
tests/test_install.py
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
"""
|
||||
Integration tests for install.py and uninstall.py — cross-platform.
|
||||
Replaces tests/test_install.bats.
|
||||
|
||||
Each test runs inside a fully isolated tmp_path with a fake inkscape binary
|
||||
injected via PATH and an overridden config home pointing to tmp_path.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
REPO = Path(__file__).parent.parent
|
||||
INSTALL_PY = REPO / "install.py"
|
||||
UNINSTALL_PY = REPO / "uninstall.py"
|
||||
|
||||
_FAKE_INKSCAPE_SH = """\
|
||||
#!/usr/bin/env sh
|
||||
case "$1" in
|
||||
--version) echo 'Inkscape 1.3.2 (1:1.3.2+202311252150+091e20ef0f)' ;;
|
||||
esac
|
||||
"""
|
||||
|
||||
_FAKE_INKSCAPE_BAT = """\
|
||||
@echo off
|
||||
if "%1"=="--version" echo Inkscape 1.3.2 (1:1.3.2+202311252150+091e20ef0f)
|
||||
"""
|
||||
|
||||
|
||||
def _make_fake_inkscape(bin_dir: Path) -> None:
|
||||
"""Create a platform-appropriate fake inkscape binary in *bin_dir*."""
|
||||
if platform.system() == "Windows":
|
||||
bat = bin_dir / "inkscape.bat"
|
||||
bat.write_text(_FAKE_INKSCAPE_BAT)
|
||||
else:
|
||||
script = bin_dir / "inkscape"
|
||||
script.write_text(_FAKE_INKSCAPE_SH)
|
||||
script.chmod(0o755)
|
||||
|
||||
|
||||
def _config_dir(tmp_path: Path) -> Path:
|
||||
"""
|
||||
Return the expected config path matching detect_config() for this platform
|
||||
when the env fixture overrides the config home to *tmp_path*.
|
||||
"""
|
||||
if platform.system() == "Windows":
|
||||
# install.py on Windows: APPDATA/inkscape
|
||||
return tmp_path / "config" / "inkscape"
|
||||
else:
|
||||
# install.py on Linux/macOS: XDG_CONFIG_HOME/inkscape
|
||||
return tmp_path / "config" / "inkscape"
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def env(tmp_path: Path):
|
||||
"""
|
||||
Isolated subprocess environment with a fake inkscape and a temp config dir.
|
||||
On Linux/macOS: overrides HOME and XDG_CONFIG_HOME.
|
||||
On Windows: overrides APPDATA and LOCALAPPDATA.
|
||||
"""
|
||||
bin_dir = tmp_path / "bin"
|
||||
bin_dir.mkdir()
|
||||
_make_fake_inkscape(bin_dir)
|
||||
|
||||
cfg_dir = _config_dir(tmp_path)
|
||||
cfg_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
base_env = os.environ.copy()
|
||||
base_env["PATH"] = str(bin_dir) + os.pathsep + base_env.get("PATH", "")
|
||||
# Block flatpak / snap detection inside subprocesses
|
||||
base_env.pop("FLATPAK_ID", None)
|
||||
|
||||
if platform.system() == "Windows":
|
||||
base_env["APPDATA"] = str(tmp_path / "config")
|
||||
base_env["LOCALAPPDATA"] = str(tmp_path / "local")
|
||||
else:
|
||||
base_env["XDG_CONFIG_HOME"] = str(tmp_path / "config")
|
||||
base_env["HOME"] = str(tmp_path)
|
||||
|
||||
return {
|
||||
"tmp_path": tmp_path,
|
||||
"config_dir": cfg_dir,
|
||||
"env": base_env,
|
||||
}
|
||||
|
||||
|
||||
def _run_install(env_fixture: dict, preset: str = "cc") -> subprocess.CompletedProcess[str]:
|
||||
return subprocess.run(
|
||||
[sys.executable, str(INSTALL_PY), "--yes", f"--preset={preset}"],
|
||||
env=env_fixture["env"],
|
||||
cwd=str(REPO),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
|
||||
def _run_uninstall(env_fixture: dict) -> subprocess.CompletedProcess[str]:
|
||||
return subprocess.run(
|
||||
[sys.executable, str(UNINSTALL_PY)],
|
||||
env=env_fixture["env"],
|
||||
cwd=str(REPO),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
|
||||
# ── install tests ─────────────────────────────────────────────────────────────
|
||||
|
||||
def test_install_creates_backup(env):
|
||||
result = _run_install(env)
|
||||
assert result.returncode == 0, result.stderr
|
||||
backups = list(env["tmp_path"].glob("config/inkscape.bak-illuscape-*"))
|
||||
assert backups, "No backup directory created"
|
||||
|
||||
|
||||
def test_install_backup_is_idempotent(env):
|
||||
_run_install(env)
|
||||
first_backups = sorted(env["tmp_path"].glob("config/inkscape.bak-illuscape-*"))
|
||||
_run_install(env)
|
||||
second_backups = sorted(env["tmp_path"].glob("config/inkscape.bak-illuscape-*"))
|
||||
assert first_backups == second_backups, "Second install created an extra backup"
|
||||
|
||||
|
||||
def test_install_cc_key_file(env):
|
||||
result = _run_install(env, preset="cc")
|
||||
assert result.returncode == 0, result.stderr
|
||||
assert (env["config_dir"] / "keys/illustrator-cc.xml").exists()
|
||||
|
||||
|
||||
def test_install_cs6_key_file(env):
|
||||
result = _run_install(env, preset="cs6")
|
||||
assert result.returncode == 0, result.stderr
|
||||
assert (env["config_dir"] / "keys/illustrator-cs6.xml").exists()
|
||||
|
||||
|
||||
def test_install_palettes(env):
|
||||
result = _run_install(env)
|
||||
assert result.returncode == 0, result.stderr
|
||||
for name in (
|
||||
"Illustrator-Defaults.gpl",
|
||||
"Illustrator-Grays.gpl",
|
||||
"Illustrator-Earth.gpl",
|
||||
):
|
||||
assert (env["config_dir"] / "palettes" / name).exists(), f"Missing palette: {name}"
|
||||
|
||||
|
||||
def test_install_templates(env):
|
||||
result = _run_install(env)
|
||||
assert result.returncode == 0, result.stderr
|
||||
for name in (
|
||||
"Letter.svg",
|
||||
"A4.svg",
|
||||
"Web-1920x1080.svg",
|
||||
"Web-1280x720.svg",
|
||||
"Print-CMYK-Letter.svg",
|
||||
"Print-CMYK-A4.svg",
|
||||
):
|
||||
assert (env["config_dir"] / "templates" / name).exists(), f"Missing template: {name}"
|
||||
|
||||
|
||||
def test_install_creates_prefs(env):
|
||||
result = _run_install(env)
|
||||
assert result.returncode == 0, result.stderr
|
||||
assert (env["config_dir"] / "preferences.xml").exists()
|
||||
|
||||
|
||||
def test_install_prefs_contains_units(env):
|
||||
result = _run_install(env)
|
||||
assert result.returncode == 0, result.stderr
|
||||
content = (env["config_dir"] / "preferences.xml").read_text()
|
||||
assert "px" in content or "pt" in content, "No unit setting found in preferences.xml"
|
||||
|
||||
|
||||
def test_install_noninteractive(env):
|
||||
"""--yes + --preset should exit 0 without any stdin."""
|
||||
result = _run_install(env)
|
||||
assert result.returncode == 0, f"Non-interactive install failed:\n{result.stderr}"
|
||||
|
||||
|
||||
# ── uninstall tests ───────────────────────────────────────────────────────────
|
||||
|
||||
def test_uninstall_restores_prefs(env):
|
||||
"""Original prefs.xml is restored after install + uninstall."""
|
||||
original_xml = '<inkscape version="1.0" />'
|
||||
(env["config_dir"] / "preferences.xml").write_text(original_xml)
|
||||
|
||||
_run_install(env)
|
||||
# prefs should now contain the patched version
|
||||
result = _run_uninstall(env)
|
||||
assert result.returncode == 0, result.stderr
|
||||
|
||||
restored = (env["config_dir"] / "preferences.xml").read_text()
|
||||
assert restored == original_xml, "prefs.xml was not restored to the original content"
|
||||
|
||||
|
||||
def test_uninstall_removes_palettes(env):
|
||||
_run_install(env)
|
||||
result = _run_uninstall(env)
|
||||
assert result.returncode == 0, result.stderr
|
||||
for name in (
|
||||
"Illustrator-Defaults.gpl",
|
||||
"Illustrator-Grays.gpl",
|
||||
"Illustrator-Earth.gpl",
|
||||
):
|
||||
assert not (
|
||||
env["config_dir"] / "palettes" / name
|
||||
).exists(), f"Palette was not removed: {name}"
|
||||
|
||||
|
||||
def test_uninstall_removes_templates(env):
|
||||
_run_install(env)
|
||||
result = _run_uninstall(env)
|
||||
assert result.returncode == 0, result.stderr
|
||||
for name in ("Letter.svg", "A4.svg"):
|
||||
assert not (
|
||||
env["config_dir"] / "templates" / name
|
||||
).exists(), f"Template was not removed: {name}"
|
||||
151
uninstall.py
Normal file
151
uninstall.py
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
#!/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()
|
||||
74
uninstall.sh
74
uninstall.sh
|
|
@ -1,74 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
# Illuscape uninstaller
|
||||
# Illuscape uninstaller — thin wrapper around uninstall.py
|
||||
# Usage: ./uninstall.sh
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
source "$SCRIPT_DIR/scripts/detect_platform.sh"
|
||||
|
||||
echo "╔══════════════════════════════╗"
|
||||
echo "║ Illuscape Uninstaller ║"
|
||||
echo "╚══════════════════════════════╝"
|
||||
echo ""
|
||||
echo "→ Inkscape config: $INKSCAPE_CONFIG"
|
||||
|
||||
# ── Find backup ───────────────────────────────────────────────────────────────
|
||||
BACKUP=$(ls -1d "${INKSCAPE_CONFIG}".bak-illuscape-* 2>/dev/null | sort | tail -1 || true)
|
||||
|
||||
if [[ -z "$BACKUP" ]]; then
|
||||
echo "⚠ No Illuscape backup found at ${INKSCAPE_CONFIG}.bak-illuscape-*"
|
||||
echo " Cannot restore original preferences.xml automatically."
|
||||
echo " Removing only Illuscape-installed files."
|
||||
else
|
||||
echo "→ Restoring preferences.xml from: $BACKUP"
|
||||
cp "$BACKUP/preferences.xml" "$INKSCAPE_CONFIG/preferences.xml" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# ── Remove Illuscape-installed files ─────────────────────────────────────────
|
||||
remove_files() {
|
||||
# Keys
|
||||
rm -f "$INKSCAPE_CONFIG/keys/illustrator-cc.xml"
|
||||
rm -f "$INKSCAPE_CONFIG/keys/illustrator-cs6.xml"
|
||||
|
||||
# Palettes
|
||||
rm -f "$INKSCAPE_CONFIG/palettes/Illustrator-Defaults.gpl"
|
||||
rm -f "$INKSCAPE_CONFIG/palettes/Illustrator-Grays.gpl"
|
||||
rm -f "$INKSCAPE_CONFIG/palettes/Illustrator-Earth.gpl"
|
||||
|
||||
# Templates
|
||||
rm -f "$INKSCAPE_CONFIG/templates/Letter.svg"
|
||||
rm -f "$INKSCAPE_CONFIG/templates/A4.svg"
|
||||
rm -f "$INKSCAPE_CONFIG/templates/Web-1920x1080.svg"
|
||||
rm -f "$INKSCAPE_CONFIG/templates/Web-1280x720.svg"
|
||||
rm -f "$INKSCAPE_CONFIG/templates/Print-CMYK-Letter.svg"
|
||||
rm -f "$INKSCAPE_CONFIG/templates/Print-CMYK-A4.svg"
|
||||
|
||||
# Symbols
|
||||
rm -f "$INKSCAPE_CONFIG/symbols/illuscape-common.svg"
|
||||
|
||||
# Splash
|
||||
rm -f "$INKSCAPE_CONFIG/splashscreens/illuscape-splash.png"
|
||||
|
||||
echo "→ Illuscape config files removed"
|
||||
}
|
||||
|
||||
remove_desktop() {
|
||||
[[ "$INKSCAPE_INSTALL_METHOD" != "native" ]] && return 0
|
||||
rm -f "$HOME/.local/share/applications/org.inkscape.Inkscape.desktop"
|
||||
for size in 16 32 48 64 128 256 512; do
|
||||
rm -f "$HOME/.local/share/icons/hicolor/${size}x${size}/apps/illuscape.png"
|
||||
done
|
||||
update-desktop-database "$HOME/.local/share/applications" 2>/dev/null || true
|
||||
echo "→ Desktop launcher removed"
|
||||
}
|
||||
|
||||
remove_files
|
||||
remove_desktop
|
||||
|
||||
echo ""
|
||||
echo "✓ Illuscape uninstalled."
|
||||
echo ""
|
||||
echo " Note: Your Inkscape preferences may have changed since Illuscape was"
|
||||
echo " installed. If anything looks wrong, review:"
|
||||
echo " $INKSCAPE_CONFIG/preferences.xml"
|
||||
echo ""
|
||||
exec python3 "$SCRIPT_DIR/uninstall.py"
|
||||
|
|
|
|||
Loading…
Reference in a new issue