wslc-wip 0.14.2 → 0.15.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f9b53bdcacc5491c788acf9af933f377cc0afe046ef133391ae866700145c83
4
- data.tar.gz: b4ad717fba296d8082bc272238a8dd83afa206f7aaca67628e47186a0551c531
3
+ metadata.gz: b8248f18abf8e946e333de3e2e9b70e72b9b0f8806a3216c97e62bfe83ad53bb
4
+ data.tar.gz: 19119fe6787aad4b17cc6ed9e1f1048d664cbcd119414bd4bc4b86e0c26dfb5d
5
5
  SHA512:
6
- metadata.gz: d65e654b92b30b19a987c2b239014bb0071b92bd99d0fdb09728e23ce3948488a330ebbf61878d7c81c7b4f588888d87720e41542f91e947c7358a02e495fbe2
7
- data.tar.gz: 3008f5c32bfaa6771ef60a75d8445a427b3ddcbc9ef19f226602275a3b4eb997a6f9b7d99fc649dcc481dcfacbeea8b32e0c03a6902934f82d6c7534a08901af
6
+ metadata.gz: 91535a4b496bc4cc2e55cc44d7feadbf8709811df0ab660c7d7fe8e6f20feccac18a497804b13bd83a6d2775396e3061c51f64040864e3d6635eeaf22edf9b8e
7
+ data.tar.gz: 1151d286900c2c11812c607f123d966862ea41b1ac5ee01a74d957f0626667c616fdabf13f618fdad4a62a1b4c8a26f1c68bf837030f1e8f4508a8f2d0e733b1
data/README.md CHANGED
@@ -181,6 +181,17 @@ sync:
181
181
  tag: null # optional (default: "wip-sync-<container>:latest")
