moved api server code into new directory structure
[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         begin
47           imported = Commit.new(repository_name: repo_name,
48                                 sha1: sha1,
49                                 message: message[0..254]).save
50         rescue ActiveRecord::RecordNotUnique
51         end
52         stat[!!imported] += 1
53         if (stat[true] + stat[false]) % 100 == 0
54           if $stdout.tty? or ARGV[0] == '-v'
55             puts "#{$0} #{$$}: repo #{repo_name} add #{stat[true]} skip #{stat[false]}"
56           end
57         end
58       end
59       if $stdout.tty? or ARGV[0] == '-v'
60         puts "#{$0} #{$$}: repo #{repo_name} add #{stat[true]} skip #{stat[false]}"
61       end
62     end
63   end
64
65   protected
66
67   def self.repositories
68     return @repositories if @repositories
69
70     @repositories = {}
71     @gitdirbase = Rails.configuration.git_repositories_dir
72     Dir.foreach @gitdirbase do |repo|
73       next if repo.match /^\./
74       git_dir = File.join(@gitdirbase,
75                           repo.match(/\.git$/) ? repo : File.join(repo, '.git'))
76       repo_name = repo.sub(/\.git$/, '')
77       @repositories[repo_name] = {git_dir: git_dir}
78     end
79
80     @repositories
81   end
82 end