diff --git a/Makefile b/Makefile index 2826148b..ee153c95 100644 --- a/Makefile +++ b/Makefile @@ -67,6 +67,11 @@ gem_build_install: gem_uninstall: gem uninstall uffizzi-cli +gem_reinstall: + ls -la | grep uffizzi-cli- | rm -f + make gem_uninstall + make gem_build_install + brew_add_tap: brew tap UffizziCloud/tap diff --git a/lib/uffizzi.rb b/lib/uffizzi.rb index 0326dad6..1b57c762 100644 --- a/lib/uffizzi.rb +++ b/lib/uffizzi.rb @@ -38,7 +38,19 @@ def root end def process - @process ||= Process + Process + end + + def signal + Signal + end + + def thread + Thread + end + + def at_exit(&block) + Kernel.at_exit(&block) end end end diff --git a/lib/uffizzi/cli/dev.rb b/lib/uffizzi/cli/dev.rb index b96f48d0..40e52d38 100644 --- a/lib/uffizzi/cli/dev.rb +++ b/lib/uffizzi/cli/dev.rb @@ -222,8 +222,8 @@ def parse_kubeconfig(kubeconfig) def launch_demonise_skaffold(config_path) Uffizzi.process.daemon(true) - at_exit do - DevService.delete_pid + Uffizzi.at_exit do + DevService.stop_process end DevService.save_pid @@ -235,8 +235,8 @@ def launch_demonise_skaffold(config_path) end def launch_basic_skaffold(config_path) - at_exit do - DevService.delete_pid + Uffizzi.at_exit do + DevService.stop_process end DevService.save_pid diff --git a/lib/uffizzi/services/dev_service.rb b/lib/uffizzi/services/dev_service.rb index b47558b5..61caf485 100644 --- a/lib/uffizzi/services/dev_service.rb +++ b/lib/uffizzi/services/dev_service.rb @@ -32,13 +32,27 @@ def stop_process dev_pid = running_pid skaffold_pid = running_skaffold_pid - Uffizzi.process.kill('INT', skaffold_pid) - Uffizzi.process.kill('INT', dev_pid) + begin + Uffizzi.process.kill('INT', skaffold_pid) + rescue Errno::ESRCH + end + + wait_process_stop(skaffold_pid) delete_pid + + Uffizzi.process.kill('INT', dev_pid) rescue Errno::ESRCH delete_pid end + def wait_process_stop(pid) + loop do + Uffizzi.process.kill(0, pid) + sleep(1) + end + rescue Errno::ESRCH + end + def process_running? pid = running_pid return false unless pid.positive? @@ -50,9 +64,9 @@ def process_running? end def start_check_pid_file_existence - Thread.new do + Uffizzi.thread.new do loop do - Uffizzi.process.kill('QUIT', Uffizzi.process.pid) unless File.exist?(pid_path) + stop_process unless File.exist?(pid_path) sleep(1) end end @@ -62,6 +76,8 @@ def start_basic_skaffold(config_path, options) Uffizzi.ui.say('Start skaffold') cmd = build_skaffold_dev_command(config_path, options) + Uffizzi.signal.trap('INT') {} + Uffizzi.ui.popen2e(cmd) do |_stdin, stdout_and_stderr, wait_thr| pid = wait_thr.pid skaffold_pid = find_skaffold_pid(pid) @@ -198,13 +214,29 @@ def dev_environment Uffizzi::ConfigHelper.dev_environment end - def find_skaffold_pid(ppid) - ppid_regex = /\w*\s+\d+\s+#{ppid}.*\sskaffold dev/ - pid_regex = /\w*\s+(\d+)\s+#{ppid}.*\sskaffold dev/ - + def find_skaffold_pid(pid) + pid_regex = /\w*#{pid}.*skaffold dev/ io = Uffizzi.ui.popen('ps -ef') - ps = io.readlines.detect { |l| l.match?(ppid_regex) } - ps.match(pid_regex)[1] + processes = io.readlines.select { |l| l.match?(pid_regex) } + + if processes.count.zero? + raise StandardError.new('Can\'t find skaffold process pid') + end + + # HACK: For MacOS + if processes.count == 1 + current_pid = processes[0].gsub(/\s+/, ' ').lstrip.split[1] + return pid if current_pid.to_s == pid.to_s + + raise StandardError.new('Can\'t find skaffold process pid') + end + + # HACK: For Linux + parent_process = processes + .map { |ps| ps.gsub(/\s+/, ' ').lstrip.split } + .detect { |ps| ps[2].to_s == pid.to_s } + + parent_process[1] end end end diff --git a/test/support/mocks/mock_prompt.rb b/test/support/mocks/mock_prompt.rb index 1051317d..7882e213 100644 --- a/test/support/mocks/mock_prompt.rb +++ b/test/support/mocks/mock_prompt.rb @@ -38,7 +38,6 @@ def promise_question_answer(question, answer) def get_answer(question) answer_index = @question_answers.index do |question_answer| - question_answer[:question] == question case question_answer[:question] when Regexp question_answer[:question].match?(question) diff --git a/test/support/mocks/mock_signal.rb b/test/support/mocks/mock_signal.rb new file mode 100644 index 00000000..d0f4c029 --- /dev/null +++ b/test/support/mocks/mock_signal.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class MockSignal + class << self + def trap(_sig); end + end +end diff --git a/test/support/mocks/mock_thread.rb b/test/support/mocks/mock_thread.rb new file mode 100644 index 00000000..a63a887a --- /dev/null +++ b/test/support/mocks/mock_thread.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class MockThread + def initialize; end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index 6e1b81b7..cf8ee0eb 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -37,7 +37,7 @@ class Minitest::Test TEST_CONFIG_DIR = 'tmp/config_default.json' TEST_TOKEN_PATH = 'tmp/token_default.json' TEST_PID_PATH = 'tmp/dev.pid' - TEST_PID_PATH = 'tmp/skaffold_dev.pid' + TEST_SKAFFOLD_PID_PATH = 'tmp/skaffold_dev.pid' TEST_DEV_LOGS_PATH = 'tmp/dev-logs.txt' def before_setup @@ -49,11 +49,14 @@ def before_setup Uffizzi.stubs(:ui).returns(@mock_shell) Uffizzi.stubs(:prompt).returns(@mock_prompt) Uffizzi.stubs(:process).returns(@mock_process) + Uffizzi.stubs(:signal).returns(MockSignal) + Uffizzi.stubs(:thread).returns(MockSignal) + Uffizzi.stubs(:at_exit).returns(nil) Uffizzi::ConfigFile.stubs(:config_path).returns(TEST_CONFIG_PATH) Uffizzi::Token.stubs(:token_path).returns(TEST_TOKEN_PATH) Uffizzi::ConfigFile.stubs(:config_path).returns(TEST_CONFIG_PATH) DevService.stubs(:pid_path).returns(TEST_PID_PATH) - DevService.stubs(:skaffold_pid_path).returns(TEST_PID_PATH) + DevService.stubs(:skaffold_pid_path).returns(TEST_SKAFFOLD_PID_PATH) DevService.stubs(:logs_path).returns(TEST_DEV_LOGS_PATH) end @@ -70,6 +73,7 @@ def before_teardown File.delete(TEST_CONFIG_PATH) if File.exist?(TEST_CONFIG_PATH) File.delete(TEST_TOKEN_PATH) if File.exist?(TEST_TOKEN_PATH) File.delete(TEST_PID_PATH) if File.exist?(TEST_PID_PATH) + File.delete(TEST_SKAFFOLD_PID_PATH) if File.exist?(TEST_SKAFFOLD_PID_PATH) File.delete(TEST_DEV_LOGS_PATH) if File.exist?(TEST_DEV_LOGS_PATH) end