boinc/tools/make_project

262 lines
8.8 KiB
Python
Executable File

#!/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!
<Directory "%(proot)s/html_user">
Options Indexes FollowSymlinks MultiViews
AllowOverride None
Order allow,deny
Allow from all
</Directory>
<Directory "%(proot)s/html_ops">
Options FollowSymLinks
AllowOverride AuthConfig
Order allow,deny
Allow from all
</Directory>
<Directory "%(proot)s/cgi-bin">
Options ExecCGI
Order allow,deny
Allow from all
</Directory>
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.