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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e7b0bd4c2f45a3da0af9c48c3b6cba896b0fab28
4
- data.tar.gz: 9590ad4e9ac568a4aeb884c6eeca181cac4df735
3
+ metadata.gz: 085e22641bbbe62e08c1e198162675d47b6db9c5
4
+ data.tar.gz: 538f05195800115aa28338cc4896378bc57df811
5
5
  SHA512:
6
- metadata.gz: 7b04dc8e517f01daf72e181782ddafd2b2d944db7dbdc5db269bbb445c8f2db7775eb328f93c5dd070e806ab2ec9d364a36e74d6bbf87f4f653f217f33a39f92
7
- data.tar.gz: 69a04b5e51d35ce5329569bc68568ae83e61e77b0f0434769a72458f355ec27297247678f52603c2a409c23b12fd424fe7ff044e19addecc14dbaa6d76709a98
6
+ metadata.gz: ee81f2adb4f68ccb702a32931fbabb4a6030edc2732bc87e1b6ad12d54c803ee4a8f34c6e8a620d6db08fb53ade3618a67d8d7fb2080550f2fc3965518e2d0ad
7
+ data.tar.gz: 1e0483923ba73473f685f91cda9a9f132fbb2df7bf67a958ede16f825d5082ee8f3cab1725d1f9a5636236477fc09fcec1898f998c15c95ad58af0aaa0a34dd5
@@ -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
@@ -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
- Migration::ACTIONS.each do |action|
22
- run_action_and_wait(action)
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
- def run_action_and_wait(action)
45
- run_action(action)
46
- wait
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 run_action(action)
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
- # have not being executed
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 start_role_action(role, action)
61
- script_path = find_script(role, action)
62
- log_path = log_path(@dir,run_id,role, action)
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
- run(script_path,log_path)
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
@@ -0,0 +1,12 @@
1
+ require 'curses'
2
+
3
+ module Themigrator
4
+ module UI
5
+
6
+ def render
7
+ puts "hello"
8
+
9
+ end
10
+
11
+ end
12
+ end
@@ -1,3 +1,3 @@
1
1
  module Themigrator
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
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
@@ -23,4 +23,5 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "minitest", "~> 5.0"
24
24
 
25
25
  spec.add_dependency "thor", "~> 0.19"
26
+ spec.add_dependency "curses", "~> 1.0"
26
27
  end
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.2
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-23 00:00:00.000000000 Z
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/runner.rb
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
@@ -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