получить git теги от python 3.x на windows - PullRequest
0 голосов
/ 05 января 2020

Я пытался, но не смог выполнить, казалось бы, тривиальное задание в Python 3.8 на Windows 10. В PowerShell (ядро) мне требуется менее 2 минут, чтобы написать:

repo = "../micropython/git"
return (&git --git-dir=$repo describe --tags $(git --git-dir=$repo rev-list --tags='v[0-9].[0-9]*' --max-count=1))

результат 'v1.12' (или какой-либо самой новой версии), с которой ветвится

с использованием python Я не могу получить никаких результатов, потратив слишком много времени на этот предполагаемый oneliner

пробовал:

# 1 feeding it the commandline as text 
cmd_str = "git --git-dir=../micropython/.git describe --tags $(git --git-dir=../micropython/.git rev-list --tags='v[0-9].[0-9]*' --max-count=1)"
subprocess.run( cmdstr , capture_output=True,shell=True)

#2 splitting the cmdline using shlex.split 

command_line = """
git describe --tags $(git rev-list --tags=\"v[0-9].[0-9]*\" --max-count=1)
"""
cmd = shlex.split(command_line)
x = subprocess.run( cmd, capture_output=True )
print(x)

# 3 using the 'gitpython' library
would not even import .... : see issue below

#4..20 
many variations of the above 

https://github.com/gitpython-developers/GitPython/issues/970

так что для меня, как для разработчика, самый простой способ - просто раскошелиться на python для powershell (поскольку это кроссплатформенный) и получения зависимости.

Однако я начал это в python, а не в powershell, так как скрипт предназначен для сообщества python (и в качестве обучения опыт), конечно, есть способ сделать это более pylike, и, возможно, даже несколько элегантно?

Версии:

  • Microsoft Windows [Версия 10.0.19041.1]
  • git версия 2.24.1. windows .2
  • Python 3.8.1

1 Ответ

0 голосов
/ 06 января 2020

... неужели есть способ сделать это более пьяным, а может быть, даже несколько элегантным способом?

Элегантный находится в глазах кодер. Вы можете найти более элегантным использование одной из множества различных оболочек 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...