Class: Treet::Repo

Inherits:
Object
  • Object
show all
Defined in:
lib/treet/repo.rb

Direct Known Subclasses

Gitrepo

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, opts = {}) ⇒ Repo

Returns a new instance of Repo.

Raises:

  • (Errno::ENOENT)


6
7
8
9
10
# File 'lib/treet/repo.rb', line 6

def initialize(path, opts = {})
  raise Errno::ENOENT, "Missing or invalid source path #{path}" unless File.directory?(path)

  @root = path
end

Instance Attribute Details

#rootObject (readonly)

Returns the value of attribute root.



4
5
6
# File 'lib/treet/repo.rb', line 4

def root
  @root
end

Class Method Details

.filefor(keyname) ⇒ Object

patch keys can look like

name.first
emails[]

(address syntax has been eliminated, we recognize array elements by matching the entire content)



24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/treet/repo.rb', line 24

def self.filefor(keyname)
  if keyname =~ /\[/
    keyname = keyname.match(/^(.*)\[\]$/).captures.first
    [keyname, '', nil]
  elsif keyname =~ /\./
    # subelement
    # negative lookbehind; don't split on a dot at beginning of string
    filename,field = keyname.split(/(?<!^)\./)
    ['.', filename, field]
  else
    ['.', keyname]
  end
end

Instance Method Details

#compare(target) ⇒ Object



16
17
18
# File 'lib/treet/repo.rb', line 16

def compare(target)
  Treet::Hash.diff(to_hash, target.to_hash)
end

#patch(diffs) ⇒ Object

Patching a repo is not the same as patching a hash. Make the changes directly to the data files.



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/treet/repo.rb', line 40

def patch(diffs)
  @hash = nil # invalidate any cached image

  Dir.chdir(root) do
    diffs.each do |diff|
      flag, key, v1, _ = diff
      # if key =~ /\[/
      #   keyname = key.match(/^(.*)\[\]$/).captures
      # elsif key =~ /\./
      #   keyname, subkey = key.match(/^(.*)\.(.*)$/).captures
      # else
      #   keyname = key
      # end

      dirname, filename, fieldname = Treet::Repo.filefor(key)
      filepath = "#{dirname}/#{filename}"

      case flag
      when '~'
        # change a value in place
        # load the current data & overwrite with the new value
        # idempotent: this will overwrite the file with the same contents
        if fieldname
          # hash entry
          data = File.exists?(filepath) ? JSON.load(File.open(filepath)) : {}
          data[fieldname] = v1
          File.open(filepath, "w") {|f| f << JSON.pretty_generate(data)}
        else
          # string entry
          File.open(filepath, "w") {|f| f << v1}
        end

      when '+'
        # add something
        if fieldname
          # writing a value into a hash
          # idempotent: this will overwrite the file with the same contents
          data = File.exists?(filepath) ? JSON.load(File.open(filepath)) : {}
          data[fieldname] = v1
          Dir.mkdir(dirname) unless Dir.exists?(dirname)
          File.open(filepath, "w") {|f| f << JSON.pretty_generate(data)}
        else
          # writing an entire hash into an array entry
          # idempotent: this will overwrite the file with the same contents
          subfile = "#{dirname}/#{Treet::Hash.digestify(v1)}"
          Dir.mkdir(dirname) unless Dir.exists?(dirname)
          case v1
          when Hash
            # hash entry
            File.open(subfile, "w") {|f| f << JSON.pretty_generate(v1)}
          else
            # string entry - create empty file with this name
            FileUtils.touch(subfile)
          end
        end

      when '-'
        # remove something
        if fieldname
          # this is a key in a subhash
          if File.exists?(filepath)
            # if the subhash is missing, there's nothing to remove, so do nothing (for idempotence)
            data = JSON.load(File.open(filepath))
            data.delete(fieldname)
            if data.empty?
              # all keys have been removed, clean up the file
              File.delete(filename)
            else
              File.open(filepath, "w") {|f| f << JSON.pretty_generate(data)}
            end
          end
        elsif dirname == "."
          # this is a top-level string
          File.delete(filename) if File.exists?(filename) # need the existence check for idempotence
        else
          # this is an array, we look for a match on the entire contents via digest
          subfile = "#{dirname}/#{Treet::Hash.digestify(v1)}"
          File.delete(subfile) if File.exists?(subfile) # need the existence check for idempotence
          # TODO: if dirname is now empty, should it be removed? is that worthwhile?
        end
      end
    end
  end

  to_hash # ?? return the patched data? or no return value? true/false for success?
end

#to_hashObject



12
13
14
# File 'lib/treet/repo.rb', line 12

def to_hash
  expand(root)
end