personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at d18a7c02359cd827d0ff15058861de5c2600a96f 167 lines 4.4 kB view raw
1# SPDX-License-Identifier: AGPL-3.0-only 2# Copyright (c) 2026 sol pbc 3 4"""Guard user-level sol alias ownership.""" 5 6from __future__ import annotations 7 8import os 9import sys 10from enum import Enum 11from pathlib import Path 12 13 14class AliasState(Enum): 15 WORKTREE = "worktree" 16 ABSENT = "absent" 17 OWNED = "owned" 18 CROSS_REPO = "cross_repo" 19 DANGLING = "dangling" 20 NOT_SYMLINK = "not_symlink" 21 22 23def alias_path() -> Path: 24 return Path.home() / ".local" / "bin" / "sol" 25 26 27def expected_target(curdir: Path) -> Path: 28 return curdir / ".venv" / "bin" / "sol" 29 30 31def check_alias(curdir: Path) -> tuple[AliasState, Path | None]: 32 if (curdir / ".git").is_file(): 33 return AliasState.WORKTREE, None 34 35 alias = alias_path() 36 if not alias.exists() and not alias.is_symlink(): 37 return AliasState.ABSENT, None 38 39 if alias.is_symlink(): 40 target = Path(os.readlink(alias)) 41 if not target.is_absolute(): 42 target = alias.parent / target 43 target = target.resolve() 44 if not target.exists(): 45 return AliasState.DANGLING, target 46 if target == expected_target(curdir).resolve(): 47 return AliasState.OWNED, target 48 return AliasState.CROSS_REPO, target 49 50 return AliasState.NOT_SYMLINK, None 51 52 53def format_error( 54 state: AliasState, 55 curdir: Path, 56 _alias: Path, 57 other_target: Path | None, 58) -> str: 59 if state is AliasState.WORKTREE: 60 return ( 61 f"ERROR: refusing to run from a git worktree ({curdir}). " 62 "Run from the primary clone." 63 ) 64 65 if state is AliasState.CROSS_REPO: 66 installed = f" installed: {other_target}" 67 elif state is AliasState.DANGLING: 68 installed = f" installed: dangling: {other_target} does not exist" 69 else: 70 installed = " installed: not a symlink" 71 72 return "\n".join( 73 [ 74 "ERROR: Another solstone install owns ~/.local/bin/sol.", 75 f" this repo: {curdir}", 76 installed, 77 "Run 'make uninstall-service' from the installed repo first,", 78 "or remove ~/.local/bin/sol manually if that repo is gone. No --force available.", 79 ] 80 ) 81 82 83def _print_error( 84 state: AliasState, 85 curdir: Path, 86 alias: Path, 87 other_target: Path | None, 88) -> None: 89 sys.stderr.write(format_error(state, curdir, alias, other_target) + "\n") 90 91 92def cmd_check(curdir: Path) -> int: 93 alias = alias_path() 94 state, other_target = check_alias(curdir) 95 96 if state is AliasState.ABSENT: 97 print("fresh") 98 return 0 99 if state is AliasState.OWNED: 100 print("upgrade") 101 return 0 102 103 print(state.value) 104 _print_error(state, curdir, alias, other_target) 105 return 1 106 107 108def cmd_install(curdir: Path) -> int: 109 alias = alias_path() 110 state, other_target = check_alias(curdir) 111 112 if state is AliasState.WORKTREE: 113 _print_error(state, curdir, alias, other_target) 114 return 1 115 if state is AliasState.ABSENT: 116 alias.parent.mkdir(parents=True, exist_ok=True) 117 alias.symlink_to(expected_target(curdir)) 118 print("installed") 119 return 0 120 if state is AliasState.OWNED: 121 alias.unlink() 122 alias.symlink_to(expected_target(curdir)) 123 print("installed") 124 return 0 125 126 _print_error(state, curdir, alias, other_target) 127 return 1 128 129 130def cmd_uninstall(curdir: Path) -> int: 131 alias = alias_path() 132 state, other_target = check_alias(curdir) 133 134 if state is AliasState.WORKTREE: 135 _print_error(state, curdir, alias, other_target) 136 return 1 137 if state is AliasState.ABSENT: 138 print("absent") 139 return 0 140 if state is AliasState.OWNED: 141 alias.unlink() 142 print("removed") 143 return 0 144 145 _print_error(state, curdir, alias, other_target) 146 return 1 147 148 149def main(argv: list[str] | None = None) -> int: 150 if argv is None: 151 argv = sys.argv[1:] 152 if len(argv) != 1 or argv[0] not in {"check", "install", "uninstall"}: 153 sys.stderr.write( 154 "usage: python -m think.install_guard <check|install|uninstall>\n" 155 ) 156 return 2 157 158 curdir = Path.cwd().resolve() 159 if argv[0] == "check": 160 return cmd_check(curdir) 161 if argv[0] == "install": 162 return cmd_install(curdir) 163 return cmd_uninstall(curdir) 164 165 166if __name__ == "__main__": 167 sys.exit(main())