spacr.install_cleanup

Find spaCR installations and run the appropriate update or removal procedure.

The online installers stage and validate the new runtime before retiring old application copies. They preserve the current installation during staging and restore its previous runtime if the replacement fails verification. The update helper verifies the desktop interpreter and imported application before retiring other copies or requesting a restart. run_update_sequence() remains the low-level removal procedure used by explicit cleanup commands.

Supported macOS online installations and dedicated POSIX or Windows pip environments use their existing package tool to stage and verify an updated sibling runtime before requesting Restart. Activation requires approved shutdown. Bootstrap files, launchers, unchanged packages and the previous runtime are retained. Shared and Conda environments require their own replacement adapter.

A supported frozen macOS, Windows or Debian installation stages its verified replacement while the desktop remains open. Protected installations obtain graphical administrator authorization before requesting Restart. Activation requires approved shutdown and actual process exit; recovery data remains until the updated desktop confirms its identity and main window.

Ordinary removal preserves preferences and user data. The confirmed GUI uninstall instead previews current or all detected installations and separate cleanup categories, selected by default with individual opt-outs. Protected removal uses only a validated installed helper with the required protocol; authorization, preparation and approved desktop exit precede deletion. Unrelated projects, unverified data and shared environments are preserved.

A pip or conda environment the user made is listed but never deleted; the spaCR package is uninstalled from it only when the caller says it was ticked. An editable source checkout is reported and left alone.

The module uses only the standard library and imports nothing from spaCR, so an installer can run it with its bootstrapped Python before any spaCR exists, and a helper process can run a copy of it after the running spaCR has closed:

python -I install_cleanup.py find [--json]
python -I install_cleanup.py remove [--keep PATH] [--sudo] [--purge [--yes]]
python -I install_cleanup.py purge [--yes] [--dry-run]
python -I install_cleanup.py run-plan PLAN.json

purge is the opt-in clean uninstall: it also deletes spaCR’s caches, backend environments and user data, after listing them and asking. It never runs on its own; remove --purge runs it after the removal succeeded.

Classes

InstallRecord

One spaCR installation found on this computer.

RemovalReport

What remove_install() did with one installation.

Functions

apply_optional_cleanup(preview, choices, *[, system, ...])

Apply a fresh selected-cache action under the application's live run guard.

find_old_installs(→ List[InstallRecord])

Find every spaCR installation on this computer.

preview_optional_cleanup(operation_id, *[, system, guard])

Inspect dedicated caches and offer selection only under a live run guard.

remove_install([system])

Remove one installation, without running its own uninstaller.

run_update_sequence(install, *[, records, ticked, ...])

Remove old installations; install only if every installer-made copy is gone.

start_update_helper(, pid, workdir[, system, spawn])

Run an installation update in a process that outlives spaCR.

Module Contents

class spacr.install_cleanup.InstallRecord[source]

One spaCR installation found on this computer.

Parameters:
  • kind – "installer" for a copy a spaCR installer made, "environment" for a pip or conda environment the user made, or "checkout" for an editable source checkout.

  • layout – which layout it is, for example "windows-online", "linux-online", "macos-app" or "conda".

  • platform – "windows", "macos" or "linux".

  • root – the directory the installation lives in.

  • version – the spaCR version, when it can be read.

  • launchers – command launchers that start this copy.

  • shortcuts – desktop and Start Menu shortcut files.

  • menu_entries – application-menu entries: .desktop files and Start Menu folders.

  • registrations – uninstall registrations: registry: keys, deb: packages, and application bundles.

  • python – the environment’s interpreter, used to uninstall spaCR.

  • running – whether the current process runs from this copy.

  • needs_admin – whether removal needs administrator rights.

  • notes – other facts worth showing, such as a missing uninstaller.

class spacr.install_cleanup.RemovalReport[source]

What remove_install() did with one installation.

Parameters:
  • record – the installation this report is about.

  • removed – every path, registry entry and package that was removed.

  • failed – (item, reason) for everything that could not be removed.

  • skipped – (item, reason) for everything left in place on purpose.

property ok: bool[source]

Whether nothing failed.

spacr.install_cleanup.apply_optional_cleanup(preview, choices, *, system=None, guard=None)[source]

Apply a fresh selected-cache action under the application’s live run guard.

Only a trusted Python context-manager factory can enable execution. The application’s caller must hold its established run-registration lock and refuse active work throughout the context. This is an application-local safeguard, not proof that every other process is idle. A separate helper or saved dictionary cannot grant that authority.

Every selected snapshot is validated before mutation. Each action identity is consumed once in this process. Changed, unknown or locked detached entries remain in private staging; no recursive deletion or overwriting restoration is performed. Models, data and other protected roots cannot be selected. Supported no-follow directory descriptors are required.

Parameters:
  • preview – Immutable result of preview_optional_cleanup().

  • choices – Current operation ID, snapshot ID and explicitly chosen registered cache keys returned by the GUI.

  • system – Optional isolated machine adapter used for reinspection.

  • guard – Trusted live context-manager factory receiving derived paths; it yields None only while application-local cleanup is permitted.

