mxup 0.3.1 → 1.0.1
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 +4 -4
- data/README.md +254 -40
- data/bin/mxup +6 -1
- data/examples/myapp-dev.yml +49 -14
- data/lib/mxup/cli.rb +10 -7
- data/lib/mxup/config.rb +409 -62
- data/lib/mxup/migrations.rb +109 -0
- data/lib/mxup/reconciler.rb +4 -2
- data/lib/mxup/runner.rb +10 -9
- data/lib/mxup/status_view.rb +1 -1
- data/lib/mxup/version.rb +1 -1
- data/lib/mxup.rb +2 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4531ad3aa556a0ca370760f6f2021bbbf4c9a111d404989cd6b24fb6e88f1e06
|
|
4
|
+
data.tar.gz: 93a8f02afacc7332e064124807f5ea47c400d0de44584c90fbcc18b7e8399134
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4a3c824064e22953dd14a56a6cef28548b62d2b0d8d7bd0603d61070a89c602476436977d16da51e13e5511d0ca6249fb223784456407bae5c4e777e76efd334
|
|
7
|
+
data.tar.gz: 8df2f3eade22728fca31fcd384de5a7820358b0ec2d4512898b4c5424601bc60dddfae6a12845de428ee4a8a9e24dadbb48b25f725054268433b6452eb058a2f
|
data/README.md
CHANGED
|
@@ -6,20 +6,37 @@ Run `mxup up` any time — it creates what's missing, restarts what crashed, rem
|
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
### Homebrew (recommended on macOS)
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Current Homebrew versions require third-party taps to be added and trusted
|
|
12
|
+
explicitly:
|
|
12
13
|
|
|
13
14
|
```bash
|
|
14
|
-
|
|
15
|
+
brew tap Recognized/mxup
|
|
16
|
+
brew trust Recognized/mxup
|
|
17
|
+
brew install mxup
|
|
18
|
+
mxup --version
|
|
15
19
|
```
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
Homebrew installs the required `tmux` and Ruby versions automatically. If
|
|
22
|
+
Homebrew reports that Xcode or the Command Line Tools are outdated, update
|
|
23
|
+
them through System Settings or Apple Developer Downloads, then retry.
|
|
24
|
+
|
|
25
|
+
### RubyGems
|
|
26
|
+
|
|
27
|
+
RubyGems installation requires Ruby 3.1+ and `tmux`:
|
|
18
28
|
|
|
19
29
|
```bash
|
|
20
|
-
|
|
30
|
+
ruby --version
|
|
31
|
+
gem install mxup
|
|
32
|
+
mxup --version
|
|
21
33
|
```
|
|
22
34
|
|
|
35
|
+
The Ruby bundled with older macOS versions is too old. Install a current Ruby
|
|
36
|
+
first (for example with `brew install ruby`). If installation succeeds but
|
|
37
|
+
`mxup` is not found, add the executable directory shown by `gem environment`
|
|
38
|
+
to your `PATH`.
|
|
39
|
+
|
|
23
40
|
### From source
|
|
24
41
|
|
|
25
42
|
```bash
|
|
@@ -112,6 +129,7 @@ windows:
|
|
|
112
129
|
| Field | Required | Description |
|
|
113
130
|
|-------|----------|-------------|
|
|
114
131
|
| `session` | yes | tmux session name |
|
|
132
|
+
| `mxup_version` | no | Config format generation this config is written for. Omit it and the config is read as the pre-1.0 format, which keeps working (see [Config format versions](#config-format-versions)) |
|
|
115
133
|
| `setup` | no | Shell snippet prepended to every window's command |
|
|
116
134
|
| `root` | no | Base directory for relative window `root` values. Relative paths resolve against the config file's directory — or, if the config lives in a project-local `.mxup/` directory, against `.mxup/`'s parent (the project root). `~` and absolute paths are kept as-is. Supports `$VAR` / `${VAR}` env-var expansion (an unset variable is an error). |
|
|
117
135
|
| `required_env` | no | Env vars that must be filled in before `mxup up` will start (see [Required env vars](#required-env-vars)) |
|
|
@@ -127,6 +145,96 @@ Per window:
|
|
|
127
145
|
| `wait_for` | no | Readiness check to pass before running command (see below) |
|
|
128
146
|
| `commands` | no | Map of named one-off commands runnable via `mxup <config> <window>:<name>` (see [Named commands](#named-commands-mxup-configwindowname)) |
|
|
129
147
|
|
|
148
|
+
### Config format versions
|
|
149
|
+
|
|
150
|
+
`mxup_version` names the **config format generation** a config is written
|
|
151
|
+
for, and mxup reads every generation up to its own:
|
|
152
|
+
|
|
153
|
+
```yaml
|
|
154
|
+
mxup_version: '1'
|
|
155
|
+
session: my-project
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Only the major is read, so `'1'`, `'1.0'` and `'1.4.2'` all name the same
|
|
159
|
+
generation — write whichever reads best. Majors compare numerically, so
|
|
160
|
+
`10.x` is newer than `9.x`.
|
|
161
|
+
|
|
162
|
+
**Omitting the key is fine, and always will be.** A config with no
|
|
163
|
+
`mxup_version` is read as the pre-1.0 format, major 0 — including the way
|
|
164
|
+
its [profiles](#profiles) work — so every config written for `0.3.1` or
|
|
165
|
+
earlier keeps running under `1.x` untouched. Nothing to migrate, no flag to
|
|
166
|
+
pass.
|
|
167
|
+
|
|
168
|
+
Two things follow from that:
|
|
169
|
+
|
|
170
|
+
- **Upgrading mxup never forces a config rewrite.** A new generation ships
|
|
171
|
+
with a new mxup major, and older generations keep being read. `mxup_version`
|
|
172
|
+
selects how your config is interpreted; it is not a gate that locks you out.
|
|
173
|
+
- **The generation is a choice, not a version check.** Set `mxup_version: '1'`
|
|
174
|
+
when you want the 1.x format's behaviour — [additive
|
|
175
|
+
profiles](#profiles), and selecting several at once. Until then your config
|
|
176
|
+
behaves the way it always did.
|
|
177
|
+
|
|
178
|
+
The one thing mxup can't read is a config from the *future* — a generation
|
|
179
|
+
newer than it knows about:
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
$ mxup up my-project
|
|
183
|
+
This config targets the mxup 2.x config format, but mxup 1.0.0
|
|
184
|
+
reads up to 1.x. Update mxup, then try again:
|
|
185
|
+
brew upgrade mxup # if installed via Homebrew
|
|
186
|
+
gem update mxup # if installed via RubyGems
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
That's resolved before any other validation, so such a config says so
|
|
190
|
+
instead of failing on a key it doesn't recognise.
|
|
191
|
+
|
|
192
|
+
Because format 0 and format 1 read the same `profiles:` block differently,
|
|
193
|
+
a config that uses profiles and hasn't picked a generation is told which
|
|
194
|
+
meaning it's getting, once per command, on stderr:
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
mxup: reading `profiles:` with the 0.x meaning (every window in `windows:` runs;
|
|
198
|
+
the profile overrides some and drops others with `~`). Run `mxup migrations`,
|
|
199
|
+
then set `mxup_version: '1'` to switch to additive profiles.
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Configs with no `profiles:` block stay silent — the two generations are
|
|
203
|
+
identical for them. So does one that pins `mxup_version: '0'`, which says
|
|
204
|
+
the 0.x reading is deliberate.
|
|
205
|
+
|
|
206
|
+
### What each major changed (`mxup migrations`)
|
|
207
|
+
|
|
208
|
+
`mxup migrations` prints the config format's history — for every major, what
|
|
209
|
+
changed and how to update a config written for the previous one. It needs no
|
|
210
|
+
config file, which is the point: it's what you run when your config won't
|
|
211
|
+
load.
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
$ mxup migrations
|
|
215
|
+
mxup 1.0.0 — config format changes by major version.
|
|
216
|
+
|
|
217
|
+
0.x -> 1.x
|
|
218
|
+
|
|
219
|
+
1. Profiles select windows additively instead of subtracting them
|
|
220
|
+
Before: Every window in `windows:` ran. A profile overrode some of them
|
|
221
|
+
and dropped others with `~`, so `staging: {}` meant "run
|
|
222
|
+
everything, unchanged".
|
|
223
|
+
Now: `windows:` is a catalog and nothing in it runs on its own. Each
|
|
224
|
+
profile lists the windows it runs, and several profiles can be
|
|
225
|
+
selected at once (`-p a,b`) — the live set is their union. A
|
|
226
|
+
window no selected profile lists stays down.
|
|
227
|
+
Fix: In every profile, list the windows it should run: `name: {}` to
|
|
228
|
+
include one as declared in the catalog, or a non-empty block to
|
|
229
|
+
include it with overrides. …
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
One caveat this can't solve retroactively, and it points the other way:
|
|
233
|
+
mxup versions released before `mxup_version` existed (0.3.1 and earlier)
|
|
234
|
+
don't know the key, so a config carrying `mxup_version: '1'` is refused by
|
|
235
|
+
an *old* mxup as an unknown top-level key. New mxup reading old configs is
|
|
236
|
+
the direction that's seamless.
|
|
237
|
+
|
|
130
238
|
### Wait-for checks
|
|
131
239
|
|
|
132
240
|
`wait_for` blocks a window's command until a readiness condition is met.
|
|
@@ -336,19 +444,24 @@ mxup layout my-project compact
|
|
|
336
444
|
|
|
337
445
|
### Profiles
|
|
338
446
|
|
|
339
|
-
A single project often needs to run under different stacks — "
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
447
|
+
A single project often needs to run under different stacks — "just the
|
|
448
|
+
backend", "frontend against staging", "everything plus a scratch shell".
|
|
449
|
+
Profiles are **additive slices** of the `windows:` block: each profile
|
|
450
|
+
lists the windows it runs, and you can select as many as you like at
|
|
451
|
+
once. The live selection is the union of what those profiles include.
|
|
452
|
+
|
|
453
|
+
This describes the `1.x` config format, so the config declares it with
|
|
454
|
+
[`mxup_version`](#config-format-versions). A config that omits the key
|
|
455
|
+
keeps the older, subtractive meaning — see [Profiles in the 0.x
|
|
456
|
+
format](#profiles-in-the-0x-format) below.
|
|
344
457
|
|
|
345
458
|
```yaml
|
|
459
|
+
mxup_version: '1'
|
|
346
460
|
session: my-project
|
|
347
461
|
|
|
348
|
-
windows:
|
|
462
|
+
windows: # a catalog; nothing here runs on its own
|
|
349
463
|
backend:
|
|
350
464
|
root: ~/projects/my-app/backend
|
|
351
|
-
command: ./start-server.sh
|
|
352
465
|
env:
|
|
353
466
|
DATABASE_URL: postgres://localhost/myapp_dev
|
|
354
467
|
|
|
@@ -356,56 +469,150 @@ windows:
|
|
|
356
469
|
root: ~/projects/my-app/frontend
|
|
357
470
|
command: npm run dev
|
|
358
471
|
|
|
472
|
+
scratch:
|
|
473
|
+
root: ~/projects/my-app
|
|
474
|
+
|
|
359
475
|
profiles:
|
|
360
|
-
|
|
476
|
+
backend: # backend, served locally
|
|
477
|
+
windows:
|
|
478
|
+
backend:
|
|
479
|
+
command: ./start-server.sh
|
|
361
480
|
|
|
362
|
-
staging:
|
|
481
|
+
staging-backend: # same window, pointed at staging
|
|
363
482
|
windows:
|
|
364
483
|
backend:
|
|
365
484
|
command: ./connect-staging.sh
|
|
366
485
|
env:
|
|
367
486
|
DATABASE_URL: postgres://staging-db/myapp
|
|
487
|
+
|
|
488
|
+
frontend:
|
|
489
|
+
windows:
|
|
490
|
+
frontend: {} # include as declared in the catalog
|
|
491
|
+
|
|
492
|
+
scratch:
|
|
493
|
+
windows:
|
|
494
|
+
scratch: {}
|
|
368
495
|
```
|
|
369
496
|
|
|
370
|
-
|
|
497
|
+
Settings shared by every variant of a window live in the catalog; the bits
|
|
498
|
+
that differ live in the profiles that select it.
|
|
499
|
+
|
|
500
|
+
Select profiles with `--profile` (short: `-p`), which is repeatable and
|
|
501
|
+
accepts a comma-separated list:
|
|
371
502
|
|
|
372
503
|
```bash
|
|
373
|
-
mxup up my-project
|
|
374
|
-
mxup up my-project -p
|
|
375
|
-
mxup
|
|
504
|
+
mxup up my-project -p backend,frontend # both slices
|
|
505
|
+
mxup up my-project -p backend -p frontend # same thing
|
|
506
|
+
mxup up my-project -p staging-backend -p frontend
|
|
507
|
+
mxup status my-project # shows the live selection
|
|
376
508
|
```
|
|
377
509
|
|
|
378
510
|
| Field | Required | Description |
|
|
379
511
|
|-------|----------|-------------|
|
|
380
|
-
| `profiles` | no | Map of profile name →
|
|
381
|
-
| `default_profile` | no | Profile
|
|
382
|
-
|
|
383
|
-
**
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
512
|
+
| `profiles` | no | Map of profile name → the windows it runs (plus optional overrides) |
|
|
513
|
+
| `default_profile` | no | Profile name, or list of names, selected when `--profile` is omitted (defaults to the first declared) |
|
|
514
|
+
|
|
515
|
+
**Inclusion**: a window runs when at least one selected profile lists it.
|
|
516
|
+
A window no selected profile lists stays down — including when it is
|
|
517
|
+
declared in the base `windows:` block. A profile that lists no windows at
|
|
518
|
+
all is an error, since it would bring up an empty session.
|
|
519
|
+
|
|
520
|
+
Layout groups are pruned to the windows that actually run: names are
|
|
521
|
+
stripped from `panes:` lists, and a group that ends up empty is removed
|
|
522
|
+
from its layout.
|
|
523
|
+
|
|
524
|
+
**Overrides**: `{}` includes a window as declared in the catalog. A
|
|
525
|
+
non-empty block overrides it per key, so you can tweak just `command` or
|
|
526
|
+
`env` without redeclaring `root`; `env` and `commands` maps are merged
|
|
527
|
+
entry by entry. A profile may also declare a window that isn't in the base
|
|
528
|
+
catalog at all. `setup`, `root` and `layouts` replace their base value; a
|
|
529
|
+
profile may not override `session`, since all profiles of a config share
|
|
530
|
+
one tmux session.
|
|
531
|
+
|
|
532
|
+
**Vetoing**: mapping a window to `~` (YAML null) is an explicit "this must
|
|
533
|
+
not run". On its own it changes nothing — an unlisted window is already
|
|
534
|
+
down — but it collides loudly if another selected profile includes the
|
|
535
|
+
same window:
|
|
392
536
|
|
|
393
537
|
```yaml
|
|
394
538
|
profiles:
|
|
395
|
-
|
|
539
|
+
no-db:
|
|
396
540
|
windows:
|
|
397
|
-
|
|
398
|
-
|
|
541
|
+
backend: {}
|
|
542
|
+
db: ~ # refuse to run alongside anything that starts db
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
#### Collisions
|
|
546
|
+
|
|
547
|
+
Overlap between selected profiles is fine as long as they agree. Two
|
|
548
|
+
profiles including the same window, or setting the same key to the same
|
|
549
|
+
value, merge silently. A genuine disagreement aborts before anything
|
|
550
|
+
starts, naming the setting and both profiles:
|
|
551
|
+
|
|
399
552
|
```
|
|
553
|
+
$ mxup up my-project -p backend,staging-backend
|
|
554
|
+
Profile collision: the selected profiles (backend, staging-backend) disagree.
|
|
400
555
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
556
|
+
window 'backend' → command
|
|
557
|
+
backend sets "./start-server.sh"
|
|
558
|
+
staging-backend sets "./connect-staging.sh"
|
|
559
|
+
|
|
560
|
+
Select fewer profiles, or make the conflicting values agree.
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
| Situation | Result |
|
|
564
|
+
|-----------|--------|
|
|
565
|
+
| Several profiles include the same window | fine — included once |
|
|
566
|
+
| One includes a window, another includes it with overrides | fine |
|
|
567
|
+
| Two profiles set different keys of one window | fine — merged |
|
|
568
|
+
| Two profiles set the same key to the same value | fine |
|
|
569
|
+
| Two profiles set the same key to different values | **collision** |
|
|
570
|
+
| One profile vetoes a window another includes | **collision** |
|
|
571
|
+
| Several profiles veto the same window | fine — it stays down |
|
|
572
|
+
|
|
573
|
+
The same rule covers `setup`, `root` and `layouts` (compared whole) and
|
|
574
|
+
`live_env` (compared per variable). Every conflict in a selection is
|
|
575
|
+
reported at once, not one per run.
|
|
404
576
|
|
|
405
577
|
**Switching**: if the tmux session is already running under a different
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
`
|
|
578
|
+
selection, `mxup up` runs `down` first (including the graceful-stop
|
|
579
|
+
dance), then brings the new selection up from a clean slate. Order doesn't
|
|
580
|
+
matter — `-p a,b` and `-p b,a` are the same live stack, so re-running
|
|
581
|
+
either leaves the panes alone. `mxup status` always shows the currently
|
|
582
|
+
live selection in its header.
|
|
583
|
+
|
|
584
|
+
#### Profiles in the 0.x format
|
|
585
|
+
|
|
586
|
+
A config with no [`mxup_version`](#config-format-versions) — anything
|
|
587
|
+
written for mxup `0.3.1` or earlier — keeps the profile semantics it was
|
|
588
|
+
written against. They are **subtractive**, and the differences are worth
|
|
589
|
+
knowing if you're reading the section above with an old config in hand:
|
|
590
|
+
|
|
591
|
+
| | 0.x format (no `mxup_version`) | 1.x format (`mxup_version: '1'`) |
|
|
592
|
+
|---|---|---|
|
|
593
|
+
| `windows:` | the live set — everything in it runs | a catalog — nothing runs until a profile opts in |
|
|
594
|
+
| A profile listing nothing (`staging: {}`) | runs every window, unchanged | runs nothing |
|
|
595
|
+
| A window no profile mentions | runs | stays down |
|
|
596
|
+
| `name: ~` in a profile | drops that window | vetoes it; collides with a profile that includes it |
|
|
597
|
+
| Profiles selected at once | exactly one | any number, unioned |
|
|
598
|
+
| `default_profile` | one name | a name or a list |
|
|
599
|
+
|
|
600
|
+
Everything else — `setup`, `root` and `layouts` replacing their base
|
|
601
|
+
value, `live_env` merging per variable, `env` and `commands` merging entry
|
|
602
|
+
by entry, the ban on overriding `session` — behaves the same in both.
|
|
603
|
+
|
|
604
|
+
So under a 0.x config, `-p` takes a single profile:
|
|
605
|
+
|
|
606
|
+
```bash
|
|
607
|
+
mxup up my-project -p staging # fine
|
|
608
|
+
mxup up my-project -p a,b # rejected: multi-select is a 1.x feature
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
To move a config to the 1.x format, run `mxup migrations`, list the
|
|
612
|
+
windows each profile should run, then add `mxup_version: '1'`. There's no
|
|
613
|
+
deadline: mxup goes on reading the 0.x format. The one thing that changed
|
|
614
|
+
is that a profile which drops *every* window is now an error ("Config
|
|
615
|
+
declares no windows") rather than an empty session.
|
|
409
616
|
|
|
410
617
|
## Commands
|
|
411
618
|
|
|
@@ -422,6 +629,7 @@ graceful-stop dance), then brings the new profile up from a clean slate.
|
|
|
422
629
|
| `mxup target [name]` | Print targets for every declared window (tab-separated) |
|
|
423
630
|
| `mxup exec -t [name:]<window> "<cmd>"` | Run `<cmd>` in a pane, wait for completion, print output, exit with its status |
|
|
424
631
|
| `mxup [name] <window>:<command>` | Run a window's named `command` in a copy of its environment, streaming output to your shell |
|
|
632
|
+
| `mxup migrations` | Print what each major version changed in the config format, and how to update a config (needs no config file) |
|
|
425
633
|
|
|
426
634
|
### Flags
|
|
427
635
|
|
|
@@ -431,7 +639,7 @@ graceful-stop dance), then brings the new profile up from a clean slate.
|
|
|
431
639
|
| `--dry-run` | Preview changes without applying (for `up`, `restart`, `exec`) |
|
|
432
640
|
| `--lines N` | Output lines to show (for `status` default 15, for `exec` default 50) |
|
|
433
641
|
| `--layout NAME` | Layout to use (for `up`) |
|
|
434
|
-
| `-p`, `--profile NAME` | Profile to
|
|
642
|
+
| `-p`, `--profile NAME` | Profile(s) to select; repeatable and comma-separated. Auto-teardowns a live session running under a different selection (for `up`, `status`, `restart`) |
|
|
435
643
|
| `-t TARGET` | Pane target (for `exec`); accepts `name:window`, `window`, or `window.pane` |
|
|
436
644
|
| `--timeout N` | Max seconds to wait for the command (for `exec`; exit 124 on timeout) |
|
|
437
645
|
| `--force` | Send the command even if the pane is busy with another process (for `exec`) |
|
|
@@ -519,6 +727,12 @@ session is up, and won't disturb the long-running process. (The window's
|
|
|
519
727
|
|
|
520
728
|
## Releasing
|
|
521
729
|
|
|
730
|
+
**Versioning promise.** The major version is bumped **only** when the config
|
|
731
|
+
format gains a new generation, and every older generation goes on being read
|
|
732
|
+
— so a config that any release accepts is accepted by every later release,
|
|
733
|
+
whatever its major. That's what [`mxup_version`](#config-format-versions)
|
|
734
|
+
selects. Additive config features (new optional keys) go in a minor release.
|
|
735
|
+
|
|
522
736
|
Releases are automated by `.github/workflows/release.yml`. To cut a new version:
|
|
523
737
|
|
|
524
738
|
1. Bump `Mxup::VERSION` in `lib/mxup/version.rb`.
|
data/bin/mxup
CHANGED
|
@@ -7,4 +7,9 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
|
7
7
|
|
|
8
8
|
require 'mxup'
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
# No `__FILE__ == $PROGRAM_NAME` guard: this file is only ever an entry point,
|
|
11
|
+
# and RubyGems' generated wrapper `load`s it with $PROGRAM_NAME pointing at the
|
|
12
|
+
# wrapper — so the guard was false for every `gem install` and the CLI silently
|
|
13
|
+
# did nothing. Homebrew's wrapper execs this file directly, which is why the
|
|
14
|
+
# formula kept working and hid it.
|
|
15
|
+
Mxup::CLI.new.run(ARGV)
|
data/examples/myapp-dev.yml
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
#
|
|
3
3
|
# This is a showcase config — it exercises most mxup features (multiple
|
|
4
4
|
# windows, wait_for probes, per-window env, alternative layouts, and
|
|
5
|
-
# profiles
|
|
6
|
-
#
|
|
5
|
+
# combinable profiles). Adapt the paths, commands, and env vars to your
|
|
6
|
+
# own project.
|
|
7
7
|
#
|
|
8
8
|
# Place your copy at ~/.config/mxup/myapp-dev.yml, then:
|
|
9
9
|
# mxup up myapp-dev
|
|
@@ -15,13 +15,23 @@
|
|
|
15
15
|
# mxup layout myapp-dev compact
|
|
16
16
|
# mxup up myapp-dev --layout=flat
|
|
17
17
|
#
|
|
18
|
-
#
|
|
19
|
-
# mxup up myapp-dev
|
|
20
|
-
# mxup up myapp-dev
|
|
18
|
+
# Select profiles (tears down a different live selection first):
|
|
19
|
+
# mxup up myapp-dev # the default_profile selection
|
|
20
|
+
# mxup up myapp-dev -p backend,frontend # everything on localhost
|
|
21
|
+
# mxup up myapp-dev -p frontend-staging # frontend only, hosted API
|
|
22
|
+
# mxup up myapp-dev -p backend -p scratch # the flag is repeatable too
|
|
21
23
|
#
|
|
22
24
|
# Parameterize via env vars:
|
|
23
25
|
# DOCKER_PROFILES=core mxup up myapp-dev
|
|
24
26
|
|
|
27
|
+
# The config format generation this file is written for. Optional: mxup reads
|
|
28
|
+
# every generation up to its own, so a file without this key is read as the
|
|
29
|
+
# pre-1.0 format (major 0) and keeps working. Declaring '1' is what opts this
|
|
30
|
+
# file in to the 1.x format — most visibly, additive profiles (see the bottom
|
|
31
|
+
# of this file). Only the major is read; minor and patch don't matter. Run
|
|
32
|
+
# `mxup migrations` to see what each generation changed.
|
|
33
|
+
mxup_version: '1'
|
|
34
|
+
|
|
25
35
|
session: myapp-dev
|
|
26
36
|
|
|
27
37
|
# Base directory for the windows below. Relative values are resolved against
|
|
@@ -97,8 +107,8 @@ windows:
|
|
|
97
107
|
wait_for:
|
|
98
108
|
http: http://localhost:8080/health
|
|
99
109
|
timeout: 60
|
|
100
|
-
|
|
101
|
-
|
|
110
|
+
# API_URL is deliberately absent: each profile that selects this window
|
|
111
|
+
# supplies the backend it should talk to.
|
|
102
112
|
command: pnpm run dev
|
|
103
113
|
|
|
104
114
|
storybook:
|
|
@@ -126,16 +136,41 @@ layouts:
|
|
|
126
136
|
|
|
127
137
|
flat: {}
|
|
128
138
|
|
|
139
|
+
# Selection used when `--profile` is omitted. Without this, `mxup up` would
|
|
140
|
+
# select only the first profile declared below.
|
|
141
|
+
default_profile: [backend, frontend]
|
|
142
|
+
|
|
143
|
+
# Profiles are additive slices of the `windows:` block above: each one lists
|
|
144
|
+
# the windows it runs, and any number can be selected at once. A window no
|
|
145
|
+
# selected profile lists simply doesn't start. Selecting two profiles that
|
|
146
|
+
# override the same setting differently aborts with an explanation.
|
|
129
147
|
profiles:
|
|
130
|
-
# Everything
|
|
131
|
-
|
|
148
|
+
# Everything backend, running locally via docker + ./gradlew run.
|
|
149
|
+
backend:
|
|
150
|
+
windows:
|
|
151
|
+
docker: {}
|
|
152
|
+
api: {}
|
|
153
|
+
worker: {}
|
|
154
|
+
scheduler: {}
|
|
155
|
+
|
|
156
|
+
frontend:
|
|
157
|
+
windows:
|
|
158
|
+
frontend:
|
|
159
|
+
env:
|
|
160
|
+
API_URL: http://localhost:8080
|
|
161
|
+
storybook: {}
|
|
132
162
|
|
|
133
|
-
#
|
|
134
|
-
|
|
163
|
+
# The same frontend windows, pointed at the hosted API. Selecting this
|
|
164
|
+
# together with `frontend` collides — both set `frontend`'s API_URL, to
|
|
165
|
+
# different values — so pick one or the other.
|
|
166
|
+
frontend-staging:
|
|
135
167
|
windows:
|
|
136
|
-
api: ~
|
|
137
|
-
worker: ~
|
|
138
|
-
scheduler: ~
|
|
139
168
|
frontend:
|
|
140
169
|
env:
|
|
141
170
|
API_URL: https://api.staging.example.com
|
|
171
|
+
storybook: {}
|
|
172
|
+
|
|
173
|
+
# Add-on slice: composes with any of the above.
|
|
174
|
+
scratch:
|
|
175
|
+
windows:
|
|
176
|
+
scratch: {}
|
data/lib/mxup/cli.rb
CHANGED
|
@@ -6,7 +6,7 @@ module Mxup
|
|
|
6
6
|
# Argv parser + dispatch. Keeps parsing rules in one place; the actual
|
|
7
7
|
# behaviour lives in Runner and the focused modules it drives.
|
|
8
8
|
class CLI
|
|
9
|
-
COMMANDS = %w[up status down restart layout target exec watch].freeze
|
|
9
|
+
COMMANDS = %w[up status down restart layout target exec watch migrations].freeze
|
|
10
10
|
|
|
11
11
|
def run(argv)
|
|
12
12
|
args, options = parse(argv.dup)
|
|
@@ -28,7 +28,7 @@ module Mxup
|
|
|
28
28
|
options = {
|
|
29
29
|
dry_run: false, config: nil, lines: nil, layout: nil,
|
|
30
30
|
target: nil, timeout: nil, force: false, quiet: false,
|
|
31
|
-
|
|
31
|
+
profiles: []
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
parser = OptionParser.new do |opts|
|
|
@@ -38,7 +38,8 @@ module Mxup
|
|
|
38
38
|
opts.on('--lines N', Integer, 'Output lines (status/exec)') { |n| options[:lines] = n }
|
|
39
39
|
opts.on('--layout NAME', 'Layout to use (for up/layout)') { |l| options[:layout] = l }
|
|
40
40
|
opts.on('-p', '--profile NAME',
|
|
41
|
-
'Profile to use
|
|
41
|
+
'Profile(s) to use; repeatable or comma-separated ' \
|
|
42
|
+
'(for up/status/restart/layout)') { |p| options[:profiles] << p }
|
|
42
43
|
opts.on('-t', '--target TARGET',
|
|
43
44
|
'Target window/pane for exec (e.g. name:window)') { |t| options[:target] = t }
|
|
44
45
|
opts.on('--timeout N', Integer, 'Timeout in seconds (exec)') { |n| options[:timeout] = n }
|
|
@@ -69,6 +70,8 @@ module Mxup
|
|
|
69
70
|
when 'layout' then run_layout(args, options)
|
|
70
71
|
when 'exec' then run_exec(args, options)
|
|
71
72
|
when 'watch' then run_watch(args, options)
|
|
73
|
+
# Needs no config — it's what you run when your config won't load.
|
|
74
|
+
when 'migrations' then Migrations.render
|
|
72
75
|
else
|
|
73
76
|
abort "Unknown command: #{command}. Use: #{COMMANDS.join(', ')}"
|
|
74
77
|
end
|
|
@@ -126,7 +129,7 @@ module Mxup
|
|
|
126
129
|
# declares any `live_env`. Useful in the foreground for debugging.
|
|
127
130
|
def run_watch(args, options)
|
|
128
131
|
name = args.shift
|
|
129
|
-
config = load_config(options[:config], name, options[:
|
|
132
|
+
config = load_config(options[:config], name, options[:profiles])
|
|
130
133
|
if config.live_env.empty?
|
|
131
134
|
abort "Config has no live_env declared; nothing to watch."
|
|
132
135
|
end
|
|
@@ -176,17 +179,17 @@ module Mxup
|
|
|
176
179
|
end
|
|
177
180
|
|
|
178
181
|
def build_runner(options, name)
|
|
179
|
-
config = load_config(options[:config], name, options[:
|
|
182
|
+
config = load_config(options[:config], name, options[:profiles])
|
|
180
183
|
Runner.new(config, dry_run: options[:dry_run], layout: options[:layout])
|
|
181
184
|
end
|
|
182
185
|
|
|
183
|
-
def load_config(explicit_path, name,
|
|
186
|
+
def load_config(explicit_path, name, profiles = [])
|
|
184
187
|
path = resolve_config(explicit_path, name)
|
|
185
188
|
unless path
|
|
186
189
|
abort "Config not found. Provide -f path, place config in #{CONFIG_DIR}/, " \
|
|
187
190
|
"or in a local ./#{LOCAL_CONFIG_DIR}/ directory."
|
|
188
191
|
end
|
|
189
|
-
Config.new(path,
|
|
192
|
+
Config.new(path, profiles: profiles)
|
|
190
193
|
rescue ArgumentError => e
|
|
191
194
|
abort e.message
|
|
192
195
|
end
|