pv2/util/gitutil.py
Louis Abel 185d144567
Add importutil module
Adds the importutil module that allows targetting a specific source RPM
file and importing and tagging. It aims to keep the same structure of
git.centos.org.

Other changes:

* constants.py: New constants added for git and rpm
* error.py: New git and rpm error classes added
* fileutil.py:
  * Add filter_files_inverse (matches everything but the filter)
  * Add get_magic_file (returns magic data from a file)
  * Add get_magic_content (returns magic data from data/content)
* generic.py: Add safe_encoding to return a urlquote string
* processor.py:
  * Add run_proc_foreground_shell to support shell calls
  * Add run_proc_no_output_shell to support shell calls
* rpmutil.py:
  * get_rpm_header now supports verify_signature parameter (default
    false). If set to true and key is not available, raises exception.
  * Add verify_rpm_signature, which allows local rpm verification
    without ingesting the whole header into a usable object.
  * Add add_rpm_key, which enables a user to add a key to the rpm
    keyring.
2023-06-27 17:20:44 -07:00

157 lines
4.1 KiB
Python

# -*-:python; coding:utf-8; -*-
# author: Louis Abel <label@rockylinux.org>
"""
Git Utilities and Accessories
"""
import os
import git as rawgit
from git import Repo
from git import exc as gitexc
from pv2.util import error as err
__all__ = [
'add_all',
'clone',
'commit',
'init',
'push',
'tag',
'lsremote'
]
def add_all(repo):
"""
Add all files to repo
"""
try:
repo.git.add(all=True)
except Exception as exc:
raise err.GitCommitError('Unable to add files') from exc
def checkout(repo, branch: str, orphan: bool = False):
"""
Checkout a branch for some reason or another
Only set orphan to true if this is a brand new branch that never existed
and you want to avoid tracking from another branch.
"""
# We are NOT using repo.heads.NAME.checkout() because it does not play
# very well with branches that have dashes in the name
try:
if orphan:
repo.git.checkout('--orphan', branch)
else:
repo.git.checkout(branch)
except repo.git.exc.CheckoutError as exc:
raise err.GitCheckoutError('Unable to checkout that branch.') from exc
def clone(
git_url_path: str,
repo_name: str,
to_path: str = None,
branch: str = None
):
"""
clone a repo. if branch is None, it will just clone the repo in general and
you'll be expected to checkout.
"""
if not to_path:
clone_path = f'/var/tmp/{repo_name}'
try:
repo = Repo.clone_from(
url=git_url_path,
to_path=clone_path,
branch=branch
)
# pylint: disable=no-member
except gitexc.CommandError as exc:
raise err.GitInitError(f'Repo could not be cloned: {exc.stderr}') from exc
return repo
def commit(repo, message: str):
"""
create a commit message (no tag)
"""
try:
repo.index.commit(message=message)
# pylint: disable=no-member
except gitexc.CommandError as exc:
raise err.GitCommitError('Unable to create commit') from exc
def init(
git_url_path: str,
repo_name: str,
to_path: str = None,
branch: str = None
):
"""
init a git repo
"""
path_way = to_path
if not to_path:
path_way = f'/var/tmp/{repo_name}'
if os.path.exists(path_way):
raise err.GenericError(f'File or directory already exists: {path_way}')
try:
repo = Repo.init(path_way, initial_branch=branch)
repo.create_remote(
name='origin',
url=git_url_path
)
# pylint: disable=no-member
except gitexc.CommandError as exc:
raise err.GitInitError('Could not generate git repository') from exc
return repo
def push(repo, ref=None):
"""
push what we want
if ref is not none (aka an object), we'll push the commit first and
then the tag ref, this way the commits and tags are in sync.
"""
active_branch = f'{repo.active_branch.name}:{repo.active_branch.name}'
try:
if ref:
repo.remote('origin').push(active_branch).raise_if_error()
repo.remote('origin').push(ref).raise_if_error()
else:
repo.remote('origin').push(active_branch).raise_if_error()
# pylint: disable=no-member
except gitexc.CommandError as exc:
raise err.GitPushError('Unable to push commit to remote') from exc
def tag(repo, tag_name:str, message: str):
"""
make a tag with message
"""
ref = repo.create_tag(tag_name, message=message)
return ref
def lsremote(url):
"""
Helps check if a repo exists, and if it does, return references. If not,
return None and assume it doesn't exist.
"""
remote_refs = {}
git_cmd = rawgit.cmd.Git()
try:
git_cmd.ls_remote(url)
# pylint: disable=no-member
except gitexc.CommandError as exc:
print(f'Repo does not exist or is not accessible: {exc.stderr}')
return None
for ref in git_cmd.ls_remote(url).split('\n'):
hash_ref_list = ref.split('\t')
remote_refs[hash_ref_list[1]] = hash_ref_list[0]
return remote_refs