From ab873b5e58a58f7904b1c72c5ed3520fe2f0c2cb Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 26 Mar 2019 17:21:32 +1100 Subject: [PATCH] gitlab: add a script to clone a repository using manifest details --- gitlab/clone_manifest_ref.py | 86 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100755 gitlab/clone_manifest_ref.py diff --git a/gitlab/clone_manifest_ref.py b/gitlab/clone_manifest_ref.py new file mode 100755 index 0000000..cbaf75d --- /dev/null +++ b/gitlab/clone_manifest_ref.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 + +import argparse +import os +import subprocess + +from collections import namedtuple +import xml.etree.ElementTree as ET + +# Disallow git prompting for a username/password +os.environ['GIT_TERMINAL_PROMPT'] = '0' +def git(*args, repository_path='.'): + return subprocess.check_output(["git"] + list(args), cwd=repository_path).decode() + +class Manifest(object): + ''' + Parse and store the content of a manifest file + ''' + + remotes = {} + projects = {} + default_remote = 'origin' + default_revision = 'refs/heads/master' + + def __init__(self, manifest_path): + self.manifest_path = manifest_path + + def parse(self): + try: + tree = ET.parse(self.manifest_path) + except Exception as ex: + raise Exception("Error loading manifest %s in file %s" % (self.manifest_path, ex)) + + root = tree.getroot() + + for child in root: + if child.tag == 'remote': + self.remotes[child.attrib['name']] = child.attrib['fetch'] + if child.tag == 'default': + self.default_remote = child.attrib['remote'] or self.default_remote + self.default_revision = child.attrib['revision'] or self.default_revision + if child.tag == 'project': + project = namedtuple('Project', ['name', 'remote', + 'revision', 'fetch_uri']) + + project.name = child.attrib['name'] + if project.name.endswith('.git'): + project.name = project.name[:-4] + project.remote = child.attrib.get('remote') or self.default_remote + project.revision = child.attrib.get('revision') or self.default_revision + project.fetch_uri = self.remotes[project.remote] + project.name + '.git' + + self.projects[project.name] = project + + def find_project(self, name): + try: + return self.projects[name] + except KeyError as ex: + raise Exception("Could not find project %s in manifest %s" % (name, self.manifest_path)) + + def get_fetch_uri(self, project, remote): + fetch = self.remotes[remote] + return fetch + project.name + '.git' + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--project", action="store", type=str) + parser.add_argument("--destination", action="store", type=str, default='.') + parser.add_argument("--manifest", action="store", type=str) + options = parser.parse_args() + + if not options.project: + raise ValueError("--project argument not provided") + if not options.manifest: + raise ValueError("--manifest argument not provided") + + manifest = Manifest(options.manifest) + manifest.parse() + project = manifest.find_project(options.project) + + dest = options.destination + if dest == '.': + dest = os.path.join (os.getcwd(), project.name) + + git('clone', project.fetch_uri, dest) + git('checkout', '--detach', project.revision, repository_path=dest) -- 2.7.4