mirror of https://github.com/BOINC/boinc.git
180 lines
6.1 KiB
Python
180 lines
6.1 KiB
Python
#!/usr/bin/env python
|
|
|
|
# $Id$
|
|
|
|
# add_util.py - code shared between add and xadd
|
|
|
|
import database, tools
|
|
import time, pprint
|
|
import MySQLdb
|
|
|
|
CREATE_TIME = ['?create_time', int(time.time())]
|
|
TRANSITION_TIME = ['?transition_time', int(time.time())]
|
|
|
|
class XAppVersion(database.AppVersion):
|
|
def __init__(self,**kwargs):
|
|
kwargs['xml_doc'] = tools.process_app_version(
|
|
app = kwargs['app'],
|
|
version_num = int(kwargs['version_num']),
|
|
exec_files = kwargs['exec_files'],
|
|
signature_files = kwargs.setdefault('signature_files',{}))
|
|
del kwargs['signature_files']
|
|
del kwargs['exec_files']
|
|
del kwargs['exec_file']
|
|
database.AppVersion.__init__(self,**kwargs)
|
|
|
|
# format: [ database.Object, args, ...]
|
|
# arg format:
|
|
# 'arg'
|
|
# '?arg' optional
|
|
# [ 'arg', default_value ]
|
|
|
|
# NOTE TO KARL: If cross_project_id is not supplied, the default value
|
|
# should be a random 32 character script obtained by doing the md5sum
|
|
# hash of (say) 512 bytes from /dev/urandom or similar.
|
|
|
|
list_objects_to_add = [
|
|
[ database.Platform, 'name', 'user_friendly_name', CREATE_TIME ],
|
|
[ database.App, 'name', 'user_friendly_name', ['?min_version',0], CREATE_TIME],
|
|
[ XAppVersion, 'app', 'platform', 'version_num', 'exec_file', '?signature_file',
|
|
CREATE_TIME ],
|
|
[ database.User, 'name', 'email_addr', 'authenticator',
|
|
['?country','United States'], ['?postal_code','0'], ['?cross_project_id', '0'],
|
|
'?global_prefs', '?global_prefs_file',
|
|
CREATE_TIME ],
|
|
# [ database.Workunit, 'zzzz' ],
|
|
]
|
|
|
|
class AddObject:
|
|
pass
|
|
|
|
add_objects = {}
|
|
for o in list_objects_to_add:
|
|
add_object = AddObject()
|
|
add_object.DatabaseObject = o[0]
|
|
add_object.name = add_object.DatabaseObject._table.table
|
|
add_object.args = []
|
|
add_object.optional_args = []
|
|
add_object.default_values = {}
|
|
for arg in o[1:]:
|
|
if isinstance(arg, list):
|
|
default_value = arg[1]
|
|
arg = arg[0]
|
|
else:
|
|
default_value = None
|
|
if arg.startswith('?'):
|
|
optional = True
|
|
arg = arg[1:]
|
|
else:
|
|
optional = False
|
|
if optional:
|
|
add_object.optional_args.append(arg)
|
|
else:
|
|
add_object.args.append(arg)
|
|
if default_value:
|
|
add_object.default_values[arg] = default_value
|
|
add_objects[add_object.name] = add_object
|
|
|
|
most_recent_exec_file = None
|
|
|
|
def translate_arg(object, arg, value, args_dict):
|
|
'''Translate various user argument values, for adding given ``object``.
|
|
Modifies ``args_dict``.'''
|
|
|
|
database_table = None
|
|
try:
|
|
database_table = database.__dict__[arg.capitalize()]._table
|
|
except:
|
|
pass
|
|
if database_table:
|
|
args_dict[arg] = translate_database_arg(database_table, arg, value)
|
|
return
|
|
|
|
if arg == 'global_prefs_file':
|
|
args_dict['global_prefs'] = open(value).read()
|
|
return
|
|
|
|
if object.DatabaseObject == XAppVersion:
|
|
# 'add app_version' accepts multiple '-exec_file's with
|
|
# '-signature_file' applying to the most recent exec_file
|
|
if arg == 'exec_file':
|
|
global most_recent_exec_file
|
|
most_recent_exec_file = value
|
|
args_dict.setdefault('exec_files',[]).append(value)
|
|
# since 'exec_file' (without 's') is required, set it to None so
|
|
# that argument checker knows we got one; we'll delete it later.
|
|
args_dict[arg] = None
|
|
return
|
|
if arg == 'signature_file':
|
|
args_dict.setdefault('signature_files',{})[most_recent_exec_file] = value
|
|
return
|
|
|
|
if arg == 'cross_project_id':
|
|
if not value:
|
|
value = tools.make_uuid()
|
|
|
|
args_dict[arg] = value
|
|
|
|
def translate_database_arg(database_table, arg, value):
|
|
'''Look up an object ``value`` either as a database ID or string.
|
|
This allows us to accept e.g. either --app Astropulse or --app 1'''
|
|
try:
|
|
id = int(value)
|
|
results = database_table.find(id=id)
|
|
if not results:
|
|
raise Exception("")
|
|
except:
|
|
results = database_table.find(name=value)
|
|
if len(results) == 0:
|
|
raise SystemExit('No %s "%s" found' %(arg,value))
|
|
if len(results) > 1:
|
|
print >>sys.stderr, 'Too many %ss match "%s": '%(arg,value)
|
|
for result in results:
|
|
print >>sys.stderr, ' ', result.name
|
|
raise SystemExit
|
|
return results[0]
|
|
|
|
class AddObjectException(Exception): pass
|
|
|
|
def check_required_arguments(add_object, args_dict):
|
|
for arg in add_object.args:
|
|
if not arg in args_dict:
|
|
raise AddObjectException('required value for %s not given'%arg)
|
|
|
|
def translate_args_dict(add_object, untranslated_args_dict):
|
|
args_dict = add_object.default_values.copy()
|
|
for arg,value in untranslated_args_dict.items():
|
|
translate_arg(add_object,arg,value,args_dict)
|
|
return args_dict
|
|
|
|
def exception_is_duplicate_entry(exception):
|
|
'''Checks a MySQLdb.IntegrityError for whether the error is Duplicate
|
|
Entry. Kludgy.'''
|
|
return (isinstance(exception, MySQLdb.IntegrityError) and
|
|
str(exception).find('Duplicate entry')!=-1)
|
|
|
|
def do_add_object(add_object, untranslated_args_dict, skip_old=False):
|
|
'''Input ```args_dict``` must have been translated already.'''
|
|
args_dict = translate_args_dict(add_object, untranslated_args_dict)
|
|
check_required_arguments(add_object, args_dict)
|
|
dbobject = add_object.DatabaseObject(**args_dict)
|
|
print "Processing", dbobject, "..."
|
|
# print "Commiting", dbobject, "with args:"
|
|
# pprint.pprint(dbobject.__dict__)
|
|
try:
|
|
dbobject.commit()
|
|
except MySQLdb.MySQLError, e:
|
|
if skip_old and exception_is_duplicate_entry(e):
|
|
print " Skipped existing", dbobject
|
|
return
|
|
else:
|
|
raise SystemExit('Error committing %s: %s' %(dbobject, e))
|
|
|
|
# delete object and re-select it from database to allow user to check
|
|
# consistency
|
|
id = dbobject.id
|
|
del dbobject
|
|
dbobject = add_object.DatabaseObject._table[id]
|
|
print " Committed", dbobject, "; values:"
|
|
pprint.pprint(dbobject.__dict__)
|