1 class Commit < ActiveRecord::Base
4 # Make sure the specified commit really exists, and return the full
7 # Accepts anything "git rev-list" accepts, optionally (and
8 # preferably) preceded by "repo_name:".
10 # Examples: "1234567", "master", "apps:1234567", "apps:master",
13 # def self.find_by_commit_ish(commit_ish)
14 # if only_valid_chars.match(commit_ish)
15 # logger.warn "find_by_commit_ish called with string containing invalid characters: '#{commit_ish}'"
20 # if commit_ish.index(':')
21 # want_repo, commit_ish = commit_ish.split(':',2)
23 # repositories.each do |repo_name, repo|
24 # next if want_repo and want_repo != repo_name
25 # ENV['GIT_DIR'] = repo[:git_dir]
26 # # we're passing user input to a command line, this is a potential a security hole but I am reasonably confident that shellescape sanitizes the input adequately
27 # IO.foreach("|git rev-list --max-count=1 --format=oneline 'origin/'#{commit_ish.shellescape} 2>/dev/null || git rev-list --max-count=1 --format=oneline ''#{commit_ish.shellescape}") do |line|
28 # sha1, message = line.strip.split " ", 2
29 # next if sha1.length != 40
31 # Commit.find_or_create_by_repository_name_and_sha1_and_message(repo_name, sha1, message[0..254])
33 # logger.warn "find_or_create failed: repo_name #{repo_name} sha1 #{sha1} message #{message[0..254]}"
34 # # Ignore cache failure. Commit is real. We should proceed.
42 def self.find_commit_range(current_user, repository, minimum, maximum, exclude)
43 only_valid_chars = /[^A-Za-z0-9_-]/
44 if only_valid_chars.match(minimum) || only_valid_chars.match(maximum)
45 logger.warn "find_commit_range called with string containing invalid characters: '#{minimum}', '#{maximum}'"
49 if minimum and minimum.empty?
57 # Get list of actual repository directories under management
58 on_disk_repos = repositories
60 # Get list of repository objects readable by user
61 readable = Repository.readable_by(current_user)
63 # filter repository objects on requested repository name
65 readable = readable.where(name: repository)
68 #puts "min #{minimum}"
69 #puts "max #{maximum}"
70 #puts "rep #{repository}"
74 if on_disk_repos[r.name]
75 ENV['GIT_DIR'] = on_disk_repos[r.name][:git_dir]
77 #puts "dir #{on_disk_repos[r.name][:git_dir]}"
79 # We've filtered for invalid characters, so we can pass the contents of
80 # minimum and maximum safely on the command line
82 #puts "git rev-list --max-count=1 #{maximum}"
84 # Get the commit hash for the upper bound
86 IO.foreach("|git rev-list --max-count=1 #{maximum}") do |line|
90 # If not found, nothing else to do
93 resolved_exclude = nil
97 IO.foreach("|git rev-list --max-count=1 #{e}") do |line|
98 resolved_exclude.push(line.strip)
104 # Get the commit hash for the lower bound
106 IO.foreach("|git rev-list --max-count=1 #{minimum}") do |line|
107 min_hash = line.strip
110 # If not found, nothing else to do
113 # Now find all commits between them
114 #puts "git rev-list #{min_hash}..#{max_hash}"
115 IO.foreach("|git rev-list #{min_hash}..#{max_hash}") do |line|
117 commits.push(hash) if !resolved_exclude or !resolved_exclude.include? hash
120 commits.push(min_hash) if !resolved_exclude or !resolved_exclude.include? min_hash
122 commits.push(max_hash) if !resolved_exclude or !resolved_exclude.include? max_hash
127 if !commits or commits.empty?
134 # Import all commits from configured git directory into the commits
138 repositories.each do |repo_name, repo|
139 stat = { true => 0, false => 0 }
140 ENV['GIT_DIR'] = repo[:git_dir]
141 IO.foreach("|git rev-list --format=oneline --all") do |line|
142 sha1, message = line.strip.split " ", 2
144 Commit.find_or_create_by_repository_name_and_sha1_and_message(repo_name, sha1, message[0..254]) do
147 stat[!!imported] += 1
148 if (stat[true] + stat[false]) % 100 == 0
149 if $stdout.tty? or ARGV[0] == '-v'
150 puts "#{$0} #{$$}: repo #{repo_name} add #{stat[true]} skip #{stat[false]}"
154 if $stdout.tty? or ARGV[0] == '-v'
155 puts "#{$0} #{$$}: repo #{repo_name} add #{stat[true]} skip #{stat[false]}"
160 def self.refresh_repositories
166 def self.repositories
167 return @repositories if @repositories
170 @gitdirbase = Rails.configuration.git_repositories_dir
171 Dir.foreach @gitdirbase do |repo|
172 next if repo.match /^\./
173 git_dir = File.join(@gitdirbase,
174 repo.match(/\.git$/) ? repo : File.join(repo, '.git'))
175 repo_name = repo.sub(/\.git$/, '')
176 @repositories[repo_name] = {git_dir: git_dir}