Skip to content

Commit

Permalink
Process interactive commands and stream output in logs (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
SmartManoj authored Aug 11, 2024
1 parent ad96c2a commit 7149834
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 33 deletions.
96 changes: 64 additions & 32 deletions opendevin/runtime/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from fastapi.responses import JSONResponse
from pathspec import PathSpec
from pathspec.patterns import GitWildMatchPattern
from pexpect import EOF, TIMEOUT, ExceptionPexpect
from pydantic import BaseModel
from uvicorn import run

Expand Down Expand Up @@ -228,43 +229,74 @@ def _get_bash_prompt_and_update_pwd(self):
prompt += '$'
return prompt + ' '

def _execute_bash(
def _send_interrupt(
self,
command: str,
timeout: int | None,
keep_prompt: bool = True,
) -> tuple[str, int]:
logger.exception(
f'Command "{command}" timed out, killing process...', exc_info=False
)
# send a SIGINT to the process
self.shell.sendintr()
self.shell.expect(self.__bash_expect_regex, timeout=timeout)
command_output = self.shell.before
return (
f'Command: "{command}" timed out. Sent SIGINT to the process: {command_output}',
130,
)

def _execute_bash(
self, command: str, timeout: int | None, keep_prompt: bool = True
) -> tuple[str, int]:
logger.debug(f'Executing command: {command}')
try:
self.shell.sendline(command)
self.shell.expect(self.__bash_expect_regex, timeout=timeout)

output = self.shell.before

# Get exit code
self.shell.sendline('echo $?')
logger.debug(f'Executing command for exit code: {command}')
self.shell.expect(self.__bash_expect_regex, timeout=timeout)
_exit_code_output = self.shell.before
logger.debug(f'Exit code Output: {_exit_code_output}')
exit_code = int(_exit_code_output.strip().split()[0])

except pexpect.TIMEOUT as e:
self.shell.sendintr() # send SIGINT to the shell
self.shell.expect(self.__bash_expect_regex, timeout=timeout)
output = self.shell.before
output += (
'\r\n\r\n'
+ f'[Command timed out after {timeout} seconds. SIGINT was sent to interrupt it.]'
)
exit_code = 130 # SIGINT
logger.error(f'Failed to execute command: {command}. Error: {e}')

finally:
bash_prompt = self._get_bash_prompt_and_update_pwd()
if keep_prompt:
output += '\r\n' + bash_prompt
logger.debug(f'Command output: {output}')
self.shell.sendline(command)

prompts = [
r'Do you want to continue\? \[Y/n\]',
self.__bash_expect_regex,
EOF,
TIMEOUT,
]
output = ''
timeout_counter = 0
timeout = 5
while True:
try:
# Wait for one of the prompts
index = self.shell.expect(prompts, timeout=1)
line = self.shell.before
logger.info(line)
output += line
if index == 0:
self.shell.sendline('Y')
elif index == 1:
break
elif index == 2:
logger.debug('End of file')
break
elif index == 3:
timeout_counter += 1
if timeout_counter > timeout:
logger.exception(
'Command timed out, killing process...', exc_info=False
)
return self._send_interrupt(command, timeout=timeout)
except ExceptionPexpect as e:
logger.exception(f'Unexpected exception: {e}')
break

if keep_prompt:
output += '\r\n' + self._get_bash_prompt_and_update_pwd()

# Get exit code
self.shell.sendline('echo $?')
logger.debug(f'Executing command for exit code: {command}')
self.shell.expect(self.__bash_expect_regex, timeout=timeout)
_exit_code_output = self.shell.before
logger.debug(f'Exit code Output: {_exit_code_output}')
exit_code = int(_exit_code_output.strip().split()[0])
logger.debug(f'Command output: {output}')

return output, exit_code

Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ async def test_env_vars_os_environ(temp_dir, box_class, run_as_devin):
print(obs)
assert obs.exit_code == 0, 'The exit code should be 0.'
assert (
obs.content.strip().split('\n\r')[0].strip() == 'BAZ'
obs.content.strip().split('\r\n')[0].strip() == 'BAZ'
), f'Output: [{obs.content}] for {box_class}'

await runtime.close()
Expand Down

0 comments on commit 7149834

Please sign in to comment.