diff options
author | Winnie Hellmann <winnie@gitlab.com> | 2017-10-18 21:52:53 +0300 |
---|---|---|
committer | Winnie Hellmann <winnie@gitlab.com> | 2017-10-18 21:52:53 +0300 |
commit | 7e72a6751fc954756f514396453042927766a785 (patch) | |
tree | b0bf571e885791fb3bbd85bca8f06593a2e56b2b /lib/gitlab/git/popen.rb | |
parent | 03106288f92ac5ec9c4867cc1be9b070f157ccac (diff) | |
parent | 83b59da6549d3137f1424ee9bf16b95e4f72173e (diff) |
Merge branch '10-1-stable-prepare-rc3' into '10-1-stable'
Prepare 10.1 RC3 release
See merge request gitlab-org/gitlab-ce!14921
Diffstat (limited to 'lib/gitlab/git/popen.rb')
-rw-r--r-- | lib/gitlab/git/popen.rb | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/lib/gitlab/git/popen.rb b/lib/gitlab/git/popen.rb index 3d2fc471d28..b45da6020ee 100644 --- a/lib/gitlab/git/popen.rb +++ b/lib/gitlab/git/popen.rb @@ -5,6 +5,8 @@ require 'open3' module Gitlab module Git module Popen + FAST_GIT_PROCESS_TIMEOUT = 15.seconds + def popen(cmd, path, vars = {}) unless cmd.is_a?(Array) raise "System commands must be given as an array of strings" @@ -27,6 +29,67 @@ module Gitlab [@cmd_output, @cmd_status] end + + def popen_with_timeout(cmd, timeout, path, vars = {}) + unless cmd.is_a?(Array) + raise "System commands must be given as an array of strings" + end + + path ||= Dir.pwd + vars['PWD'] = path + + unless File.directory?(path) + FileUtils.mkdir_p(path) + end + + rout, wout = IO.pipe + rerr, werr = IO.pipe + + pid = Process.spawn(vars, *cmd, out: wout, err: werr, chdir: path, pgroup: true) + + begin + status = process_wait_with_timeout(pid, timeout) + + # close write ends so we could read them + wout.close + werr.close + + cmd_output = rout.readlines.join + cmd_output << rerr.readlines.join # Copying the behaviour of `popen` which merges stderr into output + + [cmd_output, status.exitstatus] + rescue Timeout::Error => e + kill_process_group_for_pid(pid) + + raise e + ensure + wout.close unless wout.closed? + werr.close unless werr.closed? + + rout.close + rerr.close + end + end + + def process_wait_with_timeout(pid, timeout) + deadline = timeout.seconds.from_now + wait_time = 0.01 + + while deadline > Time.now + sleep(wait_time) + _, status = Process.wait2(pid, Process::WNOHANG) + + return status unless status.nil? + end + + raise Timeout::Error, "Timeout waiting for process ##{pid}" + end + + def kill_process_group_for_pid(pid) + Process.kill("KILL", -pid) + Process.wait(pid) + rescue Errno::ESRCH + end end end end |