dev-setup 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dev_setup-1.0.0/.gitignore +10 -0
- dev_setup-1.0.0/PKG-INFO +358 -0
- dev_setup-1.0.0/README.md +332 -0
- dev_setup-1.0.0/dev-setup +26 -0
- dev_setup-1.0.0/install.sh +25 -0
- dev_setup-1.0.0/pyproject.toml +46 -0
- dev_setup-1.0.0/src/dev_setup/__init__.py +1 -0
- dev_setup-1.0.0/src/dev_setup/__main__.py +9 -0
- dev_setup-1.0.0/src/dev_setup/base.py +78 -0
- dev_setup-1.0.0/src/dev_setup/cli.py +38 -0
- dev_setup-1.0.0/src/dev_setup/commands/__init__.py +0 -0
- dev_setup-1.0.0/src/dev_setup/commands/add_cmd.py +185 -0
- dev_setup-1.0.0/src/dev_setup/commands/delete_cmd.py +44 -0
- dev_setup-1.0.0/src/dev_setup/commands/help_cmd.py +46 -0
- dev_setup-1.0.0/src/dev_setup/commands/install_cmd.py +96 -0
- dev_setup-1.0.0/src/dev_setup/commands/list_cmd.py +57 -0
- dev_setup-1.0.0/src/dev_setup/commands/remove_cmd.py +50 -0
- dev_setup-1.0.0/src/dev_setup/generic.py +302 -0
- dev_setup-1.0.0/src/dev_setup/packages/__init__.py +0 -0
- dev_setup-1.0.0/src/dev_setup/packages/aws_cli.py +73 -0
- dev_setup-1.0.0/src/dev_setup/packages/docker.py +93 -0
- dev_setup-1.0.0/src/dev_setup/packages/htop.py +53 -0
- dev_setup-1.0.0/src/dev_setup/packages/nvm.py +84 -0
- dev_setup-1.0.0/src/dev_setup/packages/php.py +65 -0
- dev_setup-1.0.0/src/dev_setup/packages/saml2aws.py +100 -0
- dev_setup-1.0.0/src/dev_setup/packages/starship.py +65 -0
- dev_setup-1.0.0/src/dev_setup/packages/uv_tool.py +68 -0
- dev_setup-1.0.0/src/dev_setup/registry.py +78 -0
- dev_setup-1.0.0/src/dev_setup/ui.py +97 -0
- dev_setup-1.0.0/uv.lock +117 -0
dev_setup-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dev-setup
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Development environment setup CLI for Linux
|
|
5
|
+
Project-URL: Repository, https://github.com/thesawdawg/dev-setup-py
|
|
6
|
+
Author-email: Sawyer <sawyerksu@gmail.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Keywords: cli,developer,devtools,linux,setup
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: System :: Installation/Setup
|
|
20
|
+
Classifier: Topic :: Utilities
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: click>=8.1
|
|
23
|
+
Requires-Dist: questionary>=2.0
|
|
24
|
+
Requires-Dist: rich>=13.0
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# dev-setup
|
|
28
|
+
|
|
29
|
+
A Python-based CLI for managing your Linux development environment. Install, remove, and track developer tools from a single command — with an interactive picker, a guided wizard for adding custom packages, and a consistent Rich terminal UI.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## How it works
|
|
34
|
+
|
|
35
|
+
The entry point is a thin bash wrapper (`./dev-setup`) that bootstraps Python automatically:
|
|
36
|
+
|
|
37
|
+
1. Checks for `uv` on `PATH`; installs it via the official installer if missing
|
|
38
|
+
2. Runs `uv run --project <dir> python -m dev_setup` — uv provisions Python 3.11+ if needed
|
|
39
|
+
3. All further logic (commands, UI, installs) is pure Python
|
|
40
|
+
|
|
41
|
+
You never need to manually install Python or manage a virtualenv. The first invocation after a fresh clone may take a few seconds to resolve dependencies; every run after that is instant.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
git clone <repo-url> ~/dev-setup-py
|
|
49
|
+
cd ~/dev-setup-py
|
|
50
|
+
bash install.sh
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`install.sh` creates a symlink at `~/.local/bin/dev-setup` and ensures `~/.local/bin` is on `PATH` in `~/.bashrc`. Open a new terminal (or run `source ~/.bashrc`) and you're done.
|
|
54
|
+
|
|
55
|
+
> **Note:** Installing this tool symlinks `~/.local/bin/dev-setup`, which will replace an existing bash `dev-setup` at that path if you have one.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Commands
|
|
60
|
+
|
|
61
|
+
### `list`
|
|
62
|
+
|
|
63
|
+
Show all available packages with their install status, type, version, and help command.
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
dev-setup list # all packages
|
|
67
|
+
dev-setup list core # core category only
|
|
68
|
+
dev-setup list tools # tools category only
|
|
69
|
+
dev-setup list custom # custom/user-added packages only
|
|
70
|
+
dev-setup list --installed # only installed packages
|
|
71
|
+
dev-setup list --available # only packages not yet installed
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Output columns: status (✔/✘), package key, description, install type, version (if installed), help command.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
### `install`
|
|
79
|
+
|
|
80
|
+
Install one or more packages by key, or launch an interactive multi-select picker.
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
dev-setup install docker nvm # install specific packages
|
|
84
|
+
dev-setup install # interactive picker (Space to toggle, Enter to confirm)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The interactive picker shows all available packages with their current install status and lets you select multiple at once before confirming.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### `remove`
|
|
92
|
+
|
|
93
|
+
Uninstall an installed package. Always asks for confirmation before proceeding.
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
dev-setup remove htop
|
|
97
|
+
dev-setup uninstall htop # alias
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
### `add`
|
|
103
|
+
|
|
104
|
+
Guided wizard to register a new custom package. Supports six install types:
|
|
105
|
+
|
|
106
|
+
| Type | What it does |
|
|
107
|
+
|------|-------------|
|
|
108
|
+
| `npm` | `npm install -g <package>` |
|
|
109
|
+
| `pip` | `uv tool install <package>` (falls back to `pip3 install --user`) |
|
|
110
|
+
| `apt` | `sudo apt-get install -y <packages>` |
|
|
111
|
+
| `git` | `git clone --depth=1 <url>` with optional post-clone and pre-remove commands |
|
|
112
|
+
| `script` | `curl -fsSL <url> \| sh` — single-URL convenience script |
|
|
113
|
+
| `bash` | Arbitrary multi-step bash — opens `$EDITOR` for install and remove scripts |
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
dev-setup add
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The wizard collects type-specific fields, then prompts for a help command (e.g. `tool --help`). Packages are saved as JSON files in `~/.config/dev-setup/packages/`.
|
|
120
|
+
|
|
121
|
+
#### `bash` type
|
|
122
|
+
|
|
123
|
+
For tools like AWS CLI or saml2aws that require multiple download/extract/install steps, choose the `bash` type. The wizard opens `$EDITOR` twice — once for the install script and once for the optional remove script — with a `#!/usr/bin/env bash / set -euo pipefail` template pre-filled.
|
|
124
|
+
|
|
125
|
+
Example JSON for a `bash`-type custom package:
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"name": "batcat",
|
|
130
|
+
"description": "Modern cat with syntax highlighting",
|
|
131
|
+
"category": "custom",
|
|
132
|
+
"type": "bash",
|
|
133
|
+
"check_cmd": "bat",
|
|
134
|
+
"help_cmd": "bat --help",
|
|
135
|
+
"install_script": "set -euo pipefail\nVER=$(curl -s https://api.github.com/repos/sharkdp/bat/releases/latest | grep tag_name | cut -d'\"' -f4 | sed 's/v//')\ncurl -fsSL \"https://github.com/sharkdp/bat/releases/download/v${VER}/bat_${VER}_amd64.deb\" -o /tmp/bat.deb\nsudo dpkg -i /tmp/bat.deb && rm /tmp/bat.deb",
|
|
136
|
+
"remove_script": "sudo dpkg -r bat"
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### `delete`
|
|
143
|
+
|
|
144
|
+
Remove a custom package from the registry. Built-in packages cannot be deleted.
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
dev-setup delete my-tool
|
|
148
|
+
dev-setup rm my-tool # alias
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Asks for confirmation, then deletes the JSON file from `~/.config/dev-setup/packages/`.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Built-in packages
|
|
156
|
+
|
|
157
|
+
### Core
|
|
158
|
+
|
|
159
|
+
These are the foundation tools — install them on every machine.
|
|
160
|
+
|
|
161
|
+
| Key | Name | Description | Help |
|
|
162
|
+
|-----|------|-------------|------|
|
|
163
|
+
| `docker` | Docker | Container runtime + docker compose plugin | `docker --help` |
|
|
164
|
+
| `nvm` | NVM + Node LTS | Node Version Manager + latest Node LTS | `nvm help` |
|
|
165
|
+
| `uv` | uv | Astral Python package and project manager | `uv --help` |
|
|
166
|
+
|
|
167
|
+
### Tools
|
|
168
|
+
|
|
169
|
+
Optional utilities you may want on some machines.
|
|
170
|
+
|
|
171
|
+
| Key | Name | Description | Help |
|
|
172
|
+
|-----|------|-------------|------|
|
|
173
|
+
| `aws` | AWS CLI | Amazon Web Services CLI v2 | `aws help` |
|
|
174
|
+
| `htop` | htop | Interactive process and resource monitor | `man htop` |
|
|
175
|
+
| `php` | PHP 8.4 | PHP 8.4 + common extensions via ondrej/php PPA | `php --help` |
|
|
176
|
+
| `saml2aws` | saml2aws | SAML → AWS STS credentials CLI (Versent) | `saml2aws --help` |
|
|
177
|
+
| `starship` | Starship | Fast, cross-shell customizable prompt | `starship --help` |
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Custom packages
|
|
182
|
+
|
|
183
|
+
Custom packages live in `~/.config/dev-setup/packages/` as JSON files. Each file is named `<key>.json`. You can create them via `dev-setup add` or write them by hand.
|
|
184
|
+
|
|
185
|
+
### JSON fields
|
|
186
|
+
|
|
187
|
+
| Field | Required | Description |
|
|
188
|
+
|-------|----------|-------------|
|
|
189
|
+
| `name` | yes | Display name shown in `list` |
|
|
190
|
+
| `description` | no | Short description shown in `list` |
|
|
191
|
+
| `category` | no | `custom` (default), `core`, or `tools` |
|
|
192
|
+
| `type` | yes | `npm`, `pip`, `apt`, `git`, `script`, or `bash` |
|
|
193
|
+
| `check_cmd` | no | Binary name checked with `which` to detect install status |
|
|
194
|
+
| `help_cmd` | no | Command shown in `list` under the package entry |
|
|
195
|
+
| `npm_name` | npm | npm package name |
|
|
196
|
+
| `pip_name` | pip | PyPI package name |
|
|
197
|
+
| `apt_packages` | apt | Space-separated list of apt packages |
|
|
198
|
+
| `git_url` | git | Repository URL to clone |
|
|
199
|
+
| `git_install_cmd` | git | Bash command run inside the cloned repo after clone |
|
|
200
|
+
| `git_remove_cmd` | git | Bash command run inside the repo before deletion |
|
|
201
|
+
| `script_url` | script | URL passed to `curl -fsSL … \| sh` |
|
|
202
|
+
| `install_script` | bash | Full bash script to run on install |
|
|
203
|
+
| `remove_script` | bash | Full bash script to run on remove |
|
|
204
|
+
|
|
205
|
+
### Examples
|
|
206
|
+
|
|
207
|
+
**npm package:**
|
|
208
|
+
```json
|
|
209
|
+
{
|
|
210
|
+
"name": "Prettier",
|
|
211
|
+
"description": "Opinionated code formatter",
|
|
212
|
+
"type": "npm",
|
|
213
|
+
"npm_name": "prettier",
|
|
214
|
+
"check_cmd": "prettier",
|
|
215
|
+
"help_cmd": "prettier --help"
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**pip package:**
|
|
220
|
+
```json
|
|
221
|
+
{
|
|
222
|
+
"name": "httpie",
|
|
223
|
+
"description": "Human-friendly HTTP client",
|
|
224
|
+
"type": "pip",
|
|
225
|
+
"pip_name": "httpie",
|
|
226
|
+
"check_cmd": "http",
|
|
227
|
+
"help_cmd": "http --help"
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**apt package:**
|
|
232
|
+
```json
|
|
233
|
+
{
|
|
234
|
+
"name": "ripgrep",
|
|
235
|
+
"description": "Fast recursive search tool",
|
|
236
|
+
"type": "apt",
|
|
237
|
+
"apt_packages": "ripgrep",
|
|
238
|
+
"check_cmd": "rg",
|
|
239
|
+
"help_cmd": "rg --help"
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Multi-step bash install:**
|
|
244
|
+
```json
|
|
245
|
+
{
|
|
246
|
+
"name": "saml2aws (custom)",
|
|
247
|
+
"description": "SAML-to-AWS credential helper",
|
|
248
|
+
"type": "bash",
|
|
249
|
+
"check_cmd": "saml2aws",
|
|
250
|
+
"help_cmd": "saml2aws --help",
|
|
251
|
+
"install_script": "set -euo pipefail\nVER=$(curl -s https://api.github.com/repos/Versent/saml2aws/releases/latest | grep tag_name | cut -d'v' -f2 | cut -d'\"' -f1)\ncurl -fsSL \"https://github.com/Versent/saml2aws/releases/download/v${VER}/saml2aws_${VER}_linux_amd64.tar.gz\" | tar -xz -C /tmp\nsudo mv /tmp/saml2aws /usr/local/bin/saml2aws\nsudo chmod +x /usr/local/bin/saml2aws",
|
|
252
|
+
"remove_script": "sudo rm -f /usr/local/bin/saml2aws"
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Architecture
|
|
259
|
+
|
|
260
|
+
```
|
|
261
|
+
dev-setup-py/
|
|
262
|
+
├── dev-setup # Bash entry point — bootstraps uv, then exec's Python
|
|
263
|
+
├── install.sh # Symlinks dev-setup into ~/.local/bin
|
|
264
|
+
├── pyproject.toml # Python project (hatchling, requires-python >=3.11)
|
|
265
|
+
└── src/
|
|
266
|
+
└── dev_setup/
|
|
267
|
+
├── __main__.py # python -m dev_setup entry point
|
|
268
|
+
├── cli.py # Click group, command registration
|
|
269
|
+
├── base.py # Tool ABC, patch_bashrc / remove_bashrc_block utilities
|
|
270
|
+
├── registry.py # Auto-discovers Tool subclasses via pkgutil, loads custom JSON
|
|
271
|
+
├── generic.py # GenericTool — handles all 6 custom install types
|
|
272
|
+
├── ui.py # Rich console helpers, questionary wrappers, styled prompts
|
|
273
|
+
├── commands/
|
|
274
|
+
│ ├── list_cmd.py
|
|
275
|
+
│ ├── install_cmd.py
|
|
276
|
+
│ ├── remove_cmd.py
|
|
277
|
+
│ ├── add_cmd.py
|
|
278
|
+
│ └── delete_cmd.py
|
|
279
|
+
└── packages/ # Built-in Tool subclasses — one file per tool
|
|
280
|
+
├── docker.py
|
|
281
|
+
├── nvm.py
|
|
282
|
+
├── uv_tool.py
|
|
283
|
+
├── aws_cli.py
|
|
284
|
+
├── saml2aws.py
|
|
285
|
+
├── php.py
|
|
286
|
+
├── starship.py
|
|
287
|
+
└── htop.py
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Adding a new built-in tool
|
|
291
|
+
|
|
292
|
+
Create one file in `src/dev_setup/packages/`. The registry auto-discovers any class that subclasses `Tool` and has a non-empty `key` — no registration arrays to update.
|
|
293
|
+
|
|
294
|
+
```python
|
|
295
|
+
# src/dev_setup/packages/my_tool.py
|
|
296
|
+
import shutil, subprocess
|
|
297
|
+
from typing import Optional
|
|
298
|
+
from dev_setup.base import Tool
|
|
299
|
+
|
|
300
|
+
class MyTool(Tool):
|
|
301
|
+
key = "mytool"
|
|
302
|
+
name = "My Tool"
|
|
303
|
+
description = "Does something useful"
|
|
304
|
+
category = "tools" # "core", "tools", or "custom"
|
|
305
|
+
install_type = "script"
|
|
306
|
+
help_cmd = "mytool --help"
|
|
307
|
+
|
|
308
|
+
def is_installed(self) -> bool:
|
|
309
|
+
return shutil.which("mytool") is not None
|
|
310
|
+
|
|
311
|
+
def get_version(self) -> str:
|
|
312
|
+
r = subprocess.run(["mytool", "--version"], capture_output=True, text=True)
|
|
313
|
+
return r.stdout.strip() if r.returncode == 0 else ""
|
|
314
|
+
|
|
315
|
+
def install(self) -> Optional[str]:
|
|
316
|
+
from dev_setup import ui
|
|
317
|
+
with ui.spinner("Installing My Tool..."):
|
|
318
|
+
subprocess.run(["bash", "-c", "curl -fsSL https://example.com/install.sh | sh"],
|
|
319
|
+
check=True, capture_output=True)
|
|
320
|
+
if not self.is_installed():
|
|
321
|
+
raise RuntimeError("mytool binary not found after install")
|
|
322
|
+
return self.get_version()
|
|
323
|
+
|
|
324
|
+
def remove(self) -> None:
|
|
325
|
+
from dev_setup import ui
|
|
326
|
+
with ui.spinner("Removing My Tool..."):
|
|
327
|
+
subprocess.run(["sudo", "rm", "-f", "/usr/local/bin/mytool"],
|
|
328
|
+
check=True, capture_output=True)
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Key design decisions
|
|
332
|
+
|
|
333
|
+
- **uv owns Python provisioning.** The bash wrapper only guarantees uv is present; Python version and virtualenv management is delegated entirely to `uv run`.
|
|
334
|
+
- **Registry is auto-discovery.** `pkgutil.iter_modules` scans `packages/` for `Tool` subclasses — adding a built-in is a single file drop-in.
|
|
335
|
+
- **Custom packages are plain JSON.** No executable files in the registry; scripts are stored as strings and written to a temp file at install time, giving bash full parsing fidelity.
|
|
336
|
+
- **`install()` raises on failure.** Tools raise `RuntimeError` or `subprocess.CalledProcessError`; command handlers catch and report them. No `InstallResult` enum to check.
|
|
337
|
+
- **UI is import-isolated.** Package classes do `from dev_setup import ui` inside method bodies, keeping `is_installed()` and `get_version()` side-effect free and testable without terminal output.
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## Requirements
|
|
342
|
+
|
|
343
|
+
- Debian/Ubuntu Linux (apt-based; htop and php fall back to yum/dnf/pacman for detection)
|
|
344
|
+
- `curl` (for bootstrapping uv and install scripts)
|
|
345
|
+
- `git` (for `git`-type custom packages)
|
|
346
|
+
- `sudo` access (Docker, PHP, saml2aws, htop installs write to system paths)
|
|
347
|
+
|
|
348
|
+
Python 3.11+ is provisioned automatically by uv if not already present.
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## Dependencies
|
|
353
|
+
|
|
354
|
+
| Package | Version | Purpose |
|
|
355
|
+
|---------|---------|---------|
|
|
356
|
+
| `click` | ≥ 8.1 | CLI command dispatch, `--help` generation, editor integration |
|
|
357
|
+
| `rich` | ≥ 13.0 | Terminal UI — panels, tables, spinners, styled text |
|
|
358
|
+
| `questionary` | ≥ 2.0 | Interactive prompts — multi-select, confirm, text input |
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
# dev-setup
|
|
2
|
+
|
|
3
|
+
A Python-based CLI for managing your Linux development environment. Install, remove, and track developer tools from a single command — with an interactive picker, a guided wizard for adding custom packages, and a consistent Rich terminal UI.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## How it works
|
|
8
|
+
|
|
9
|
+
The entry point is a thin bash wrapper (`./dev-setup`) that bootstraps Python automatically:
|
|
10
|
+
|
|
11
|
+
1. Checks for `uv` on `PATH`; installs it via the official installer if missing
|
|
12
|
+
2. Runs `uv run --project <dir> python -m dev_setup` — uv provisions Python 3.11+ if needed
|
|
13
|
+
3. All further logic (commands, UI, installs) is pure Python
|
|
14
|
+
|
|
15
|
+
You never need to manually install Python or manage a virtualenv. The first invocation after a fresh clone may take a few seconds to resolve dependencies; every run after that is instant.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
git clone <repo-url> ~/dev-setup-py
|
|
23
|
+
cd ~/dev-setup-py
|
|
24
|
+
bash install.sh
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`install.sh` creates a symlink at `~/.local/bin/dev-setup` and ensures `~/.local/bin` is on `PATH` in `~/.bashrc`. Open a new terminal (or run `source ~/.bashrc`) and you're done.
|
|
28
|
+
|
|
29
|
+
> **Note:** Installing this tool symlinks `~/.local/bin/dev-setup`, which will replace an existing bash `dev-setup` at that path if you have one.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Commands
|
|
34
|
+
|
|
35
|
+
### `list`
|
|
36
|
+
|
|
37
|
+
Show all available packages with their install status, type, version, and help command.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
dev-setup list # all packages
|
|
41
|
+
dev-setup list core # core category only
|
|
42
|
+
dev-setup list tools # tools category only
|
|
43
|
+
dev-setup list custom # custom/user-added packages only
|
|
44
|
+
dev-setup list --installed # only installed packages
|
|
45
|
+
dev-setup list --available # only packages not yet installed
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Output columns: status (✔/✘), package key, description, install type, version (if installed), help command.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
### `install`
|
|
53
|
+
|
|
54
|
+
Install one or more packages by key, or launch an interactive multi-select picker.
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
dev-setup install docker nvm # install specific packages
|
|
58
|
+
dev-setup install # interactive picker (Space to toggle, Enter to confirm)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The interactive picker shows all available packages with their current install status and lets you select multiple at once before confirming.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
### `remove`
|
|
66
|
+
|
|
67
|
+
Uninstall an installed package. Always asks for confirmation before proceeding.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
dev-setup remove htop
|
|
71
|
+
dev-setup uninstall htop # alias
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
### `add`
|
|
77
|
+
|
|
78
|
+
Guided wizard to register a new custom package. Supports six install types:
|
|
79
|
+
|
|
80
|
+
| Type | What it does |
|
|
81
|
+
|------|-------------|
|
|
82
|
+
| `npm` | `npm install -g <package>` |
|
|
83
|
+
| `pip` | `uv tool install <package>` (falls back to `pip3 install --user`) |
|
|
84
|
+
| `apt` | `sudo apt-get install -y <packages>` |
|
|
85
|
+
| `git` | `git clone --depth=1 <url>` with optional post-clone and pre-remove commands |
|
|
86
|
+
| `script` | `curl -fsSL <url> \| sh` — single-URL convenience script |
|
|
87
|
+
| `bash` | Arbitrary multi-step bash — opens `$EDITOR` for install and remove scripts |
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
dev-setup add
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The wizard collects type-specific fields, then prompts for a help command (e.g. `tool --help`). Packages are saved as JSON files in `~/.config/dev-setup/packages/`.
|
|
94
|
+
|
|
95
|
+
#### `bash` type
|
|
96
|
+
|
|
97
|
+
For tools like AWS CLI or saml2aws that require multiple download/extract/install steps, choose the `bash` type. The wizard opens `$EDITOR` twice — once for the install script and once for the optional remove script — with a `#!/usr/bin/env bash / set -euo pipefail` template pre-filled.
|
|
98
|
+
|
|
99
|
+
Example JSON for a `bash`-type custom package:
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"name": "batcat",
|
|
104
|
+
"description": "Modern cat with syntax highlighting",
|
|
105
|
+
"category": "custom",
|
|
106
|
+
"type": "bash",
|
|
107
|
+
"check_cmd": "bat",
|
|
108
|
+
"help_cmd": "bat --help",
|
|
109
|
+
"install_script": "set -euo pipefail\nVER=$(curl -s https://api.github.com/repos/sharkdp/bat/releases/latest | grep tag_name | cut -d'\"' -f4 | sed 's/v//')\ncurl -fsSL \"https://github.com/sharkdp/bat/releases/download/v${VER}/bat_${VER}_amd64.deb\" -o /tmp/bat.deb\nsudo dpkg -i /tmp/bat.deb && rm /tmp/bat.deb",
|
|
110
|
+
"remove_script": "sudo dpkg -r bat"
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
### `delete`
|
|
117
|
+
|
|
118
|
+
Remove a custom package from the registry. Built-in packages cannot be deleted.
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
dev-setup delete my-tool
|
|
122
|
+
dev-setup rm my-tool # alias
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Asks for confirmation, then deletes the JSON file from `~/.config/dev-setup/packages/`.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Built-in packages
|
|
130
|
+
|
|
131
|
+
### Core
|
|
132
|
+
|
|
133
|
+
These are the foundation tools — install them on every machine.
|
|
134
|
+
|
|
135
|
+
| Key | Name | Description | Help |
|
|
136
|
+
|-----|------|-------------|------|
|
|
137
|
+
| `docker` | Docker | Container runtime + docker compose plugin | `docker --help` |
|
|
138
|
+
| `nvm` | NVM + Node LTS | Node Version Manager + latest Node LTS | `nvm help` |
|
|
139
|
+
| `uv` | uv | Astral Python package and project manager | `uv --help` |
|
|
140
|
+
|
|
141
|
+
### Tools
|
|
142
|
+
|
|
143
|
+
Optional utilities you may want on some machines.
|
|
144
|
+
|
|
145
|
+
| Key | Name | Description | Help |
|
|
146
|
+
|-----|------|-------------|------|
|
|
147
|
+
| `aws` | AWS CLI | Amazon Web Services CLI v2 | `aws help` |
|
|
148
|
+
| `htop` | htop | Interactive process and resource monitor | `man htop` |
|
|
149
|
+
| `php` | PHP 8.4 | PHP 8.4 + common extensions via ondrej/php PPA | `php --help` |
|
|
150
|
+
| `saml2aws` | saml2aws | SAML → AWS STS credentials CLI (Versent) | `saml2aws --help` |
|
|
151
|
+
| `starship` | Starship | Fast, cross-shell customizable prompt | `starship --help` |
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Custom packages
|
|
156
|
+
|
|
157
|
+
Custom packages live in `~/.config/dev-setup/packages/` as JSON files. Each file is named `<key>.json`. You can create them via `dev-setup add` or write them by hand.
|
|
158
|
+
|
|
159
|
+
### JSON fields
|
|
160
|
+
|
|
161
|
+
| Field | Required | Description |
|
|
162
|
+
|-------|----------|-------------|
|
|
163
|
+
| `name` | yes | Display name shown in `list` |
|
|
164
|
+
| `description` | no | Short description shown in `list` |
|
|
165
|
+
| `category` | no | `custom` (default), `core`, or `tools` |
|
|
166
|
+
| `type` | yes | `npm`, `pip`, `apt`, `git`, `script`, or `bash` |
|
|
167
|
+
| `check_cmd` | no | Binary name checked with `which` to detect install status |
|
|
168
|
+
| `help_cmd` | no | Command shown in `list` under the package entry |
|
|
169
|
+
| `npm_name` | npm | npm package name |
|
|
170
|
+
| `pip_name` | pip | PyPI package name |
|
|
171
|
+
| `apt_packages` | apt | Space-separated list of apt packages |
|
|
172
|
+
| `git_url` | git | Repository URL to clone |
|
|
173
|
+
| `git_install_cmd` | git | Bash command run inside the cloned repo after clone |
|
|
174
|
+
| `git_remove_cmd` | git | Bash command run inside the repo before deletion |
|
|
175
|
+
| `script_url` | script | URL passed to `curl -fsSL … \| sh` |
|
|
176
|
+
| `install_script` | bash | Full bash script to run on install |
|
|
177
|
+
| `remove_script` | bash | Full bash script to run on remove |
|
|
178
|
+
|
|
179
|
+
### Examples
|
|
180
|
+
|
|
181
|
+
**npm package:**
|
|
182
|
+
```json
|
|
183
|
+
{
|
|
184
|
+
"name": "Prettier",
|
|
185
|
+
"description": "Opinionated code formatter",
|
|
186
|
+
"type": "npm",
|
|
187
|
+
"npm_name": "prettier",
|
|
188
|
+
"check_cmd": "prettier",
|
|
189
|
+
"help_cmd": "prettier --help"
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**pip package:**
|
|
194
|
+
```json
|
|
195
|
+
{
|
|
196
|
+
"name": "httpie",
|
|
197
|
+
"description": "Human-friendly HTTP client",
|
|
198
|
+
"type": "pip",
|
|
199
|
+
"pip_name": "httpie",
|
|
200
|
+
"check_cmd": "http",
|
|
201
|
+
"help_cmd": "http --help"
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**apt package:**
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"name": "ripgrep",
|
|
209
|
+
"description": "Fast recursive search tool",
|
|
210
|
+
"type": "apt",
|
|
211
|
+
"apt_packages": "ripgrep",
|
|
212
|
+
"check_cmd": "rg",
|
|
213
|
+
"help_cmd": "rg --help"
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Multi-step bash install:**
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"name": "saml2aws (custom)",
|
|
221
|
+
"description": "SAML-to-AWS credential helper",
|
|
222
|
+
"type": "bash",
|
|
223
|
+
"check_cmd": "saml2aws",
|
|
224
|
+
"help_cmd": "saml2aws --help",
|
|
225
|
+
"install_script": "set -euo pipefail\nVER=$(curl -s https://api.github.com/repos/Versent/saml2aws/releases/latest | grep tag_name | cut -d'v' -f2 | cut -d'\"' -f1)\ncurl -fsSL \"https://github.com/Versent/saml2aws/releases/download/v${VER}/saml2aws_${VER}_linux_amd64.tar.gz\" | tar -xz -C /tmp\nsudo mv /tmp/saml2aws /usr/local/bin/saml2aws\nsudo chmod +x /usr/local/bin/saml2aws",
|
|
226
|
+
"remove_script": "sudo rm -f /usr/local/bin/saml2aws"
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Architecture
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
dev-setup-py/
|
|
236
|
+
├── dev-setup # Bash entry point — bootstraps uv, then exec's Python
|
|
237
|
+
├── install.sh # Symlinks dev-setup into ~/.local/bin
|
|
238
|
+
├── pyproject.toml # Python project (hatchling, requires-python >=3.11)
|
|
239
|
+
└── src/
|
|
240
|
+
└── dev_setup/
|
|
241
|
+
├── __main__.py # python -m dev_setup entry point
|
|
242
|
+
├── cli.py # Click group, command registration
|
|
243
|
+
├── base.py # Tool ABC, patch_bashrc / remove_bashrc_block utilities
|
|
244
|
+
├── registry.py # Auto-discovers Tool subclasses via pkgutil, loads custom JSON
|
|
245
|
+
├── generic.py # GenericTool — handles all 6 custom install types
|
|
246
|
+
├── ui.py # Rich console helpers, questionary wrappers, styled prompts
|
|
247
|
+
├── commands/
|
|
248
|
+
│ ├── list_cmd.py
|
|
249
|
+
│ ├── install_cmd.py
|
|
250
|
+
│ ├── remove_cmd.py
|
|
251
|
+
│ ├── add_cmd.py
|
|
252
|
+
│ └── delete_cmd.py
|
|
253
|
+
└── packages/ # Built-in Tool subclasses — one file per tool
|
|
254
|
+
├── docker.py
|
|
255
|
+
├── nvm.py
|
|
256
|
+
├── uv_tool.py
|
|
257
|
+
├── aws_cli.py
|
|
258
|
+
├── saml2aws.py
|
|
259
|
+
├── php.py
|
|
260
|
+
├── starship.py
|
|
261
|
+
└── htop.py
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Adding a new built-in tool
|
|
265
|
+
|
|
266
|
+
Create one file in `src/dev_setup/packages/`. The registry auto-discovers any class that subclasses `Tool` and has a non-empty `key` — no registration arrays to update.
|
|
267
|
+
|
|
268
|
+
```python
|
|
269
|
+
# src/dev_setup/packages/my_tool.py
|
|
270
|
+
import shutil, subprocess
|
|
271
|
+
from typing import Optional
|
|
272
|
+
from dev_setup.base import Tool
|
|
273
|
+
|
|
274
|
+
class MyTool(Tool):
|
|
275
|
+
key = "mytool"
|
|
276
|
+
name = "My Tool"
|
|
277
|
+
description = "Does something useful"
|
|
278
|
+
category = "tools" # "core", "tools", or "custom"
|
|
279
|
+
install_type = "script"
|
|
280
|
+
help_cmd = "mytool --help"
|
|
281
|
+
|
|
282
|
+
def is_installed(self) -> bool:
|
|
283
|
+
return shutil.which("mytool") is not None
|
|
284
|
+
|
|
285
|
+
def get_version(self) -> str:
|
|
286
|
+
r = subprocess.run(["mytool", "--version"], capture_output=True, text=True)
|
|
287
|
+
return r.stdout.strip() if r.returncode == 0 else ""
|
|
288
|
+
|
|
289
|
+
def install(self) -> Optional[str]:
|
|
290
|
+
from dev_setup import ui
|
|
291
|
+
with ui.spinner("Installing My Tool..."):
|
|
292
|
+
subprocess.run(["bash", "-c", "curl -fsSL https://example.com/install.sh | sh"],
|
|
293
|
+
check=True, capture_output=True)
|
|
294
|
+
if not self.is_installed():
|
|
295
|
+
raise RuntimeError("mytool binary not found after install")
|
|
296
|
+
return self.get_version()
|
|
297
|
+
|
|
298
|
+
def remove(self) -> None:
|
|
299
|
+
from dev_setup import ui
|
|
300
|
+
with ui.spinner("Removing My Tool..."):
|
|
301
|
+
subprocess.run(["sudo", "rm", "-f", "/usr/local/bin/mytool"],
|
|
302
|
+
check=True, capture_output=True)
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Key design decisions
|
|
306
|
+
|
|
307
|
+
- **uv owns Python provisioning.** The bash wrapper only guarantees uv is present; Python version and virtualenv management is delegated entirely to `uv run`.
|
|
308
|
+
- **Registry is auto-discovery.** `pkgutil.iter_modules` scans `packages/` for `Tool` subclasses — adding a built-in is a single file drop-in.
|
|
309
|
+
- **Custom packages are plain JSON.** No executable files in the registry; scripts are stored as strings and written to a temp file at install time, giving bash full parsing fidelity.
|
|
310
|
+
- **`install()` raises on failure.** Tools raise `RuntimeError` or `subprocess.CalledProcessError`; command handlers catch and report them. No `InstallResult` enum to check.
|
|
311
|
+
- **UI is import-isolated.** Package classes do `from dev_setup import ui` inside method bodies, keeping `is_installed()` and `get_version()` side-effect free and testable without terminal output.
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Requirements
|
|
316
|
+
|
|
317
|
+
- Debian/Ubuntu Linux (apt-based; htop and php fall back to yum/dnf/pacman for detection)
|
|
318
|
+
- `curl` (for bootstrapping uv and install scripts)
|
|
319
|
+
- `git` (for `git`-type custom packages)
|
|
320
|
+
- `sudo` access (Docker, PHP, saml2aws, htop installs write to system paths)
|
|
321
|
+
|
|
322
|
+
Python 3.11+ is provisioned automatically by uv if not already present.
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## Dependencies
|
|
327
|
+
|
|
328
|
+
| Package | Version | Purpose |
|
|
329
|
+
|---------|---------|---------|
|
|
330
|
+
| `click` | ≥ 8.1 | CLI command dispatch, `--help` generation, editor integration |
|
|
331
|
+
| `rich` | ≥ 13.0 | Terminal UI — panels, tables, spinners, styled text |
|
|
332
|
+
| `questionary` | ≥ 2.0 | Interactive prompts — multi-select, confirm, text input |
|