Class: Au::Repository

Inherits:
Object show all
Defined in:
lib/au/models/repository.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, create = false) ⇒ Repository

Returns a new instance of Repository.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/au/models/repository.rb', line 36

def initialize(path, create = false)
  if path.nil?
    working_dir = Dir.pwd
    # little bit different with mercurial 0.1
    # here we only check whether the current working directory is a repository
    if not File.directory?(File.join(working_dir, '.au')) and not create
      raise 'Repository not found in ' + working_dir
    end
    path = working_dir
  end

  @root = path
  @path = File.join(path, '.au')

  Dir.mkdir(@path) if create && !File.directory?(@path)

  @head_pstore = PStore.new(File.join(@path, 'head.pstore'))

  update_head_var

  @alt_pstore = PStore.new(File.join(@path, 'alt.pstore'))

  update_alt_list

  @leaves_pstore = PStore.new(File.join(@path, 'leaves.pstore'))
end

Instance Attribute Details

#currentObject (readonly)

singleton class



6
7
8
# File 'lib/au/models/repository.rb', line 6

def current
  @current
end

#headObject (readonly)

singleton class



6
7
8
# File 'lib/au/models/repository.rb', line 6

def head
  @head
end

#pathObject (readonly)

singleton class



6
7
8
# File 'lib/au/models/repository.rb', line 6

def path
  @path
end

#rootObject (readonly)

singleton class



6
7
8
# File 'lib/au/models/repository.rb', line 6

def root
  @root
end

Class Method Details

.diff(file_path) ⇒ Object



20
21
22
23
24
25
# File 'lib/au/models/repository.rb', line 20

def self.diff(file_path)
  return nil unless head
  tracked_version = head.cat(file_path)
  return nil unless tracked_version
  `diff -c #{tracked_version.path} #{File.join(root, file_path)}`
end

.head(path = nil) ⇒ Object



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

def self.head(path = nil)
  Commit.find instance(path, false).head
end

.instance(path = nil, create = false) ⇒ Object



27
28
29
30
31
32
33
34
# File 'lib/au/models/repository.rb', line 27

def self.instance(path = nil, create = false)
  return @single_instance unless @single_instance.nil?
  begin
    @single_instance = new(path, create)
  rescue
    Kernel.abort("Fetal error: Repository not found. ")
  end
end

.path(path = nil) ⇒ Object



12
13
14
# File 'lib/au/models/repository.rb', line 12

def self.path(path = nil)
  instance(path, false).path
end

.root(path = nil) ⇒ Object



8
9
10
# File 'lib/au/models/repository.rb', line 8

def self.root(path = nil)
  instance(path, false).root
end

Instance Method Details

#checkout(commit_id) ⇒ Object



88
89
90
91
92
93
94
95
96
# File 'lib/au/models/repository.rb', line 88

def checkout(commit_id)
  this_commit = Commit.find(commit_id)
  if this_commit
    this_commit.checkout(update_head_var)
    update_alt_pstore(update_head_var)
    update_head_pstore(commit_id)
    update_head_var
  end
end

#commit(commit_message) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/au/models/repository.rb', line 71

def commit(commit_message)
  staged_file_paths = Staging.staged_file_paths
  return if staged_file_paths.empty?
  commit_created_id =
      if File.exist?(Repository.resolve_conflict_fname)
        parent_id1, parent_id2 = File.read(Repository.resolve_conflict_fname).split(',')
        File.delete(Repository.resolve_conflict_fname)
        Commit.create_commit_resolve_conflict(staged_file_paths, parent_id1, parent_id2)
      else
        Commit.create(staged_file_paths, commit_message, @head)
      end
  update_head_pstore(commit_created_id)
  update_leaves_pstore(commit_created_id)
  Staging.clear_staged_file_paths
  commit_created_id
end

#headsObject

def clone

end



211
212
213
214
215
# File 'lib/au/models/repository.rb', line 211

def heads
  @leaves_pstore.transaction(true) do
    @leaves_pstore.roots
  end
end

#merge(commit_to_merge) ⇒ Object



63
64
65
66
67
68
69
# File 'lib/au/models/repository.rb', line 63

def merge(commit_to_merge)
  commit_id = Commit.merge(@head, commit_to_merge)
  return nil if commit_id.nil?
  # checkout to new commit
  checkout(commit_id)
  commit_id
end

#pull(remote_repo) ⇒ Object



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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/au/models/repository.rb', line 98

