From e4293652d5b2a80725e6f83843f91364e19ba199 Mon Sep 17 00:00:00 2001
From: Gunnar Wrobel
Date: Tue, 11 Sep 2007 05:53:25 +0000
Subject: Import layman.
---
.svn.ignore | 1 +
__init__.py | 1 +
action.py | 420 ++++++++++++++++++++++++++
config.py | 300 ++++++++++++++++++
db.py | 585 ++++++++++++++++++++++++++++++++++++
debug.py | 501 ++++++++++++++++++++++++++++++
overlay.py | 247 +++++++++++++++
overlays/.svn.ignore | 1 +
overlays/__init__.py | 1 +
overlays/bzr.py | 66 ++++
overlays/cvs.py | 73 +++++
overlays/darcs.py | 64 ++++
overlays/git.py | 63 ++++
overlays/mercurial.py | 64 ++++
overlays/overlay.py | 266 ++++++++++++++++
overlays/rsync.py | 68 +++++
overlays/svn.py | 65 ++++
overlays/tar.py | 189 ++++++++++++
tests/dtest.py | 90 ++++++
tests/testfiles/global-overlays.xml | 30 ++
tests/testfiles/layman-test.tar.bz2 | Bin 0 -> 845 bytes
tests/testfiles/make.conf | 345 +++++++++++++++++++++
utils.py | 208 +++++++++++++
version.py | 24 ++
24 files changed, 3672 insertions(+)
create mode 100644 .svn.ignore
create mode 100644 __init__.py
create mode 100644 action.py
create mode 100644 config.py
create mode 100644 db.py
create mode 100644 debug.py
create mode 100644 overlay.py
create mode 100644 overlays/.svn.ignore
create mode 100644 overlays/__init__.py
create mode 100644 overlays/bzr.py
create mode 100644 overlays/cvs.py
create mode 100644 overlays/darcs.py
create mode 100644 overlays/git.py
create mode 100644 overlays/mercurial.py
create mode 100644 overlays/overlay.py
create mode 100644 overlays/rsync.py
create mode 100644 overlays/svn.py
create mode 100644 overlays/tar.py
create mode 100644 tests/dtest.py
create mode 100644 tests/testfiles/global-overlays.xml
create mode 100644 tests/testfiles/layman-test.tar.bz2
create mode 100644 tests/testfiles/make.conf
create mode 100644 utils.py
create mode 100644 version.py
diff --git a/.svn.ignore b/.svn.ignore
new file mode 100644
index 0000000..0d20b64
--- /dev/null
+++ b/.svn.ignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/__init__.py b/__init__.py
new file mode 100644
index 0000000..792d600
--- /dev/null
+++ b/__init__.py
@@ -0,0 +1 @@
+#
diff --git a/action.py b/action.py
new file mode 100644
index 0000000..b2c67ce
--- /dev/null
+++ b/action.py
@@ -0,0 +1,420 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN ACTIONS
+#################################################################################
+# File: action.py
+#
+# Handles layman actions.
+#
+# Copyright:
+# (c) 2005 - 2006 Gunnar Wrobel
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel
+#
+''' Provides the different actions that can be performed by layman.'''
+
+__version__ = "$Id: action.py 312 2007-04-09 19:45:49Z wrobel $"
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+import sys
+
+from layman.db import DB, RemoteDB
+
+from layman.debug import OUT
+
+#===============================================================================
+#
+# Class Fetch
+#
+#-------------------------------------------------------------------------------
+
+class Fetch:
+ ''' Fetches the overlay listing.
+
+ >>> import os
+ >>> 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 = Fetch(config)
+ >>> a.run()
+ 0
+ >>> b = open(a.db.path(config['overlays']))
+ >>> b.readlines()[24]
+ ' A collection of ebuilds from Gunnar Wrobel [wrobel@gentoo.org].\\n'
+
+ >>> b.close()
+ >>> os.unlink(a.db.path(config['overlays']))
+
+ >>> a.db.overlays.keys()
+ [u'wrobel', u'wrobel-stable']
+ '''
+
+ def __init__(self, config):
+ self.db = RemoteDB(config)
+
+ def run(self):
+ '''Fetch the overlay listing.'''
+ try:
+ self.db.cache()
+ except Exception, error:
+ OUT.die('Failed to fetch overlay list!\nError was: '
+ + str(error))
+
+ return 0
+
+#===============================================================================
+#
+# Class Sync
+#
+#-------------------------------------------------------------------------------
+
+class Sync:
+ ''' Syncs the selected overlays.'''
+
+ def __init__(self, config):
+
+ self.db = DB(config)
+
+ self.rdb = RemoteDB(config)
+
+ self.selection = config['sync']
+
+ if config['sync_all'] or 'ALL' in self.selection:
+ self.selection = self.db.overlays.keys()
+
+ def run(self):
+ '''Synchronize the overlays.'''
+
+ OUT.debug('Updating selected overlays', 6)
+
+ warnings = []
+ success = []
+ for i in self.selection:
+ ordb = self.rdb.select(i)
+ odb = self.db.select(i)
+ if ordb and odb and ordb.src != odb.src:
+ warnings.append(
+ 'The source of the overlay "' + i + '" seems to have c'
+ 'hanged. You currently sync from "' + odb.src + '" whi'
+ 'le the global layman list reports "' + ordb.src + '" '
+ 'as correct location. Please consider removing and rea'
+ 'dding the overlay!')
+
+ try:
+ self.db.sync(i)
+ success.append('Successfully synchronized overlay "' + i + '".')
+ except Exception, error:
+ warnings.append(
+ 'Failed to sync overlay "' + i + '".\nError was: '
+ + str(error))
+
+ if success:
+ OUT.info('\nSuccess:\n------\n', 3)
+ for i in success:
+ OUT.info(i, 3)
+
+ if warnings:
+ OUT.warn('\nErrors:\n------\n', 2)
+ for i in warnings:
+ OUT.warn(i + '\n', 2)
+ return 1
+
+ return 0
+
+#===============================================================================
+#
+# Class Add
+#
+#-------------------------------------------------------------------------------
+
+class Add:
+ ''' Adds the selected overlays.'''
+
+ def __init__(self, config):
+
+ self.config = config
+
+ self.db = DB(config)
+
+ self.rdb = RemoteDB(config)
+
+ self.selection = config['add']
+
+ if 'ALL' in self.selection:
+ self.selection = self.rdb.overlays.keys()
+
+ def run(self):
+ '''Add the overlay.'''
+
+ OUT.debug('Adding selected overlays', 6)
+
+ result = 0
+
+ for i in self.selection:
+ overlay = self.rdb.select(i)
+
+ OUT.debug('Selected overlay', 7)
+
+ if overlay:
+ try:
+ self.db.add(overlay)
+ OUT.info('Successfully added overlay "' + i + '".', 2)
+ except Exception, error:
+ OUT.warn('Failed to add overlay "' + i + '".\nError was: '
+ + str(error), 2)
+ result = 1
+ else:
+ OUT.warn('Overlay "' + i + '" does not exist!', 2)
+ result = 1
+
+ return result
+
+#===============================================================================
+#
+# Class Delete
+#
+#-------------------------------------------------------------------------------
+
+class Delete:
+ ''' Deletes the selected overlays.'''
+
+ def __init__(self, config):
+
+ self.db = DB(config)
+
+ self.selection = config['delete']
+
+ if 'ALL' in self.selection:
+ self.selection = self.db.overlays.keys()
+
+ def run(self):
+ '''Delete the overlay.'''
+
+ OUT.debug('Deleting selected overlays', 6)
+
+ result = 0
+
+ for i in self.selection:
+ overlay = self.db.select(i)
+
+ OUT.debug('Selected overlay', 7)
+
+ if overlay:
+ try:
+ self.db.delete(overlay)
+ OUT.info('Successfully deleted overlay "' + i + '".', 2)
+ except Exception, error:
+ OUT.warn('Failed to delete overlay "' + i + '".\nError was: '
+ + str(error), 2)
+ result = 1
+ else:
+ OUT.warn('Overlay "' + i + '" does not exist!', 2)
+ result = 1
+
+ return result
+
+#===============================================================================
+#
+# Class List
+#
+#-------------------------------------------------------------------------------
+
+class List:
+ ''' Lists the available overlays.
+
+ >>> import os
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> cache = os.tmpnam()
+ >>> config = {'overlays' :
+ ... 'file://' + here + '/tests/testfiles/global-overlays.xml',
+ ... 'cache' : cache,
+ ... 'proxy' : None,
+ ... 'nocheck' : False,
+ ... 'verbose': False,
+ ... 'quietness':3}
+ >>> a = List(config)
+ >>> a.rdb.cache()
+ >>> OUT.color_off()
+ >>> a.run()
+ * wrobel [Subversion] (source: https://overlays.gentoo.or...)
+ 0
+ >>> a.config['verbose'] = True
+ >>> a.run()
+ * wrobel
+ * ~~~~~~
+ * Source : https://overlays.gentoo.org/svn/dev/wrobel
+ * Contact : nobody@gentoo.org
+ * Type : Subversion; Priority: 10
+ *
+ * Description:
+ * Test
+ *
+ * *** This is no official gentoo overlay ***
+ *
+ * wrobel-stable
+ * ~~~~~~~~~~~~~
+ * Source : rsync://gunnarwrobel.de/wrobel-stable
+ * Contact : nobody@gentoo.org
+ * Type : Rsync; Priority: 50
+ *
+ * Description:
+ * A collection of ebuilds from Gunnar Wrobel [wrobel@gentoo.org].
+ *
+ 0
+ '''
+
+ def __init__(self, config):
+
+ OUT.debug('Creating RemoteDB handler', 6)
+
+ self.rdb = RemoteDB(config)
+ self.config = config
+
+ def run(self):
+ ''' List the available overlays.'''
+
+ for i in self.rdb.list(self.config['verbose']):
+ # Is the overlay supported?
+ if i[1]:
+ # Is this an official overlay?
+ if i[2]:
+ OUT.info(i[0], 1)
+ # Unofficial overlays will only be listed if we are not
+ # checking or listing verbose
+ elif self.config['nocheck'] or self.config['verbose']:
+ # Give a reason why this is marked yellow if it is a verbose
+ # listing
+ if self.config['verbose']:
+ OUT.warn('*** This is no official gentoo overlay ***\n', 1)
+ OUT.warn(i[0], 1)
+ # Unsupported overlays will only be listed if we are not checking
+ # or listing verbose
+ elif self.config['nocheck'] or self.config['verbose']:
+ # Give a reason why this is marked red if it is a verbose
+ # listing
+ if self.config['verbose']:
+ OUT.error('*** You are lacking the necessary tools to insta'
+ 'll this overlay ***\n')
+ OUT.error(i[0])
+
+ return 0
+
+#===============================================================================
+#
+# Class ListLocal
+#
+#-------------------------------------------------------------------------------
+
+class ListLocal:
+ ''' Lists the local overlays.'''
+
+ def __init__(self, config):
+ self.db = DB(config)
+ self.config = config
+
+ def run(self):
+ '''List the overlays.'''
+
+ for i in self.db.list(self.config['verbose']):
+
+ OUT.debug('Printing local overlay.', 8)
+
+ # Is the overlay supported?
+ if i[1]:
+ # Is this an official overlay?
+ if i[2]:
+ OUT.info(i[0], 1)
+ # Unofficial overlays will only be listed if we are not
+ # checking or listing verbose
+ else:
+ # Give a reason why this is marked yellow if it is a verbose
+ # listing
+ if self.config['verbose']:
+ OUT.warn('*** This is no official gentoo overlay ***\n', 1)
+ OUT.warn(i[0], 1)
+ # Unsupported overlays will only be listed if we are not checking
+ # or listing verbose
+ else:
+ # Give a reason why this is marked red if it is a verbose
+ # listing
+ if self.config['verbose']:
+ OUT.error('*** You are lacking the necessary tools to insta'
+ 'll this overlay ***\n')
+ OUT.error(i[0])
+
+ return 0
+
+#===============================================================================
+#
+# Class Actions
+#
+#-------------------------------------------------------------------------------
+
+class Actions:
+ '''Dispatches to the actions the user selected. '''
+
+ # Given in order of precedence
+ actions = [('fetch', Fetch),
+ ('add', Add),
+ ('sync', Sync),
+ ('sync_all', Sync),
+ ('delete', Delete),
+ ('list', List),
+ ('list_local', ListLocal),]
+
+ def __init__(self, config):
+
+ # Make fetching the overlay list a default action
+ if not 'nofetch' in config.keys():
+ # Actions that implicitely call the fetch operation before
+ fetch_actions = ['fetch', 'sync', 'sync_all', 'list']
+ for i in fetch_actions:
+ if i in config.keys():
+ # Implicitely call fetch, break loop
+ Fetch(config).run()
+ break
+
+ result = 0
+
+ for i in self.actions:
+
+ OUT.debug('Checking for action', 7)
+
+ if i[0] in config.keys():
+ result += i[1](config).run()
+
+
+ if not result:
+ sys.exit(0)
+ else:
+ sys.exit(1)
+
+#===============================================================================
+#
+# 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()
diff --git a/config.py b/config.py
new file mode 100644
index 0000000..287f223
--- /dev/null
+++ b/config.py
@@ -0,0 +1,300 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#################################################################################
+# LAYMAN CONFIGURATION
+#################################################################################
+# File: config.py
+#
+# Handles layman configuration
+#
+# Copyright:
+# (c) 2005 - 2006 Gunnar Wrobel
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Gunnar Wrobel
+#
+'''Defines the configuration options and provides parsing functionality.'''
+
+__version__ = "$Id: config.py 286 2007-01-09 17:48:23Z wrobel $"
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+import sys, ConfigParser
+
+from optparse import OptionParser, OptionGroup
+from layman.debug import OUT
+from layman.version import VERSION
+
+#===============================================================================
+#
+# Class Config
+#
+#-------------------------------------------------------------------------------
+
+class Config(object):
+ '''Handles the configuration.'''
+
+ def __init__(self):
+ '''
+ Creates and describes all possible polymeraZe options and creates
+ a debugging object.
+
+ >>> import os.path
+ >>> here = os.path.dirname(os.path.realpath(__file__))
+ >>> sys.argv.append('--config')
+ >>> sys.argv.append(here + '/../etc/layman.cfg')
+ >>> a = Config()
+ >>> a['overlays']
+ '\\nhttp://www.gentoo.org/proj/en/overlays/layman-global.txt'
+ >>> sorted(a.keys())
+ ['cache', 'config', 'config_dir', 'local_list', 'make_conf', 'nocheck', 'overlays', 'proxy', 'quietness', 'storage']
+ '''
+
+ self.defaults = {'config_dir': '/etc/layman',
+ 'config' : '/etc/layman/layman.cfg',
+ 'storage' : '/usr/portage/local/layman',
+ 'cache' : '%(storage)s/cache',
+ 'local_list': '%(storage)s/overlays.xml',
+ 'make_conf' : '%(storage)s/make.conf',
+ 'nocheck' : 'no',
+ 'proxy' : '',
+ 'overlays' :
+ 'http://www.gentoo.org/proj/en/overlays/layman-global.'
+ 'txt',}
+
+
+ self.parser = OptionParser(
+ usage = '\n\nlayman -a/-d/-S|overlay\nlayman -f [-o url]\nlayman' \
+ ' -l|-L',
+ version = VERSION)
+
+ #-----------------------------------------------------------------
+ # Main Options
+
+ group = OptionGroup(self.parser,
+ '')
+
+ group.add_option('-a',
+ '--add',
+ action = 'append',
+ help = 'Add the given overlay from the cached remote li'
+ 'st to your locally installed overlays.. Specify "ALL" '
+ 'to add all overlays from the remote list.')
+
+ group.add_option('-d',
+ '--delete',
+ action = 'append',
+ help = 'Remove the given overlay from your locally inst'
+ 'alled overlays. Specify "ALL" to remove all overlays')
+
+ group.add_option('-s',
+ '--sync',
+ action = 'append',
+ help = 'Update the specified overlay. Use "ALL" as para'
+ 'meter to synchronize all overlays')
+
+ group.add_option('-S',
+ '--sync-all',
+ action = 'store_true',
+ help = 'Update all overlays.')
+
+ group.add_option('-L',
+ '--list',
+ action = 'store_true',
+ help = 'List the contents of the remote list.')
+
+ group.add_option('-l',
+ '--list-local',
+ action = 'store_true',
+ help = 'List the locally installed overlays.')
+
+ group.add_option('-f',
+ '--fetch',
+ action = 'store_true',
+ help = 'Fetch a remote list of overlays. This option is'
+ ' deprecated. The fetch operation will be performed by '
+ 'default when you run sync, sync-all, or list.')
+
+ group.add_option('-n',
+ '--nofetch',
+ action = 'store_true',
+ help = 'Do not fetch a remote list of overlays.')
+
+ group.add_option('-p',
+ '--priority',
+ action = 'store',
+ help = 'Use this with the --add switch to set the prior'
+ 'ity of the added overlay. This will influence the sort'
+ 'ing order of the overlays in the PORTDIR_OVERLAY varia'
+ 'ble.')
+
+ self.parser.add_option_group(group)
+
+ #-----------------------------------------------------------------
+ # Additional Options
+
+ group = OptionGroup(self.parser,
+ '')
+
+ group.add_option('-c',
+ '--config',
+ action = 'store',
+ help = 'Path to the config file [default: ' \
+ + self.defaults['config'] + '].')
+
+ group.add_option('-o',
+ '--overlays',
+ action = 'append',
+ help = 'The list of overlays [default: ' \
+ + self.defaults['overlays'] + '].')
+
+ self.parser.add_option_group(group)
+
+ #-----------------------------------------------------------------
+ # Output Options
+
+ group = OptionGroup(self.parser,
+ '