| | """Execute code in a Docker container""" |
| | import os |
| | import subprocess |
| |
|
| | import docker |
| | from docker.errors import ImageNotFound |
| |
|
| | from autogpt.workspace import WORKSPACE_PATH, path_in_workspace |
| |
|
| |
|
| | def execute_python_file(file: str) -> str: |
| | """Execute a Python file in a Docker container and return the output |
| | |
| | Args: |
| | file (str): The name of the file to execute |
| | |
| | Returns: |
| | str: The output of the file |
| | """ |
| |
|
| | print(f"Executing file '{file}' in workspace '{WORKSPACE_PATH}'") |
| |
|
| | if not file.endswith(".py"): |
| | return "Error: Invalid file type. Only .py files are allowed." |
| |
|
| | file_path = path_in_workspace(file) |
| |
|
| | if not os.path.isfile(file_path): |
| | return f"Error: File '{file}' does not exist." |
| |
|
| | if we_are_running_in_a_docker_container(): |
| | result = subprocess.run( |
| | f"python {file_path}", capture_output=True, encoding="utf8", shell=True |
| | ) |
| | if result.returncode == 0: |
| | return result.stdout |
| | else: |
| | return f"Error: {result.stderr}" |
| |
|
| | try: |
| | client = docker.from_env() |
| |
|
| | |
| | |
| | |
| | image_name = "python:3-alpine" |
| | try: |
| | client.images.get(image_name) |
| | print(f"Image '{image_name}' found locally") |
| | except ImageNotFound: |
| | print(f"Image '{image_name}' not found locally, pulling from Docker Hub") |
| | |
| | low_level_client = docker.APIClient() |
| | for line in low_level_client.pull(image_name, stream=True, decode=True): |
| | |
| | status = line.get("status") |
| | progress = line.get("progress") |
| | if status and progress: |
| | print(f"{status}: {progress}") |
| | elif status: |
| | print(status) |
| |
|
| | container = client.containers.run( |
| | image_name, |
| | f"python {file}", |
| | volumes={ |
| | os.path.abspath(WORKSPACE_PATH): { |
| | "bind": "/workspace", |
| | "mode": "ro", |
| | } |
| | }, |
| | working_dir="/workspace", |
| | stderr=True, |
| | stdout=True, |
| | detach=True, |
| | ) |
| |
|
| | container.wait() |
| | logs = container.logs().decode("utf-8") |
| | container.remove() |
| |
|
| | |
| | |
| |
|
| | return logs |
| |
|
| | except docker.errors.DockerException as e: |
| | print( |
| | "Could not run the script in a container. If you haven't already, please install Docker https://docs.docker.com/get-docker/" |
| | ) |
| | return f"Error: {str(e)}" |
| |
|
| | except Exception as e: |
| | return f"Error: {str(e)}" |
| |
|
| |
|
| | def execute_shell(command_line: str) -> str: |
| | """Execute a shell command and return the output |
| | |
| | Args: |
| | command_line (str): The command line to execute |
| | |
| | Returns: |
| | str: The output of the command |
| | """ |
| | current_dir = os.getcwd() |
| | |
| | if str(WORKSPACE_PATH) not in current_dir: |
| | os.chdir(WORKSPACE_PATH) |
| |
|
| | print(f"Executing command '{command_line}' in working directory '{os.getcwd()}'") |
| |
|
| | result = subprocess.run(command_line, capture_output=True, shell=True) |
| | output = f"STDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}" |
| |
|
| | |
| |
|
| | os.chdir(current_dir) |
| |
|
| | return output |
| |
|
| |
|
| | def execute_shell_popen(command_line) -> str: |
| | """Execute a shell command with Popen and returns an english description |
| | of the event and the process id |
| | |
| | Args: |
| | command_line (str): The command line to execute |
| | |
| | Returns: |
| | str: Description of the fact that the process started and its id |
| | """ |
| | current_dir = os.getcwd() |
| | |
| | if str(WORKSPACE_PATH) not in current_dir: |
| | os.chdir(WORKSPACE_PATH) |
| |
|
| | print(f"Executing command '{command_line}' in working directory '{os.getcwd()}'") |
| |
|
| | do_not_show_output = subprocess.DEVNULL |
| | process = subprocess.Popen( |
| | command_line, shell=True, stdout=do_not_show_output, stderr=do_not_show_output |
| | ) |
| |
|
| | |
| |
|
| | os.chdir(current_dir) |
| |
|
| | return f"Subprocess started with PID:'{str(process.pid)}'" |
| |
|
| |
|
| | def we_are_running_in_a_docker_container() -> bool: |
| | """Check if we are running in a Docker container |
| | |
| | Returns: |
| | bool: True if we are running in a Docker container, False otherwise |
| | """ |
| | return os.path.exists("/.dockerenv") |
| |
|