cli.py содержит функцию run_cli(), которая получает 4 функции(выбирает реализации интерфейса):
read_command - Возвращает новую команду для исполнения () -> str
substitute - Производит замены $variable на значение variable в окружении. Сама анализирует кавычки. str -> str
tokenize - Разбивает строку на токены str -> List[str]
interpret - Запускает токенизированную команду(List[str]) и ждёт её завершения. List[str] -> Nothing
Алгоритм работы:
- Считать команду с помощью read_command,
- Сделать замены с помощью substitute,
- Разбить команду на токены с помощью tokenize,
- Запустить команду с помощью interpret
Реализация read_command сейчас считывает строку с консоли.
Реализация substitute сейчас производит замены всех $var вне строк в одинарных кавычках
Реализация tokenize сейчас использует shlex.split() для разбиения на токены
Реализация interpret:
- Разбить входные токены на одиночные команды(без пайпов(|))
- Запустить все одиночные команды, передав им в качестве stdin и stdout соответствующие анонимные пайпы.
- Дождаться завершения каждой команды с помощью метода .wait() у объекта, возвращенного после запуска команды. Закрыть все файловые дескрипторы, созданные для коммуникации.
- Считать и вывести stdout последней команды.
Запуск одиночной команды производится таким алгоритмом:
- Попытаться запустить команду как встроенную.
- Если удалось, получить поток и обернуть его своим классом, добавив метод .wait(), который дожидается завершения.
- Иначе запустить процесс и вернуть Popen объект, у которого есть .wait() для ожидания завершения.
По сути запуск одиночной команды возвращает какой-то объект с методом .wait() (такой интерфейс)