tree.rb 3.15 KB
Newer Older
1 2
# Gitaly note: JV: needs 1 RPC, migration is in progress.

Robert Speicher's avatar
Robert Speicher committed
3 4 5
module Gitlab
  module Git
    class Tree
6
      include Gitlab::EncodingHelper
Robert Speicher's avatar
Robert Speicher committed
7

8
      attr_accessor :id, :root_id, :name, :path, :flat_path, :type,
Robert Speicher's avatar
Robert Speicher committed
9 10 11 12 13 14
        :mode, :commit_id, :submodule_url

      class << self
        # Get list of tree objects
        # for repository based on commit sha and path
        # Uses rugged for raw objects
15 16
        #
        # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/320
Robert Speicher's avatar
Robert Speicher committed
17 18 19
        def where(repository, sha, path = nil)
          path = nil if path == '' || path == '/'

20 21
          Gitlab::GitalyClient.migrate(:tree_entries) do |is_enabled|
            if is_enabled
22
              repository.gitaly_commit_client.tree_entries(repository, sha, path)
23 24 25
            else
              tree_entries_from_rugged(repository, sha, path)
            end
Robert Speicher's avatar
Robert Speicher committed
26 27 28
          end
        end

29 30
        private

Robert Speicher's avatar
Robert Speicher committed
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
        # Recursive search of tree id for path
        #
        # Ex.
        #   blog/            # oid: 1a
        #     app/           # oid: 2a
        #       models/      # oid: 3a
        #       views/       # oid: 4a
        #
        #
        # Tree.find_id_by_path(repo, '1a', 'app/models') # => '3a'
        #
        def find_id_by_path(repository, root_id, path)
          root_tree = repository.lookup(root_id)
          path_arr = path.split('/')

          entry = root_tree.find do |entry|
            entry[:name] == path_arr[0] && entry[:type] == :tree
          end

          return nil unless entry

          if path_arr.size > 1
            path_arr.shift
            find_id_by_path(repository, entry[:oid], path_arr.join('/'))
          else
            entry[:oid]
          end
        end
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86

        def tree_entries_from_rugged(repository, sha, path)
          commit = repository.lookup(sha)
          root_tree = commit.tree

          tree = if path
                   id = find_id_by_path(repository, root_tree.oid, path)
                   if id
                     repository.lookup(id)
                   else
                     []
                   end
                 else
                   root_tree
                 end

          tree.map do |entry|
            new(
              id: entry[:oid],
              root_id: root_tree.oid,
              name: entry[:name],
              type: entry[:type],
              mode: entry[:filemode].to_s(8),
              path: path ? File.join(path, entry[:name]) : entry[:name],
              commit_id: sha
            )
          end
        end
Robert Speicher's avatar
Robert Speicher committed
87 88 89
      end

      def initialize(options)
90
        %w(id root_id name path flat_path type mode commit_id).each do |key|
91
          self.send("#{key}=", options[key.to_sym]) # rubocop:disable GitlabSecurity/PublicSend
Robert Speicher's avatar
Robert Speicher committed
92 93 94 95 96 97 98
        end
      end

      def name
        encode! @name
      end

99 100 101 102
      def path
        encode! @path
      end

103 104 105 106
      def flat_path
        encode! @flat_path
      end

Robert Speicher's avatar
Robert Speicher committed
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
      def dir?
        type == :tree
      end

      def file?
        type == :blob
      end

      def submodule?
        type == :commit
      end

      def readme?
        name =~ /^readme/i
      end

      def contributing?
        name =~ /^contributing/i
      end
    end
  end
end