Class: Wip::CommandBuilder

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

Overview

Builds the argument arrays for wslc build/exec/run/custom invocations.

Instance Method Summary collapse

Constructor Details

#initialize(wslc:, config:, environment: Environment.new, dotenv: {}) ⇒ CommandBuilder

Returns a new instance of CommandBuilder.



8
9
10
11
12
13
# File 'lib/wip/command_builder.rb', line 8

def initialize(wslc:, config:, environment: Environment.new, dotenv: {})
  @wslc = wslc
  @config = config
  @environment = environment
  @dotenv = dotenv
end

Instance Method Details

#build(settings:, extra: []) ⇒ Object

Raises:



129
130
131
132
133
134
135
136
# File 'lib/wip/command_builder.rb', line 129

def build(settings:, extra: [])
  values = primary_values.merge(settings)
  context = values['context'] || '.'
  tag = values['tag'] || values['image']
  raise ConfigError, 'Build image/tag must not be empty' if tag.to_s.empty?

  [@wslc, 'build', '-t', tag, *extra, context]
end

#custom(name, arguments) ⇒ Object



138
139
140
141
142
143
144
145
# File 'lib/wip/command_builder.rb', line 138

def custom(name, arguments)
  values = @config.command(name) || raise(ConfigError, "Unknown command: #{name}")
  type = values['type'] || (name.to_s == 'build' ? 'build' : 'exec')
  base = Shellwords.split(values['command'].to_s)
  return build(settings: values, extra: arguments) if type == 'build'

  public_send(type, base + arguments, settings: values, interactive: values.fetch('interactive', false))
end

#dependency_down(name) ⇒ Object



121
122
123
# File 'lib/wip/command_builder.rb', line 121

def dependency_down(name)
  [@wslc, 'stop', name.to_s]
end

#dependency_find(name) ⇒ Object



117
118
119
# File 'lib/wip/command_builder.rb', line 117

def dependency_find(name)
  [@wslc, 'list', '--all', '--filter', "name=#{name}", '--format', 'json']
end

#dependency_remove(name) ⇒ Object



125
126
127
# File 'lib/wip/command_builder.rb', line 125

def dependency_remove(name)
  [@wslc, 'remove', '-f', name.to_s]
end

#dependency_start(name) ⇒ Object



113
114
115
# File 'lib/wip/command_builder.rb', line 113

def dependency_start(name)
  [@wslc, 'start', name.to_s]
end

#dependency_up(name, detach: true) ⇒ Object



103
104
105
106
107
108
109
110
111
# File 'lib/wip/command_builder.rb', line 103

def dependency_up(name, detach: true)
  values = dependency_values(name)
  command = [@wslc, 'run', '--name', name.to_s]
  command.push('--network', @config.network) if @config.network
  command << '-d' if detach
  command.concat(options(values, sync: false)).push(required(values, 'image'))
  command.concat(Shellwords.split(values['command'].to_s)) unless values['command'].to_s.empty?
  command
end

#downObject



87
88
89
# File 'lib/wip/command_builder.rb', line 87

def down
  [@wslc, 'stop', required_container]
end

#exec(arguments, settings: {}, interactive: true) ⇒ Object



15
16
17
18
19
20
21
22
23
# File 'lib/wip/command_builder.rb', line 15

def exec(arguments, settings: {}, interactive: true)
  # dependencies: entries don't carry their own name (it's the hash key), so the
  # exec target defaults to @config.container; a commands: entry can still
  # redirect it by setting its own `container:`.
  values = primary_values.merge('container' => required_container).merge(settings)
  command = [@wslc, 'exec']
  command << '-it' if tty?(interactive)
  command.concat(options(values, include_container: true, include_publish: false)).concat(arguments)
end

#findObject



50
51
52
# File 'lib/wip/command_builder.rb', line 50

def find
  [@wslc, 'list', '--all', '--filter', "name=#{required_container}", '--format', 'json']
end

#network_createObject



95
96
97
# File 'lib/wip/command_builder.rb', line 95

def network_create
  [@wslc, 'network', 'create', required_network]
end

#network_listObject



99
100
101
# File 'lib/wip/command_builder.rb', line 99

def network_list
  [@wslc, 'network', 'list', '--format', 'json']
end

#removeObject



91
92
93
# File 'lib/wip/command_builder.rb', line 91

def remove
  [@wslc, 'remove', '-f', required_container]
end

#run(arguments, settings: {}, interactive: true) ⇒ Object



25
26
27
28
29
30
31
# File 'lib/wip/command_builder.rb', line 25

def run(arguments, settings: {}, interactive: true)
  values = primary_values.merge(settings)
  command = [@wslc, 'run']
  command << '--rm' if values['remove']
  command << '-it' if tty?(interactive)
  command.concat(options(values)).push(required(values, 'image')).concat(arguments)
end

#start(detach: false) ⇒ Object



44
45
46
47
48
# File 'lib/wip/command_builder.rb', line 44

def start(detach: false)
  command = [@wslc, 'start', required_container]
  command.push('-a', '-i') unless detach
  command
end

#sync_build(context) ⇒ Object

Builds sync.build's image from a Dockerfile staged in context (a caller- managed directory, since the build only reads it once wslc build runs). Doesn't touch dependencies: at all, so it works the same under compose mode as it does under container mode.

Raises:



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

def sync_build(context)
  sync = required_sync
  raise ConfigError, 'No sync.build configured in wip.yml' unless sync.build

  [@wslc, 'build', '-t', sync.build['tag'], context]
end

#sync_execObject

Mirrors from inside the already-running container. Only valid for sync.mode: exec (mode: container's default), since only a container wip itself booted is guaranteed to have both the read-only source mount and the volume attached.



83
84
85
# File 'lib/wip/command_builder.rb', line 83

def sync_exec
  [@wslc, 'exec', required_container, *required_sync.mirror_command]
end

#sync_runObject

Mirrors into the volume from a throwaway container. Used for sync.mode: run (compose's default, and mode: container's fallback for when the app container isn't running yet — e.g. just before up boots it). The image comes from sync.build's tag (once built via sync_build), else sync.image, else the primary dependencies: entry; compose mode requires one of the first two, since it has no dependencies: entry to fall back to.



60
61
62
63
64
65
66
# File 'lib/wip/command_builder.rb', line 60

def sync_run
  sync = required_sync
  command = [@wslc, 'run', '--rm']
  sync.volume_specs.each { |spec| command.push('-v', spec) }
  image = sync.build&.fetch('tag') || sync.image || required(primary_values, 'image')
  command.push(image).concat(sync.mirror_command)
end

#tty?(requested) ⇒ Boolean

Returns:

  • (Boolean)


147
# File 'lib/wip/command_builder.rb', line 147

def tty?(requested) = requested && @environment.interactive?

#up(detach: false) ⇒ Object



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

def up(detach: false)
  values = primary_values
  command = [@wslc, 'run', '--name', required_container]
  command.push('--network', @config.network) if @config.network
  command << '-d' if detach
  command << '-it' if !detach && tty?(true)
  command.concat(options(values)).push(required(values, 'image'))
  command.concat(Shellwords.split(values['command'].to_s)) unless values['command'].to_s.empty?
  command
end