... неужели есть способ сделать это более пьяным, а может быть, даже несколько элегантным способом?
Элегантный находится в глазах кодер. Вы можете найти более элегантным использование одной из множества различных оболочек Git. Тем не менее, ваш первый метод является относительно простым, который имеет много достоинств. Мы можем избежать нового 3.7 capture_output=True
в случае, если кто-то ( кашель me кашель ) имеет 3.6 в качестве базовой версии в своей удобной тестовой системе и разрешает использование оболочки , что требуется для расширения $(...)
, которое более или менее дает нам вашу первую попытку. Но мы можем использовать тот факт, что --git-dir
эквивалентно установке GIT_DIR
в среде, что означает, что нам не нужно делать это дважды в нашей командной строке:
import os, subprocess
env = os.environ.copy()
env["GIT_DIR"] = "../micropython/.git"
cmd = "git describe --tags $(git rev-list --tags='v[0-9].[0-9]*' --max-count=1)"
ret = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
env=env, shell=True)
(используя capture_output=True
как сокращение для двух stdout / stderr, конечно, хорошо, если все ваши питоны 3,7 или более поздние).
Обратите внимание, что мы должны сохранить результат . Вот почему у нас есть ret =
здесь, чтобы зафиксировать результат. Теперь у нас есть результат в ret
:
>>> print(ret)
CompletedProcess(args="git describe --tags $(git rev-list --tags='v[0-9].[0-9]*' --max-count=1)", returncode=0, stdout=b'v2.24.0\n', stderr=b'')
Обратите внимание, что retcode
равен нулю, т. Е. Вещь в целом сработала, а два поля stdout
и stderr
равны байтов вместо строк. Чтобы исправить это, мы можем либо декодировать результат впоследствии:
>>> print(ret.stdout.decode('utf-8'))
v2.24.0
>>>
(что предполагает вывод UTF-8), либо сделать так, чтобы subprocess
сделал это за нас. Современный (3.7 или более поздний) способ сделать это - установить text=True
, но, поскольку я все еще использую 3.6 на этой конкретной машине, я использую более старый способ:
ret = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
env=env, shell=True, universal_newlines=True)
, что приводит к более полезное:
>>> print(ret)
CompletedProcess(args="git describe --tags $(git rev-list --tags='v[0-9].[0-9]*' --max-count=1)", returncode=0, stdout='v2.24.0\n', stderr='')
Обратите внимание, что для использования shell=True
требуется , чтобы тщательно проверить любую команду, которую вы можете запустить . В документации также говорится, что в Windows вы получаете все, что находится в «переменной среды COMSPEC
». Может быть разумнее использовать значение по умолчанию shell=False
и вызывать каждый компонент отдельно:
import os, shlex, subprocess
env = os.environ.copy()
env["GIT_DIR"] = "../micropython/.git"
cmd = shlex.split("git rev-list --tags='v[0-9].[0-9]*' --max-count=1")
ret = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
if ret.returncode == 0:
# Note: I tested this w/o using universal_newlines=True and it
# worked fine, although the notion of adding a list of bytes to
# a list of strings seems a bit odd. This might not work well on
# Windows; consider adding `text=True` or `universal_newlines=True`
# above (and again below).
cmd = shlex.split("git describe --tags") + [ret.stdout.strip()]
ret = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
В этот момент ret
снова подходит для проверки: если ret.returncode
равно нулю, ret.stdout
имеет строка байтов от git sdescribe
. При необходимости добавьте соответствующий перевод байтов в текст.
>>> print(ret)
CompletedProcess(args=['git', 'describe', '--tags', b'da72936f544fec5a335e66432610e4cef4430991'], returncode=0, stdout=b'v2.24.0\n', stderr=b'')
Если ret.returncode
равен , а не ноль, либо git describe
не выполнен, либо произошел сбой более раннего git rev-list
. У вас есть сбойная команда в ret.args
, ее статус в ret.returncode
, любой стандартный текст в ret.stdout
и любое сообщение об ошибке от Git в ret.stderr
.