Python subprocess.popen завершается ошибкой при взаимодействии с подпроцессом

У меня есть скрипт сборки Python для приложения Xamarin, который мне нужно скомпилировать в разные ipa и apk в зависимости от локали.

Сценарий манипулирует необходимыми значениями в info.plist и манифесте Android, а затем создает каждую из версий, используя subprocess.popen для вызова xbuild. Или, по крайней мере, так оно и должно быть.

Проблема в том, что когда я все равно взаимодействую с подпроцессом (в основном мне нужно подождать, пока это не будет сделано, прежде чем я начну изменять значения для следующей версии)

Это работает:

    build_path = os.path.dirname(os.path.realpath(__file__))
    ipa_path = "/path/to/my.ipa"

    cmd = '/Library/Frameworks/Mono.framework/Versions/4.6.2/Commands/xbuild /p:Configuration="Release" /p:Platform="iPhone" /p:IpaPackageDir="%s" /t:Build %s/MyApp/iOS/MyApp.iOS.csproj' % (ipa_path, build_path)

    subprocess.Popen(cmd, env=os.environ, shell=True)

Однако это приведет к тому, что скрипт python будет продолжен параллельно со сборкой.

Если я сделаю это:

    subprocess.Popen(cmd, env=os.environ, shell=True).wait()

Ошибка Xbuild со следующим сообщением об ошибке:

    Build FAILED.
    Errors:

    /Users/sune/dev/MyApp/iOS/MyApp.iOS.csproj: error :
    /Users/sune/dev/MyApp/iOS/MyApp.iOS.csproj: There is an unclosed literal string.
    Line 2434, position 56.

Сбой в течение миллисекунд после вызова, тогда как обычно процесс сборки занимает несколько минут

Любые другие сокращенные методы subprocess.popen, такие как.call, .check_call, и базовые операции subprocess.poll и subprocess.communicate вызывают такую ​​же ошибку.

Что действительно странно, так это то, что даже вызов time.sleep может вызвать ту же ошибку:

    subprocess.Popen(cmd, env=os.environ, shell=True)

    time.sleep(2)

Что я не понимаю, потому что, насколько я понимаю, я должен быть в состоянии сделать что-то вроде этого:

    shell = subprocess.Popen(cmd, env=os.environ, shell=True)

    while shell.poll() is None:
        time.sleep(2)

    print "done"

По сути, добиться того же, что и при вызове shell.wait()

Изменить: Использование списка команд вместо строки

Если я использую список команд и shell=False, как это

      cmd = [
        '/Library/Frameworks/Mono.framework/Versions/4.6.2/Commands/xbuild',
        '/p:Configuration="Release"',
        '/p:Platform="iPhone"',
        '/p:IpaPackageDir="%s' % ipa_path,
        '/t:Build %s/MyApp/iOS/MyApp.iOS.csproj' % build_path

    ]

    subprocess.Popen(cmd, env=os.environ, shell=False)

Тогда это результат:

    MSBUILD: error MSBUILD0003: Please specify the project or solution file to build, as none was found in the current directory.

Любой вклад очень ценится. Я бьюсь головой о стену здесь.

1 ответ

Решение

Я твердо верю, что это невозможно. Это должно быть недостатком способа реализации модуля подпроцесса.

xbuild порождает несколько подпроцессов во время сборки, и при опросе на состояние подпроцесс в python обнаружит, что один из них имеет ненулевой статус возврата, и остановит выполнение одного или нескольких подпроцессов xbuild, что приведет к сбою сборки, как описано.

В итоге я использовал скрипт bash для компиляции и использовал python для работы с XML-файлами и т. Д.

Другие вопросы по тегам