dev_context 1.0.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +18 -0
- data/DESIGN.md +250 -0
- data/LICENSE.txt +21 -0
- data/README.md +184 -0
- data/bin/console +11 -0
- data/bin/dev_context.rb +6 -0
- data/bin/setup +8 -0
- data/lib/dev_context/cli.rb +103 -0
- data/lib/dev_context/commands/context_lifecycle.rb +80 -0
- data/lib/dev_context/commands/find.rb +123 -0
- data/lib/dev_context/commands/git_ops.rb +163 -0
- data/lib/dev_context/commands/help.rb +81 -0
- data/lib/dev_context/commands/init.rb +22 -0
- data/lib/dev_context/commands/remove.rb +22 -0
- data/lib/dev_context/commands/repos.rb +42 -0
- data/lib/dev_context/commands/search_helpers.rb +53 -0
- data/lib/dev_context/commands/stashes.rb +50 -0
- data/lib/dev_context/commands/status.rb +100 -0
- data/lib/dev_context/commands/support.rb +361 -0
- data/lib/dev_context/config.rb +123 -0
- data/lib/dev_context/matcher.rb +56 -0
- data/lib/dev_context/shell_emitter.rb +61 -0
- data/lib/dev_context/shell_setup.rb +59 -0
- data/lib/dev_context/status.rb +51 -0
- data/lib/dev_context/version.rb +8 -0
- data/lib/dev_context.rb +24 -0
- metadata +116 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 3ec8da4562204b25b61b33aa7c0bcf48e75c4db79d85ad153f59c86dffad62a1
|
|
4
|
+
data.tar.gz: 5c7a271e4eabb39c9e60d009c0da8a983b4d2e907029c32b095e46cda997b60b
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: b8c424382c0f58b5be6254621cec4cc6b0a204a5f934417fdaec0f5f4a1f98da35877709d54c278116bf7b3ed394dfd616d2721cfe6b3fa884ca55214aeebe16
|
|
7
|
+
data.tar.gz: 0e9458aa53afb5729b9270e56b90ff0e1be01ef3e56a00818a0843e6a0206949672f3c69edc6381b0163ab74d7a711871c9b09d19a38f7a9c7a79e68eeb4e4a3
|
data/CHANGELOG.md
ADDED
data/CODE_OF_CONDUCT.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
This repository, "dev_context", follows [The Ruby Community Conduct
|
|
4
|
+
Guideline](https://www.ruby-lang.org/en/conduct) in all "collaborative space",
|
|
5
|
+
which is defined as community communications channels (such as mailing lists,
|
|
6
|
+
submitted patches, commit comments, etc.):
|
|
7
|
+
|
|
8
|
+
* Participants will be tolerant of opposing views.
|
|
9
|
+
|
|
10
|
+
* Participants must ensure that their language and actions are free of personal
|
|
11
|
+
* attacks and disparaging personal remarks.
|
|
12
|
+
|
|
13
|
+
* When interpreting the words and actions of others, participants should always
|
|
14
|
+
* assume good intentions.
|
|
15
|
+
|
|
16
|
+
* Behaviour which can be reasonably considered harassment will not be tolerated.
|
|
17
|
+
|
|
18
|
+
If you have any concerns about behaviour within this project, please contact us at ["aks@stebbens.org"](mailto:"aks@stebbens.org").
|
data/DESIGN.md
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# dx — DevContext: Design
|
|
2
|
+
|
|
3
|
+
`dx` is a Ruby CLI for managing development context across repositories and branches.
|
|
4
|
+
It is the layer between filesystem navigation, Git branch intent, and daily workflow.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1) Core Model
|
|
9
|
+
|
|
10
|
+
- **Context identity:** a context is exactly one pair: `(repo_dir, branch)`.
|
|
11
|
+
- **Context naming:** a context name is either:
|
|
12
|
+
- explicit (provided by user), or
|
|
13
|
+
- implicit: `<repo_basename>:<branch>`.
|
|
14
|
+
- **Name normalization:** all context names are stored lowercase; lookup is case-insensitive.
|
|
15
|
+
- **Active stack:** `dx` maintains an ordered stack of active contexts, most recent first.
|
|
16
|
+
- **Scope for status/diff/branches/wip:** operates on active contexts.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 2) Shell Integration Model
|
|
21
|
+
|
|
22
|
+
Because a child process cannot change the parent shell CWD, `dx` is used through a shell function wrapper.
|
|
23
|
+
|
|
24
|
+
- The wrapper calls the Ruby executable and evaluates emitted shell for stateful commands.
|
|
25
|
+
- The Ruby executable supports:
|
|
26
|
+
- **shell-emitting mode** for commands like `cd`, `activate`, `pushd`, and `popd`
|
|
27
|
+
- **plain output mode** for report commands like `status`, `diff`, `branches`, `wip`
|
|
28
|
+
- Shell-emitting responses are prefixed with a marker (`# DX_SHELL_EVAL`) so wrappers can detect eval-safe output without hardcoding command names.
|
|
29
|
+
|
|
30
|
+
### Required behavior
|
|
31
|
+
|
|
32
|
+
- `dx cd ...` changes the current shell directory.
|
|
33
|
+
- `dx activate ...` also changes directory (same destination semantics as `dx cd`).
|
|
34
|
+
- `dx pushd ...` changes current shell directory and pushes context on active stack.
|
|
35
|
+
- `dx popd ...` removes context from active stack and changes directory to new top context when present.
|
|
36
|
+
- On partial failure (for example pull conflict), CWD remains in the target repo to enable direct investigation.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 3) Activation Semantics
|
|
41
|
+
|
|
42
|
+
Activating a context should be DWIM and deterministic:
|
|
43
|
+
|
|
44
|
+
1. Resolve the requested context (exact name, exact path, FSF fuzzy).
|
|
45
|
+
2. Ensure repository exists and is a valid Git repo.
|
|
46
|
+
3. Resolve/switch branch:
|
|
47
|
+
- if branch exists locally: checkout it
|
|
48
|
+
- else if remote branch exists and `DX_AUTO_CREATE_LOCAL_BRANCH=true`: create tracking branch
|
|
49
|
+
- else fail with actionable guidance
|
|
50
|
+
4. Pull latest changes using configured remote policy.
|
|
51
|
+
5. Persist activation metadata (`last_used_at`, active stack update).
|
|
52
|
+
|
|
53
|
+
### Pull behavior UX
|
|
54
|
+
|
|
55
|
+
- Use safe defaults (fast-forward only).
|
|
56
|
+
- If pull fails:
|
|
57
|
+
- keep user in target repo/branch
|
|
58
|
+
- return non-zero
|
|
59
|
+
- print short next-step hints (`git status`, conflict resolution, retry strategy)
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 4) Remote Resolution Policy
|
|
64
|
+
|
|
65
|
+
- `DX_GIT_REMOTE_NAME=USE-REPO` by default.
|
|
66
|
+
- If `USE-REPO`, resolve remote from the repository itself:
|
|
67
|
+
- prefer branch upstream (`@{upstream}`)
|
|
68
|
+
- otherwise use single-remote fallback when unambiguous
|
|
69
|
+
- fail with guidance when ambiguous or absent
|
|
70
|
+
- If `DX_GIT_REMOTE_NAME=<name>` (for example `origin`), force that remote.
|
|
71
|
+
|
|
72
|
+
`~/.dxcf` does not duplicate Git remote topology; Git remains source of truth.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 5) Global Config: `~/.dxcf`
|
|
77
|
+
|
|
78
|
+
Store as YAML. Suggested v1 shape:
|
|
79
|
+
|
|
80
|
+
```yaml
|
|
81
|
+
version: 1
|
|
82
|
+
|
|
83
|
+
contexts:
|
|
84
|
+
dev_context:main:
|
|
85
|
+
name: dev_context:main
|
|
86
|
+
repo_path: /Users/aks/src/github/aks/dev_context
|
|
87
|
+
branch: main
|
|
88
|
+
created_at: 2026-05-12T09:30:00Z
|
|
89
|
+
last_used_at: 2026-05-12T10:15:00Z
|
|
90
|
+
|
|
91
|
+
active_stack:
|
|
92
|
+
- dev_context:main
|
|
93
|
+
|
|
94
|
+
repos:
|
|
95
|
+
dev_context:
|
|
96
|
+
path: /Users/aks/src/github/aks/dev_context
|
|
97
|
+
last_seen_at: 2026-05-12T10:15:00Z
|
|
98
|
+
|
|
99
|
+
clone_roots:
|
|
100
|
+
- /Users/aks/src/github
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Notes:
|
|
104
|
+
- context key collisions are prevented via normalized lowercase naming
|
|
105
|
+
- repo metadata and context metadata are separate concerns
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 6) Name Resolution and Matching
|
|
110
|
+
|
|
111
|
+
Resolution order for context arguments:
|
|
112
|
+
|
|
113
|
+
1. exact context name match
|
|
114
|
+
2. exact path match
|
|
115
|
+
3. `DX_PATH` + `DX_CLONE_BASE_DIR` directory search for relative repo targets
|
|
116
|
+
4. FSF-style fuzzy match against known context names and repo basenames
|
|
117
|
+
|
|
118
|
+
If fuzzy matching returns multiple candidates, `dx` lists them and exits non-zero.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## 7) URL and Path Handling
|
|
123
|
+
|
|
124
|
+
Accepted location inputs:
|
|
125
|
+
|
|
126
|
+
- relative path (`./api`)
|
|
127
|
+
- absolute path (`/Users/aks/src/github/api`)
|
|
128
|
+
- Git URL (`https://github.com/org/repo.git`, `git@github.com:org/repo.git`)
|
|
129
|
+
|
|
130
|
+
`DX_PATH` behavior for repo target lookup:
|
|
131
|
+
|
|
132
|
+
- `DX_PATH` is a path-separated list of directories (like `PATH`).
|
|
133
|
+
- When a relative target is not found under current working directory, `dx` searches each `DX_PATH` root and `DX_CLONE_BASE_DIR` for `<root>/<target>`.
|
|
134
|
+
- A single match is accepted.
|
|
135
|
+
- Multiple matches are treated as ambiguous and fail with candidate listing.
|
|
136
|
+
- If exact path search does not find a unique match, `dx` performs FSF subsequence matching across directory basenames in those roots.
|
|
137
|
+
|
|
138
|
+
URL behavior:
|
|
139
|
+
|
|
140
|
+
1. derive repo basename (`repo.git` -> `repo`)
|
|
141
|
+
2. place clone under `clone_roots`/`DX_CLONE_BASE_DIR` policy
|
|
142
|
+
3. clone if missing, otherwise reuse existing path
|
|
143
|
+
4. register repo and optionally create context
|
|
144
|
+
5. activate/cd when command requires it
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 8) Command Set (v1)
|
|
149
|
+
|
|
150
|
+
- `dx init`
|
|
151
|
+
- `dx add PATH|URL ...`
|
|
152
|
+
- `dx create NAME [PATH] [BRANCH]`
|
|
153
|
+
- `dx cd CONTEXT|PATH|URL`
|
|
154
|
+
- `dx activate CONTEXT|PATH|URL`
|
|
155
|
+
- `dx pushd CONTEXT|PATH|URL`
|
|
156
|
+
- `dx popd [CONTEXT]`
|
|
157
|
+
- `dx deactivate CONTEXT`
|
|
158
|
+
- `dx active`
|
|
159
|
+
- `dx status` (`dx wip` alias allowed)
|
|
160
|
+
- `dx diff [CONTEXT]`
|
|
161
|
+
- `dx branches [CONTEXT]`
|
|
162
|
+
- `dx co -b FEATURE [CONTEXT]`
|
|
163
|
+
- `dx help [COMMAND]`
|
|
164
|
+
- `dx doctor` (or `dx check`)
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## 9) Status Output Contract
|
|
169
|
+
|
|
170
|
+
Single-line status summary per active context:
|
|
171
|
+
|
|
172
|
+
- `m`: staged modified count
|
|
173
|
+
- `u`: unstaged modified count
|
|
174
|
+
- `n`: new/untracked count
|
|
175
|
+
- `d`: deleted count
|
|
176
|
+
- `r`: renamed count
|
|
177
|
+
|
|
178
|
+
Example:
|
|
179
|
+
|
|
180
|
+
`m:0 u:10 n:26 d:3 r:0`
|
|
181
|
+
|
|
182
|
+
If all counts are zero, display `Up to date`.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## 10) High-Level Ruby Architecture
|
|
187
|
+
|
|
188
|
+
- `DevContext::CLI` - argument parsing and command dispatch
|
|
189
|
+
- `DevContext::Config` - load/save/validate `~/.dxcf`
|
|
190
|
+
- `DevContext::Context` - context value object `(repo_path, branch, name)`
|
|
191
|
+
- `DevContext::Registry` - known repos and contexts
|
|
192
|
+
- `DevContext::Matcher` - exact/fuzzy resolution
|
|
193
|
+
- `DevContext::Git` - status, branch, pull, checkout helpers
|
|
194
|
+
- `DevContext::ShellEmitter` - emits safe shell snippets for stateful commands
|
|
195
|
+
- `DevContext::Commands::*` - command handlers
|
|
196
|
+
- `DevContext::JJ` - optional read-only integration
|
|
197
|
+
- `DevContext::TUI` - optional dashboard (future)
|
|
198
|
+
|
|
199
|
+
Execution flow:
|
|
200
|
+
|
|
201
|
+
1. Parse command
|
|
202
|
+
2. Load config
|
|
203
|
+
3. Resolve target (name/path/url)
|
|
204
|
+
4. Perform command logic (Git + config updates)
|
|
205
|
+
5. Emit shell script or plain output
|
|
206
|
+
6. Return stable exit code
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## 11) DWIM UX Contract
|
|
211
|
+
|
|
212
|
+
`dx` is a DWIM-first CLI: easy, intuitive, forgiving, and discoverable.
|
|
213
|
+
|
|
214
|
+
- **Default usefulness**
|
|
215
|
+
- Bare `dx` performs the most useful safe default for initialized users (`dx status`).
|
|
216
|
+
- If uninitialized, `dx` guides user to `dx init`.
|
|
217
|
+
|
|
218
|
+
- **Help discoverability**
|
|
219
|
+
- `dx help`
|
|
220
|
+
- `dx help <command>`
|
|
221
|
+
- `dx <command> --help`
|
|
222
|
+
- All three forms are supported and consistent.
|
|
223
|
+
|
|
224
|
+
- **Name resolution**
|
|
225
|
+
- Context lookup order: exact name -> exact path -> FSF fuzzy match.
|
|
226
|
+
- Matching is case-insensitive; stored context names are lowercase.
|
|
227
|
+
- Ambiguous fuzzy matches never guess silently; show candidates and exit non-zero.
|
|
228
|
+
|
|
229
|
+
- **Error ergonomics**
|
|
230
|
+
- Every error message includes:
|
|
231
|
+
- what failed
|
|
232
|
+
- why (if known)
|
|
233
|
+
- one concrete next command
|
|
234
|
+
- Prefer short, actionable output over long diagnostics.
|
|
235
|
+
|
|
236
|
+
- **Activation behavior**
|
|
237
|
+
- `dx activate` / `dx cd` prioritize flow:
|
|
238
|
+
- switch to target repo/branch
|
|
239
|
+
- attempt pull using configured policy
|
|
240
|
+
- On pull failure, keep user in target repo for investigation.
|
|
241
|
+
- Return non-zero on failure so scripts can detect problems.
|
|
242
|
+
|
|
243
|
+
- **Safe automation**
|
|
244
|
+
- Non-destructive by default.
|
|
245
|
+
- No silent data-changing operations without explicit user intent.
|
|
246
|
+
- Behavior controlled by env vars with sensible defaults.
|
|
247
|
+
|
|
248
|
+
- **Operator confidence**
|
|
249
|
+
- `dx doctor` (or `dx check`) validates shell integration, config, and git availability.
|
|
250
|
+
- Command output is stable and script-friendly when possible.
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alan Stebbens
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# DevContext (dx)
|
|
2
|
+
|
|
3
|
+
This repo contains `dx` (`dev_context`), a script for managing developer context across repository directories and branches.
|
|
4
|
+
|
|
5
|
+
A context is one `(repo_dir, branch)` pair. Context names can be explicit, or implicit as `<repo_basename>:<branch>` (stored lowercase), and resolved with exact then FSF-style fuzzy matching.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
gem install -n ~/bin dev_context
|
|
10
|
+
|
|
11
|
+
Install the gem in the current ruby gem path, with the executable installed as `~/bin/dev_context.rb`.
|
|
12
|
+
|
|
13
|
+
To clone from the github repo:
|
|
14
|
+
|
|
15
|
+
cd ~/src/github # or wherever you keep github repos
|
|
16
|
+
git clone https://github.com/aks/dev_context.git
|
|
17
|
+
cd dev_context
|
|
18
|
+
bundle install
|
|
19
|
+
bundle exec rake install
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### Current model (authoritative)
|
|
24
|
+
|
|
25
|
+
- A context is exactly one repo+branch pair (not a multi-repo aggregate).
|
|
26
|
+
- `dx cd` and `dx activate` both activate the target context and change CWD via shell integration.
|
|
27
|
+
- Activation attempts branch checkout + pull; on pull failure, CWD remains in the target repo for investigation and the command exits non-zero.
|
|
28
|
+
- Defaults:
|
|
29
|
+
- `DX_AUTO_CREATE_LOCAL_BRANCH=true`
|
|
30
|
+
- `DX_GIT_REMOTE_NAME=USE-REPO` (or explicit like `origin`)
|
|
31
|
+
|
|
32
|
+
### Shell integration
|
|
33
|
+
|
|
34
|
+
To support `cd`, `dx` should be wrapped by a shell function that evaluates shell output for stateful commands.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
dx() {
|
|
38
|
+
case "$1" in
|
|
39
|
+
cd|activate|pushd|popd)
|
|
40
|
+
local out
|
|
41
|
+
out="$(DX_SHELL_WRAPPED=1 command dev_context.rb "$@")" || return $?
|
|
42
|
+
case "$out" in
|
|
43
|
+
"# DX_SHELL_EVAL"*) eval "$out" ;;
|
|
44
|
+
*) printf "%s\n" "$out" ;;
|
|
45
|
+
esac
|
|
46
|
+
;;
|
|
47
|
+
*)
|
|
48
|
+
command dev_context.rb "$@"
|
|
49
|
+
;;
|
|
50
|
+
esac
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
In the descriptions below, the following terms are used consistently:
|
|
55
|
+
|
|
56
|
+
- `NAME`: the context NAME (which can match a PATH)
|
|
57
|
+
|
|
58
|
+
- `PATH`: the file system path to a single repository directory.
|
|
59
|
+
|
|
60
|
+
- `URL`: a standard http/https/git scheme URL that leads to a git-based
|
|
61
|
+
repository.
|
|
62
|
+
|
|
63
|
+
- `CONTEXT`: a context name, a `PATH`, or `URL` that identifies one context.
|
|
64
|
+
Implicit naming uses `<repo_basename>:<branch>`.
|
|
65
|
+
|
|
66
|
+
### Common Options
|
|
67
|
+
|
|
68
|
+
These options are currently supported on `dx add`, `dx clone`, and `dx create`:
|
|
69
|
+
|
|
70
|
+
- `-c, --context NAME`: explicit context name
|
|
71
|
+
- `-n, --norun`: preview actions without changing state
|
|
72
|
+
- `-v, --verbose`: print extra command details
|
|
73
|
+
|
|
74
|
+
Examples:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
dx add -c api:main ~/src/github/api
|
|
78
|
+
dx clone -n https://github.com/acme/tooling.git
|
|
79
|
+
dx create -v feature:abc-123 ~/src/github/dev_context feature/abc-123
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Context stack commands
|
|
83
|
+
|
|
84
|
+
- `dx pushd CONTEXT|PATH|URL`: activate and push context to top of stack
|
|
85
|
+
- `dx popd [CONTEXT]`: pop the top context (or a specific one); if a new top exists, switch CWD to it
|
|
86
|
+
|
|
87
|
+
### `DX_PATH` repo lookup
|
|
88
|
+
|
|
89
|
+
`DX_PATH` can be used as a list of parent directories that contain repositories.
|
|
90
|
+
|
|
91
|
+
- Format: path-separated directories (same separator as shell `PATH`)
|
|
92
|
+
- Example:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
export DX_PATH="$HOME/src/github:$HOME/src/work"
|
|
96
|
+
dx add dev_context
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Lookup behavior for relative repo targets:
|
|
100
|
+
|
|
101
|
+
1. check current directory-relative path
|
|
102
|
+
2. check each `DX_PATH` root and `DX_CLONE_BASE_DIR` as `<root>/<target>`
|
|
103
|
+
3. if needed, run FSF subsequence search across repo directory names in those roots
|
|
104
|
+
4. if one match is found, use it
|
|
105
|
+
5. if multiple matches are found, fail and list candidates
|
|
106
|
+
|
|
107
|
+
### Initialization and Adding Directories
|
|
108
|
+
|
|
109
|
+
dx [init | help]
|
|
110
|
+
dx init
|
|
111
|
+
dx help
|
|
112
|
+
|
|
113
|
+
The first thing to do is to initialize `dx` with one or more repo directories.
|
|
114
|
+
They do not need to be added but, they can be discovered automatically with `dx
|
|
115
|
+
add PATH`.
|
|
116
|
+
|
|
117
|
+
When initialized, a `~/.dxcf` file will exist with the current `dx` settings.
|
|
118
|
+
|
|
119
|
+
When `dx` is invoked without any arguments (or options), and `~/.dxcf` does
|
|
120
|
+
*not* exist, then `dx init` is performed. `dx init` returns exit code 0
|
|
121
|
+
(success) when it actually succeeds in performing the initialization; it returns
|
|
122
|
+
1 (fail) otherwise.
|
|
123
|
+
|
|
124
|
+
When `dx` is invoked without any arguments or options, and `~/.dxcf`
|
|
125
|
+
*already* exists, `dx` defaults to `dx status`.
|
|
126
|
+
|
|
127
|
+
| dx command | ~/.dxcf? | action |
|
|
128
|
+
| ---------- | -------- | ----------- |
|
|
129
|
+
| `dx` | no | `dx init` |
|
|
130
|
+
| `dx` | yes | `dx status` |
|
|
131
|
+
|
|
132
|
+
> Note: some command examples below were written before the current context model was finalized.
|
|
133
|
+
> The authoritative behavior is defined in the "Current model (authoritative)" section above and in `DESIGN.md`.
|
|
134
|
+
|
|
135
|
+
### Command reference (v1)
|
|
136
|
+
|
|
137
|
+
```text
|
|
138
|
+
dx init
|
|
139
|
+
dx add PATH|URL ...
|
|
140
|
+
dx clone URL [PATH]
|
|
141
|
+
dx create NAME [PATH] [BRANCH]
|
|
142
|
+
dx remove CONTEXT|PATH
|
|
143
|
+
dx active
|
|
144
|
+
dx activate CONTEXT|PATH|URL
|
|
145
|
+
dx cd CONTEXT|PATH|URL
|
|
146
|
+
dx deactivate CONTEXT
|
|
147
|
+
dx pushd CONTEXT|PATH|URL
|
|
148
|
+
dx popd [CONTEXT]
|
|
149
|
+
dx status|wip [--all] [--dirty] [-b BRANCHPATTERN] [-p PATHPATTERN]
|
|
150
|
+
dx repos [-b BRANCHPATTERN] [-p PATHPATTERN] [PATTERN]
|
|
151
|
+
dx stashes [--list] [PATTERN]
|
|
152
|
+
dx find [--stashes|--branches|--paths] <pattern>
|
|
153
|
+
dx find --all
|
|
154
|
+
dx branches|br [CONTEXT|PATTERN]
|
|
155
|
+
dx checkout|co [-b] FEATURE [CONTEXT]
|
|
156
|
+
dx diff [CONTEXT]
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Notes:
|
|
160
|
+
|
|
161
|
+
- `dx add` accepts one or more `PATH`/`URL` targets; there is no trailing aggregate context argument.
|
|
162
|
+
- `dx add URL` behaves like clone+register for that repo.
|
|
163
|
+
- `dx stashes [PATTERN]`, `dx repos [PATTERN]`, and `dx branches [PATTERN]` are focused find-style shortcuts.
|
|
164
|
+
- `dx <pattern>` is shorthand for `dx find <pattern>` when the first token is not a command.
|
|
165
|
+
- `dx wip` is `dx status --dirty` by default.
|
|
166
|
+
- `dx status`/`dx wip` show stash count as `s:<count>` when non-zero.
|
|
167
|
+
|
|
168
|
+
## Development
|
|
169
|
+
|
|
170
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
171
|
+
|
|
172
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
173
|
+
|
|
174
|
+
## Contributing
|
|
175
|
+
|
|
176
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/aks/dev_context. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/aks/dev_context/blob/main/CODE_OF_CONDUCT.md).
|
|
177
|
+
|
|
178
|
+
## License
|
|
179
|
+
|
|
180
|
+
MIT License — see [LICENSE.txt](LICENSE.txt).
|
|
181
|
+
|
|
182
|
+
## Code of Conduct
|
|
183
|
+
|
|
184
|
+
Please adhere to our [code of conduct](https://github.com/aks/dev_context/blob/main/CODE_OF_CONDUCT.md).
|
data/bin/console
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "bundler/setup"
|
|
5
|
+
require "dev_context"
|
|
6
|
+
|
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
9
|
+
|
|
10
|
+
require "irb"
|
|
11
|
+
IRB.start(__FILE__)
|
data/bin/dev_context.rb
ADDED
data/bin/setup
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "shellwords"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
require "pathname"
|
|
6
|
+
require "optparse"
|
|
7
|
+
|
|
8
|
+
module DevContext
|
|
9
|
+
class CLI
|
|
10
|
+
include Commands::Init
|
|
11
|
+
include Commands::Help
|
|
12
|
+
include Commands::Support
|
|
13
|
+
include Commands::ContextLifecycle
|
|
14
|
+
include Commands::GitOps
|
|
15
|
+
include Commands::SearchHelpers
|
|
16
|
+
include Commands::Find
|
|
17
|
+
include Commands::Repos
|
|
18
|
+
include Commands::Stashes
|
|
19
|
+
include Commands::Status
|
|
20
|
+
include Commands::Remove
|
|
21
|
+
|
|
22
|
+
COLOR_RESET = "\e[0m"
|
|
23
|
+
COLOR_ORANGE = "\e[38;5;208m"
|
|
24
|
+
COLOR_CYAN = "\e[36m"
|
|
25
|
+
COLOR_GREEN = "\e[32m"
|
|
26
|
+
COLOR_RED = "\e[31m"
|
|
27
|
+
COLOR_YELLOW = "\e[33m"
|
|
28
|
+
COLOR_MAGENTA = "\e[35m"
|
|
29
|
+
|
|
30
|
+
def self.run(argv, out: $stdout, err: $stderr, env: ENV, pwd: Dir.pwd)
|
|
31
|
+
new(argv, out: out, err: err, env: env, pwd: pwd).run
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def initialize(argv, out:, err:, env:, pwd:)
|
|
35
|
+
@argv = argv.dup
|
|
36
|
+
@out = out
|
|
37
|
+
@err = err
|
|
38
|
+
@env = env
|
|
39
|
+
@pwd = pwd
|
|
40
|
+
@config = Config.new
|
|
41
|
+
@matcher = Matcher.new(config: @config)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def run
|
|
45
|
+
raw_command = argv.shift
|
|
46
|
+
|
|
47
|
+
return default_action if raw_command.nil?
|
|
48
|
+
|
|
49
|
+
resolution = resolve_command(raw_command)
|
|
50
|
+
command = resolution[:command]
|
|
51
|
+
if command.nil?
|
|
52
|
+
if resolution[:error] == :unknown && !raw_command.start_with?("-")
|
|
53
|
+
argv.unshift(raw_command)
|
|
54
|
+
return cmd_find
|
|
55
|
+
end
|
|
56
|
+
return 1
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
if %w[--help -h].include?(argv.first)
|
|
60
|
+
argv.shift
|
|
61
|
+
return cmd_help_topic(command)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
case command
|
|
65
|
+
when "init" then cmd_init
|
|
66
|
+
when "help", "--help", "-h" then cmd_help
|
|
67
|
+
when "add" then cmd_add
|
|
68
|
+
when "clone" then cmd_clone
|
|
69
|
+
when "create" then cmd_create
|
|
70
|
+
when "remove" then cmd_remove
|
|
71
|
+
when "active" then cmd_active
|
|
72
|
+
when "deactivate" then cmd_deactivate
|
|
73
|
+
when "find" then cmd_find
|
|
74
|
+
when "stashes" then cmd_stashes
|
|
75
|
+
when "repos" then cmd_repos
|
|
76
|
+
when "status", "wip" then cmd_status(mode: command)
|
|
77
|
+
when "diff" then cmd_diff
|
|
78
|
+
when "branches", "br" then cmd_branches
|
|
79
|
+
when "co", "checkout" then cmd_checkout
|
|
80
|
+
when "cd", "activate", "pushd" then cmd_activate
|
|
81
|
+
when "popd" then cmd_pop
|
|
82
|
+
else
|
|
83
|
+
err.puts("dx: unknown command '#{raw_command}'")
|
|
84
|
+
cmd_help
|
|
85
|
+
1
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
attr_reader :argv, :out, :err, :env, :pwd, :config, :matcher
|
|
92
|
+
|
|
93
|
+
COMMANDS = %w[
|
|
94
|
+
init help add clone create remove active deactivate find repos stashes status wip diff branches br co checkout cd activate pushd popd
|
|
95
|
+
].freeze
|
|
96
|
+
|
|
97
|
+
def default_action
|
|
98
|
+
return cmd_init unless config.initialized?
|
|
99
|
+
|
|
100
|
+
cmd_status
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|