dev-setup 1.2.0__tar.gz → 1.4.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.
Files changed (47) hide show
  1. dev_setup-1.4.0/.claude/settings.local.json +11 -0
  2. dev_setup-1.4.0/.github/workflows/publish.yml +44 -0
  3. {dev_setup-1.2.0 → dev_setup-1.4.0}/CHANGELOG.md +12 -0
  4. {dev_setup-1.2.0 → dev_setup-1.4.0}/PKG-INFO +1 -1
  5. {dev_setup-1.2.0 → dev_setup-1.4.0}/pyproject.toml +1 -1
  6. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/base.py +1 -0
  7. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/commands/install_cmd.py +17 -9
  8. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/commands/list_cmd.py +3 -0
  9. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/generic.py +12 -0
  10. dev_setup-1.4.0/src/dev_setup/packages/eza.py +59 -0
  11. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/packages/pi_agent.py +1 -0
  12. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/registry.py +9 -0
  13. {dev_setup-1.2.0 → dev_setup-1.4.0}/uv.lock +1 -1
  14. dev_setup-1.2.0/.claude/settings.local.json +0 -9
  15. {dev_setup-1.2.0 → dev_setup-1.4.0}/.gitignore +0 -0
  16. {dev_setup-1.2.0 → dev_setup-1.4.0}/README.md +0 -0
  17. {dev_setup-1.2.0 → dev_setup-1.4.0}/app-design-output/recommendations.md +0 -0
  18. {dev_setup-1.2.0 → dev_setup-1.4.0}/dev/Dockerfile +0 -0
  19. {dev_setup-1.2.0 → dev_setup-1.4.0}/dev/Makefile +0 -0
  20. {dev_setup-1.2.0 → dev_setup-1.4.0}/dev/docker-compose.yml +0 -0
  21. {dev_setup-1.2.0 → dev_setup-1.4.0}/dev-setup +0 -0
  22. {dev_setup-1.2.0 → dev_setup-1.4.0}/install.sh +0 -0
  23. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/__init__.py +0 -0
  24. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/__main__.py +0 -0
  25. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/cli.py +0 -0
  26. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/commands/__init__.py +0 -0
  27. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/commands/add_cmd.py +0 -0
  28. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/commands/delete_cmd.py +0 -0
  29. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/commands/docs_cmd.py +0 -0
  30. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/commands/help_cmd.py +0 -0
  31. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/commands/remove_cmd.py +0 -0
  32. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/packages/__init__.py +0 -0
  33. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/packages/aws_cli.py +0 -0
  34. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/packages/docker.py +0 -0
  35. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/packages/gh.py +0 -0
  36. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/packages/go.py +0 -0
  37. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/packages/htop.py +0 -0
  38. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/packages/java.py +0 -0
  39. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/packages/mkcert.py +0 -0
  40. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/packages/nvm.py +0 -0
  41. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/packages/ollama.py +0 -0
  42. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/packages/php.py +0 -0
  43. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/packages/ruby.py +0 -0
  44. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/packages/saml2aws.py +0 -0
  45. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/packages/starship.py +0 -0
  46. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/packages/uv_tool.py +0 -0
  47. {dev_setup-1.2.0 → dev_setup-1.4.0}/src/dev_setup/ui.py +0 -0
@@ -0,0 +1,11 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(uv run *)",
5
+ "Bash(docker build *)",
6
+ "Bash(git -C /home/sawyer/Documents/Projects/ClaudeProjects/dev-setup-py log --format=\"%H %ai %s\")",
7
+ "Bash(git -C /home/sawyer/Documents/Projects/ClaudeProjects/dev-setup-py add src/dev_setup/packages/eza.py)",
8
+ "Bash(git -C /home/sawyer/Documents/Projects/ClaudeProjects/dev-setup-py commit -m ' *)"
9
+ ]
10
+ }
11
+ }
@@ -0,0 +1,44 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ build:
10
+ name: Build distribution
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - name: Install uv
16
+ uses: astral-sh/setup-uv@v5
17
+
18
+ - name: Build wheel and source distribution
19
+ run: uv build
20
+
21
+ - name: Upload dist artifacts
22
+ uses: actions/upload-artifact@v4
23
+ with:
24
+ name: dist
25
+ path: dist/
26
+
27
+ publish:
28
+ name: Publish to PyPI
29
+ needs: build
30
+ runs-on: ubuntu-latest
31
+ environment:
32
+ name: pypi
33
+ url: https://pypi.org/p/dev-setup
34
+ permissions:
35
+ id-token: write # required for OIDC trusted publishing
36
+ steps:
37
+ - name: Download dist artifacts
38
+ uses: actions/download-artifact@v4
39
+ with:
40
+ name: dist
41
+ path: dist/
42
+
43
+ - name: Publish to PyPI
44
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -1,3 +1,15 @@
1
+ ## v1.4.0 (2026-06-19)
2
+
3
+ ### Feat
4
+
5
+ - add eza builtin tool
6
+
7
+ ## v1.3.0 (2026-06-19)
8
+
9
+ ### Feat
10
+
11
+ - gate tool availability on required dependencies
12
+
1
13
  ## v1.2.0 (2026-06-19)
