Как запустить vimdiff из демона python

У меня были проблемы с vimdiff, python и демонами.

Дело в том, что я не могу использовать vimdiff с python при запуске программы в качестве демона, я не знаю, что происходит, он просто не генерирует файл diff.html. Это не проблема разрешения. Мое решение этой проблемы состояло в том, чтобы добавить & в конец команды, но diff.html не имеет обычной подсветки vimdiff, и я действительно хочу, чтобы он выводился с подсветкой.

Кто-нибудь знает, как запустить vimdiff из python, не теряя его свойств?

Я использую функцию daemon.DaemonContext() из библиотеки python-daemon для запуска программы в качестве демона.

Фрагмент:

from os import system

def generate_diff(old_file, new_file):
        system("vimdiff "+ old_file +" "+ new_file +" -c TOhtml -c 'w! diff.html' -c 'qa!' &")

person diegofelipe01    schedule 03.12.2020    source источник


Ответы (2)


Когда вы запускаете что-то в виде процесса-демона, среды не устанавливаются так же, как при запуске в терминале.

Ваш домашний .profile не выполняется для примера. Домашний каталог не будет установлен таким же образом, поэтому такие инструменты, как vim или vimdiff, не будут читать их .vimrc, поэтому всех этих персонализированных конфигураций там не будет.

Таким образом, есть вероятность, что PATH не настроен до такой степени, что он найдет команду (иначе /usr/bin там нет).

Легко протестировать, создайте скрипт, который будет распечатывать env в файл журнала или что-то в этом роде.

Поэтому используйте полный путь для команды, которую вы пытаетесь использовать. Или создайте сценарий, который настроит среду со всем, что нужно вашей команде, и вместо этого вызовет ее.

PS: Могу ли я также предложить использовать модуль подпроцесса Python вместо создания командной строки, как вы делаете, тем более, что вы запускаете его в фоновом режиме. https://docs.python.org/3/library/subprocess.html

Соображения безопасности: я очень надеюсь, что old_file и new_file не являются аргументами, контролируемыми пользователем. Процесс демона, скорее всего, работает от имени пользователя root, и если вы запустите свою команду как есть, любая команда может быть передана как имя файла и запущена в вашей системе как привилегированный пользователь. Это очень опасно. по крайней мере, поместите его в одинарные кавычки, чтобы строка не интерпретировалась. и подтвердите, что значения являются допустимыми существующими файлами перед вызовом вашей команды.

person Rob    schedule 03.12.2020

Как упоминалось в @Rob answer, вы должны использовать subprocessбиблиотека для прямого вызова vimdiff и управления аргументами вместо их интерпретации оболочкой. (Это не причина, почему это не работает для вас, но решение включает в себя принятие subprocess для управления потоками, передаваемыми порожденному vimdiff, поэтому давайте сначала примем его.)

Вы можете использовать subprocess для запуска эквивалентной команды:

subprocess.check_call(
    [
        "vimdiff",
        old_file,
        new_file,
        "-c",
        "TOhtml | w! diff.html | qa!"
    ],
)

Обратите внимание, что я объединил множество команд Vimscript, переданных как отдельные -c, в одну, используя разделитель команд Vimscript |, который хорошо работает в данном случае.

Теперь это все еще не удастся под daemon.DaemonContext(), он создаст diff.html, который, похоже, не включает старые и новые файлы (по большей части пустой шаблон html).

Чтобы решить эту проблему, вы можете явно перенаправить потоки (стандартный ввод, стандартный вывод и стандартная ошибка) на /dev/null, чтобы vimdiff не ждал пользовательского ввода (или не пытался отобразить вывод) и не застревал, пытаясь это сделать. .

Вы можете легко сделать это, используя subprocess, передавая вызову дополнительные аргументы:

subprocess.check_call(
    [
        "vimdiff",
        old_file,
        new_file,
        "-c",
        "TOhtml | w! diff.html | qa!"
    ],
    stdin=subprocess.DEVNULL,
    stdout=subprocess.DEVNULL,
    stderr=subprocess.DEVNULL,
)

Используя этот фрагмент, я получил diff.html, который был очень похож на тот, который я создал, выполняя шаги вручную с vimdiff. Единственная разница заключалась в том, что тот, который я создал, имел дополнительные пробелы в конце каждой строки в старом и новом файлах.

Оказывается, это произошло потому, что при интерактивном использовании vimdiff определял размер моего терминала и использовал это конкретное количество столбцов на дисплее, в то время как то же самое было невозможно, когда потоки были перенаправлены на /dev/null, и он не мог иметь доступ к терминалу, чтобы найти его настройки.

Если вы хотите изменить это, вы можете легко обойти это, установив 'columns' явно в вашей команде Vimscript. Например, для ширины 160 столбцов:

subprocess.check_call(
    [
        "vimdiff",
        old_file,
        new_file,
        "-c",
        "set columns=160 | TOhtml | w! diff.html | qa!"
    ],
    stdin=subprocess.DEVNULL,
    stdout=subprocess.DEVNULL,
    stderr=subprocess.DEVNULL,
)

Последнее препятствие, которое я обнаружил во время тестирования, заключалось в том, что daemon.DaemonContext() изменит текущий каталог на / (обычно это часть того, что влечет за собой настройка контекста демона), поэтому попытка записи в diff.html в текущем каталоге, скорее всего, потерпит неудачу (если вы не иметь привилегии суперпользователя, а затем он будет записывать в корневой каталог, что, скорее всего, не то, что вам нужно.)

Вы можете исправить это, вызвав os.chdir() внутри контекста демона чтобы перейти в каталог, в котором вы хотите создать файл diff.html, или передав путь к этому каталогу в качестве именованного аргумента cwd=... в subprocess.check_call().

person filbranden    schedule 04.12.2020