e46b67a1d9
Rather than check mounts, check if the source and destination reside on the same st_dev; if so use hardlinks, otherwise copy. Change-Id: Ic5fdc899d70c67ddcfc19994c254a8efcd0fd3d6
194 lines
6.6 KiB
Django/Jinja
194 lines
6.6 KiB
Django/Jinja
#!{{ destination | dirname }}/python
|
|
# Copyright 2017 Red Hat
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import argparse
|
|
import os
|
|
import re
|
|
import sys
|
|
import textwrap
|
|
import yaml
|
|
|
|
from collections import defaultdict
|
|
from collections import OrderedDict
|
|
|
|
REPO_SRC_DIR = "{{ repo_src_dir }}"
|
|
|
|
|
|
# Class copied from zuul/lib/conemapper.py with minor logging changes
|
|
class CloneMapper(object):
|
|
|
|
def __init__(self, clonemap, projects):
|
|
self.clonemap = clonemap
|
|
self.projects = projects
|
|
|
|
def expand(self, workspace):
|
|
print("Workspace path set to: %s" % workspace)
|
|
|
|
is_valid = True
|
|
ret = OrderedDict()
|
|
errors = []
|
|
for project in self.projects:
|
|
dests = []
|
|
for mapping in self.clonemap:
|
|
if re.match(r'^%s$' % mapping['name'], project):
|
|
# Might be matched more than one time
|
|
dests.append(
|
|
re.sub(mapping['name'], mapping['dest'], project))
|
|
|
|
if len(dests) > 1:
|
|
errors.append(
|
|
"Duplicate destinations for %s: %s." % (project, dests))
|
|
is_valid = False
|
|
elif len(dests) == 0:
|
|
print("Using %s as destination (unmatched)" % project)
|
|
ret[project] = [project]
|
|
else:
|
|
ret[project] = dests
|
|
|
|
if not is_valid:
|
|
raise Exception("Expansion errors: %s" % errors)
|
|
|
|
print("Mapping projects to workspace...")
|
|
for project, dest in ret.items():
|
|
dest = os.path.normpath(os.path.join(workspace, dest[0]))
|
|
ret[project] = dest
|
|
print(" %s -> %s" % (project, dest))
|
|
|
|
print("Checking overlap in destination directories...")
|
|
check = defaultdict(list)
|
|
for project, dest in ret.items():
|
|
check[dest].append(project)
|
|
|
|
dupes = dict((d, p) for (d, p) in check.items() if len(p) > 1)
|
|
if dupes:
|
|
raise Exception("Some projects share the same destination: %s",
|
|
dupes)
|
|
|
|
print("Expansion completed.")
|
|
return ret
|
|
|
|
|
|
def parseArgs():
|
|
ZUUL_ENV_SUFFIXES = ('branch', 'ref', 'url', 'project', 'newrev')
|
|
|
|
parser = argparse.ArgumentParser()
|
|
|
|
# Ignored arguments
|
|
parser.add_argument('-v', '--verbose', dest='verbose',
|
|
action='store_true', help='IGNORED')
|
|
parser.add_argument('--color', dest='color', action='store_true',
|
|
help='IGNORED')
|
|
parser.add_argument('--cache-dir', dest='cache_dir', help='IGNORED')
|
|
parser.add_argument('git_base_url', help='IGNORED')
|
|
parser.add_argument('--branch', help='IGNORED')
|
|
parser.add_argument('--project-branch', nargs=1, action='append',
|
|
metavar='PROJECT=BRANCH', help='IGNORED')
|
|
for zuul_suffix in ZUUL_ENV_SUFFIXES:
|
|
env_name = 'ZUUL_%s' % zuul_suffix.upper()
|
|
parser.add_argument(
|
|
'--zuul-%s' % zuul_suffix, metavar='$' + env_name,
|
|
help='IGNORED'
|
|
)
|
|
|
|
# Active arguments
|
|
parser.add_argument('-m', '--map', dest='clone_map_file',
|
|
help='specify clone map file')
|
|
parser.add_argument('--workspace', dest='workspace',
|
|
default=os.getcwd(),
|
|
help='where to clone repositories too')
|
|
parser.add_argument('projects', nargs='+',
|
|
help='list of Gerrit projects to clone')
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
def readCloneMap(clone_map):
|
|
clone_map_file = os.path.expanduser(clone_map)
|
|
if not os.path.exists(clone_map_file):
|
|
raise Exception("Unable to read clone map file at %s." %
|
|
clone_map_file)
|
|
clone_map_file = open(clone_map_file)
|
|
clone_map = yaml.safe_load(clone_map_file).get('clonemap')
|
|
return clone_map
|
|
|
|
|
|
def main():
|
|
args = parseArgs()
|
|
|
|
clone_map = []
|
|
if args.clone_map_file:
|
|
clone_map = readCloneMap(args.clone_map_file)
|
|
|
|
mapper = CloneMapper(clone_map, args.projects)
|
|
dests = mapper.expand(workspace=args.workspace)
|
|
|
|
for project in args.projects:
|
|
src = os.path.join(os.path.expanduser(REPO_SRC_DIR), project)
|
|
if not os.path.exists(src):
|
|
print(textwrap.dedent(
|
|
"""
|
|
**********************************
|
|
ERROR! {src} not found
|
|
In Zuul v3 all repositories used need to be declared
|
|
in the 'required-projects' parameter on the job.
|
|
To fix this issue, add:
|
|
|
|
{project}
|
|
|
|
to 'required-projects'.
|
|
|
|
While you're at it, it's worth noting that zuul-cloner itself
|
|
is deprecated and this shim is only present for transition
|
|
purposes. Start thinking about how to rework job content to
|
|
just use the git repos that zuul will place into
|
|
{repo_src_dir} directly.
|
|
**********************************
|
|
""".format(
|
|
src=src, project=project, repo_src_dir=REPO_SRC_DIR)))
|
|
sys.exit(1)
|
|
|
|
dst = dests[project]
|
|
|
|
# Remove the tail end of the path (since the copy operation will
|
|
# automatically create that)
|
|
d = dst.rstrip('/')
|
|
if not os.path.exists(d):
|
|
print("Creating %s" % d)
|
|
os.makedirs(d)
|
|
|
|
#
|
|
# Create (possible hard link) copy of the source directory
|
|
#
|
|
|
|
# Check if src & dst are on the same filesystem; if so we will
|
|
# hardlink, otherwise we copy
|
|
src_dev = os.stat(src).st_dev
|
|
dst_dev = os.stat(dst).st_dev
|
|
link = "l" if src_dev == dst_dev else ""
|
|
|
|
# note: don't use "-a" here as that implies "--preserve=all"
|
|
# which overwrites the permissions of dst from src ... this is
|
|
# fatal to ssh if dst is a home directory and we make it
|
|
# world-accessable. This should leave dst alone
|
|
cmd = "cp -dR%s %s/. %s" % (link, src, dst)
|
|
print("%s" % cmd)
|
|
if os.system(cmd):
|
|
print("Error executing: %s" % cmd)
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|