path_locks_finder.rb 1.36 KB
Newer Older
Valery Sizov's avatar
Valery Sizov committed
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
# The database stores locked paths as following:
# 'app/models/project.rb' or 'lib/gitlab'
# To determine that 'lib/gitlab/some_class.rb' is locked we need to generate
# tokens for every requested paths and check every token whether it exist in path locks table or not.
# So for 'lib/gitlab/some_class.rb' path we would need to search next paths:
# 'lib', 'lib/gitlab' and 'lib/gitlab/some_class.rb'
# This class also implements a memoization for common paths like 'lib' 'lib/gitlab', 'app', etc.

class Gitlab::PathLocksFinder
  def initialize(project)
    @project = project
    @non_locked_paths = []
  end

  def get_lock_info(path, exact_match: false)
    if exact_match
      return find_lock(path)
    else
      tokenize(path).each do |token|
        if lock = find_lock(token)
          return lock
        end
      end

      false
    end
  end

  private

  # This returns hierarchy tokens for path
  # app/models/project.rb => ['app', 'app/models', 'app/models/project.rb']
  def tokenize(path)
    segments = path.split("/")

    tokens = []
    begin
      tokens << segments.join("/")
      segments.pop
    end until segments.empty?

    tokens
  end

  def find_lock(token)
    if @non_locked_paths.include?(token)
      return false
    end

    lock = @project.path_locks.find_by(path: token)

    unless lock
      @non_locked_paths << token
    end

    lock
  end
end