Fixed tests
[arvados.git] / services / api / app / models / commit.rb
1 class Commit < ActiveRecord::Base
2   require 'shellwords'
3
4   def self.find_commit_range(current_user, repository, minimum, maximum, exclude)
5     # disallow starting with '-' so verision strings can't be interpreted as command line options
6     valid_pattern = /[A-Za-z0-9_][A-Za-z0-9_-]/
7     if (minimum and !minimum.match valid_pattern) || !maximum.match valid_pattern
8       logger.warn "find_commit_range called with string containing invalid characters: '#{minimum}', '#{maximum}'"
9       return nil
10     end
11
12     if minimum and minimum.empty?
13         minimum = nil
14     end
15     
16     if !maximum
17       maximum = "HEAD"
18     end
19
20     # Get list of actual repository directories under management
21     on_disk_repos = repositories
22
23     # Get list of repository objects readable by user
24     readable = Repository.readable_by(current_user)
25
26     # filter repository objects on requested repository name
27     if repository
28       readable = readable.where(name: repository)
29     end
30
31     #puts "min #{minimum}"
32     #puts "max #{maximum}"
33     #puts "rep #{repository}"
34
35     commits = []
36     readable.each do |r|
37       if on_disk_repos[r.name]
38         ENV['GIT_DIR'] = on_disk_repos[r.name][:git_dir]
39
40         #puts "dir #{on_disk_repos[r.name][:git_dir]}"
41
42         # We've filtered for invalid characters, so we can pass the contents of
43         # minimum and maximum safely on the command line
44
45         #puts "git rev-list --max-count=1 #{maximum}"
46
47         # Get the commit hash for the upper bound
48         max_hash = nil
49         IO.foreach("|git rev-list --max-count=1 #{maximum}") do |line|
50           max_hash = line.strip
51         end
52
53         # If not found or string is invalid, nothing else to do
54         next if !max_hash or !max_hash.match valid_pattern
55
56         resolved_exclude = nil
57         if exclude
58           resolved_exclude = []
59           exclude.each do |e|
60             if e.match valid_pattern
61               IO.foreach("|git rev-list --max-count=1 #{e}") do |line|
62                 resolved_exclude.push(line.strip)
63               end
64             end
65           end
66         end
67
68         if minimum          
69           # Get the commit hash for the lower bound
70           min_hash = nil
71           IO.foreach("|git rev-list --max-count=1 #{minimum}") do |line|
72             min_hash = line.strip
73           end
74
75           # If not found or string is invalid, nothing else to do
76           next if !min_hash or !min_hash.match valid_pattern
77           
78           # Now find all commits between them
79           #puts "git rev-list #{min_hash}..#{max_hash}"
80           IO.foreach("|git rev-list #{min_hash}..#{max_hash}") do |line|
81             hash = line.strip
82             commits.push(hash) if !resolved_exclude or !resolved_exclude.include? hash              
83           end
84
85           commits.push(min_hash) if !resolved_exclude or !resolved_exclude.include? min_hash
86         else
87           commits.push(max_hash) if !resolved_exclude or !resolved_exclude.include? max_hash
88         end
89       end
90     end
91
92     if !commits or commits.empty?
93       nil
94     else
95       commits
96     end
97   end
98
99   # Import all commits from configured git directory into the commits
100   # database.
101
102   def self.import_all
103     repositories.each do |repo_name, repo|
104       stat = { true => 0, false => 0 }
105       ENV['GIT_DIR'] = repo[:git_dir]
106       IO.foreach("|git rev-list --format=oneline --all") do |line|
107         sha1, message = line.strip.split " ", 2
108         imported = false
109         Commit.find_or_create_by_repository_name_and_sha1_and_message(repo_name, sha1, message[0..254]) do
110           imported = true
111         end
112         stat[!!imported] += 1
113         if (stat[true] + stat[false]) % 100 == 0
114           if $stdout.tty? or ARGV[0] == '-v'
115             puts "#{$0} #{$$}: repo #{repo_name} add #{stat[true]} skip #{stat[false]}"
116           end
117         end
118       end
119       if $stdout.tty? or ARGV[0] == '-v'
120         puts "#{$0} #{$$}: repo #{repo_name} add #{stat[true]} skip #{stat[false]}"
121       end
122     end
123   end
124
125   def self.refresh_repositories
126     @repositories = nil
127   end
128
129   protected
130
131   def self.repositories
132     return @repositories if @repositories
133
134     @repositories = {}
135     @gitdirbase = Rails.configuration.git_repositories_dir
136     Dir.foreach @gitdirbase do |repo|
137       next if repo.match /^\./
138       git_dir = File.join(@gitdirbase,
139                           repo.match(/\.git$/) ? repo : File.join(repo, '.git'))
140       repo_name = repo.sub(/\.git$/, '')
141       @repositories[repo_name] = {git_dir: git_dir}
142     end
143
144     @repositories
145   end
146 end