OSDN Git Service

diff view on commit with parallel diff view
[wvm/gitlab.git] / lib / gitlab / satellite / satellite.rb
1 module Gitlab
2   class SatelliteNotExistError < StandardError;  end
3
4   module Satellite
5     class Satellite
6       include Gitlab::Popen
7
8       PARKING_BRANCH = "__parking_branch"
9
10       attr_accessor :project
11
12       def initialize(project)
13         @project = project
14       end
15
16       def log message
17         Gitlab::Satellite::Logger.error(message)
18       end
19
20       def raise_no_satellite
21         raise SatelliteNotExistError.new("Satellite doesn't exist")
22       end
23
24       def clear_and_update!
25         raise_no_satellite unless exists?
26
27         File.exists? path
28         @repo = nil
29         clear_working_dir!
30         delete_heads!
31         remove_remotes!
32         update_from_source!
33       end
34
35       def create
36         output, status = popen("git clone #{project.repository.path_to_repo} #{path}",
37                                Gitlab.config.satellites.path)
38
39         log("PID: #{project.id}: git clone #{project.repository.path_to_repo} #{path}")
40         log("PID: #{project.id}: -> #{output}")
41
42         if status.zero?
43           true
44         else
45           log("Failed to create satellite for #{project.name_with_namespace}")
46           false
47         end
48       end
49
50       def exists?
51         File.exists? path
52       end
53
54       # * Locks the satellite
55       # * Changes the current directory to the satellite's working dir
56       # * Yields
57       def lock
58         raise_no_satellite unless exists?
59
60         File.open(lock_file, "w+") do |f|
61           begin
62             f.flock File::LOCK_EX
63             Dir.chdir(path) { return yield }
64           ensure
65             f.flock File::LOCK_UN
66           end
67         end
68       end
69
70       def lock_file
71         create_locks_dir unless File.exists?(lock_files_dir)
72         File.join(lock_files_dir, "satellite_#{project.id}.lock")
73       end
74
75       def path
76         File.join(Gitlab.config.satellites.path, project.path_with_namespace)
77       end
78
79       def repo
80         raise_no_satellite unless exists?
81
82         @repo ||= Grit::Repo.new(path)
83       end
84
85       def destroy
86         FileUtils.rm_rf(path)
87       end
88
89       private
90
91       # Clear the working directory
92       def clear_working_dir!
93         repo.git.reset(hard: true)
94       end
95
96       # Deletes all branches except the parking branch
97       #
98       # This ensures we have no name clashes or issues updating branches when
99       # working with the satellite.
100       def delete_heads!
101         heads = repo.heads.map(&:name)
102
103         # update or create the parking branch
104         if heads.include? PARKING_BRANCH
105           repo.git.checkout({}, PARKING_BRANCH)
106         else
107           repo.git.checkout(default_options({b: true}), PARKING_BRANCH)
108         end
109
110         # remove the parking branch from the list of heads ...
111         heads.delete(PARKING_BRANCH)
112         # ... and delete all others
113         heads.each { |head| repo.git.branch(default_options({D: true}), head) }
114       end
115
116       # Deletes all remotes except origin
117       #
118       # This ensures we have no remote name clashes or issues updating branches when
119       # working with the satellite.
120       def remove_remotes!
121         remotes = repo.git.remote.split(' ')
122         remotes.delete('origin')
123         remotes.each { |name| repo.git.remote(default_options,'rm', name)}
124       end
125
126       # Updates the satellite from Gitolite
127       #
128       # Note: this will only update remote branches (i.e. origin/*)
129       def update_from_source!
130         repo.git.fetch(default_options, :origin)
131       end
132
133       def default_options(options = {})
134         {raise: true, timeout: true}.merge(options)
135       end
136
137       # Create directory for storing
138       # satellites lock files
139       def create_locks_dir
140         FileUtils.mkdir_p(lock_files_dir)
141       end
142
143       def lock_files_dir
144         @lock_files_dir ||= File.join(Gitlab.config.satellites.path, "tmp")
145       end
146     end
147   end
148 end