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))
|