Returns:

Action outcome with a refusal reason or removed counts and any private retained paths.

spacr.install_cleanup.find_old_installs(*, system=None) → List[InstallRecord][source]

Find every spaCR installation on this computer.

Installer-made copies come first, then environments the user made, then editable source checkouts. Every layout any released installer used is looked for: the Windows online and offline installers, the Linux and macOS online installers, the macOS application bundle, and the Debian package.

Parameters:

system – the computer to look at; None means this one. Tests pass a stand-in over a temporary directory.

Returns:

one InstallRecord per installation.

spacr.install_cleanup.preview_optional_cleanup(operation_id, *, system=None, guard=None)[source]

Inspect dedicated caches and offer selection only under a live run guard.

Recognized cache contents are inspected only under the default spaCR home. A bounded relocation manifest may also be read from a configured spaCR home to display retained external paths. External, symlinked, unknown and protected cache contents remain unavailable. Inspection is bounded and never follows links. A trusted live application guard can enable candidates; a saved selection cannot authorize removal. This does not establish that every other application instance is idle.

Parameters:
  • operation_id – Fresh identity supplied by the current installer or update coordinator, independent of saved privacy preferences.

  • system – Optional machine adapter for isolated filesystem checks.

  • guard – Optional trusted live context-manager factory receiving derived candidate paths and yielding None only while cleanup is permitted.

Returns:

An immutable operation-bound preview with actual paths, content sizes and a snapshot identity. Without a live guard, removal stays disabled. No file is changed during inspection.

Raises:

ValueError – The operation identity is empty or invalid.

spacr.install_cleanup.remove_install(record: InstallRecord, *, ticked: bool = False, keep: Sequence[str] = (), system=None) → RemovalReport[source]

Remove one installation, without running its own uninstaller.

An installer-made copy’s application code, launchers, shortcuts, menu entries and uninstall registrations are removed. Known caches, models, test data, configured user locations and non-application entries in online runtime roots are kept. Its root can remain to hold those files. A Debian package is removed through the package manager, and reported as needing administrator rights when that is what stops it. From an environment the user made, only the spaCR package is uninstalled, and only when ticked; the environment itself stays. A source checkout is skipped.

The running copy is not removed here, because on Windows an installation cannot delete itself while it runs. start_update_helper() runs the appropriate update procedure after spaCR has closed.

Parameters:
  • record – an installation from find_old_installs().

  • ticked – whether the user ticked this environment for removal.

  • keep – paths to leave in place, such as the log of the install that is about to start.

  • system – the computer; None means this one.

Returns:

what was removed, what could not be, and why.

spacr.install_cleanup.run_update_sequence(install: Callable[[], object], *, records: Sequence[InstallRecord] | None = None, ticked: Iterable[str] = (), keep: Sequence[str] = (), find=None, remove=None, system=None)[source]

Remove old installations; install only if every installer-made copy is gone.

Every installer-made copy is removed, the spaCR package is uninstalled from each ticked environment, and only then is install called. When an installer-made copy could not be removed, install is not called at all, and the reports say what stopped it.

Parameters:
  • install – zero-argument callable that installs the new version.

  • records – installations already found; find_old_installs() is called when None.

  • ticked – roots of the environments the user ticked.

  • keep – paths removal must leave in place.

  • find – replaces find_old_installs().

  • remove – replaces remove_install().

  • system – the computer; None means this one.

Returns:

(reports, install_result); install_result is None when the install was not run.

spacr.install_cleanup.start_update_helper(records: Sequence[InstallRecord], version: str, *, ticked: Iterable[str] = (), pid: int | None = None, workdir: str | None = None, system=None, spawn=None) → Dict[source]

Run an installation update in a process that outlives spaCR.

Installer-made copies and supported dedicated POSIX or Windows pip environments can use this helper. It stages replacements while the current application runs and requires authenticated shutdown approval and actual process exit before activation.

For a supported macOS online installation, use the existing bundled uv and private Python to install the requested spaCR release into a staged sibling environment. Preserve bootstrap files, the application launcher, and packages that need no update. After verified staging and approved shutdown, activate the staged environment at the existing runtime path and retain the complete previous environment for recovery. Relaunch verifies the requested version, executable, imported module and visible main window. Failed preparation leaves the running environment unchanged.

Runtime adapters install and verify a private replacement before publishing readiness. The GUI offers Restart and preserves its settings before approving shutdown. Relaunch verifies the actual new desktop process and its main window. Unsupported layouts refuse before starting an installer.

Parameters:
  • records – installations from find_old_installs().

  • version – the version to install.

  • ticked – roots of the environments the user ticked.

  • pid – the process to wait for; this process when None.

  • workdir – the helper’s folder; a new temporary folder when None.

  • system – the computer; None means this one.

  • spawn – replaces the detached process launcher.

Returns:

