mongify 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +20 -0
- data/CHANGELOG.rdoc +22 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +68 -0
- data/LICENSE +20 -0
- data/README.rdoc +86 -0
- data/Rakefile +73 -0
- data/bin/mongify +14 -0
- data/features/options.feature +46 -0
- data/features/print.feature +10 -0
- data/features/process.feature +19 -0
- data/features/step_definitions/mongify_steps.rb +42 -0
- data/features/step_definitions/mongo_steps.rb +7 -0
- data/features/support/env.rb +28 -0
- data/lib/mongify.rb +22 -0
- data/lib/mongify/cli.rb +8 -0
- data/lib/mongify/cli/application.rb +43 -0
- data/lib/mongify/cli/help_command.rb +16 -0
- data/lib/mongify/cli/options.rb +94 -0
- data/lib/mongify/cli/report.rb +11 -0
- data/lib/mongify/cli/version_command.rb +18 -0
- data/lib/mongify/cli/worker_command.rb +93 -0
- data/lib/mongify/configuration.rb +46 -0
- data/lib/mongify/database.rb +5 -0
- data/lib/mongify/database/base_connection.rb +78 -0
- data/lib/mongify/database/column.rb +81 -0
- data/lib/mongify/database/no_sql_connection.rb +62 -0
- data/lib/mongify/database/sql_connection.rb +61 -0
- data/lib/mongify/database/table.rb +74 -0
- data/lib/mongify/exceptions.rb +13 -0
- data/lib/mongify/translation.rb +55 -0
- data/lib/mongify/translation/printer.rb +20 -0
- data/lib/mongify/translation/process.rb +61 -0
- data/lib/mongify/ui.rb +45 -0
- data/lib/mongify/version.rb +3 -0
- data/mongify.gemspec +42 -0
- data/spec/default.watch +199 -0
- data/spec/files/base_configuration.rb +9 -0
- data/spec/files/empty_translation.rb +0 -0
- data/spec/files/simple_translation.rb +26 -0
- data/spec/mongify/cli/application_spec.rb +19 -0
- data/spec/mongify/cli/help_command_spec.rb +18 -0
- data/spec/mongify/cli/options_spec.rb +62 -0
- data/spec/mongify/cli/version_command_spec.rb +24 -0
- data/spec/mongify/cli/worker_command_spec.rb +115 -0
- data/spec/mongify/configuration_spec.rb +25 -0
- data/spec/mongify/database/base_connection_spec.rb +59 -0
- data/spec/mongify/database/column_spec.rb +103 -0
- data/spec/mongify/database/no_sql_connection_spec.rb +131 -0
- data/spec/mongify/database/sql_connection_spec.rb +91 -0
- data/spec/mongify/database/table_spec.rb +120 -0
- data/spec/mongify/translation/printer_spec.rb +34 -0
- data/spec/mongify/translation/process_spec.rb +68 -0
- data/spec/mongify/translation_spec.rb +59 -0
- data/spec/mongify/ui_spec.rb +73 -0
- data/spec/mongify_spec.rb +15 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/support/config_reader.rb +21 -0
- data/spec/support/database.example +17 -0
- data/spec/support/database_output.txt +27 -0
- data/spec/support/generate_database.rb +91 -0
- metadata +370 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
$:.unshift 'lib'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'tempfile'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'mongify/cli/application'
|
7
|
+
require 'mongify'
|
8
|
+
require 'spec/support/generate_database'
|
9
|
+
require 'spec/support/config_reader'
|
10
|
+
|
11
|
+
::CONNECTION_CONFIG = ConfigReader.new(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))) + '/spec/support/database.yml')
|
12
|
+
::DATABASE_PRINT = File.read(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))) + '/spec/support/database_output.txt')
|
13
|
+
|
14
|
+
module MongifyWorld
|
15
|
+
def run(cmd)
|
16
|
+
stderr_file = Tempfile.new('mongify-world')
|
17
|
+
stderr_file.close
|
18
|
+
@last_stdout = `#{cmd} 2> #{stderr_file.path}`
|
19
|
+
@last_exit_status = $?.exitstatus
|
20
|
+
@last_stderr = IO.read(stderr_file.path)
|
21
|
+
end
|
22
|
+
|
23
|
+
def mongify(args)
|
24
|
+
run("ruby -Ilib -rubygems bin/mongify #{args}")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
World(MongifyWorld)
|
data/lib/mongify.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#
|
2
|
+
# Mongify's core functionality
|
3
|
+
#
|
4
|
+
require 'active_support/core_ext'
|
5
|
+
|
6
|
+
require 'mongify/ui'
|
7
|
+
require 'mongify/exceptions'
|
8
|
+
require 'mongify/translation'
|
9
|
+
require 'mongify/configuration'
|
10
|
+
require 'mongify/database'
|
11
|
+
|
12
|
+
module Mongify
|
13
|
+
class << self
|
14
|
+
def root=(value)
|
15
|
+
@root = value
|
16
|
+
end
|
17
|
+
def root
|
18
|
+
raise RootMissing, "Root not configured" if @root.nil?
|
19
|
+
@root
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/mongify/cli.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
module Mongify
|
2
|
+
module CLI
|
3
|
+
#
|
4
|
+
# Represents an instance of a Mongify application.
|
5
|
+
# This is the entry point for all invocations of Mongify from the
|
6
|
+
# command line.
|
7
|
+
#
|
8
|
+
class Application
|
9
|
+
|
10
|
+
STATUS_SUCCESS = 0
|
11
|
+
STATUS_ERROR = 1
|
12
|
+
|
13
|
+
def initialize(arguments=["--help"], stdin=$stdin, stdout=$stdout)
|
14
|
+
@options = Options.new(arguments)
|
15
|
+
@status = STATUS_SUCCESS
|
16
|
+
Mongify::Configuration.in_stream = stdin
|
17
|
+
Mongify::Configuration.out_stream = stdout
|
18
|
+
end
|
19
|
+
|
20
|
+
def execute!
|
21
|
+
begin
|
22
|
+
cmd = @options.parse
|
23
|
+
cmd.execute(self)
|
24
|
+
rescue Exception => error
|
25
|
+
$stderr.puts "Error: #{error}"
|
26
|
+
report_error
|
27
|
+
end
|
28
|
+
return @status
|
29
|
+
end
|
30
|
+
|
31
|
+
def output(message)
|
32
|
+
UI.puts(message)
|
33
|
+
end
|
34
|
+
|
35
|
+
def report_success
|
36
|
+
@status = STATUS_SUCCESS
|
37
|
+
end
|
38
|
+
def report_error
|
39
|
+
@status = STATUS_ERROR
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Mongify
|
2
|
+
module CLI
|
3
|
+
#
|
4
|
+
# A command to display usage information for this application.
|
5
|
+
#
|
6
|
+
class HelpCommand
|
7
|
+
def initialize(parser)
|
8
|
+
@parser = parser
|
9
|
+
end
|
10
|
+
def execute(view)
|
11
|
+
view.output(@parser.to_s)
|
12
|
+
view.report_success
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
module Mongify
|
3
|
+
module CLI
|
4
|
+
#
|
5
|
+
# Used to parse the options for an application
|
6
|
+
#
|
7
|
+
class Options
|
8
|
+
def initialize(argv)
|
9
|
+
@parsed = false
|
10
|
+
@argv = argv
|
11
|
+
@parser = OptionParser.new
|
12
|
+
@report_class = VerboseReport
|
13
|
+
#@command_class = ReekCommand
|
14
|
+
set_options
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
def banner
|
19
|
+
progname = @parser.program_name
|
20
|
+
return <<EOB
|
21
|
+
Usage: #{progname} command [database_translation.rb] [-c database.config]
|
22
|
+
|
23
|
+
Commands:
|
24
|
+
#{Mongify::CLI::WorkerCommand.list_commands.join("\n")}
|
25
|
+
|
26
|
+
Examples:
|
27
|
+
|
28
|
+
#{progname} translate -c datbase.config
|
29
|
+
#{progname} tr -c database.config
|
30
|
+
#{progname} check -c database.config
|
31
|
+
#{progname} process database_translation.rb -c database.config
|
32
|
+
|
33
|
+
See http://github.com/anlek/mongify for more details
|
34
|
+
|
35
|
+
EOB
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def set_options
|
40
|
+
@parser.banner = banner
|
41
|
+
@parser.separator "Common options:"
|
42
|
+
@parser.on("-h", "--help", "Show this message") do
|
43
|
+
@command_class = HelpCommand
|
44
|
+
end
|
45
|
+
@parser.on("-v", "--version", "Show version") do
|
46
|
+
@command_class = VersionCommand
|
47
|
+
end
|
48
|
+
@parser.on('-c', '--config FILE', "Configuration File to use") do |file|
|
49
|
+
@config_file = file
|
50
|
+
end
|
51
|
+
|
52
|
+
@parser.separator "\nReport formatting:"
|
53
|
+
@parser.on("-q", "--[no-]quiet", "Suppress extra output") do |opt|
|
54
|
+
@report_class = opt ? QuietReport : VerboseReport
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def parse
|
59
|
+
parse_options
|
60
|
+
|
61
|
+
if @command_class == HelpCommand
|
62
|
+
HelpCommand.new(@parser)
|
63
|
+
elsif @command_class == VersionCommand
|
64
|
+
VersionCommand.new(@parser.program_name)
|
65
|
+
else
|
66
|
+
raise ConfigurationFileNotFound unless @config_file
|
67
|
+
#TODO: In the future, request sql_connection and nosql_connection from user input
|
68
|
+
config = Configuration.parse(@config_file)
|
69
|
+
|
70
|
+
WorkerCommand.new(action, config, translation_file, @parser)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def translation_file(argv=@argv)
|
77
|
+
parse_options
|
78
|
+
return nil if argv.length < 2
|
79
|
+
argv[1]
|
80
|
+
end
|
81
|
+
|
82
|
+
def action(argv=@argv)
|
83
|
+
parse_options
|
84
|
+
@argv.try(:[],0) || ''
|
85
|
+
end
|
86
|
+
|
87
|
+
def parse_options
|
88
|
+
@parsed = true && @parser.parse!(@argv) unless @parsed
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'mongify/version'
|
2
|
+
module Mongify
|
3
|
+
module CLI
|
4
|
+
|
5
|
+
#
|
6
|
+
# A command to report the application's current version number.
|
7
|
+
#
|
8
|
+
class VersionCommand
|
9
|
+
def initialize(progname)
|
10
|
+
@progname = progname
|
11
|
+
end
|
12
|
+
def execute(view)
|
13
|
+
view.output("#{@progname} #{Mongify::VERSION}\n")
|
14
|
+
view.report_success
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Mongify
|
2
|
+
module CLI
|
3
|
+
|
4
|
+
#
|
5
|
+
# A command to run the different commands in the application (related to Mongifying).
|
6
|
+
#
|
7
|
+
class WorkerCommand
|
8
|
+
attr_accessor :view
|
9
|
+
|
10
|
+
AVAILABLE_COMMANDS = {
|
11
|
+
:check => {:commands => ['check', 'ck'], :description => "Checks connection for sql and no_sql databases", :required => [:configuration_file]},
|
12
|
+
:translate => {:commands => ['translate', 'tr'], :description => "Spits out translation from a sql connection", :required => [:configuration_file]},
|
13
|
+
:process => {:commands => ['process', 'pr'], :description => "Takes a translation and process it to mongodb", :required => [:configuration_file, :translation_file]}
|
14
|
+
}
|
15
|
+
def self.list_commands
|
16
|
+
[].tap do |commands|
|
17
|
+
AVAILABLE_COMMANDS.each do |key, obj|
|
18
|
+
commands << "#{obj[:commands].map{|w| %["#{w}"]}.to_sentence(:two_words_connector => ' or ', :last_word_connector => ', or ').ljust(25)} >> #{obj[:description]}#{ " [#{obj[:required].join(', ')}]" if obj[:required]}"
|
19
|
+
end
|
20
|
+
end.sort
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.find_command(command)
|
24
|
+
AVAILABLE_COMMANDS.each do |key, options|
|
25
|
+
return [key, options] if(options[:commands].include?(command.to_s.downcase))
|
26
|
+
end
|
27
|
+
'unknown'
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(command, config=nil, translation_file=nil, parser="")
|
31
|
+
@command = command.to_s.downcase
|
32
|
+
@config = config
|
33
|
+
@translation_file = translation_file
|
34
|
+
@parser = parser
|
35
|
+
end
|
36
|
+
|
37
|
+
def execute(view)
|
38
|
+
self.view = view
|
39
|
+
|
40
|
+
current_command, command_options = find_command
|
41
|
+
|
42
|
+
if command_options
|
43
|
+
#FIXME: Should parse configuration file in this action, (when I know it's required)
|
44
|
+
raise ConfigurationFileNotFound, "Configuration file is required" if command_options[:required] && command_options[:required].include?(:configuration_file) && @config.nil?
|
45
|
+
if command_options[:required] && command_options[:required].include?(:translation_file)
|
46
|
+
raise TranslationFileNotFound, "Translation file is required for command '#{current_command}'" unless @translation_file
|
47
|
+
raise TranslationFileNotFound, "Unable to find Translation File at #{@translation_file}" unless File.exists?(@translation_file)
|
48
|
+
@translation = Translation.parse(@translation_file)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
case current_command
|
53
|
+
when :translate
|
54
|
+
check_connections
|
55
|
+
view.output(Mongify::Translation.load(@config.sql_connection).print)
|
56
|
+
when :check
|
57
|
+
view.output("SQL connection works") if check_sql_connection
|
58
|
+
view.output("NoSQL connection works") if check_nosql_connection
|
59
|
+
when :process
|
60
|
+
check_connections
|
61
|
+
@translation.process(@config.sql_connection, @config.no_sql_connection)
|
62
|
+
else
|
63
|
+
view.output("Unknown action #{@command}\n\n#{@parser}")
|
64
|
+
view.report_error
|
65
|
+
return
|
66
|
+
end
|
67
|
+
view.report_success
|
68
|
+
end
|
69
|
+
|
70
|
+
def find_command(command=@command)
|
71
|
+
self.class.find_command(command)
|
72
|
+
end
|
73
|
+
|
74
|
+
#######
|
75
|
+
private
|
76
|
+
#######
|
77
|
+
|
78
|
+
def check_connections(sql_only = false)
|
79
|
+
check_sql_connection && (sql_only || check_nosql_connection)
|
80
|
+
end
|
81
|
+
|
82
|
+
def check_sql_connection
|
83
|
+
@config.sql_connection.valid? && @config.sql_connection.has_connection?
|
84
|
+
end
|
85
|
+
|
86
|
+
def check_nosql_connection
|
87
|
+
@config.no_sql_connection.valid? && @config.no_sql_connection.has_connection?
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Mongify
|
2
|
+
#
|
3
|
+
# This extracts the configuration for sql and no sql
|
4
|
+
#
|
5
|
+
class Configuration
|
6
|
+
class << self
|
7
|
+
attr_accessor :in_stream, :out_stream
|
8
|
+
|
9
|
+
def parse_translation(file_name)
|
10
|
+
raise Mongify::TranslationFileNotFound, "File #{file_name} is missing" unless File.exists?(file_name)
|
11
|
+
Mongify::Translation.parse(file_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse_configuration(file_name)
|
15
|
+
raise Mongify::ConfigurationFileNotFound, "File #{file_name} is missing" unless File.exists?(file_name)
|
16
|
+
Mongify::Configuration.parse(file_name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse(file_name)
|
20
|
+
config = self.new
|
21
|
+
config.instance_eval(File.read(file_name))
|
22
|
+
config
|
23
|
+
end
|
24
|
+
|
25
|
+
end #self
|
26
|
+
|
27
|
+
def mongodb_connection(options={}, &block)
|
28
|
+
options.stringify_keys!
|
29
|
+
options['adapter'] ||= 'mongodb'
|
30
|
+
no_sql_connection(options, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def sql_connection(options={}, &block)
|
34
|
+
@sql_connection ||= Mongify::Database::SqlConnection.new(options)
|
35
|
+
@sql_connection.instance_exec(&block) if block_given?
|
36
|
+
@sql_connection
|
37
|
+
end
|
38
|
+
|
39
|
+
def no_sql_connection(options={}, &block)
|
40
|
+
@no_sql_connection ||= Mongify::Database::NoSqlConnection.new(options)
|
41
|
+
@no_sql_connection.instance_exec(&block) if block_given?
|
42
|
+
@no_sql_connection
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module Mongify
|
4
|
+
module Database
|
5
|
+
#
|
6
|
+
# Basic configuration for any sql or non sql database
|
7
|
+
#
|
8
|
+
class BaseConnection
|
9
|
+
|
10
|
+
REQUIRED_FIELDS = %w{host}
|
11
|
+
AVAILABLE_FIELDS = %w{adapter host username password database socket port}
|
12
|
+
|
13
|
+
def initialize(options=nil)
|
14
|
+
if options
|
15
|
+
options.stringify_keys!
|
16
|
+
options.each do |key, value|
|
17
|
+
instance_variable_set "@#{key}", value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_hash
|
23
|
+
hash = {}
|
24
|
+
instance_variables.each do |variable|
|
25
|
+
value = self.instance_variable_get variable
|
26
|
+
hash[variable.gsub('@','').to_sym] = value unless value.nil?
|
27
|
+
end
|
28
|
+
hash
|
29
|
+
end
|
30
|
+
|
31
|
+
def valid?
|
32
|
+
REQUIRED_FIELDS.each do |require_field|
|
33
|
+
return false unless instance_variables.include?("@#{require_field}") and
|
34
|
+
!instance_variable_get("@#{require_field}").to_s.empty?
|
35
|
+
end
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def setup_connection_adapter
|
41
|
+
raise NotImplementedError
|
42
|
+
end
|
43
|
+
|
44
|
+
def has_connection?
|
45
|
+
raise NotImplementedError
|
46
|
+
end
|
47
|
+
|
48
|
+
def adapter(value=nil)
|
49
|
+
@adapter = value.to_s unless value.nil?
|
50
|
+
@adapter
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def respond_to?(method, *args)
|
55
|
+
return true if AVAILABLE_FIELDS.include?(method.to_s)
|
56
|
+
super(method)
|
57
|
+
end
|
58
|
+
|
59
|
+
def method_missing(method, *args)
|
60
|
+
method_name = method.to_s #.gsub("=", '')
|
61
|
+
if AVAILABLE_FIELDS.include?(method_name.to_s)
|
62
|
+
class_eval <<-EOF
|
63
|
+
def #{method_name}(value=nil)
|
64
|
+
@#{method_name} = value unless value.nil?
|
65
|
+
@#{method_name}
|
66
|
+
end
|
67
|
+
EOF
|
68
|
+
value = args.first if args.size > 0
|
69
|
+
send(method,value)
|
70
|
+
else
|
71
|
+
super(method, args)
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|