2
14
 
3
15
  ### Feat
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dev-setup
3
- Version: 1.2.0
3
+ Version: 1.4.0
4
4
  Summary: Development environment setup CLI for Linux
5
5
  Project-URL: Repository, https://github.com/thesawdawg/dev-setup-py
6
6
  Author-email: Sawyer <sawyerksu@gmail.com>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "dev-setup"
3
- version = "1.2.0"
3
+ version = "1.4.0"
4
4
  description = "Development environment setup CLI for Linux"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -16,6 +16,7 @@ class Tool(ABC):
16
16
  builtin: bool = True
17
17
  help_cmd: str = ""
18
18
  docs_url: str = ""
19
+ requires: list = [] # keys of tools that must be installed before this one
19
20
 
20
21
  @abstractmethod
21
22
  def is_installed(self) -> bool: ...
@@ -38,6 +38,11 @@ def _install_one(tool: Tool) -> bool:
38
38
  if tool.is_installed():
39
39
  ui.success(f"{tool.name} is already installed: {tool.get_version()}")
40
40
  return True
41
+ missing = registry.missing_requires(tool)
42
+ if missing:
43
+ ui.error(f"Cannot install {tool.name} — missing required tools: {', '.join(missing)}")
44
+ ui.dim(f"Install first: dev-setup install {' '.join(missing)}")
45
+ return False
41
46
  try:
42
47
  version = tool.install()
43
48
  msg = f"{tool.name} installed"
@@ -54,17 +59,20 @@ def _install_interactive() -> None:
54
59
  ui.print_banner()
55
60
  tools = registry.all_tools()
56
61
 
57
- choices = [
58
- questionary.Choice(
59
- title=(
60
- f"{'[installed] ' if t.is_installed() else ''}"
61
- f"{t.key:<14} {t.description}"
62
- ),
62
+ choices = []
63
+ for t in tools:
64
+ is_inst = t.is_installed()
65
+ missing = registry.missing_requires(t) if not is_inst else []
66
+ label = (
67
+ f"{'[installed] ' if is_inst else ''}"
68
+ f"{t.key:<14} {t.description}"
69
+ )
70
+ choices.append(questionary.Choice(
71
+ title=label,
63
72
  value=t.key,
64
73
  checked=False,
65
- )
66
- for t in tools
67
- ]
74
+ disabled=f"requires {', '.join(missing)}" if missing else False,
75
+ ))
68
76
 
69
77
  selected = questionary.checkbox(
70
78
  "Select packages to install (Space to toggle, Enter to confirm):",
@@ -48,11 +48,14 @@ def list_cmd(show_filter: str, category: str) -> None:
48
48
  tbl.add_column("Version", style="dim")
49
49
 
50
50
  for tool, is_inst in entries:
51
+ missing = registry.missing_requires(tool) if not is_inst else []
51
52
  icon = "[green bold]✔[/]" if is_inst else "[red bold]✘[/]"
52
53
  version = tool.get_version() if is_inst else ""
53
54
  tbl.add_row(icon, tool.key, tool.description, tool.install_type, version)
54
55
  if tool.help_cmd:
55
56
  tbl.add_row("", "", f"[dim cyan] ? {tool.help_cmd}[/]", "", "")
57
+ if missing:
58
+ tbl.add_row("", "", f"[yellow] ⚠ requires: {', '.join(missing)}[/]", "", "")
56
59
 
57
60
  ui.console.print(tbl)
58
61
  ui.console.print()
@@ -48,6 +48,7 @@ class GenericTool(Tool):
48
48
  remove_script: str = "",
49
49
  help_cmd: str = "",
50
50
  docs_url: str = "",
51
+ requires: Optional[list] = None,
51
52
  ) -> None:
52
53
  self.key = key
53
54
  self.name = name
@@ -66,6 +67,13 @@ class GenericTool(Tool):
66
67
  self.remove_script = remove_script
67
68
  self.help_cmd = help_cmd
68
69
  self.docs_url = docs_url
70
+ # npm packages need nvm/node; explicit requires in JSON takes precedence
71
+ if requires is not None:
72
+ self.requires = requires
73
+ elif install_type == "npm":
74
+ self.requires = ["nvm"]
75
+ else:
76
+ self.requires = []
69
77
 
70
78
  @classmethod
71
79
  def from_dict(cls, data: dict, key: str) -> "GenericTool":