the plan as written to plan.json. plan["command"] is the helper’s command, or None with plan["error"] saying why nothing was started.

Frozen macOS, Windows and protocol-marked Debian installations use their verified native replacement adapters. Protected macOS requires an installed helper with the current native phase protocol. Windows requires a separately published, checksummed update executable. Administrator authorization and staging precede Restart; activation follows approved desktop exit. The new desktop must confirm its identity and main window before recovery files are retired. Unsupported layouts or missing capabilities leave the running application unchanged; no ordinary-installer fallback is enabled.

Nested helpers

_coordinate_native_update._run_authorized()

Retain the native worker’s completion or error until its owned process finishes.

spacr/install_cleanup.py:5168

_coordinate_native_update._stopped()

Check desktop cancellation before observing native worker completion.

spacr/install_cleanup.py:5177

_delete._writable_then_retry(func, failed_path, exc_info)

Clear a read-only flag and retry once, recording failures.

Parameters:
  • func – the os function that failed.

  • failed_path – the path it failed on.

  • exc_info – the error, as shutil.rmtree() passes it.

spacr/install_cleanup.py:1187

_macos_recover_user_bundle.identity(path)

Return the device and inode of a journaled bundle directory.

Parameters:

path – journaled bundle directory to identify.

Returns:

JSON-compatible device/inode pair.

spacr/install_cleanup.py:4580

_macos_replace_user_bundle.identity(path)

Record the actual directory identity before or after the exchange.

Parameters:

path – bundle directory whose device and inode are recorded.

Returns:

JSON-compatible device/inode pair.

spacr/install_cleanup.py:3999

_macos_tree.refuse_unreadable(error)

Propagate a filesystem traversal failure instead of omitting its subtree.

Parameters:

error – operating-system exception reported by os.walk.

spacr/install_cleanup.py:3797

_macos_uninstall_tree.visit(parent, name, absolute)

Remove one verified child through its parent descriptor while preserving selected paths.

spacr/install_cleanup.py:2570

_run_debian_update._check_current()

Bind activation to the same installed Debian package and trusted helper.

spacr/install_cleanup.py:6494

_run_macos_frozen_update._authorized(endpoint)

Request one native authorization for trusted staging and deferred activation.

spacr/install_cleanup.py:4441

_run_macos_frozen_update._new_desktop()

Verify the activated release and wait for its actual main window.

spacr/install_cleanup.py:4448

_run_macos_frozen_update._unchanged()

Refuse activation if the installed bundle or authenticated image changed.

spacr/install_cleanup.py:4433

_run_macos_online_update.prepared()

Offer Restart only after the replacement passes its staged checks.

spacr/install_cleanup.py:6144

_run_native_uninstall.stopped()

Check desktop cancellation before observing the authorized helper’s completion.

spacr/install_cleanup.py:2668

_run_pip_environment_update.prepared()

Keep the running environment until the verified replacement is accepted.

spacr/install_cleanup.py:7748

_run_plan._finish(code: int) → int

Write the update log and return code.

Parameters:

code – the exit code to return.

spacr/install_cleanup.py:8608

_run_windows_frozen_update._check_current()

Recheck the pinned installer and unchanged Windows destination before activation.

spacr/install_cleanup.py:8203

_run_windows_frozen_update._launch_verified()

Confirm the activated Windows payload and its unelevated main window.

spacr/install_cleanup.py:8211

_run_windows_native_uninstall.authorize()

Retain the native uninstaller’s bootstrap result until authenticated completion.

spacr/install_cleanup.py:2851

_run_windows_native_uninstall.stopped()

Treat failed native startup as stopped without confusing bootstrap exit with completion.

spacr/install_cleanup.py:2858

_run_windows_pip_update.prepared()

Request shutdown only when the private replacement is verified.

spacr/install_cleanup.py:7438

_standalone_helper_command.contains(path, root)

Compare canonical paths using the host filesystem’s case semantics.

Parameters:
  • path – candidate nested path.

  • root – containing directory to check.

Returns:

whether the candidate resolves inside the directory.

spacr/install_cleanup.py:4660

_transactional_runtime_update.note(phase)

Persist the current update phase in the transaction journal using an atomic file replacement.

spacr/install_cleanup.py:5975

_uninstall_data_candidates.expand(value)

Expand the configured user’s leading home marker.

spacr/install_cleanup.py:2092

preview_optional_cleanup.normalized(value, *, expand=True)

Return an absolute display path using the writer’s tilde rule.

Parameters:
  • value – Configured or default path text.

  • expand – Whether this writer expands a leading user-home marker.

Returns:

Absolute path text without inspecting cache contents.

spacr/install_cleanup.py:9372

preview_optional_cleanup.retained_path(variable, default)

Resolve a retained cache path with external override precedence.

Parameters:
  • variable – Registered cache environment-variable name.

  • default – Fallback when neither environment nor relocation supplies it.

Returns:

Normalized display path; its protected contents are not scanned.

spacr/install_cleanup.py:9447