macOS compatibility (#23)

* Correcting URL for github; ra-aid.git -> RA.Aid.git

* Additional fix to cloning instructions

* Initial draft of tweaks to add macOS compatibility

* Changing LS test to check for not-zero instead of specific error code

* Further macOS compatibility tweaks - dealing with mystery control characters

* Additional compatibility for macOS - flag as macOS, and detect and change command based it

* Removing unneeded variable
This commit is contained in:
Will 2024-12-30 12:38:06 -05:00 committed by GitHub
parent 96c4620df0
commit ccb4756035
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 36 additions and 16 deletions

3
.gitignore vendored
View File

@ -7,3 +7,6 @@ __pycache__/
/dist /dist
/.ra-aid /.ra-aid
.coverage .coverage
/.venv
/venv
/.idea

View File

@ -10,6 +10,9 @@ import shutil
from typing import List, Tuple from typing import List, Tuple
# Add macOS detection
IS_MACOS = os.uname().sysname == "Darwin"
def run_interactive_command(cmd: List[str]) -> Tuple[bytes, int]: def run_interactive_command(cmd: List[str]) -> Tuple[bytes, int]:
""" """
Runs an interactive command with a pseudo-tty, capturing combined output. Runs an interactive command with a pseudo-tty, capturing combined output.
@ -57,7 +60,10 @@ def run_interactive_command(cmd: List[str]) -> Tuple[bytes, int]:
os.environ['PAGER'] = '' os.environ['PAGER'] = ''
# Run command with script for TTY and output capture # Run command with script for TTY and output capture
os.system(f"script -q -c {shlex.quote(shell_cmd)} {shlex.quote(output_path)}") if IS_MACOS:
os.system(f"script -q {shlex.quote(output_path)} {shell_cmd}")
else:
os.system(f"script -q -c {shlex.quote(shell_cmd)} {shlex.quote(output_path)}")
# Read and clean the output # Read and clean the output
with open(output_path, "rb") as f: with open(output_path, "rb") as f:

View File

@ -26,7 +26,7 @@ def test_stderr_capture():
# Use a command that definitely writes to stderr # Use a command that definitely writes to stderr
output, retcode = run_interactive_command(["/bin/bash", "-c", "ls /nonexistent/path"]) output, retcode = run_interactive_command(["/bin/bash", "-c", "ls /nonexistent/path"])
assert b"No such file or directory" in output assert b"No such file or directory" in output
assert retcode == 2 # ls returns 2 for file not found assert retcode != 0 # ls returns 0 upon success
def test_command_not_found(): def test_command_not_found():
@ -51,25 +51,28 @@ def test_interactive_command():
assert b"stderr" in output assert b"stderr" in output
assert retcode == 0 assert retcode == 0
def test_large_output(): def test_large_output():
"""Test handling of commands that produce large output.""" """Test handling of commands that produce large output."""
# Generate a large output with predictable content # Generate a large output with predictable content
cmd = "for i in {1..10000}; do echo \"Line $i of test output\"; done" cmd = "for i in {1..10000}; do echo \"Line $i of test output\"; done"
output, retcode = run_interactive_command(["/bin/bash", "-c", cmd]) output, retcode = run_interactive_command(["/bin/bash", "-c", cmd])
# Filter out script header/footer # Clean up specific artifacts (e.g., ^D)
lines = [line for line in output.splitlines() if b"Script" not in line and line.strip()] output_cleaned = output.lstrip(b'^D') # Remove the leading ^D if present
# Split and filter lines
lines = [line.strip() for line in output_cleaned.splitlines() if b"Script" not in line and line.strip()]
# Verify we got all 10000 lines # Verify we got all 10000 lines
assert len(lines) == 10000 assert len(lines) == 10000, f"Expected 10000 lines, but got {len(lines)}"
# Verify content of some lines # Verify content of some lines
assert lines[0] == b"Line 1 of test output" assert lines[0] == b"Line 1 of test output", f"Unexpected line: {lines[0]}"
assert lines[999] == b"Line 1000 of test output" assert lines[999] == b"Line 1000 of test output", f"Unexpected line: {lines[999]}"
assert lines[-1] == b"Line 10000 of test output" assert lines[-1] == b"Line 10000 of test output", f"Unexpected line: {lines[-1]}"
assert retcode == 0 # Verify return code
assert retcode == 0, f"Unexpected return code: {retcode}"
def test_unicode_handling(): def test_unicode_handling():
@ -124,9 +127,17 @@ def test_realtime_output():
assert b"third" in lines[2] assert b"third" in lines[2]
assert retcode == 0 assert retcode == 0
def test_tty_available(): def test_tty_available():
"""Test that commands have access to a TTY.""" """Test that commands have access to a TTY."""
# Run the tty command
output, retcode = run_interactive_command(["/bin/bash", "-c", "tty"]) output, retcode = run_interactive_command(["/bin/bash", "-c", "tty"])
assert b"/dev/pts/" in output # Should show a PTY device
# Clean up specific artifacts (e.g., ^D)
output_cleaned = output.lstrip(b'^D') # Remove leading ^D if present
# Debug: Print cleaned output
print(f"Cleaned TTY Output: {output_cleaned}")
# Check if the output contains a valid TTY path
assert b"/dev/pts/" in output_cleaned or b"/dev/ttys" in output_cleaned, f"Unexpected TTY output: {output_cleaned}"
assert retcode == 0 assert retcode == 0