jawshooah-overcommit 0.22.0
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 +7 -0
- data/bin/overcommit +8 -0
- data/config/default.yml +275 -0
- data/config/starter.yml +31 -0
- data/lib/overcommit.rb +20 -0
- data/lib/overcommit/cli.rb +205 -0
- data/lib/overcommit/configuration.rb +183 -0
- data/lib/overcommit/configuration_loader.rb +49 -0
- data/lib/overcommit/configuration_validator.rb +40 -0
- data/lib/overcommit/constants.rb +8 -0
- data/lib/overcommit/exceptions.rb +35 -0
- data/lib/overcommit/git_repo.rb +147 -0
- data/lib/overcommit/hook/base.rb +174 -0
- data/lib/overcommit/hook/commit_msg/base.rb +11 -0
- data/lib/overcommit/hook/commit_msg/gerrit_change_id.rb +18 -0
- data/lib/overcommit/hook/commit_msg/hard_tabs.rb +13 -0
- data/lib/overcommit/hook/commit_msg/russian_novel.rb +14 -0
- data/lib/overcommit/hook/commit_msg/single_line_subject.rb +12 -0
- data/lib/overcommit/hook/commit_msg/text_width.rb +38 -0
- data/lib/overcommit/hook/commit_msg/trailing_period.rb +12 -0
- data/lib/overcommit/hook/post_checkout/base.rb +11 -0
- data/lib/overcommit/hook/post_checkout/index_tags.rb +26 -0
- data/lib/overcommit/hook/post_commit/base.rb +11 -0
- data/lib/overcommit/hook/post_commit/git_guilt.rb +9 -0
- data/lib/overcommit/hook/pre_commit/author_email.rb +18 -0
- data/lib/overcommit/hook/pre_commit/author_name.rb +17 -0
- data/lib/overcommit/hook/pre_commit/base.rb +70 -0
- data/lib/overcommit/hook/pre_commit/berksfile_check.rb +20 -0
- data/lib/overcommit/hook/pre_commit/brakeman.rb +12 -0
- data/lib/overcommit/hook/pre_commit/broken_symlinks.rb +15 -0
- data/lib/overcommit/hook/pre_commit/bundle_check.rb +25 -0
- data/lib/overcommit/hook/pre_commit/chamber_security.rb +11 -0
- data/lib/overcommit/hook/pre_commit/coffee_lint.rb +11 -0
- data/lib/overcommit/hook/pre_commit/css_lint.rb +11 -0
- data/lib/overcommit/hook/pre_commit/go_lint.rb +12 -0
- data/lib/overcommit/hook/pre_commit/haml_lint.rb +19 -0
- data/lib/overcommit/hook/pre_commit/hard_tabs.rb +14 -0
- data/lib/overcommit/hook/pre_commit/image_optim.rb +41 -0
- data/lib/overcommit/hook/pre_commit/js_hint.rb +13 -0
- data/lib/overcommit/hook/pre_commit/jscs.rb +22 -0
- data/lib/overcommit/hook/pre_commit/json_syntax.rb +22 -0
- data/lib/overcommit/hook/pre_commit/jsx_hint.rb +13 -0
- data/lib/overcommit/hook/pre_commit/jsxcs.rb +20 -0
- data/lib/overcommit/hook/pre_commit/local_paths_in_gemfile.rb +14 -0
- data/lib/overcommit/hook/pre_commit/merge_conflicts.rb +14 -0
- data/lib/overcommit/hook/pre_commit/pry_binding.rb +14 -0
- data/lib/overcommit/hook/pre_commit/python_flake8.rb +11 -0
- data/lib/overcommit/hook/pre_commit/rails_schema_up_to_date.rb +45 -0
- data/lib/overcommit/hook/pre_commit/reek.rb +22 -0
- data/lib/overcommit/hook/pre_commit/rubocop.rb +19 -0
- data/lib/overcommit/hook/pre_commit/scss_lint.rb +19 -0
- data/lib/overcommit/hook/pre_commit/shell_check.rb +19 -0
- data/lib/overcommit/hook/pre_commit/trailing_whitespace.rb +13 -0
- data/lib/overcommit/hook/pre_commit/travis_lint.rb +11 -0
- data/lib/overcommit/hook/pre_commit/yaml_syntax.rb +22 -0
- data/lib/overcommit/hook_context.rb +17 -0
- data/lib/overcommit/hook_context/base.rb +69 -0
- data/lib/overcommit/hook_context/commit_msg.rb +32 -0
- data/lib/overcommit/hook_context/post_checkout.rb +26 -0
- data/lib/overcommit/hook_context/post_commit.rb +19 -0
- data/lib/overcommit/hook_context/pre_commit.rb +148 -0
- data/lib/overcommit/hook_context/run_all.rb +39 -0
- data/lib/overcommit/hook_loader/base.rb +36 -0
- data/lib/overcommit/hook_loader/built_in_hook_loader.rb +12 -0
- data/lib/overcommit/hook_loader/plugin_hook_loader.rb +61 -0
- data/lib/overcommit/hook_runner.rb +129 -0
- data/lib/overcommit/hook_signer.rb +79 -0
- data/lib/overcommit/installer.rb +148 -0
- data/lib/overcommit/interrupt_handler.rb +87 -0
- data/lib/overcommit/logger.rb +79 -0
- data/lib/overcommit/message_processor.rb +132 -0
- data/lib/overcommit/printer.rb +116 -0
- data/lib/overcommit/subprocess.rb +46 -0
- data/lib/overcommit/utils.rb +163 -0
- data/lib/overcommit/version.rb +4 -0
- data/libexec/gerrit-change-id +174 -0
- data/libexec/index-tags +17 -0
- data/template-dir/hooks/commit-msg +81 -0
- data/template-dir/hooks/overcommit-hook +81 -0
- data/template-dir/hooks/post-checkout +81 -0
- data/template-dir/hooks/pre-commit +81 -0
- metadata +184 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
# Provides a handler for interrupt signals (SIGINT), allowing the application to
|
4
|
+
# finish what it's currently working on.
|
5
|
+
class InterruptHandler
|
6
|
+
include Singleton
|
7
|
+
|
8
|
+
attr_accessor :isolate_signals, :signal_received, :reenable_on_interrupt
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
self.isolate_signals = false
|
12
|
+
self.signal_received = false
|
13
|
+
self.reenable_on_interrupt = false
|
14
|
+
|
15
|
+
Signal.trap('INT') do
|
16
|
+
if isolate_signals
|
17
|
+
self.signal_received = true
|
18
|
+
else
|
19
|
+
if reenable_on_interrupt
|
20
|
+
self.reenable_on_interrupt = false
|
21
|
+
self.isolate_signals = true
|
22
|
+
end
|
23
|
+
|
24
|
+
raise Interrupt # Allow interrupt to propagate to code
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class << self
|
30
|
+
# Provide a way to allow a single Ctrl-C interrupt to happen and atomically
|
31
|
+
# re-enable interrupt protections once that interrupt is propagated.
|
32
|
+
#
|
33
|
+
# This prevents a race condition where code like the following:
|
34
|
+
#
|
35
|
+
# begin
|
36
|
+
# InterruptHandler.disable!
|
37
|
+
# ... do stuff ...
|
38
|
+
# rescue Interrupt
|
39
|
+
# ... handle it ...
|
40
|
+
# ensure
|
41
|
+
# InterruptHandler.enable!
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# ...could have the `enable!` call to the interrupt handler not called in
|
45
|
+
# the event another interrupt was received in between the interrupt being
|
46
|
+
# handled and the `ensure` block being entered.
|
47
|
+
#
|
48
|
+
# Thus you should always write:
|
49
|
+
#
|
50
|
+
# begin
|
51
|
+
# InterruptHandler.disable_until_finished_or_interrupted do
|
52
|
+
# ... do stuff ...
|
53
|
+
# end
|
54
|
+
# rescue Interrupt
|
55
|
+
# ... handle it ...
|
56
|
+
# rescue
|
57
|
+
# ... handle any other exceptions ...
|
58
|
+
# end
|
59
|
+
def disable_until_finished_or_interrupted
|
60
|
+
instance.reenable_on_interrupt = true
|
61
|
+
instance.isolate_signals = false
|
62
|
+
yield
|
63
|
+
ensure
|
64
|
+
instance.isolate_signals = true
|
65
|
+
end
|
66
|
+
|
67
|
+
def disable!
|
68
|
+
instance.isolate_signals = false
|
69
|
+
end
|
70
|
+
|
71
|
+
def enable!
|
72
|
+
instance.isolate_signals = true
|
73
|
+
end
|
74
|
+
|
75
|
+
def isolate_from_interrupts
|
76
|
+
instance.signal_received = false
|
77
|
+
instance.isolate_signals = true
|
78
|
+
result = yield
|
79
|
+
instance.isolate_signals = false
|
80
|
+
result
|
81
|
+
end
|
82
|
+
|
83
|
+
def signal_received?
|
84
|
+
instance.signal_received
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Overcommit
|
2
|
+
# Encapsulates all communication to an output source.
|
3
|
+
class Logger
|
4
|
+
# Helper for creating a logger which outputs nothing.
|
5
|
+
def self.silent
|
6
|
+
new(File.open('/dev/null', 'w'))
|
7
|
+
end
|
8
|
+
|
9
|
+
# Creates a logger that will write to the given output stream.
|
10
|
+
#
|
11
|
+
# @param out [IO]
|
12
|
+
def initialize(out)
|
13
|
+
@out = out
|
14
|
+
end
|
15
|
+
|
16
|
+
# Write output without a trailing newline.
|
17
|
+
def partial(*args)
|
18
|
+
@out.print(*args)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Prints a newline character (alias for readability).
|
22
|
+
def newline
|
23
|
+
log
|
24
|
+
end
|
25
|
+
|
26
|
+
# Write a line of output.
|
27
|
+
#
|
28
|
+
# A newline character will always be appended.
|
29
|
+
def log(*args)
|
30
|
+
@out.puts(*args)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Write a line of output that is intended to be emphasized.
|
34
|
+
def bold(*args)
|
35
|
+
color('1', *args)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Write a line of output indicating a problem or error.
|
39
|
+
def error(*args)
|
40
|
+
color(31, *args)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Write a line of output indicating a problem or error which is emphasized
|
44
|
+
# over a regular problem or error.
|
45
|
+
def bold_error(*args)
|
46
|
+
color('1;31', *args)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Write a line of output indicating a successful or noteworthy event.
|
50
|
+
def success(*args)
|
51
|
+
color(32, *args)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Write a line of output indicating a potential cause for concern, but not
|
55
|
+
# an actual error.
|
56
|
+
def warning(*args)
|
57
|
+
color(33, *args)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Write a line of output indicating a potential cause for concern, but with
|
61
|
+
# greater emphasize compared to other warnings.
|
62
|
+
def bold_warning(*args)
|
63
|
+
color('1;33', *args)
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# Outputs text wrapped in ANSI escape code necessary to produce a given
|
69
|
+
# color/text display.
|
70
|
+
#
|
71
|
+
# @param code [String] ANSI escape code, e.g. '1;33' for "bold yellow"
|
72
|
+
# @param str [String] string to wrap
|
73
|
+
# @param partial [true,false] whether to omit a newline
|
74
|
+
def color(code, str, partial = false)
|
75
|
+
send(partial ? :partial : :log,
|
76
|
+
@out.tty? ? "\033[#{code}m#{str}\033[0m" : str)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Overcommit
|
2
|
+
# Utility class that encapsulates the handling of hook messages and whether
|
3
|
+
# they affect lines the user has modified or not.
|
4
|
+
#
|
5
|
+
# This class exposes an endpoint that extracts an appropriate hook/status
|
6
|
+
# output tuple from an array of {Overcommit::Hook::Message}s, respecting the
|
7
|
+
# configuration settings for the given hook.
|
8
|
+
class MessageProcessor
|
9
|
+
ERRORS_MODIFIED_HEADER = 'Errors on modified lines:'
|
10
|
+
WARNINGS_MODIFIED_HEADER = 'Warnings on modified lines:'
|
11
|
+
ERRORS_UNMODIFIED_HEADER = "Errors on lines you didn't modify:"
|
12
|
+
WARNINGS_UNMODIFIED_HEADER = "Warnings on lines you didn't modify:"
|
13
|
+
|
14
|
+
# @param hook [Overcommit::Hook::Base]
|
15
|
+
# @param unmodified_lines_setting [String] how to treat messages on
|
16
|
+
# unmodified lines
|
17
|
+
def initialize(hook, unmodified_lines_setting)
|
18
|
+
@hook = hook
|
19
|
+
@setting = unmodified_lines_setting
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns a hook status/output tuple from the messages this processor was
|
23
|
+
# initialized with.
|
24
|
+
#
|
25
|
+
# @return [Array<Symbol,String>]
|
26
|
+
def hook_result(messages)
|
27
|
+
status, output = basic_status_and_output(messages)
|
28
|
+
|
29
|
+
# Nothing to do if there are no problems to begin with
|
30
|
+
return [status, output] if status == :pass
|
31
|
+
|
32
|
+
# Return as-is if this type of hook doesn't have the concept of modified lines
|
33
|
+
return [status, output] unless @hook.respond_to?(:modified_lines_in_file)
|
34
|
+
|
35
|
+
handle_modified_lines(messages, status)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def handle_modified_lines(messages, status)
|
41
|
+
messages = remove_ignored_messages(messages)
|
42
|
+
|
43
|
+
messages_on_modified_lines, messages_on_unmodified_lines =
|
44
|
+
messages.partition { |message| message_on_modified_line?(message) }
|
45
|
+
|
46
|
+
output = print_messages(
|
47
|
+
messages_on_modified_lines,
|
48
|
+
ERRORS_MODIFIED_HEADER,
|
49
|
+
WARNINGS_MODIFIED_HEADER
|
50
|
+
)
|
51
|
+
output += print_messages(
|
52
|
+
messages_on_unmodified_lines,
|
53
|
+
ERRORS_UNMODIFIED_HEADER,
|
54
|
+
WARNINGS_UNMODIFIED_HEADER
|
55
|
+
)
|
56
|
+
|
57
|
+
[transform_status(status, messages_on_modified_lines), output]
|
58
|
+
end
|
59
|
+
|
60
|
+
def transform_status(status, messages_on_modified_lines)
|
61
|
+
# `report` indicates user wants the original status
|
62
|
+
return status if @setting == 'report'
|
63
|
+
|
64
|
+
error_messages, warning_messages =
|
65
|
+
messages_on_modified_lines.partition { |msg| msg.type == :error }
|
66
|
+
|
67
|
+
if can_upgrade_to_warning?(status, error_messages)
|
68
|
+
status = :warn
|
69
|
+
end
|
70
|
+
|
71
|
+
if can_upgrade_to_passing?(status, warning_messages)
|
72
|
+
status = :pass
|
73
|
+
end
|
74
|
+
|
75
|
+
status
|
76
|
+
end
|
77
|
+
|
78
|
+
def can_upgrade_to_warning?(status, error_messages)
|
79
|
+
status == :fail && error_messages.empty?
|
80
|
+
end
|
81
|
+
|
82
|
+
def can_upgrade_to_passing?(status, warning_messages)
|
83
|
+
status == :warn && @setting == 'ignore' && warning_messages.empty?
|
84
|
+
end
|
85
|
+
|
86
|
+
# Returns status and output for messages assuming no special treatment of
|
87
|
+
# messages occurring on unmodified lines.
|
88
|
+
def basic_status_and_output(messages)
|
89
|
+
status =
|
90
|
+
if messages.any? { |message| message.type == :error }
|
91
|
+
:fail
|
92
|
+
elsif messages.any? { |message| message.type == :warning }
|
93
|
+
:warn
|
94
|
+
else
|
95
|
+
:pass
|
96
|
+
end
|
97
|
+
|
98
|
+
output = ''
|
99
|
+
if messages.any?
|
100
|
+
output += messages.join("\n") + "\n"
|
101
|
+
end
|
102
|
+
|
103
|
+
[status, output]
|
104
|
+
end
|
105
|
+
|
106
|
+
def print_messages(messages, error_heading, warning_heading)
|
107
|
+
output = ''
|
108
|
+
errors, warnings = messages.partition { |msg| msg.type == :error }
|
109
|
+
|
110
|
+
if errors.any?
|
111
|
+
output += "#{error_heading}\n#{errors.join("\n")}\n"
|
112
|
+
end
|
113
|
+
|
114
|
+
if warnings.any?
|
115
|
+
output += "#{warning_heading}\n#{warnings.join("\n")}\n"
|
116
|
+
end
|
117
|
+
|
118
|
+
output
|
119
|
+
end
|
120
|
+
|
121
|
+
def remove_ignored_messages(messages)
|
122
|
+
# If user wants to ignore messages on unmodified lines, simply remove them
|
123
|
+
return messages unless @setting == 'ignore'
|
124
|
+
|
125
|
+
messages.select { |message| message_on_modified_line?(message) }
|
126
|
+
end
|
127
|
+
|
128
|
+
def message_on_modified_line?(message)
|
129
|
+
@hook.modified_lines_in_file(message.file).include?(message.line)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Overcommit
|
4
|
+
# Provide a set of callbacks which can be executed as events occur during the
|
5
|
+
# course of {HookRunner#run}.
|
6
|
+
class Printer
|
7
|
+
attr_reader :log
|
8
|
+
|
9
|
+
def initialize(logger, context)
|
10
|
+
@log = logger
|
11
|
+
@context = context
|
12
|
+
end
|
13
|
+
|
14
|
+
# Executed at the very beginning of running the collection of hooks.
|
15
|
+
def start_run
|
16
|
+
log.bold "Running #{hook_script_name} hooks"
|
17
|
+
end
|
18
|
+
|
19
|
+
def nothing_to_run
|
20
|
+
log.success "✓ No applicable #{hook_script_name} hooks to run"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Executed at the start of an individual hook run.
|
24
|
+
def start_hook(hook)
|
25
|
+
unless hook.quiet?
|
26
|
+
print_header(hook)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def hook_skipped(hook)
|
31
|
+
log.warning "Skipping #{hook.name}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def required_hook_not_skipped(hook)
|
35
|
+
log.warning "Cannot skip #{hook.name} since it is required"
|
36
|
+
end
|
37
|
+
|
38
|
+
# Executed at the end of an individual hook run.
|
39
|
+
def end_hook(hook, status, output)
|
40
|
+
# Want to print the header for quiet hooks only if the result wasn't good
|
41
|
+
# so that the user knows what failed
|
42
|
+
print_header(hook) if hook.quiet? && ![:good, :pass].include?(status)
|
43
|
+
|
44
|
+
print_result(hook, status, output)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Executed when a hook run was interrupted/cancelled by user.
|
48
|
+
def run_interrupted
|
49
|
+
log.newline
|
50
|
+
log.warning '⚠ Hook run interrupted by user'
|
51
|
+
log.newline
|
52
|
+
end
|
53
|
+
|
54
|
+
# Executed when one or more hooks by the end of the run.
|
55
|
+
def run_failed
|
56
|
+
log.newline
|
57
|
+
log.error "✗ One or more #{hook_script_name} hooks failed"
|
58
|
+
log.newline
|
59
|
+
end
|
60
|
+
|
61
|
+
# Executed when no hooks failed by the end of the run.
|
62
|
+
def run_succeeded
|
63
|
+
log.newline
|
64
|
+
log.success "✓ All #{hook_script_name} hooks passed"
|
65
|
+
log.newline
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def print_header(hook)
|
71
|
+
hook_name = "[#{hook.name}] "
|
72
|
+
log.partial hook.description
|
73
|
+
log.partial '.' * [70 - hook.description.length - hook_name.length, 0].max
|
74
|
+
log.partial hook_name
|
75
|
+
end
|
76
|
+
|
77
|
+
def print_result(hook, status, output) # rubocop:disable CyclomaticComplexity, MethodLength
|
78
|
+
case status
|
79
|
+
when :pass
|
80
|
+
log.success 'OK' unless hook.quiet?
|
81
|
+
when :good
|
82
|
+
log.success 'OK'
|
83
|
+
log.bold_error 'Hook returned a status of `:good`. This is deprecated ' \
|
84
|
+
'in favor of `:pass` and will be removed in a future ' \
|
85
|
+
'version of Overcommit'
|
86
|
+
when :warn
|
87
|
+
log.warning 'WARNING'
|
88
|
+
print_report(output, :bold_warning)
|
89
|
+
when :bad
|
90
|
+
log.error 'FAILED'
|
91
|
+
log.bold_error 'Hook returned a status of `:bad`. This is deprecated ' \
|
92
|
+
'in favor of `:fail` and will be removed in a future ' \
|
93
|
+
'version of Overcommit'
|
94
|
+
print_report(output, :bold_error)
|
95
|
+
when :fail
|
96
|
+
log.error 'FAILED'
|
97
|
+
print_report(output, :bold_error)
|
98
|
+
when :interrupt
|
99
|
+
log.error 'INTERRUPTED'
|
100
|
+
print_report(output, :bold_error)
|
101
|
+
else
|
102
|
+
log.error '???'
|
103
|
+
print_report("Hook returned unknown status `#{status.inspect}` -- ignoring.",
|
104
|
+
:bold_error)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def print_report(output, format = :log)
|
109
|
+
log.send(format, output) unless output.nil? || output.empty?
|
110
|
+
end
|
111
|
+
|
112
|
+
def hook_script_name
|
113
|
+
@context.hook_script_name
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'childprocess'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
module Overcommit
|
5
|
+
# Manages execution of a child process, collecting the exit status and
|
6
|
+
# standard out/error output.
|
7
|
+
class Subprocess
|
8
|
+
# Encapsulates the result of a process.
|
9
|
+
Result = Struct.new(:status, :stdout, :stderr) do
|
10
|
+
def success?
|
11
|
+
status == 0
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class << self
|
16
|
+
# Spawns a new process using the given array of arguments (the first
|
17
|
+
# element is the command).
|
18
|
+
def spawn(args)
|
19
|
+
process = ChildProcess.build(*args)
|
20
|
+
|
21
|
+
out, err = assign_output_streams(process)
|
22
|
+
|
23
|
+
process.start
|
24
|
+
process.wait
|
25
|
+
|
26
|
+
err.rewind
|
27
|
+
out.rewind
|
28
|
+
|
29
|
+
Result.new(process.exit_code, out.read, err.read)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# @param process [ChildProcess]
|
35
|
+
# @return [Array<IO>]
|
36
|
+
def assign_output_streams(process)
|
37
|
+
%w[out err].map do |stream_name|
|
38
|
+
::Tempfile.new(stream_name).tap do |stream|
|
39
|
+
stream.sync = true
|
40
|
+
process.io.send("std#{stream_name}=", stream)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|