blob: 3d1b2ae974d90705d131f23e4a264faf73808f4d [file] [log] [blame]
David Shrewsburyd29460a2017-09-05 12:38:45 -04001#!/usr/bin/env python
2# Copyright 2017 Red Hat
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16import argparse
17import os
18import re
19import sys
20import yaml
21
22from collections import defaultdict
23from collections import OrderedDict
24
25REPO_SRC_DIR = "~zuul/src/git.openstack.org/"
26
27
28# Class copied from zuul/lib/conemapper.py with minor logging changes
29class CloneMapper(object):
30
31 def __init__(self, clonemap, projects):
32 self.clonemap = clonemap
33 self.projects = projects
34
35 def expand(self, workspace):
36 print("Workspace path set to: %s" % workspace)
37
38 is_valid = True
39 ret = OrderedDict()
40 errors = []
41 for project in self.projects:
42 dests = []
43 for mapping in self.clonemap:
44 if re.match(r'^%s$' % mapping['name'], project):
45 # Might be matched more than one time
46 dests.append(
47 re.sub(mapping['name'], mapping['dest'], project))
48
49 if len(dests) > 1:
50 errors.append(
51 "Duplicate destinations for %s: %s." % (project, dests))
52 is_valid = False
53 elif len(dests) == 0:
54 print("Using %s as destination (unmatched)" % project)
55 ret[project] = [project]
56 else:
57 ret[project] = dests
58
59 if not is_valid:
60 raise Exception("Expansion errors: %s" % errors)
61
62 print("Mapping projects to workspace...")
63 for project, dest in ret.items():
64 dest = os.path.normpath(os.path.join(workspace, dest[0]))
65 ret[project] = dest
66 print(" %s -> %s" % (project, dest))
67
68 print("Checking overlap in destination directories...")
69 check = defaultdict(list)
70 for project, dest in ret.items():
71 check[dest].append(project)
72
73 dupes = dict((d, p) for (d, p) in check.items() if len(p) > 1)
74 if dupes:
75 raise Exception("Some projects share the same destination: %s",
76 dupes)
77
78 print("Expansion completed.")
79 return ret
80
81
82def parseArgs():
83 ZUUL_ENV_SUFFIXES = ('branch', 'ref', 'url', 'project', 'newrev')
84
85 parser = argparse.ArgumentParser()
86
87 # Ignored arguments
88 parser.add_argument('-v', '--verbose', dest='verbose',
89 action='store_true', help='IGNORED')
90 parser.add_argument('--color', dest='color', action='store_true',
91 help='IGNORED')
92 parser.add_argument('--cache-dir', dest='cache_dir', help='IGNORED')
93 parser.add_argument('git_base_url', help='IGNORED')
94 parser.add_argument('--branch', help='IGNORED')
95 parser.add_argument('--project-branch', nargs=1, action='append',
96 metavar='PROJECT=BRANCH', help='IGNORED')
97 for zuul_suffix in ZUUL_ENV_SUFFIXES:
98 env_name = 'ZUUL_%s' % zuul_suffix.upper()
99 parser.add_argument(
100 '--zuul-%s' % zuul_suffix, metavar='$' + env_name,
101 help='IGNORED'
102 )
103
104 # Active arguments
105 parser.add_argument('-m', '--map', dest='clone_map_file',
106 help='specify clone map file')
107 parser.add_argument('--workspace', dest='workspace',
108 default=os.getcwd(),
109 help='where to clone repositories too')
110 parser.add_argument('projects', nargs='+',
111 help='list of Gerrit projects to clone')
112
113 return parser.parse_args()
114
115
116def readCloneMap(clone_map):
117 clone_map_file = os.path.expanduser(clone_map)
118 if not os.path.exists(clone_map_file):
119 raise Exception("Unable to read clone map file at %s." %
120 clone_map_file)
121 clone_map_file = open(clone_map_file)
122 clone_map = yaml.safe_load(clone_map_file).get('clonemap')
123 return clone_map
124
125
126def main():
127 args = parseArgs()
128
129 clone_map = []
130 if args.clone_map_file:
131 clone_map = readCloneMap(args.clone_map_file)
132
133 mapper = CloneMapper(clone_map, args.projects)
134 dests = mapper.expand(workspace=args.workspace)
135
136 for project in args.projects:
137 src = os.path.join(os.path.expanduser(REPO_SRC_DIR), project)
138 dst = dests[project]
139
140 # Remove the tail end of the path (since the copy operation will
141 # automatically create that)
142 d = dst.rstrip('/')
143 d, base = os.path.split(d)
144 if not os.path.exists(d):
145 print("Creating %s" % d)
146 os.makedirs(d)
147
148 # Create hard link copy of the source directory
149 cmd = "cp -al %s %s" % (src, dst)
150 print("%s" % cmd)
151 if os.system(cmd):
152 print("Error executing: %s" % cmd)
153 sys.exit(1)
154
155
156if __name__ == "__main__":
157 main()