コード例 #1
0
    def test_getboolean(self, mock_getboolean):
        dcp = DefaultConfigParser()
        mock_getboolean.return_value = True
        self.assertEqual(dcp.getboolean("section", "option"), True)
        mock_getboolean.assert_called_with(dcp, "section", "option")

        mock_getboolean.reset_mock()
        self.assertEqual(
            dcp.getboolean("section", "option", default=False, other="test"),
            True)
        mock_getboolean.assert_called_with(dcp,
                                           "section",
                                           "option",
                                           other="test")

        for etype, err in [(ConfigParser.NoOptionError,
                            ConfigParser.NoOptionError(None, None)),
                           (ConfigParser.NoSectionError,
                            ConfigParser.NoSectionError(None))]:
            mock_getboolean.side_effect = err
            mock_getboolean.reset_mock()
            self.assertEqual(
                dcp.getboolean("section", "option", default=False), False)
            mock_getboolean.assert_called_with(dcp, "section", "option")

            mock_getboolean.reset_mock()
            self.assertRaises(etype, dcp.getboolean, "section", "option")
            mock_getboolean.assert_called_with(dcp, "section", "option")
コード例 #2
0
ファイル: git_commit.py プロジェクト: xschlef/bcfg2
def parse_options():
    config = ConfigParser.SafeConfigParser(DEFAULTS)
    config.read(CONFIG)

    optinfo = dict(
        profile=Bcfg2.Options.CLIENT_PROFILE,
        dryrun=Bcfg2.Options.CLIENT_DRYRUN,
        groups=Bcfg2.Options.Option("Groups",
                                    default=[],
                                    cmd="-g",
                                    odesc='<group>:<group>',
                                    cook=Bcfg2.Options.colon_split))
    optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS)
    optinfo.update(Bcfg2.Options.SERVER_COMMON_OPTIONS)
    argv = [Bcfg2.Options.CFILE.cmd, config.get("global", "config")]
    argv.extend(sys.argv[1:])
    setup = Bcfg2.Options.OptionParser(optinfo, argv=argv)
    setup.parse(argv)

    setup['commit'] = Bcfg2.Options.list_split(config.get("global",
                                                          "commit"))
    for opt in ['debug', 'verbose']:
        try:
            setup[opt] = config.getboolean("global", opt)
        except ConfigParser.NoOptionError:
            pass

    try:
        hostname = setup['args'][0]
    except IndexError:
        print(setup.hm)
        raise SystemExit(1)
    return (setup, hostname)
コード例 #3
0
    def __init__(self, **kwargs):
        """ See :class:`argparse.ArgumentParser` for a full list of
        accepted parameters.

        In addition to supporting all arguments and keyword arguments
        from :class:`argparse.ArgumentParser`, several additional
        keyword arguments are allowed.

        :param components: A list of components to add to the parser.
        :type components: list
        :param namespace: The namespace to store options in.  Default
                          is :attr:`Bcfg2.Options.setup`.
        :type namespace: argparse.Namespace
        :param add_base_options: Whether or not to add the options in
                                 :attr:`Bcfg2.Options.Parser.options`
                                 to the parser.  Setting this to False
                                 is default for subparsers. Default is
                                 True.
        :type add_base_options: bool
        """
        self._cfp = ConfigParser.ConfigParser()
        components = kwargs.pop('components', [])

        #: The namespace options will be stored in.
        self.namespace = kwargs.pop('namespace', setup)
        if self.namespace is None:
            self.namespace = setup
        add_base_options = kwargs.pop('add_base_options', True)

        #: Flag to indicate that this is the pre-parsing 'early' run
        #: for important options like database settings that must be
        #: loaded before other components can be.
        self._early = kwargs.pop('early', False)

        if 'add_help' not in kwargs:
            kwargs['add_help'] = add_base_options
        argparse.ArgumentParser.__init__(self, **kwargs)

        #: Whether or not parsing has completed on all current options.
        self.parsed = False

        #: The argument list that was parsed.
        self.argv = None

        #: Components that have been added to the parser
        self.components = []

        #: Options that have been added to the parser
        self.option_list = []
        self._defaults_set = []
        self._config_files = []
        if add_base_options:
            self.add_component(self)
        if components:
            for component in components:
                self.add_component(component)
