Class: Wip::SyncSettings

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

Overview

Validated access to the sync: block, which mirrors the host source tree into a named volume instead of bind-mounting it live.

A bind-mounted app directory is shared into the container's VM over virtiofs, so every stat/open a boot-time directory scan makes is a round trip. Mirroring the tree into a named volume (native storage inside the VM) and re-running the mirror on demand keeps the edit-on-the-host workflow while leaving the running app on fast disk.

Constant Summary collapse

DEFAULT_MOUNT =
'/host-src'
DEFAULT_TARGET =
'/app'
DEFAULT_BINARY =
'rsync'
DEFAULT_INTERVAL =
2
BASE_OPTIONS =

Minimal set for a fast local-to-local mirror: -r walks the tree, -l keeps symlinks as symlinks, -t preserves mtimes so re-syncs can quick- check (size+mtime) instead of re-transferring unchanged files, and --whole-file skips the delta-transfer checksum pass that only pays off over a slow network. Owner/group/perm preservation (-o -g -p, part of -a) is left out since both sides are the same user; add them back via sync.options if a project needs them.

%w[-r -l -t --whole-file].freeze
VOLUME_MODES =

Trailing mount options wslc/docker accept after the container path.

%w[ro rw z Z cached delegated consistent].freeze
SYNC_MODES =

exec mirrors inside the already-running, wip-managed container (fast, but only correct when wip itself created that container with the sync mounts attached). run always mirrors from a disposable container, since compose owns its own services' mounts and never guarantees that shape.

%w[exec run].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(raw, base: nil, workdir: nil, container: nil, compose: false) ⇒ SyncSettings

Returns a new instance of SyncSettings.

Raises:



37
38
39
40
41
42
43
44
45
# File 'lib/wip/sync_settings.rb', line 37

def initialize(raw, base: nil, workdir: nil, container: nil, compose: false)
  raise ConfigError, 'sync must be a mapping' unless raw.is_a?(Hash)

  @base = base
  assign_paths(raw, workdir: workdir, container: container)
  assign_mirror(raw)
  assign_mode(raw, compose: compose)
  validate!
end

Instance Attribute Details

#binaryObject (readonly)

Returns the value of attribute binary.



35
36
37
# File 'lib/wip/sync_settings.rb', line 35

def binary
  @binary
end

#excludeObject (readonly)

Returns the value of attribute exclude.



35
36
37
# File 'lib/wip/sync_settings.rb', line 35

def exclude
  @exclude
end

#extra_optionsObject (readonly)

Returns the value of attribute extra_options.



35
36
37
# File 'lib/wip/sync_settings.rb', line 35

def extra_options
  @extra_options
end

#intervalObject (readonly)

Returns the value of attribute interval.



35
36
37
# File 'lib/wip/sync_settings.rb', line 35

def interval
  @interval
end

#modeObject (readonly)

Returns the value of attribute mode.



35
36
37
# File 'lib/wip/sync_settings.rb', line 35

def mode
  @mode
end

#mountObject (readonly)

Returns the value of attribute mount.



35
36
37
# File 'lib/wip/sync_settings.rb', line 35

def mount
  @mount
end

#targetObject (readonly)

Returns the value of attribute target.



35
36
37
# File 'lib/wip/sync_settings.rb', line 35

def target
  @target
end

#volumeObject (readonly)

Returns the value of attribute volume.



35
36
37
# File 'lib/wip/sync_settings.rb', line 35

def volume
  @volume
end

Instance Method Details

#delete?Boolean

Returns:

  • (Boolean)


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

def delete? = !!@delete

#exec?Boolean

Returns:

  • (Boolean)


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

def exec? = mode == 'exec'

#mirror_commandObject

Trailing slashes matter to rsync: they copy the contents of the mount into the target rather than nesting it one directory deeper.



68
69
70
71
72
73
74
# File 'lib/wip/sync_settings.rb', line 68

def mirror_command
  command = [binary, *BASE_OPTIONS]
  command << '--delete' if delete?
  command.concat(exclude.map { |pattern| "--exclude=#{pattern}" })
  command.concat(extra_options)
  command.push("#{mount.chomp('/')}/", "#{target.chomp('/')}/")
end

#replaces?(spec) ⇒ Boolean

True for a configured volume that sync replaces, so .:/app in defaults.volumes quietly becomes the read-only mount plus the volume.

Returns:

  • (Boolean)


62
63
64
# File 'lib/wip/sync_settings.rb', line 62

def replaces?(spec)
  [target.chomp('/'), mount.chomp('/')].include?(container_path(spec))
end

#sourceObject

Expanded against the wip.yml directory so the mirror covers the same tree no matter which subdirectory wip was invoked from.



52
53
54
# File 'lib/wip/sync_settings.rb', line 52

def source
  @source ||= @base ? Pathname(@base).join(@raw_source).expand_path.to_s : @raw_source
end

#to_hObject



76
77
78
79
80
# File 'lib/wip/sync_settings.rb', line 76

def to_h
  { 'source' => source, 'target' => target, 'mount' => mount, 'volume' => volume,
    'delete' => delete?, 'exclude' => exclude, 'command' => binary, 'options' => extra_options,
    'interval' => interval, 'mode' => mode }
end

#volume_specsObject

What -v specs the main container needs: the source read-only, and the named volume where the app actually runs.



58
# File 'lib/wip/sync_settings.rb', line 58

def volume_specs = ["#{source}:#{mount}:ro", "#{volume}:#{target}"]