File: copy-related-files.rb

package info (click to toggle)
groonga 15.0.4%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 163,080 kB
  • sloc: ansic: 770,564; cpp: 48,925; ruby: 40,447; javascript: 10,250; yacc: 7,045; sh: 5,602; python: 2,821; makefile: 1,672
file content (157 lines) | stat: -rwxr-xr-x 4,296 bytes parent folder | download | duplicates (4)
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/usr/bin/env ruby

require "fileutils"
require "optparse"
require "json"

class CopyRelatedFiles
  def initialize
    @database_path = nil
    @groonga = "groonga"
    @destination_path = "."
    @targets = []
  end

  def run(argv)
    return false unless parse_options(argv)

    ensure_schema
    copy

    true
  end

  private
  def parse_options(argv)
    parser = OptionParser.new
    parser.banner += " DATABASE_PATH"
    parser.on("--groonga=PATH",
              "The path to the groonga command.",
              "#{@grronga}") do |path|
      @groonga = path
    end
    parser.on("--destination=PATH",
              "The path to the destination directory.",
              "#{@destination_path}") do |path|
      @destination_path = path
    end
    parser.on("--target=TARGET",
              "The target table/column to be copied.",
              "You can specify this option multiple times",
              "to copy multiple tables/columns.") do |target|
      @targets << target
    end

    @database_path, = parser.parse!(argv)
    not @database_path.nil?
  end

  def ensure_schema
    response = ""
    IO.pipe do |input, output|
      pid = spawn(@groonga,
                  @database_path,
                  "schema",
                  "--output_pretty", "yes",
                  :out => output)
      output.close
      input.each_line do |line|
        response << line
      end
      Process.waitpid(pid)
    end
    @schema = JSON.parse(response)[1]
  end

  def copy
    FileUtils.mkdir_p(@destination_path)
    copy_builtin_files
    copy_target_files
  end

  def copy_builtin_files
    suffixes = [
      "",
      ".001",
      ".conf",
      ".options",
      ".0000000",
    ]
    suffixes.each do |suffix|
      FileUtils.cp("#{@database_path}#{suffix}",
                   @destination_path)
    end
  end

  def copy_target_files
    target_ids.each do |id|
      FileUtils.cp(Dir.glob("%s.%07X*" % [@database_path, id]),
                   @destination_path)
    end
  end

  def target_ids
    ids = []
    processed_targets = {}
    @targets.each do |target|
      table_name, column_name = target.split(".", 2)
      table = @schema["tables"][table_name]
      ids.concat(extract_ids_from_table(table, processed_targets))
      next if column_name.nil?
      column = table["columns"][column_name]
      ids.concat(extract_ids_from_column(column, processed_targets))
    end
    ids.uniq
  end

  def extract_ids_from_table(table, processed_targets)
    return [] if processed_targets.key?(table)
    processed_targets[table] = true

    ids = []
    ids << table["id"]
    key_type = table["key_type"]
    if key_type && key_type["type"] == "reference"
      ids.concat(extract_ids_from_table(@schema["tables"][key_type["name"]],
                                        processed_targets))
    end
    value_type = table["value_type"]
    if value_type && value_type["type"] == "reference"
      ids.concat(extract_ids_from_table(@schema["tables"][value_type["name"]],
                                        processed_targets))
    end
    ids
  end

  def extract_ids_from_column(column, processed_targets)
    return [] if processed_targets.key?(column)
    processed_targets[column] = true

    ids = []
    ids << column["id"]
    value_type = column["value_type"]
    if value_type && value_type["type"] == "reference"
      ids.concat(extract_ids_from_table(@schema["tables"][value_type["name"]],
                                        processed_targets))
    end
    sources = column["sources"] || []
    sources.each do |source|
      source_table = @schema["tables"][source["table"]]
      ids.concat(extract_ids_from_table(source_table, processed_targets))
      source_name = source["name"]
      source_column = source_table["columns"][source_name]
      ids.concat(extract_ids_from_column(source_column, processed_targets))
    end
    indexes = column["indexes"] || []
    indexes.each do |index|
      index_table = @schema["tables"][index["table"]]
      ids.concat(extract_ids_from_table(index_table, processed_targets))
      index_column = index_table["columns"][index["name"]]
      ids.concat(extract_ids_from_column(index_column, processed_targets))
    end
    ids
  end
end

command = CopyRelatedFiles.new
exit(command.run(ARGV))