コード例 #4
0
ファイル: migrate_configs.py プロジェクト: xschlef/bcfg2
def main():
    parser = Bcfg2.Options.get_parser(
        description="Migrate from Bcfg2 1.2 per-plugin config files to 1.3 "
        "unified config file")
    parser.add_options([Bcfg2.Options.Common.repository])
    parser.parse()
    repo = Bcfg2.Options.setup.repository
    cfp = ConfigParser.ConfigParser()
    cfp.read(Bcfg2.Options.setup.config)

    # files that you should remove manually
    remove = []

    # move rules config out of rules.conf and into bcfg2.conf
    rules_conf = os.path.join(repo, 'Rules', 'rules.conf')
    if os.path.exists(rules_conf):
        remove.append(rules_conf)
        copy_section(rules_conf, cfp, "rules")

    # move packages config out of packages.conf and into bcfg2.conf
    pkgs_conf = os.path.join(repo, 'Packages', 'packages.conf')
    if os.path.exists(pkgs_conf):
        remove.append(pkgs_conf)
        copy_section(pkgs_conf, cfp, "global", newsection="packages")
        for section in ["apt", "yum", "pulp"]:
            copy_section(pkgs_conf, cfp, section,
                         newsection="packages:" + section)

    # move reports database config into [database] section
    if cfp.has_section("statistics"):
        if not cfp.has_section("database"):
            cfp.add_section("database")
        for opt in cfp.options("statistics"):
            if opt.startswith("database_"):
                newopt = opt[9:]
                if cfp.has_option("database", newopt):
                    print("%s in [database] already populated, skipping" %
                          newopt)
                else:
                    cfp.set("database", newopt, cfp.get("statistics", opt))
                    cfp.remove_option("statistics", opt)

    print("Writing %s" % Bcfg2.Options.setup.config)
    try:
        cfp.write(open(Bcfg2.Options.setup.config, "w"))
        if len(remove):
            print("Settings were migrated, but you must remove these files "
                  "manually:")
            for path in remove:
                print("  %s" % path)
    except IOError:
        err = sys.exc_info()[1]
        print("Could not write %s: %s" % (Bcfg2.Options.setup.config, err))
コード例 #5
0
    def test_get(self, mock_get):
        dcp = DefaultConfigParser()
        mock_get.return_value = "foo"
        self.assertEqual(dcp.get("section", "option"), "foo")
        mock_get.assert_called_with(dcp, "section", "option")

        mock_get.reset_mock()
        self.assertEqual(
            dcp.get("section", "option", default="bar", other="test"), "foo")
        mock_get.assert_called_with(dcp, "section", "option", other="test")

        for etype, err in [(ConfigParser.NoOptionError,
                            ConfigParser.NoOptionError(None, None)),
                           (ConfigParser.NoSectionError,
                            ConfigParser.NoSectionError(None))]:
            mock_get.side_effect = err
            mock_get.reset_mock()
            self.assertEqual(dcp.get("section", "option", default="bar"),
                             "bar")
            mock_get.assert_called_with(dcp, "section", "option")

            mock_get.reset_mock()
            self.assertRaises(etype, dcp.get, "section", "option")
            mock_get.assert_called_with(dcp, "section", "option")
コード例 #6
0
ファイル: __init__.py プロジェクト: psteinbachs/bcfg2
def db_from_config(cfile):
    cp = ConfigParser.ConfigParser()
    cp.read([cfile])
    driver = cp.get('snapshots', 'driver')
    if driver == 'sqlite':
        path = cp.get('snapshots', 'database')
        return 'sqlite:///%s' % path
    elif driver in ['mysql', 'postgres']:
        user = cp.get('snapshots', 'user')
        password = cp.get('snapshots', 'password')
        host = cp.get('snapshots', 'host')
        db = cp.get('snapshots', 'database')
        return '%s://%s:%s@%s/%s' % (driver, user, password, host, db)
    else:
        raise Exception("unsupported db driver %s" % driver)
