wslc-wip 1.1.3 → 1.1.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 753cbc1f34c7c0c598edd7b4e4bc821953b97e12c66cec448096e05a0debd909
4
- data.tar.gz: c9cc51e4f53a4f8240be292487315ee4cdec019febc006d232d09560457e1a20
3
+ metadata.gz: 585bcc92d8ab78eb38c134e779738c6eb527dd57b8aad87bbfae18a724a10974
4
+ data.tar.gz: 908afba4af5470c777896379a143a6759ab08ef453f6d8baf727e22ff4a8adf2
5
5
  SHA512:
6
- metadata.gz: c45401f388f42dc378066a1a3e14b39b622f13087f8627439f59ce8fa384fa2fb7f162bee8d6ee1f11581e32d5ece6d782bcb2d1c7bfd06f64973944d30ee1c5
7
- data.tar.gz: beb47f232295309e11aa6df585b829165fa125024283da3e29f8ee222ea05eaee530df0ee9f759bb2de8b29b11dfb789d883691c8750e43e6e5655b44ebc4122
6
+ metadata.gz: c01879ea531294531b0283b53a7fdfe01586a8c9c17dbd83814ad92c11d915cecd5f141a0ffd6f94f96dd633e0e63657f15a10ec4f1e372cc53ea0207a8b22be
7
+ data.tar.gz: e3cb38ab627b56487b8965f9107c03f7081fd24defb2a731415af8e9533cd51e5af1eea5da3f0075d854371cbb77ed6e1b75c8843737df4528e806965bfc5137
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ <img src="docs/logo.png" alt="wip logo" width="120" align="left">
2
+
1
3
  # wip
2
4
 