def pull(remote_repo)
  # Initialize local and remote db and commit list
  remote_commit_db = Commit.db(remote_repo.path)
  remote_commit_list = remote_commit_db.transaction do
    remote_commit_db.roots
  end
  local_commit_db = Commit.db
  local_commit_list = local_commit_db.transaction do
    local_commit_db.roots
  end
  # Check if the root commits are the same
  if local_commit_list[0] != remote_commit_list[0]
    raise "Error: Root commits do not match."
  end

  # Find commits that only exist on remote repo
  commit_id_to_add_list = remote_commit_list.reject{|x| local_commit_list.include?(x)}
  commits_to_add = {}
  remote_commit_db.transaction(true) do
    commit_id_to_add_list.each{|commit_id| commits_to_add[commit_id] = remote_commit_db[commit_id]}
  end

  # Write those commits to local commit db
  local_commit_db.transaction do
    commits_to_add.each{|commit_id, data| local_commit_db[commit_id] = data}
  end

  # Find documents and their diff_id in those commits that only existed remotely
  remote_diff_id_to_add_list = {}
  commits_to_add.each do |_, commit|
    commit[:doc_diff_ids].each do |doc_path, diff_id|
      remote_diff_id_to_add_list[doc_path] = diff_id
    end
  end

  # Write these information to local
  remote_diff_id_to_add_list.each do |doc_path, diff_id|
    diff_pstore_remote = PStore.new(diff_db_name_remote(doc_path, remote_repo.path))
    diff_pstore_remote.transaction(true) do
      diff_pstore_local = PStore.new(diff_db_name_remote(doc_path, @path))
      diff_pstore_local.transaction do
        if diff_pstore_local[diff_id] == nil
          diff_pstore_local[diff_id] = diff_pstore_remote[diff_id]
        elsif diff_pstore_local[diff_id] != diff_pstore_remote[diff_id]
          raise "Error: Remote and local reposiroty have different content in a same diff"
        end
      end
    end
  end

  # Find heads that only exist on remote repo
  heads_to_add = remote_repo.heads.reject{|x| heads.include?(x)}
  heads_to_add.each{|x| update_leaves_pstore(x)}
end

#push(remote_repo) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/au/models/repository.rb', line 153

def push(remote_repo)
  # Initialize local and remote db and commit list
  remote_commit_db = Commit.db(remote_repo.path)
  remote_commit_list = remote_commit_db.transaction do
    remote_commit_db.roots
  end
  local_commit_db = Commit.db
  local_commit_list = local_commit_db.transaction do
    local_commit_db.roots
  end
  # Check if the root commits are the same
  if local_commit_list[0] != remote_commit_list[0]
    raise "Error: Root commits do not match."
  end

  # Find commits that only exist locally
  commit_id_to_add_list = local_commit_list.reject{|x| remote_commit_list.include?(x)}
  commits_to_add = {}
  local_commit_db.transaction(true) do
    commit_id_to_add_list.each{|commit_id| commits_to_add[commit_id] = local_commit_db[commit_id]}
  end

  # Write those commits to remote commit db
  remote_commit_db.transaction do
    commits_to_add.each{|commit_id, data| remote_commit_db[commit_id] = data}
  end

  # Find documents and their diff_id in those commits that only existed locally
  local_diff_id_to_add_list = {}
  commits_to_add.each do |_, commit|
    commit[:doc_diff_ids].each do |doc_path, diff_id|
      local_diff_id_to_add_list[doc_path] = diff_id
    end
  end

  # Write these information to remote
  local_diff_id_to_add_list.each do |doc_path, diff_id|
    diff_pstore_local = PStore.new(diff_db_name_remote(doc_path, @path))
    diff_pstore_local.transaction(true) do
      diff_pstore_remote = PStore.new(diff_db_name_remote(doc_path, remote_repo.path))
      diff_pstore_remote.transaction do
        if diff_pstore_remote[diff_id] == nil
          diff_pstore_remote[diff_id] = diff_pstore_local[diff_id]
        elsif diff_pstore_local[diff_id] != diff_pstore_remote[diff_id]
          raise "Error: Remote and local reposiroty have different content in a same diff"
        end
      end
    end
  end
  # Find heads that only exist on remote repo
  heads_to_add = heads.reject{|x| remote_repo.heads.include?(x)}
  heads_to_add.each{|x| remote_repo.update_leaves_pstore(x)}
end

#update_head_varObject



217
218
219
220
221
# File 'lib/au/models/repository.rb', line 217

def update_head_var
  @head = @head_pstore.transaction(true) do
    @head_pstore[:head]
  end
end

#update_leaves_pstore(commit_id) ⇒ Object



223
224
225
226
227
228
229
230
231
232
233
# File 'lib/au/models/repository.rb', line 223

def update_leaves_pstore(commit_id)
  @leaves_pstore.transaction do
    commit = Commit.find(commit_id)
    if commit
      parent_commit_id_1, parent_commit_id_2 = commit.parent_id_1, commit.parent_id_2
      @leaves_pstore.delete(parent_commit_id_1)
      @leaves_pstore.delete(parent_commit_id_2)
      @leaves_pstore[commit_id] = 1
    end
  end
end