-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
lpmatos
committed
Jul 28, 2020
1 parent
96f122e
commit 91e7af2
Showing
5 changed files
with
183 additions
and
201 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
VERSION = (0, 0, 1) | ||
VERSION = (1, 0, 0) | ||
|
||
__version__ = ".".join(map(str, VERSION)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
import os | ||
from .constants import CLI | ||
from .settings import Config | ||
from .method import CloneMethod | ||
from typing import NoReturn, Text, Optional, Type, Dict | ||
from argparse import ArgumentParser, RawTextHelpFormatter | ||
|
||
# https://docs.python.org/3/library/argparse.html | ||
|
||
class Arguments: | ||
|
||
def __init__(self, argv: Optional[Type[Dict]] = None) -> NoReturn: | ||
self._config = Config() | ||
self._parser = self._create_parser_object() | ||
self._adding_arguments() | ||
self.args = self._parser.parse_args(argv) | ||
|
||
def _create_parser_object(self) -> ArgumentParser: | ||
return ArgumentParser( | ||
description="GitlabRC is a CLI that help you to clone all projects inside a specific namespace in Gitlab", | ||
prog="gitlabrc", | ||
epilog=CLI, | ||
formatter_class=RawTextHelpFormatter) | ||
|
||
def _adding_arguments(self) -> NoReturn: | ||
self._parser.add_argument("-u", "--url", | ||
type = str, | ||
dest = "url", | ||
default = "https://gitlab.com", | ||
metavar = "<url>", | ||
help = "base URL of GitLab instance") | ||
self._parser.add_argument("-t", "--token", | ||
type = str, | ||
dest = "token", | ||
default = self._config.get_env("GITLAB_TOKEN"), | ||
metavar = "<token>", | ||
help = "token GitLab API") | ||
self._parser.add_argument("-n", "--namespace", | ||
type = str, | ||
dest = "namespace", | ||
default = "", | ||
metavar = "<namespace>", | ||
help = "namespace in GitLab to clone all projects") | ||
self._parser.add_argument("-p", "--path", | ||
dest = "path", | ||
default = self._config.get_env("PWD"), | ||
metavar = "<path>", | ||
help = "destination path to cloned projects") | ||
self._parser.add_argument("-m", "--method", | ||
type = CloneMethod.parse, | ||
dest = "method", | ||
default = self._config.get_env("GITLAB_CLONE_METHOD", "http"), | ||
metavar = "<method>", | ||
choices = list(CloneMethod), | ||
help = "method used in GitLabRC to cloning repositories (either <http> or <ssh>)") | ||
self._parser.add_argument("--disable-root", | ||
action ="store_true", | ||
dest = "noroot", | ||
default = False, | ||
help = "don't create root namepace folder in path") | ||
self._parser.add_argument("--dry-run", | ||
action = "store_true", | ||
dest = "dryrun", | ||
default = False, | ||
help = "list all repositories without clone/fetch") | ||
self._parser.add_argument("--version", | ||
action = "store_true", | ||
help = "show version") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,70 +1,115 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
import os | ||
from .constants import CLI | ||
from .settings import Config | ||
import sys | ||
import re | ||
import shutil | ||
import time | ||
import gitlab | ||
import optparse | ||
from art import * | ||
import subprocess | ||
from .arguments import Arguments | ||
from .method import CloneMethod | ||
from typing import NoReturn, Text | ||
from argparse import ArgumentParser, RawTextHelpFormatter | ||
|
||
# https://docs.python.org/3/library/argparse.html | ||
|
||
class Arguments: | ||
|
||
def __init__(self, argv=None) -> NoReturn: | ||
self._config = Config() | ||
self._parser = self._create_parser_object() | ||
self._adding_arguments() | ||
self.args = self._parser.parse_args(argv) | ||
|
||
def _create_parser_object(self) -> ArgumentParser: | ||
return ArgumentParser( | ||
description="GitlabRC is a CLI that help you to clone all projects inside a specific namespace in Gitlab", | ||
prog="gitlabrc", | ||
epilog=CLI, | ||
formatter_class=RawTextHelpFormatter) | ||
|
||
def _adding_arguments(self) -> NoReturn: | ||
self._parser.add_argument("-u", "--url", | ||
type = str, | ||
dest = "url", | ||
default = "https://gitlab.com", | ||
metavar = "<url>", | ||
help = "base URL of GitLab instance") | ||
self._parser.add_argument("-t", "--token", | ||
type = str, | ||
dest = "token", | ||
default = self._config.get_env("GITLAB_TOKEN"), | ||
metavar = "<token>", | ||
help = "token GitLab API") | ||
self._parser.add_argument("-n", "--namespace", | ||
type = str, | ||
dest = "namespace", | ||
default = "", | ||
metavar = "<namespace>", | ||
help = "namespace in GitLab to clone all projects") | ||
self._parser.add_argument("-p", "--path", | ||
dest = "path", | ||
default = self._config.get_env("PWD"), | ||
metavar = "<path>", | ||
help = "destination path to cloned projects") | ||
self._parser.add_argument("-m", "--method", | ||
type = CloneMethod.parse, | ||
dest = "method", | ||
default = self._config.get_env("GITLAB_CLONE_METHOD", "http"), | ||
metavar = "<method>", | ||
choices = list(CloneMethod), | ||
help = "method used in GitLabRC to cloning repositories (either <http> or <ssh>)") | ||
self._parser.add_argument("--disable-root", | ||
action ="store_true", | ||
dest = "noroot", | ||
default = False, | ||
help = "don't create root namepace folder in path") | ||
self._parser.add_argument("--dry-run", | ||
action = "store_true", | ||
dest = "dryrun", | ||
default = False, | ||
help = "list all repositories without clone/fetch") | ||
self._parser.add_argument("--version", | ||
action = "store_true", | ||
help = "show version") | ||
from . import __version__ as VERSION | ||
|
||
def pname(): | ||
return f"[gitlabrc - {str(os.getpid())}]" | ||
|
||
def main(): | ||
Art=text2art("GitLabRC") | ||
print(Art) | ||
args = Arguments(argv=None if sys.argv[1:] else ["--help"]).args | ||
if args.version: | ||
print(f"Version: {VERSION}") | ||
sys.exit(0) | ||
perform(args) | ||
|
||
def perform(options): | ||
url, token, namespace = options.url, options.token, options.namespace | ||
|
||
if not url: | ||
sys.stderr.write("\nError: we need gitlab url information\n\n") | ||
exit(1) | ||
|
||
if not token: | ||
sys.stderr.write("\nError: we need gitlab token information\n\n") | ||
exit(1) | ||
|
||
if not namespace: | ||
sys.stderr.write("\nError: we need gitlab namespace information\n\n") | ||
exit(1) | ||
|
||
if not os.path.isdir(options.path): | ||
sys.stderr.write("\nError: destination path does not exist " + options.path + "\n\n") | ||
exit(1) | ||
|
||
git_path = shutil.which("git") | ||
if git_path == "None": | ||
sys.stderr.write("Error: git executable not installed or not in $PATH" + "\n") | ||
exit(2) | ||
else: | ||
print(pname() + " using " + git_path) | ||
|
||
t = time.time() | ||
|
||
gl = gitlab.Gitlab(url, token) | ||
|
||
group = gl.groups.get(namespace, lazy=True, include_subgroups=True) | ||
|
||
projects = [] | ||
|
||
# Get all projects inside the namespace | ||
for project in group.projects.list(all=True): | ||
projects.append(project) | ||
print(pname() + " found " + project.path_with_namespace) | ||
|
||
# Get all projects inside the subgroups | ||
for group in gl.groups.list(all=True, owned=True, query_parameters={"id": namespace}): | ||
for project in group.projects.list(all=True): | ||
projects.append(project) | ||
print(pname() + " found " + project.path_with_namespace) | ||
|
||
subgroups = group.subgroups.list(all=True) | ||
while True: | ||
for subgroup in subgroups: | ||
real_group = gl.groups.get(subgroup.id, lazy=True) | ||
for project in real_group.projects.list(all=True): | ||
projects.append(project) | ||
print(pname() + " found " + project.path_with_namespace) | ||
subgroups = real_group.subgroups.list(all=True) | ||
if len(subgroups) == 0: next | ||
if len(subgroups) == 0: break | ||
|
||
if not options.dryrun: | ||
for project in projects: | ||
print(pname() + " clone/fetch project " + project.path_with_namespace) | ||
folders = [f.strip().lower() for f in project.path_with_namespace.split("/")] | ||
if options.noroot: | ||
folders.remove(namespace) | ||
mkdir = options.path | ||
for i in range(len(folders) - 1): | ||
mkdir = mkdir + "/" + folders[i] | ||
if not os.path.isdir(mkdir): | ||
os.mkdir(mkdir) | ||
clone_path = options.path + "/" + "/".join(str(x) for x in folders) | ||
clone_path = re.sub("/+", "/", clone_path) | ||
print(pname() + " folder " + clone_path) | ||
project_url = project.http_url_to_repo if options.method is CloneMethod.HTTP else project.ssh_url_to_repo | ||
if not os.path.isdir(clone_path): | ||
print(pname() + " cloning " + project_url) | ||
try: | ||
subprocess.run(["git", "clone", project_url, clone_path]) | ||
except: | ||
sys.stderr.write("Unexpected error while cloning: terminating\n") | ||
exit(2) | ||
else: | ||
print(pname() + " fetching " + project_url) | ||
try: | ||
subprocess.run(["git", "-C", clone_path, "fetch", "--all"]) | ||
except: | ||
sys.stderr.write("Unexpected error while fetching: terminating\n") | ||
exit(3) | ||
|
||
print(pname() + " mission accomplished in " + str(round(time.time() - t, 2)) + "s") | ||
exit(0) |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.