summaryrefslogtreecommitdiff
path: root/gitlab/cli.py
diff options
context:
space:
mode:
authorNejc Habjan <hab.nejc@gmail.com>2021-12-01 01:04:53 +0100
committerGitHub <noreply@github.com>2021-12-01 01:04:53 +0100
commit8d76826fa64460e504acc5924f859f8dbc246b42 (patch)
tree083fefada982c795e2415092794db429abb0c184 /gitlab/cli.py
parent5a1678f43184bd459132102cc13cf8426fe0449d (diff)
parent86ab04e54ea4175f10053decfad5086cda7aa024 (diff)
downloadgitlab-master.tar.gz
Merge pull request #1723 from python-gitlab/jlvillal/dead_mastermaster
Close-out `master` branch
Diffstat (limited to 'gitlab/cli.py')
-rw-r--r--gitlab/cli.py260
1 files changed, 0 insertions, 260 deletions
diff --git a/gitlab/cli.py b/gitlab/cli.py
deleted file mode 100644
index c053a38..0000000
--- a/gitlab/cli.py
+++ /dev/null
@@ -1,260 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2013-2017 Gauvain Pocentek <gauvain@pocentek.net>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-
-import argparse
-import functools
-import re
-import sys
-from types import ModuleType
-from typing import Any, Callable, cast, Dict, Optional, Tuple, Type, TypeVar, Union
-
-from requests.structures import CaseInsensitiveDict
-
-import gitlab.config
-from gitlab.base import RESTObject
-
-# This regex is based on:
-# https://github.com/jpvanhal/inflection/blob/master/inflection/__init__.py
-camel_upperlower_regex = re.compile(r"([A-Z]+)([A-Z][a-z])")
-camel_lowerupper_regex = re.compile(r"([a-z\d])([A-Z])")
-
-# custom_actions = {
-# cls: {
-# action: (mandatory_args, optional_args, in_obj),
-# },
-# }
-custom_actions: Dict[str, Dict[str, Tuple[Tuple[str, ...], Tuple[str, ...], bool]]] = {}
-
-
-# For an explanation of how these type-hints work see:
-# https://mypy.readthedocs.io/en/stable/generics.html#declaring-decorators
-#
-# The goal here is that functions which get decorated will retain their types.
-__F = TypeVar("__F", bound=Callable[..., Any])
-
-
-def register_custom_action(
- cls_names: Union[str, Tuple[str, ...]],
- mandatory: Tuple[str, ...] = tuple(),
- optional: Tuple[str, ...] = tuple(),
- custom_action: Optional[str] = None,
-) -> Callable[[__F], __F]:
- def wrap(f: __F) -> __F:
- @functools.wraps(f)
- def wrapped_f(*args: Any, **kwargs: Any) -> Any:
- return f(*args, **kwargs)
-
- # in_obj defines whether the method belongs to the obj or the manager
- in_obj = True
- if isinstance(cls_names, tuple):
- classes = cls_names
- else:
- classes = (cls_names,)
-
- for cls_name in classes:
- final_name = cls_name
- if cls_name.endswith("Manager"):
- final_name = cls_name.replace("Manager", "")
- in_obj = False
- if final_name not in custom_actions:
- custom_actions[final_name] = {}
-
- action = custom_action or f.__name__.replace("_", "-")
- custom_actions[final_name][action] = (mandatory, optional, in_obj)
-
- return cast(__F, wrapped_f)
-
- return wrap
-
-
-def die(msg: str, e: Optional[Exception] = None) -> None:
- if e:
- msg = "%s (%s)" % (msg, e)
- sys.stderr.write(msg + "\n")
- sys.exit(1)
-
-
-def what_to_cls(what: str, namespace: ModuleType) -> Type[RESTObject]:
- classes = CaseInsensitiveDict(namespace.__dict__)
- lowercase_class = what.replace("-", "")
-
- return classes[lowercase_class]
-
-
-def cls_to_what(cls: RESTObject) -> str:
- dasherized_uppercase = camel_upperlower_regex.sub(r"\1-\2", cls.__name__)
- dasherized_lowercase = camel_lowerupper_regex.sub(r"\1-\2", dasherized_uppercase)
- return dasherized_lowercase.lower()
-
-
-def _get_base_parser(add_help: bool = True) -> argparse.ArgumentParser:
- parser = argparse.ArgumentParser(
- add_help=add_help, description="GitLab API Command Line Interface"
- )
- parser.add_argument("--version", help="Display the version.", action="store_true")
- parser.add_argument(
- "-v",
- "--verbose",
- "--fancy",
- help="Verbose mode (legacy format only)",
- action="store_true",
- )
- parser.add_argument(
- "-d", "--debug", help="Debug mode (display HTTP requests)", action="store_true"
- )
- parser.add_argument(
- "-c",
- "--config-file",
- action="append",
- help="Configuration file to use. Can be used multiple times.",
- )
- parser.add_argument(
- "-g",
- "--gitlab",
- help=(
- "Which configuration section should "
- "be used. If not defined, the default selection "
- "will be used."
- ),
- required=False,
- )
- parser.add_argument(
- "-o",
- "--output",
- help="Output format (v4 only): json|legacy|yaml",
- required=False,
- choices=["json", "legacy", "yaml"],
- default="legacy",
- )
- parser.add_argument(
- "-f",
- "--fields",
- help=(
- "Fields to display in the output (comma "
- "separated). Not used with legacy output"
- ),
- required=False,
- )
-
- return parser
-
-
-def _get_parser() -> argparse.ArgumentParser:
- # NOTE: We must delay import of gitlab.v4.cli until now or
- # otherwise it will cause circular import errors
- import gitlab.v4.cli
-
- parser = _get_base_parser()
- return gitlab.v4.cli.extend_parser(parser)
-
-
-def _parse_value(v: Any) -> Any:
- if isinstance(v, str) and v.startswith("@"):
- # If the user-provided value starts with @, we try to read the file
- # path provided after @ as the real value. Exit on any error.
- try:
- with open(v[1:]) as fl:
- return fl.read()
- except Exception as e:
- sys.stderr.write("%s\n" % e)
- sys.exit(1)
-
- return v
-
-
-def docs() -> argparse.ArgumentParser:
- """
- Provide a statically generated parser for sphinx only, so we don't need
- to provide dummy gitlab config for readthedocs.
- """
- if "sphinx" not in sys.modules:
- sys.exit("Docs parser is only intended for build_sphinx")
-
- return _get_parser()
-
-
-def main() -> None:
- if "--version" in sys.argv:
- print(gitlab.__version__)
- sys.exit(0)
-
- parser = _get_base_parser(add_help=False)
-
- # This first parsing step is used to find the gitlab config to use, and
- # load the propermodule (v3 or v4) accordingly. At that point we don't have
- # any subparser setup
- (options, _) = parser.parse_known_args(sys.argv)
- try:
- config = gitlab.config.GitlabConfigParser(options.gitlab, options.config_file)
- except gitlab.config.ConfigError as e:
- if "--help" in sys.argv or "-h" in sys.argv:
- parser.print_help()
- sys.exit(0)
- sys.exit(e)
- # We only support v4 API at this time
- if config.api_version not in ("4",):
- raise ModuleNotFoundError(name="gitlab.v%s.cli" % config.api_version)
-
- # Now we build the entire set of subcommands and do the complete parsing
- parser = _get_parser()
- try:
- import argcomplete # type: ignore
-
- argcomplete.autocomplete(parser)
- except Exception:
- pass
- args = parser.parse_args()
-
- config_files = args.config_file
- gitlab_id = args.gitlab
- verbose = args.verbose
- output = args.output
- fields = []
- if args.fields:
- fields = [x.strip() for x in args.fields.split(",")]
- debug = args.debug
- action = args.whaction
- what = args.what
-
- args_dict = vars(args)
- # Remove CLI behavior-related args
- for item in (
- "gitlab",
- "config_file",
- "verbose",
- "debug",
- "what",
- "whaction",
- "version",
- "output",
- ):
- args_dict.pop(item)
- args_dict = {k: _parse_value(v) for k, v in args_dict.items() if v is not None}
-
- try:
- gl = gitlab.Gitlab.from_config(gitlab_id, config_files)
- if gl.private_token or gl.oauth_token or gl.job_token:
- gl.auth()
- except Exception as e:
- die(str(e))
-
- if debug:
- gl.enable_debug()
-
- gitlab.v4.cli.run(gl, what, action, args_dict, verbose, output, fields)