1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
module Gitlab
module Git
class Checksum
include Gitlab::Git::Popen
EMPTY_REPOSITORY_CHECKSUM = '0000000000000000000000000000000000000000'.freeze
Failure = Class.new(StandardError)
attr_reader :path, :relative_path, :storage, :storage_path
def initialize(storage, relative_path)
@storage = storage
@storage_path = Gitlab.config.repositories.storages[storage].legacy_disk_path
@relative_path = "#{relative_path}.git"
@path = File.join(storage_path, @relative_path)
end
def calculate
unless repository_exists?
failure!(Gitlab::Git::Repository::NoRepository, 'No repository for such path')
end
calculate_checksum_by_shelling_out
end
private
def repository_exists?
raw_repository.exists?
end
def calculate_checksum_by_shelling_out
args = %W(--git-dir=#{path} show-ref --heads --tags)
output, status = run_git(args)
if status&.zero?
refs = output.split("\n")
result = refs.inject(nil) do |checksum, ref|
value = Digest::SHA1.hexdigest(ref).hex
if checksum.nil?
value
else
checksum ^ value
end
end
result.to_s(16)
else
# Empty repositories return with a non-zero status and an empty output.
if output&.empty?
EMPTY_REPOSITORY_CHECKSUM
else
failure!(Gitlab::Git::Checksum::Failure, output)
end
end
end
def failure!(klass, message)
Gitlab::GitLogger.error("'git show-ref --heads --tags' in #{path}: #{message}")
raise klass.new("Could not calculate the checksum for #{path}: #{message}")
end
def circuit_breaker
@circuit_breaker ||= Gitlab::Git::Storage::CircuitBreaker.for_storage(storage)
end
def raw_repository
Gitlab::Git::Repository.new(storage, relative_path, nil)
end
def run_git(args)
circuit_breaker.perform do
popen([Gitlab.config.git.bin_path, *args], path)
end
end
end
end
end
|