summaryrefslogtreecommitdiff
path: root/ci/gitlab/clone_manifest_ref.py
blob: b26043b5101ecf34aa244aed2b7887fe4b4591e4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#!/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)
    parser.add_argument("--fetch", action="store_true", default=False)
    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)

    if options.fetch:
        assert os.path.exists(dest) == True
        git('fetch', project.fetch_uri, project.revision, repository_path=dest)
    else:
        git('clone', project.fetch_uri, dest)

    git('checkout', '--detach', project.revision, repository_path=dest)