satellite.rb 3.7 KB
Newer Older
1
module Gitlab
2
  class SatelliteNotExistError < StandardError;  end
3

4 5
  module Satellite
    class Satellite
6 7
      include Gitlab::Popen

8 9 10 11 12 13 14 15
      PARKING_BRANCH = "__parking_branch"

      attr_accessor :project

      def initialize(project)
        @project = project
      end

D
Dmitriy Zaporozhets 已提交
16 17 18 19
      def log message
        Gitlab::Satellite::Logger.error(message)
      end

20 21 22 23
      def raise_no_satellite
        raise SatelliteNotExistError.new("Satellite doesn't exist")
      end

24
      def clear_and_update!
25
        raise_no_satellite unless exists?
26

I
Izaak Alpert 已提交
27 28
        File.exists? path
        @repo = nil
29
        clear_working_dir!
M
murank 已提交
30
        delete_heads!
I
Izaak Alpert 已提交
31
        remove_remotes!
32
        update_from_source!
33 34 35
      end

      def create
36
        output, status = popen(%W(git clone -- #{project.repository.path_to_repo} #{path}),
37 38
                               Gitlab.config.satellites.path)

39
        log("PID: #{project.id}: git clone #{project.repository.path_to_repo} #{path}")
D
Dmitriy Zaporozhets 已提交
40 41
        log("PID: #{project.id}: -> #{output}")

42
        if status.zero?
43 44
          true
        else
D
Dmitriy Zaporozhets 已提交
45
          log("Failed to create satellite for #{project.name_with_namespace}")
46 47
          false
        end
48 49 50 51 52 53
      end

      def exists?
        File.exists? path
      end

R
Riyad Preukschas 已提交
54 55 56
      # * Locks the satellite
      # * Changes the current directory to the satellite's working dir
      # * Yields
57
      def lock
58
        raise_no_satellite unless exists?
59 60

        File.open(lock_file, "w+") do |f|
I
Izaak Alpert 已提交
61 62 63 64 65
          begin
            f.flock File::LOCK_EX
            Dir.chdir(path) { return yield }
          ensure
            f.flock File::LOCK_UN
R
Riyad Preukschas 已提交
66
          end
67 68 69 70
        end
      end

      def lock_file
71 72
        create_locks_dir unless File.exists?(lock_files_dir)
        File.join(lock_files_dir, "satellite_#{project.id}.lock")
73 74
      end

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 83

        @repo ||= Grit::Repo.new(path)
      end
84 85 86 87

      def destroy
        FileUtils.rm_rf(path)
      end
88

89 90 91 92 93 94 95 96 97 98 99 100
      private

      # Clear the working directory
      def clear_working_dir!
        repo.git.reset(hard: true)
      end

      # Deletes all branches except the parking branch
      #
      # This ensures we have no name clashes or issues updating branches when
      # working with the satellite.
      def delete_heads!
101
        heads = repo.heads.map(&:name)
102 103 104 105 106

        # update or create the parking branch
        if heads.include? PARKING_BRANCH
          repo.git.checkout({}, PARKING_BRANCH)
        else
I
Izaak Alpert 已提交
107
          repo.git.checkout(default_options({b: true}), PARKING_BRANCH)
108 109 110 111 112
        end

        # remove the parking branch from the list of heads ...
        heads.delete(PARKING_BRANCH)
        # ... and delete all others
I
Izaak Alpert 已提交
113 114 115 116 117 118 119 120 121 122 123
        heads.each { |head| repo.git.branch(default_options({D: true}), head) }
      end

      # Deletes all remotes except origin
      #
      # This ensures we have no remote name clashes or issues updating branches when
      # working with the satellite.
      def remove_remotes!
        remotes = repo.git.remote.split(' ')
        remotes.delete('origin')
        remotes.each { |name| repo.git.remote(default_options,'rm', name)}
124 125
      end

D
Dmitriy Zaporozhets 已提交
126
      # Updates the satellite from bare repo
127 128 129
      #
      # Note: this will only update remote branches (i.e. origin/*)
      def update_from_source!
I
Izaak Alpert 已提交
130 131 132 133 134
        repo.git.fetch(default_options, :origin)
      end

      def default_options(options = {})
        {raise: true, timeout: true}.merge(options)
135
      end
136

J
Johannes Schleifenbaum 已提交
137
      # Create directory for storing
138 139 140 141 142 143 144 145
      # satellites lock files
      def create_locks_dir
        FileUtils.mkdir_p(lock_files_dir)
      end

      def lock_files_dir
        @lock_files_dir ||= File.join(Gitlab.config.satellites.path, "tmp")
      end
146 147 148
    end
  end
end