X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=roundup%2Fadmin.py;h=b8cfb840bb81fce6cfcd55b24849d76940b65354;hb=64860b7d36f9fa7af75bf98aa1257263671a5a07;hp=d7b702a5f1914db73ed0015005c16a0b954155f4;hpb=7ab00a03fb52e9ab27168a934454860c3a76cf49;p=roundup.git diff --git a/roundup/admin.py b/roundup/admin.py index d7b702a..b8cfb84 100644 --- a/roundup/admin.py +++ b/roundup/admin.py @@ -16,14 +16,15 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: admin.py,v 1.3 2002-01-08 05:26:32 rochecompaan Exp $ +# $Id: admin.py,v 1.17 2002-07-14 06:05:50 richard Exp $ -import sys, os, getpass, getopt, re, UserDict, shlex +import sys, os, getpass, getopt, re, UserDict, shlex, shutil try: import csv except ImportError: csv = None from roundup import date, hyperdb, roundupdb, init, password, token +from roundup import __version__ as roundup_version import roundup.instance from roundup.i18n import _ @@ -71,7 +72,7 @@ class AdminTool: except KeyError: raise UsageError, _('no such class "%(classname)s"')%locals() - def props_from_args(self, args, klass=None): + def props_from_args(self, args): props = {} for arg in args: if arg.find('=') == -1: @@ -209,7 +210,11 @@ Command help: initopts -- init command options all -- all available help ''' - topic = args[0] + if len(args)>0: + topic = args[0] + else: + topic = 'help' + # try help_ methods if self.help.has_key(topic): @@ -245,19 +250,31 @@ Command help: print _('Back ends:'), ', '.join(backends) - def do_initialise(self, instance_home, args): - '''Usage: initialise [template [backend [admin password]]] - Initialise a new Roundup instance. + def do_install(self, instance_home, args): + '''Usage: install [template [backend [admin password]]] + Install a new Roundup instance. The command will prompt for the instance home directory (if not supplied through INSTANCE_HOME or the -i option). The template, backend and admin password may be specified on the command-line as arguments, in that order. + The initialise command must be called after this command in order + to initialise the instance's database. You may edit the instance's + initial database contents before running that command by editing + the instance's dbinit.py module init() function. + See also initopts help. ''' if len(args) < 1: raise UsageError, _('Not enough arguments supplied') + + # make sure the instance home can be created + parent = os.path.split(instance_home)[0] + if not os.path.exists(parent): + raise UsageError, _('Instance home parent directory "%(parent)s"' + ' does not exist')%locals() + # select template import roundup.templates templates = roundup.templates.listTemplates() @@ -269,6 +286,7 @@ Command help: if not template: template = 'classic' + # select hyperdb backend import roundup.backends backends = roundup.backends.__all__ backend = len(args) > 2 and args[2] or '' @@ -278,15 +296,64 @@ Command help: backend = raw_input(_('Select backend [anydbm]: ')).strip() if not backend: backend = 'anydbm' - if len(args) > 3: - adminpw = confirm = args[3] + + # install! + init.install(instance_home, template, backend) + + print _(''' + You should now edit the instance configuration file: + %(instance_config_file)s + ... at a minimum, you must set MAILHOST, MAIL_DOMAIN and ADMIN_EMAIL. + + If you wish to modify the default schema, you should also edit the database + initialisation file: + %(database_config_file)s + ... see the documentation on customizing for more information. +''')%{ + 'instance_config_file': os.path.join(instance_home, 'instance_config.py'), + 'database_config_file': os.path.join(instance_home, 'dbinit.py') +} + return 0 + + + def do_initialise(self, instance_home, args): + '''Usage: initialise [adminpw] + Initialise a new Roundup instance. + + The administrator details will be set at this step. + + Execute the instance's initialisation function dbinit.init() + ''' + # password + if len(args) > 1: + adminpw = args[1] else: adminpw = '' confirm = 'x' - while adminpw != confirm: - adminpw = getpass.getpass(_('Admin Password: ')) - confirm = getpass.getpass(_(' Confirm: ')) - init.init(instance_home, template, backend, adminpw) + while adminpw != confirm: + adminpw = getpass.getpass(_('Admin Password: ')) + confirm = getpass.getpass(_(' Confirm: ')) + + # make sure the instance home is installed + if not os.path.exists(instance_home): + raise UsageError, _('Instance home does not exist')%locals() + if not os.path.exists(os.path.join(instance_home, 'html')): + raise UsageError, _('Instance has not been installed')%locals() + + # is there already a database? + if os.path.exists(os.path.join(instance_home, 'db')): + print _('WARNING: The database is already initialised!') + print _('If you re-initialise it, you will lose all the data!') + ok = raw_input(_('Erase it? Y/[N]: ')).strip() + if ok.lower() != 'y': + return 0 + + # nuke it + shutil.rmtree(os.path.join(instance_home, 'db')) + + # GO + init.initialise(instance_home, adminpw) + return 0 @@ -420,9 +487,6 @@ Command help: except TypeError: raise UsageError, _('%(classname)s has no key property"')%{ 'classname': link_class.classname} - except KeyError: - raise UsageError, _('%(classname)s has no entry "%(propname)s"')%{ - 'classname': link_class.classname, 'propname': propname} # now do the find try: @@ -525,7 +589,7 @@ Command help: props = self.props_from_args(args[1:]) # convert types - for propname in props.keys(): + for propname, value in props.items(): # get the property try: proptype = properties[propname] @@ -535,18 +599,18 @@ Command help: if isinstance(proptype, hyperdb.Date): try: - props[key] = date.Date(value) + props[propname] = date.Date(value) except ValueError, message: raise UsageError, _('"%(value)s": %(message)s')%locals() elif isinstance(proptype, hyperdb.Interval): try: - props[key] = date.Interval(value) + props[propname] = date.Interval(value) except ValueError, message: raise UsageError, _('"%(value)s": %(message)s')%locals() elif isinstance(proptype, hyperdb.Password): - props[key] = password.Password(value) + props[propname] = password.Password(value) elif isinstance(proptype, hyperdb.Multilink): - props[key] = value.split(',') + props[propname] = value.split(',') # check for the key property propname = cl.getkey() @@ -832,6 +896,9 @@ Command help: while 1: l = p.parse(line) if l: break + line = f.readline() + if not line: + raise ValueError, "Unexpected EOF during CSV parse" # make the new node's property map d = {} @@ -857,6 +924,55 @@ Command help: apply(cl.create, (), d) return 0 + def do_pack(self, args): + '''Usage: pack period | date + +Remove journal entries older than a period of time specified or +before a certain date. + +A period is specified using the suffixes "y", "m", and "d". The +suffix "w" (for "week") means 7 days. + + "3y" means three years + "2y 1m" means two years and one month + "1m 25d" means one month and 25 days + "2w 3d" means two weeks and three days + +Date format is "YYYY-MM-DD" eg: + 2001-01-01 + + ''' + if len(args) <> 1: + raise UsageError, _('Not enough arguments supplied') + + # are we dealing with a period or a date + value = args[0] + date_re = re.compile(r''' + (?P\d\d\d\d-\d\d?-\d\d?)? # yyyy-mm-dd + (?P(\d+y\s*)?(\d+m\s*)?(\d+d\s*)?)? + ''', re.VERBOSE) + m = date_re.match(value) + if not m: + raise ValueError, _('Invalid format') + m = m.groupdict() + if m['period']: + pack_before = date.Date(". - %s"%value) + elif m['date']: + pack_before = date.Date(value) + self.db.pack(pack_before) + return 0 + + def do_reindex(self, args): + '''Usage: reindex + Re-generate an instance's search indexes. + + This will re-generate the search indexes for an instance. This will + typically happen automatically. + ''' + self.db.indexer.force_reindex() + self.db.reindex() + return 0 + def run_command(self, args): '''Run a single command ''' @@ -895,16 +1011,26 @@ Command help: while not self.instance_home: self.instance_home = raw_input(_('Enter instance home: ')).strip() - # before we open the db, we may be doing an init + # before we open the db, we may be doing an install or init if command == 'initialise': - return self.do_initialise(self.instance_home, args) + try: + return self.do_initialise(self.instance_home, args) + except UsageError, message: + print _('Error: %(message)s')%locals() + return 1 + elif command == 'install': + try: + return self.do_install(self.instance_home, args) + except UsageError, message: + print _('Error: %(message)s')%locals() + return 1 # get the instance try: instance = roundup.instance.open(self.instance_home) except ValueError, message: self.instance_home = '' - print _("Couldn't open instance: %(message)s")%locals() + print _("Error: Couldn't open instance: %(message)s")%locals() return 1 # only open the database once! @@ -917,6 +1043,7 @@ Command help: ret = function(args[1:]) except UsageError, message: print _('Error: %(message)s')%locals() + print print function.__doc__ ret = 1 except: @@ -928,7 +1055,7 @@ Command help: def interactive(self): '''Run in an interactive mode ''' - print _('Roundup {version} ready for input.') + print _('Roundup %s ready for input.'%roundup_version) print _('Type "help" for help.') try: import readline @@ -963,6 +1090,7 @@ Command help: # handle command-line args self.instance_home = os.environ.get('ROUNDUP_INSTANCE', '') + # TODO: reinstate the user/password stuff (-u arg too) name = password = '' if os.environ.has_key('ROUNDUP_LOGIN'): l = os.environ['ROUNDUP_LOGIN'].split(':') @@ -995,6 +1123,53 @@ if __name__ == '__main__': # # $Log: not supported by cvs2svn $ +# Revision 1.16 2002/07/09 04:19:09 richard +# Added reindex command to roundup-admin. +# Fixed reindex on first access. +# Also fixed reindexing of entries that change. +# +# Revision 1.15 2002/06/17 23:14:44 richard +# . #569415 ] {version} +# +# Revision 1.14 2002/06/11 06:41:50 richard +# Removed prompt for admin email in initialisation. +# +# Revision 1.13 2002/05/30 23:58:14 richard +# oops +# +# Revision 1.12 2002/05/26 09:04:42 richard +# out by one in the init args +# +# Revision 1.11 2002/05/23 01:14:20 richard +# . split instance initialisation into two steps, allowing config changes +# before the database is initialised. +# +# Revision 1.10 2002/04/27 10:07:23 richard +# minor fix to error message +# +# Revision 1.9 2002/03/12 22:51:47 richard +# . #527416 ] roundup-admin uses undefined value +# . #527503 ] unfriendly init blowup when parent dir +# (also handles UsageError correctly now in init) +# +# Revision 1.8 2002/02/27 03:28:21 richard +# Ran it through pychecker, made fixes +# +# Revision 1.7 2002/02/20 05:04:32 richard +# Wasn't handling the cvs parser feeding properly. +# +# Revision 1.6 2002/01/23 07:27:19 grubert +# . allow abbreviation of "help" in admin tool too. +# +# Revision 1.5 2002/01/21 16:33:19 rochecompaan +# You can now use the roundup-admin tool to pack the database +# +# Revision 1.4 2002/01/14 06:51:09 richard +# . #503164 ] create and passwords +# +# Revision 1.3 2002/01/08 05:26:32 rochecompaan +# Missing "self" in props_from_args +# # Revision 1.2 2002/01/07 10:41:44 richard # #500140 ] AdminTool.get_class() returns nothing #