themigrator 0.1.12 → 0.1.14

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,7 +5,7 @@ module Themigrator
5
5
  attr_reader :script, :log_file, :attr
6
6
 
7
7
  # new creates a new script but doesn't start until called run
8
- # Arguments:
8
+ # Arguments:
9
9
  # * script : Fullpath of the file to execute
10
10
  # * log_file: Fullpath of the file to save the log
11
11
  # * attr: Extra attributes that could be handy (not used
@@ -16,7 +16,7 @@ module Themigrator
16
16
  @attr = attr
17
17
  @script = script
18
18
  @log_file = log_file
19
- @log_fd = File.open(@log_file, "w", 0600)
19
+ @log_fd = File.open(@log_file, 'w', 0o600)
20
20
  @wd_dir = File.dirname(script)
21
21
  @pid = nil
22
22
  @thread = nil
@@ -31,36 +31,36 @@ module Themigrator
31
31
 
32
32
  def run
33
33
  @thread = Thread.new do
34
- @pid = Process.spawn(@script,
35
- err: @log_fd,
36
- out: @log_fd,
37
- chdir: @wd_dir)
38
- pid, status = Process.wait2(@pid)
39
- @end_time = Time.now
40
- close
41
- return_code = if status.signaled?
42
- signal = Signal.list.find{|k,v|
43
- v == status.termsig
44
- }
45
- signal.nil? ? :unknown_signal : signal[0].downcase.to_sym
46
- else
47
- status.exitstatus
48
- end
49
-
50
- Thread.new { invoke_cbks } if @finish_cbk
51
-
52
- return_code
34
+ @pid = Process.spawn(@script,
35
+ err: @log_fd,
36
+ out: @log_fd,
37
+ chdir: @wd_dir)
38
+ pid, status = Process.wait2(@pid)
39
+ @end_time = Time.now
40
+ close
41
+ return_code = if status.signaled?
42
+ signal = Signal.list.find do |_k, v|
43
+ v == status.termsig
44
+ end
45
+ signal.nil? ? :unknown_signal : signal[0].downcase.to_sym
46
+ else
47
+ status.exitstatus
48
+ end
49
+
50
+ Thread.new { invoke_cbks } if @finish_cbk
51
+
52
+ return_code
53
53
  end
54
54
  sleep 0
55
55
  end
56
56
 
57
57
  def invoke_cbks
58
- @finish_cbk.call(self)
58
+ @finish_cbk.call(self)
59
59
  end
60
60
 
61
61
  # Waits for the process to be over
62
62
  def wait(seconds = nil)
63
- @thread.join(seconds)
63
+ @thread.join(seconds)
64
64
  end
65
65
 
66
66
  def exitcode
@@ -69,26 +69,24 @@ module Themigrator
69
69
 
70
70
  def stop
71
71
  if running?
72
- send_int
73
- if wait(5) == nil
74
- send_kill
75
- end
76
- wait
72
+ send_int
73
+ send_kill if wait(5).nil?
74
+ wait
77
75
  end
78
76
  end
79
77
 
80
78
  def success?
81
- exitcode == 0
79
+ exitcode.zero?
82
80
  end
83
81
 
84
82
  private
85
83
 
86
84
  def running?
87
- @thread and @thread.alive?
85
+ @thread && @thread.alive?
88
86
  end
89
87
 
90
88
  def send_signal(signal)
91
- Process.kill(signal.to_s.upcase,@pid)
89
+ Process.kill(signal.to_s.upcase, @pid)
92
90
  end
93
91
 
94
92
  def send_int
@@ -102,6 +100,5 @@ module Themigrator
102
100
  def close
103
101
  @log_fd.close
104
102
  end
105
-
106
103
  end
107
104
  end
@@ -1,6 +1,5 @@
1
1
  require 'themigrator/script'
2
2
 
3
-
4
3
  module Themigrator
5
4
  class ScriptPool
6
5
  attr_reader :scripts, :run_time
@@ -10,10 +9,10 @@ module Themigrator
10
9
  @scripts = []
11
10
  end
12
11
 
13
- def add_script(script,log_file, attr = {},&block)
12
+ def add_script(script, log_file, attr = {}, &block)
14
13
  s = Script.new(script, log_file, attr, &block)
15
14
  @lock.synchronize do
16
- @scripts << s
15
+ @scripts << s
17
16
  end
18
17
  s
19
18
  end
@@ -25,8 +24,8 @@ module Themigrator
25
24
  def run_and_wait
26
25
  start = Time.now
27
26
  @lock.synchronize do
28
- start_scripts
29
- collect_result
27
+ start_scripts
28
+ collect_result
30
29
  end
31
30
  ensure
32
31
  @run_time = Time.now - start
@@ -36,33 +35,30 @@ module Themigrator
36
35
 
37
36
  def start_scripts
38
37
  @scripts.each do |s|
39
- Thread.new {
40
- s.run
41
- s.wait
42
- @queue << s
43
- }
38
+ Thread.new do
39
+ s.run
40
+ s.wait
41
+ @queue << s
42
+ end
44
43
  end
