wslc-wip 0.17.4 → 0.17.6
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 +2 -2
- data/lib/wip/build_context.rb +23 -4
- data/lib/wip/cli.rb +38 -7
- data/lib/wip/command_builder.rb +2 -1
- data/lib/wip/command_runner.rb +9 -2
- data/lib/wip/docker_ignore.rb +18 -0
- data/lib/wip/doctor.rb +3 -1
- data/lib/wip/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: adf27a8bafbb2482bfe25b393e3623a39fd0c8d77f92a7c6e6e60286506c8f17
|
|
4
|
+
data.tar.gz: 77d180849706ea0915e82c03a7bfcae6d5ee0c581a87db808e3eceacdb0b8210
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f894b61d72a792604221a0bc41c5bef018cb2257ee7469d958f17f96fd5de57e52f2a1665b74e51bfbbd3e6cea6ba9f684f42a4ab64747462098c4742b7cd350
|
|
7
|
+
data.tar.gz: 68201cce4009583ffee442f06858d930a9d618a399553fbf04523281c8012630e0c8bedc1517012b5f9afca9896612d42829206303943b5548118d0a2d960d17
|
data/README.md
CHANGED
|
@@ -370,8 +370,8 @@ valid compose.yml over sections it doesn't need to look at:
|
|
|
370
370
|
| `wip version` | wip's version, plus WSLC's if it can be detected |
|
|
371
371
|
| `wip doctor` | Diagnose WSL2, interop, WSLC, config, architecture, and Git |
|
|
372
372
|
| `wip config` | Print the effective configuration (secrets masked) |
|
|
373
|
-
| `wip build --
|
|
374
|
-
| `wip up [-d] [--no-sync]` | 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` |
|
|
373
|
+
| `wip build [--no-cache] [-- OPTIONS]` | Build the image from the `build` definition. By default, wip passes the target tag as `--cache-from` so previous layers can be reused; `--no-cache` disables that cache path. |
|
|
374
|
+
| `wip up [-d] [--no-sync] [--no-cache]` | 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` |
|
|
375
375
|
| `wip down` | Stop and remove the primary container and its sidecar `dependencies:` |
|
|
376
376
|
| `wip exec [--no-interactive] COMMAND...` | Run a command in the existing container |
|
|
377
377
|
| `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) |
|
data/lib/wip/build_context.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'find'
|
|
3
4
|
require 'fileutils'
|
|
4
5
|
require 'pathname'
|
|
5
6
|
require 'tmpdir'
|
|
@@ -41,13 +42,31 @@ module Wip
|
|
|
41
42
|
end
|
|
42
43
|
end
|
|
43
44
|
|
|
45
|
+
# Walks the tree by hand (rather than Dir.glob-ing it all up front) so an
|
|
46
|
+
# ignored directory — node_modules, vendor/bundle, a multi-gigabyte
|
|
47
|
+
# storage/ — is never descended into just to be thrown away afterward.
|
|
44
48
|
def included_files
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
result = []
|
|
50
|
+
Find.find(@root.to_s) do |path|
|
|
51
|
+
next if path == @root.to_s
|
|
47
52
|
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
entry = Pathname(path).relative_path_from(@root).to_s
|
|
54
|
+
result << entry if visit?(path, entry)
|
|
50
55
|
end
|
|
56
|
+
result
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Returns whether `path` belongs in the staged context, pruning the walk
|
|
60
|
+
# when it's an ignored directory so nothing under it is even visited —
|
|
61
|
+
# unless a later negated rule could still re-include something beneath it.
|
|
62
|
+
def visit?(path, entry)
|
|
63
|
+
ignored = @ignore.ignored?(entry)
|
|
64
|
+
if !File.symlink?(path) && File.directory?(path)
|
|
65
|
+
Find.prune if ignored && @ignore.prunable?(entry)
|
|
66
|
+
return false
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
!ignored && (File.file?(path) || File.symlink?(path))
|
|
51
70
|
end
|
|
52
71
|
end
|
|
53
72
|
end
|
data/lib/wip/cli.rb
CHANGED
|
@@ -66,15 +66,17 @@ module Wip
|
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
desc 'build [OPTIONS]', 'Build the configured image'
|
|
69
|
+
option :no_cache, type: :boolean, default: false, desc: 'Build without using cached layers'
|
|
69
70
|
def build(*extra)
|
|
70
|
-
extra
|
|
71
|
+
extra = build_extra_options(extra)
|
|
71
72
|
settings = load_config.command('build') || {}
|
|
72
|
-
context = settings['context'] || '.'
|
|
73
|
+
context = Pathname(load_config.path).dirname.join(settings['context'] || '.').to_s
|
|
73
74
|
warn "wip: staging build context (#{context})"
|
|
74
75
|
progress = StagingProgress.new
|
|
75
76
|
BuildContext.new(context).stage(on_progress: progress.method(:tick)) do |staged_context|
|
|
76
77
|
progress.finish
|
|
77
|
-
|
|
78
|
+
built = builder.build(settings: settings.merge('context' => staged_context), extra: extra)
|
|
79
|
+
execute(built, interactive: tty?(true))
|
|
78
80
|
end
|
|
79
81
|
ensure
|
|
80
82
|
progress&.finish
|
|
@@ -83,6 +85,7 @@ module Wip
|
|
|
83
85
|
desc 'up', 'Start the configured container and its dependencies, creating them if necessary'
|
|
84
86
|
option :detach, type: :boolean, default: false, aliases: '-d'
|
|
85
87
|
option :sync, type: :boolean, default: true, desc: 'Mirror the source into the sync volume first (--no-sync skips)'
|
|
88
|
+
option :no_cache, type: :boolean, default: false, desc: 'Build compose-native images without cached layers'
|
|
86
89
|
def up
|
|
87
90
|
if load_config.compose?
|
|
88
91
|
sync_before_boot if options[:sync]
|
|
@@ -301,11 +304,39 @@ module Wip
|
|
|
301
304
|
# `wip up` invocation, mirroring ensure_sync_image's "build once, not every tick"
|
|
302
305
|
# approach. A no-op for mode: container/compose and for build:-less services.
|
|
303
306
|
def ensure_compose_images
|
|
304
|
-
load_config.compose_build_specs.each_value
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
307
|
+
load_config.compose_build_specs.each_value { |spec| build_compose_image(spec) }
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# Stages spec['context'] the same way `wip build` does, so a .dockerignore next to
|
|
311
|
+
# a compose-native service's build: is honored and progress is reported here too.
|
|
312
|
+
def build_compose_image(spec)
|
|
313
|
+
extra = compose_build_extra(spec)
|
|
314
|
+
warn "wip: staging build context (#{spec['context']})"
|
|
315
|
+
progress = StagingProgress.new
|
|
316
|
+
BuildContext.new(spec['context']).stage(on_progress: progress.method(:tick)) do |staged_context|
|
|
317
|
+
progress.finish
|
|
318
|
+
settings = { 'context' => staged_context, 'tag' => spec['tag'] }
|
|
319
|
+
execute(builder.build(settings: settings, extra: extra), interactive: tty?(true))
|
|
308
320
|
end
|
|
321
|
+
ensure
|
|
322
|
+
progress&.finish
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def build_extra_options(extra)
|
|
326
|
+
extra = extra.dup
|
|
327
|
+
extra.shift if extra.first == '--'
|
|
328
|
+
with_no_cache_option(extra)
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def compose_build_extra(spec)
|
|
332
|
+
extra = spec['dockerfile'] ? ['-f', spec['dockerfile']] : []
|
|
333
|
+
spec['args']&.each { |key, value| extra.push('--build-arg', "#{key}=#{value}") }
|
|
334
|
+
with_no_cache_option(extra)
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def with_no_cache_option(extra)
|
|
338
|
+
extra.unshift('--no-cache') if options[:no_cache] && !extra.include?('--no-cache')
|
|
339
|
+
extra
|
|
309
340
|
end
|
|
310
341
|
|
|
311
342
|
# Builds sync.build's image once per invocation (not per --watch tick, which
|
data/lib/wip/command_builder.rb
CHANGED
|
@@ -142,7 +142,8 @@ module Wip
|
|
|
142
142
|
tag = values['tag'] || values['image']
|
|
143
143
|
raise ConfigError, 'Build image/tag must not be empty' if tag.to_s.empty?
|
|
144
144
|
|
|
145
|
-
|
|
145
|
+
cache_options = extra.include?('--no-cache') ? [] : ['--cache-from', tag]
|
|
146
|
+
[@wslc, 'build', '-t', tag, *cache_options, *extra, context]
|
|
146
147
|
end
|
|
147
148
|
|
|
148
149
|
def custom(name, arguments)
|
data/lib/wip/command_runner.rb
CHANGED
|
@@ -27,7 +27,7 @@ module Wip
|
|
|
27
27
|
status = wait.value
|
|
28
28
|
end
|
|
29
29
|
report_hint(captured) unless status.success?
|
|
30
|
-
status
|
|
30
|
+
exitstatus(status)
|
|
31
31
|
rescue Errno::ENOENT => e
|
|
32
32
|
@stderr.puts e.message
|
|
33
33
|
127
|
|
@@ -38,6 +38,13 @@ module Wip
|
|
|
38
38
|
|
|
39
39
|
private
|
|
40
40
|
|
|
41
|
+
# exitstatus is nil when the process was killed by a signal instead of
|
|
42
|
+
# exiting normally; fall back to the conventional 128+signal shell code
|
|
43
|
+
# so callers always get a comparable integer.
|
|
44
|
+
def exitstatus(status)
|
|
45
|
+
status.exitstatus || (128 + status.termsig)
|
|
46
|
+
end
|
|
47
|
+
|
|
41
48
|
def report_hint(captured)
|
|
42
49
|
hint = @interpreter.interpret(captured.force_encoding(Encoding::UTF_8).scrub)
|
|
43
50
|
@stderr.puts("\n#{hint}") if hint
|
|
@@ -50,7 +57,7 @@ module Wip
|
|
|
50
57
|
def run_attached(command, env)
|
|
51
58
|
pid = Process.spawn(env, *command)
|
|
52
59
|
_, status = Process.wait2(pid)
|
|
53
|
-
status
|
|
60
|
+
exitstatus(status)
|
|
54
61
|
rescue Errno::ENOENT => e
|
|
55
62
|
@stderr.puts e.message
|
|
56
63
|
127
|
data/lib/wip/docker_ignore.rb
CHANGED
|
@@ -30,8 +30,26 @@ module Wip
|
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
# Whether a walker can stop descending into an ignored directory without
|
|
34
|
+
# risking a miss: false if some later negated rule (e.g. `!node_modules/pkg`
|
|
35
|
+
# after `node_modules`) could still match something beneath it.
|
|
36
|
+
def prunable?(relative_path)
|
|
37
|
+
dir_components = relative_path.split('/')
|
|
38
|
+
@rules.none? { |rule| rule.negate && targets_descendant?(rule.pattern, dir_components) }
|
|
39
|
+
end
|
|
40
|
+
|
|
33
41
|
private
|
|
34
42
|
|
|
43
|
+
def targets_descendant?(pattern, dir_components)
|
|
44
|
+
pattern_components = pattern.split('/')
|
|
45
|
+
return true if pattern_components.first == '**'
|
|
46
|
+
return false if pattern_components.size <= dir_components.size
|
|
47
|
+
|
|
48
|
+
pattern_components.first(dir_components.size).each_with_index.all? do |component, i|
|
|
49
|
+
File.fnmatch(component, dir_components[i], FNMATCH_FLAGS)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
35
53
|
def parse(line)
|
|
36
54
|
line = line.strip
|
|
37
55
|
return nil if line.empty? || line.start_with?('#')
|
data/lib/wip/doctor.rb
CHANGED
|
@@ -151,6 +151,8 @@ module Wip
|
|
|
151
151
|
condition == :ok ? ok_message : fail_message)
|
|
152
152
|
end
|
|
153
153
|
|
|
154
|
-
def command_available?(name)
|
|
154
|
+
def command_available?(name)
|
|
155
|
+
ENV.fetch('PATH', '').split(File::PATH_SEPARATOR).any? { |dir| File.executable?(File.join(dir, name)) }
|
|
156
|
+
end
|
|
155
157
|
end
|
|
156
158
|
end
|
data/lib/wip/version.rb
CHANGED