Class: Amp::FileLog

Inherits:
Revlog show all
Defined in:
lib/amp/revlogs/file_log.rb

Overview

FileLog

A FileLog is the revision log that stores revision history for each individual file tracked by the system. It stores special meta-data for handling files that have been copied over their history.

Direct Known Subclasses

Bundles::BundleFileLog

Constant Summary

Constants included from RevlogSupport::Node

RevlogSupport::Node::NULL_ID, RevlogSupport::Node::NULL_REV

Instance Attribute Summary

Attributes inherited from Revlog

#data_file, #index, #index_file

Instance Method Summary collapse

Methods inherited from Revlog

#[], #add_group, #add_revision, #all_indices, #ancestor, #ancestors, #base_revision_for_index, #check_inline_size, #checksize, #children, #data_end_for_index, #data_size_for_index, #data_start_for_index, #decompress_revision, #descendants, #empty?, #files, #find_missing, #get_chunk, #group, #heads, #id_match, #link_revision_for_index, #load_cache, #lookup_id, #node_id_for_index, #nodes_between, #open, #parent_indices_for_index, #parents_for_node, #partial_id_match, #reachable_nodes_for_node, #revision_diff, #revision_index_for_node, #strip, #tip, #uncompressed_size_for_index

Methods included from RevlogSupport::Node

#short

Methods included from Enumerable

#inject, #select_map

Constructor Details

#initialize(opener, path) ⇒ FileLog

Initializes the revision log, being sure to encode directories to avoid naming conflicts

Parameters:

  • opener (Opener)

    the opener to use for opening the file

  • path (String)

    the path to the file, excluding “data”.



15
16
17
# File 'lib/amp/revlogs/file_log.rb', line 15

def initialize(opener, path)
  super(opener, ["data", encode_dir(path + ".i")].join("/"))
end

Instance Method Details

#add(text, meta, journal, link, p1 = nil, p2 = nil) ⇒ Object

Adds a revision to the file’s history. Overridden for special metadata

Parameters:

  • text (String)

    the new text of the file

  • meta (Hash)

    the meta data to use (if we copied)

  • journal (Journal)

    for aborting transaction

  • link (Integer)

    the revision number this is linked to

  • p1 (Integer) (defaults to: nil)

    (nil) the first parent of this new revision

  • p2 (Integer) (defaults to: nil)

    (nil) the second parent of this new revision

  • digest (String)

    referring to the node this makes



79
80
81
82
83
84
85
86
# File 'lib/amp/revlogs/file_log.rb', line 79

def add(text, meta, journal, link, p1=nil, p2=nil)
  if (meta && meta.any?) || text.start_with?("\1\n")
    mt = ""
    mt = meta.map {|k, v| "#{k}: #{v}\n"} if meta
    text = "\1\n" + mt.join + "\1\n" + text
  end
  add_revision(text, journal, link, p1, p2)
end

#cmp(thenode, text) ⇒ Boolean

Converts a given node in this revision with the text provided. overridden because it handles renamed files.

Parameters:

  • thenode (String)

    the node ID to use

  • text (String)

    the text to compare against

Returns:

  • (Boolean)

    true if they’re different, false if not. silly, isn’t it?



156
157
158
159
160
161
162
# File 'lib/amp/revlogs/file_log.rb', line 156

def cmp(thenode, text)
  if renamed? thenode
    t2 = read thenode
    return t2 != text
  end
  super(thenode, text)
end

#decode_dir(path) ⇒ String

Decodes the directory to avoid naming conflicts

Parameters:

  • path (String)

    the path to decode for naming conflict issues

Returns:

  • (String)

    the decoded directory path



33
34
35
# File 'lib/amp/revlogs/file_log.rb', line 33

def decode_dir(path)
  path.gsub(".d.hg/",".d/").gsub(".i.hg/",".i/").gsub(".hg.hg/",".hg/")
end

#each(&block) ⇒ Object

Yields a block for every revision, while being sure to follow copies.



110
111
112
113
114
115
116
117
118
119
# File 'lib/amp/revlogs/file_log.rb', line 110

def each(&block)
  if @index[0].parent_one_rev == NULL_REV
    meta_info = renamed(@index[0].node_id)
    if meta_info
      copied_log = FileLog.new(@opener, meta_info.first)
      copied_log.each(&block)
    end
  end
  super(&block)
end

#encode_dir(path) ⇒ String

Encodes the directory to avoid naming conflicts

Parameters:

  • path (String)

    the path to encode for naming conflict issues

Returns:

  • (String)

    the encoded directory path



24
25
26
# File 'lib/amp/revlogs/file_log.rb', line 24

def encode_dir(path)
  path.gsub(".hg/",".hg.hg/").gsub(".i/",".i.hg/").gsub(".d/",".d.hg/")
end

#read(node) ⇒ String

Reads the data of the revision, ignoring the meta data for copied files

Parameters:

  • node (String)

    the node_id to read

Returns:

  • (String)

    the data of the revision



42
43
44
45
46
47
48
# File 'lib/amp/revlogs/file_log.rb', line 42

def read(node)
  t = decompress_revision(node)
  return t unless t.start_with?("\1\n")

  start = t.index("\1\n", 2)
  t[(start+2)..-1]
end

#read_meta(node) ⇒ Hash

Reads the meta data in the node

Parameters:

  • node (String)

    the node_id to read the meta of

Returns:

  • (Hash)

    the meta data in this revision. Could be empty hash.



55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/amp/revlogs/file_log.rb', line 55

def read_meta(node)
  t = decompress_revision(node)
  return {} unless t.start_with?("\1\n")
  
  start = t.index("\1\n", 2)
  mt = t[2..(start-1)]
  m = {}
  mt.split("\n").each do |l|
    k, v = l.split(": ", 2)
    m[k] = v
  end
  m
end

#renamed(node) ⇒ Boolean Also known as: renamed?

Returns whether or not the file at node has been renamed or copied.

Parameters:

  • node (String)

    the node_id of the revision

Returns:

  • (Boolean)

    has the file been renamed or copied at this revision?



95
96
97
98
99
100
101
102
103
104
105
# File 'lib/amp/revlogs/file_log.rb', line 95

def renamed(node)
  return false if parents_for_node(node).first != NULL_ID
  
  m = read_meta node
  
  if m.any? && m["copy"]
    return [m["copy"], m["copyrev"].unhexlify]
  end
  
  false
end

#size(rev) ⇒ String

Gets the size of the file. Overridden because of the metadata for copied files.

Parameters:

  • rev (Integer)

    the number of the revision to lookup

Returns:

  • (String)

    the file’s data



139
140
141
142
143
144
145
146
# File 'lib/amp/revlogs/file_log.rb', line 139

def size(rev)
  node = self.node rev
  if renamed? node
    read(node).size
  else
    self[rev].compressed_len
  end
end

#unified_revision_diff(rev1, old_date, rev2, new_date, path1, path2, opts = {}) ⇒ Object

Unified diffs 2 revisions, based on their indices. They are returned in a sexified unified diff format.



124
125
126
127
128
129
130
131
# File 'lib/amp/revlogs/file_log.rb', line 124

def unified_revision_diff(rev1, old_date, rev2, new_date, path1, path2, opts={})
  opts = Diffs::MercurialDiff::DEFAULT_OPTIONS.merge(opts)
  version_1 = rev1 ? read(self.node_id_for_index(rev1)) : nil
  version_2 = rev2 ? read(self.node_id_for_index(rev2)) : nil
  
  Diffs::MercurialDiff.unified_diff( version_1, old_date, version_2, new_date,
                                  path1, path2, false, opts)
end