themigrator 0.1.2 → 0.1.3
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 +4 -4
- data/lib/themigrator/logger.rb +24 -0
- data/lib/themigrator/migration_progress.rb +30 -0
- data/lib/themigrator/migrator.rb +45 -29
- data/lib/themigrator/script.rb +78 -0
- data/lib/themigrator/script_pool.rb +64 -0
- data/lib/themigrator/ui.rb +12 -0
- data/lib/themigrator/version.rb +1 -1
- data/lib/themigrator.rb +4 -1
- data/themigrator.gemspec +1 -0
- metadata +20 -3
- data/lib/themigrator/runner.rb +0 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 085e22641bbbe62e08c1e198162675d47b6db9c5
|
4
|
+
data.tar.gz: 538f05195800115aa28338cc4896378bc57df811
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee81f2adb4f68ccb702a32931fbabb4a6030edc2732bc87e1b6ad12d54c803ee4a8f34c6e8a620d6db08fb53ade3618a67d8d7fb2080550f2fc3965518e2d0ad
|
7
|
+
data.tar.gz: 1e0483923ba73473f685f91cda9a9f132fbb2df7bf67a958ede16f825d5082ee8f3cab1725d1f9a5636236477fc09fcec1898f998c15c95ad58af0aaa0a34dd5
|
data/lib/themigrator/logger.rb
CHANGED
@@ -1,9 +1,33 @@
|
|
1
1
|
require 'fileutils'
|
2
|
+
require 'logger'
|
2
3
|
|
3
4
|
module Themigrator
|
4
5
|
module Logger
|
6
|
+
|
7
|
+
MAINLOGFILE = "themigrator.log"
|
5
8
|
include FileUtils
|
6
9
|
|
10
|
+
def log(msg)
|
11
|
+
logger.info msg
|
12
|
+
end
|
13
|
+
|
14
|
+
def init_logger(log_file)
|
15
|
+
@logger = ::Logger.new(log_file)
|
16
|
+
@logger.formatter = proc do |severity, datetime, progname, msg|
|
17
|
+
t = datetime.strftime('%Y-%m-%d %H:%M:%S')
|
18
|
+
"#{t}: #{msg}\n"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def logger
|
23
|
+
@logger || ::Logger.new(STDOUT)
|
24
|
+
end
|
25
|
+
|
26
|
+
def main_log_path(base_dir, run_id)
|
27
|
+
filename = MAINLOGFILE
|
28
|
+
directory = log_dir(base_dir, run_id)
|
29
|
+
File.join(directory,filename)
|
30
|
+
end
|
7
31
|
|
8
32
|
def log_path(base_dir, run_id, role, action)
|
9
33
|
filename = "#{role}-#{action}.log"
|
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Themigrator
|
4
|
+
class MigrationProgress
|
5
|
+
include Logger
|
6
|
+
|
7
|
+
|
8
|
+
def initialize(dir, run_id)
|
9
|
+
@dir, @run_id = dir, run_id
|
10
|
+
@log_file_path = main_log_path(dir, run_id)
|
11
|
+
start_log_parser
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def start_log_parser
|
17
|
+
|
18
|
+
File.open(@log_file_path, "r") do |f|
|
19
|
+
f.readline
|
20
|
+
raise File.read(@log_file_path)
|
21
|
+
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
rescue EOFError
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
data/lib/themigrator/migrator.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
|
-
require 'themigrator/runner'
|
2
1
|
require 'themigrator/logger'
|
3
2
|
require 'themigrator/migration'
|
3
|
+
require 'themigrator/script_pool'
|
4
4
|
|
5
5
|
|
6
6
|
module Themigrator
|
7
7
|
class Migrator
|
8
|
-
include Runner
|
9
8
|
include Logger
|
10
9
|
|
11
10
|
|
@@ -17,51 +16,68 @@ module Themigrator
|
|
17
16
|
def migrate!
|
18
17
|
@migration = Migration.new(@dir)
|
19
18
|
@migration.analyze_project!
|
19
|
+
|
20
|
+
init_logger(main_log_path(@dir, run_id))
|
20
21
|
|
21
|
-
|
22
|
-
|
22
|
+
log "* [starting]"
|
23
|
+
catch(:rollback) do
|
24
|
+
each_action do |action|
|
25
|
+
log "[step #{action}]"
|
26
|
+
run_action_and_wait(action)
|
27
|
+
end
|
28
|
+
return true
|
23
29
|
end
|
24
|
-
|
25
|
-
rescue ActionFailedException
|
26
30
|
run_rollback_and_wait
|
27
31
|
end
|
28
32
|
|
29
|
-
private
|
30
|
-
|
31
|
-
def run_rollback_and_wait
|
32
|
-
rollbacks = @migration.roles_for_action("rollback") & @runned_roles
|
33
|
-
rollbacks .each do |role|
|
34
|
-
start_role_action(role, "rollback")
|
35
|
-
end
|
36
|
-
|
37
|
-
wait
|
38
|
-
end
|
39
|
-
|
40
33
|
def run_id
|
41
34
|
@run_id ||= Time.now.strftime("%Y-%m-%d-%H:%M:%S")
|
42
35
|
end
|
43
36
|
|
44
|
-
|
45
|
-
|
46
|
-
|
37
|
+
private
|
38
|
+
|
39
|
+
def each_action
|
40
|
+
Migration::ACTIONS.each do |action|
|
41
|
+
yield action
|
42
|
+
end
|
47
43
|
end
|
48
44
|
|
49
|
-
def
|
45
|
+
def each_role(action)
|
50
46
|
@migration.roles_for_action(action).each do |role|
|
51
47
|
@runned_roles << role # To prevent calling rollback on roles that
|
52
|
-
|
53
|
-
|
54
|
-
start_role_action(role, action)
|
55
|
-
|
48
|
+
yield role
|
56
49
|
end
|
57
50
|
@runned_roles.uniq!
|
58
51
|
end
|
59
52
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
53
|
+
def run_rollback_and_wait
|
54
|
+
script_pool = ScriptPool.new
|
55
|
+
each_role("rollback") do |role|
|
56
|
+
next unless @runned_roles.include?(role)
|
57
|
+
script_path = find_script(role, action)
|
58
|
+
log_path = log_path(@dir,run_id,role, action)
|
59
|
+
|
60
|
+
log("[running #{action} for #{role}]")
|
61
|
+
|
62
|
+
script_pool.add_script(script_path,log_path)
|
63
|
+
end
|
64
|
+
script_pool.run_and_wait
|
65
|
+
end
|
66
|
+
|
67
|
+
def run_action_and_wait(action)
|
68
|
+
script_pool = ScriptPool.new
|
69
|
+
|
70
|
+
each_role(action) do |role|
|
71
|
+
script_path = find_script(role, action)
|
72
|
+
log_path = log_path(@dir,run_id,role, action)
|
73
|
+
|
74
|
+
log("[running #{action} for #{role}]")
|
63
75
|
|
64
|
-
|
76
|
+
script_pool.add_script(script_path,log_path)
|
77
|
+
end
|
78
|
+
|
79
|
+
script_pool.run_and_wait or throw :rollback
|
80
|
+
|
65
81
|
end
|
66
82
|
|
67
83
|
def find_script(role, action)
|
@@ -0,0 +1,78 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Themigrator
|
4
|
+
class Script
|
5
|
+
def initialize(script, log_file)
|
6
|
+
@script = script
|
7
|
+
@log_file = File.open(log_file, "w", 0600)
|
8
|
+
@wd_dir = File.dirname(script)
|
9
|
+
@pid = nil
|
10
|
+
@thread = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
@thread = Thread.new do
|
15
|
+
@pid = Process.spawn(@script,
|
16
|
+
err: @log_file,
|
17
|
+
out: @log_file,
|
18
|
+
chdir: @wd_dir)
|
19
|
+
pid, status = Process.wait2(@pid)
|
20
|
+
if status.signaled?
|
21
|
+
signal = Signal.list.find{|k,v|
|
22
|
+
v == status.termsig
|
23
|
+
}
|
24
|
+
signal.nil? ? :unknown_signal : signal[0].downcase.to_sym
|
25
|
+
else
|
26
|
+
status.exitstatus
|
27
|
+
end
|
28
|
+
end
|
29
|
+
sleep 0
|
30
|
+
end
|
31
|
+
|
32
|
+
# Waits for the process to be over
|
33
|
+
def wait(seconds = nil)
|
34
|
+
@thread.join(seconds)
|
35
|
+
end
|
36
|
+
|
37
|
+
def exitcode
|
38
|
+
@thread.value
|
39
|
+
end
|
40
|
+
|
41
|
+
def stop
|
42
|
+
if running?
|
43
|
+
send_int
|
44
|
+
if wait(5) == nil
|
45
|
+
send_kill
|
46
|
+
end
|
47
|
+
wait
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def success?
|
52
|
+
exitcode == 0
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def running?
|
58
|
+
@thread and @thread.alive?
|
59
|
+
end
|
60
|
+
|
61
|
+
def send_signal(signal)
|
62
|
+
Process.kill(signal.to_s.upcase,@pid)
|
63
|
+
end
|
64
|
+
|
65
|
+
def send_int
|
66
|
+
send_signal(:int)
|
67
|
+
end
|
68
|
+
|
69
|
+
def send_kill
|
70
|
+
send_signal(:kill)
|
71
|
+
end
|
72
|
+
|
73
|
+
def close
|
74
|
+
@log_file.close
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'themigrator/script'
|
2
|
+
|
3
|
+
|
4
|
+
module Themigrator
|
5
|
+
class ScriptPool
|
6
|
+
def initialize
|
7
|
+
@queue = Queue.new
|
8
|
+
@lock = Mutex.new
|
9
|
+
@scripts = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_script(script,log_file)
|
13
|
+
s = Script.new(script, log_file)
|
14
|
+
@lock.synchronize do
|
15
|
+
@scripts << s
|
16
|
+
end
|
17
|
+
s
|
18
|
+
end
|
19
|
+
|
20
|
+
# Run the scripts
|
21
|
+
# returns:
|
22
|
+
# * true: All scripts returned 0
|
23
|
+
# * false: Some of the scripts fail
|
24
|
+
def run_and_wait
|
25
|
+
@lock.synchronize do
|
26
|
+
start_scripts
|
27
|
+
collect_result
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def start_scripts
|
34
|
+
@scripts.each do |s|
|
35
|
+
Thread.new {
|
36
|
+
s.run
|
37
|
+
s.wait
|
38
|
+
@queue << s
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def collect_result
|
44
|
+
running_scripts = @scripts.size
|
45
|
+
success = true
|
46
|
+
while running_scripts != 0
|
47
|
+
s = @queue.pop
|
48
|
+
if !s.success?
|
49
|
+
stop_and_kill
|
50
|
+
success = false
|
51
|
+
end
|
52
|
+
running_scripts -= 1
|
53
|
+
end
|
54
|
+
success
|
55
|
+
end
|
56
|
+
|
57
|
+
def stop_and_kill
|
58
|
+
@scripts.each {|s|
|
59
|
+
s.stop
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
data/lib/themigrator/version.rb
CHANGED
data/lib/themigrator.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
require "themigrator/version"
|
2
2
|
require "themigrator/logger"
|
3
|
-
require "themigrator/runner"
|
4
3
|
require "themigrator/migration"
|
4
|
+
require "themigrator/migrator"
|
5
|
+
require "themigrator/script_pool"
|
6
|
+
require "themigrator/script"
|
7
|
+
require "themigrator/migration_progress"
|
5
8
|
|
6
9
|
module Themigrator
|
7
10
|
|
data/themigrator.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: themigrator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Guillermo Álvarez
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-08-
|
11
|
+
date: 2016-08-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0.19'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: curses
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.0'
|
69
83
|
description: The migrator is a program that eases and automates data migrations.
|
70
84
|
email:
|
71
85
|
- guillermo@cientifico.net
|
@@ -88,8 +102,11 @@ files:
|
|
88
102
|
- lib/themigrator/helper.rb
|
89
103
|
- lib/themigrator/logger.rb
|
90
104
|
- lib/themigrator/migration.rb
|
105
|
+
- lib/themigrator/migration_progress.rb
|
91
106
|
- lib/themigrator/migrator.rb
|
92
|
-
- lib/themigrator/
|
107
|
+
- lib/themigrator/script.rb
|
108
|
+
- lib/themigrator/script_pool.rb
|
109
|
+
- lib/themigrator/ui.rb
|
93
110
|
- lib/themigrator/version.rb
|
94
111
|
- test.sh
|
95
112
|
- themigrator.gemspec
|
data/lib/themigrator/runner.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
require 'themigrator/logger'
|
2
|
-
|
3
|
-
|
4
|
-
module Themigrator
|
5
|
-
module Runner
|
6
|
-
include Logger
|
7
|
-
|
8
|
-
class ActionFailedException < Exception; end
|
9
|
-
|
10
|
-
|
11
|
-
class Script
|
12
|
-
def initialize(script, log_file)
|
13
|
-
@script = script
|
14
|
-
@log_file = File.open(log_file, "w", 0600)
|
15
|
-
end
|
16
|
-
|
17
|
-
def close
|
18
|
-
@log_file.close
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
|
23
|
-
def run(script, log_file)
|
24
|
-
wd_dir = File.dirname(script)
|
25
|
-
log_fd = File.open(log_file, "w", 0600)
|
26
|
-
pid = Process.spawn(script, err: log_fd, out: log_fd, chdir: wd_dir)
|
27
|
-
add_pid(pid)
|
28
|
-
end
|
29
|
-
|
30
|
-
def wait
|
31
|
-
processes.each do |pid|
|
32
|
-
pid, status = Process.wait2(pid)
|
33
|
-
return_code = status.exitstatus
|
34
|
-
remove_pid(pid)
|
35
|
-
|
36
|
-
if return_code != 0
|
37
|
-
raise ActionFailedException.new(pid)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def processes
|
45
|
-
@processes || []
|
46
|
-
end
|
47
|
-
|
48
|
-
def add_pid(pid)
|
49
|
-
@processes ||= []
|
50
|
-
@processes << pid
|
51
|
-
end
|
52
|
-
|
53
|
-
def remove_pid(pid)
|
54
|
-
@processes.delete(pid)
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
58
|
-
end
|