3
5
  [![Tests](https://github.com/slidict/wip/actions/workflows/test.yml/badge.svg)](https://github.com/slidict/wip/actions/workflows/test.yml)
@@ -5,7 +7,7 @@
5
7
  [![License: MIT](https://img.shields.io/github/license/slidict/wip.svg)](LICENSE)
6
8
  [![Ruby](https://img.shields.io/badge/ruby-%3E%3D%203.2-red.svg)](wslc-wip.gemspec)
7
9
 
8
- Homepage: https://wslc-wip.slidict.com/
10
+ Homepage: https://wslc-wip.slidict.com/ · **[Full documentation: wip Wiki](https://github.com/slidict/wip/wiki)**
9
11
 
10
12
  `wip` is a Ruby-built OSS CLI wrapper that brings a [`dip`](https://github.com/bibendi/dip)-like
11
13
  workflow to Microsoft WSLC. It collects a project's container, image, environment variables, and
@@ -16,25 +18,19 @@ commands into a single `wip.yml`, and forwards them to `wslc.exe` / `wslc` as sa
16
18
 
17
19
  > **Status:** early release. Expect to track WSLC's own interface as it evolves.
18
20
 
21
+ This README covers the fastest path to a running `wip.yml`. For everything else — every config
22
+ key, every command's flags, guides, and troubleshooting — see the **[wip Wiki](https://github.com/slidict/wip/wiki)**.
23
+
19
24
  ## Contents
20
25
 
21
26
  - [Which mode should you use?](#which-mode-should-you-use)
22
27
  - [Requirements & installation](#requirements--installation)
23
28
  - [Quick start](#quick-start)
24
29
  - [Configuration](#configuration)
25
- - [Container mode](#container-mode)
26
- - [Compose mode](#compose-mode)
27
- - [Compose mode (native)](#compose-mode-native)
28
- - [.env](#env)
29
- - [.dockerignore](#dockerignore)
30
- - [Source sync](#source-sync)
31
30
  - [Commands](#commands)
32
- - [doctor](#doctor)
33
31
  - [Common errors](#common-errors)
34
- - [FAQ](#faq)
35
32
  - [Development](#development)
36
33
  - [Contributing](#contributing)
37
- - [Roadmap](#roadmap)
38
34
  - [License](#license)
39
35
 
40
36
  ## Which mode should you use?
@@ -43,12 +39,14 @@ commands into a single `wip.yml`, and forwards them to `wslc.exe` / `wslc` as sa
43
39
 
44
40
  | Situation | Use |
45
41
  |---|---|
46
- | No `compose.yml` — wip manages containers directly | [`mode: container`](#container-mode) (default) |
47
- | Have `compose.yml`, don't want to install a third-party tool | [`mode: compose-native`](#compose-mode-native) |
48
- | Have `compose.yml` and already use/prefer a third-party compose-for-`wslc` tool | [`mode: compose`](#compose-mode) |
42
+ | No `compose.yml` — wip manages containers directly | `mode: container` (default) |
43
+ | Have `compose.yml`, don't want to install a third-party tool | `mode: compose-native` |
44
+ | Have `compose.yml` and already use/prefer a third-party compose-for-`wslc` tool | `mode: compose` |
49
45
 
50
- `wip init` picks `compose-native` automatically when it finds a `compose.yml`/`docker-compose.yml`
51
- next to it, and `container` otherwise — see [Commands](#commands).
46
+ `wip init` picks `compose-native` automatically when it finds a `compose.yml`, `compose.yaml`,
47
+ `docker-compose.yml`, or `docker-compose.yaml` next to it, and `container` otherwise — see
48
+ [Commands](#commands). For the full breakdown and trade-offs, see
49
+ [Choosing a Mode](https://github.com/slidict/wip/wiki/Choosing-a-Mode) on the wiki.
52
50
 
53
51
  ## Requirements & installation
54
52
 
@@ -63,7 +61,8 @@ From source: `bundle install && bundle exec exe/wip version`.
63
61
  ## Quick start
64
62
 
65
63
  This walks through `mode: container` (the default). Already have a `compose.yml`? See
66
- [Which mode should you use?](#which-mode-should-you-use) first.
64
+ [Which mode should you use?](#which-mode-should-you-use) first, or read the wiki's
65
+ [Getting Started](https://github.com/slidict/wip/wiki/Getting-Started) guide.
67
66
 
68
67
  ```bash
69
68
  gem install wslc-wip
@@ -80,8 +79,6 @@ wip rails console
80
79
  Put a `wip.yml` in your project root. Running from a subdirectory walks up to find it, or pass
81
80
  `--config PATH` to point at one explicitly.
82
81
 
83
- ### Container mode
84
-
85
82
  ```yaml
86
83
  version: 1
87
84
  mode: container # default
@@ -148,495 +145,67 @@ sync: # optional; mirror the source into a named volume instead of bind-mounting
148
145
 
149
146
  `env` values are stringified. `wip config` masks any key matching token, password, secret,
150
147
  credential, or auth. Keep real secrets out of the config file and in your runtime environment
151
- instead.
148
+ instead — see [Secret Masking](https://github.com/slidict/wip/wiki/Secret-Masking).
152
149
 
153
150
  `interaction:` can also be spelled `commands:` — the same block under a different name, e.g. for
154
- projects that already use `commands:`. `wip config` prints the effective config using `commands:`.
155
- The two are aliases for the same feature, not separate ones: pick whichever name you like, but declaring both
156
- `commands:` and `interaction:` in the same `wip.yml` is a `ConfigError`.
157
-
158
- #### Dependency containers
159
-
160
- `dependencies:` holds every container uniformly — the primary one `container:` points at and any
161
- sidecar services (a database, Redis, ...) alongside it. Each entry accepts `image` (required),
162
- `command`, `env`, `ports`, `volumes`, `workdir`, and `restart`; there's no separate, differently-shaped
163
- block for "the one you exec into." `container:` has no default; once `dependencies:` has any entries,
164
- wip needs to be told explicitly which one is primary rather than guessing a name. `restart` is stored
165
- but inert on its own see
166
- [Restarting exited dependencies](#restarting-exited-dependencies-wip-up---watch) for what actually
167
- acts on it (`wip up --watch`).
168
-
169
- What sets the primary entry apart is operational, not structural: `wip up` brings up every other
170
- entry by name first (creating `network:` beforehand if it doesn't exist and set), then boots or
171
- starts the primary one — so `bin/rails c` (or anything else run inside it) can reach
172
- `development.mysql`/`redis`/etc. by their dependency name, the same way Compose's service names
173
- resolve. `wip down` tears the primary container and all sidecars down (the network itself is left
174
- in place). Only the primary container is a target for `exec`/`run`/`build`/`interaction:` — sidecars
175
- are only ever started and stopped, matching Compose's own service-vs-you-exec-into-one-of-them
176
- split.
177
-
178
- #### Restarting exited dependencies (`wip up --watch`)
179
-
180
- Real Compose auto-restarts a container tagged `restart: always`/`unless-stopped`/`on-failure` when
181
- it exits. `wslc` has no such policy, and no push-based "container exited" notification for `wip` to
182
- hook into, so the closest approximation is polling: `wip up --watch` brings everything up the same
183
- way `wip up -d` does, then keeps checking (`--interval SECONDS`, default 5) whether any
184
- dependency — the primary container included — has exited, restarting the ones whose `restart:`
185
- allows it.
186
-
187
- ```console
188
- $ wip up --watch
189
- wip: watching app, mysql for exited restart: containers every 5s (running detached; Ctrl-C to stop)
190
- ```
191
-
192
- - `restart:` accepts the same values Compose does — `no` (the default), `always`, `unless-stopped`,
193
- `on-failure`, optionally with a `:MAX_RETRIES` suffix. `wip up --watch` treats the three
194
- restarting values identically: it restarts on any exited container regardless of exit code,
195
- unlike real `on-failure`, which skips a clean (zero) exit — reading an exit code needs a heavier
196
- call this polling loop doesn't make.
197
- - This is a foreground loop, not a background daemon or service — the project intentionally has
198
- neither (see [Roadmap](#roadmap)). Keep the terminal it's running in open, the same as
199
- `wip sync --watch`; Ctrl-C (or closing the terminal) stops the supervision.
200
- - `--watch` implies `-d`: it can't attach a TTY to the primary container and poll in a loop on the
201
- same thread, so the primary container always runs detached under `--watch`, whether or not you
202
- also passed `-d`.
203
- - Not available under `mode: compose` — wip never parses a service list in that mode, so there's
204
- nothing for it to poll; use whatever restart support your external compose-for-`wslc` tool offers.
205
- - It's status-based, not event-based: each tick checks whether a dependency is currently exited, not
206
- whether it *just* exited. It can't tell "crashed on its own" apart from "you ran `wip stop`/
207
- `wip down` in another terminal" — Ctrl-C the `--watch` loop first, or it may race and restart
208
- what you just stopped.
209
- - Re-running `wip up -d --watch` against an already-running stack is safe: an already-running
210
- container's `start` is a no-op, the same as it is for plain `wip up`.
211
- - The exit-detection reads `wslc list --all --format json`'s `State` field as a raw integer, per
212
- `WslcContainerState` ([wsl.dev](https://wsl.dev/api-reference/c/enumerations/wslccontainerstate/)):
213
- `0` invalid, `1` created, `2` running, `3` exited, `4` deleted. Unlike Docker, there's no separate
214
- `dead` state — a `deleted` container is gone and needs `wip up` (not `--watch`) to recreate it.
215
- If `--watch` never restarts anything you believe really exited, run `wip up --watch --debug` and
216
- check the logged `list` entry against this enum.
217
-
218
- ### Compose mode
219
-
220
- If your project already has a real `compose.yml`, don't duplicate it in `dependencies:` — point
221
- `wip` at it instead:
222
-
223
- ```yaml
224
- version: 1
225
- mode: compose # required to enable compose mode; a compose: block with no mode: compose is an error
226
- compose:
227
- service: app # required: which compose service wip run/exec/NAME target
228
- command: wslc-compose # required: the compose-for-wslc binary/path you have installed
229
- file: compose.yml # optional; auto-detected next to wip.yml otherwise
230
- project: myapp # optional; omitted lets the compose tool pick its own default
231
- ```
232
-
233
- `compose:` is mutually exclusive with `dependencies:`/`network` — pick one orchestration path per
234
- project. In compose mode, `wip` becomes a thin bridge to an external compose-for-`wslc` CLI rather
235
- than reimplementing Compose itself.
236
-
237
- `wslc` itself has no native Compose support yet (tracked upstream in
238
- [microsoft/WSL#40948](https://github.com/microsoft/WSL/issues/40948)), and until it does,
239
- independent third-party tools fill the gap — for example
240
- [bacarndiaye/wslc-compose](https://github.com/bacarndiaye/wslc-compose) (Python) and
241
- [inuyume/wslc-compose](https://github.com/inuyume/wslc-compose) (Go), among others. `wslc` is new
242
- and still evolving, so expect more of these to show up (and existing ones to change) over time.
243
- `wip` deliberately doesn't pick a winner or default to any of them (unlike `wslc.command`, which
244
- defaults to `auto` and searches for `wslc.exe`/`wslc`): `compose.command` is required and treats
245
- every implementation equally — set it to whichever binary name or absolute path you've installed.
246
- Whichever one you use needs to understand `-f FILE [-p PROJECT] up|down|exec|logs`, the subset of
247
- the Compose CLI vocabulary `wip` drives. `wip doctor` reports whether the configured command is
248
- found, its version, and which compose file `wip` resolved.
249
-
250
- - `wip up`/`wip down` delegate straight to `<compose command> up -d`/`down`.
251
- - `wip exec`/`wip NAME` (custom `interaction:`) run inside `compose.service`.
252
- - `wip shell` also goes through the bridge: unless `interaction.shell` is defined in `wip.yml`, it
253
- `exec`s `bash` against `compose.service`, falling back to `sh`.
254
- - `wip logs [-f] [SERVICE...]` is only available in compose mode.
255
- - `wip run` has no ephemeral-container equivalent in this exec-only vocabulary, so it falls back
256
- to `exec` against the already-running `compose.service` (wip warns when this happens).
257
- - `interaction:` entries with `type: run`/`type: build` aren't supported in compose mode — use your
258
- compose tool's own `build`/`up --build` directly; compose owns builds for its own services.
259
-
260
- ### Compose mode (native)
261
-
262
- Don't want to install a third-party compose-for-`wslc` tool at all? `mode: compose-native` parses
263
- `compose.yml` itself and drives `wslc` directly, the same way `mode: container` +`dependencies:`
264
- already does — no external binary, and `wip run` gets a real ephemeral `wslc run --rm` instead of
265
- the `exec` fallback above:
266
-
267
- ```yaml
268
- version: 1
269
- mode: compose-native
270
-
271
- compose:
272
- service: app # required: which compose service wip run/exec/NAME target
273
- file: compose.yml # optional; auto-detected next to wip.yml otherwise
274
- project: myapp # optional; also names wip's own project network (defaults to the wip.yml
275
- # directory's name) so services can reach each other by name
276
- ```
277
-
278
- There's no `compose.command` here (no external binary to name), and no top-level `container:` —
279
- `compose.service` already names it.
280
-
281
- This is explicitly a stopgap for as long as `wslc` itself has no native Compose support (tracked
282
- upstream in [microsoft/WSL#40948](https://github.com/microsoft/WSL/issues/40948)) and third-party
283
- compose-for-`wslc` tools stay incomplete. It only understands a minimal subset of the Compose spec.
284
- Within `services.<name>:`, anything outside that subset is a load-time `ConfigError` naming the
285
- offending key, rather than silently ignored — but everything *outside* `services:` at the document's
286
- top level (`networks:`, `volumes:`, `configs:`, `secrets:`, ...) is the one exception: it's read by
287
- real Compose tools, not by `wip`, so `wip` silently ignores it rather than rejecting an otherwise
288
- valid compose.yml over sections it doesn't need to look at:
289
-
290
- - Per service: `image`, `build` (string or `{context:, dockerfile:, args:, shadow_context:}`;
291
- `context` is resolved relative to `compose.yml`, not wherever `wip` is invoked from; `dockerfile`
292
- stays relative to `context` itself — see [.dockerignore](#dockerignore) for what `shadow_context`
293
- does), `command` (shell or exec form), `environment`
294
- (mapping or `KEY=VALUE` array — a mapping value must not be null; host environment pass-through
295
- isn't supported), `ports`/`volumes` (short syntax only — `"host:container"` strings, not
296
- long-syntax mappings), `working_dir`, `user`, `restart` (stored as-is; `no` is the default —
297
- `wip up --watch` is what actually acts on it, see
298
- [Restarting exited dependencies](#restarting-exited-dependencies-wip-up---watch)), `depends_on`
299
- (ordering only — a `condition:` other than `service_started` is rejected, since there's no
300
- health-check support). `tty`, `stdin_open`, and `networks` are accepted but silently ignored:
301
- TTY/stdin allocation is already decided per invocation (see "TTY allocation" below), not fixed
302
- per service, and every service already shares the one project network `compose.project` sets up.
303
- - `wip logs` takes at most one `SERVICE` (defaulting to `compose.service`) — `wslc logs`, like
304
- `docker logs`, follows a single container, unlike a real compose tool's multi-service view.
305
- - `sync:` behaves exactly like `mode: container`'s (falls back to the primary service's own image,
306
- defaults to `sync.mode: exec`) — none of the external bridge's `sync.image`/`sync.build`
307
- requirement applies, since wip itself boots every container here.
308
-
309
- ### .env
310
-
311
- Like `docker compose`, `wip` automatically loads a `.env` file next to `wip.yml` (one `KEY=VALUE`
312
- per line; `#` comments, blank lines, `export` prefixes, and quoted values are all supported) and
313
- passes its keys through as container environment variables on `build`, `up`, `run`, `exec`, and
314
- custom commands. `.env` only fills in keys that aren't already set by the primary container's
315
- `env` or a command/dependency's own `env` — those always win on conflict. Pass `--env-file PATH`
316
- to load a different file instead.
317
-
318
- ### .dockerignore
319
-
320
- `wip build` reads `.dockerignore` from the build context and excludes anything it matches before
321
- handing the context to `wslc build`, since `wslc` sends the context as-is otherwise. Set
322
- `commands.build.shadow_context` in `wip.yml` (or `build.shadow_context` on a compose-native
323
- `build:` service in `compose.yml`) to a directory on the Windows filesystem to enable a persistent
324
- shadow context for projects outside `/mnt/<drive>`. The first build copies every included file;
325
- later builds only copy added or changed files and remove deleted or newly ignored files. Without
326
- this setting the optimization is disabled, and it only applies under WSL2 — on WSL1 (or anywhere
327
- else) the context is handed to `wslc build` directly. Projects already on `/mnt/c` (or another
328
- mounted Windows drive) also continue to build directly even when the setting is present. The path
329
- must live outside the build context itself, or `wip build`/`wip up` refuses it.
330
-
331
- ### Source sync
332
-
333
- Bind-mounting the app directory (`.:/app`) is what usually makes a container boot crawl under
334
- wslc — see [Slow boot when the app directory is
335
- bind-mounted](#slow-boot-when-the-app-directory-is-bind-mounted) for why. A `sync:` block hands
336
- that problem to `wip`: the source is mounted read-only, the app runs off a named volume, and wip
337
- mirrors one into the other with `rsync`.
338
-
339
- `wip up`'s pre-boot mirror always uses a throwaway container (the primary one isn't running yet),
340
- so `sync.image`/`sync.build` apply there regardless of `sync.mode` — falling back to the primary
341
- container's own image if neither is set under `mode: container`/`compose-native` (both have a
342
- `dependencies:` entry to borrow it from); `mode: compose` has no such entry, so one of
343
- `sync.image`/`sync.build` is required there. Where `sync.mode` actually matters is every mirror
344
- *after* that: under `sync.mode: exec` (the default for `mode: container`/`compose-native`), `wip
345
- sync`/`wip sync --watch` run `rsync` inside the already-running primary container instead, so
346
- *that* image needs `rsync` installed — `sync.image`/`sync.build` are ignored for these. Under
347
- `sync.mode: run`, every mirror (pre-boot included) uses a throwaway container, so `sync.image`/
348
- `sync.build` (or the primary image fallback, where available) need `rsync` throughout.
349
-
350
- ```yaml
351
- sync:
352
- source: . # host path, relative to wip.yml (default: the wip.yml directory)
353
- target: /app # container path served by the volume (default: the primary container's workdir, else /app)
354
- volume: app-src # named volume holding the mirror (default: "<container>-src")
355
- mount: /host-src # where the source is bind-mounted read-only (default: /host-src)
356
- exclude: # rsync --exclude patterns
357
- - .git
358
- - tmp/
359
- - node_modules/
360
- delete: true # rsync --delete (default: true)
361
- command: rsync # binary that does the mirroring (default: rsync)
362
- options: [] # extra flags appended to the rsync invocation
363
- interval: 2 # seconds between syncs for `wip sync --watch` (default: 2)
364
- mode: exec # exec (mirror inside the running container) or run (a throwaway one);
365
- # default: exec for `mode: container`, run for `mode: compose`
366
- image: null # image for the mirror container; unused under mode: container unless set
367
- # (falls back to the primary container's own image). Under mode: compose,
368
- # one of image or build is required (there's no dependencies: entry to fall
369
- # back to)
370
- build: # optional; has wip build the mirror image itself instead of requiring one to
371
- # already exist. build.tag wins over image if both are set.
372
- dockerfile: |
373
- FROM alpine:latest
374
- RUN apk add --no-cache rsync
375
- tag: null # optional (default: "wip-sync-<container>:latest")
376
- ```
377
-
378
- `wip init --template NAME` writes `exclude`'s default list live, picked from that stack's own
379
- `github/gitignore` template:
380
-
381
- | `--template` | Stack | Default `exclude` |
382
- |---|---|---|
383
- | `rails` | Rails | `.git`, `log/`, `tmp/`, `storage/`, `public/assets/`, `public/packs/`, `.bundle/`, `vendor/bundle/`, `coverage/`, `node_modules/` |
384
- | `node` | Node.js | `.git`, `node_modules/`, `dist/`, `build/`, `.next/`, `.cache/`, `coverage/` |
385
- | `rust` | Rust | `.git`, `target/` |
386
- | `csharp` | C# | `.git`, `bin/`, `obj/`, `.vs/`, `packages/` |
387
- | (omitted) | — | `.git`, `tmp/`, `node_modules/` |
388
-
389
- Everything below `sync:` is optional — `sync: {}` alone already works. With it in place:
390
-
391
- - Any `volumes` entry on the primary container mounting `target` (the usual `.:/app`) is replaced
392
- by `<source>:/host-src:ro` plus `app-src:/app`, so the running app only ever touches the volume.
393
- Other volumes (`bundle:/usr/local/bundle`, ...) are passed through untouched, and sidecar
394
- `dependencies:` entries keep mounting whatever they declare.
395
- - `wip up` mirrors the source into the volume before the container boots; `wip up --no-sync`
396
- skips that step.
397
- - `wip sync` mirrors on demand: `sync.mode: exec` (the default under `mode: container`) execs
398
- rsync inside the already-running container; `sync.mode: run` always uses a throwaway container
399
- with the same mounts instead. Which one runs is fixed by config, not guessed at from whether a
400
- container happens to be up.
401
- - `wip sync --watch [--interval N]` keeps re-syncing until Ctrl-C, so host edits reach the
402
- container with a short delay. Run it in a second terminal alongside `wip up -d`.
403
- - `wip doctor` reports the resolved source, volume, and target, and fails if the source is missing.
404
- - With `sync.build` configured, `wip build`s that image once per `wip up`/`wip sync` invocation
405
- (including once before a `--watch` loop starts, not on every tick) before mirroring with it.
406
-
407
- Like every built-in command, `wip sync` takes precedence over an `interaction:` entry of the same
408
- name; wip says so and points at `wip dispatch sync`, which still runs yours.
409
-
410
- Two things to keep in mind. The mirror runs `rsync` *inside* the container, so the image needs it
411
- (`RUN apt-get update && apt-get install -y rsync`) — or point `sync.command` at a copy tool the
412
- image already has. And the mirror is one-way (host → volume): anything the app writes under
413
- `target` is removed by the next `--delete` pass unless you `exclude` it, give it its own volume,
414
- or set `delete: false`.
415
-
416
- `sync:` works alongside `mode: compose` too, but two things change:
417
-
418
- - Compose still owns the volume layout, so wip doesn't rewrite any mounts for you: the compose
419
- service that runs your app must itself declare a named volume with the exact same name as
420
- `sync.volume` (`<container>-src` by default) mounted at the path your app expects, e.g.:
421
- ```yaml
422
- # compose.yml
423
- services:
424
- app:
425
- volumes:
426
- - app-src:/app
427
- volumes:
428
- app-src:
429
- ```
430
- wip's mirror writes into that volume from a separate, disposable container; it never touches
431
- the compose service directly.
432
- - `sync.mode` defaults to `run` and can't be set to `exec` (only a container wip itself booted is
433
- guaranteed to have the read-only source mount attached, which compose services never do), and
434
- `sync.image` or `sync.build` becomes required, since that disposable container needs an image
435
- from somewhere — under `mode: container` it borrows the primary `dependencies:` entry's image,
436
- but compose mode has no such entry to borrow from.
437
-
438
- `wip up`'s pre-boot mirror (and the `--no-sync` flag that skips it) works the same way under
439
- `mode: compose` as it does otherwise: the source is mirrored into the volume before
440
- `compose up` starts the service that mounts it.
441
-
442
- Since `sync.mode: run` boots a fresh container on every mirror, reusing your app's full image here
443
- just adds startup overhead for something that only ever runs `rsync`. A dedicated, minimal image is
444
- worth it — `wip` doesn't publish or default to one itself (same reasoning as `compose.command`:
445
- picking a specific third-party image for you isn't its call to make), but `sync.build` covers it
446
- without needing to manage a separate image yourself:
447
-
448
- ```yaml
449
- sync:
450
- build:
451
- dockerfile: |
452
- FROM alpine:latest
453
- RUN apk add --no-cache rsync
454
- ```
455
-
456
- wip builds this once per `wip up`/`wip sync` invocation (not on every `--watch` tick — see above)
457
- and uses the result, tagged `wip-sync-<container>:latest` by default (`build.tag` overrides it).
458
- Prefer managing the image yourself instead? Build and tag it however you like, then set `sync.image`
459
- to that tag directly — `sync.build`'s tag wins if both are set, so don't configure both at once.
151
+ projects that already use `commands:`. The two are aliases for the same feature; declaring both in
152
+ the same `wip.yml` is a `ConfigError`. See [Interactions](https://github.com/slidict/wip/wiki/Interactions).
153
+
154
+ Every key above is covered across the wiki's feature pages, with the full behavior, edge cases,
155
+ and examples — start at the
156
+ **[Configuration Reference](https://github.com/slidict/wip/wiki/Configuration-Reference)**. Notably:
157
+
158
+ - [Dependencies](https://github.com/slidict/wip/wiki/Dependencies) the primary container vs. sidecars
159
+ - [Restart Policies](https://github.com/slidict/wip/wiki/Restart-Policies) /
160
+ [Auto Restarting Containers](https://github.com/slidict/wip/wiki/Auto-Restarting-Containers) `restart:` and `wip up --watch`
161
+ - [Compose Mode](https://github.com/slidict/wip/wiki/Compose-Mode) bridging to a third-party compose-for-`wslc` tool
162
+ - [Compose Native Mode](https://github.com/slidict/wip/wiki/Compose-Native-Mode)wip parsing `compose.yml` itself
163
+ - [Env Files](https://github.com/slidict/wip/wiki/Env-Files) `.env` loading and precedence
164
+ - [Dockerignore](https://github.com/slidict/wip/wiki/Dockerignore) / [Shadow Build Context](https://github.com/slidict/wip/wiki/Shadow-Build-Context)
165
+ - [Source Sync](https://github.com/slidict/wip/wiki/Source-Sync) / [Sync Modes](https://github.com/slidict/wip/wiki/Sync-Modes) / [Continuous Sync](https://github.com/slidict/wip/wiki/Continuous-Sync)
460
166
 
461
167
  ## Commands
462
168
 
463
169
  | Command | Description |
464
170
  |---|---|
465
- | `wip init [--force] [--template NAME]` | Write a starter `wip.yml`: `mode: compose-native` if a `compose.yml`/`docker-compose.yml` is found next to it, `mode: container` otherwise. `--template` picks `sync.exclude`'s default patterns for a stack (`rails`, `node`, `rust`, `csharp`); omitted, it falls back to `.git`/`tmp/`/`node_modules/`. Refuses to overwrite an existing `wip.yml` unless `--force` |
171
+ | `wip init [--force] [--template NAME]` | Write a starter `wip.yml`: `mode: compose-native` if a `compose.yml`, `compose.yaml`, `docker-compose.yml`, or `docker-compose.yaml` is found next to it, `mode: container` otherwise |
466
172
  | `wip version` | wip's version, plus WSLC's if it can be detected |
467
173
  | `wip doctor` | Diagnose WSL2, interop, WSLC, config, architecture, and Git |
468
174
  | `wip config` | Print the effective configuration (secrets masked) |
469
- | `wip build [--no-cache] [-- OPTIONS]` | Build the image from the `build` definition. `wslc build` reuses matching local layers by default; `--no-cache` disables that. |
470
- | `wip up [-d] [--no-sync] [--no-cache] [--watch] [--interval N]` | Start the primary `dependencies:` entry (`container:` names which one) and its sidecars (creating any that are missing, on `network:` if set). `-d` runs the main container in the background; with `sync:` configured, the source is mirrored into the volume first unless `--no-sync`. `--watch` polls every `N` seconds (default 5, implies `-d`) and restarts any exited dependency whose `restart:` allows it (not available under mode: compose) |
471
- | `wip stop` | Stop the primary container and its sidecar `dependencies:` without removing them |
472
- | `wip down` | Stop and remove the primary container and its sidecar `dependencies:` |
175
+ | `wip build [--no-cache] [-- OPTIONS]` | Build the image from the `build` definition |
176
+ | `wip up [-d] [--no-sync] [--no-cache] [--watch] [--interval N]` | Start the configured stack, creating it if necessary |
177
+ | `wip stop` | Stop the configured stack without removing it |
178
+ | `wip down` | Stop and remove the configured stack |
473
179
  | `wip exec [--no-interactive] COMMAND...` | Run a command in the existing container |
474
- | `wip run [--no-interactive] COMMAND...` | Run a command in a new `--rm` container (mode: compose `exec`s into `compose.service` instead see "Compose mode" above) |
180
+ | `wip run [--no-interactive] COMMAND...` | Run a command in a new `--rm` container (`mode: compose` has no ephemeral run — falls back to `exec` in the running service, with a warning) |
475
181
  | `wip shell` | Open the configured shell, falling back to `bash` then `sh` |
476
- | `wip logs [-f] [SERVICE...]` | Follow compose service logs (compose modes only; mode: compose-native takes at most one `SERVICE`) |
477
- | `wip sync [-w] [--interval N]` | Mirror the source into the sync volume once, or keep re-syncing with `--watch` (needs `sync:`) |
182
+ | `wip logs [-f] [SERVICE...]` | Follow compose service logs (compose modes only; under `mode: compose-native`, at most one `SERVICE`) |
183
+ | `wip sync [-w\|--watch] [--interval N]` | Mirror the source into the sync volume once, or keep re-syncing with `--watch` (needs `sync:`) |
478
184
  | `wip NAME ARGS...` | Run `interaction.NAME`, appending any extra arguments |
479
185
 
480
- TTY allocation is decided by combining the command's config, the CLI option, and whether both
481
- stdin and stdout are real TTYs.
482
-
483
- Pass `--debug` (or set `WIP_DEBUG=1`) to see where time is going: wip prints each step it takes —
484
- checking for an existing network/container/dependency, and running the resolved `wslc`/`docker`
485
- command — along with how long that step took, e.g.:
486
-
487
- ```console
488
- $ wip rails c --debug
489
- wip: [debug] running: wslc.exe exec -it -w /app app bin/rails c
490
- + wslc.exe exec -it -w /app app bin/rails c
491
- ...
492
- wip: [debug] done in 4.32s: running: wslc.exe exec -it -w /app app bin/rails c
493
- ```
494
-
495
- For long-running interactive commands (like `rails c`), the "done" line only prints after you
496
- exit, but the timestamp of the `+ ...` line tells you when wip finished its own setup and handed
497
- off to `wslc`/`docker` — useful for telling wip-side overhead apart from time spent booting inside
498
- the container.
499
-
500
- While a step is still running, wip also prints a host resource snapshot (load average, memory,
501
- disk I/O, and the top CPU-consuming processes) every 5 seconds, so a hang is visible even before
502
- the command has produced any output of its own:
503
-
504
- ```console
505
- wip: [debug] still running (load 3.42 2.10 1.05 | mem 6.1G/15.6G | io read 12000KB/s write 400KB/s | top: wslc.exe(8842) cpu 61.0%/mem 3.2%, ...): running: wslc.exe exec -it -w /app app bin/rails c
506
- ```
507
-
508
- The disk I/O figure is worth watching first if the host's CPU and memory look idle — a slow
509
- `bundle`/`rails` boot is often WSL2's bind-mounted (`.:/app`-style) volumes doing a lot of small
510
- reads, not the container starving for CPU.
511
-
512
- For commands that hand the real terminal to the child (`-it`, e.g. `rails c`), these periodic
513
- snapshots go to a log file instead of your terminal — wip prints the path once at the start —
514
- since writing into a terminal the child controls in raw mode would garble both outputs. Commands
515
- that don't need a TTY still get the snapshots printed live.
516
-
517
- Override that choice with `--debug-log`:
186
+ Every command has flags, per-mode behavior, and examples on its own wiki page see the
187
+ **[CLI Command Reference](https://github.com/slidict/wip/wiki/CLI-Command-Reference)**.
518
188
 
519
- - `--debug-log=-` forces snapshots inline even for `-it` commands (only useful if you know your
520
- terminal/pager can tolerate the interleaving).
521
- - `--debug-log=PATH` always writes snapshots to `PATH`, including for non-TTY commands, e.g. to
522
- keep every run's snapshots in one place: `wip rails c --debug --debug-log=/tmp/wip-debug.log`.
189
+ Pass `--debug` (or set `WIP_DEBUG=1`) to see where time is going: wip prints each step it takes,
190
+ along with a periodic host resource snapshot (load, memory, disk I/O, top processes), so a hang is
191
+ visible even before a command produces output. See
192
+ [Debug Output](https://github.com/slidict/wip/wiki/Debug-Output) for the full behavior and the
193
+ `--debug-log` option.
523
194
 
524
- ## doctor
525
-
526
- Each check prints as `[OK]`, `[WARN]`, or `[FAIL]`. Warnings alone exit 0; a WSL2, interop, WSLC,
527
- or config problem that blocks execution exits 1. Git being unreachable from the real build
528
- environment is only a warning.
195
+ `wip doctor` prints `[OK]`/`[WARN]`/`[FAIL]` per check; warnings alone exit 0, a blocking problem
196
+ exits 1. See [`wip doctor`](https://github.com/slidict/wip/wiki/wip-doctor).
529
197
 
530
198
  ## Common errors
531
199
 
532
- ### WSLC not found
533
-
534
- Install or update the WSL container tooling, then run `wip doctor`. `auto` looks for `wslc.exe`,
535
- `wslc`, then `/mnt/c/Windows/System32/wslc.exe`, in that order.
536
-
537
- ### Docker Hub authentication
200
+ - [WSLC not found](https://github.com/slidict/wip/wiki/WSLC-Not-Found)
201
+ - [Docker Hub / registry authentication](https://github.com/slidict/wip/wiki/Registry-Authentication)
202
+ - [Slow boot when the app directory is bind-mounted](https://github.com/slidict/wip/wiki/Fixing-a-Slow-Boot)
203
+ - [CPU architecture mismatch](https://github.com/slidict/wip/wiki/Architecture-Mismatch)
538
204
 
539
- When `pull access denied` (or similar) is detected, wip suggests how to log in:
540
-
541
- ```bash
542
- wslc registry login -u <username> docker.io
543
- ```
544
-
545
- ### Slow boot when the app directory is bind-mounted
546
-
547
- wslc containers run in their own VM, so a bind-mounted host directory (`.:/app`) is always shared
548
- in over virtiofs, even when the host path is already on WSL's native filesystem. Frameworks that
549
- scan large directory trees at startup (Ruby's Zeitwerk autoloader, for example) issue many small
550
- per-file stat/open calls, and each one is a round trip through that layer — CPU on the Windows
551
- side can look busy while almost no data is actually transferred, and the process can appear hung
552
- for minutes with barely any resource usage to show for it.
553
-
554
- If a debug log shows a boot-time command "stuck" with low CPU/mem/IO in `resource_monitor`'s
555
- output, this is worth checking before assuming the app itself is broken. The fix is to stop
556
- bind-mounting the source live and mirror it into a named volume instead, so the app only ever
557
- touches fast native storage once it's running. `wip` does that for you — add a `sync:` block and
558
- it rewrites the mounts, mirrors before boot, and re-syncs on demand. See [Source
559
- sync](#source-sync).
560
-
561
- ### CPU architecture mismatch
562
-
563
- Check the image and publish a multi-arch (amd64/arm64) image:
564
-
565
- ```bash
566
- docker buildx imagetools inspect <image>
567
- docker buildx build \
568
- --platform linux/amd64,linux/arm64 \
569
- -t <image> \
570
- --push .
571
- ```
572
-
573
- ## FAQ
574
-
575
- **Which mode should I start with?**
576
- Pick whichever `mode:` fits your project — see [Which mode should you use?](#which-mode-should-you-use)
577
- for the breakdown.
578
-
579
- **Can I use `dependencies:` and `compose:` together?**
580
- No — `compose:` is mutually exclusive with `dependencies:`/`network`. Pick one orchestration path
581
- per project; see [Configuration](#configuration).
582
-
583
- **What's the difference between `mode: compose` and `mode: compose-native`?**
584
- `compose` delegates to a third-party compose-for-`wslc` binary you install yourself
585
- (`compose.command`); `compose-native` parses `compose.yml` itself and drives `wslc` directly, no
586
- external tool required. `compose-native`'s Compose coverage isn't frozen at whatever it handles
587
- today — it keeps growing until `wslc` ships native Compose support of its own. See
588
- [Compose mode](#compose-mode) and [Compose mode (native)](#compose-mode-native).
589
-
590
- **`dependencies:` already gives me sidecar containers — why would I need `compose-native` too?**
591
- `dependencies:` and `compose-native` aren't really alternatives to each other — they're for two
592
- different starting points. No `compose.yml`? Declare containers directly in `wip.yml`'s own shape
593
- with `dependencies:`. Already have a `compose.yml`? Reusing it is where `compose-native` and
594
- `mode: compose` both come in, so the real comparison is between those two, not against
595
- `dependencies:`: `mode: compose` reuses it too, but only by delegating to a third-party
596
- compose-for-`wslc` binary you install yourself; `compose-native` reuses the same `compose.yml`
597
- without installing anything external, parsing it and driving `wslc` directly — and gets a real
598
- `wslc run --rm` for `wip run` instead of the `exec` fallback `mode: compose` falls back to.
599
- `mode: compose`'s coverage is whatever the external tool you point it at supports; `compose-native`'s
600
- is maintained in this repo and actively extended, not treated as a permanent ceiling. See
601
- [Which mode should you use?](#which-mode-should-you-use) for the full picture.
602
-
603
- **What happens to `compose-native` once `wslc` gets official Compose support?**
604
- `compose-native` exists to close the gap for as long as `wslc` has no native Compose support of its
605
- own (tracked upstream in [microsoft/WSL#40948](https://github.com/microsoft/WSL/issues/40948)), and
606
- we intend to keep extending its Compose coverage until that lands — see
607
- [Compose mode (native)](#compose-mode-native) and [Roadmap](#roadmap). `wip.yml`'s shape (`mode:`,
608
- `compose:`) isn't planned to change for existing `container`/`compose`/`compose-native` setups, so
609
- whatever we do once `wslc` catches up won't require rewriting your config.
610
-
611
- **Is `sync:` required?**
612
- No, it's entirely optional. Add it if boot times feel slow with a bind-mounted app directory — see
613
- [Slow boot when the app directory is bind-mounted](#slow-boot-when-the-app-directory-is-bind-mounted).
614
-
615
- **How does `wip` actually fix the slow bind-mount boot problem?**
616
- The slowness comes from `.:/app`-style bind mounts going through virtiofs, where frameworks that
617
- stat/open many small files at startup (e.g. Ruby's Zeitwerk) pay a round trip per file. A `sync:`
618
- block moves the app off that path entirely: the host source is mounted read-only, the app itself
619
- runs off a named volume (fast native storage inside the VM), and `wip` mirrors the read-only
620
- source into that volume with `rsync` — once before boot, and on demand afterward via `wip sync`
621
- (or continuously with `wip sync --watch`). Since the app never touches the bind mount directly, its
622
- own file access is no longer paying the virtiofs cost; the trade-off is a one-way, slightly-delayed
623
- mirror instead of an always-live view of host edits. See [Source sync](#source-sync) for the full
624
- config and [Slow boot when the app directory is bind-mounted](#slow-boot-when-the-app-directory-is-bind-mounted)
625
- for the root cause.
626
-
627
- **Is it safe to put passwords/secrets in `wip.yml`?**
628
- `wip config` masks any key matching token/password/secret/credential/auth when printing, but the
629
- raw file itself is not encrypted. Keep real secrets in your runtime environment or `.env` instead
630
- of committing them in `wip.yml` — but `.env` is only safe if it's actually untracked: add `.env` to
631
- `.gitignore` (and confirm with `git check-ignore .env`) before putting anything sensitive in it.
632
-
633
- **`wslc.exe`/`wslc` isn't found — what do I do?**
634
- See [WSLC not found](#wslc-not-found) under Common errors.
635
-
636
- **I'm migrating from `dip` — do I have to rename `interaction:`?**
637
- No, `wip.yml` accepts `interaction:` as-is — it's the primary spelling, same as in `dip`. `commands:`
638
- also works as an alias if you prefer it, but not both in the same file (that's a `ConfigError`). See
639
- [Container mode](#container-mode).
205
+ More errors, causes, and fixes are indexed on the wiki's
206
+ **[Troubleshooting & FAQ](https://github.com/slidict/wip/wiki/Troubleshooting-and-FAQ)** page,
207
+ including [Configuration Errors](https://github.com/slidict/wip/wiki/Configuration-Errors) (every
208
+ `ConfigError` and what triggers it).
640
209
 
641
210
  ## Development
642
211
 
@@ -651,7 +220,9 @@ bundle exec rake
651
220
 
652
221
  The test suite doesn't need WSLC — the resolution, build, and execution layers are all
653
222
  swappable. This project uses RuboCop for Ruby style and static analysis; `bundle exec rake` runs
654
- both RSpec and RuboCop. GitHub Actions checks them on Ruby 3.2, 3.3, 3.4, and 4.0.
223
+ both RSpec and RuboCop. GitHub Actions checks them on Ruby 3.2, 3.3, 3.4, and 4.0. See
224
+ [Development](https://github.com/slidict/wip/wiki/Development) and
225
+ [Architecture](https://github.com/slidict/wip/wiki/Architecture) on the wiki for more.
655
226
 
656
227
  ## Contributing
657
228
 
@@ -659,53 +230,6 @@ Bug reports and pull requests are welcome on [GitHub](https://github.com/slidict
659
230
  [CONTRIBUTING.md](CONTRIBUTING.md) for commit conventions, versioning policy, and the PR
660
231
  checklist.
661
232
 
662
- ## Roadmap
663
-
664
- `wip` already covers most of what [`dip`](https://github.com/bibendi/dip) adds on top of Compose —
665
- named commands (`interaction:`), `run`/`exec` hidden behind a single verb, `.env` passthrough, and
666
- sidecar services via `dependencies:` + `network:`. Rather than waiting on `wslc`'s own Compose
667
- support ([microsoft/WSL#40948](https://github.com/microsoft/WSL/issues/40948)) or an external
668
- compose-for-`wslc` tool staying complete, `mode: compose-native` (see
669
- [Compose mode (native)](#compose-mode-native)) parses `compose.yml` itself and drives `wslc`
670
- directly — no external binary in the loop, `wip run` gets a real `--rm` container, and iterating
671
- on the parser is faster than chasing a third-party tool's own bugs. It's still a deliberately
672
- minimal subset (`depends_on` ordering but no health checks, single-container `logs`, no named
673
- volumes/scaling), and `dependencies:` + `network:` remains the escape hatch for sidecars it
674
- doesn't model. Fuller Compose semantics beyond that subset stay behind delegating to a separate
675
- compose-for-`wslc` tool in [compose mode](#compose-mode) — which of those actually work is
676
- entirely up to the external tool you point `compose.command` at; `wip` only forwards
677
- `-f FILE [-p PROJECT] up|down|exec|logs`, so treat that list as what Compose offers, not as
678
- something `wip` guarantees. See that section for what compose mode covers
679
- and its current limitations (`run`, and `interaction:` of type `run`/`build`).
680
-
681
- Beyond Compose parity, a resident/daemon process, a GUI, PowerShell-specific tuning, direct
682
- registry API/manifest parsing, self-update, and plugins are all unimplemented and not currently
683
- planned. (`wip up --watch`'s restart-policy poll loop isn't an exception to this — it's a
684
- foreground, opt-in loop you keep a terminal open for, the same shape as `wip sync --watch`, not a
685
- background service; see
686
- [Restarting exited dependencies](#restarting-exited-dependencies-wip-up---watch).) What's still
687
- planned for `wip`, roughly in priority order:
688
-
689
- 1. **`wip provision`** — a dip-style one-shot bootstrap hook (build → up deps → install deps →
690
- create/migrate/seed DB) so a new contributor can go from `git clone` to a working environment
691
- in two commands (`wip provision && wip up`).
692
- 2. **Config file merging** — `--config` currently accepts one file; support layering
693
- (`wip.yml` + `wip.override.yml`, or a `WIP_CONFIG` list) for dev/CI/debug variants without
694
- duplicating the whole file, plus a `wip config --resolved` view of the merged result.
695
- 3. **Bind-mount boot time (`rails c`, `bundle`, ...)** — commands like `wip rails c` still start
696
- noticeably slower than the equivalent under `docker compose`, mostly from WSL2 bind-mounted
697
- (`.:/app`-style) volumes doing many small reads for gems/`node_modules` (use `--debug` to
698
- confirm it's disk I/O and not `wip`'s own overhead). [Source sync](#source-sync) works around
699
- this today by running the app off a named volume and mirroring the host tree into it, at the
700
- cost of a one-way sync with a short delay. A tighter loop (host-side file watching instead of
701
- interval polling, two-way sync) is the natural next step. We're also hoping for improvements on
702
- the `wslc` side itself (faster bind-mount/cache behavior); `wip` will pick those up for free as
703
- soon as they land.
704
-
705
- Each of these should stay additive to the existing `wip.yml` shape — no breaking changes to
706
- `container`, `network`, `commands`, `dependencies`, or `compose` are planned. A resident daemon
707
- and a GUI remain out of scope.
708
-
709
233
  ## License
710
234
 
711
235
  [MIT License](LICENSE)
@@ -11,6 +11,7 @@ module Wip
11
11
  # --template values wip init accepts, and the label used in the exclude: comment.
12
12
  TEMPLATE_LABELS = {
13
13
  'rails' => 'Rails',
14
+ 'ruby' => 'Ruby',
14
15
  'node' => 'Node.js',
15
16
  'rust' => 'Rust',
16
17
  'csharp' => 'C#'
@@ -22,6 +23,7 @@ module Wip
22
23
  TEMPLATE_EXCLUDES = {
23
24
  'rails' => %w[.git log/ tmp/ storage/ public/assets/ public/packs/ .bundle/ vendor/bundle/
24
25
  coverage/ node_modules/],
26
+ 'ruby' => %w[.git log/ tmp/ .bundle/ vendor/bundle/ coverage/],
25
27
  'node' => %w[.git node_modules/ dist/ build/ .next/ .cache/ coverage/],
26
28
  'rust' => %w[.git target/],
27
29
  'csharp' => %w[.git bin/ obj/ .vs/ packages/]
data/lib/wip/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Wip
4
- VERSION = '1.1.3'
4
+ VERSION = '1.1.4'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wslc-wip
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.3
4
+ version: 1.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wip contributors
@@ -56,15 +56,14 @@ files:
56
56
  - lib/wip/sync_settings.rb
57
57
  - lib/wip/variable_interpolation.rb
58
58
  - lib/wip/version.rb
59
- homepage: https://wslc-wip.slidict.com/
59
+ homepage: https://github.com/slidict/wip
60
60
  licenses:
61
61
  - MIT
62
62
  metadata:
63
63
  rubygems_mfa_required: 'true'
64
- homepage_uri: https://wslc-wip.slidict.com/
65
- source_code_uri: https://github.com/slidict/wip
64
+ homepage_uri: https://github.com/slidict/wip
66
65
  changelog_uri: https://github.com/slidict/wip/releases
67
- bug_tracker_uri: https://github.com/slidict/wip/issues
66
+ source_code_uri: https://github.com/slidict/wip/tree/v1.1.4
68
67
  rdoc_options: []
69
68
  require_paths:
70
69
  - lib