BigW Consortium Gitlab

satellite.rb 3.98 KB
Newer Older
1 2
module Gitlab
  module Satellite
3 4 5 6 7
    autoload :DeleteFileAction, 'gitlab/satellite/files/delete_file_action'
    autoload :EditFileAction,   'gitlab/satellite/files/edit_file_action'
    autoload :FileAction,       'gitlab/satellite/files/file_action'
    autoload :NewFileAction,    'gitlab/satellite/files/new_file_action'

8 9 10 11
    class CheckoutFailed < StandardError; end
    class CommitFailed < StandardError; end
    class PushFailed < StandardError; end

12
    class Satellite
13 14
      include Gitlab::Popen

15 16 17 18 19 20 21 22
      PARKING_BRANCH = "__parking_branch"

      attr_accessor :project

      def initialize(project)
        @project = project
      end

23
      def log(message)
Dmitriy Zaporozhets committed
24 25 26
        Gitlab::Satellite::Logger.error(message)
      end

27
      def clear_and_update!
28
        project.ensure_satellite_exists
29

30
        @repo = nil
31
        clear_working_dir!
32
        delete_heads!
33
        remove_remotes!
34
        update_from_source!
35 36 37
      end

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

41
        log("PID: #{project.id}: git clone #{project.repository.path_to_repo} #{path}")
Dmitriy Zaporozhets committed
42 43
        log("PID: #{project.id}: -> #{output}")

44
        if status.zero?
45 46
          true
        else
Dmitriy Zaporozhets committed
47
          log("Failed to create satellite for #{project.name_with_namespace}")
48 49
          false
        end
50 51 52 53 54 55
      end

      def exists?
        File.exists? path
      end

Riyad Preukschas committed
56 57 58
      # * Locks the satellite
      # * Changes the current directory to the satellite's working dir
      # * Yields
59
      def lock
60
        project.ensure_satellite_exists
61 62

        File.open(lock_file, "w+") do |f|
63 64
          begin
            f.flock File::LOCK_EX
65
            yield
66 67
          ensure
            f.flock File::LOCK_UN
Riyad Preukschas committed
68
          end
69 70 71 72
        end
      end

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

77
      def path
78
        File.join(Gitlab.config.satellites.path, project.path_with_namespace)
79
      end
80

81
      def repo
82
        project.ensure_satellite_exists
83 84 85

        @repo ||= Grit::Repo.new(path)
      end
86 87 88 89

      def destroy
        FileUtils.rm_rf(path)
      end
90

91 92 93 94 95
      private

      # Clear the working directory
      def clear_working_dir!
        repo.git.reset(hard: true)
96
        repo.git.clean(f: true, d: true, x: true)
97 98 99 100 101 102 103
      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!
104
        heads = repo.heads.map(&:name)
105 106

        # update or create the parking branch
107
        repo.git.checkout(default_options({ B: true }), PARKING_BRANCH)
108 109 110 111

        # remove the parking branch from the list of heads ...
        heads.delete(PARKING_BRANCH)
        # ... and delete all others
112
        heads.each { |head| repo.git.branch(default_options({ D: true }), head) }
113 114 115 116 117 118 119 120 121 122
      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)}
123 124
      end

125
      # Updates the satellite from bare repo
126 127 128
      #
      # Note: this will only update remote branches (i.e. origin/*)
      def update_from_source!
129
        repo.git.remote(default_options, 'set-url', :origin, project.repository.path_to_repo)
130 131 132 133
        repo.git.fetch(default_options, :origin)
      end

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

Johannes Schleifenbaum committed
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