#!/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.