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.
@@ -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
  [![GitHub pull-requests merged](https://badgen.net/github/merged-prs/blooop/devlaunch)](https://github.com/blooop/devlaunch/pulls?q=is%3Amerged)
11
34
  [![GitHub release](https://img.shields.io/github/release/blooop/devlaunch.svg)](https://GitHub.com/blooop/devlaunch/releases/)
12
35
  [![PyPI](https://img.shields.io/pypi/v/devlaunch)](https://pypi.org/project/devlaunch/)
13
- [![Conda](https://img.shields.io/badge/conda-blooop-green?logo=conda-forge)](https://prefix.dev/channels/blooop/packages/devlaunch)
36
+ [![Conda](https://img.shields.io/badge/conda-v0.0.7-brightgreen?logo=anaconda)](https://prefix.dev/channels/blooop/packages/devlaunch)
14
37
  [![License](https://img.shields.io/github/license/blooop/devlaunch)](https://opensource.org/license/mit/)
15
38
  [![Python](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue)](https://www.python.org/downloads/)
16
39
  [![Pixi Badge](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/prefix-dev/pixi/main/assets/badge/v0.json)](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
  [![GitHub pull-requests merged](https://badgen.net/github/merged-prs/blooop/devlaunch)](https://github.com/blooop/devlaunch/pulls?q=is%3Amerged)
32
11
  [![GitHub release](https://img.shields.io/github/release/blooop/devlaunch.svg)](https://GitHub.com/blooop/devlaunch/releases/)
33
12
  [![PyPI](https://img.shields.io/pypi/v/devlaunch)](https://pypi.org/project/devlaunch/)
34
- [![Conda](https://img.shields.io/badge/conda-blooop-green?logo=conda-forge)](https://prefix.dev/channels/blooop/packages/devlaunch)
13
+ [![Conda](https://img.shields.io/badge/conda-v0.0.7-brightgreen?logo=anaconda)](https://prefix.dev/channels/blooop/packages/devlaunch)
35
14
  [![License](https://img.shields.io/github/license/blooop/devlaunch)](https://opensource.org/license/mit/)
36
15
  [![Python](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue)](https://www.python.org/downloads/)
37
16
  [![Pixi Badge](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/prefix-dev/pixi/main/assets/badge/v0.json)](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