syncoku 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.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +80 -0
- data/Rakefile +2 -0
- data/bin/syncoku +8 -0
- data/lib/syncoku/capture_backup.rb +21 -0
- data/lib/syncoku/control.rb +52 -0
- data/lib/syncoku/local.rb +26 -0
- data/lib/syncoku/local_db.rb +112 -0
- data/lib/syncoku/remote.rb +35 -0
- data/lib/syncoku/remote_db.rb +31 -0
- data/lib/syncoku/runnable.rb +26 -0
- data/lib/syncoku/s3.rb +93 -0
- data/lib/syncoku/version.rb +3 -0
- data/lib/syncoku.rb +14 -0
- data/syncoku.gemspec +23 -0
- metadata +104 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f4fb8a94d545cfbd3ceca353015892221e9cb754
|
4
|
+
data.tar.gz: b2d8fd4509402e592ae9f70ce314402018b530c2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0e6aa7c4c8d0c6152069c95f517a954f7d5af33a7cf674220ab575998c82c6d285fd4e99b854bfdf54ed0e8d0db73cdca01082a35c5ec523e0b94abc59196896
|
7
|
+
data.tar.gz: e02b9ab5796c8b1abd3fcb8c03dc754b4d9b70677291cbf9c3854a2cdc56e69b4c00148142a3ecaf583589dc3902b2f5227e191195dc773db282b36f612511cc
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Bill Horsman
|
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,80 @@
|
|
1
|
+
# Syncoku
|
2
|
+
|
3
|
+
Copies a production Heroku Postgresql database to the local development database or a staging Heroku database. Optionally syncs the production S3 bucket with another bucket.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'syncoku'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install syncoku
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
To copy production to your local development database:
|
24
|
+
```
|
25
|
+
syncoku
|
26
|
+
```
|
27
|
+
|
28
|
+
If you have S3 configured it will do the database and S3. To choose just one of those:
|
29
|
+
```
|
30
|
+
syncoku db
|
31
|
+
syncoku s3
|
32
|
+
```
|
33
|
+
|
34
|
+
To target the staging environment:
|
35
|
+
```
|
36
|
+
syncoku staging
|
37
|
+
```
|
38
|
+
|
39
|
+
or more simply:
|
40
|
+
```
|
41
|
+
syncoku s
|
42
|
+
```
|
43
|
+
|
44
|
+
## Downloading the database (locally)
|
45
|
+
|
46
|
+
It will capture a backup of the database and download it to a local file called `.syncoku.dump`. If you run Syncoku a second time and it discovers this file then it will give you the option of reusing it or downloading a new one. Reusing the existing one comes in useful if you have messed around with the local database and want to clean it up.
|
47
|
+
|
48
|
+
## Hooks
|
49
|
+
|
50
|
+
If you define a rake task called `syncoku:after_sync` then it will automatically be run after the database has been restored and migrated. This is a good place to put anonymization tasks, for instance.
|
51
|
+
|
52
|
+
## S3
|
53
|
+
|
54
|
+
If you add a file called `syncoku.yml` with the following information, it can sync between S3 buckets too:
|
55
|
+
|
56
|
+
```
|
57
|
+
# syncoku.yml
|
58
|
+
s3:
|
59
|
+
access_key_id: "ABCDEFGH123456789"
|
60
|
+
secret_access_key: "a1secret2key3to4access5s3"
|
61
|
+
|
62
|
+
development:
|
63
|
+
bucket: "my-bucket-development"
|
64
|
+
|
65
|
+
staging:
|
66
|
+
bucket: "my-bucket-staging"
|
67
|
+
|
68
|
+
production:
|
69
|
+
bucket: "my-bucket-production"
|
70
|
+
```
|
71
|
+
|
72
|
+
*Note:* a limitation is that that the buckets must use the same credentials.
|
73
|
+
|
74
|
+
## Contributing
|
75
|
+
|
76
|
+
1. Fork it ( https://github.com/billhorsman/syncoku/fork )
|
77
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
78
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
79
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
80
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/syncoku
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Syncoku
|
2
|
+
module CaptureBackup
|
3
|
+
include Runnable
|
4
|
+
|
5
|
+
def capture
|
6
|
+
puts "Capturing #{production_app_name} backup..."
|
7
|
+
run_on_production("pgbackups:capture --expire")
|
8
|
+
run_on_production("pgbackups:url")
|
9
|
+
end
|
10
|
+
|
11
|
+
def run_on_production(command)
|
12
|
+
run_command "heroku #{command} --app #{production_app_name}"
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def production_app_name
|
17
|
+
@production_app_name ||= run_command("git remote -v | grep production | grep push").match(/heroku[^:]*:(.*)\.git/)[1]
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Syncoku
|
2
|
+
|
3
|
+
module Control
|
4
|
+
extend Syncoku::Runnable
|
5
|
+
|
6
|
+
def self.run(args)
|
7
|
+
matching_remotes = remotes & args
|
8
|
+
if matching_remotes.size == 0 && remote_index_uniq?
|
9
|
+
if key = (remote_index.keys & args)[0]
|
10
|
+
matching_remotes = [remote_index[key]]
|
11
|
+
args.delete key
|
12
|
+
end
|
13
|
+
end
|
14
|
+
target = case matching_remotes.compact.size
|
15
|
+
when 0
|
16
|
+
Syncoku::Local.new
|
17
|
+
when 1
|
18
|
+
remote = matching_remotes[0]
|
19
|
+
args.delete remote
|
20
|
+
Syncoku::Remote.new(remote)
|
21
|
+
else
|
22
|
+
puts "Please choose just one remote out of #{remotes.join(" or ")}"
|
23
|
+
exit 1
|
24
|
+
end
|
25
|
+
commands = %w[both db s3 rebuild] & args
|
26
|
+
commands << "both" if commands.size == 0
|
27
|
+
if commands.size > 1
|
28
|
+
puts "Choose just one command"
|
29
|
+
exit 1
|
30
|
+
else
|
31
|
+
args.delete commands[0]
|
32
|
+
target.send(commands[0], args)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.remotes
|
37
|
+
@remotes ||= run_command("git remote -v | grep heroku | grep push").split("\n").map {|line|
|
38
|
+
line.match(/^(.*)\t/)[1]
|
39
|
+
}.reject {|r| r == "production" || r == "heroku" }
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.remote_index_uniq?
|
43
|
+
remote_index.size == remotes.size
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.remote_index
|
47
|
+
@remote_index ||= Hash[remotes.map{|r| [r.slice(0, 1), r] }]
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Syncoku
|
2
|
+
|
3
|
+
# Responsible for syncing to a local app
|
4
|
+
class Local
|
5
|
+
include Runnable
|
6
|
+
include CaptureBackup
|
7
|
+
|
8
|
+
def both(args)
|
9
|
+
db(args)
|
10
|
+
s3(args) if S3.config?
|
11
|
+
end
|
12
|
+
|
13
|
+
def db(args)
|
14
|
+
Syncoku::LocalDb.new.sync
|
15
|
+
end
|
16
|
+
|
17
|
+
def s3(args)
|
18
|
+
Syncoku::S3.new(:development).sync
|
19
|
+
end
|
20
|
+
|
21
|
+
def rebuild(args)
|
22
|
+
Syncoku::LocalDb.new.rebuild
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Syncoku
|
2
|
+
|
3
|
+
class LocalDb
|
4
|
+
include Runnable
|
5
|
+
include CaptureBackup
|
6
|
+
|
7
|
+
def sync
|
8
|
+
if File.exist?("#{dump_filename}")
|
9
|
+
ask_to_download
|
10
|
+
else
|
11
|
+
download
|
12
|
+
end
|
13
|
+
drop_and_create
|
14
|
+
pg_restore
|
15
|
+
migrate
|
16
|
+
run_hook 'after_sync'
|
17
|
+
`touch tmp/restart.txt`
|
18
|
+
end
|
19
|
+
|
20
|
+
def rebuild
|
21
|
+
kill_connections
|
22
|
+
puts "Rebuilding database"
|
23
|
+
run_command "bundle exec rake db:drop db:create db:migrate"
|
24
|
+
puts "Seeding"
|
25
|
+
run_command "bundle exec rake db:seed"
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def run_hook(name)
|
31
|
+
if test_command "rake syncoku:#{name}"
|
32
|
+
puts "Running #{name} hook"
|
33
|
+
run_command "bundle exec rake syncoku:#{name}"
|
34
|
+
else
|
35
|
+
puts "Skipping #{name} hook. Define a Rake task called syncoku:#{name} to activate."
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def ask_to_download
|
40
|
+
print "Found existing #{dump_filename}. Choose:\n D = download new backup, or\n R = reuse existing backup\nPress D or R or anything else to abort: "
|
41
|
+
proceed = STDIN.getch.downcase
|
42
|
+
puts proceed
|
43
|
+
if proceed == 'd'
|
44
|
+
download
|
45
|
+
elsif proceed == 'r'
|
46
|
+
puts "OK, reusing backup"
|
47
|
+
else
|
48
|
+
exit 1
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def download
|
53
|
+
run_command "curl -o #{dump_filename} \"#{capture}\""
|
54
|
+
end
|
55
|
+
|
56
|
+
def kill_connections
|
57
|
+
pids = `ps x|grep postgres|grep #{database_config["database"]} | grep -v 'grep' | cut -b 1,2,3,4,5,6`.gsub(/[^0-9]/, ' ').split(' ')
|
58
|
+
if pids.any?
|
59
|
+
puts "Killing #{pids.size} Postgres connection(s) (#{pids.join(", ")})"
|
60
|
+
pids.each do |pid|
|
61
|
+
`kill #{pid}`
|
62
|
+
end
|
63
|
+
else
|
64
|
+
puts "No connections to kill"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def drop_and_create
|
69
|
+
kill_connections
|
70
|
+
puts "Dropping and recreating #{database_name} database"
|
71
|
+
run_command "bundle exec rake db:drop db:create"
|
72
|
+
end
|
73
|
+
|
74
|
+
def migrate
|
75
|
+
run_command "bundle exec rake db:migrate"
|
76
|
+
end
|
77
|
+
|
78
|
+
def pg_restore
|
79
|
+
puts "Restoring database from #{dump_filename}"
|
80
|
+
options = []
|
81
|
+
options << "--verbose"
|
82
|
+
options << "--clean"
|
83
|
+
options << "--no-acl"
|
84
|
+
options << "--no-owner"
|
85
|
+
options << "--username=#{database_config["user"]}" if database_config["user"]
|
86
|
+
options << "--password=#{database_config["password"]}" if database_config["password"]
|
87
|
+
options << "--dbname=#{database_name}"
|
88
|
+
options << "--port=#{database_config["port"] || "5432"}"
|
89
|
+
output = `pg_restore #{options.join(' ')} #{dump_filename} 2> /dev/null`
|
90
|
+
if output =~ /a transfer is currently in progress/
|
91
|
+
puts "It looks like a backup is already in progress (or possibly stuck):"
|
92
|
+
puts output
|
93
|
+
`heroku pgbackups --app #{production_app}`
|
94
|
+
puts "Use pgbackups:destroy to remove the offending backup (or wait a bit to see if it fixes itself)"
|
95
|
+
exit 1
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def database_name
|
100
|
+
database_config["database"]
|
101
|
+
end
|
102
|
+
|
103
|
+
def database_config
|
104
|
+
YAML.load(File.read("config/database.yml"))["development"]
|
105
|
+
end
|
106
|
+
|
107
|
+
def dump_filename
|
108
|
+
".syncoku.dump"
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Syncoku
|
2
|
+
|
3
|
+
# Responsible for syncing to a remote app
|
4
|
+
class Remote
|
5
|
+
include Runnable
|
6
|
+
|
7
|
+
attr_reader :remote
|
8
|
+
|
9
|
+
def initialize(remote)
|
10
|
+
@remote = remote
|
11
|
+
end
|
12
|
+
|
13
|
+
def both(args)
|
14
|
+
db(args)
|
15
|
+
s3(args) if S3.config?
|
16
|
+
end
|
17
|
+
|
18
|
+
def db(args)
|
19
|
+
Syncoku::RemoteDb.new(app_name).sync
|
20
|
+
end
|
21
|
+
|
22
|
+
def s3(args)
|
23
|
+
Syncoku::S3.new(remote).sync
|
24
|
+
end
|
25
|
+
|
26
|
+
def rebuild(args)
|
27
|
+
puts "Rebuild not implemented"
|
28
|
+
end
|
29
|
+
|
30
|
+
def app_name
|
31
|
+
@app_name ||= run_command("git remote -v | grep #{remote} | grep push").match(/heroku\.com:(.*)\.git/)[1]
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Syncoku
|
2
|
+
|
3
|
+
class RemoteDb
|
4
|
+
include Runnable
|
5
|
+
include CaptureBackup
|
6
|
+
|
7
|
+
attr_reader :app_name
|
8
|
+
|
9
|
+
def initialize(app_name)
|
10
|
+
@app_name = app_name
|
11
|
+
end
|
12
|
+
|
13
|
+
def sync
|
14
|
+
puts "Switch on maintenance mode"
|
15
|
+
run_remotely "maintenance:on"
|
16
|
+
puts "Restoring database"
|
17
|
+
run_remotely "pg:reset DATABASE_URL --confirm #{app_name}"
|
18
|
+
run_remotely "pgbackups:restore DATABASE_URL '#{capture}' --confirm #{app_name}"
|
19
|
+
run_remotely "run rake db:migrate"
|
20
|
+
run_remotely "run rake syncoku:after_sync"
|
21
|
+
run_remotely "restart"
|
22
|
+
puts "Switch off maintenance mode"
|
23
|
+
run_remotely "maintenance:off"
|
24
|
+
end
|
25
|
+
|
26
|
+
def run_remotely(command)
|
27
|
+
run_command "heroku #{command} --app #{app_name}"
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Syncoku
|
2
|
+
module Runnable
|
3
|
+
|
4
|
+
def run_command(command)
|
5
|
+
Bundler.with_clean_env {
|
6
|
+
out = `#{command}`
|
7
|
+
if $?.success?
|
8
|
+
out
|
9
|
+
else
|
10
|
+
puts "Error running command:"
|
11
|
+
puts command
|
12
|
+
puts out
|
13
|
+
exit $?.exitstatus
|
14
|
+
end
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_command(command)
|
19
|
+
Bundler.with_clean_env {
|
20
|
+
`#{command} 2> /dev/null`
|
21
|
+
$?.success?
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
data/lib/syncoku/s3.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
module Syncoku
|
2
|
+
|
3
|
+
class S3
|
4
|
+
|
5
|
+
attr_reader :to_env, :from_name, :to_name, :from_bucket, :to_bucket, :from_keys, :to_keys
|
6
|
+
|
7
|
+
def initialize(to_env)
|
8
|
+
@to_env = to_env
|
9
|
+
end
|
10
|
+
|
11
|
+
def sync
|
12
|
+
@missing = []
|
13
|
+
@from_name = config_value "production.bucket"
|
14
|
+
@to_name = config_value "#{to_env}.bucket"
|
15
|
+
access_key_id = config_value "access_key_id"
|
16
|
+
secret_access_key = config_value "secret_access_key"
|
17
|
+
if @missing.any?
|
18
|
+
puts "Missing syncoku.yml values prevented S3 sync"
|
19
|
+
@missing.each do |path|
|
20
|
+
puts " s3.#{path}"
|
21
|
+
end
|
22
|
+
return
|
23
|
+
end
|
24
|
+
puts "Syncing S3 from #{from_name} to #{to_name}..."
|
25
|
+
AWS.config access_key_id: access_key_id, secret_access_key: secret_access_key
|
26
|
+
@from_bucket = AWS::S3.new.buckets[from_name]
|
27
|
+
@to_bucket = AWS::S3.new.buckets[to_name]
|
28
|
+
return unless get_keys
|
29
|
+
if !simple_sync & !remove_spare
|
30
|
+
puts "S3 is in sync. Nothing to do :)"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_keys
|
35
|
+
@from_keys = from_bucket.objects.map(&:key)
|
36
|
+
@to_keys = to_bucket.objects.map(&:key)
|
37
|
+
true
|
38
|
+
rescue AWS::S3::Errors::SignatureDoesNotMatch => e
|
39
|
+
puts "Can't sync S3 because #{e.message.sub(/^T/, 't')}"
|
40
|
+
false
|
41
|
+
end
|
42
|
+
|
43
|
+
def simple_sync
|
44
|
+
missing = from_keys - to_keys
|
45
|
+
return false if missing.empty?
|
46
|
+
puts "On #{from_name} but not on #{to_name}: #{"%7d" % missing.size}"
|
47
|
+
puts "Copying to #{to_name}"
|
48
|
+
missing.each do |key|
|
49
|
+
to_bucket.objects[key].copy_from key, { bucket: from_bucket, acl: :public_read}
|
50
|
+
print "."
|
51
|
+
STDOUT.flush
|
52
|
+
end
|
53
|
+
puts " done"
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
def remove_spare
|
58
|
+
spare = to_keys - from_keys
|
59
|
+
return false if spare.empty?
|
60
|
+
puts "On #{to_name} but not on #{from_name}: #{"%7d" % spare.size}"
|
61
|
+
puts "Deleting from #{to_name}"
|
62
|
+
spare.each do |key|
|
63
|
+
to_bucket.objects[key].delete
|
64
|
+
print "."
|
65
|
+
STDOUT.flush
|
66
|
+
end
|
67
|
+
puts " done"
|
68
|
+
true
|
69
|
+
end
|
70
|
+
|
71
|
+
def config_value(path)
|
72
|
+
value = config.dup["s3"]
|
73
|
+
path.split(".").each do |name|
|
74
|
+
value = value[name]
|
75
|
+
if value.nil?
|
76
|
+
@missing << path
|
77
|
+
return nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
value
|
81
|
+
end
|
82
|
+
|
83
|
+
def config
|
84
|
+
@config ||= YAML.load(File.read("syncoku.yml"))
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.config?
|
88
|
+
File.exist?("syncoku.yml")
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
data/lib/syncoku.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'aws-sdk-v1'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'rake'
|
4
|
+
require 'yaml'
|
5
|
+
require 'io/console'
|
6
|
+
require "syncoku/runnable"
|
7
|
+
require "syncoku/capture_backup"
|
8
|
+
require "syncoku/control"
|
9
|
+
require "syncoku/local"
|
10
|
+
require "syncoku/local_db"
|
11
|
+
require "syncoku/remote"
|
12
|
+
require "syncoku/remote_db"
|
13
|
+
require "syncoku/s3"
|
14
|
+
require "syncoku/version"
|
data/syncoku.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'syncoku/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "syncoku"
|
8
|
+
spec.version = Syncoku::VERSION
|
9
|
+
spec.authors = ["Bill Horsman"]
|
10
|
+
spec.email = ["bill@logicalcobwebs.com"]
|
11
|
+
spec.summary = %q{Convenient way of syncing data from and to Heroku}
|
12
|
+
spec.homepage = "https://github.com/billhorsman/syncoku"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
21
|
+
spec.add_development_dependency "aws-sdk-v1", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: syncoku
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bill Horsman
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: aws-sdk-v1
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.7'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- bill@logicalcobwebs.com
|
58
|
+
executables:
|
59
|
+
- syncoku
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".gitignore"
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE.txt
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- bin/syncoku
|
69
|
+
- lib/syncoku.rb
|
70
|
+
- lib/syncoku/capture_backup.rb
|
71
|
+
- lib/syncoku/control.rb
|
72
|
+
- lib/syncoku/local.rb
|
73
|
+
- lib/syncoku/local_db.rb
|
74
|
+
- lib/syncoku/remote.rb
|
75
|
+
- lib/syncoku/remote_db.rb
|
76
|
+
- lib/syncoku/runnable.rb
|
77
|
+
- lib/syncoku/s3.rb
|
78
|
+
- lib/syncoku/version.rb
|
79
|
+
- syncoku.gemspec
|
80
|
+
homepage: https://github.com/billhorsman/syncoku
|
81
|
+
licenses:
|
82
|
+
- MIT
|
83
|
+
metadata: {}
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
requirements: []
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 2.4.5
|
101
|
+
signing_key:
|
102
|
+
specification_version: 4
|
103
|
+
summary: Convenient way of syncing data from and to Heroku
|
104
|
+
test_files: []
|