コード例 #7
0
 def build_req_config(self, metadata):
     """
     generates a temporary openssl configuration file that is
     used to generate the required certificate request
     """
     # create temp request config file
     fd, fname = tempfile.mkstemp()
     cfp = ConfigParser.ConfigParser({})
     cfp.optionxform = str
     defaults = {
         'req': {
             'default_md': 'sha1',
             'distinguished_name': 'req_distinguished_name',
             'req_extensions': 'v3_req',
             'x509_extensions': 'v3_req',
             'prompt': 'no'
         },
         'req_distinguished_name': {},
         'v3_req': {
             'subjectAltName': '@alt_names'
         },
         'alt_names': {}
     }
     for section in list(defaults.keys()):
         cfp.add_section(section)
         for key in defaults[section]:
             cfp.set(section, key, defaults[section][key])
     cert_spec = self.cert.get_spec(metadata)
     altnamenum = 1
     altnames = cert_spec['subjectaltname']
     altnames.extend(list(metadata.aliases))
     altnames.append(metadata.hostname)
     for altname in altnames:
         cfp.set('alt_names', 'DNS.' + str(altnamenum), altname)
         altnamenum += 1
     for item in ['C', 'L', 'ST', 'O', 'OU', 'emailAddress']:
         if cert_spec[item]:
             cfp.set('req_distinguished_name', item, cert_spec[item])
     cfp.set('req_distinguished_name', 'CN', metadata.hostname)
     self.debug_log("SSLCA: Writing temporary request config to %s" % fname)
     try:
         cfp.write(os.fdopen(fd, 'w'))
     except IOError:
         raise PluginExecutionError("SSLCA: Failed to write temporary CSR "
                                    "config file: %s" % sys.exc_info()[1])
     return fname
コード例 #8
0
        def inner(*args, **kwargs):
            """decorated function."""
            cfp = ConfigParser.ConfigParser()
            for section, options in self.config_data.items():
                cfp.add_section(section)
                for key, val in options.items():
                    cfp.set(section, key, val)
            fd, name = tempfile.mkstemp()
            config_file = os.fdopen(fd, 'w')
            cfp.write(config_file)
            config_file.close()

            args = list(args) + [name]
            try:
                rv = func(*args, **kwargs)
            finally:
                os.unlink(name)
            return rv
コード例 #9
0
 def build_req_config(self, entry, metadata):
     """
     generates a temporary openssl configuration file that is
     used to generate the required certificate request
     """
     # create temp request config file
     conffile = open(tempfile.mkstemp()[1], 'w')
     cfp = ConfigParser.ConfigParser({})
     cfp.optionxform = str
     defaults = {
         'req': {
             'default_md': 'sha1',
             'distinguished_name': 'req_distinguished_name',
             'req_extensions': 'v3_req',
             'x509_extensions': 'v3_req',
             'prompt': 'no'
         },
         'req_distinguished_name': {},
         'v3_req': {
             'subjectAltName': '@alt_names'
         },
         'alt_names': {}
     }
     for section in list(defaults.keys()):
         cfp.add_section(section)
         for key in defaults[section]:
             cfp.set(section, key, defaults[section][key])
     altnamenum = 1
     altnames = list(metadata.aliases)
     altnames.append(metadata.hostname)
     for altname in altnames:
         cfp.set('alt_names', 'DNS.' + str(altnamenum), altname)
         altnamenum += 1
     for item in ['C', 'L', 'ST', 'O', 'OU', 'emailAddress']:
         if self.cert_specs[entry.get('name')][item]:
             cfp.set('req_distinguished_name', item,
                     self.cert_specs[entry.get('name')][item])
     cfp.set('req_distinguished_name', 'CN', metadata.hostname)
     cfp.write(conffile)
     conffile.close()
     return conffile.name
コード例 #10
0
ファイル: CfgSSLCACertCreator.py プロジェクト: xschlef/bcfg2
 def build_req_config(self, metadata):
     """ Generates a temporary openssl configuration file that is
     used to generate the required certificate request. """
     fd, fname = tempfile.mkstemp()
     cfp = ConfigParser.ConfigParser({})
     cfp.optionxform = str
     defaults = dict(
         req=dict(
             default_md='sha1',
             distinguished_name='req_distinguished_name',
             req_extensions='v3_req',
             x509_extensions='v3_req',
             prompt='no'),
         req_distinguished_name=dict(),
         v3_req=dict(subjectAltName='@alt_names'),
         alt_names=dict())
     for section in list(defaults.keys()):
         cfp.add_section(section)
         for key in defaults[section]:
             cfp.set(section, key, defaults[section][key])
     spec = self.XMLMatch(metadata)
     cert = spec.find("Cert")
     altnamenum = 1
     altnames = spec.findall('subjectAltName')
     altnames.extend(list(metadata.aliases))
     altnames.append(metadata.hostname)
     for altname in altnames:
         cfp.set('alt_names', 'DNS.' + str(altnamenum), altname)
         altnamenum += 1
     for item in ['C', 'L', 'ST', 'O', 'OU', 'emailAddress']:
         if cert.get(item):
             cfp.set('req_distinguished_name', item, cert.get(item))
     cfp.set('req_distinguished_name', 'CN', metadata.hostname)
     self.debug_log("Cfg: Writing temporary CSR config to %s" % fname)
     try:
         cfp.write(os.fdopen(fd, 'w'))
     except IOError:
         raise CfgCreationError("Cfg: Failed to write temporary CSR config "
                                "file: %s" % sys.exc_info()[1])
     return fname
