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

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

Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
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

27
        clear_working_dir!
28
        delete_heads!
29
        update_from_source!
30 31 32
      end

      def create
33
        output, status = popen("git clone #{project.repository.path_to_repo} #{path}",
34 35
                               Gitlab.config.satellites.path)

36
        log("PID: #{project.id}: git clone #{project.repository.path_to_repo} #{path}")
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
37 38
        log("PID: #{project.id}: -> #{output}")

39
        if status.zero?
40 41
          true
        else
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
42
          log("Failed to create satellite for #{project.name_with_namespace}")
43 44
          false
        end
45 46 47 48 49 50
      end

      def exists?
        File.exists? path
      end

Riyad Preukschas's avatar
Riyad Preukschas committed
51 52 53
      # * Locks the satellite
      # * Changes the current directory to the satellite's working dir
      # * Yields
54
      def lock
55
        raise_no_satellite unless exists?
56 57 58 59

        File.open(lock_file, "w+") do |f|
          f.flock(File::LOCK_EX)

Riyad Preukschas's avatar
Riyad Preukschas committed
60 61 62
          Dir.chdir(path) do
            return yield
          end
63 64 65 66
        end
      end

      def lock_file
67 68
        create_locks_dir unless File.exists?(lock_files_dir)
        File.join(lock_files_dir, "satellite_#{project.id}.lock")
69 70
      end

71
      def path
72
        File.join(Gitlab.config.satellites.path, project.path_with_namespace)
73
      end
74

75
      def repo
76
        raise_no_satellite unless exists?
77 78 79

        @repo ||= Grit::Repo.new(path)
      end
80 81 82 83

      def destroy
        FileUtils.rm_rf(path)
      end
84

85 86 87 88 89 90 91 92 93 94 95 96
      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!
97
        heads = repo.heads.map(&:name)
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115

        # update or create the parking branch
        if heads.include? PARKING_BRANCH
          repo.git.checkout({}, PARKING_BRANCH)
        else
          repo.git.checkout({b: true}, PARKING_BRANCH)
        end

        # remove the parking branch from the list of heads ...
        heads.delete(PARKING_BRANCH)
        # ... and delete all others
        heads.each { |head| repo.git.branch({D: true}, head) }
      end

      # Updates the satellite from Gitolite
      #
      # Note: this will only update remote branches (i.e. origin/*)
      def update_from_source!
116
        repo.git.fetch({timeout: true}, :origin)
117
      end
118

Johannes Schleifenbaum's avatar
Johannes Schleifenbaum committed
119
      # Create directory for storing
120 121 122 123 124 125 126 127
      # 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
128 129 130
    end
  end
end