Class: Constancy::SyncTarget

Inherits:
Object
  • Object
show all
Defined in:
lib/constancy/sync_target.rb

Constant Summary collapse

VALID_CONFIG_KEYS =
%w( name type datacenter prefix path exclude chomp delete )
REQUIRED_CONFIG_KEYS =
%w( prefix )
VALID_TYPES =
[ :dir, :file ]
DEFAULT_TYPE =
:dir

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config:, imperium_config:, base_dir:) ⇒ SyncTarget

Returns a new instance of SyncTarget.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/constancy/sync_target.rb', line 12

def initialize(config:, imperium_config:, base_dir:)
  if not config.is_a? Hash
    raise Constancy::ConfigFileInvalid.new("Sync target entries must be specified as hashes")
  end

  if (config.keys - Constancy::SyncTarget::VALID_CONFIG_KEYS) != []
    raise Constancy::ConfigFileInvalid.new("Only the following keys are valid in a sync target entry: #{Constancy::SyncTarget::VALID_CONFIG_KEYS.join(", ")}")
  end

  if (Constancy::SyncTarget::REQUIRED_CONFIG_KEYS - config.keys) != []
    raise Constancy::ConfigFileInvalid.new("The following keys are required in a sync target entry: #{Constancy::SyncTarget::REQUIRED_CONFIG_KEYS.join(", ")}")
  end

  @base_dir = base_dir
  self.datacenter = config['datacenter']
  self.prefix = config['prefix']
  self.path = config['path'] || config['prefix']
  self.name = config['name']
  self.type = (config['type'] || Constancy::SyncTarget::DEFAULT_TYPE).to_sym
  unless Constancy::SyncTarget::VALID_TYPES.include?(self.type)
    raise Constancy::ConfigFileInvalid.new("Sync target '#{self.name || self.path}' has type '#{self.type}'. But only the following types are valid: #{Constancy::SyncTarget::VALID_TYPES.collect(&:to_s).join(", ")}")
  end

  if self.type == :file and File.directory?(self.base_path)
    raise Constancy::ConfigFileInvalid.new("Sync target '#{self.name || self.path}' has type 'file', but path '#{self.path}' is a directory.")
  end

  self.exclude = config['exclude'] || []
  if config.has_key?('chomp')
    @do_chomp = config['chomp'] ? true : false
  end
  if config.has_key?('delete')
    @do_delete = config['delete'] ? true : false
  else
    @do_delete = false
  end

  self.consul = Imperium::KV.new(imperium_config)
end

Instance Attribute Details

#consulObject

Returns the value of attribute consul.



6
7
8
# File 'lib/constancy/sync_target.rb', line 6

def consul
  @consul
end

#datacenterObject

Returns the value of attribute datacenter.



6
7
8
# File 'lib/constancy/sync_target.rb', line 6

def datacenter
  @datacenter
end

#excludeObject

Returns the value of attribute exclude.



6
7
8
# File 'lib/constancy/sync_target.rb', line 6

def exclude
  @exclude
end

#nameObject

Returns the value of attribute name.



6
7
8
# File 'lib/constancy/sync_target.rb', line 6

def name
  @name
end

#pathObject

Returns the value of attribute path.



6
7
8
# File 'lib/constancy/sync_target.rb', line 6

def path
  @path
end

#prefixObject

Returns the value of attribute prefix.



6
7
8
# File 'lib/constancy/sync_target.rb', line 6

def prefix
  @prefix
end

#typeObject

Returns the value of attribute type.



6
7
8
# File 'lib/constancy/sync_target.rb', line 6

def type
  @type
end

Instance Method Details

#base_pathObject



75
76
77
# File 'lib/constancy/sync_target.rb', line 75

def base_path
  @base_path ||= File.join(@base_dir, self.path)
end

#chomp?Boolean

Returns:

  • (Boolean)


52
53
54
# File 'lib/constancy/sync_target.rb', line 52

def chomp?
  @do_chomp
end

#clear_cacheObject



68
69
70
71
72
73
# File 'lib/constancy/sync_target.rb', line 68

def clear_cache
  @base_path = nil
  @local_files = nil
  @local_items = nil
  @remote_items = nil
end

#delete?Boolean

Returns:

  • (Boolean)


56
57
58
# File 'lib/constancy/sync_target.rb', line 56

def delete?
  @do_delete
end

#description(mode = :push) ⇒ Object



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

def description(mode = :push)
  if mode == :pull
    "#{self.name.nil? ? '' : self.name.bold + "\n"}#{'consul'.cyan}:#{self.datacenter.green}:#{self.prefix} => #{'local'.blue}:#{self.path}"
  else
    "#{self.name.nil? ? '' : self.name.bold + "\n"}#{'local'.blue}:#{self.path} => #{'consul'.cyan}:#{self.datacenter.green}:#{self.prefix}"
  end
end

#diff(mode) ⇒ Object



122
123
124
# File 'lib/constancy/sync_target.rb', line 122

def diff(mode)
  Constancy::Diff.new(target: self, local: self.local_items, remote: self.remote_items, mode: mode)
end

#local_filesObject



79
80
81
82
# File 'lib/constancy/sync_target.rb', line 79

def local_files
  # see https://stackoverflow.com/questions/357754/can-i-traverse-symlinked-directories-in-ruby-with-a-glob
  @local_files ||= Dir["#{self.base_path}/**{,/*/**}/*"].select { |f| File.file?(f) }
end

#local_itemsObject



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/constancy/sync_target.rb', line 84

def local_items
  return @local_items if not @local_items.nil?
  @local_items = {}

  case self.type
  when :dir
    self.local_files.each do |local_file|
      @local_items[local_file.sub(%r{^#{self.base_path}/?}, '')] =
        if self.chomp?
          File.read(local_file).chomp.force_encoding(Encoding::ASCII_8BIT)
        else
          File.read(local_file).force_encoding(Encoding::ASCII_8BIT)
        end
    end

  when :file
    if File.exist?(self.base_path)
      @local_items = flatten_hash(nil, YAML.load_file(self.base_path))
    end
  end

  @local_items
end

#remote_itemsObject



108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/constancy/sync_target.rb', line 108

def remote_items
  return @remote_items if not @remote_items.nil?
  @remote_items = {}

  resp = self.consul.get(self.prefix, :recurse, dc: self.datacenter)

  return @remote_items if resp.values.nil?
  Constancy::Util.flatten_hash(resp.values).each_pair do |key, value|
    @remote_items[key.join("/")] = (value.nil? ? '' : value)
  end

  @remote_items
end