コード例 #11
0
    def test_reparse(self, config_file):
        """reparse options."""
        result = argparse.Namespace()
        parser = Parser(components=[self], namespace=result)
        parser.parse(["-C", config_file])
        self.assertFalse(result.test_false_boolean)

        parser.parse(["-C", config_file])
        self.assertFalse(result.test_false_boolean)

        parser.reparse()
        self.assertFalse(result.test_false_boolean)

        parser.reparse(["-C", config_file, "--test-false-boolean"])
        self.assertTrue(result.test_false_boolean)

        cfp = ConfigParser.ConfigParser()
        cfp.add_section("test")
        cfp.set("test", "false_boolean", "on")
        parser.parse(["-C", config_file])
        cfp.write(open(config_file, "w"))
        self.assertTrue(result.test_false_boolean)
コード例 #12
0
ファイル: migrate_configs.py プロジェクト: rcuza/bcfg2
def copy_section(src_file, tgt_cfg, section, newsection=None):
    if newsection is None:
        newsection = section

    cfg = ConfigParser.ConfigParser()
    if len(cfg.read(src_file)) == 1:
        if cfg.has_section(section):
            try:
                tgt_cfg.add_section(newsection)
            except ConfigParser.DuplicateSectionError:
                print("[%s] section already exists in %s, adding options" %
                      (newsection, setup['cfile']))
            for opt in cfg.options(section):
                val = cfg.get(section, opt)
                if tgt_cfg.has_option(newsection, opt):
                    print("%s in [%s] already populated in %s, skipping" %
                          (opt, newsection, setup['cfile']))
                    print("  %s: %s" %
                          (setup['cfile'], tgt_cfg.get(newsection, opt)))
                    print("  %s: %s" % (src_file, val))
                else:
                    print("Set %s in [%s] to %s" % (opt, newsection, val))
                    tgt_cfg.set(newsection, opt, val)
コード例 #13
0
import os.path
# Compatibility import
from Bcfg2.Compat import ConfigParser

PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))

c = ConfigParser.ConfigParser()
#This needs to be configurable one day somehow
c.read(['./bcfg2.conf'])

defaults = {
    'database_engine': 'sqlite3',
    'database_name': './dev.db',
    'database_user': '',
    'database_password': '',
    'database_host': '',
    'database_port': 3306,
    'default_mx': 'localhost',
    'priority': 10,
    'authorized_group': 'admins',
}

if c.has_section('hostbase'):
    options = dict(c.items('hostbase'))
else:
    options = defaults

# Django settings for Hostbase project.
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (('Root', 'root'), )
コード例 #14
0
ファイル: __init__.py プロジェクト: rcuza/bcfg2
 def getCFP(self):
     """ get a config parser for the Bcfg2 config file """
     if not self.__cfp:
         self.__cfp = ConfigParser.ConfigParser()
         self.__cfp.read(self.configfile)
     return self.__cfp
コード例 #15
0
            self.indent_level = self.indent_level + 1

        self._write_common_entries(pkgdata)
        self._write_perarch_entries(pkgdata)

        for group in self.groups:
            self.indent_level = self.indent_level - 1
            self._write_to_file('</Group>')
        self.indent_level = self.indent_level - 1
        self._write_to_file('</PackageList>')
        self._close_file()
        self._rename_file()


if __name__ == '__main__':
    # Prefix is relative to script path
    complete_script_path = os.path.join(os.getcwd(), sys.argv[0])
    prefix = complete_script_path[:-len('etc/create-debian-pkglist.py')]

    confparser = ConfigParser.SafeConfigParser()
    confparser.read(prefix + "etc/debian-pkglist.conf")

    # We read the whole configuration file before processing each entries
    # to avoid doing work if there is a problem in the file.
    sources_list = []
    for section in confparser.sections():
        sources_list.append(Source(confparser, section, prefix))

    for source in sources_list:
        source.process()
