#!/usr/bin/env ruby $: << File.expand_path("#{File.dirname __FILE__}/../lib") require 'rubygems' require 'gratan' require 'optparse' require 'json' Version = Gratan::VERSION DEFAULT_FILENAME = 'Grantfile' mode = nil file = DEFAULT_FILENAME output_file = '-' split = false MAGIC_COMMENT = <<-EOS # -*- mode: ruby -*- # vi: set ft=ruby : EOS mysql_options = { :host => 'localhost', :username => 'root', } options = { :dry_run => false, :color => true, :debug => false, } ARGV.options do |opt| begin opt.on('' , '--host HOST') {|v| mysql_options[:host] = v } opt.on('' , '--port PORT', Integer) {|v| mysql_options[:port] = v } opt.on('' , '--socket SOCKET') {|v| mysql_options[:socket] = v } opt.on('' , '--username USERNAME') {|v| mysql_options[:username] = v } opt.on('' , '--password PASSWORD') {|v| mysql_options[:password] = v } opt.on('' , '--database DATABASE') {|v| mysql_options[:database] = v } opt.on('-a', '--apply') { mode = :apply } opt.on('-f', '--file FILE') {|v| file = v } opt.on('' , '--dry-run') { options[:dry_run] = true } opt.on('-e', '--export') { mode = :export } opt.on('' , '--with-identifier') { options[:with_identifier] = true } opt.on('' , '--split') { split = true } opt.on('' , '--chunk-by-user') { options[:chunk_by_user] = true } opt.on('-o', '--output FILE') {|v| output_file = v } opt.on('' , '--ignore-user REGEXP') {|v| options[:ignore_user] = Regexp.new(v) } opt.on('' , '--target-user REGEXP') {|v| options[:target_user] = Regexp.new(v) } opt.on('' , '--ignore-object REGEXP') {|v| options[:ignore_object] = Regexp.new(v) } opt.on('' , '--enable-expired') { options[:enable_expired] = true } opt.on('' , '--ignore-not-exist') {|v| options[:ignore_not_exist] = true } opt.on('' , '--ignore-password-secret') {|v| options[:ignore_password_secret] = true } opt.on('' , '--skip-disable-log-bin') { options[:skip_disable_log_bin] = true } opt.on('' , '--no-color') { options[:color] = false } opt.on('' , '--debug') { options[:debug] = true } opt.on('' , '--auto-identify OUTPUT') {|v| options[:identifier] = Gratan::Identifier::Auto.new(v, options) } opt.on('' , '--csv-identify CSV') {|v| options[:identifier] = Gratan::Identifier::CSV.new(v, options) } opt.on('' , '--mysql2-options JSON') do |json| json = JSON.parse(json) json.each do |key, value| options[key.to_sym] = value end end opt.on('-h', '--help') do puts opt.help exit 1 end opt.parse! unless mode puts opt.help exit 1 end rescue => e $stderr.puts("[ERROR] #{e.message}") exit 1 end end options.update(mysql_options) String.colorize = options[:color] begin logger = Gratan::Logger.instance logger.set_debug(options[:debug]) client = Gratan::Client.new(options) case mode when :export if split logger.info('Export Grants') output_file = DEFAULT_FILENAME if output_file == '-' requires = [] client.export do |user, dsl| grant_file = File.join(File.dirname(output_file), "#{user}.grant") requires << grant_file logger.info(" write `#{grant_file}`") open(grant_file, 'wb') do |f| f.puts MAGIC_COMMENT f.puts dsl end end logger.info(" write `#{output_file}`") open(output_file, 'wb') do |f| f.puts MAGIC_COMMENT requires.each do |grant_file| f.puts "require '#{File.basename grant_file}'" end end else if output_file == '-' logger.info('# Export Grants') puts client.export(options) else logger.info("Export Grants to `#{output_file}`") open(output_file, 'wb') do |f| f.puts MAGIC_COMMENT f.puts client.export(options) end end end when :apply unless File.exist?(file) raise "No Grantfile found (looking for: #{file})" end mysql_info = mysql_options.dup mysql_info.delete(:password) mysql_info = JSON.dump(mysql_info) msg = "Apply `#{file}` to #{mysql_info}" msg << ' (dry-run)' if options[:dry_run] logger.info(msg) updated = client.apply(file) logger.info('No change'.intense_blue) unless updated end rescue => e if options[:debug] raise e else $stderr.puts("[ERROR] #{e.message}".red) exit 1 end end