182
182
  ```
183
183
 
184
+ `wip init --template NAME` writes `exclude`'s default list live, picked from that stack's own
185
+ `github/gitignore` template:
186
+
187
+ | `--template` | Stack | Default `exclude` |
188
+ |---|---|---|
189
+ | `rails` | Rails | `.git`, `log/`, `tmp/`, `storage/`, `public/assets/`, `public/packs/`, `.bundle/`, `vendor/bundle/`, `coverage/`, `node_modules/` |
190
+ | `node` | Node.js | `.git`, `node_modules/`, `dist/`, `build/`, `.next/`, `.cache/`, `coverage/` |
191
+ | `rust` | Rust | `.git`, `target/` |
192
+ | `csharp` | C# | `.git`, `bin/`, `obj/`, `.vs/`, `packages/` |
193
+ | (omitted) | — | `.git`, `tmp/`, `node_modules/` |
194
+
184
195
  Everything below `sync:` is optional — `sync: {}` alone already works. With it in place:
185
196
 
186
197
  - Any `volumes` entry on the primary container mounting `target` (the usual `.:/app`) is replaced
@@ -341,7 +352,7 @@ valid compose.yml over sections it doesn't need to look at:
341
352
 
342
353
  | Command | Description |
343
354
  |---|---|
344
- | `wip init [--force]` | Write a starter `wip.yml`: `mode: compose-native` if a `compose.yml`/`docker-compose.yml` is found next to it, `mode: container` otherwise. Refuses to overwrite an existing `wip.yml` unless `--force` |
355
+ | `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` |
345
356
  | `wip version` | wip's version, plus WSLC's if it can be detected |
346
357
  | `wip doctor` | Diagnose WSL2, interop, WSLC, config, architecture, and Git |
347
358
  | `wip config` | Print the effective configuration (secrets masked) |
data/lib/wip/cli.rb CHANGED
@@ -42,11 +42,13 @@ module Wip
42
42
 
43
43
  desc 'init', 'Create a starter wip.yml (detects an existing compose.yml/docker-compose.yml)'
44
44
  option :force, type: :boolean, default: false, desc: 'Overwrite an existing wip.yml'
45
+ option :template, type: :string,
46
+ desc: "sync.exclude preset: #{Initializer::TEMPLATE_LABELS.keys.join(', ')} (default: none)"
45
47
  def init
46
48
  path = Pathname(options[:config] || ConfigLoader::FILENAME).expand_path
47
49
  raise Error, "#{path} already exists (use --force to overwrite)" if path.file? && !options[:force]
48
50
 
49
- initializer = Initializer.new(dir: path.dirname)
51
+ initializer = Initializer.new(dir: path.dirname, template: options[:template])
50
52
  path.write(initializer.call)
51
53
  warn "wip: wrote #{path} (mode: #{initializer.compose? ? 'compose-native' : 'container'})"
52
54
  end
@@ -8,72 +8,54 @@ module Wip
8
8
  # mode: compose-native and mode: container, since that's the one decision
9
9
  # `wip init` can't leave to a placeholder.
10
10
  class Initializer
11
- # Appended to sync: in both templates. Every key here is either a plain constant
12
- # default (safe to state literally) or, where commented, a value SyncSettings
13
- # derives from another key (target from workdir, volume from the container/service
14
- # name) — those stay unset so they keep tracking that key instead of going stale.
15
- SYNC_EXTRAS = <<~YAML.chomp.gsub(/^/, ' ')
16
- source: . # optional; host path to mirror (default: wip.yml directory)
17
- # target: /app # optional; in-container mount point for the mirror (default: the container's workdir, else /app)
18
- mount: /host-src # optional; read-only host mount inside the container
19
- # volume: app-src # optional; named volume holding the mirrored tree (default: "<container>-src")
20
- delete: true # optional; rsync --delete so removals on the host are mirrored too
21
- exclude: [] # optional; rsync --exclude patterns, e.g. ["node_modules", "*.log"]
22
- command: rsync # optional; mirror binary to shell out to
23
- options: [] # optional; extra flags appended to the mirror command
24
- interval: 2 # optional; seconds between mirrors
25
- mode: exec # optional; exec (default, mirrors into the running container) | run (always a fresh container)
26
- # image: your/image:tag # only needed if sync.mode: run (or under mode: compose); image the mirror container runs
27
- # build: # alternative to image — let wip build a small dedicated mirror image itself
28
- # dockerfile: |
29
- # FROM alpine:latest
30
- # RUN apk add --no-cache rsync
31
- # tag: wip-sync-app:latest # optional (default: wip-sync-<container>:latest)
32
- YAML
11
+ # --template values wip init accepts, and the label used in the exclude: comment.
12
+ TEMPLATE_LABELS = {
13
+ 'rails' => 'Rails',
14
+ 'node' => 'Node.js',
15
+ 'rust' => 'Rust',
16
+ 'csharp' => 'C#'
17
+ }.freeze
18
+
19
+ # sync.exclude patterns written live for each --template. They mirror that
20
+ # stack's own github/gitignore template directories that are either
21
+ # regenerated inside the container or too large/irrelevant to mirror over rsync.
22
+ TEMPLATE_EXCLUDES = {
23
+ 'rails' => %w[.git log/ tmp/ storage/ public/assets/ public/packs/ .bundle/ vendor/bundle/
24
+ coverage/ node_modules/],
25
+ 'node' => %w[.git node_modules/ dist/ build/ .next/ .cache/ coverage/],
26
+ 'rust' => %w[.git target/],
27
+ 'csharp' => %w[.git bin/ obj/ .vs/ packages/]
28
+ }.freeze
29
+
30
+ # Used when --template is omitted — the same starting point the README's own
31
+ # example uses.
32
+ FALLBACK_EXCLUDES = %w[.git tmp/ node_modules/].freeze
33
33
 
34
34
  # Appended to both templates after dependencies/compose. commands: itself is left
35
35
  # commented since an empty commands: {} is indistinguishable from omitting the key.
36
36
  COMMANDS_EXAMPLE = <<~YAML.chomp
37
- # commands: # optional; custom subcommands, e.g. `wip test` — see README
37
+ # optional; custom subcommands, e.g. `wip test` — see README
38
+ # commands:
38
39
  # test:
39
- # type: exec # optional; exec (default, runs in the running container) | run (fresh container) | build
40
- # command: bundle exec rspec # TODO
41
- YAML
42
-
43
- CONTAINER_TEMPLATE = <<~YAML.freeze
44
- version: 1
45
- mode: container # container | compose | compose-native (see README)
46
- container: app # TODO: rename freely, as long as it matches a key under dependencies: below
47
-
48
- wslc:
49
- command: auto # optional; wslc binary/path wip shells out to ("auto" resolves it for you)
40
+ # optional; exec (default, runs in the running container) | run (fresh container) | build
41
+ # type: exec
50
42
 
51
- # network: my-network # optional; container network name (mode: container only)
52
-
53
- dependencies:
54
- app: # this is the container wip creates, execs into, and runs commands in
55
- image: your/image:tag # TODO: image to run
56
- workdir: /app # TODO: adjust to match your image, or delete this line
57
- interactive: false # optional; keep stdin open / allocate a tty
58
- remove: true # optional; remove the container after each run
59
- env: {} # optional; environment variables passed to the container, e.g. {FOO: bar}
60
- ports: [] # optional; published ports, e.g. ["3000:3000"]
61
- volumes: [] # optional; extra -v specs beyond the sync mounts below
62
-
63
- #{COMMANDS_EXAMPLE}
64
-
65
- sync: # optional; mirrors the source into a named volume instead of bind-mounting it live
66
- #{SYNC_EXTRAS}
43
+ # TODO
44
+ # command: bundle exec rspec
67
45
  YAML
68
46
 
69
- def initialize(dir: Dir.pwd)
47
+ def initialize(dir: Dir.pwd, template: nil)
48
+ raise Error, "unknown --template #{template.inspect} (valid: #{TEMPLATE_LABELS.keys.join(', ')})" \
49
+ if template && !TEMPLATE_LABELS.key?(template)
50
+
70
51
  @dir = dir
52
+ @template = template
71
53
  end
72
54
 
73
55
  def compose? = !!compose_file
74
56
 
75
57
  def call
76
- compose? ? compose_template : CONTAINER_TEMPLATE
58
+ compose? ? compose_template : container_template
77
59
  end
78
60
 
79
61
  private
@@ -87,29 +69,156 @@ module Wip
87
69
  # without duplicating it as a live value that would go stale if the directory moves.
88
70
  def compose_project_default = Pathname(@dir).basename.to_s
89
71
 
72
+ def exclude_comment
73
+ if @template
74
+ "# optional; rsync --exclude patterns picked for --template #{@template} (#{TEMPLATE_LABELS[@template]})"
75
+ else
76
+ '# optional; rsync --exclude patterns, e.g. ["node_modules", "*.log"]'
77
+ end
78
+ end
79
+
80
+ def exclude_list
81
+ patterns = @template ? TEMPLATE_EXCLUDES.fetch(@template) : FALLBACK_EXCLUDES
82
+ patterns.map { |pattern| " - #{pattern}" }.join("\n")
83
+ end
84
+
85
+ # Appended to sync: in both templates. Every key here is either a plain constant
86
+ # default (safe to state literally) or, where commented, a value SyncSettings
87
+ # derives from another key (target from workdir, volume from the container/service
88
+ # name) — those stay unset so they keep tracking that key instead of going stale.
89
+ # A blank line separates every key from its neighbor; the gsub only indents
90
+ # non-blank lines so those separators stay actual blank lines, not trailing
91
+ # whitespace.
92
+ def sync_extras
93
+ <<~YAML.chomp.gsub(/^(?=.)/, ' ')
94
+ # optional; host path to mirror (default: wip.yml directory)
95
+ source: .
96
+
97
+ # optional; in-container mount point for the mirror (default: the container's workdir, else /app)
98
+ # target: /app
99
+
100
+ # optional; read-only host mount inside the container
101
+ mount: /host-src
102
+
103
+ # optional; named volume holding the mirrored tree (default: "<container>-src")
104
+ # volume: app-src
105
+
106
+ # optional; rsync --delete so removals on the host are mirrored too
107
+ delete: true
108
+
109
+ #{exclude_comment}
110
+ exclude:
111
+ #{exclude_list}
112
+
113
+ # optional; mirror binary to shell out to
114
+ command: rsync
115
+
116
+ # optional; extra flags appended to the mirror command
117
+ options: []
118
+
119
+ # optional; seconds between mirrors
120
+ interval: 2
121
+
122
+ # optional; exec (default, mirrors into the running container) | run (always a fresh container)
123
+ mode: exec
124
+
125
+ # only needed if sync.mode: run (or under mode: compose); image the mirror container runs
126
+ # image: your/image:tag
127
+
128
+ # alternative to image — let wip build a small dedicated mirror image itself
129
+ # build:
130
+ # dockerfile: |
131
+ # FROM alpine:latest
132
+ # RUN apk add --no-cache rsync
133
+
134
+ # optional (default: wip-sync-<container>:latest)
135
+ # tag: wip-sync-app:latest
136
+ YAML
137
+ end
138
+
139
+ def container_template
140
+ <<~YAML
141
+ version: 1
142
+
143
+ # container | compose | compose-native (see README)
144
+ mode: container
145
+
146
+ # TODO: rename freely, as long as it matches a key under dependencies: below
147
+ container: app
148
+
149
+ wslc:
150
+ # optional; wslc binary/path wip shells out to ("auto" resolves it for you)
151
+ command: auto
152
+
153
+ # optional; container network name (mode: container only)
154
+ # network: my-network
155
+
156
+ dependencies:
157
+ # this is the container wip creates, execs into, and runs commands in
158
+ app:
159
+ # TODO: image to run
160
+ image: your/image:tag
161
+
162
+ # TODO: adjust to match your image, or delete this line
163
+ workdir: /app
164
+
165
+ # optional; keep stdin open / allocate a tty
166
+ interactive: false
167
+
168
+ # optional; remove the container after each run
169
+ remove: true
170
+
171
+ # optional; environment variables passed to the container, e.g. {FOO: bar}
172
+ env: {}
173
+
174
+ # optional; published ports, e.g. ["3000:3000"]
175
+ ports: []
176
+
177
+ # optional; extra -v specs beyond the sync mounts below
178
+ volumes: []
179
+
180
+ #{COMMANDS_EXAMPLE}
181
+
182
+ # optional; mirrors the source into a named volume instead of bind-mounting it live
183
+ sync:
184
+ #{sync_extras}
185
+ YAML
186
+ end
187
+
90
188
  def compose_template
91
189
  <<~YAML
92
190
  version: 1
93
- mode: compose-native # wip parses #{compose_file} itself and drives wslc directly — no external
94
- # compose-for-wslc binary needed. Prefer a real compose tool instead? Use
95
- # mode: compose (see README "Compose mode") and set compose.command.
191
+
192
+ # wip parses #{compose_file} itself and drives wslc directly no external
193
+ # compose-for-wslc binary needed. Prefer a real compose tool instead? Use
194
+ # mode: compose (see README "Compose mode") and set compose.command.
195
+ mode: compose-native
96
196
 
97
197
  wslc:
98
- command: auto # optional; wslc binary/path wip shells out to ("auto" resolves it for you)
198
+ # optional; wslc binary/path wip shells out to ("auto" resolves it for you)
199
+ command: auto
99
200
 
100
201
  compose:
101
- service: app # TODO: which service in #{compose_file} wip run/exec/NAME target
102
- # file: #{compose_file} # optional; override which compose file wip parses (default: auto-detected)
103
- # project: #{compose_project_default} # optional; project/network name (default: this directory's name)
104
- # command: # only used under mode: compose (external compose-for-wslc binary); unused here under compose-native
202
+ # TODO: which service in #{compose_file} wip run/exec/NAME target
203
+ service: app
204
+
205
+ # optional; override which compose file wip parses (default: auto-detected)
206
+ # file: #{compose_file}
207
+
208
+ # optional; project/network name (default: this directory's name)
209
+ # project: #{compose_project_default}
210
+
211
+ # only used under mode: compose (external compose-for-wslc binary); unused here under compose-native
212
+ # command:
105
213
 
106
214
  # network: is derived from compose.project above (or this directory's name) — setting it
107
215
  # directly conflicts with compose: (ConfigError), so it's intentionally left out here.
108
216
 
109
217
  #{COMMANDS_EXAMPLE}
110
218
 
111
- sync: # optional; mirrors the source into a named volume instead of bind-mounting it live
112
- #{SYNC_EXTRAS}
219
+ # optional; mirrors the source into a named volume instead of bind-mounting it live
220
+ sync:
221
+ #{sync_extras}
113
222
  YAML
114
223
  end
115
224
  end
data/lib/wip/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Wip
4
- VERSION = '0.14.2'
4
+ VERSION = '0.15.0'
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: 0.14.2
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wip contributors