|
"""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") |
|
|