summaryrefslogtreecommitdiff
path: root/lib/gitlab/import_export/json/legacy_writer.rb
blob: 7be21410d2611b24978b1c5be152f7e58c593e08 (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
# frozen_string_literal: true

module Gitlab
  module ImportExport
    module JSON
      class LegacyWriter
        include Gitlab::ImportExport::CommandLineUtil

        attr_reader :path

        def initialize(path, allowed_path:)
          @path = path
          @keys = Set.new

          # This is legacy writer, to be used in transition
          # period before `.ndjson`,
          # we strong validate what is being written
          @allowed_path = allowed_path

          mkdir_p(File.dirname(@path))
          file.write('{}')
        end

        def close
          @file&.close
          @file = nil
        end

        def write_attributes(exportable_path, hash)
          unless exportable_path == @allowed_path
            raise ArgumentError, "Invalid #{exportable_path}"
          end

          hash.each do |key, value|
            write(key, value)
          end
        end

        def write_relation(exportable_path, key, value)
          unless exportable_path == @allowed_path
            raise ArgumentError, "Invalid #{exportable_path}"
          end

          write(key, value)
        end

        def write_relation_array(exportable_path, key, items)
          unless exportable_path == @allowed_path
            raise ArgumentError, "Invalid #{exportable_path}"
          end

          write(key, [])

          # rewind by two bytes, to overwrite ']}'
          file.pos = file.size - 2

          items.each_with_index do |item, idx|
            file.write(',') if idx > 0
            file.write(item.to_json)
          end

          file.write(']}')
        end

        private

        def write(key, value)
          raise ArgumentError, "key '#{key}' already written" if @keys.include?(key)

          # rewind by one byte, to overwrite '}'
          file.pos = file.size - 1

          file.write(',') if @keys.any?
          file.write(key.to_json)
          file.write(':')
          file.write(value.to_json)
          file.write('}')

          @keys.add(key)
        end

        def file
          @file ||= File.open(@path, "wb")
        end
      end
    end
  end
end