class Mercurial::FileIndex
This class was ported from grit.
It implements a file-based 'file index', a simple index of all of the reachable commits in a repo, along with the parents and which files were modified during each commit.
This class creates and reads a file named '[.hg]/file-index'.
Attributes
Public Class Methods
initializes index given repository
# File lib/mercurial-ruby/file_index.rb, line 28 def initialize(repository) @repository = repository end
Public Instance Methods
returns all commits for a file
# File lib/mercurial-ruby/file_index.rb, line 97 def commits_for(file) read_if_needed @all_files[file] || [] end
builds a list of all commits reachable from a single commit
# File lib/mercurial-ruby/file_index.rb, line 63 def commits_from(commit_sha) raise UnsupportedRef if commit_sha.is_a? Array read_if_needed already = {} final = [] left_to_do = [commit_sha] while commit_sha = left_to_do.shift next if already[commit_sha] final << commit_sha already[commit_sha] = true commit = @commit_index[commit_sha] commit[:parents].each do |sha| left_to_do << sha end if commit end sort_commits(final) end
returns count of all commits reachable from SHA note: originally did this recursively, but ruby gets pissed about that on really big repos where the stack level gets 'too deep' (thats what she said)
# File lib/mercurial-ruby/file_index.rb, line 57 def count(commit_sha) read_if_needed commits_from(commit_sha).size end
returns count of all commits
# File lib/mercurial-ruby/file_index.rb, line 49 def count_all read_if_needed @sha_count end
# File lib/mercurial-ruby/file_index.rb, line 131 def destroy! FileUtils.rm_f(path) end
returns files changed at commit sha
# File lib/mercurial-ruby/file_index.rb, line 87 def files(commit_sha) read_if_needed if commit = @commit_index[commit_sha] commit[:files] else [] end end
returns the shas of the last commits for all the files in [] from commit_sha files_matcher can be a regexp or an array
# File lib/mercurial-ruby/file_index.rb, line 105 def last_commits(commit_sha, files_matcher) read_if_needed acceptable = commits_from(commit_sha) matches = {} if files_matcher.is_a? Regexp files = @all_files.keys.select { |file| file =~ files_matcher } files_matcher = files end if files_matcher.is_a? Array # find the last commit for each file in the array files_matcher.each do |f| @all_files[f].each do |try| if acceptable.include?(try) matches[f] = try break end end if @all_files[f] end end matches end
# File lib/mercurial-ruby/file_index.rb, line 135 def path File.join(repository.dothg_path, 'file-index') end
# File lib/mercurial-ruby/file_index.rb, line 32 def reload @_read_complete = false end
updates file index
# File lib/mercurial-ruby/file_index.rb, line 37 def update(oldrev=nil, newrev=nil) if index_file_exists? && oldrev != "0"*40 hg([ "log --debug -r ?:? --style ? >> ?", oldrev, newrev, Style.file_index, path ]) else hg(["log --debug -r : --style ? > ?", Style.file_index, path]) end end
Private Instance Methods
# File lib/mercurial-ruby/file_index.rb, line 141 def index_file_exists? FileTest.exists?(path) end
# File lib/mercurial-ruby/file_index.rb, line 145 def index_file_valid? File.file?(path) && (File.size(path) < Mercurial::FileIndex.max_file_size) end
# File lib/mercurial-ruby/file_index.rb, line 154 def read_if_needed if @_read_complete true else begin read_index rescue IndexFileNotFound => e if @_tried_updating raise e else @_tried_updating = true update retry end end end end
# File lib/mercurial-ruby/file_index.rb, line 182 def read_index validate_index_file f = File.new(path, 'rb') @sha_count = 0 @commit_index = {} @commit_order = {} @all_files = {} while line = f.gets if /^(\w{40})/.match(line) shas = line.scan(/(\w{40})/) current_sha = shas.shift.first parents = shas.map { |sha| sha.first } parents = parents.delete_if { |sha| sha == '0'*40 } @commit_index[current_sha] = {:files => [], :parents => parents } @commit_order[current_sha] = @sha_count @sha_count += 1 else file_name = line.chomp unless file_name.empty? tree = '' File.dirname(file_name).split('/').each do |part| next if part == '.' tree += part + '/' @all_files[tree] ||= [] @all_files[tree].unshift(current_sha) end @all_files[file_name] ||= [] @all_files[file_name].unshift(current_sha) @commit_index[current_sha][:files] << file_name end end end @_read_complete = true end
# File lib/mercurial-ruby/file_index.rb, line 149 def sort_commits(sha_array) read_if_needed sha_array.sort { |a, b| @commit_order[b].to_i <=> @commit_order[a].to_i } end
# File lib/mercurial-ruby/file_index.rb, line 172 def validate_index_file if File.file?(path) if File.size(path) > Mercurial::FileIndex.max_file_size raise IndexFileTooBig, "#{ path } is bigger than #{ Mercurial::FileIndex.max_file_size }" end else raise IndexFileNotFound, path unless index_file_valid? end end