multi_ar 1.0.0.pre.rc1
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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/bin/mar +4 -0
- data/bin/multi_ar +65 -0
- data/lib/multi_ar/database.rb +62 -0
- data/lib/multi_ar/interface.rb +188 -0
- data/lib/multi_ar/multi_ar_model.rb +36 -0
- data/lib/multi_ar/rake/ext.rb +40 -0
- data/lib/multi_ar/rake/migration_generator.rb +21 -0
- data/lib/multi_ar/rake/tasks.rb +155 -0
- data/lib/multi_ar/version.rb +4 -0
- data/lib/multi_ar.rb +82 -0
- data.tar.gz.sig +0 -0
- metadata +183 -0
- metadata.gz.sig +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8bb5b123951c55685e13a738e7cfbf9f12a60c01
|
4
|
+
data.tar.gz: 9e91ce2afc46d52e33ea4f2c7e735307d978f609
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6c685d03c1cbe001b957c946b97513f940957c8399a293d82fc1a9fcdcff8bbb2084c1ee59cf872fe324764bfba4af1871541692022224805c105892e6bed37d
|
7
|
+
data.tar.gz: 3e70852de5be0497a6de35a8cfddb9708b1e633a63409f3af42d537e2e2e34b4588ff4a8a1c88873b33af6ecfe8af7b34f08592db61a83bdf655d21456a3752a
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data/bin/mar
ADDED
data/bin/multi_ar
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "trollop"
|
4
|
+
|
5
|
+
require_relative "../lib/multi_ar"
|
6
|
+
require_relative "../lib/multi_ar/version"
|
7
|
+
require_relative "../lib/multi_ar/helper/rake_ext"
|
8
|
+
|
9
|
+
# configuration
|
10
|
+
|
11
|
+
p = Trollop::Parser.new do
|
12
|
+
version "multi_ar-#{MultiAR::VERSION}"
|
13
|
+
banner <<-EOS
|
14
|
+
Helper utility to executing Rake tasks for ActiveRecord migrations.
|
15
|
+
EOS
|
16
|
+
opt "all_rake_tasks", "List all Rake tasks, not only commented ones", short: "A", type: :flag
|
17
|
+
opt "common_migrations", "Run the migrations bundled with the gem, for common databases.", type: :flag, default: true
|
18
|
+
opt "config", "Location to configuration file of MultiAR.", type: :string, default: "config/multi_ar.yaml"
|
19
|
+
opt "databases", "List of databases to perform operations", type: :strings
|
20
|
+
opt "db_config", "Path to database config file", type: :string, default: "config/database.yaml"
|
21
|
+
opt "environment", "The environment to use. Corresponds to database config name " +
|
22
|
+
"(environment for foo_development is “development”).", type: :string, default: "development"
|
23
|
+
# TODO: not implemented currently, do we really need this?
|
24
|
+
#opt "list_databases", "Lists databases that contains migrations in the gem", type: :flag
|
25
|
+
opt "migration_dir", "The directory where migrations for databases are read from", type: :string, default: "db/migrate"
|
26
|
+
opt "task", "Rake task to execute", type: :string
|
27
|
+
opt "tasks", "List available Rake tasks", short: "T", type: :flag
|
28
|
+
opt "verbose", "Be more verbose", type: :flag
|
29
|
+
end
|
30
|
+
|
31
|
+
opts = Trollop::with_standard_exception_handling p do
|
32
|
+
|
33
|
+
args = ARGV.clone
|
34
|
+
|
35
|
+
# and then reparse with arguments from the config file (here so that Trollop can erase ARGV)
|
36
|
+
result = p.parse ARGV
|
37
|
+
|
38
|
+
# show help screen
|
39
|
+
raise Trollop::HelpNeeded if args.empty? # need to be different what we parse, as parser will remove used arguments
|
40
|
+
|
41
|
+
result
|
42
|
+
end
|
43
|
+
|
44
|
+
# running the task
|
45
|
+
|
46
|
+
multi_ar = MultiAR::MultiAR.new common_migrations: opts["common_migrations"],
|
47
|
+
config: opts["config"],
|
48
|
+
databases: opts["databases"],
|
49
|
+
db_config: opts["db_config"],
|
50
|
+
environment: opts["environment"],
|
51
|
+
migration_dir: opts["migration_dir"]
|
52
|
+
|
53
|
+
if opts["tasks"] || opts["all_rake_tasks"]
|
54
|
+
multi_ar.list_tasks all_rake_tasks: opts["all_rake_tasks"]
|
55
|
+
exit 1
|
56
|
+
end
|
57
|
+
|
58
|
+
if opts["task"].nil?
|
59
|
+
puts "Task must be specified. Check if you passed --task option."
|
60
|
+
exit 1
|
61
|
+
end
|
62
|
+
puts "Running task #{opts["task"]}" if opts["verbose"]
|
63
|
+
multi_ar.rake_task opts["task"]
|
64
|
+
|
65
|
+
#rake.top_level
|
@@ -0,0 +1,62 @@
|
|
1
|
+
|
2
|
+
# TODO: we don’t want to unconditionally load Rails as that gives too many unnecessary dependencies,
|
3
|
+
# but if we need it for something, it should be conditional dep through dep-gem or just used if present
|
4
|
+
require "rails"
|
5
|
+
require "rails/application"
|
6
|
+
|
7
|
+
require "active_record"
|
8
|
+
require "active_record/tasks/database_tasks"
|
9
|
+
|
10
|
+
require "erb"
|
11
|
+
require "yaml"
|
12
|
+
|
13
|
+
module MultiAR
|
14
|
+
class Database
|
15
|
+
|
16
|
+
# @todo test if this @@initialized thingy actually works, I’m not sure how it in practice works
|
17
|
+
def self.initialize db_config: "config/database.yaml", migration_dir: "db/migrate"
|
18
|
+
@@initialized ||= false
|
19
|
+
return if @@initialized == true
|
20
|
+
Class.new(Rails::Application) unless Rails.application
|
21
|
+
raise "The database configuration file was not found. You can be pass path to it with db_config attribute. Current path: #{db_config}" unless File.exist? db_config
|
22
|
+
db_config_data = YAML.load(ERB.new(File.read db_config).result)
|
23
|
+
include ActiveRecord::Tasks
|
24
|
+
|
25
|
+
ActiveRecord::Base.configurations = ::ActiveRecord::Tasks::DatabaseTasks.database_configuration = db_config_data
|
26
|
+
ActiveRecord::Tasks::DatabaseTasks.migrations_paths = [ migration_dir ] # this is only used by db:new_migration rake task. # TODO: because of that, maybe we want to handle this differently?
|
27
|
+
@@initialized = true
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return real connection name, nil in case connection is not available
|
31
|
+
def self.connection_name base_name
|
32
|
+
raise "#{base_name} is not in databases configuration variable." unless MultiAR.app.databases.include? base_name
|
33
|
+
return nil unless MultiAR.app.databases.include? base_name
|
34
|
+
"#{base_name}_#{MultiAR.app.environment}"
|
35
|
+
end
|
36
|
+
|
37
|
+
# Expects config file to have the config in activerecord’s format.
|
38
|
+
def self.mysql_client connection_name
|
39
|
+
real_connection_name = self.connection_name connection_name
|
40
|
+
@@mysql_client ||= {}
|
41
|
+
return @@mysql_client[real_connection_name] unless @@mysql_client[real_connection_name].nil?
|
42
|
+
raise "Invalid connection name #{real_connection_name}" unless config = self.database_config[real_connection_name]
|
43
|
+
client = Mysql2::Client.new(
|
44
|
+
host: config["host"],
|
45
|
+
username: config["username"],
|
46
|
+
password: config["password"],
|
47
|
+
database: config["database"]
|
48
|
+
)
|
49
|
+
|
50
|
+
@@mysql_client[real_connection_name] ||= client
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return database configuration in a hash.
|
54
|
+
def self.database_config
|
55
|
+
return @@db_config_cache unless (@@db_config_cache ||= nil).nil?
|
56
|
+
|
57
|
+
db_config = MultiAR.app.db_config
|
58
|
+
@@db_config_cache = Psych.load_file db_config
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
|
2
|
+
require "fileutils"
|
3
|
+
require "trollop"
|
4
|
+
|
5
|
+
require_relative "../multi_ar"
|
6
|
+
require_relative "version"
|
7
|
+
|
8
|
+
module MultiAR
|
9
|
+
|
10
|
+
# An utility to ease creation of executable using multi database ActiveRecord
|
11
|
+
# through command line interface.
|
12
|
+
#
|
13
|
+
# Usage:
|
14
|
+
#
|
15
|
+
# TODO: write usage
|
16
|
+
# TODO: mention this usage in README.md too
|
17
|
+
class Interface
|
18
|
+
|
19
|
+
# Options that will be enabled.
|
20
|
+
#
|
21
|
+
# Options supported by this system are:
|
22
|
+
# - config
|
23
|
+
# - db_config
|
24
|
+
# - dry
|
25
|
+
# - environment
|
26
|
+
# - verbose
|
27
|
+
# - databases
|
28
|
+
#
|
29
|
+
# environment is enabled by default, rest are disabled.
|
30
|
+
attr_accessor :options
|
31
|
+
|
32
|
+
# Version shown with --version flag on CLI
|
33
|
+
attr_accessor :version
|
34
|
+
|
35
|
+
# Description of the application show in usage texts on CLI
|
36
|
+
attr_accessor :description
|
37
|
+
|
38
|
+
# Array of databases that will be used insted if none have not been passed through CLI.
|
39
|
+
attr_accessor :databases
|
40
|
+
|
41
|
+
# Boolean of whether no arguments are needed
|
42
|
+
attr_accessor :run_by_default
|
43
|
+
|
44
|
+
# Hash of gems the application depends to.
|
45
|
+
#
|
46
|
+
# Format should be:
|
47
|
+
# { "gem_name" => "~> 2.0", "another_gem" => nil }
|
48
|
+
#
|
49
|
+
# This is used in --init.
|
50
|
+
#
|
51
|
+
# TODO: what for this actually is? Write an example or just tell what for this should be used.
|
52
|
+
attr_accessor :dependencies
|
53
|
+
|
54
|
+
def initialize
|
55
|
+
@options = {}
|
56
|
+
@dependencies = {}
|
57
|
+
@run_by_default = false
|
58
|
+
end
|
59
|
+
|
60
|
+
# @note Consumes ARGV, create copy of it if you need it for something.
|
61
|
+
# TODO: hardcode shorthands
|
62
|
+
def cli
|
63
|
+
p = Trollop::Parser.new
|
64
|
+
p.version @version if @version
|
65
|
+
p.banner @description if @description
|
66
|
+
p.opt "init", "Create stub environment with configuration and database.yaml", type: :string
|
67
|
+
p.opt "databases", "Databases that will be enabled", type: :strings if @options["databases"]
|
68
|
+
p.opt "db_config", "Path to database config file", type: :string, default: "config/database.yaml" if @options["db_config"]
|
69
|
+
p.opt "config", "Path to config file", type: :string, default: "config/settings.yaml" if @options["config"]
|
70
|
+
p.opt "dry", "Run the program without doing anything. Useful for debugging with -v", type: :flag if @options["dry"]
|
71
|
+
p.opt "environment", "Environment to run the alarms for", type: :string, default: "development"
|
72
|
+
p.opt "verbose", "Be verbose", type: :flag if @options["verbose"]
|
73
|
+
|
74
|
+
yield p if block_given?
|
75
|
+
|
76
|
+
opts = Trollop::with_standard_exception_handling p do
|
77
|
+
args = ARGV.clone
|
78
|
+
|
79
|
+
result = p.parse ARGV
|
80
|
+
|
81
|
+
if not @run_by_default
|
82
|
+
raise Trollop::HelpNeeded if args.empty?
|
83
|
+
end
|
84
|
+
|
85
|
+
result
|
86
|
+
end
|
87
|
+
|
88
|
+
bootstrap opts if opts["init"]
|
89
|
+
|
90
|
+
raise "--config must be path to valid file" if @options["config"] and not File.exist? opts["config"]
|
91
|
+
raise "config/database.yaml seems to be missing" if @options["db_config"] and not File.exist? opts["db_config"]
|
92
|
+
|
93
|
+
@opts = opts
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
# @note This method will always quit the application or raise another exception for errors. Catch SystemExit if that’s not good for you.
|
99
|
+
def bootstrap opts
|
100
|
+
opts["databases"] ||= @databases
|
101
|
+
raise "--databases must be given when bootstrapping." unless opts["databases"]
|
102
|
+
raise "#{opts["init"]} already exists" if File.exist? opts["init"]
|
103
|
+
|
104
|
+
config_dir = "config"
|
105
|
+
database_config = "database.yaml"
|
106
|
+
|
107
|
+
FileUtils.mkdir opts["init"]
|
108
|
+
Dir.chdir opts["init"] do
|
109
|
+
File.write "README", bootstrap_readme(opts)
|
110
|
+
File.write "Gemfile", bootstrap_gemfile
|
111
|
+
|
112
|
+
FileUtils.mkdir config_dir
|
113
|
+
Dir.chdir config_dir do
|
114
|
+
File.write database_config, bootstrap_db_config(opts)
|
115
|
+
end
|
116
|
+
|
117
|
+
run_bundler
|
118
|
+
end
|
119
|
+
|
120
|
+
puts "#{opts["init"]} has been initialized. You can now run your program at the directory."
|
121
|
+
exit 0
|
122
|
+
end
|
123
|
+
|
124
|
+
def bootstrap_db_config opts
|
125
|
+
str = ""
|
126
|
+
opts["databases"].each do |db|
|
127
|
+
[ "development", "production", "test"].each do |env|
|
128
|
+
full_name = "#{db}_#{env}"
|
129
|
+
str << <<-EOS.gsub(/^ {10}/, "")
|
130
|
+
#{full_name}:
|
131
|
+
adapter: sqlite3
|
132
|
+
database: db/#{full_name}_.sqlite3
|
133
|
+
pool: 5
|
134
|
+
timeout: 5000
|
135
|
+
|
136
|
+
EOS
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
str
|
141
|
+
end
|
142
|
+
|
143
|
+
def bootstrap_gemfile
|
144
|
+
str = <<-EOS.gsub(/^ {6}/, "")
|
145
|
+
source "http://service.slm.fi:9292/"
|
146
|
+
|
147
|
+
gem "#{script_name}"
|
148
|
+
EOS
|
149
|
+
|
150
|
+
@dependencies.each do |dep, version|
|
151
|
+
line = "gem \"#{dep}\""
|
152
|
+
line += ", #{version}" unless version.nil?
|
153
|
+
line += "\n"
|
154
|
+
str << line
|
155
|
+
end
|
156
|
+
|
157
|
+
str
|
158
|
+
end
|
159
|
+
|
160
|
+
def bootstrap_readme opts
|
161
|
+
str = <<-EOS.gsub(/^ {6}/, "")
|
162
|
+
## #{script_name}
|
163
|
+
|
164
|
+
This is scaffolded runtime directory for project #{script_name}, created by cimmgnd #{script_name} --init #{opts["init"]}.
|
165
|
+
|
166
|
+
Purpose of this scaffold is to ease usage of this #{script_name}, by providing sample configuration and ready
|
167
|
+
bundle just ready for running. Default configuration is for SQLite3, but any databases supported
|
168
|
+
by Activerecord can be used (you may need to add them to Gemfile in order for more rare adapters to work).
|
169
|
+
|
170
|
+
You can run #{script_name} using bundler:
|
171
|
+
|
172
|
+
bundle exec #{script_name}
|
173
|
+
|
174
|
+
#{script_name} is powered by ActiveRecord migration framework MultiAR-#{VERSION}. More information bundler can be found
|
175
|
+
at its homepage: http://bundler.io
|
176
|
+
EOS
|
177
|
+
end
|
178
|
+
|
179
|
+
def run_bundler
|
180
|
+
puts `bundle install`
|
181
|
+
end
|
182
|
+
|
183
|
+
def script_name
|
184
|
+
@script_name ||= File.basename($0)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "active_record"
|
2
|
+
|
3
|
+
require_relative "multi_ar"
|
4
|
+
|
5
|
+
module MultiAR
|
6
|
+
|
7
|
+
#
|
8
|
+
# Base model for different model groups to include.
|
9
|
+
#
|
10
|
+
# This is not supposed to be included by models itself, instead you should have
|
11
|
+
# common main parent model that extends this model, and the actual model should extend that model.
|
12
|
+
class Model < ActiveRecord::Base
|
13
|
+
self.abstract_class = true
|
14
|
+
|
15
|
+
ActiveRecord::Base.time_zone_aware_attributes = true
|
16
|
+
ActiveRecord::Base.default_timezone = :local
|
17
|
+
|
18
|
+
# Can be used to set custom database config.
|
19
|
+
def self.database_config= config
|
20
|
+
@db_config = config
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def self.establish_connection connection_name
|
26
|
+
raise "MultiAR app must be initialized first" if MultiAR.app.nil?
|
27
|
+
Database.initialize db_config: MultiAR.app.db_config
|
28
|
+
real_connection_name = Database.connection_name connection_name
|
29
|
+
raise "Connection #{real_connection_name} is not present in the db config file #{MultiAR.app.db_config}" if not Database.database_config[real_connection_name]
|
30
|
+
|
31
|
+
super Database.database_config[real_connection_name]
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
require "rake"
|
3
|
+
|
4
|
+
# Extension to Rake to provide rename task.
|
5
|
+
module Rake
|
6
|
+
# Extension to Rake to provide rename task.
|
7
|
+
class Application
|
8
|
+
# A Rake task to rename another Rake task.
|
9
|
+
def rename_task(task, oldname, newname)
|
10
|
+
if @tasks.nil?
|
11
|
+
@tasks = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
@tasks[newname.to_s] = task
|
15
|
+
|
16
|
+
if @tasks.has_key? oldname
|
17
|
+
@tasks.delete oldname
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# add new rename method to Rake::Task class
|
24
|
+
# to rename a task
|
25
|
+
class Rake::Task
|
26
|
+
# Renames current Rake task.
|
27
|
+
def rename(new_name)
|
28
|
+
if !new_name.nil?
|
29
|
+
old_name = @name
|
30
|
+
|
31
|
+
if old_name == new_name
|
32
|
+
return
|
33
|
+
end
|
34
|
+
|
35
|
+
@name = new_name.to_s
|
36
|
+
application.rename_task(self, old_name, new_name)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
require "rails/generators/active_record/migration/migration_generator"
|
3
|
+
require "active_record/tasks/database_tasks"
|
4
|
+
|
5
|
+
module ActiveRecordMigrations
|
6
|
+
module Generators
|
7
|
+
class MigrationGenerator < ::ActiveRecord::Generators::MigrationGenerator
|
8
|
+
source_root ::ActiveRecord::Generators::MigrationGenerator.source_root
|
9
|
+
|
10
|
+
def create_migration_file
|
11
|
+
set_local_assigns!
|
12
|
+
validate_file_name!
|
13
|
+
dir = ::ActiveRecord::Tasks::DatabaseTasks.migrations_paths.first
|
14
|
+
db_dir = ::ActiveRecord::Tasks::DatabaseTasks.sub_db_dir
|
15
|
+
migration_template @migration_template, "#{dir}/#{db_dir}/#{file_name}.rb"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
@@ -0,0 +1,155 @@
|
|
1
|
+
|
2
|
+
# TODO: we don’t want to unconditionally load Rails as that gives too many unnecessary dependencies,
|
3
|
+
# but if we need it for something, it should be conditional dep through dep-gem or just used if present
|
4
|
+
require "rails"
|
5
|
+
require "rails/generators"
|
6
|
+
|
7
|
+
require "active_record"
|
8
|
+
require "active_record/tasks/database_tasks"
|
9
|
+
|
10
|
+
require_relative "migration_generator"
|
11
|
+
|
12
|
+
module MultiAR::Rake
|
13
|
+
|
14
|
+
# Utility that defines Rake tasks of Slam
|
15
|
+
class Tasks
|
16
|
+
#include Rake::DSL
|
17
|
+
|
18
|
+
# DSL wrapper partly copied from Rake::DSL.
|
19
|
+
module DSL
|
20
|
+
# Defines a Rake namespace (see Rake’s namespace() in dsl_definition.rb)
|
21
|
+
def self.namespace(name=nil, &block)
|
22
|
+
name = name.to_s if name.kind_of?(Symbol)
|
23
|
+
name = name.to_str if name.respond_to?(:to_str)
|
24
|
+
unless name.kind_of?(String) || name.nil?
|
25
|
+
raise ArgumentError, "Expected a String or Symbol for a namespace name"
|
26
|
+
end
|
27
|
+
Rake.application.in_namespace(name, &block)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Defines a Rake task’s description (see Rake’s desc() in dsl_definition.rb)
|
31
|
+
def self.desc(description)
|
32
|
+
Rake.application.last_description = description
|
33
|
+
end
|
34
|
+
|
35
|
+
# Defines a Rake task (see Rake’s task() in dsl_definition.rb)
|
36
|
+
def self.task(*args, &block)
|
37
|
+
Rake::Task.define_task(*args, &block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class << self
|
42
|
+
attr_accessor :databases
|
43
|
+
attr_accessor :environment
|
44
|
+
attr_accessor :common_migrations
|
45
|
+
attr_accessor :migration_dir
|
46
|
+
end
|
47
|
+
|
48
|
+
# When called, this declares Rake tasks of Slam project,
|
49
|
+
# most notably custom active record migration tasks.
|
50
|
+
def self.define
|
51
|
+
load "active_record/railties/databases.rake"
|
52
|
+
|
53
|
+
# dunno if this is any use
|
54
|
+
#task environment: 'db:load_config' do
|
55
|
+
# ActiveRecord::Base.establish_connection ActiveRecord::Tasks::DatabaseTasks.current_config
|
56
|
+
#end
|
57
|
+
|
58
|
+
DSL.namespace :db do
|
59
|
+
|
60
|
+
DSL.desc "Creates a new migration file with the specified name"
|
61
|
+
DSL.task :new_migration, :name, :options do |t, args|
|
62
|
+
name = args[:name] || ENV["name"]
|
63
|
+
options = args[:options] || ENV["options"]
|
64
|
+
|
65
|
+
raise "You need to specify exactly one database for migration generation. See --databases. Given databases: #{databases.inspect}" if databases.size != 1
|
66
|
+
|
67
|
+
unless name
|
68
|
+
generator = Rails::Generators.find_by_namespace "migration"
|
69
|
+
desc = generator.desc.gsub(/`rails (?:g|generate) migration (\w+)`/, '`rake "db:new_migration[\\1]"`' ).
|
70
|
+
gsub(/`rails (?:g|generate) migration (\w+) (.*)`/, '`rake "db:new_migration[\\1, \\2]"`' )
|
71
|
+
puts [
|
72
|
+
%Q{Usage: rake "#{t.name}[AddFieldToForm[, field[:type][:index]] field[:type][:index]]"},
|
73
|
+
desc,
|
74
|
+
].join "\n\n"
|
75
|
+
abort
|
76
|
+
end
|
77
|
+
params = [name]
|
78
|
+
params.concat options.split(' ') if options
|
79
|
+
Rails::Generators.invoke "active_record_migrations:migration", params,
|
80
|
+
behavior: :invoke, destination_root: Rails.root
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
multiple_databases_task "migrate", "db" do |database_name|
|
85
|
+
establish_connection database_name
|
86
|
+
|
87
|
+
if common_migrations
|
88
|
+
# TODO: Slam.root
|
89
|
+
path = "#{__dir__}/../../../db/migrate/#{database_name}"
|
90
|
+
ActiveRecord::Migrator.migrate path if Dir.exist? path
|
91
|
+
end
|
92
|
+
|
93
|
+
path = "#{migration_dir}/#{database_name}/"
|
94
|
+
ActiveRecord::Migrator.migrate path if Dir.exist? path
|
95
|
+
end
|
96
|
+
|
97
|
+
multiple_databases_task "create", "db" do |database_name|
|
98
|
+
establish_connection database_name
|
99
|
+
ActiveRecord::Tasks::DatabaseTasks.create_current(connection_name(database_name))
|
100
|
+
end
|
101
|
+
|
102
|
+
multiple_databases_task "rollback", "db" do |database_name|
|
103
|
+
establish_connection database_name
|
104
|
+
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
105
|
+
path = "#{migration_dir}/#{database_name}/"
|
106
|
+
ActiveRecord::Migrator.rollback(path, step) if Dir.exist? path
|
107
|
+
end
|
108
|
+
|
109
|
+
multiple_databases_task "drop", "db" do |database_name|
|
110
|
+
establish_connection database_name
|
111
|
+
ActiveRecord::Tasks::DatabaseTasks.drop_current(connection_name(database_name))
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def self.rename_task name, namespace = nil
|
118
|
+
new_name = "old_#{name}"
|
119
|
+
#new_name = "#{namespace}:#{new_name}" unless namespace.nil?
|
120
|
+
Rake::Task[name].rename(new_name)
|
121
|
+
old_comment = Rake::Task[new_name].comment
|
122
|
+
Rake::Task[new_name].clear_comments
|
123
|
+
old_comment
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.multiple_databases_task name_without_namespace, namespace = nil
|
127
|
+
name = (namespace && name) || "#{namespace}:#{name_without_namespace}"
|
128
|
+
old_comment = rename_task name, namespace
|
129
|
+
|
130
|
+
DSL.desc "Runs task #{name} for all selected databases"
|
131
|
+
DSL.task name.to_sym do
|
132
|
+
databases.each do |database_name|
|
133
|
+
Rake::Task["#{name}:#{database_name}"].invoke
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
databases.each do |database_name|
|
138
|
+
DSL.desc old_comment
|
139
|
+
DSL.task :"#{name}:#{database_name}" do
|
140
|
+
yield database_name
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.connection_name database_name
|
146
|
+
"#{database_name}_#{environment}"
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.establish_connection database_name
|
150
|
+
ActiveRecord::Base.establish_connection connection_name(database_name).to_sym
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
data/lib/multi_ar.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
require_relative "multi_ar/rake/ext"
|
4
|
+
require_relative "multi_ar/rake/tasks"
|
5
|
+
|
6
|
+
require_relative "multi_ar/database"
|
7
|
+
|
8
|
+
module MultiAR
|
9
|
+
|
10
|
+
# Base of Slam gem.
|
11
|
+
#
|
12
|
+
# Must be initialized before most actions works, that relies on Slam#app for getting configuration.
|
13
|
+
class MultiAR
|
14
|
+
|
15
|
+
attr_reader :databases
|
16
|
+
attr_reader :db_config
|
17
|
+
attr_reader :environment
|
18
|
+
|
19
|
+
class << self
|
20
|
+
# Instance of MultiAR::MultiAR, automatically assigned by MultiAR::MultiAR#new.
|
21
|
+
# Used internally in the gem, to access configuration and other internal parts.
|
22
|
+
attr_accessor :app
|
23
|
+
end
|
24
|
+
|
25
|
+
# @param databases array of available databases
|
26
|
+
# @todo config file is overriding parameters passed here... I think it should be other way around, but need more custom logic for that :/
|
27
|
+
def initialize databases:, environment: "development", config: "config/multi_ar.yaml", db_config: "config/database.yaml", common_migrations: true, migration_dir: "db/migrate"
|
28
|
+
|
29
|
+
# first load config
|
30
|
+
if File.exist? config
|
31
|
+
require "psych"
|
32
|
+
config = Psych.load_file config
|
33
|
+
b = binding
|
34
|
+
config.each do |key, value|
|
35
|
+
b.local_variable_set key.to_sym, value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# then check that we have data in format we want it to be
|
40
|
+
raise "#{db_config} is not valid path to a file. Try specifying --db-config <path> or configuring it in the configuration file." unless File.exist?(db_config)
|
41
|
+
raise "databases is not responding to :each. Try passing passing --databases <database> or configuring it in the configuration file." unless databases.respond_to? :each
|
42
|
+
|
43
|
+
@databases = databases
|
44
|
+
@db_config = db_config
|
45
|
+
@environment = environment
|
46
|
+
|
47
|
+
Database.initialize db_config: db_config, migration_dir: migration_dir
|
48
|
+
|
49
|
+
ActiveRecord::Tasks::DatabaseTasks.class_eval { attr_accessor :sub_db_dir }
|
50
|
+
ActiveRecord::Tasks::DatabaseTasks.sub_db_dir = databases.first # TODO: I don’t think this is how it should work
|
51
|
+
|
52
|
+
@rake = Rake::Application.new
|
53
|
+
Rake.application = @rake
|
54
|
+
@rake.init
|
55
|
+
Rake::TaskManager.record_task_metadata = true
|
56
|
+
|
57
|
+
RakeTasks.databases = databases
|
58
|
+
RakeTasks.environment = environment
|
59
|
+
RakeTasks.common_migrations = common_migrations
|
60
|
+
RakeTasks.migration_dir = migration_dir
|
61
|
+
RakeTasks.define
|
62
|
+
|
63
|
+
MultiAR.app = self
|
64
|
+
end
|
65
|
+
|
66
|
+
# @todo this shows rake in start of the command, we want to show multi_ar instead.
|
67
|
+
def list_tasks all_rake_tasks: false
|
68
|
+
@rake.options.show_all_tasks = true if all_rake_tasks
|
69
|
+
@rake.options.show_tasks = :tasks
|
70
|
+
@rake.options.show_task_pattern = // # all tasks; we don’t have support for string-matching tasks
|
71
|
+
@rake.display_tasks_and_comments
|
72
|
+
end
|
73
|
+
|
74
|
+
def rake_task task_name
|
75
|
+
@rake.invoke_task task_name
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# For convenience, it may make shorter namespace.
|
81
|
+
Mar = MultiAR # TODO: there is Mar gem, maybe we should avoid this to avoid conflicts?
|
82
|
+
MultiAr = MultiAR
|
data.tar.gz.sig
ADDED
Binary file
|
metadata
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: multi_ar
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0.pre.rc1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Samu Voutilainen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain:
|
11
|
+
- |
|
12
|
+
-----BEGIN CERTIFICATE-----
|
13
|
+
MIIDWDCCAkCgAwIBAgIBATANBgkqhkiG9w0BAQUFADA5MQ0wCwYDVQQDDARzbWFy
|
14
|
+
MRQwEgYKCZImiZPyLGQBGRYEc21hcjESMBAGCgmSJomT8ixkARkWAmZpMB4XDTE1
|
15
|
+
MTAwMTEzNTgyMloXDTE2MDkzMDEzNTgyMlowOTENMAsGA1UEAwwEc21hcjEUMBIG
|
16
|
+
CgmSJomT8ixkARkWBHNtYXIxEjAQBgoJkiaJk/IsZAEZFgJmaTCCASIwDQYJKoZI
|
17
|
+
hvcNAQEBBQADggEPADCCAQoCggEBAPEmTZJAAOZgj1DJHKkofM61lXBIddQ4XzEQ
|
18
|
+
H1xhaQOa5B73KCexYphvMx+/leDB1MoPSuhzMmYcPmrKK5mcG083VFa3RmVsQMFt
|
19
|
+
/XeTdKmNDl3/zZlGlMIfKCHRWCva9wNJBfxwPiq9r5EmCrlbu5RL7repfGCfnxap
|
20
|
+
TW9xbmpc7ox/nHTxuoS3/62YIcnZZ6ogt5im3fCW5iBWmNjfCL7KjfqNDA7F5ubq
|
21
|
+
leOtQxhO+FmgmnnbQy3GosSowEtGVwwmq6ZfOfXpCuVtRrh1untbIteit+azhwGc
|
22
|
+
/5K/Ti9VBJ3+3z+JA6gixDwpOw6KbYg6HK2yH8TLMSuANAcg/gECAwEAAaNrMGkw
|
23
|
+
CQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFBN3c/APp9RBTNfpEA2/
|
24
|
+
AIUeI6oaMBcGA1UdEQQQMA6BDHNtYXJAc21hci5maTAXBgNVHRIEEDAOgQxzbWFy
|
25
|
+
QHNtYXIuZmkwDQYJKoZIhvcNAQEFBQADggEBAG5vbcLY9EkJH4TyJVdI/gUo8XE5
|
26
|
+
6J2s7yicIy2jBJWu7WGgSB7HfTw7WWhSbcQp0aKTa7ahowzQBqiGlYByhfunav7R
|
27
|
+
/rVBTlrvLMnqR/cQxk0L6TDzssxGaed5RSN/9aajZgl1uOTSsUEFILQI4OfZB21i
|
28
|
+
y/c3cPGVipOwwz+IIKpl8ss3pKAeB3B7k9Xd9DDf6XrGA0+ztEaAIcLED06vwifg
|
29
|
+
Ws73WZ+F+DOnfopIMUaeYUzKyUG+59p17ls//xzTouiLjcC9ee5ZaC9e+TzYsp4t
|
30
|
+
ofnwRrqEHVW+zRWs/VIwm70F2Jnl5eSc3MjyhpWIC0eGFXtBY1XYCrHeCdQ=
|
31
|
+
-----END CERTIFICATE-----
|
32
|
+
date: 2015-10-01 00:00:00.000000000 Z
|
33
|
+
dependencies:
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: trollop
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.1'
|
41
|
+
type: :runtime
|
42
|
+
prerelease: false
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.1'
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: activerecord
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rails
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4'
|
69
|
+
type: :runtime
|
70
|
+
prerelease: false
|
71
|
+
version_requirements: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '4'
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: railties
|
78
|
+
requirement: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '4'
|
83
|
+
type: :runtime
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '4'
|
90
|
+
- !ruby/object:Gem::Dependency
|
91
|
+
name: rake
|
92
|
+
requirement: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '10.4'
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: 10.4.2
|
100
|
+
type: :runtime
|
101
|
+
prerelease: false
|
102
|
+
version_requirements: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - "~>"
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '10.4'
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 10.4.2
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: migration_comments
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - "~>"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 0.3.2
|
117
|
+
type: :runtime
|
118
|
+
prerelease: false
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: 0.3.2
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: safe_attributes
|
126
|
+
requirement: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - "~>"
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '1.0'
|
131
|
+
type: :runtime
|
132
|
+
prerelease: false
|
133
|
+
version_requirements: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - "~>"
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '1.0'
|
138
|
+
description: |-
|
139
|
+
Migration support and some other relevant utilities implemented using ActiveRecord
|
140
|
+
4.
|
141
|
+
email: smar@smar.fi
|
142
|
+
executables:
|
143
|
+
- multi_ar
|
144
|
+
- mar
|
145
|
+
extensions: []
|
146
|
+
extra_rdoc_files: []
|
147
|
+
files:
|
148
|
+
- bin/mar
|
149
|
+
- bin/multi_ar
|
150
|
+
- lib/multi_ar.rb
|
151
|
+
- lib/multi_ar/database.rb
|
152
|
+
- lib/multi_ar/interface.rb
|
153
|
+
- lib/multi_ar/multi_ar_model.rb
|
154
|
+
- lib/multi_ar/rake/ext.rb
|
155
|
+
- lib/multi_ar/rake/migration_generator.rb
|
156
|
+
- lib/multi_ar/rake/tasks.rb
|
157
|
+
- lib/multi_ar/version.rb
|
158
|
+
homepage: http://smarre.github.io/multi_ar/
|
159
|
+
licenses:
|
160
|
+
- MIT
|
161
|
+
metadata: {}
|
162
|
+
post_install_message:
|
163
|
+
rdoc_options: []
|
164
|
+
require_paths:
|
165
|
+
- lib
|
166
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
167
|
+
requirements:
|
168
|
+
- - ">="
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: '0'
|
171
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
172
|
+
requirements:
|
173
|
+
- - ">"
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: 1.3.1
|
176
|
+
requirements: []
|
177
|
+
rubyforge_project:
|
178
|
+
rubygems_version: 2.4.5.1
|
179
|
+
signing_key:
|
180
|
+
specification_version: 4
|
181
|
+
summary: Multi database migrations and utilities for ActiveRecord
|
182
|
+
test_files: []
|
183
|
+
has_rdoc:
|
metadata.gz.sig
ADDED
Binary file
|