command_manager.py 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. import subprocess
  2. import select
  3. from typing import List
  4. from opendevin.lib.event import Event
  5. from opendevin.sandbox.sandbox import DockerInteractive
  6. class BackgroundCommand:
  7. def __init__(self, id: int, command: str, dir: str):
  8. self.command = command
  9. self.id = id
  10. self.shell = DockerInteractive(id=str(id), workspace_dir=dir)
  11. self.shell.execute_in_background(command)
  12. def get_logs(self):
  13. # TODO: get an exit code if process is exited
  14. return self.shell.read_logs()
  15. class CommandManager:
  16. def __init__(self, dir):
  17. self.cur_id = 0
  18. self.directory = dir
  19. self.background_commands = {}
  20. self.shell = DockerInteractive(id="default", workspace_dir=dir)
  21. def run_command(self, command: str, background=False) -> str:
  22. if background:
  23. return self.run_background(command)
  24. else:
  25. return self.run_immediately(command)
  26. def run_immediately(self, command: str) -> str:
  27. exit_code, output = self.shell.execute(command)
  28. if exit_code != 0:
  29. raise ValueError('Command failed with exit code ' + str(exit_code) + ': ' + output)
  30. return output
  31. def run_background(self, command: str) -> str:
  32. bg_cmd = BackgroundCommand(self.cur_id, command, self.directory)
  33. self.cur_id += 1
  34. self.background_commands[bg_cmd.id] = bg_cmd
  35. return "Background command started. To stop it, send a `kill` action with id " + str(bg_cmd.id)
  36. def kill_command(self, id: int) -> str:
  37. # TODO: get log events before killing
  38. self.background_commands[id].shell.close()
  39. del self.background_commands[id]
  40. def get_background_events(self) -> List[Event]:
  41. events = []
  42. for id, cmd in self.background_commands.items():
  43. output = cmd.get_logs()
  44. events.append(Event('output', {
  45. 'output': output,
  46. 'id': id,
  47. 'command': cmd.command,
  48. }))
  49. return events