themigrator 0.1.12 → 0.1.14

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.
@@ -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