blob: b0ab227b0c74a889d0a6a7999370eec9c5c2d182 [file] [log] [blame]
#!/usr/bin/python
#
# Main Madpack installation driver executable.
import yaml
import os
import sys
import argparse
from argparse import RawTextHelpFormatter
import glob
import shutil
import madpy
import subprocess
from madpy.madpack import configyml
import madpy.madpack.mkmethods
import madpy.madpack.migrations
def __get_config(conf_dir):
return madpy.madpack.configyml.get_config(conf_dir, False)
def __get_mig(conf_dir, mig_dir):
return madpy.madpack.migrations.MadPackMigration(mig_dir, conf_dir)
## the prep() method does two things:
# 1) if needed, create the "scripts" subdirectory to hold the
# migration scripts, and copy Config.yml in there
# 2) generate a single MADPack migration script from the forward/backward
# scripts in each of the MADlib methods specified in Config.yml, named
# with version number from Version.yml
# @param targetdir directory to place migration script files
# @param conf_dir directory where we can find Config.yml
def prep(targetdir, conf_dir):
version = configyml.get_version(madpy.__path__[0])
if not os.path.exists(targetdir):
# initialize scripts directory.
os.mkdir(targetdir)
if not os.path.exists(targetdir+"/Config.yml"):
# copy the Config.yml file in there for subsequent use
shutil.copyfile(configyml.get_configfile(conf_dir),
targetdir+"/Config.yml")
mig = __get_mig(conf_dir,targetdir)
conf = __get_config(conf_dir)
# sanity check: is there an existing script matching current version?
version = configyml.get_version(madpy.__path__[0])
matches = glob.glob(targetdir+"/"+"".join(["[0-9]" for i in range (0,mig.mig_number_len)])+"_"+version+".py")
if len(matches) > 0:
print "migration files matching version " + version + " already exist: " + str(matches)
sys.exit(2)
forwards = []
backwards = []
for m in conf['methods']:
# XXX We assume here that madlib and madpy are installed side-by-side
# in the same directory!
mdir = madpy.__path__[0]+'/../madlib/' + m['name'] + '/src/' + m['port'] + '/'
try:
install = yaml.load(open(mdir+'Install.yml'))
except:
print "method " + m['name'] + " misconfigured: missing Install.yml file in " + mdir
sys.exit(2)
try:
install['fw'] and install['bw']
except:
print "method " + m['name'] + " misconfigured: Install.yml misformatted"
sys.exit(2)
if install['fw'] != None:
forwards.append(mdir+install['fw'])
if install['bw'] != None:
backwards.append(mdir+install['bw'])
fname = mig.generate(targetdir, version, forwards, backwards)
## internal function sanity checks and installs by num or version.
# @param scriptdir directory with migration script files
# @param num MADpack migration number
# @param version MADlib version number
# @param conf_dir directory where we can find Config.yml
def __install(scriptdir, num, version, conf_dir):
if not os.path.isdir(scriptdir):
print "directory " + scriptdir + " does not exist"
exit(2)
m = __get_mig(conf_dir,scriptdir)
try:
m.setup()
except madpy.madpack.migrations.MadPackMigrationError:
print "no schema named 'madlib' in database"
exit(2)
m.migrate(mignumber=num, migversion=version)
## roll scripts fw/bw by MADpack migration number
# @param scriptdir where we can find migration scripts
# @param n migration number to roll to
# @param conf_dir directory where we can find Config.yml
def install_number(scriptdir, n, conf_dir):
__install(scriptdir,n,None,conf_dir)
## roll scripts fw/bw by MADlib version number
# @param scriptdir where we can find migration scripts
# @param v MADlib version to roll to
# @param conf_dir directory where we can find Config.yml
def install_version(scriptdir, v, conf_dir):
__install(scriptdir,None,v,conf_dir)
## invoke migration sanity check
# @param scriptdir where we can find migration scripts
# @param conf_dir directory where we can find Config.yml
def __sanity(scriptdir, conf_dir):
m = __get_mig(conf_dir,scriptdir)
try:
m.sanity()
except madpy.madpack.migrations.MadPackMigrationError:
print "sanity check failure"
exit(2)
## uninstall is the same as install version <0
# @param scriptdir where we can find migration scripts
# @param conf_dir directory where we can find Config.yml
def uninstall(scriptdir, conf_dir):
install_number(scriptdir, -1, conf_dir)
# parse args and invoke appropriate code.
# try running "-h" for usage info.
def main(argv):
parser = argparse.ArgumentParser(description='Configure madlib package manager',
argument_default=False,
formatter_class=RawTextHelpFormatter,
epilog="""Command quickref:
install: 'make install' methods, run sql scripts to load into DB
uninstall: run sql scripts to uninstall from DB, 'make uninstall' methods
update: migrate forward to latest script (same as '-e install')
build: 'make install' methods, but do run sql scripts to load into DB
clean: 'make clean' methods
version: print current version in DB
sanity: check if scriptdir files match migrationhistory in db""")
parser.add_argument('command',
choices=['install','uninstall','update','build',
'clean','version', 'sanity'],
help="choice of commands")
parser.add_argument('-i', '--install_version', nargs=1, dest='install_version',
metavar='VERSION',
help="migrate to version VERSION")
parser.add_argument('-p', '--prep-only', dest='preponly',
action="store_true",
help="prepare scripts but do not install")
parser.add_argument('-n', '--nomake', dest='nomake',
action="store_true",
help="do not run 'make' on methods")
parser.add_argument('-e', '--existing', dest='installonly',
action="store_true",
help="use existing scripts, do not generate new scripts")
parser.add_argument('-c', '--configdir', nargs=1, dest='configdir',
default=None,
help="""directory holding Config.yml
(default SCRIPTDIR if already initialized, else
"""
+ madpy.__path__[0]+")")
parser.add_argument('-s', '--scriptdir', nargs=1, dest='scriptdir',
default=madpy.__path__[0] + "/config/scripts",
help="""directory holding scripts
(default """
+ madpy.__path__[0] + "/config/scripts"
+")")
parser.add_argument('-v', '--verbose', dest='verbose',
action="store_true",
help="print more details during installation")
args = parser.parse_args()
# if config file left unspecified, first check scriptdir.
# if nothing there, take the installed version: madpy/Config.yml
if not args.configdir:
if os.path.exists(args.scriptdir+"/Config.yml"):
args.configdir = [args.scriptdir]
else:
args.configdir = madpy.__path__
conf = configyml.get_config(args.configdir[0], False)
# command 'update' a synonym for "-e install"
if args.command == 'update':
args.command = 'install'
args.installonly = True
if args.install_version and args.command != 'install':
print "-i or --install_version flag only compatible with 'install' command"
exit(2)
if args.install_version:
instv = args.install_version[0]
else:
instv = None
if args.command == 'version':
v = __get_mig(args.configdir[0],mig_dir = args.scriptdir).current_version()
if v == -1:
print "no version found in database"
else:
print v
elif args.command == 'uninstall':
print "Uninstalling MADlib : " # + conf['connect_args'][1] + ", schema=" + conf['target_schema']
if not args.nomake:
madpy.madpack.mkmethods.make_methods('uninstall', conf, args.verbose)
if not os.path.exists(args.scriptdir):
print "scripts directory missing"
sys.exit(2)
uninstall(args.scriptdir, args.configdir[0])
print "MADlib uninstalled OK."
elif args.command == 'install':
print "\n*** Installing MADlib: " + conf['connect_args'][1] + ", schema=" + conf['target_schema'] + ' ***\n'
# run make clean_data_built and make install on methods
# unless preponly or nomake
if not args.preponly and not args.nomake:
madpy.madpack.mkmethods.make_methods('clean_data_built', conf, args.verbose)
madpy.madpack.mkmethods.make_methods('install', conf, args.verbose)
# prep script unless version given or installonly
if not args.installonly and not args.install_version:
prep(args.scriptdir, args.configdir[0])
# run install script unless preponly or makeonly
if not args.preponly:
# run a specific install extension
if conf['post_hook'] != 'undefined':
post_hook = args.configdir[0] + '/ext/' + conf['post_hook']
if not os.path.isfile( post_hook):
print "post install hook script missing (" + post_hook + ")"
sys.exit(2)
print "Running post installation script: " + conf['post_hook']
try:
subprocess.call(['python ' + post_hook], shell=True)
except madpy.madpack.migrations.MadPackMigrationError:
print "error while running post installation script: " + conf['post_hook']
sys.exit(2)
# run db migration
install_version(args.scriptdir, instv, args.configdir[0])
print "\n*** MADlib installation finished OK ***\n"
elif args.command == 'build':
if not args.nomake:
madpy.madpack.mkmethods.make_methods('install', conf, args.verbose)
elif args.command == 'clean' and not args.nomake:
madpy.madpack.mkmethods.make_methods('clean', conf, args.verbose)
elif args.command == 'sanity':
__sanity(args.scriptdir, args.configdir[0])
if __name__ == "__main__":
main(sys.argv[1:])