コード例 #16
0
    def HandleEvent(self, event=None):
        """
        Updates which files this plugin handles based upon filesystem events.
        Allows configuration items to be added/removed without server restarts.
        """
        action = event.code2str()
        if event.filename[0] == '/':
            return
        epath = "".join(
            [self.data, self.handles[event.requestID], event.filename])
        if os.path.isdir(epath):
            ident = self.handles[event.requestID] + event.filename
        else:
            ident = self.handles[event.requestID][:-1]

        fname = os.path.join(ident, event.filename)

        if event.filename.endswith('.xml'):
            if action in ['exists', 'created', 'changed']:
                if event.filename.endswith('key.xml'):
                    key_spec = dict(
                        list(
                            lxml.etree.parse(
                                epath, parser=Bcfg2.Server.XMLParser).find(
                                    'Key').items()))
                    self.key_specs[ident] = {
                        'bits': key_spec.get('bits', 2048),
                        'type': key_spec.get('type', 'rsa')
                    }
                    self.Entries['Path'][ident] = self.get_key
                elif event.filename.endswith('cert.xml'):
                    cert_spec = dict(
                        list(
                            lxml.etree.parse(
                                epath, parser=Bcfg2.Server.XMLParser).find(
                                    'Cert').items()))
                    ca = cert_spec.get('ca', 'default')
                    self.cert_specs[ident] = {
                        'ca': ca,
                        'format': cert_spec.get('format', 'pem'),
                        'key': cert_spec.get('key'),
                        'days': cert_spec.get('days', 365),
                        'C': cert_spec.get('c'),
                        'L': cert_spec.get('l'),
                        'ST': cert_spec.get('st'),
                        'OU': cert_spec.get('ou'),
                        'O': cert_spec.get('o'),
                        'emailAddress': cert_spec.get('emailaddress')
                    }
                    cfp = ConfigParser.ConfigParser()
                    cfp.read(self.core.cfile)
                    self.CAs[ca] = dict(cfp.items('sslca_' + ca))
                    self.Entries['Path'][ident] = self.get_cert
                elif event.filename.endswith("info.xml"):
                    self.infoxml[ident] = Bcfg2.Server.Plugin.InfoXML(epath)
                    self.infoxml[ident].HandleEvent(event)
            if action == 'deleted':
                if ident in self.Entries['Path']:
                    del self.Entries['Path'][ident]
        else:
            if action in ['exists', 'created']:
                if os.path.isdir(epath):
                    self.AddDirectoryMonitor(epath[len(self.data):])
                if ident not in self.entries and os.path.isfile(epath):
                    self.entries[fname] = self.__child__(epath)
                    self.entries[fname].HandleEvent(event)
            if action == 'changed':
                self.entries[fname].HandleEvent(event)
            elif action == 'deleted':
                if fname in self.entries:
                    del self.entries[fname]
                else:
                    self.entries[fname].HandleEvent(event)
コード例 #17
0
            self.indent_level = self.indent_level + 1

        self._write_common_entries(pkgdata)
        self._write_perarch_entries(pkgdata)

        for group in self.groups:
            self.indent_level = self.indent_level - 1
            self._write_to_file('</Group>')
        self.indent_level = self.indent_level - 1
        self._write_to_file('</PackageList>')
        self._close_file()
        self._rename_file()


if __name__ == '__main__':
    main_conf_parser = ConfigParser.SafeConfigParser()
    main_conf_parser.read(['/etc/bcfg2.conf'])
    repo = main_conf_parser.get('server', 'repository')

    confparser = ConfigParser.SafeConfigParser()
    confparser.read(os.path.join(repo, "etc/debian-pkglist.conf"))

    # We read the whole configuration file before processing each entries
    # to avoid doing work if there is a problem in the file.
    sources_list = []
    for section in confparser.sections():
        sources_list.append(Source(confparser, section, repo))

    for source in sources_list:
        source.process()