@@ -87,6 +95,7 @@ class GenericTool(Tool):
87
95
  remove_script=data.get("remove_script", ""),
88
96
  help_cmd=data.get("help_cmd", ""),
89
97
  docs_url=data.get("docs_url", ""),
98
+ requires=data.get("requires") or None,
90
99
  )
91
100
 
92
101
  def to_dict(self) -> dict:
@@ -112,6 +121,9 @@ class GenericTool(Tool):
112
121
  ]:
113
122
  if val:
114
123
  d[field] = val
124
+ # Only persist explicit requires — auto-inferred ones are re-derived on load
125
+ if self.requires and not (self.install_type == "npm" and self.requires == ["nvm"]):
126
+ d["requires"] = self.requires
115
127
  return d
116
128
 
117
129
  def save(self) -> None:
@@ -0,0 +1,59 @@
1
+ from __future__ import annotations
2
+
3
+ import subprocess
4
+ from typing import Optional
5
+
6
+ from dev_setup.base import WhichTool
7
+
8
+
9
+ class EzaTool(WhichTool):
10
+ key = "eza"
11
+ name = "eza"
12
+ description = "Modern ls replacement with git status, icons, and tree view"
13
+ category = "tools"
14
+ install_type = "script"
15
+ help_cmd = "eza --help"
16
+ docs_url = "https://eza.rocks/"
17
+
18
+ def install(self) -> Optional[str]:
19
+ from dev_setup import ui
20
+
21
+ ui.info("Adding eza apt repository...")
22
+ subprocess.run(
23
+ [
24
+ "bash", "-c",
25
+ "wget -qO- https://raw.githubusercontent.com/eza-community/eza/main/deb.asc"
26
+ " | sudo gpg --dearmor -o /etc/apt/keyrings/gierens.gpg"
27
+ " && echo 'deb [signed-by=/etc/apt/keyrings/gierens.gpg]"
28
+ " http://deb.gierens.de stable main'"
29
+ " | sudo tee /etc/apt/sources.list.d/gierens.list > /dev/null"
30
+ " && sudo chmod 644 /etc/apt/keyrings/gierens.gpg"
31
+ " /etc/apt/sources.list.d/gierens.list",
32
+ ],
33
+ check=True, capture_output=True,
34
+ )
35
+
36
+ with ui.spinner("Updating package index..."):
37
+ subprocess.run(["sudo", "apt-get", "update", "-q"], check=True, capture_output=True)
38
+
39
+ ui.info("Installing eza...")
40
+ subprocess.run(["sudo", "apt-get", "install", "-y", "eza"], check=True, capture_output=True)
41
+
42
+ if not self.is_installed():
43
+ raise RuntimeError("eza installation failed — binary not found")
44
+ return self.get_version()
45
+
46
+ def remove(self) -> None:
47
+ from dev_setup import ui
48
+
49
+ with ui.spinner("Removing eza..."):
50
+ subprocess.run(
51
+ ["sudo", "apt-get", "remove", "-y", "eza"],
52
+ check=True, capture_output=True,
53
+ )
54
+ subprocess.run(
55
+ ["sudo", "rm", "-f",
56
+ "/etc/apt/keyrings/gierens.gpg",
57
+ "/etc/apt/sources.list.d/gierens.list"],
58
+ check=True, capture_output=True,
59
+ )
@@ -16,6 +16,7 @@ class PiAgentTool(Tool):
16
16
  install_type = "npm"
17
17
  help_cmd = "pi --help"
18
18
  docs_url = "https://www.npmjs.com/package/pi-coding-agent"
19
+ requires = ["nvm"]
19
20
 
20
21
  def is_installed(self) -> bool:
21
22
  try:
@@ -90,3 +90,12 @@ def deregister(key: str) -> None:
90
90
  _registry.pop(key, None)
91
91
  if key in _order:
92
92
  _order.remove(key)
93
+
94
+
95
+ def missing_requires(tool: Tool) -> list:
96
+ """Return keys in tool.requires that are not currently installed."""
97
+ init()
98
+ return [
99
+ key for key in tool.requires
100
+ if key not in _registry or not _registry[key].is_installed()
101
+ ]
@@ -167,7 +167,7 @@ wheels = [
167
167
 
168
168
  [[package]]
169
169
  name = "dev-setup"
170
- version = "1.2.0"
170
+ version = "1.3.0"
171
171
  source = { editable = "." }
172
172
  dependencies = [
173
173
  { name = "click" },
@@ -1,9 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(uv run *)",
5
- "Bash(docker build *)",
6
- "Bash(git -C /home/sawyer/Documents/Projects/ClaudeProjects/dev-setup-py log --format=\"%H %ai %s\")"
7
- ]
8
- }
9
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes