cassandra_migrate 0.0.1
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 +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +84 -0
- data/Rakefile +1 -0
- data/bin/cassandra_migrate +42 -0
- data/cassandra_migrate.gemspec +26 -0
- data/lib/cassandra_migrate.rb +220 -0
- data/lib/cassandra_migrate/version.rb +5 -0
- metadata +137 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Noah Gibbs
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# Cassandra Migrate
|
2
|
+
|
3
|
+
This gem is designed to allow Cassandra migrations in very roughly the
|
4
|
+
style of Rails migrations, but with a few extra features... And
|
5
|
+
without the Rails-style DSL for running the migrations. CQL is
|
6
|
+
basically fine. But we *do* want Erb!
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
gem 'cassandra_migrate'
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install cassandra_migrate
|
21
|
+
|
22
|
+
You don't have to use cassandra_migrate as part of an app, but you'll
|
23
|
+
need a recent (1.9.2+) Ruby with Rubygems.
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
To run migrations from the current directory if you have them:
|
28
|
+
|
29
|
+
> cassandra_migrate latest
|
30
|
+
|
31
|
+
You can also migrate to a filename or a date string, either of which
|
32
|
+
will use the date as the important part -- you'll migrate forward or
|
33
|
+
back until the specified migration is the last one performed. You can
|
34
|
+
also roll back a single migration:
|
35
|
+
|
36
|
+
> cassandra_migrate rollback
|
37
|
+
|
38
|
+
See other options:
|
39
|
+
|
40
|
+
> cassandra_migrate --help
|
41
|
+
|
42
|
+
## Writing Migrations
|
43
|
+
|
44
|
+
You'll need a directory for Cassandra migrations. Every migration
|
45
|
+
should have a filename of the form:
|
46
|
+
|
47
|
+
20131023000000_create_keyspace_argus_up.cql.erb
|
48
|
+
|
49
|
+
The first fourteen digits are the date in YYYYMMDD format, followed
|
50
|
+
by six digits of your choice -- base them on time, or just make sure
|
51
|
+
they don't conflict. You can't have two migrations with exactly the
|
52
|
+
same fourteen-digit time code!
|
53
|
+
|
54
|
+
Then you can use a freeform description, like "create_keyspace_argus"
|
55
|
+
above. Then an action, like "up" or "down" (later, scripts as well),
|
56
|
+
and one or more extensions to tell Cassandra Migrate how to use the
|
57
|
+
file. Most commonly you'll want .cql or .cql.erb as the extension.
|
58
|
+
Such files will be run through Cassandra, optionally after Erubis
|
59
|
+
processing.
|
60
|
+
|
61
|
+
Here's an example that uses Erb, in this case to set the replication
|
62
|
+
factor of the keyspace via an environment variable:
|
63
|
+
|
64
|
+
~~~
|
65
|
+
# 20131024001100_create_keyspace_cryptic_up.cql.erb
|
66
|
+
CREATE KEYSPACE "cryptic" WITH REPLICATION =
|
67
|
+
{ 'class' : 'SimpleStrategy', 'replication_factor' : <%= ENV['CASS_REPLICATION'] || 1 %> };
|
68
|
+
~~~
|
69
|
+
|
70
|
+
## Contributing
|
71
|
+
|
72
|
+
1. Fork it
|
73
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
74
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
75
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
76
|
+
5. Create new Pull Request
|
77
|
+
|
78
|
+
## Future Directions
|
79
|
+
|
80
|
+
A cassandra_migrate_rails gem could add generators for simple
|
81
|
+
Cassandra migrations from Rails.
|
82
|
+
|
83
|
+
We could add Ruby, bash or other scripts/executables to be run before
|
84
|
+
and after migrations, or as the migration itself.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Copyright (C) 2013 OL2, inc. See LICENSE.txt for details.
|
3
|
+
|
4
|
+
require "trollop"
|
5
|
+
require "cassandra_migrate"
|
6
|
+
|
7
|
+
OPTS = Trollop::options do
|
8
|
+
banner <<-BANNER
|
9
|
+
Migrate Cassandra to latest revision, based on your directory of migrations.
|
10
|
+
|
11
|
+
Usage: cassandra_migrate [options] [target_migration_date_or_file|latest|rollback]
|
12
|
+
BANNER
|
13
|
+
opt :migration_dir, "Directory of Cassandra migrations", :type => String, :default => "cassandra_migrations"
|
14
|
+
opt :host, "Cassandra host", :type => String, :default => "localhost"
|
15
|
+
opt :port, "Cassandra port", :type => Integer, :default => 9042
|
16
|
+
opt :dry_run, "Dry run, print Cassandra commands"
|
17
|
+
end
|
18
|
+
|
19
|
+
Trollop::die "Must specify no more than one argument: date, filename, latest or rollback!" if ARGV.size > 1
|
20
|
+
|
21
|
+
arg = ARGV.size > 0 ? ARGV[0] : "latest"
|
22
|
+
|
23
|
+
migrate = CassandraMigrate.new
|
24
|
+
|
25
|
+
# Pass arguments along to the migrate object
|
26
|
+
[:host, :port, :migration_dir].each do |arg|
|
27
|
+
migrate.send "#{arg}=", OPTS[arg]
|
28
|
+
end
|
29
|
+
|
30
|
+
options = {}
|
31
|
+
options[:dry_run] = OPTS[:dry_run]
|
32
|
+
|
33
|
+
case arg
|
34
|
+
when "latest"
|
35
|
+
migrate.to_latest options
|
36
|
+
when "rollback"
|
37
|
+
migrate.rollback options
|
38
|
+
when proc { arg =~ /^(\d{14})/ }
|
39
|
+
migrate.to_target $1, options
|
40
|
+
else
|
41
|
+
raise "Didn't recognize argument as a 14-digit date string, a migration pathname, 'latest' or 'rollback': #{arg.inspect}!"
|
42
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cassandra_migrate/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cassandra_migrate"
|
8
|
+
spec.version = CassandraMigrate::VERSION
|
9
|
+
spec.authors = ["Noah Gibbs"]
|
10
|
+
spec.email = ["noah.gibbs@onlive.com"]
|
11
|
+
spec.description = %q{Migrations for Cassandra in CQL and Erb.}
|
12
|
+
spec.summary = %q{Migrations for Cassandra in CQL and Erb.}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_runtime_dependency "trollop"
|
24
|
+
spec.add_runtime_dependency "cql-rb"
|
25
|
+
spec.add_runtime_dependency "erubis"
|
26
|
+
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
# Copyright (C) 2013 OL2, inc. See LICENSE.txt for details.
|
2
|
+
|
3
|
+
require "cassandra_migrate/version"
|
4
|
+
|
5
|
+
require "cql"
|
6
|
+
require "erubis"
|
7
|
+
|
8
|
+
require "digest/sha1"
|
9
|
+
|
10
|
+
class CassandraMigrate
|
11
|
+
attr_accessor :host
|
12
|
+
attr_accessor :port
|
13
|
+
attr_accessor :migration_dir
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def cql_client
|
18
|
+
return @cassandra_client if @cassandra_client
|
19
|
+
|
20
|
+
STDERR.puts "Connecting to Cassandra: #{host.inspect} / #{port.inspect}"
|
21
|
+
@cassandra_client = Cql::Client.connect(hosts: [host].flatten, port: port, consistency: :quorum)
|
22
|
+
|
23
|
+
@cassandra_client
|
24
|
+
end
|
25
|
+
|
26
|
+
def execute_cql(cql, options = {})
|
27
|
+
if options[:dry_run]
|
28
|
+
puts "Dry run, execute: #{cql}"
|
29
|
+
return
|
30
|
+
end
|
31
|
+
|
32
|
+
last_result = nil
|
33
|
+
# Can only execute single chunks at once
|
34
|
+
cql.split(";").map(&:strip).select {|s| s != ""}.each do |statement|
|
35
|
+
# Prep-then-execute so that a syntax error will be detectable as such
|
36
|
+
last_result = cql_client.execute statement
|
37
|
+
puts "Executing CQL: #{statement}"
|
38
|
+
end
|
39
|
+
|
40
|
+
last_result
|
41
|
+
end
|
42
|
+
|
43
|
+
def migrations_in_dir(refresh = false)
|
44
|
+
return @migrations_in_dir if @migrations_in_dir && !refresh
|
45
|
+
|
46
|
+
@migrations_in_dir = {}
|
47
|
+
Dir[File.join migration_dir, "*"].each do |file|
|
48
|
+
unless File.basename(file) =~ /^(\d{14})_/
|
49
|
+
puts "No match: #{file.inspect}"
|
50
|
+
next
|
51
|
+
end
|
52
|
+
|
53
|
+
unless /^(?<date_str>\d{14})_(?<desc>[^.]+)_(?<action>[^_.]+)(?<extensions>\..*)$/ =~ File.basename(file)
|
54
|
+
puts "No match with regexp: #{file.inspect}"
|
55
|
+
next
|
56
|
+
end
|
57
|
+
|
58
|
+
@migrations_in_dir[date_str] ||= {}
|
59
|
+
migration = @migrations_in_dir[date_str]
|
60
|
+
migration[:actions] ||= {}
|
61
|
+
|
62
|
+
if migration[:desc] && migration[:desc] != desc
|
63
|
+
raise "Only one migration name per date string! #{desc.inspect} != #{migration[:desc].inspect}"
|
64
|
+
end
|
65
|
+
migration[:desc] = desc
|
66
|
+
|
67
|
+
migration[:actions][action.to_sym] = {
|
68
|
+
file: file
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
raise "No migrations in directory #{migration_dir.inspect}! Did you mean to specify a migration directory?" if @migrations_in_dir.empty?
|
73
|
+
|
74
|
+
@migrations_in_dir
|
75
|
+
end
|
76
|
+
|
77
|
+
def ensure_schema_keyspace_exists(options = {})
|
78
|
+
ks = execute_cql "SELECT keyspace_name FROM system.schema_keyspaces WHERE keyspace_name = 'schema';"
|
79
|
+
|
80
|
+
if ks.empty?
|
81
|
+
raise "No schema keyspace in a dry run!" if options[:dry_run]
|
82
|
+
|
83
|
+
peers = execute_cql "SELECT peer FROM system.peers;"
|
84
|
+
|
85
|
+
@replication = [3, peers.to_a.size + 1].min
|
86
|
+
execute_cql <<-MIGRATION, options
|
87
|
+
CREATE KEYSPACE "schema" WITH REPLICATION =
|
88
|
+
{ 'class' : 'SimpleStrategy', 'replication_factor' : #{@replication} };
|
89
|
+
MIGRATION
|
90
|
+
end
|
91
|
+
|
92
|
+
cf = execute_cql "SELECT columnfamily_name FROM system.schema_columnfamilies WHERE columnfamily_name = 'migrations' AND keyspace_name = 'schema';"
|
93
|
+
if cf.empty?
|
94
|
+
raise "No migration table in a dry run!" if options[:dry_run]
|
95
|
+
|
96
|
+
execute_cql <<-MIGRATION
|
97
|
+
CREATE TABLE "schema"."migrations" (
|
98
|
+
"date_string" varchar,
|
99
|
+
"up_filename" varchar,
|
100
|
+
"sha1" varchar,
|
101
|
+
PRIMARY KEY ("date_string", "up_filename"));
|
102
|
+
MIGRATION
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def migrations_completed(refresh = false, options = {})
|
107
|
+
return @migrations_completed if @migrations_completed && !refresh
|
108
|
+
|
109
|
+
ensure_schema_keyspace_exists(options)
|
110
|
+
|
111
|
+
@migrations_completed = {}
|
112
|
+
|
113
|
+
migrations = execute_cql 'SELECT * FROM "schema"."migrations";'
|
114
|
+
migrations.each do |migration|
|
115
|
+
@migrations_completed[migration["date_string"]] = migration.to_hash
|
116
|
+
end
|
117
|
+
|
118
|
+
@migrations_completed
|
119
|
+
end
|
120
|
+
|
121
|
+
def sha1(path)
|
122
|
+
Digest::SHA1.hexdigest File.read path
|
123
|
+
end
|
124
|
+
|
125
|
+
def execute_migration_file(path, options)
|
126
|
+
ensure_schema_keyspace_exists(options)
|
127
|
+
|
128
|
+
STDERR.puts "Executing migration file: #{path.inspect}"
|
129
|
+
|
130
|
+
components = File.basename(path).split(".")
|
131
|
+
components.shift # Take just the extensions
|
132
|
+
|
133
|
+
content = File.read path
|
134
|
+
|
135
|
+
while components.size > 1
|
136
|
+
ext = components.pop
|
137
|
+
|
138
|
+
if ext == "erb" || ext == "erubis"
|
139
|
+
eruby = Erubis::Eruby.new content
|
140
|
+
content = eruby.result :replication => @replication
|
141
|
+
else
|
142
|
+
raise "Unknown intermediate extension in path #{path.inspect}: #{ext.inspect}!"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
final_type = components.first
|
147
|
+
if ["cql", "cqlsh"].include?(final_type)
|
148
|
+
execute_cql content, options
|
149
|
+
elsif ["erb", "erubis"].include?(final_type)
|
150
|
+
raise "Can't use erb as the final extension in path #{path.inspect}!"
|
151
|
+
else
|
152
|
+
raise "Unknown extension #{final_type.inspect} in path #{path.inspect}!"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
public
|
157
|
+
|
158
|
+
def up(date_str, options = {})
|
159
|
+
raise "Can't apply migration #{date_str} that already happened!" if migrations_completed(false,options)[date_str]
|
160
|
+
raise "Can't apply migration #{date_str} that has no migration files!" unless migrations_in_dir[date_str]
|
161
|
+
raise "Can't apply migration #{date_str} with no up migration!" unless migrations_in_dir[date_str][:actions][:up]
|
162
|
+
|
163
|
+
up_filename = migrations_in_dir[date_str][:actions][:up][:file]
|
164
|
+
execute_migration_file up_filename, options
|
165
|
+
execute_cql "INSERT INTO \"schema\".\"migrations\" (date_string, up_filename, sha1) VALUES ('#{date_str}', '#{up_filename}', '#{sha1 up_filename}')", options
|
166
|
+
end
|
167
|
+
|
168
|
+
def down(date_str, options = {})
|
169
|
+
raise "Can't reverse migration #{date_str} that didn't happen!" unless migrations_completed(false,options)[date_str]
|
170
|
+
raise "Can't reverse migration #{date_str} that has no migration files!" unless migrations_in_dir[date_str]
|
171
|
+
raise "Can't reverse migration #{date_str} with no down migration!" unless migrations_in_dir[date_str][:actions][:down]
|
172
|
+
|
173
|
+
execute_migration_file migrations_in_dir[date_str][:actions][:down][:file], options
|
174
|
+
execute_cql "DELETE FROM \"schema\".\"migrations\" WHERE date_string = '#{date_str}';", options
|
175
|
+
end
|
176
|
+
|
177
|
+
def up_to(date_str, options = {})
|
178
|
+
uncompleted_dates = migrations_in_dir.keys - migrations_completed(false,options).keys
|
179
|
+
|
180
|
+
STDERR.puts "Uncompleted: #{uncompleted_dates.inspect}"
|
181
|
+
migrations_to_run = uncompleted_dates.select { |d| d <= date_str }
|
182
|
+
|
183
|
+
STDERR.puts "Run #{migrations_to_run.size} migrations, update to #{date_str}."
|
184
|
+
migrations_to_run.each { |m| up(m, options) }
|
185
|
+
end
|
186
|
+
|
187
|
+
def down_to(date_str, options = {})
|
188
|
+
migrations_to_run = migrations_completed(false,options).keys.select { |d| d > date_str }
|
189
|
+
|
190
|
+
STDERR.puts "Run #{migrations_to_run.size} migrations, roll back to #{date_str}."
|
191
|
+
migrations_to_run.each { |m| down(m, options) }
|
192
|
+
end
|
193
|
+
|
194
|
+
def current_latest(options = {})
|
195
|
+
migrations_completed(false,options).keys.max
|
196
|
+
end
|
197
|
+
|
198
|
+
def latest_in_directory
|
199
|
+
migrations_in_dir.keys.max
|
200
|
+
end
|
201
|
+
|
202
|
+
def to_latest(options = {})
|
203
|
+
latest = latest_in_directory
|
204
|
+
raise "No latest migration!" unless latest
|
205
|
+
up_to latest, options
|
206
|
+
end
|
207
|
+
|
208
|
+
def to_target(date_str, options = {})
|
209
|
+
if date_str < current_latest(options)
|
210
|
+
down_to date_str, options
|
211
|
+
else
|
212
|
+
up_to date_str, options
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def rollback(options = {})
|
217
|
+
down(current_latest(options), options)
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
metadata
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cassandra_migrate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Noah Gibbs
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-12-17 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.3'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.3'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: trollop
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: cql-rb
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: erubis
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: Migrations for Cassandra in CQL and Erb.
|
95
|
+
email:
|
96
|
+
- noah.gibbs@onlive.com
|
97
|
+
executables:
|
98
|
+
- cassandra_migrate
|
99
|
+
extensions: []
|
100
|
+
extra_rdoc_files: []
|
101
|
+
files:
|
102
|
+
- .gitignore
|
103
|
+
- Gemfile
|
104
|
+
- LICENSE.txt
|
105
|
+
- README.md
|
106
|
+
- Rakefile
|
107
|
+
- bin/cassandra_migrate
|
108
|
+
- cassandra_migrate.gemspec
|
109
|
+
- lib/cassandra_migrate.rb
|
110
|
+
- lib/cassandra_migrate/version.rb
|
111
|
+
homepage: ''
|
112
|
+
licenses:
|
113
|
+
- MIT
|
114
|
+
post_install_message:
|
115
|
+
rdoc_options: []
|
116
|
+
require_paths:
|
117
|
+
- lib
|
118
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
119
|
+
none: false
|
120
|
+
requirements:
|
121
|
+
- - ! '>='
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
|
+
none: false
|
126
|
+
requirements:
|
127
|
+
- - ! '>='
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
requirements: []
|
131
|
+
rubyforge_project:
|
132
|
+
rubygems_version: 1.8.25
|
133
|
+
signing_key:
|
134
|
+
specification_version: 3
|
135
|
+
summary: Migrations for Cassandra in CQL and Erb.
|
136
|
+
test_files: []
|
137
|
+
has_rdoc:
|