From c2ea6560f4ca3497eddec9970e76d76d98f4e485 Mon Sep 17 00:00:00 2001 From: Brian Dolbec Date: Thu, 3 Feb 2011 00:08:43 -0800 Subject: Mass namespace rename and update --- overlord/db.py | 353 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 353 insertions(+) create mode 100644 overlord/db.py (limited to 'overlord/db.py') diff --git a/overlord/db.py b/overlord/db.py new file mode 100644 index 0000000..d54efa5 --- /dev/null +++ b/overlord/db.py @@ -0,0 +1,353 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +################################################################################# +# overlord OVERLAY DB +################################################################################# +# File: db.py +# +# Access to the db of overlays +# +# Copyright: +# (c) 2005 - 2008 Gunnar Wrobel +# Distributed under the terms of the GNU General Public License v2 +# +# Author(s): +# Gunnar Wrobel +# +'''Handles different storage files.''' + +__version__ = "$Id: db.py 309 2007-04-09 16:23:38Z wrobel $" + +#=============================================================================== +# +# Dependencies +# +#------------------------------------------------------------------------------- + +import os, os.path, urllib2, hashlib + +from overlord.utils import path, delete_empty_directory +from overlord.dbbase import DbBase +from overlord.makeconf import MakeConf + +#from overlord.debug import OUT + +#=============================================================================== +# +# Class DB +# +#------------------------------------------------------------------------------- + +class DB(DbBase): + ''' Handle the list of local overlays.''' + + def __init__(self, config): + + self.config = config + self.output = config['output'] + + self.path = config['local_list'] + + if config['nocheck']: + ignore = 2 + else: + ignore = 1 + + quiet = int(config['quietness']) < 3 + + DbBase.__init__(self, + [config['local_list'], ], + config, + ignore, + quiet) + + self.output.debug('DB handler initiated', 6) + + # overrider + def _broken_catalog_hint(self): + return '' + + def add(self, overlay, quiet = False): + ''' + Add an overlay to the local list of overlays. + + >>> write = os.tmpnam() + >>> write2 = os.tmpnam() + >>> write3 = os.tmpnam() + >>> here = os.path.dirname(os.path.realpath(__file__)) + >>> config = {'local_list' : + ... here + '/tests/testfiles/global-overlays.xml', + ... 'make_conf' : write2, + ... 'nocheck' : True, + ... 'storage' : write3, + ... 'quietness':3} + + >>> here = os.path.dirname(os.path.realpath(__file__)) + >>> a = DB(config) + >>> config['local_list'] = write + >>> b = DB(config) + >>> OUT.color_off() + + >>> m = MakeConf(config, b.overlays) + >>> m.path = write2 + >>> m.write() + + Commented out since it needs network access: + + # >>> b.add(a.select('wrobel-stable')) #doctest: +ELLIPSIS + # * Running command "/usr/bin/rsync -rlptDvz --progress --delete --delete-after --timeout=180 --exclude="distfiles/*" --exclude="local/*" --exclude="packages/*" "rsync://gunnarwrobel.de/wrobel-stable/*" "/tmp/file.../wrobel-stable""... + # >>> c = DbBase([write, ], dict()) + # >>> c.overlays.keys() + # [u'wrobel-stable'] + + # >>> m = MakeConf(config, b.overlays) + # >>> [i.name for i in m.overlays] #doctest: +ELLIPSIS + # [u'wrobel-stable'] + + + # >>> os.unlink(write) + >>> os.unlink(write2) + >>> import shutil + + # >>> shutil.rmtree(write3) + ''' + + if overlay.name not in self.overlays.keys(): + result = overlay.add(self.config['storage'], quiet) + if result == 0: + if 'priority' in self.config.keys(): + overlay.set_priority(self.config['priority']) + self.overlays[overlay.name] = overlay + self.write(self.path) + make_conf = MakeConf(self.config, self.overlays) + make_conf.add(overlay) + else: + mdir = path([self.config['storage'], overlay.name]) + delete_empty_directory(mdir, self.output) + if os.path.exists(mdir): + raise Exception('Adding overlay "%s" failed!' + ' Possible remains of the operation have NOT' + ' been removed and may be left at "%s".' + ' Please remove them manually if required.' \ + % (overlay.name, mdir)) + else: + raise Exception('Adding overlay "%s" failed!' % overlay.name) + else: + raise Exception('Overlay "' + overlay.name + '" already in the loca' + 'l list!') + + def delete(self, overlay): + ''' + Add an overlay to the local list of overlays. + + >>> write = os.tmpnam() + >>> write2 = os.tmpnam() + >>> write3 = os.tmpnam() + >>> here = os.path.dirname(os.path.realpath(__file__)) + >>> config = {'local_list' : + ... here + '/tests/testfiles/global-overlays.xml', + ... 'make_conf' : write2, + ... 'nocheck' : True, + ... 'storage' : write3, + ... 'quietness':3} + + >>> here = os.path.dirname(os.path.realpath(__file__)) + >>> a = DB(config) + >>> config['local_list'] = write + >>> b = DB(config) + >>> .color_off() + + >>> m = MakeConf(config, b.overlays) + >>> m.path = here + '/tests/testfiles/make.conf' + >>> m.read() + + >>> m.path = write2 + >>> m.write() + + # >>> b.add(a.select('wrobel-stable')) #doctest: +ELLIPSIS + # * Running command "/usr/bin/rsync -rlptDvz --progress --delete --delete-after --timeout=180 --exclude="distfiles/*" --exclude="local/*" --exclude="packages/*" "rsync://gunnarwrobel.de/wrobel-stable/*" "/tmp/file.../wrobel-stable""... + # >>> b.add(a.select('wrobel')) #doctest: +ELLIPSIS + # * Running command "/usr/bin/svn co "https://overlays.gentoo.org/svn/dev/wrobel/" "/tmp/file.../wrobel""... + # >>> c = DbBase([write, ], dict()) + # >>> c.overlays.keys() + # [u'wrobel', u'wrobel-stable'] + + # >>> b.delete(b.select('wrobel')) + # >>> c = DbBase([write, ], dict()) + # >>> c.overlays.keys() + # [u'wrobel-stable'] + + # >>> m = MakeConf(config, b.overlays) + # >>> [i.name for i in m.overlays] #doctest: +ELLIPSIS + # [u'wrobel-stable'] + + # >>> os.unlink(write) + >>> os.unlink(write2) + >>> import shutil + + # >>> shutil.rmtree(write3) + ''' + + if overlay.name in self.overlays.keys(): + make_conf = MakeConf(self.config, self.overlays) + overlay.delete(self.config['storage']) + del self.overlays[overlay.name] + self.write(self.path) + make_conf.delete(overlay) + else: + raise Exception('No local overlay named "' + overlay.name + '"!') + + def sync(self, overlay_name, quiet = False): + '''Synchronize the given overlay.''' + + overlay = self.select(overlay_name) + result = overlay.sync(self.config['storage'], quiet) + if result: + raise Exception('Syncing overlay "' + overlay_name + + '" returned status ' + str(result) + '!') + +#=============================================================================== +# +# Class RemoteDB +# +#------------------------------------------------------------------------------- + +class RemoteDB(DbBase): + '''Handles fetching the remote overlay list.''' + + def __init__(self, config, ignore_init_read_errors=False): + + self.config = config + self.output = config['output'] + + self.proxies = {} + + if config['proxy']: + self.proxies['http'] = config['proxy'] + elif os.getenv('http_proxy'): + self.proxies['http'] = os.getenv('http_proxy') + + if self.proxies: + proxy_handler = urllib2.ProxyHandler(self.proxies) + opener = urllib2.build_opener(proxy_handler) + urllib2.install_opener(opener) + + self.urls = [i.strip() for i in config['overlays'].split('\n') if i] + + paths = [self.path(i) for i in self.urls] + + if config['nocheck']: + ignore = 2 + else: + ignore = 0 + + quiet = int(config['quietness']) < 3 + + DbBase.__init__(self, paths, config, ignore, quiet, ignore_init_read_errors) + + # overrider + def _broken_catalog_hint(self): + return 'Try running "sudo overlord -f" to re-fetch that file' + + def cache(self): + ''' + Copy the remote overlay list to the local cache. + + >>> here = os.path.dirname(os.path.realpath(__file__)) + >>> cache = os.tmpnam() + >>> config = {'overlays' : + ... 'file://' + here + '/tests/testfiles/global-overlays.xml', + ... 'cache' : cache, + ... 'nocheck' : True, + ... 'proxy' : None, + ... 'quietness':3} + >>> a = RemoteDB(config) + >>> a.cache() + >>> b = open(a.path(config['overlays'])) + >>> b.readlines()[24] + ' A collection of ebuilds from Gunnar Wrobel [wrobel@gentoo.org].\\n' + + >>> b.close() + >>> os.unlink(a.path(config['overlays'])) + + >>> a.overlays.keys() + [u'wrobel', u'wrobel-stable'] + ''' + for url in self.urls: + + mpath = self.path(url) + + # Check for sufficient privileges + if os.path.exists(mpath) and not os.access(mpath, os.W_OK): + self.output.warn('You do not have permission to update the cache (%s).' % mpath) + import getpass + if getpass.getuser() != 'root': + self.output.warn('Hint: You are not root.\n') + continue + + try: + + # Fetch the remote list + olist = urllib2.urlopen(url).read() + + # Create our storage directory if it is missing + if not os.path.exists(os.path.dirname(mpath)): + try: + os.makedirs(os.path.dirname(mpath)) + except OSError, error: + raise OSError('Failed to create overlord storage direct' + + 'ory ' + os.path.dirname(mpath) + '\n' + + 'Error was:' + str(error)) + + # Before we overwrite the old cache, check that the downloaded + # file is intact and can be parsed + try: + self.read(olist, origin=url) + except Exception, error: + raise IOError('Failed to parse the overlays list fetched fr' + 'om ' + url + '\nThis means that the download' + 'ed file is somehow corrupt or there was a pr' + 'oblem with the webserver. Check the content ' + 'of the file. Error was:\n' + str(error)) + + # Ok, now we can overwrite the old cache + try: + out_file = open(mpath, 'w') + out_file.write(olist) + out_file.close() + + except Exception, error: + raise IOError('Failed to temporarily cache overlays list in' + ' ' + mpath + '\nError was:\n' + str(error)) + + + except IOError, error: + self.output.warn('Failed to update the overlay list from: ' + + url + '\nError was:\n' + str(error)) + + def path(self, url): + '''Return a unique file name for the url.''' + + base = self.config['cache'] + + self.output.debug('Generating cache path.', 6) + + return base + '_' + hashlib.md5(url).hexdigest() + '.xml' + + +#=============================================================================== +# +# Testing +# +#------------------------------------------------------------------------------- + +if __name__ == '__main__': + import doctest, sys + + # Ignore warnings here. We are just testing + from warnings import filterwarnings, resetwarnings + filterwarnings('ignore') + + doctest.testmod(sys.modules[__name__]) + + resetwarnings() -- cgit v1.2.3-18-g5258