summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Pipping <sebastian@pipping.org>2010-11-07 05:02:42 +0100
committerSebastian Pipping <sebastian@pipping.org>2010-11-07 05:07:18 +0100
commit86e9330e797676e131cd80329400173db4ee9bcf (patch)
treec82dbf611aad0d7a048e84134939804bf8b02f44 /layman/dbtools
parentMigrate overlay differ from gitosis to gitolite (diff)
downloadrepositories-xml-format-86e9330e797676e131cd80329400173db4ee9bcf.tar.gz
repositories-xml-format-86e9330e797676e131cd80329400173db4ee9bcf.tar.bz2
repositories-xml-format-86e9330e797676e131cd80329400173db4ee9bcf.zip
Move package laymandbtools back to layman.dbtools
Diffstat (limited to 'layman/dbtools')
-rwxr-xr-xlayman/dbtools/gitoliteextractor.py261
-rw-r--r--layman/dbtools/gitoliteparser.py97
2 files changed, 358 insertions, 0 deletions
diff --git a/layman/dbtools/gitoliteextractor.py b/layman/dbtools/gitoliteextractor.py
new file mode 100755
index 0000000..0dbc344
--- /dev/null
+++ b/layman/dbtools/gitoliteextractor.py
@@ -0,0 +1,261 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright (C) 2009 Sebastian Pipping <sebastian@pipping.org>
+# Licensed under GPL 2 or later
+
+import sys
+from optparse import OptionParser
+USAGE = 'Usage: %prog [--fixes-only] conf/user.conf conf/proj.conf bar/repositories.xml [baz/extended.xml]'
+parser = OptionParser(usage=USAGE)
+parser.add_option('--fixes-only',
+ dest = 'fixes_only',
+ default = False,
+ action = 'store_true',
+ help = 'do not add entries that are missing completely')
+(opts, args) = parser.parse_args()
+if len(args) not in (3, 4):
+ parser.print_help()
+ sys.exit(1)
+gitolite_conf_locations = args[0:2]
+repositories_xml_location = args[2]
+extended_xml_location = (len(args) == 4) and args[3] or None
+
+import xml.etree.ElementTree as ET
+from ConfigParser import ConfigParser
+import re
+
+from layman.dbtools.sharedutils import * # local
+from layman.dbtools.gitoliteparser import RepoDatabase
+
+
+# From gitolite config
+# ..to repositories.xml
+repo_name_mapping = {
+ 'ruby-overlay':'ruby',
+ 'sci':'science',
+ 'perl-overlay':'perl-experimental',
+ 'xfce':'xfce-dev',
+ 'gnome-perf':'leio-gnome-perf',
+ 'flameeyes':'flameeyes-overlay',
+}
+
+
+def sort_as_in(elements, tag_order):
+ order_map = dict((v, i) for i, v in enumerate(tag_order))
+ deco = (t for t in enumerate(elements))
+ deco_sorted = sorted(deco, key=lambda (i, v): (order_map[v.tag], i))
+ return list(v for _, v in deco_sorted)
+
+class ChangeLog:
+ def __init__(self, gitolite_repo_name, is_new):
+ self.empty = True
+ self.gitolite_repo_name = gitolite_repo_name
+ self.is_new = is_new
+
+ def log(self, kind, details):
+ if self.empty:
+ if self.is_new:
+ print 'Repo "%s" missing completely' % self.gitolite_repo_name
+ else:
+ print 'Analyzing repo "%s":' % self.gitolite_repo_name
+ self.empty = False
+
+ if not self.is_new:
+ print '- Missing %s "%s"' % (kind, details)
+
+
+OWNER_REGEX = re.compile('^([^<]+) (?:\([^)]+\) )?<([^ ]+@[^ ]+)>$')
+NOT_AN_OVERLAY_MESSAGE = 'Skipping %s (not an overlay)'
+
+
+gitolite_conf = RepoDatabase()
+for filename in gitolite_conf_locations:
+ gitolite_conf.feed(filename)
+
+
+a = ET.parse(open(repositories_xml_location))
+repositories = a.getroot()
+overlays_gentoo_org_dict = dict([[e.find('name').text, e] for e in repositories])
+
+def oct_string_to_int(os):
+ l = len(os)
+ res = 0
+ for i, v in enumerate(os):
+ res = res + (8**(l-1-i)) * int(v)
+ return res
+
+assert oct_string_to_int('0713') == 0713
+assert oct_string_to_int('103') == 0103
+
+
+# GLOBAL_DIRMODE = oct_string_to_int(gitosis_conf.get('gitosis', 'dirmode'))
+# GLOBAL_GITWEB = gitosis_conf.getboolean('gitosis', 'gitweb')
+
+def is_public(section_name):
+ #local_dirmode = GLOBAL_DIRMODE
+ #if gitosis_conf.has_option(section_name, 'dirmode'):
+ # local_dirmode = oct_string_to_int(gitosis_conf.get(section_name, 'dirmode'))
+
+ #local_gitweb = GLOBAL_GITWEB
+ #if gitosis_conf.has_option(section_name, 'gitweb'):
+ # local_gitweb = gitosis_conf.getboolean(section_name, 'gitweb')
+
+ return True # ((local_dirmode & 0005) == 0005) and local_gitweb
+
+
+for section_name in gitolite_conf.names():
+ if True:
+ _repo_base = section_name
+
+ try:
+ owner_part, gitolite_repo_name = _repo_base.split('/')
+ except (ValueError) as e:
+ # TODO print NOT_AN_OVERLAY_MESSAGE % gitolite_repo_name
+ continue
+
+ if owner_part == 'proj':
+ owner_type = "project"
+ elif owner_part in ('dev', 'user'):
+ owner_type = "person"
+ else:
+ # TODO print NOT_AN_OVERLAY_MESSAGE % gitolite_repo_name
+ continue
+
+ terms_status, is_overlay, dont_add_to_layman, owner_contact, _description = gitolite_conf.data(section_name)
+
+ if dont_add_to_layman:
+ continue
+
+ overlay_status_clear = False
+ if not is_overlay is None:
+ if not is_overlay:
+ continue
+ overlay_status_clear = True
+
+ if not overlay_status_clear \
+ and not gitolite_repo_name.endswith('overlay') \
+ and not _description.lower().endswith('overlay'):
+ continue
+
+ if not is_public(section_name):
+ # TODO print 'Skipping %s (not public)' % gitolite_repo_name
+ continue
+
+ repositores_xml_repo_name = repo_name_mapping.get(gitolite_repo_name, gitolite_repo_name)
+ is_new = repositores_xml_repo_name not in overlays_gentoo_org_dict
+ if is_new:
+ if opts.fixes_only:
+ continue
+ repo = ET.Element('repo')
+ repositories.append(repo)
+ name = ET.Element('name')
+ name.text = gitolite_repo_name
+ repo.append(name)
+ else:
+ repo = overlays_gentoo_org_dict[repositores_xml_repo_name]
+ log = ChangeLog(gitolite_repo_name, is_new)
+
+ if 'status' not in repo.attrib:
+ if owner_part == 'user':
+ repo.attrib['status'] = 'unofficial'
+ else:
+ repo.attrib['status'] = 'official'
+ log.log('attribute', 'status')
+
+ if 'quality' not in repo.attrib:
+ repo.attrib['quality'] = 'experimental'
+ log.log('attribute', 'quality')
+
+ homepage = repo.find('homepage')
+ if homepage == None:
+ homepage = ET.Element('homepage')
+ homepage.text = 'http://git.overlays.gentoo.org/gitweb/?p=%s.git;a=summary' % _repo_base
+ repo.append(homepage)
+ log.log('homepage', homepage.text)
+
+ description = repo.find('description')
+ if description == None:
+ description = ET.Element('description', lang='en')
+ description.text = _description
+ repo.append(description)
+ log.log('description', _description)
+
+
+ _owner = owner_contact
+ _owner_match = OWNER_REGEX.match(_owner)
+
+ owner = repo.find('owner')
+ if owner == None:
+ owner = ET.Element('owner', type=owner_type)
+ repo.append(owner)
+ log.log('owner', 'TODO')
+
+ owner_name = owner.find('name')
+ if owner_name == None:
+ owner_name = ET.Element('name')
+ owner_name.text = _owner_match.group(1)
+ log.log('owner name', owner_name.text)
+
+ owner_email = owner.find('email')
+ if owner_email == None:
+ owner_email = ET.Element('email')
+ owner_email.text = _owner_match.group(2)
+ log.log('owner email', owner_email.text)
+
+ owner[:] = [owner_email, owner_name]
+
+
+ _sources = set((source.attrib['type'], source.text) for source in repo.findall('source'))
+ source_uris = (
+ 'git://git.overlays.gentoo.org/%s.git' % _repo_base,
+ 'http://git.overlays.gentoo.org/gitroot/%s.git' % _repo_base,
+ 'git+ssh://git@git.overlays.gentoo.org/%s.git' % _repo_base,
+ )
+ for uri in source_uris:
+ if ('git', uri) not in _sources and \
+ ('git', uri[:-len('.git')]) not in _sources:
+ source = ET.Element('source', type='git')
+ source.text = uri
+ repo.append(source)
+ log.log('git source', uri)
+
+
+ _feeds = set(feed.text for feed in repo.findall('feed'))
+ feed_uris = (
+ 'http://git.overlays.gentoo.org/gitweb/?p=%s.git;a=atom' % _repo_base,
+ 'http://git.overlays.gentoo.org/gitweb/?p=%s.git;a=rss' % _repo_base,
+ )
+ for uri in feed_uris:
+ if uri not in _feeds:
+ feed = ET.Element('feed')
+ feed.text = uri
+ repo.append(feed)
+ log.log('feed', uri)
+
+ repo[:] = sort_as_in(repo[:], (
+ 'name', 'description', 'longdescription',
+ 'homepage', 'owner', 'source', 'feed'))
+
+ if is_new or not log.empty:
+ if extended_xml_location == None:
+ TERM_WIDTH = 67
+ print '-'*TERM_WIDTH
+ sys.stdout.write(' ')
+ indent(repo, 1)
+ repo.tail = '\n'
+ ET.ElementTree(repo).write(sys.stdout)
+ print '-'*TERM_WIDTH
+ print
+
+
+if extended_xml_location != None:
+ indent(repositories)
+ extended_xml = open(extended_xml_location, 'w')
+ extended_xml.write("""\
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- $Header$ -->
+<?xml-stylesheet href="/xsl/repositories.xsl" type="text/xsl"?>
+<!DOCTYPE repositories SYSTEM "/dtd/repositories.dtd">
+""")
+ a.write(extended_xml, encoding='utf-8')
+ extended_xml.close()
diff --git a/layman/dbtools/gitoliteparser.py b/layman/dbtools/gitoliteparser.py
new file mode 100644
index 0000000..d63173c
--- /dev/null
+++ b/layman/dbtools/gitoliteparser.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Gentoo Foundation
+# Written by Sebastian Pipping <sping@gentoo.org>
+#
+# Licensed under GPL v2 or later
+
+from __future__ import print_function
+import re
+
+
+_repo_line = re.compile('^repo ([^ ]+)')
+_terms_status_line = re.compile('^# gentoo-terms-status = (.+)$')
+_overlay_marker_line = re.compile('^# gentoo-is-overlay = (True|False)')
+_desc_line = re.compile('^([^ ]+) "(.+ <[^@]+@[^>]+>)" = "(.+)"')
+_dont_add_line = re.compile('^# gentoo-dont-add-to-layman = (.+)')
+
+
+def _parse_bool(text):
+ if text == 'False':
+ return False
+ else:
+ assert(text == 'True')
+ return True
+
+
+class RepoDatabase:
+ def __init__(self):
+ self._db = dict()
+
+ def _add(self, repo, terms_status, is_overlay, dont_add_reason):
+ if not repo or repo in self._db:
+ return
+ self._db[repo] = (terms_status, is_overlay, dont_add_reason, None, None)
+
+ def _describe(self, repo, contact, desc):
+ self._db[repo] = self._db[repo][0:3] + (contact, desc)
+
+ def names(self):
+ return self._db.keys()
+
+ def data(self, repo):
+ return self._db[repo]
+
+ def feed(self, conf_filename):
+ f = open(conf_filename, 'r')
+
+ repo = None
+ terms_status = None
+ is_overlay = None
+ dont_add_reason = None
+
+ desc_map = dict()
+ for l in f:
+ line = l.rstrip('\n').lstrip()
+ for matcher in (_repo_line, _terms_status_line, _overlay_marker_line, _desc_line, _dont_add_line):
+ m = matcher.search(line)
+ if m:
+ if matcher is _repo_line:
+ self._add(repo, terms_status, is_overlay, dont_add_reason)
+ repo = m.group(1)
+ terms_status = None
+ is_overlay = None
+ dont_add_reason = None
+
+ elif matcher is _terms_status_line:
+ terms_status = m.group(1)
+
+ elif matcher is _overlay_marker_line:
+ is_overlay = _parse_bool(m.group(1))
+
+ elif matcher is _desc_line:
+ desc_repo = m.group(1)
+ desc_contact = m.group(2)
+ desc_desc = m.group(3)
+ desc_map[desc_repo] = (desc_contact, desc_desc)
+
+ elif matcher is _dont_add_line:
+ dont_add_reason = m.group(1)
+
+ self._add(repo, terms_status, is_overlay, dont_add_reason)
+
+ for desc_repo, (desc_contact, desc_desc) in desc_map.items():
+ self._describe(desc_repo, desc_contact, desc_desc)
+ f.close()
+
+ def _dump(self):
+ for repo, (terms_status, is_overlay, dont_add_reason, contact, desc) in sorted(self._db.items()):
+ print('repo %s' % repo)
+ if terms_status:
+ print('\t# gentoo-terms-status = %s' % terms_status)
+ if is_overlay:
+ print('\t# gentoo-is-overlay = %s' % str(is_overlay))
+ if dont_add_reason:
+ print('\t# gentoo-dont-add-to-layman = %s' % dont_add_reason)
+ if contact and desc:
+ print('\t%s "%s" = "%s"' % (repo, contact, desc))
+ print()