Merge remote-tracking branch 'origin/master' into 1977-provenance-report
[arvados.git] / services / api / app / models / commit.rb
1 class Commit < ActiveRecord::Base
2   require 'shellwords'
3
4   # Make sure the specified commit really exists, and return the full
5   # sha1 commit hash.
6   #
7   # Accepts anything "git rev-list" accepts, optionally (and
8   # preferably) preceded by "repo_name:".
9   #
10   # Examples: "1234567", "master", "apps:1234567", "apps:master",
11   # "apps:HEAD"
12
13   def self.find_by_commit_ish(commit_ish)
14     want_repo = nil
15     if commit_ish.index(':')
16       want_repo, commit_ish = commit_ish.split(':',2)
17     end
18     repositories.each do |repo_name, repo|
19       next if want_repo and want_repo != repo_name
20       ENV['GIT_DIR'] = repo[:git_dir]
21       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|
22         sha1, message = line.strip.split " ", 2
23         next if sha1.length != 40
24         begin
25           Commit.find_or_create_by_repository_name_and_sha1_and_message(repo_name, sha1, message[0..254])
26         rescue
27           logger.warn "find_or_create failed: repo_name #{repo_name} sha1 #{sha1} message #{message[0..254]}"
28           # Ignore cache failure. Commit is real. We should proceed.
29         end
30         return sha1
31       end
32     end
33     nil
34   end
35
36   # Import all commits from configured git directory into the commits
37   # database.
38
39   def self.import_all
40     repositories.each do |repo_name, repo|
41       stat = { true => 0, false => 0 }
42       ENV['GIT_DIR'] = repo[:git_dir]
43       IO.foreach("|git rev-list --format=oneline --all") do |line|
44         sha1, message = line.strip.split " ", 2
45         imported = false
46         Commit.find_or_create_by_repository_name_and_sha1_and_message(repo_name, sha1, message[0..254]) do
47           imported = true
48         end
49         stat[!!imported] += 1
50         if (stat[true] + stat[false]) % 100 == 0
51           if $stdout.tty? or ARGV[0] == '-v'
52             puts "#{$0} #{$$}: repo #{repo_name} add #{stat[true]} skip #{stat[false]}"
53           end
54         end
55       end
56       if $stdout.tty? or ARGV[0] == '-v'
57         puts "#{$0} #{$$}: repo #{repo_name} add #{stat[true]} skip #{stat[false]}"
58       end
59     end
60   end
61
62   protected
63
64   def self.repositories
65     return @repositories if @repositories
66
67     @repositories = {}
68     @gitdirbase = Rails.configuration.git_repositories_dir
69     Dir.foreach @gitdirbase do |repo|
70       next if repo.match /^\./
71       git_dir = File.join(@gitdirbase,
72                           repo.match(/\.git$/) ? repo : File.join(repo, '.git'))
73       repo_name = repo.sub(/\.git$/, '')
74       @repositories[repo_name] = {git_dir: git_dir}
75     end
76
77     @repositories
78   end
79 end