Class: Eternity::Repository

Inherits:
Object
  • Object
show all
Defined in:
lib/eternity/repository.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, options = {}) ⇒ Repository

Returns a new instance of Repository.



6
7
8
9
10
11
12
13
14
# File 'lib/eternity/repository.rb', line 6

def initialize(name, options={})
  @name = name.to_s
  @id = Eternity.keyspace[:repository][@name]
  @tracker = Tracker.new self
  @current = Restruct::Hash.new connection: Eternity.connection, id: id[:current]
  @branches = Restruct::Hash.new connection: Eternity.connection, id: id[:branches]
  @locker = Eternity.locker_for @name
  @default_branch = options.fetch(:default_branch, 'master').to_s
end

Instance Attribute Details

#branchesObject (readonly)

Returns the value of attribute branches.



4
5
6
# File 'lib/eternity/repository.rb', line 4

def branches
  @branches
end

#idObject (readonly)

Returns the value of attribute id.



4
5
6
# File 'lib/eternity/repository.rb', line 4

def id
  @id
end

#nameObject (readonly)

Returns the value of attribute name.



4
5
6
# File 'lib/eternity/repository.rb', line 4

def name
  @name
end

Class Method Details

.allObject



174
175
176
177
178
179
180
# File 'lib/eternity/repository.rb', line 174

def self.all
  sections_count = Eternity.keyspace[:repository].sections.count
  names = Eternity.connection.call('KEYS', Eternity.keyspace[:repository]['*']).map do |key|
    Restruct::Id.new(key).sections[sections_count]
  end.uniq
  names.map { |name| new name }
end

Instance Method Details

#[](collection) ⇒ Object



16
17
18
# File 'lib/eternity/repository.rb', line 16

def [](collection)
  tracker[collection]
end

#branch(name) ⇒ Object



67
68
69
70
71
72
# File 'lib/eternity/repository.rb', line 67

def branch(name)
  raise "Can't branch without commit" unless current_commit?
  raise "Can't branch with uncommitted changes" if changes?

  branches[name] = current_commit.id
end

#changes?Boolean

Returns:

  • (Boolean)


24
25
26
# File 'lib/eternity/repository.rb', line 24

def changes?
  !tracker.empty?
end

#changes_countObject



28
29
30
# File 'lib/eternity/repository.rb', line 28

def changes_count
  tracker.count
end

#checkout(options) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/eternity/repository.rb', line 74

def checkout(options)
  raise "Can't checkout with uncommitted changes" if changes?

  locker.lock! :checkout do
    Eternity.logger.info(self.class) { "Checkout #{name} (#{options.map { |k,v| "#{k}: #{v}" }.join(', ')})" }
    
    original_commit = current_commit

    commit_id, branch = extract_commit_and_branch options

    if commit_id
      raise "Invalid commit #{commit_id}" unless Commit.exists? commit_id
      current[:commit] = commit_id
      branches[branch] = commit_id
    else
      current.delete :commit
      branches.delete branch
    end

    current[:branch] = branch

    Patch.diff original_commit, current_commit
  end
end

#commit(options) ⇒ Object



58
59
60
61
62
63
64
65
# File 'lib/eternity/repository.rb', line 58

def commit(options)
  raise 'Nothing to commit' unless changes?

  locker.lock! :commit do
    commit! message: options.fetch(:message), 
            author:  options.fetch(:author)
  end
end

#current_branchObject



54
55
56
# File 'lib/eternity/repository.rb', line 54

def current_branch
  current[:branch] || @default_branch
end

#current_commitObject



50
51
52
# File 'lib/eternity/repository.rb', line 50

def current_commit
  Commit.new current[:commit]
end

#current_commit?Boolean

Returns:

  • (Boolean)


46
47
48
# File 'lib/eternity/repository.rb', line 46

def current_commit?
  current.key? :commit
end

#deltaObject



32
33
34
# File 'lib/eternity/repository.rb', line 32

def delta
  tracker.flatten
end

#delta=(delta) ⇒ Object



36
37
38
39
40
41
42
43
44
# File 'lib/eternity/repository.rb', line 36

def delta=(delta)
  tracker.clear
  delta.each do |collection, changes|
    changes.each do |id, change|
      args = [id, change['data']].compact
      self[collection].send(change['action'], *args)
    end
  end
end

#destroyObject



153
154
155
156
157
# File 'lib/eternity/repository.rb', line 153

def destroy
  tracker.destroy
  current.destroy
  branches.destroy
end

#empty?Boolean

Returns:

  • (Boolean)


20
21
22
# File 'lib/eternity/repository.rb', line 20

def empty?
  tracker.empty? && current.empty? && branches.empty?
end

#logObject



149
150
151
# File 'lib/eternity/repository.rb', line 149

def log
  current_commit? ? ([current_commit] + current_commit.history) : []
end

#merge(options) ⇒ Object



99
100
101
102
103
104
105
106
107
# File 'lib/eternity/repository.rb', line 99

def merge(options)
  raise "Can't merge with uncommitted changes" if changes?

  commit_id = extract_commit options

  raise "Invalid commit #{commit_id}" unless Commit.exists? commit_id

  merge! Commit.new(commit_id)
end

#pullObject



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/eternity/repository.rb', line 122

def pull
  raise "Can't pull with uncommitted changes" if changes?
  raise "Branch not found: #{current_branch}" unless Branch.exists? current_branch

  target_commit = Branch[current_branch]

  Eternity.logger.info(self.class) { "Pull #{name} (#{target_commit.id})" }

  if current_commit == target_commit || current_commit.fast_forward?(target_commit)
    Patch.merge current_commit, target_commit
  elsif target_commit.fast_forward?(current_commit)
    checkout commit: target_commit.id
  else 
    merge! target_commit
  end
end

#pushObject



109
110
111
112
# File 'lib/eternity/repository.rb', line 109

def push
  raise 'Push rejected (non fast forward)' if current_commit != Branch[current_branch] && !current_commit.fast_forward?(Branch[current_branch])
  push!
end

#push!Object



114
115
116
117
118
119
120
# File 'lib/eternity/repository.rb', line 114

def push!
  raise "Can't push without commit" unless current_commit?

  Eternity.logger.info(self.class) { "Push #{name} (#{current_commit.id})" }

  Branch[current_branch] = current_commit.id
end

#restore(dump) ⇒ Object



168
169
170
171
172
# File 'lib/eternity/repository.rb', line 168

def restore(dump)
  current.merge! dump['current']
  branches.merge! dump['branches']
  self.delta = dump['delta']
end

#revertObject



139
140
141
142
143
144
145
146
147
# File 'lib/eternity/repository.rb', line 139

def revert
  locker.lock! :revert do
    Eternity.logger.info(self.class) { "Revert #{name}" }

    current_commit.with_index do |index|
      Delta.revert(delta, index).tap { tracker.revert }
    end
  end
end

#to_hObject Also known as: dump



159
160
161
162
163
164
165
# File 'lib/eternity/repository.rb', line 159

def to_h
  {
    'current' => current.to_h,
    'branches' => branches.to_h,
    'delta' => delta
  }
end