#!/usr/bin/env python # $Id$ # Creates a new BOINC project. # TODO: use database.py (mainly for setup_project.py) # TODO: don't add app / app version here. # TODO: create 'apps' subdirectory and set it in config.xml # TODO: use configxml module import sys, os, getopt, re sys.path.append('../py') from version import * from boinc import * argv0 = sys.argv[0] HOME = os.path.expanduser('~') USER = os.environ['USER'] HELP = """ syntax: %(argv0)s [options] project-dir-name 'Project Long Name' app-exe 'AppName' Creates a new project with given name with everything running on a single server. Misc options: --verbose={0,1,2} default: 1 -v alias for --verbose=2 --no_query accept all directories without querying --user_name default: $USER (%(USER)s) --delete_prev_inst delete project-root first (from prev installation) --drop_db_first drop database first (from prev installation) Dir-options: --base default: $HOME (%(HOME)s) --key_dir default: BASE/keys --project_root default: BASE/projects/PROJECT --url_base REQUIRED; e.g.: http://maggie.ssl.berkeley.edu/ --html_user_url default: URL_BASE/PROJECT/ --html_ops_url default: URL_BASE/PROJECT_ops/ --cgi_url default: URL_BASE/PROJECT_cgi/ Example command line: ./make_project --base $HOME/boinc --url_base http://boink/ yah 'YETI @ Home' \\ upper_case 'UpperCase' Then upload_dir = $HOME/boinc/projects/yah/upload and cgi_url = http://boink/yah_cgi/ By default, directory options will be queried if they do not exist yet. """ %locals() # Project-specific directory structure that you probably don't need to change: # --bin_dir default: PROJECT_ROOT/bin # --cgi_bin_dir default: PROJECT_ROOT/cgi-bin # --html_user_dir default: PROJECT_ROOT/html_user # --html_ops_dir default: PROJECT_ROOT/html_ops # --download_dir default: PROJECT_ROOT/download # --upload_dir default: PROJECT_ROOT/upload # --log_dir default: PROJECT_ROOT/log # --pid_dir default: PROJECT_ROOT/pid def syntax_error(str): raise SystemExit('%s; See "%s --help" for help\n' % (str,sys.argv[0])) def usage(): print HELP raise SystemExit try: opts, args = getopt.getopt(sys.argv[1:], 'hv', [ 'help', 'verbose=', 'no_query', 'user_name=', 'drop_db_first', 'delete_prev_inst', 'base=', 'key_dir=', 'project_root=', 'url_base=', 'html_user_url=', 'html_ops_url=', 'cgi_url=', # 'bin_dir=', # 'cgi_bin_dir=', # 'html_user_dir=', # 'html_ops_dir=', # 'download_dir=', # 'upload_dir=', # 'log_dir=', # 'pid_dir=' ]) except getopt.GetoptError, e: syntax_error(e) options.url_base = None options.no_query = False options.delete_prev_inst = False for o,a in opts: if o == '-h' or o == '--help': usage() elif o == '-v': options.echo_verbose = 2 elif o == '--verbose': options.echo_verbose = int(a) elif o == '--no_query': options.no_query = True elif o == '--user_name': options.user_name = a elif o == '--drop_db_first': options.drop_db_first = True elif o == '--delete_prev_inst': options.delete_prev_inst = True elif o == '--base': options.base = a elif o == '--key_dir': options.key_dir = a elif o == '--project_root': options.project_root = a elif o == '--url_base': options.url_base = a elif o == '--html_user_url': options.html_user_url = a elif o == '--html_ops_url': options.html_ops_url = a elif o == '--cgi_url': options.cgi_url = a # elif o == '--bin_dir': options.bin_dir = a # elif o == '--cgi_bin_dir': options.cgi_bin_dir = a # elif o == '--html_user_dir': options.html_user_dir = a # elif o == '--html_ops_dir': options.html_ops_dir = a # elif o == '--download_dir': options.download_dir = a # elif o == '--upload_dir': options.upload_dir = a # elif o == '--log_dir': options.log_dir = a # elif o == '--pid_dir': options.pid_dir = a else: raise SystemExit('internal error o=%s'%o) if len(args) != 4: syntax_error('Need four arguments') (project_shortname, project_longname, app_exe, app_name) = args if not options.url_base: syntax_error('Need --url_base') if not options.url_base.startswith('http://'): syntax_error('url_base needs to be an URL') options.url_base = os.path.join(options.url_base, '') opt_repls = {'PROJECT':project_shortname, 'PROJECT_ops':project_shortname+'_ops', 'PROJECT_cgi':project_shortname+'_cgi', 'URL_BASE':options.url_base} def replopt(str): for key in opt_repls: str = re.compile('\\b'+key+'\\b').sub(os.path.join(opt_repls[key],'')[:-1], str) return str def add_slash(str, action=True): if action: return os.path.join(str,'') else: return str def defopt(name, v, isdir=True): options.__dict__[name] = opt_repls[name.upper()] = add_slash(replopt(options.__dict__.get(name) or v), isdir) defopt('user_name', USER, isdir=False) defopt('base', HOME) defopt('key_dir', 'BASE/keys') defopt('project_root', 'BASE/projects/PROJECT') defopt('html_user_url', 'URL_BASE/PROJECT') defopt('html_ops_url', 'URL_BASE/PROJECT_ops') defopt('cgi_url', 'URL_BASE/PROJECT_cgi') print "Creating project '%s' (short name '%s'):" %(project_longname, project_shortname) for k in ['base', 'key_dir', 'project_root', 'url_base', 'html_user_url', 'html_ops_url', 'cgi_url' ]: print k.upper().rjust(15), "=", options.__dict__[k] project_root_parent = os.path.realpath(os.path.join(options.project_root,'..')) if not os.path.exists(project_root_parent): os.makedirs(project_root_parent) if os.path.exists(options.project_root): if options.delete_prev_inst: if not options.no_query: if not query_noyes('Delete %s?'%options.project_root): raise SystemExit('Aborted') rmtree(options.project_root) else: raise SystemExit('Project root already exists! Specify --delete_prev_inst --drop_db_first to clobber') if not options.no_query: if not query_yesno("Continue?"): raise SystemExit('Aborted') app = App(app_name) app_version = AppVersion(app, exec_names=[app_exe]) options.install_method = 'copy' init() project = Project(project_shortname, project_longname, project_dir = options.project_root, master_url = options.url_base, cgi_url = options.cgi_url, key_dir = options.key_dir, apps=[app], app_versions=[app_version], ) project.install_project() project.sched_install('feeder') project.sched_install('transitioner') project.sched_install('validate_test') project.sched_install('assimilator') project.sched_install('file_deleter') print '''Done installing files. You need to manually edit your Apache httpd.conf to add these lines: Alias /%(project)s %(proot)s/html_user Alias /%(project)s_ops %(proot)s/html_ops ScriptAlias /%(project)s_cgi %(proot)s/cgi-bin # Note: projects/*/keys/ should NOT be readable! Options Indexes FollowSymlinks MultiViews AllowOverride None Order allow,deny Allow from all Options FollowSymLinks AllowOverride AuthConfig Order allow,deny Allow from all Options ExecCGI Order allow,deny Allow from all Install this in crontab: 0,5,10,15,20,25,30,35,40,45,50,55 * * * * %(proot)s/bin/start --cron (You may need to set PATH and/or PYTHONPATH since cron runs with manilla environment) To start, show status, stop BOINC daemons run: %(proot)s/bin/start %(proot)s/bin/status %(proot)s/bin/stop '''%{'project':project_shortname, 'proot':os.path.join(options.project_root,'')[:-1]} ## TODO: save settings to a file.