Class: Amp::ChangeLog
Overview
A ChangeLog is a special revision log that stores the actual commit data, including usernames, dates, messages, all kinds of stuff.
This version of the revision log is special though, because sometimes we have to hold off on writing until all other updates are done, for example during merges that might fail. So we have to actually have a real Opener and a fake one, which will save the data in memory. When you call #finalize, the fake file will replace the real deal.
Direct Known Subclasses
Constant Summary
Constants included from RevlogSupport::Node
RevlogSupport::Node::NULL_ID, RevlogSupport::Node::NULL_REV
Instance Attribute Summary collapse
-
#delay_buffer ⇒ Object
Returns the value of attribute delay_buffer.
-
#delay_count ⇒ Object
Returns the value of attribute delay_count.
-
#delay_name ⇒ Object
Returns the value of attribute delay_name.
-
#index_file ⇒ Object
Returns the value of attribute index_file.
-
#node_map ⇒ Object
Returns the value of attribute node_map.
Attributes inherited from Revlog
Instance Method Summary collapse
-
#add(manifest, files, desc, journal, p1 = nil, p2 = nil, user = nil, date = nil, extra = {}) ⇒ Object
Adds the given commit to the changelog.
-
#check_inline_size(journal, fp = nil) ⇒ Object
Does a check on our size, but knows enough to quit if we’re still in delayed-writing mode.
-
#decode_extra(text) ⇒ Hash
Decodes the extra data stored with the commit, such as requirements or just about anything else we need to save.
-
#delay_update ⇒ Object
Tells the changelog to stop writing updates directly to the file, and start saving any new info to memory/other files.
-
#encode_extra(data) ⇒ String
Encodes the extra data in a format we can use for writing.
-
#finalize(journal) ⇒ Object
Finalizes the changelog by swapping out the fake file if it has to.
-
#initialize(opener) ⇒ ChangeLog
(also: #changelog_initialize)
constructor
Initializes the revision log.
-
#read(node) ⇒ [String, String, [Float, Integer], [String], String, Hash]
Reads the revision at the given node_id.
-
#read_pending(file) ⇒ Object
Reads while we’re blocking this changelog’s output.
-
#write_pending ⇒ Object
Writes our data, while being aware of the delay buffer when we’re holding off on finalizing the changelog.
Methods inherited from Revlog
#[], #add_group, #add_revision, #all_indices, #ancestor, #ancestors, #base_revision_for_index, #checksize, #children, #cmp, #data_end_for_index, #data_size_for_index, #data_start_for_index, #decompress_revision, #descendants, #each, #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, #size, #strip, #tip, #uncompressed_size_for_index, #unified_revision_diff
Methods included from RevlogSupport::Node
Methods included from Enumerable
Constructor Details
#initialize(opener) ⇒ ChangeLog Also known as: changelog_initialize
Initializes the revision log. Just pass in an Opener. Amp::Opener.new(path) will do just fine.
163 164 165 166 |
# File 'lib/amp/revlogs/changelog.rb', line 163 def initialize(opener) super(opener, "00changelog.i") @node_map = @index.node_map end |
Instance Attribute Details
#delay_buffer ⇒ Object
Returns the value of attribute delay_buffer.
155 156 157 |
# File 'lib/amp/revlogs/changelog.rb', line 155 def delay_buffer @delay_buffer end |
#delay_count ⇒ Object
Returns the value of attribute delay_count.
155 156 157 |
# File 'lib/amp/revlogs/changelog.rb', line 155 def delay_count @delay_count end |
#delay_name ⇒ Object
Returns the value of attribute delay_name.
155 156 157 |
# File 'lib/amp/revlogs/changelog.rb', line 155 def delay_name @delay_name end |
#index_file ⇒ Object
Returns the value of attribute index_file.
155 156 157 |
# File 'lib/amp/revlogs/changelog.rb', line 155 def index_file @index_file end |
#node_map ⇒ Object
Returns the value of attribute node_map.
155 156 157 |
# File 'lib/amp/revlogs/changelog.rb', line 155 def node_map @node_map end |
Instance Method Details
#add(manifest, files, desc, journal, p1 = nil, p2 = nil, user = nil, date = nil, extra = {}) ⇒ Object
Handle text encodings
Adds the given commit to the changelog.
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
# File 'lib/amp/revlogs/changelog.rb', line 317 def add(manifest, files, desc, journal, p1=nil, p2=nil, user=nil, date=nil, extra={}) user = user.strip raise RevlogSupport::RevlogError.new("no \\n in username") if user=~ /\n/ user, desc = user, desc #TODO: encoding! date = Time.now unless date parsed_date = "#{date.to_i} #{-1 * date.utc_offset}" if extra && ["default", "", nil].include?(extra["branch"]) extra.delete "branch" end if extra extra = (extra.any?) ? encode_extra(extra) : "" parsed_date = "#{parsed_date}#{extra}" end l = [manifest.hexlify, user, parsed_date] + files.sort + ["", desc] text = l.join "\n" add_revision text, journal, self.size, p1, p2 end |
#check_inline_size(journal, fp = nil) ⇒ Object
Does a check on our size, but knows enough to quit if we’re still in delayed-writing mode.
236 237 238 239 |
# File 'lib/amp/revlogs/changelog.rb', line 236 def check_inline_size(journal, fp=nil) return if @opener.is_a? DelayedOpener super(journal, fp) end |
#decode_extra(text) ⇒ Hash
Decodes the extra data stored with the commit, such as requirements or just about anything else we need to save
246 247 248 249 250 251 252 |
# File 'lib/amp/revlogs/changelog.rb', line 246 def decode_extra(text) extra = {} text.split("\0").select {|l| l.any? }. map {|l| l.remove_slashes.split(":",2) }. each {|k,v| extra[k]=v } extra end |
#delay_update ⇒ Object
Tells the changelog to stop writing updates directly to the file, and start saving any new info to memory/other files. Used when the changelog has to be the last file saved.
173 174 175 176 177 178 179 |
# File 'lib/amp/revlogs/changelog.rb', line 173 def delay_update @_real_opener = @opener @opener = DelayedOpener.new(@_real_opener, self) # Our fake Opener @delay_count = self.size @delay_buffer = [] @delay_name = nil end |
#encode_extra(data) ⇒ String
Encodes the extra data in a format we can use for writing.
258 259 260 |
# File 'lib/amp/revlogs/changelog.rb', line 258 def encode_extra(data) " " + data.sort.map {|k| "#{k}:#{data[k]}".add_slashes }.join("\0") end |
#finalize(journal) ⇒ Object
Finalizes the changelog by swapping out the fake file if it has to. If there’s any other data left in the buffer, it will be written as well.
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/amp/revlogs/changelog.rb', line 185 def finalize(journal) if @delay_name src = @_real_opener.join(@index_file+".a") dest = @_real_opener.join(@index_file) @opener = @_real_opener # switch back to normal mode.... return File.amp_force_rename(src, dest) end if @delay_buffer && @delay_buffer.any? @fp = open(@index_file, "a") @fp.write @delay_buffer.join @fp.close @delay_buffer = [] end # check_inline_size journal end |
#read(node) ⇒ [String, String, [Float, Integer], [String], String, Hash]
Text encodings, I hate you. but i must do them
Reads the revision at the given node_id. It returns it in a format that tells us everything about the revision - the manifest, the user who committed it, timestamps, the relevant filenames, the description message, and any extra data.
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/amp/revlogs/changelog.rb', line 273 def read(node) text = decompress_revision node if text.nil? || text.empty? return [NULL_ID, "", [0,0], [], "", {"branch" => "default"}] end #p text last = text.index("\n\n") desc = text[last+2..-1] #TODO: encoding l = text[0..last].split("\n") manifest = l[0].unhexlify user = l[1] #TODO: encoding extra_data = l[2].split(' ', 3) if extra_data.size != 3 time = extra_data.shift.to_f timezone = extra_data.shift.to_i extra = {} else time, timezone, extra = extra_data time, timezone = time.to_f, timezone.to_i extra = decode_extra text end extra["branch"] = "default" unless extra["branch"] files = l[3..-1] #puts(">> Ari's tipmost changeset: "+[manifest, user, [time, timezone], files, desc, extra].inspect) #killme [manifest, user, [time, timezone], files, desc, extra] end |
#read_pending(file) ⇒ Object
Reads while we’re blocking this changelog’s output.
205 206 207 208 209 210 |
# File 'lib/amp/revlogs/changelog.rb', line 205 def read_pending(file) r = Revlog.new(@opener, file) @index = r.index @node_map = r.index.node_map @chunk_cache = r.chunk_cache end |
#write_pending ⇒ Object
Writes our data, while being aware of the delay buffer when we’re holding off on finalizing the changelog.
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
# File 'lib/amp/revlogs/changelog.rb', line 215 def write_pending if @delay_buffer && @delay_buffer.size > 0 fp1 = @_real_opener.open(@index_file) fp2 = @_real_opener.open(@index_file + ".a", "w+") UI.debug "trying to open #{@index_file + ".a"}..." fp2.write fp1.read fp2.write @delay_buffer.join fp2.close fp1.close @delay_buffer = [] @delay_name = @index_file end return true if @delay_name && @delay_name.any? false end |