コード例 #18
0
    def get_config(self, raw=False):  # pylint: disable=W0221
        """ Get the yum configuration for this collection.

        :param raw: Return a :class:`ConfigParser.SafeConfigParser`
                    object representing the configuration instead of a
                    string.  This is useful if you need to modify the
                    config before writing it (as :func:`write_config`
                    does in order to produce a server-specific
                    configuration).
        :type raw: bool
        :returns: string or ConfigParser.SafeConfigParser """

        config = ConfigParser.SafeConfigParser()
        for source in self:
            for url_map in source.url_map:
                if url_map['arch'] not in self.metadata.groups:
                    continue
                basereponame = source.get_repo_name(url_map)
                reponame = basereponame

                added = False
                while not added:
                    try:
                        config.add_section(reponame)
                        added = True
                    except ConfigParser.DuplicateSectionError:
                        match = re.search("-(\d+)", reponame)
                        if match:
                            rid = int(match.group(1)) + 1
                        else:
                            rid = 1
                        reponame = "%s-%d" % (basereponame, rid)

                config.set(reponame, "name", reponame)
                config.set(reponame, "baseurl", url_map['url'])
                config.set(reponame, "enabled", "1")
                if len(source.gpgkeys):
                    config.set(reponame, "gpgcheck", "1")
                    config.set(reponame, "gpgkey", " ".join(source.gpgkeys))
                else:
                    config.set(reponame, "gpgcheck", "0")

                if len(source.blacklist):
                    config.set(reponame, "exclude", " ".join(source.blacklist))
                if len(source.whitelist):
                    config.set(reponame, "includepkgs",
                               " ".join(source.whitelist))

                if raw:
                    opts = source.server_options
                else:
                    opts = source.client_options
                for opt, val in opts.items():
                    config.set(reponame, opt, val)

        if raw:
            return config
        else:
            # configparser only writes to file, so we have to use a
            # StringIO object to get the data out as a string
            buf = StringIO()
            config.write(buf)
            return "# This config was generated automatically by the Bcfg2 " \
                   "Packages plugin\n\n" + buf.getvalue()
コード例 #19
0
ファイル: packages-convert.py プロジェクト: rcuza/bcfg2
def main():
    opts = {'repo': Bcfg2.Options.SERVER_REPOSITORY}
    setup = Bcfg2.Options.OptionParser(opts)
    setup.parse(sys.argv[1:])
    repo = setup['repo']
    configpath = os.path.join(repo, 'Packages')
    oldconfigfile = os.path.join(configpath, 'config.xml')
    newconfigfile = os.path.join(configpath, 'packages.conf')
    newsourcesfile = os.path.join(configpath, 'sources.xml')

    if not os.path.exists(oldconfigfile):
        print("%s does not exist, nothing to do" % oldconfigfile)
        return 1

    if not os.path.exists(configpath):
        print("%s does not exist, cannot write %s" %
              (configpath, newconfigfile))
        return 2

    newconfig = ConfigParser.SafeConfigParser()
    newconfig.add_section("global")

    oldconfig = lxml.etree.parse(oldconfigfile).getroot()

    config = oldconfig.xpath('//Sources/Config')
    if config:
        if config[0].get("resolver", "enabled").lower() == "disabled":
            newconfig.add_option("global", "resolver", "disabled")
        if config[0].get("metadata", "enabled").lower() == "disabled":
            newconfig.add_option("global", "metadata", "disabled")
    newconfig.write(open(newconfigfile, "w"))
    print("%s written" % newconfigfile)

    oldsources = [oldconfigfile]
    while oldsources:
        oldfile = oldsources.pop()
        oldsource = lxml.etree.parse(oldfile).getroot()

        if oldfile == oldconfigfile:
            newfile = newsourcesfile
        else:
            newfile = os.path.join(configpath,
                                   oldfile.replace("%s/" % configpath, ''))
        newsource = lxml.etree.Element("Sources", nsmap=oldsource.nsmap)

        for el in oldsource.getchildren():
            if el.tag == lxml.etree.Comment or el.tag == 'Config':
                # skip comments and Config
                continue

            if el.tag == XI + 'include':
                oldsources.append(os.path.join(configpath, el.get('href')))
                newsource.append(el)
                continue

            # element must be a *Source
            newel = lxml.etree.Element("Source",
                                       type=el.tag.replace("Source",
                                                           "").lower())
            try:
                newel.set('recommended', el.find('Recommended').text.lower())
            except AttributeError:
                pass

            for tag in ['RawURL', 'URL', 'Version']:
                try:
                    newel.set(tag.lower(), el.find(tag).text)
                except AttributeError:
                    pass

            for child in el.getchildren():
                if child.tag in [
                        'Component', 'Blacklist', 'Whitelist', 'Arch'
                ]:
                    newel.append(child)

            groups = [e.text for e in el.findall("Group")]
            newsource = place_source(newsource, newel, groups)

        try:
            open(newfile,
                 'w').write(lxml.etree.tostring(newsource, pretty_print=True))
            print("%s written" % newfile)
        except IOError:
            print("Failed to write %s" % newfile)