45
44
  end
46
45
 
47
- def collect_result
46
+ def collect_result
48
47
  running_scripts = @scripts.size
49
48
  success = true
50
- while running_scripts != 0
51
- s = @queue.pop
52
- if !s.success?
53
- stop_and_kill
54
- success = false
55
- end
56
- running_scripts -= 1
49
+ while running_scripts.nonzero?
50
+ s = @queue.pop
51
+ unless s.success?
52
+ stop_and_kill
53
+ success = false
54
+ end
55
+ running_scripts -= 1
57
56
  end
58
57
  success
59
58
  end
60
59
 
61
60
  def stop_and_kill
62
- @scripts.each {|s|
63
- s.stop
64
- }
61
+ @scripts.each(&:stop)
65
62
  end
66
-
67
63
  end
68
64
  end
@@ -0,0 +1,40 @@
1
+
2
+ # From: http://www.alecjacobson.com/weblog/?p=75
3
+ module Themigrator
4
+ class UI
5
+ module Getchar
6
+ KEY2SYM = Hash.new { |h, k| h[k] = k }
7
+ KEY2SYM["\e[D"] = :left
8
+ KEY2SYM["\e[C"] = :right
9
+ KEY2SYM["\r"] = :enter
10
+ KEY2SYM["\e"] = :esc
11
+ KEY2SYM["\e[6~"] = :npage
12
+ KEY2SYM["\e[5~"] = :ppage
13
+ KEY2SYM["\u0003"] = :c_c
14
+ KEY2SYM["\e[B"] = :scroll_down
15
+ KEY2SYM["\e[A"] = :scroll_up
16
+
17
+ def getchar
18
+ begin
19
+ c = STDIN.getc.chr
20
+ # gather next two characters of special keys
21
+ if c == "\e"
22
+ extra_thread = Thread.new do
23
+ c += STDIN.getc.chr
24
+ c += STDIN.getc.chr
25
+ c += STDIN.getc.chr if ["\e[6", "\e[5"].include?(c)
26
+ end
27
+ # wait just long enough for special keys to get swallowed
28
+ extra_thread.join(0.00100)
29
+ # kill thread so not-so-long special keys don't wait on getc
30
+ extra_thread.kill
31
+ end
32
+ rescue => e
33
+ log_exception(e)
34
+ ensure
35
+ end
36
+ KEY2SYM[c]
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,173 @@
1
+ require 'curses'
2
+ require 'thread'
3
+
4
+ module Themigrator
5
+ class UI
6
+ module LogArea
7
+ include Curses
8
+
9
+ class LogWindow < Window
10
+ attr_accessor :role, :action
11
+ def initialize(height, width, top, left)
12
+ @height = height
13
+ @width = width
14
+ @top = top
15
+ @left = left
16
+ @inner_win = ::Curses::Window.new(height - 2, width - 2, top + 1, left + 1)
17
+ @inner_win.scrollok(true)
18
+ @buffer = ''
19
+ @scroll = -1
20
+ super
21
+ idlok(true)
22
+ end
23
+
24
+ def redraw
25
+ clear
26
+ @inner_win.clear
27
+ setpos(0, 0)
28
+ box('|', '-')
29
+ addstr(name)
30
+ log('redraw')
31
+ refresh
32
+ render(true)
33
+ end
34
+
35
+ def nextpage
36
+ @scroll += 5
37
+ @scroll = -1 if @scroll > -1
38
+ log("@scroll = #{@scroll}")
39
+ end
40
+
41
+ def prevpage
42
+ @scroll -= 5
43
+ buffer_lines = @buffer.split("\n").size
44
+ offset_lines = buffer_lines - @height + (2 + 5)
45
+
46
+ log("@scroll = #{@scroll} and offset_lines - #{offset_lines} | buffer_lines #{buffer_lines} | @height = #{@height}")
47
+ @height
48
+ @scroll = -offset_lines if @scroll < -offset_lines
49
+ end
50
+
51
+ def name
52
+ '%-13s/%-10s' % [action, role]
53
+ end
54
+
55
+ def append(msg)
56
+ @buffer << msg
57
+ end
58
+
59
+ def render(force = false)
60
+ # refresh
61
+ render_inner_win(force)
62
+ end
63
+
64
+ def log(msg)
65
+ ui_log("#{name}##{msg}")
66
+ end
67
+
68
+ private
69
+
70
+ def <<(msg)
71
+ @inner_win << msg
72
+ end
73
+
74
+ def render_inner_win(force = false)
75
+ new_content = content_changed?
76
+ return unless new_content || force
77
+ log('render')
78
+ @inner_win.clear
79
+ @inner_win << @buffer.split("\n")[0..@scroll].join("\n")
80
+ @inner_win.refresh
81
+ end
82
+
83
+ def get_content_for_win
84
+ @buffer.split("\n")[0..@scroll].join("\n")
85
+ end
86
+
87
+ def content_changed?
88
+ new_content = get_content_for_win
89
+ if @previous == new_content
90
+ nil
91
+ else
92
+ @previous = get_content_for_win
93
+ new_content
94
+ end
95
+ end
96
+ end
97
+
98
+ def initialize_log_area(roles)
99
+ @la_roles = roles
100
+ @la_scripts = Themigrator::Migration::SCRIPTS
101
+ @la_actions = Themigrator::Migration::ACTIONS
102
+ @la_current_action = nil
103
+ @la_lines = lines
104
+ @la_cols = cols
105
+ @la_mutex = Mutex.new
106
+ # @windows = Hash.new {|h,a| h[a] = {} }
107
+ # @windows[action][role]
108
+ @la_windows
109
+ @la_windows = Hash.new do |h, action|
110
+ role_windows = {}
111
+ @la_roles.each_with_index do |role, n|
112
+ column_height = @la_lines - 4
113
+ column_width = @la_cols / @la_roles.size
114
+ top = 2
115
+ left = column_width * n
116
+ w = LogWindow.new(column_height, column_width - 1, top, left)
117
+ w.role = role
118
+ w.action = action
119
+ role_windows[role] = w
120
+ end
121
+ h[action] = role_windows
122
+ end
123
+ end
124
+
125
+ def la_initialize?
126
+ defined?(@la_roles)
127
+ end
128
+
129
+ def la_npage
130
+ la_each_window(&:nextpage)
131
+ end
132
+
133
+ def la_ppage
134
+ la_each_window(&:prevpage)
135
+ end
136
+
137
+ def la_switch_action(action)
138
+ return if @la_current_action == action || @la_roles.empty?
139
+ @la_current_action = action.to_s
140
+ @la_roles.each do |role|
141
+ la_get_window(action, role).redraw
142
+ end
143
+ end
144
+
145
+ def la_append(action, role, msg)
146
+ @la_mutex.synchronize do
147
+ la_get_window(action, role).append(msg)
148
+ end
149
+ end
150
+
151
+ def la_render
152
+ la_each_window do |w, _role|
153
+ w.render
154
+ end
155
+ end
156
+
157
+ private
158
+
159
+ def la_each_window
160
+ @la_roles.each do |role|
161
+ @la_mutex.synchronize do
162
+ yield la_get_window(@la_current_action, role), role
163
+ end
164
+ end
165
+ end
166
+
167
+ def la_get_window(action, role)
168
+ fuck @la_windows[action][role]
169
+ @la_windows[action][role]
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,52 @@
1
+
2
+ module Themigrator
3
+ class UI
4
+ module ProgressWindow
5
+ include Curses
6
+ def render_progress
7
+ progress_window.clear
8
+ progress_window.setpos(0, 0)
9
+ progress_window.addstr(build_status_line)
10
+ progress_window.setpos(1, 0)
11
+ progress_window.addstr(@pw_status) if defined?(@pw_status)
12
+ progress_window.refresh
13
+ end
14
+
15
+ def pg_set_action(action)
16
+ @pg_action = action
17
+ end
18
+
19
+ def progress_window
20
+ @progress_widnow ||= Window.new(@lines - 2, @cols, @lines - 2, 0).tap do |w|
21
+ w.attrset(A_DIM)
22
+ end
23
+ end
24
+
25
+ def say(*msg)
26
+ @pw_status = msg.map(&:to_s).join(' ')
27
+ end
28
+
29
+ def build_status_line
30
+ scripts = Themigrator::Migration::SCRIPTS
31
+ width = scripts.map(&:size).inject(&:+)
32
+ free_space = @cols - width
33
+ sep_space = scripts.size - 1
34
+ inline_space = ((free_space - sep_space) / scripts.size - 1) / 2
35
+
36
+ action_msg = []
37
+ scripts.map do |script|
38
+ a = ''
39
+ inline_space.times { a << ' ' }
40
+ a << if defined?(@pg_action) && @pg_action.to_s == script.to_s
41
+ script.upcase
42
+ else
43
+ script.downcase
44
+ end
45
+ inline_space.times { a << ' ' }
46
+ action_msg << a
47
+ end
48
+ action_msg.join('>')
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,31 @@
1
+
2
+ module Themigrator
3
+ class UI
4
+ module TitleBar
5
+ include Curses
6
+
7
+ protected
8
+
9
+ def render_title
10
+ now_str = Time.now.strftime('%d %b - %H:%M.%S')
11
+ time_window.setpos(0, 0)
12
+ time_window.addstr(now_str)
13
+ time_window.refresh
14
+ end
15
+
16
+ def title_window
17
+ @title_window ||= Window.new(1, @cols - 18, 0, 0).tap do |w|
18
+ w.attrset(A_BOLD)
19
+ w.addstr('The migrator')
20
+ end
21
+ end
22
+
23
+ def time_window
24
+ width = 18
25
+ @time_window ||= Window.new(1, 18, 0, @cols - 18).tap do |w|
26
+ w.attrset(A_DIM)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end