class Au::Repository

Attributes

current[R]

singleton class

head[R]

singleton class

path[R]

singleton class

root[R]

singleton class

Public Class Methods

diff(file_path) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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
new(path, create = false) click to toggle source
# 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
path(path = nil) click to toggle source
# File lib/au/models/repository.rb, line 12
def self.path(path = nil)
  instance(path, false).path
end
root(path = nil) click to toggle source
# File lib/au/models/repository.rb, line 8
def self.root(path = nil)
  instance(path, false).root
end

Private Class Methods

resolve_conflict_fname() click to toggle source
# File lib/au/models/repository.rb, line 259
def self.resolve_conflict_fname
  File.join(Repository.instance.path, 'resolve_conflict')
end

Public Instance Methods

checkout(commit_id) click to toggle source
# 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) click to toggle source
# 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
heads() click to toggle source

def clone

end

# File lib/au/models/repository.rb, line 211
def heads
  @leaves_pstore.transaction(true) do
    @leaves_pstore.roots
  end
end
merge(commit_to_merge) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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_var() click to toggle source
# 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) click to toggle source
# 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

Private Instance Methods

diff_db_name_remote(file_path, remote_path) click to toggle source
# File lib/au/models/repository.rb, line 236
def diff_db_name_remote(file_path, remote_path)
  paths = [remote_path, "diff_#{file_path.gsub('/', '.')}.pstore"].compact
  File.join(*paths)
end
update_alt_list() click to toggle source
# File lib/au/models/repository.rb, line 247
def update_alt_list
  @alt_list = @alt_pstore.transaction(true) do
    @alt_pstore[:commit]
  end
end
update_alt_pstore(commit_id) click to toggle source
# File lib/au/models/repository.rb, line 253
def update_alt_pstore(commit_id)
  @alt_pstore.transaction do
    @alt_pstore[:commit].nil? ? (@alt_pstore[:commit] = [commit_id]) : (@alt_pstore[:commit] << commit_id)
  end
end
update_head_pstore(commit_id) click to toggle source
# File lib/au/models/repository.rb, line 241
def update_head_pstore(commit_id)
  @head = @head_pstore.transaction do
    @head_pstore[:head] = commit_id
  end
end