class Au::Document

Attributes

path[R]

Public Class Methods

find(paths) click to toggle source
# File lib/au/models/document.rb, line 16
def self.find(paths)
  paths.is_a?(Array) ? paths.map{ |path| new(path) } : new(paths)
end
new(path) click to toggle source

Do NOT invoke this method directly, always use Document.find instead.

# File lib/au/models/document.rb, line 24
def initialize(path)
  @path = path
end

Public Instance Methods

changed?(parent_diff_id) click to toggle source
# File lib/au/models/document.rb, line 52
def changed?(parent_diff_id)
  !diff(parent_diff_id).empty?
end
checkout(diff_id) click to toggle source
# File lib/au/models/document.rb, line 67
def checkout(diff_id)
  # do nothing if file didn't change
  return if File.exists?(abs_path) && calculate_md5 == md5_at(diff_id)
  FileUtils.mkdir_p(File.dirname(abs_path)) unless File.exists?(abs_path)

  File.open(abs_path, 'w') do |f|
    apply_diffs(f, diff_id)
  end
end
content_from(diff_id) click to toggle source
# File lib/au/models/document.rb, line 60
def content_from(diff_id)
  output = Tempfile.new
  return output unless diff_id
  apply_diffs(output, diff_id)
  output
end
create_diff(parent_diff_id) click to toggle source
# File lib/au/models/document.rb, line 28
def create_diff(parent_diff_id)
  return nil unless File.exists?(abs_path)
  changes = diff(parent_diff_id)
  # if not first diff AND there's no change, don't create new diff
  return parent_diff_id if changes.empty? && parent_diff_id
  Diff.create(diff_db_name, parent_diff_id, changes, calculate_md5)
end
diff(parent_diff_id) click to toggle source
# File lib/au/models/document.rb, line 56
def diff(parent_diff_id)
  `diff -c #{abs_path} #{content_from(parent_diff_id).path}`
end
diff_3(ancestor_diff_id:, other_diff_id:) click to toggle source
# File lib/au/models/document.rb, line 36
def diff_3(ancestor_diff_id:, other_diff_id:)
  file_in_ancestor_state = content_from(ancestor_diff_id)
  file_in_other_state = content_from(other_diff_id)
  diff3_args = "#{abs_path} #{file_in_ancestor_state.path} #{file_in_other_state.path}"

  # diff3 has issue when this file and other file are identical, but ancestor is different,
  # so we need a special case for identical files
  return if (`diff -c #{abs_path} #{file_in_other_state.path}` == '')

  has_conflict = !`diff3 -x #{diff3_args}`.empty?
  merged_content = `diff3 --merge #{diff3_args}`
  File.open(abs_path, 'w'){ |f| f.write(merged_content) }

  raise HasMergeConflict.new(self) if has_conflict
end
md5_at(diff_id) click to toggle source
# File lib/au/models/document.rb, line 77
def md5_at(diff_id)
  Diff.find(diff_id, db_name: diff_db_name).md5
end

Private Instance Methods

abs_path() click to toggle source
# File lib/au/models/document.rb, line 102
def abs_path
  paths = [Repository.root, path].compact
  File.join(*paths)
end
apply_diffs(output, last_diff_id) click to toggle source
# File lib/au/models/document.rb, line 87
def apply_diffs(output, last_diff_id)
  Diff.replay_changes_upto(last_diff_id, diff_db_name) do |diff|
    Tempfile.create do |f|
      f.write(diff.change)
      f.rewind
      `patch -cR #{output.path} #{f.path}`
    end
  end
end
calculate_md5() click to toggle source
# File lib/au/models/document.rb, line 83
def calculate_md5
  Digest::MD5.hexdigest(File.read(abs_path))
end
diff_db_name() click to toggle source
# File lib/au/models/document.rb, line 97
def diff_db_name
  paths = [Repository.path, "diff_#{path.gsub('/', '.')}.pstore"].compact
  File.join(*paths)
end