Coverage for src/idiap_devtools/gitlab/__init__.py: 38%
34 statements
« prev ^ index » next coverage.py v7.4.3, created at 2024-04-22 14:46 +0200
« prev ^ index » next coverage.py v7.4.3, created at 2024-04-22 14:46 +0200
1# Copyright © 2022 Idiap Research Institute <contact@idiap.ch>
2#
3# SPDX-License-Identifier: BSD-3-Clause
4"""Utilities to interact with GitLab."""
6import logging
7import os
8import pathlib
9import shutil
10import tarfile
11import tempfile
13from io import BytesIO
15import gitlab
16import gitlab.v4.objects
18logger = logging.getLogger(__name__)
21def get_gitlab_instance() -> gitlab.Gitlab:
22 """Return an instance of the gitlab object for remote operations."""
23 # tries to figure if we can authenticate using a global configuration
24 cfgs = [
25 pathlib.Path(k).expanduser()
26 for k in ["~/.python-gitlab.cfg", "/etc/python-gitlab.cfg"]
27 ]
28 if any([k.exists() for k in cfgs]):
29 gl = gitlab.Gitlab.from_config("idiap", [str(k) for k in cfgs if k.exists()])
30 else: # ask the user for a token or use one from the current runner
31 server = os.environ.get("CI_SERVER_URL", "https://gitlab.idiap.ch")
32 token = os.environ.get("CI_JOB_TOKEN")
33 if token is None:
34 logger.debug(
35 "Did not find any of %s nor CI_JOB_TOKEN is defined. "
36 "Asking for user token on the command line...",
37 "|".join([str(k) for k in cfgs]),
38 )
39 token = input(f"{server} (private) token: ")
40 gl = gitlab.Gitlab(server, private_token=token, api_version="4")
42 return gl
45def download_path(
46 package: gitlab.v4.objects.projects.Project,
47 path: str,
48 output: pathlib.Path | None = None,
49 ref: str | None = None,
50) -> None:
51 """Download paths from gitlab, with an optional recurse.
53 This method will download an archive of the repository from chosen
54 reference, and then it will search inside the zip blob for the path to be
55 copied into output. It uses :py:class:`zipfile.ZipFile` to do this search.
56 This method will not be very efficient for larger repository references,
57 but works recursively by default.
59 Args:
61 package: the gitlab package object to use (should be pre-fetched)
63 path: the path on the project to download
65 output: where to place the path to be downloaded - if not provided, use
66 the basename of ``path`` as storage point with respect to the current
67 directory
69 ref: the name of the git reference (branch, tag or commit hash) to use.
70 If None specified, defaults to the default branch of the input package
71 """
73 output = output or pathlib.Path(os.path.realpath(os.curdir))
74 ref = ref or package.default_branch
76 logger.debug(
77 'Downloading archive of "%s" from "%s"...',
78 ref,
79 package.attributes["path_with_namespace"],
80 )
81 archive = package.repository_archive(ref=ref)
82 logger.debug("Archive has %d bytes", len(archive))
83 logger.debug('Searching for "%s" within archive...', path)
85 with tempfile.TemporaryDirectory() as d:
86 with tarfile.open(fileobj=BytesIO(archive), mode="r:gz") as f:
87 f.extractall(path=d)
89 # move stuff to "output"
90 basedir = os.listdir(d)[0]
91 shutil.move(pathlib.Path(d) / basedir / path, output)