Support cgit alias sites

This allows creation of new top-level sites and aliasing of
existing repos into those sites (under arbitrary names).

For example, this will let us list only the zuul projects under
git.zuul-ci.org.  This scheme does not extend to the git protocol,
which we will start to deprecate.

Change-Id: I4c759f02d8d7e77439984d8ad1f012bd381fae59
Story: 2001382
Task: 6092
diff --git a/jeepyb/cmd/create_cgitrepos.py b/jeepyb/cmd/create_cgitrepos.py
index 722f014..96ab172 100644
--- a/jeepyb/cmd/create_cgitrepos.py
+++ b/jeepyb/cmd/create_cgitrepos.py
@@ -29,6 +29,7 @@
 PROJECTS_YAML = os.environ.get('PROJECTS_YAML', '/home/cgit/projects.yaml')
 CGIT_REPOS = os.environ.get('CGIT_REPOS', '/etc/cgitrepos')
 REPO_PATH = os.environ.get('REPO_PATH', '/var/lib/git')
+ALIAS_PATH = os.environ.get('REPO_PATH', '/var/lib/git-alias')
 SCRATCH_SUBPATH = os.environ.get('SCRATCH_SUBPATH')
 SCRATCH_OWNER = os.environ.get('SCRATCH_OWNER', 'scratch')
 SCRATCH_GROUP = os.environ.get('SCRATCH_GROUP', 'scratch')
@@ -40,7 +41,7 @@
 def clean_string(string):
     """Scrub out characters that with break cgit.
 
-    cgit can't handle newlines in many of it's fields, so strip them
+    cgit can't handle newlines in many of its fields, so strip them
     out.
 
     """
@@ -51,6 +52,8 @@
     registry = u.ProjectsRegistry(PROJECTS_YAML)
     gitorgs = {}
     names = set()
+    # site -> [(path, project, description)]
+    alias_sites = {}
     for entry in registry.configs_list:
         project = entry['project']
         if '/' in project:
@@ -64,6 +67,11 @@
         assert project not in names
         names.add(project)
         gitorgs.setdefault(org, []).append((name, description))
+        if 'cgit-alias' in entry:
+            alias_site = entry['cgit-alias']['site']
+            alias_path = entry['cgit-alias']['path']
+            alias_sites.setdefault(alias_site, []).append(
+                (alias_path, project, description))
     if SCRATCH_SUBPATH:
         assert SCRATCH_SUBPATH not in gitorgs
         scratch_path = os.path.join(REPO_PATH, SCRATCH_SUBPATH)
@@ -100,6 +108,29 @@
                     subprocess.call(['git', 'init', '--bare', project_repo])
                     subprocess.call(['chown', '-R', '%s:%s'
                                      % (CGIT_USER, CGIT_GROUP), project_repo])
+    for alias_site, aliases in alias_sites.items():
+        # Create all the symlinks for this alias site first
+        for (alias_path, project, description) in aliases:
+            alias_site_root = os.path.join(ALIAS_PATH, alias_site)
+            if not os.path.exists(alias_site_root):
+                os.makedirs(alias_site_root)
+            alias_link_path = os.path.join(alias_site_root, alias_path)
+            alias_link_path += '.git'
+            alias_repo_path = os.path.join(REPO_PATH, project)
+            alias_repo_path += '.git'
+            if not os.path.exists(alias_link_path):
+                os.symlink(alias_repo_path, alias_link_path)
+        # Then create the cgit repo config
+        cgit_path = CGIT_REPOS + '_' + alias_site
+        with open(cgit_path, 'w') as cgit_file:
+            cgit_file.write('# Autogenerated by create_cgitrepos.py\n')
+            for (alias_path, project, description) in aliases:
+                project_repo = "%s.git" % os.path.join(REPO_PATH, project)
+                cgit_file.write('\n')
+                cgit_file.write('repo.url=%s\n' % (alias_path,))
+                cgit_file.write('repo.path=%s/\n' % (project_repo,))
+                cgit_file.write(
+                    'repo.desc=%s\n' % (clean_string(description)))
 
 
 if __name__ == "__main__":