Welcome to mirror list, hosted at ThFree Co, Russian Federation.

tree_restorer.rb « group « import_export « gitlab « lib - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: d0c0999f29167d0449f37ae8a00206df578562bb (plain)
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
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# frozen_string_literal: true

module Gitlab
  module ImportExport
    module Group
      class TreeRestorer
        include Gitlab::Utils::StrongMemoize

        attr_reader :user, :shared

        def initialize(user:, shared:, group:)
          @user = user
          @shared = shared
          @top_level_group = group
          @groups_mapping = {}
        end

        def restore
          group_ids = relation_reader.consume_relation('groups', '_all').map { |value, _idx| Integer(value) }
          root_group_id = group_ids.delete_at(0)

          process_root(root_group_id)

          group_ids.each do |group_id|
            process_child(group_id)
          end

          true
        rescue => e
          shared.error(e)
          false
        end

        class GroupAttributes
          attr_reader :attributes, :group_id, :id, :path

          def initialize(group_id, relation_reader)
            @group_id = group_id

            @path = "groups/#{group_id}"
            @attributes = relation_reader.consume_attributes(@path)
            @id = @attributes.delete('id')

            unless @id == @group_id
              raise ArgumentError, "Invalid group_id for #{group_id}"
            end
          end

          def delete_attribute(name)
            attributes.delete(name)
          end

          def delete_attributes(*names)
            names.map(&method(:delete_attribute))
          end
        end
        private_constant :GroupAttributes

        private

        def process_root(group_id)
          group_attributes = GroupAttributes.new(group_id, relation_reader)

          # name and path are not imported on the root group to avoid conflict
          # with existing groups name and/or path.
          group_attributes.delete_attributes('name', 'path')

          restore_group(@top_level_group, group_attributes)
        end

        def process_child(group_id)
          group_attributes = GroupAttributes.new(group_id, relation_reader)

          group = create_group(group_attributes)

          restore_group(group, group_attributes)
        end

        def create_group(group_attributes)
          parent_id = group_attributes.delete_attribute('parent_id')
          name = group_attributes.delete_attribute('name')
          path = group_attributes.delete_attribute('path')

          parent_group = @groups_mapping.fetch(parent_id) { raise(ArgumentError, 'Parent group not found') }

          ::Groups::CreateService.new(
            user,
            name: name,
            path: path,
            parent_id: parent_group.id,
            visibility_level: sub_group_visibility_level(group_attributes.attributes, parent_group)
          ).execute
        end

        def restore_group(group, group_attributes)
          @groups_mapping[group_attributes.id] = group

          Group::GroupRestorer.new(
            user: user,
            shared: shared,
            group: group,
            attributes: group_attributes.attributes,
            importable_path: group_attributes.path,
            relation_reader: relation_reader,
            reader: reader
          ).restore
        end

        def relation_reader
          strong_memoize(:relation_reader) do
            ImportExport::JSON::NdjsonReader.new(
              File.join(shared.export_path, 'tree')
            )
          end
        end

        def sub_group_visibility_level(group_hash, parent_group)
          original_visibility_level = group_hash['visibility_level'] || Gitlab::VisibilityLevel::PRIVATE

          if parent_group && parent_group.visibility_level < original_visibility_level
            Gitlab::VisibilityLevel.closest_allowed_level(parent_group.visibility_level)
          else
            original_visibility_level
          end
        end

        def reader
          strong_memoize(:reader) do
            Gitlab::ImportExport::Reader.new(
              shared: @shared,
              config: Gitlab::ImportExport::Config.new(
                config: Gitlab::ImportExport.group_config_file
              ).to_h
            )
          end
        end
      end
    end
  end
end