Class: Wip::Config

Inherits:
Object
  • Object
show all
Defined in:
lib/wip/config.rb

Overview

Validated, defaulted access to a parsed wip.yml document.

Constant Summary collapse

DEPENDENCY_DEFAULTS =

Applied to every dependencies: entry, primary container included — there is no separate, differently-shaped bucket for "the one you exec into."

{ 'workdir' => nil, 'user' => nil, 'interactive' => false, 'remove' => true,
'env' => {}, 'ports' => [], 'volumes' => [] }.freeze
SECRET_PATTERN =
/token|password|secret|credential|auth/i
MODES =

Which orchestration path up/down/sync/etc. take. Explicit rather than inferred from a compose: block's presence, so a config reader doesn't have to know that rule to predict which mode wip runs in. compose bridges to an external compose-for-wslc binary (ComposeBridge); compose-native parses compose.yml itself and drives wslc directly (ComposeFile) — a stopgap for as long as those external tools stay incomplete (missing run, etc.).

%w[container compose compose-native].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(raw, path = nil) ⇒ Config

Returns a new instance of Config.



22
23
24
25
26
# File 'lib/wip/config.rb', line 22

def initialize(raw, path = nil)
  @raw = stringify(raw)
  @path = path
  validate!
end

Instance Attribute Details

#pathObject (readonly)

Returns the value of attribute path.



20
21
22
# File 'lib/wip/config.rb', line 20

def path
  @path
end

Instance Method Details

#command(name) ⇒ Object



72
73
74
75
76
77
# File 'lib/wip/config.rb', line 72

def command(name)
  entry = commands[name.to_s]
  return unless entry

  (primary || {}).merge('type' => 'exec').merge(entry)
end

#commandsObject



29
30
31
32
# File 'lib/wip/config.rb', line 29

def commands = @raw['commands'] || {}
# Raw dependencies: block as written in wip.yml. Under compose-native mode this stays
# empty by construction (validate_compose! forbids combining the two) — #dependencies
# below is what callers actually want, since it's synthesized from compose.yml there.

#composeObject



49
# File 'lib/wip/config.rb', line 49

def compose = @raw['compose']

#compose?Boolean

Returns:

  • (Boolean)


50
# File 'lib/wip/config.rb', line 50

def compose? = mode == 'compose'

#compose_build_specsObject

name => dockerfile:, tag: for compose-native services with a build: instead of an image: — empty otherwise. Consumed by wip up to build each one before starting it (see CommandBuilder#build).



60
# File 'lib/wip/config.rb', line 60

def compose_build_specs = compose_native? ? parsed_compose_file.build_specs : {}

#compose_commandObject



56
57
58
59
# File 'lib/wip/config.rb', line 56

def compose_command = compose && compose['command']
# name => {context:, dockerfile:, tag:} for compose-native services with a build:
# instead of an image: — empty otherwise. Consumed by `wip up` to build each one
# before starting it (see CommandBuilder#build).

#compose_fileObject



54
# File 'lib/wip/config.rb', line 54

def compose_file = compose && compose['file']

#compose_mode?Boolean

Returns:

  • (Boolean)


52
# File 'lib/wip/config.rb', line 52

def compose_mode? = compose? || compose_native?

#compose_native?Boolean

Returns:

  • (Boolean)


51
# File 'lib/wip/config.rb', line 51

def compose_native? = mode == 'compose-native'

#compose_projectObject



55
# File 'lib/wip/config.rb', line 55

def compose_project = compose && compose['project']

#compose_serviceObject



53
# File 'lib/wip/config.rb', line 53

def compose_service = compose && compose['service']

#containerObject

Which dependencies: entry up/down/exec/run/build/commands: target by default — the one container wip itself considers "the app." Everything else in dependencies: is a sidecar wip only starts and stops. No default: guessing a name here (the old default was "app") either matches by luck or fails in a way that doesn't point at the real problem (a differently-named entry), so a project with any dependencies: must say which one explicitly. Under compose-native mode, container: is compose.service — compose.yml already names the service, so there's no separate container: key to set in wip.yml.



43
44
45
46
# File 'lib/wip/config.rb', line 43

def container = compose_native? ? compose_service : presence(@raw['container'])
# Under compose-native mode, wip creates its own project network (compose.project,
# or the wip.yml directory's name) so services can reach each other by name — the
# same guarantee real Compose's per-project network gives.

#dependenciesObject



34
35
36
37
38
39
40
41
42
# File 'lib/wip/config.rb', line 34

def dependencies = compose_native? ? parsed_compose_file.to_dependencies_hash : raw_dependencies
# Which dependencies: entry `up`/`down`/`exec`/`run`/`build`/`commands:` target
# by default — the one container wip itself considers "the app." Everything
# else in dependencies: is a sidecar wip only starts and stops. No default:
# guessing a name here (the old default was "app") either matches by luck or
# fails in a way that doesn't point at the real problem (a differently-named
# entry), so a project with any dependencies: must say which one explicitly.
# Under compose-native mode, container: is compose.service — compose.yml already
# names the service, so there's no separate container: key to set in wip.yml.

#dependency(name) ⇒ Object



79
80
81
82
83
84
# File 'lib/wip/config.rb', line 79

def dependency(name)
  entry = dependencies[name.to_s]
  return unless entry

  DEPENDENCY_DEFAULTS.merge(entry)
end

#modeObject



48
# File 'lib/wip/config.rb', line 48

def mode = @raw['mode'] || 'container'

#networkObject

Under compose-native mode, wip creates its own project network (compose.project, or the wip.yml directory's name) so services can reach each other by name — the same guarantee real Compose's per-project network gives.



47
# File 'lib/wip/config.rb', line 47

def network = compose_native? ? (compose_project || default_compose_network) : @raw['network']

#primaryObject

The dependencies: entry container points at, or nil if it isn't defined.



70
# File 'lib/wip/config.rb', line 70

def primary = dependency(container)

#raw_dependenciesObject

Raw dependencies: block as written in wip.yml. Under compose-native mode this stays empty by construction (validate_compose! forbids combining the two) — #dependencies below is what callers actually want, since it's synthesized from compose.yml there.



33
# File 'lib/wip/config.rb', line 33

def raw_dependencies = @raw['dependencies'] || {}

#syncObject



63
64
65
66
67
# File 'lib/wip/config.rb', line 63

def sync
  return @sync if defined?(@sync)

  @sync = @raw.key?('sync') ? build_sync : nil
end

#sync?Boolean

Returns:

  • (Boolean)


61
# File 'lib/wip/config.rb', line 61

def sync? = !!sync

#to_h(redact: true) ⇒ Object



86
87
88
89
90
91
92
93
# File 'lib/wip/config.rb', line 86

def to_h(redact: true)
  value = { 'version' => 1, 'wslc' => { 'command' => wslc_command }, 'mode' => mode, 'container' => container,
            'network' => network, 'dependencies' => dependencies, 'compose' => compose, 'sync' => sync&.to_h,
            'commands' => commands.transform_values do |entry|
              (primary || {}).merge('type' => 'exec').merge(entry)
            end }
  redact ? redact_secrets(value) : value
end

#wslc_commandObject



28
# File 'lib/wip/config.rb', line 28

def wslc_command = @raw.dig('wslc', 'command') || 'auto'