devlaunch 0.0.5__tar.gz → 0.0.7__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.
- {devlaunch-0.0.5 → devlaunch-0.0.7}/.gitignore +5 -0
- devlaunch-0.0.5/README.md → devlaunch-0.0.7/PKG-INFO +69 -1
- devlaunch-0.0.5/PKG-INFO → devlaunch-0.0.7/README.md +46 -22
- devlaunch-0.0.7/devlaunch/completions/dl.bash +158 -0
- {devlaunch-0.0.5 → devlaunch-0.0.7}/devlaunch/dl.py +522 -142
- devlaunch-0.0.7/devlaunch/worktree/__init__.py +19 -0
- devlaunch-0.0.7/devlaunch/worktree/branch_manager.py +237 -0
- devlaunch-0.0.7/devlaunch/worktree/config.py +116 -0
- devlaunch-0.0.7/devlaunch/worktree/models.py +66 -0
- devlaunch-0.0.7/devlaunch/worktree/repo_manager.py +297 -0
- devlaunch-0.0.7/devlaunch/worktree/storage.py +131 -0
- devlaunch-0.0.7/devlaunch/worktree/workspace_clone.py +359 -0
- {devlaunch-0.0.5 → devlaunch-0.0.7}/pyproject.toml +21 -10
- devlaunch-0.0.5/devlaunch/completions/dl.bash +0 -96
- {devlaunch-0.0.5 → devlaunch-0.0.7}/LICENSE +0 -0
- {devlaunch-0.0.5 → devlaunch-0.0.7}/devlaunch/__init__.py +0 -0
- {devlaunch-0.0.5 → devlaunch-0.0.7}/devlaunch/completion.py +0 -0
- {devlaunch-0.0.5 → devlaunch-0.0.7}/devlaunch/completion_loader.py +0 -0
- {devlaunch-0.0.5 → devlaunch-0.0.7}/devlaunch/completions/__init__.py +0 -0
|
@@ -50,6 +50,7 @@ coverage.xml
|
|
|
50
50
|
.hypothesis/
|
|
51
51
|
.pytest_cache/
|
|
52
52
|
cover/
|
|
53
|
+
test/docker/results/
|
|
53
54
|
|
|
54
55
|
# Translations
|
|
55
56
|
*.mo
|
|
@@ -191,3 +192,7 @@ test_suite_analysis/metadata.json
|
|
|
191
192
|
progress.json
|
|
192
193
|
status.json
|
|
193
194
|
logs/
|
|
195
|
+
.ralph/
|
|
196
|
+
|
|
197
|
+
# uv is not this project's package manager (pixi.lock is authoritative)
|
|
198
|
+
uv.lock
|
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: devlaunch
|
|
3
|
+
Version: 0.0.7
|
|
4
|
+
Summary: DevLaunch - A streamlined CLI for devpod workspaces
|
|
5
|
+
Project-URL: Source, https://github.com/blooop/devlaunch
|
|
6
|
+
Project-URL: Home, https://github.com/blooop/devlaunch
|
|
7
|
+
Author-email: Austin Gregg-Smith <blooop@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: iterfzf>=1.0.0
|
|
11
|
+
Requires-Dist: tomli-w>=1.0.0
|
|
12
|
+
Requires-Dist: tomli>=2.0.0
|
|
13
|
+
Provides-Extra: test
|
|
14
|
+
Requires-Dist: coverage<=7.14.1,>=7.5.4; extra == 'test'
|
|
15
|
+
Requires-Dist: hypothesis<=6.155.1,>=6.104.2; extra == 'test'
|
|
16
|
+
Requires-Dist: prek<0.5.0,>=0.2.28; extra == 'test'
|
|
17
|
+
Requires-Dist: pylint<=4.0.5,>=3.2.5; extra == 'test'
|
|
18
|
+
Requires-Dist: pytest-cov<=7.1.0,>=4.1; extra == 'test'
|
|
19
|
+
Requires-Dist: pytest<=9.0.3,>=7.4; extra == 'test'
|
|
20
|
+
Requires-Dist: ruff<=0.15.15,>=0.5.0; extra == 'test'
|
|
21
|
+
Requires-Dist: ty<=0.0.19,>=0.0.12; extra == 'test'
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
1
24
|
# devlaunch
|
|
2
25
|
|
|
3
26
|
A streamlined CLI for [devpod](https://devpod.sh) with intuitive autocomplete and fzf fuzzy selection.
|
|
@@ -10,7 +33,7 @@ A streamlined CLI for [devpod](https://devpod.sh) with intuitive autocomplete an
|
|
|
10
33
|
[](https://github.com/blooop/devlaunch/pulls?q=is%3Amerged)
|
|
11
34
|
[](https://GitHub.com/blooop/devlaunch/releases/)
|
|
12
35
|
[](https://pypi.org/project/devlaunch/)
|
|
13
|
-
[](https://prefix.dev/channels/blooop/packages/devlaunch)
|
|
14
37
|
[](https://opensource.org/license/mit/)
|
|
15
38
|
[](https://www.python.org/downloads/)
|
|
16
39
|
[](https://pixi.sh)
|
|
@@ -72,12 +95,25 @@ dl ./path # Create from local path
|
|
|
72
95
|
| `dl <user/repo> reset` | Clean slate (remove all, recreate) |
|
|
73
96
|
| `dl <user/repo> -- <command>` | Run shell command in workspace |
|
|
74
97
|
|
|
98
|
+
## Options
|
|
99
|
+
|
|
100
|
+
| Option | Description |
|
|
101
|
+
|--------|-------------|
|
|
102
|
+
| `--devcontainer <variant\|path>` | Use a non-default `devcontainer.json`. A bare name means `.devcontainer/<name>/devcontainer.json`. Stored with the workspace, so pass it once. |
|
|
103
|
+
|
|
104
|
+
Projects with demanding devcontainers — several variants, compose sidecars, or a
|
|
105
|
+
host-side `initializeCommand` that has to tell branch workspaces apart — are
|
|
106
|
+
covered in [docs/devcontainer-projects.md](docs/devcontainer-projects.md).
|
|
107
|
+
|
|
75
108
|
## Global Commands
|
|
76
109
|
|
|
77
110
|
| Command | Description |
|
|
78
111
|
|---------|-------------|
|
|
79
112
|
| `dl --ls` | List all workspaces |
|
|
80
113
|
| `dl --install` | Install shell completions |
|
|
114
|
+
| `dl --purge [-y]` | Remove all devlaunch data |
|
|
115
|
+
| `dl --prune-worktrees [days]` | Remove unused worktrees (default: 30 days) |
|
|
116
|
+
| `dl --refresh` | Refresh completion cache |
|
|
81
117
|
| `dl --help, -h` | Show this help |
|
|
82
118
|
| `dl --version` | Show version |
|
|
83
119
|
|
|
@@ -102,6 +138,38 @@ dl blooop/devlaunch stop # Stop workspace
|
|
|
102
138
|
- **Branch Support**: Specify branches with `owner/repo@branch` syntax
|
|
103
139
|
- **Fast Autocomplete**: Completion cache for ~3ms response time (vs ~700ms without cache)
|
|
104
140
|
|
|
141
|
+
## Worktree Backend
|
|
142
|
+
|
|
143
|
+
For git repositories, devlaunch uses an efficient worktree backend by default:
|
|
144
|
+
|
|
145
|
+
- **Efficient Storage**: Repos are cloned once to `~/.cache/devlaunch/repos/owner/repo/`, then git worktrees are created for each branch
|
|
146
|
+
- **Shared Git Objects**: All branches share git objects, saving disk space
|
|
147
|
+
- **Lazy Fetch**: Remote updates are only fetched if the configured interval has elapsed (default: 1 hour)
|
|
148
|
+
|
|
149
|
+
### Container Sharing Mode
|
|
150
|
+
|
|
151
|
+
Use `--shared` to share a single container across multiple branches of the same repo:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
dl --shared owner/repo@branch1 # Creates container "owner-repo"
|
|
155
|
+
dl --shared owner/repo@branch2 # Reuses "owner-repo" container
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Pre-warming
|
|
159
|
+
|
|
160
|
+
Use `--warm` to prepare a workspace without attaching a shell:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
dl --warm owner/repo@branch # Creates container in background
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Backend Selection
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
dl --backend devpod owner/repo # Force legacy DevPod backend
|
|
170
|
+
DEVLAUNCH_BACKEND=devpod dl owner/repo # Use environment variable
|
|
171
|
+
```
|
|
172
|
+
|
|
105
173
|
## Shell Completion
|
|
106
174
|
|
|
107
175
|
After running `dl --install`, you get intelligent tab completion:
|
|
@@ -1,24 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: devlaunch
|
|
3
|
-
Version: 0.0.5
|
|
4
|
-
Summary: DevLaunch - A streamlined CLI for devpod workspaces
|
|
5
|
-
Project-URL: Source, https://github.com/blooop/devlaunch
|
|
6
|
-
Project-URL: Home, https://github.com/blooop/devlaunch
|
|
7
|
-
Author-email: Austin Gregg-Smith <blooop@gmail.com>
|
|
8
|
-
License-Expression: MIT
|
|
9
|
-
License-File: LICENSE
|
|
10
|
-
Requires-Dist: iterfzf>=1.0.0
|
|
11
|
-
Provides-Extra: test
|
|
12
|
-
Requires-Dist: coverage<=7.13.1,>=7.5.4; extra == 'test'
|
|
13
|
-
Requires-Dist: hypothesis<=6.150.2,>=6.104.2; extra == 'test'
|
|
14
|
-
Requires-Dist: prek<0.3.0,>=0.2.28; extra == 'test'
|
|
15
|
-
Requires-Dist: pylint<=4.0.4,>=3.2.5; extra == 'test'
|
|
16
|
-
Requires-Dist: pytest-cov<=7.0.0,>=4.1; extra == 'test'
|
|
17
|
-
Requires-Dist: pytest<=9.0.2,>=7.4; extra == 'test'
|
|
18
|
-
Requires-Dist: ruff<=0.14.13,>=0.5.0; extra == 'test'
|
|
19
|
-
Requires-Dist: ty<=0.0.12,>=0.0.12; extra == 'test'
|
|
20
|
-
Description-Content-Type: text/markdown
|
|
21
|
-
|
|
22
1
|
# devlaunch
|
|
23
2
|
|
|
24
3
|
A streamlined CLI for [devpod](https://devpod.sh) with intuitive autocomplete and fzf fuzzy selection.
|
|
@@ -31,7 +10,7 @@ A streamlined CLI for [devpod](https://devpod.sh) with intuitive autocomplete an
|
|
|
31
10
|
[](https://github.com/blooop/devlaunch/pulls?q=is%3Amerged)
|
|
32
11
|
[](https://GitHub.com/blooop/devlaunch/releases/)
|
|
33
12
|
[](https://pypi.org/project/devlaunch/)
|
|
34
|
-
[](https://prefix.dev/channels/blooop/packages/devlaunch)
|
|
35
14
|
[](https://opensource.org/license/mit/)
|
|
36
15
|
[](https://www.python.org/downloads/)
|
|
37
16
|
[](https://pixi.sh)
|
|
@@ -93,12 +72,25 @@ dl ./path # Create from local path
|
|
|
93
72
|
| `dl <user/repo> reset` | Clean slate (remove all, recreate) |
|
|
94
73
|
| `dl <user/repo> -- <command>` | Run shell command in workspace |
|
|
95
74
|
|
|
75
|
+
## Options
|
|
76
|
+
|
|
77
|
+
| Option | Description |
|
|
78
|
+
|--------|-------------|
|
|
79
|
+
| `--devcontainer <variant\|path>` | Use a non-default `devcontainer.json`. A bare name means `.devcontainer/<name>/devcontainer.json`. Stored with the workspace, so pass it once. |
|
|
80
|
+
|
|
81
|
+
Projects with demanding devcontainers — several variants, compose sidecars, or a
|
|
82
|
+
host-side `initializeCommand` that has to tell branch workspaces apart — are
|
|
83
|
+
covered in [docs/devcontainer-projects.md](docs/devcontainer-projects.md).
|
|
84
|
+
|
|
96
85
|
## Global Commands
|
|
97
86
|
|
|
98
87
|
| Command | Description |
|
|
99
88
|
|---------|-------------|
|
|
100
89
|
| `dl --ls` | List all workspaces |
|
|
101
90
|
| `dl --install` | Install shell completions |
|
|
91
|
+
| `dl --purge [-y]` | Remove all devlaunch data |
|
|
92
|
+
| `dl --prune-worktrees [days]` | Remove unused worktrees (default: 30 days) |
|
|
93
|
+
| `dl --refresh` | Refresh completion cache |
|
|
102
94
|
| `dl --help, -h` | Show this help |
|
|
103
95
|
| `dl --version` | Show version |
|
|
104
96
|
|
|
@@ -123,6 +115,38 @@ dl blooop/devlaunch stop # Stop workspace
|
|
|
123
115
|
- **Branch Support**: Specify branches with `owner/repo@branch` syntax
|
|
124
116
|
- **Fast Autocomplete**: Completion cache for ~3ms response time (vs ~700ms without cache)
|
|
125
117
|
|
|
118
|
+
## Worktree Backend
|
|
119
|
+
|
|
120
|
+
For git repositories, devlaunch uses an efficient worktree backend by default:
|
|
121
|
+
|
|
122
|
+
- **Efficient Storage**: Repos are cloned once to `~/.cache/devlaunch/repos/owner/repo/`, then git worktrees are created for each branch
|
|
123
|
+
- **Shared Git Objects**: All branches share git objects, saving disk space
|
|
124
|
+
- **Lazy Fetch**: Remote updates are only fetched if the configured interval has elapsed (default: 1 hour)
|
|
125
|
+
|
|
126
|
+
### Container Sharing Mode
|
|
127
|
+
|
|
128
|
+
Use `--shared` to share a single container across multiple branches of the same repo:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
dl --shared owner/repo@branch1 # Creates container "owner-repo"
|
|
132
|
+
dl --shared owner/repo@branch2 # Reuses "owner-repo" container
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Pre-warming
|
|
136
|
+
|
|
137
|
+
Use `--warm` to prepare a workspace without attaching a shell:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
dl --warm owner/repo@branch # Creates container in background
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Backend Selection
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
dl --backend devpod owner/repo # Force legacy DevPod backend
|
|
147
|
+
DEVLAUNCH_BACKEND=devpod dl owner/repo # Use environment variable
|
|
148
|
+
```
|
|
149
|
+
|
|
126
150
|
## Shell Completion
|
|
127
151
|
|
|
128
152
|
After running `dl --install`, you get intelligent tab completion:
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# dl completion
|
|
2
|
+
# Note: This completion function does not support quoted arguments or escaped spaces.
|
|
3
|
+
# All arguments are treated as literal strings separated by whitespace.
|
|
4
|
+
# This is acceptable because GitHub usernames, repo names, and workspace names
|
|
5
|
+
# do not contain spaces or special characters that would require quoting.
|
|
6
|
+
#
|
|
7
|
+
# Implementation note: We parse COMP_LINE directly instead of adjusting COMP_WORDBREAKS
|
|
8
|
+
# because temporary COMP_WORDBREAKS modification can have side effects with bash's
|
|
9
|
+
# internal completion state and doesn't reliably prevent word splitting in all
|
|
10
|
+
# bash versions. Direct parsing gives us full control over word boundaries.
|
|
11
|
+
_dl_completion() {
|
|
12
|
+
local cur prev opts
|
|
13
|
+
COMPREPLY=()
|
|
14
|
+
|
|
15
|
+
# Extract current line from COMP_LINE instead of COMP_WORDS
|
|
16
|
+
# This avoids issues with COMP_WORDBREAKS treating dashes as word boundaries
|
|
17
|
+
local line="${COMP_LINE:0:COMP_POINT}"
|
|
18
|
+
|
|
19
|
+
# Parse the line into an array of words (pure bash, no external processes)
|
|
20
|
+
local words
|
|
21
|
+
read -r -a words <<< "$line"
|
|
22
|
+
local word_count=${#words[@]}
|
|
23
|
+
|
|
24
|
+
# Extract current and previous words from the parsed array
|
|
25
|
+
if (( word_count > 0 )); then
|
|
26
|
+
cur="${words[word_count-1]}"
|
|
27
|
+
else
|
|
28
|
+
cur=""
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
if (( word_count > 1 )); then
|
|
32
|
+
prev="${words[word_count-2]}"
|
|
33
|
+
else
|
|
34
|
+
prev=""
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# If line ends with whitespace, we're starting a new word
|
|
38
|
+
if [[ "$line" =~ [[:space:]]$ ]]; then
|
|
39
|
+
((word_count++))
|
|
40
|
+
cur=""
|
|
41
|
+
# Update prev when starting a new word
|
|
42
|
+
if (( ${#words[@]} > 0 )); then
|
|
43
|
+
prev="${words[-1]}"
|
|
44
|
+
fi
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# Global command options (only valid as first arg)
|
|
48
|
+
local global_opts="--ls --install --help -h --version --devcontainer"
|
|
49
|
+
|
|
50
|
+
# Workspace subcommands
|
|
51
|
+
local ws_cmds="stop rm code restart recreate reset --"
|
|
52
|
+
|
|
53
|
+
# Options that take a value; a variant name or a path follows them.
|
|
54
|
+
local value_opts="--devcontainer"
|
|
55
|
+
|
|
56
|
+
# After --devcontainer, offer the repo's variant directories (and paths).
|
|
57
|
+
if [[ " ${value_opts} " == *" ${prev} "* ]]; then
|
|
58
|
+
local variants=""
|
|
59
|
+
if [[ -d .devcontainer ]]; then
|
|
60
|
+
local d
|
|
61
|
+
for d in .devcontainer/*/devcontainer.json; do
|
|
62
|
+
[[ -f "$d" ]] || continue
|
|
63
|
+
d="${d#.devcontainer/}"
|
|
64
|
+
variants+=" ${d%/devcontainer.json}"
|
|
65
|
+
done
|
|
66
|
+
fi
|
|
67
|
+
COMPREPLY=( $(compgen -W "${variants}" -- ${cur}) )
|
|
68
|
+
compopt -o default 2>/dev/null
|
|
69
|
+
return 0
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# Cache file location (honors XDG_CACHE_HOME)
|
|
73
|
+
local cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/devlaunch"
|
|
74
|
+
local cache_file="$cache_dir/completions.bash"
|
|
75
|
+
|
|
76
|
+
# Initialize completion variables
|
|
77
|
+
local DL_WORKSPACES=""
|
|
78
|
+
local DL_REPOS=""
|
|
79
|
+
local DL_OWNERS=""
|
|
80
|
+
local DL_BRANCHES=""
|
|
81
|
+
|
|
82
|
+
# Source the bash cache file (fast, no jq needed)
|
|
83
|
+
if [[ -f "$cache_file" ]]; then
|
|
84
|
+
source "$cache_file"
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# First argument: global flags, workspaces, repos, owners, or paths
|
|
88
|
+
if [[ ${word_count} -eq 2 ]]; then
|
|
89
|
+
# Global flags
|
|
90
|
+
if [[ ${cur} == -* ]]; then
|
|
91
|
+
COMPREPLY=( $(compgen -W "${global_opts}" -- ${cur}) )
|
|
92
|
+
return 0
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
# If typing a path, complete files/directories
|
|
96
|
+
if [[ "$cur" == ./* || "$cur" == /* || "$cur" == ~/* ]]; then
|
|
97
|
+
COMPREPLY=( $(compgen -d -- ${cur}) )
|
|
98
|
+
return 0
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# Check if completing branch (contains @)
|
|
102
|
+
if [[ "$cur" == *@* ]]; then
|
|
103
|
+
# Use cached branches (format: owner/repo@branch)
|
|
104
|
+
if [[ -n "$DL_BRANCHES" ]]; then
|
|
105
|
+
COMPREPLY=( $(compgen -W "${DL_BRANCHES}" -- ${cur}) )
|
|
106
|
+
fi
|
|
107
|
+
return 0
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
# Check if completing owner/repo format (contains /)
|
|
111
|
+
if [[ "$cur" == */* ]]; then
|
|
112
|
+
# Don't add space - allow @branch suffix
|
|
113
|
+
compopt -o nospace
|
|
114
|
+
# Complete from known repos
|
|
115
|
+
if [[ -n "$DL_REPOS" ]]; then
|
|
116
|
+
COMPREPLY=( $(compgen -W "${DL_REPOS}" -- ${cur}) )
|
|
117
|
+
fi
|
|
118
|
+
return 0
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
# Default: complete workspace names and offer owner/ completion
|
|
122
|
+
compopt -o nospace # For owner/ completions
|
|
123
|
+
local completions="$DL_WORKSPACES"
|
|
124
|
+
|
|
125
|
+
# Add owners with trailing slash
|
|
126
|
+
for owner in $DL_OWNERS; do
|
|
127
|
+
completions="$completions ${owner}/"
|
|
128
|
+
done
|
|
129
|
+
|
|
130
|
+
if [[ -n "$completions" ]]; then
|
|
131
|
+
COMPREPLY=( $(compgen -W "${completions}" -- ${cur}) )
|
|
132
|
+
fi
|
|
133
|
+
return 0
|
|
134
|
+
fi
|
|
135
|
+
|
|
136
|
+
# Second argument (after workspace): subcommands
|
|
137
|
+
if [[ ${word_count} -eq 3 ]]; then
|
|
138
|
+
# Don't complete after global flags
|
|
139
|
+
# Extract the first argument (word after "dl") from the words array
|
|
140
|
+
local first=""
|
|
141
|
+
if (( ${#words[@]} > 1 )); then
|
|
142
|
+
first="${words[1]}"
|
|
143
|
+
fi
|
|
144
|
+
if [[ "$first" == --* ]]; then
|
|
145
|
+
return 0
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
COMPREPLY=( $(compgen -W "${ws_cmds}" -- ${cur}) )
|
|
149
|
+
return 0
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
# After "--": no completion (user types shell command)
|
|
153
|
+
return 0
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
# Use -o default for better completion behavior
|
|
157
|
+
complete -o default -F _dl_completion dl
|
|
158
|
+
# end dl completion
|