X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=bin%2Frbotdb;h=b77939eb0647f162aebbe254c9753151ff5f3b68;hb=3d8bdf551aebdd4fa7ddb10fa8e824232dd4f82b;hp=14d61e47539fea6f2d415d273d50897bda8251f0;hpb=c66f748ad4f4e00f58fa5679f33d254f5c1f6922;p=user%2Fhenk%2Fcode%2Fruby%2Frbot.git diff --git a/bin/rbotdb b/bin/rbotdb index 14d61e47..b77939eb 100755 --- a/bin/rbotdb +++ b/bin/rbotdb @@ -2,11 +2,11 @@ #-- vim:sw=2:et #++ # -# :title: RBot Registry Export, Import and Migration Script. +# :title: RBot Registry Backup, Restore and Migration Script. # # You can use this script to, -# - export the rbot registry in a format that is platform/engine independent -# - import these backups in supported formats (dbm, daybreak) +# - backup the rbot registry in a format that is platform/engine independent +# - restore these backups in supported formats (dbm, daybreak) # - migrate old rbot registries bdb (ruby 1.8) and tokyocabinet. # # For more information, just execute the script without any arguments! @@ -22,6 +22,7 @@ begin; require 'bdb'; rescue Exception; end begin; require 'tokyocabinet'; rescue Exception; end begin; require 'dbm'; rescue Exception; end begin; require 'daybreak'; rescue Exception; end +begin; require 'sqlite3'; rescue Exception; end puts 'RBot Registry Backup/Restore/Migrate' puts '[%s]' % ['Ruby: ' + RUBY_VERSION, @@ -29,27 +30,32 @@ puts '[%s]' % ['Ruby: ' + RUBY_VERSION, 'BDB: ' + (BDB::VERSION rescue '-'), 'TokyoCabinet: ' + (TokyoCabinet::VERSION rescue '-'), 'Daybreak: ' + (Daybreak::VERSION rescue '-'), + 'SQLite: ' + (SQLite3::VERSION rescue '-'), ].join(' | ') require 'date' require 'optparse' -TYPES = [:bdb, :tc, :dbm, :daybreak, :auto] +TYPES = [:bdb, :tc, :dbm, :daybreak, :sqlite] options = { :profile => '~/.rbot', :registry => nil, - :dbfile => './%s.rbot' % DateTime.now.strftime('export_%Y-%m-%d_%H%M%S'), - :type => :auto + :dbfile => './%s.rbot' % DateTime.now.strftime('backup_%Y-%m-%d_%H%M%S'), + :type => nil } opt_parser = OptionParser.new do |opt| opt.banner = 'Usage: rbotdb COMMAND [OPTIONS]' opt.separator '' opt.separator 'Commands:' - opt.separator ' export: store rbot registry platform-independently in a file.' - opt.separator ' import: restore rbot registry from such a file.' + opt.separator ' backup: store rbot registry platform-independently in a file.' + opt.separator ' restore: restore rbot registry from such a file.' opt.separator '' opt.separator 'Options:' + opt.on('-t', '--type TYPE', TYPES, 'format to backup/restore. Values: %s.' % [TYPES.join(', ')]) do |type| + options[:type] = type + end + opt.on('-p', '--profile [PROFILE]', 'rbot profile directory. Defaults to: %s.' % options[:profile]) do |profile| options[:profile] = profile end @@ -58,18 +64,14 @@ opt_parser = OptionParser.new do |opt| options[:registry] = profile end - opt.on('-f', '--file [DBFILE]', 'cross-platform file to export to/import from. Defaults to: %s.' % options[:dbfile]) do |dbfile| + opt.on('-f', '--file [DBFILE]', 'cross-platform file to backup to/restore from. Defaults to: %s.' % options[:dbfile]) do |dbfile| options[:dbfile] = dbfile end - opt.on('-t', '--type TYPE', TYPES, 'format to export/import. Values: %s. Defaults to %s.' % [TYPES.join(', '), options[:type]]) do |type| - options[:type] = type - end - opt.separator '' end -class ExportRegistry +class BackupRegistry def initialize(profile, type, registry) @profile = File.expand_path profile @type = type @@ -78,21 +80,15 @@ class ExportRegistry end # returns a hash with the complete registry data - def export + def backup listings = search - puts 'Found registry types: bdb=%d tc=%d dbm=%d daybreak=%d' % [ + puts 'Found registry types: bdb=%d tc=%d dbm=%d daybreak=%d sqlite=%d' % [ listings[:bdb].length, listings[:tc].length, - listings[:dbm].length, listings[:daybreak].length + listings[:dbm].length, listings[:daybreak].length, listings[:sqlite].length ] - if @type == :auto - @type = :bdb if listings[:bdb].length > 0 - @type = :tc if listings[:tc].length > 0 - @type = :dbm if listings[:dbm].length > 0 - @type = :daybreak if listings[:daybreak].length > 0 - end - if @type == :auto or listings[@type].empty? + if listings[@type].empty? puts 'No suitable registry found!' - return + exit end puts 'Using registry type: %s' % @type read(listings[@type]) @@ -113,6 +109,8 @@ class ExportRegistry read_dbm(file) when :daybreak read_daybreak(file) + when :sqlite + read_sqlite(file) end count += data[file.key].length rescue @@ -130,7 +128,11 @@ class ExportRegistry def read_bdb(file) data = {} - db = BDB::Hash.open(file.abs, nil, 'r') + begin + db = BDB::Hash.open(file.abs, nil, 'r') + rescue BDB::Fatal + db = BDB::Btree.open(file.abs, nil, 'r') + end db.each do |key, value| data[key] = value end @@ -166,6 +168,18 @@ class ExportRegistry data end + def read_sqlite(file) + data = {} + db = SQLite3::Database.new(file.abs) + res = db.execute('SELECT key, value FROM data') + res.each do |row| + key, value = row + data[key] = value + end + db.close + data + end + # searches in profile directory for existing registry formats def search { @@ -173,6 +187,7 @@ class ExportRegistry :tc => list(get_registry('_tc'), '*.tdb'), :dbm => list(get_registry('_dbm'), '*.*'), :daybreak => list(get_registry('_daybreak'), '*.db'), + :sqlite => list(get_registry('_sqlite'), '*.db'), } end @@ -209,29 +224,33 @@ class ExportRegistry end end -class ImportRegistry +class RestoreRegistry def initialize(profile, type, registry) @profile = File.expand_path profile @registry = registry ? File.expand_path(registry) : nil - @type = (type == :auto) ? :dbm : type + @type = type puts 'Using type=%s profile=%s' % [@type, @profile] end - def import(data) + def restore(data) puts 'Using registry type: %s' % @type folder = create_folder - print "~Importing... (this might take a moment)\r" + print "~Restoring... (this might take a moment)\r" data.each do |file, hash| file = File.join(folder, file) create_subdir(file) case @type when :dbm write_dbm(file, hash) + when :tc + write_tc(file, hash) when :daybreak write_daybreak(file, hash) + when :sqlite + write_sqlite(file, hash) end end - puts 'Import successful! ' + puts 'Restore successful! ' end def write_dbm(file, data) @@ -242,6 +261,19 @@ class ImportRegistry db.close end + def write_tc(file, data) + db = TokyoCabinet::BDB.new + db.open(file + '.tdb', + TokyoCabinet::BDB::OREADER | + TokyoCabinet::BDB::OCREAT | + TokyoCabinet::BDB::OWRITER) + data.each_pair do |key, value| + db[key] = value + end + db.optimize + db.close + end + def write_daybreak(file, data) db = Daybreak::DB.new(file + '.db') data.each_pair do |key, value| @@ -250,7 +282,18 @@ class ImportRegistry db.close end + def write_sqlite(file, data) + db = SQLite3::Database.new(file + '.db') + db.execute('CREATE TABLE data (key PRIMARY_KEY, value)') + data.each_pair do |key, value| + db.execute('INSERT INTO data VALUES (?, ?)', + key, value) + end + db.close + end + def create_folder + Dir.mkdir(@profile) unless File.directory?(@profile) if @registry folder = @registry else @@ -258,8 +301,8 @@ class ImportRegistry end Dir.mkdir(folder) unless File.directory?(folder) if File.directory?(folder) and Dir.glob(File.join(folder, '**')).select{|f|File.file? f}.length>0 - puts 'ERROR: Unable to import!' - puts 'Import folder exists and is not empty: ' + folder + puts 'ERROR: Unable to restore!' + puts 'Restore folder exists and is not empty: ' + folder exit end folder @@ -278,17 +321,22 @@ class ImportRegistry end opt_parser.parse! +if ARGV.length > 0 and options[:type].nil? + puts opt_parser + puts 'Missing Argument: -t [type]' + exit +end case ARGV[0] -when 'export' +when 'backup' if File.exists? options[:dbfile] - puts 'Export file already exists.' + puts 'Backup file already exists.' exit end - reg = ExportRegistry.new(options[:profile], options[:type], options[:registry]) + reg = BackupRegistry.new(options[:profile], options[:type], options[:registry]) - data = reg.export + data = reg.backup if not data.empty? File.open(options[:dbfile], 'w') do |f| @@ -297,17 +345,17 @@ when 'export' puts 'Written registry to ' + options[:dbfile] end -when 'import' +when 'restore' unless File.exists? options[:dbfile] - puts 'Import file does not exist.' + puts 'Backup file does not exist.' exit end - reg = ImportRegistry.new(options[:profile], options[:type], options[:registry]) + reg = RestoreRegistry.new(options[:profile], options[:type], options[:registry]) data = Marshal.load File.read(options[:dbfile]) - puts 'Read %d registry files from import file.' % data.length - reg.import data + puts 'Read %d registry files from backup file.' % data.length + reg.restore data else puts opt_parser