| #! /usr/bin/env python |
| # -*- coding: utf-8 -*- |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| |
| |
| # the following variables are used by the target "waf dist" |
| # if you change APPNAME here, you need to change 'Name' also |
| # in cloud.spec, add a %changelog entry there, and add an |
| # entry in debian/changelog. SHORTVERSION is used in package |
| # naming for deb/rpm, VERSION is used for tarball and bin |
| VERSION = '4.0.2' |
| SHORTVERSION = '4.0.2' |
| APPNAME = 'cloud' |
| |
| import shutil,os |
| import email,time |
| import optparse |
| import Utils,Node,Options,Logs,Scripting,Environment,Build,Configure |
| from subprocess import Popen as _Popen,PIPE |
| import os |
| import sys |
| from os import unlink as _unlink, makedirs as _makedirs, getcwd as _getcwd, chdir as _chdir |
| from os.path import abspath as _abspath, basename as _basename, dirname as _dirname, exists as _exists, isdir as _isdir, split as _split, join as _join, sep, pathsep, pardir, curdir |
| from glob import glob as _glob |
| import zipfile,tarfile |
| try: |
| from os import chmod as _chmod,chown as _chown |
| import pwd,stat,grp |
| except ImportError: |
| _chmod,_chown,pwd,stat,grp = (None,None,None,None,None) |
| import xml.dom.minidom |
| import re |
| |
| # these variables are mandatory ('/' are converted automatically) |
| srcdir = '.' |
| blddir = 'artifacts' |
| |
| Configure.autoconfig = True |
| |
| # things not to include in the source tarball |
| # exclude by file name or by _glob (wildcard matching) |
| for _globber in [ |
| ["dist", # does not belong in the source tarball |
| "system", # for windows |
| "override", # not needed |
| "eclipse", # only there to please eclipse |
| "repomanagement", # internal management stuff |
| "client-api", # obsolete |
| "cloud-bridge", # not compiled and packaged yet |
| "target", # eclipse workdir |
| "apache-log4j-1.2.16", |
| "apache-log4j-extras-1.1", |
| "cglib", |
| "gson", |
| "ehcache", |
| "vhd-tools", |
| "xmlrpc", |
| "PreviousDatabaseSchema", |
| "mockito", |
| "gcc", |
| "junit" ], |
| _glob("./*.disabledblahxml"), |
| ]: |
| for f in _globber: Scripting.excludes.append(_basename(f)) # _basename() only the filename |
| |
| # things never to consider when building or installing |
| for pattern in ["**/.project","**/.classpath","**/.pydevproject"]: Node.exclude_regs += "\n%s"%pattern |
| |
| # Support functions |
| |
| def distclean(ctx): |
| """Clear the build artifacts""" |
| for root, folder, files in os.walk(blddir): |
| for f in files: |
| path = os.path.join(root, f) |
| print "Removing artifact %s"%path |
| os.remove(path) |
| |
| def inspectobj(x): |
| """Look inside an object""" |
| for m in dir(x): print m,": ",getattr(x,m) |
| Utils.inspectobj = inspectobj |
| |
| def _trm(x,y): |
| if len(x) > y: return x[:y] + "..." |
| return x |
| |
| def getrpmdeps(): |
| def rpmdeps(fileset): |
| for f in fileset: |
| lines = file(f).readlines() |
| lines = [ x[len("BuildRequires: "):] for x in lines if x.startswith("BuildRequires") ] |
| for l in lines: |
| deps = [ x.strip() for x in l.split(",") ] |
| for d in deps: |
| if "%s-"%APPNAME in d: continue |
| yield d |
| yield "rpm-build" |
| |
| deps = set(rpmdeps(_glob("./*.spec"))) |
| deps.add("ant") |
| return deps |
| |
| # CENTOS does not have this -- we have to put this here |
| try: |
| from subprocess import check_call as _check_call |
| from subprocess import CalledProcessError |
| except ImportError: |
| def _check_call(*popenargs, **kwargs): |
| import subprocess |
| retcode = subprocess.call(*popenargs, **kwargs) |
| cmd = kwargs.get("args") |
| if cmd is None: cmd = popenargs[0] |
| if retcode: raise CalledProcessError(retcode, cmd) |
| return retcode |
| |
| class CalledProcessError(Exception): |
| def __init__(self, returncode, cmd): |
| self.returncode = returncode ; self.cmd = cmd |
| def __str__(self): return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode) |
| def throws_command_errors(f): |
| def g(*args,**kwargs): |
| try: return f(*args,**kwargs) |
| except CalledProcessError,e: |
| raise Utils.WafError("system command %s failed with error value %s"%(e.cmd[0],e.returncode)) |
| except IOError,e: |
| if e.errno is 32: |
| raise Utils.WafError("system command %s terminated abruptly, closing communications with parent's pipe"%e.cmd[0]) |
| raise |
| return g |
| |
| def c(cmdlist,cwd=None): |
| # Run a command with _check_call, pretty-printing the cmd list |
| Utils.pprint("BLUE"," ".join(cmdlist)) |
| return _check_call(cmdlist,cwd=cwd) |
| |
| def svninfo(*args): |
| try: p = _Popen(['svn','info']+list(args),stdin=PIPE,stdout=PIPE,stderr=PIPE) |
| except OSError,e: |
| if e.errno == 2: return '' # svn command is not installed |
| raise |
| stdout,stderr = p.communicate('') |
| retcode = p.wait() |
| # If the guess fails, just return nothing. |
| if retcode: return |
| # SVN available |
| rev = [ x for x in stdout.splitlines() if x.startswith('Revision') ] |
| if not rev: rev = '' |
| else: rev = "SVN " + rev[0].strip() |
| url = [ x for x in stdout.splitlines() if x.startswith('URL') ] |
| if not url: url = '' |
| else: url = "SVN " + url[0].strip() |
| return rev + "\n" + url |
| |
| def gitinfo(dir=None): |
| if dir and not _isdir(dir): return '' |
| try: p = _Popen(['git','remote','show','-n','origin'],stdin=PIPE,stdout=PIPE,stderr=PIPE,cwd=dir) |
| except OSError,e: |
| if e.errno == 2: return '' # svn command is not installed |
| raise |
| stdout,stderr = p.communicate('') |
| retcode = p.wait() |
| # If the guess fails, just return nothing. |
| if retcode: return |
| stdout = [ s.strip() for s in stdout.splitlines() ] |
| try: url = [ s[11:] for s in stdout if s.startswith("Fetch URL") ][0] |
| except IndexError: url = [ s[5:] for s in stdout if s.startswith("URL") ][0] |
| assert url |
| |
| p = _Popen(['git','log','-1'],stdin=PIPE,stdout=PIPE,stderr=PIPE,cwd=dir) |
| stdout,stderr = p.communicate('') |
| retcode = p.wait() |
| if retcode: return |
| # If the guess fails, just return nothing. |
| stdout = [ s.strip() for s in stdout.splitlines() ] |
| commitid = [ s.split()[1] for s in stdout if s.startswith("commit") ][0] |
| assert commitid |
| |
| return "Git Revision: %s"%commitid + "\n" + "Git URL: %s"%url |
| |
| def allgitinfo(): |
| t = gitinfo() |
| if not t: return t |
| |
| u = gitinfo(_join(pardir,"cloudstack-proprietary")) |
| if not u: return t |
| |
| return t + "\n\ncloustack-proprietary:\n" + u |
| |
| def _getbuildnumber(): # FIXME implement for git |
| n = Options.options.BUILDNUMBER |
| if n: |
| # luntbuild prepends "build-" to the build number. we work around this here: |
| if n.startswith("build-"): n = n[6:] |
| # SVN identifiers prepend "$Revision:" to the build number. we work around this here: |
| if n.startswith("$Revision:"): n = n[11:-2].strip() |
| return n |
| else: |
| # Try to guess the SVN revision number by calling SVN info. |
| stdout = svninfo() |
| if not stdout: return '' |
| # Filter lines. |
| rev = [ x for x in stdout.splitlines() if x.startswith('SVN Revision') ] |
| if not rev: return '' |
| # Parse revision number. |
| rev = rev[0][14:].strip() |
| return rev |
| Utils.getbuildnumber = _getbuildnumber |
| |
| def mkdir_p(directory): |
| if not _isdir(directory): |
| Utils.pprint("GREEN","Creating directory %s and necessary parents"%directory) |
| _makedirs(directory) |
| |
| def relpath(path, start="."): |
| if not path: raise ValueError("no path specified") |
| |
| start_list = os.path.abspath(start).split(sep) |
| path_list = os.path.abspath(path).split(sep) |
| |
| # Work out how much of the filepath is shared by start and path. |
| i = len(os.path.commonprefix([start_list, path_list])) |
| |
| rel_list = [pardir] * (len(start_list)-i) + path_list[i:] |
| if not rel_list: |
| return curdir |
| return os.path.join(*rel_list) |
| Utils.relpath = relpath |
| |
| def dev_override(pathname): |
| p,e = _split(pathname) |
| overridden = _join(p,"override",e) |
| if _exists(overridden): return overridden |
| return pathname |
| |
| def discover_ant_targets_and_properties(files): |
| doms = [ xml.dom.minidom.parseString(file(f).read(-1)) for f in files if f.endswith(".xml") ] |
| targets = dict( [ (target.getAttribute("name"),target) for dom in doms for target in dom.getElementsByTagName("target") if target.getElementsByTagName("compile-java") ] ) |
| propsinxml = [ (prop.getAttribute("name"),prop.getAttribute("value") or prop.getAttribute("location")) for dom in doms for prop in dom.getElementsByTagName("property") ] |
| propsinpropfiles = [ l.strip().split("=",1) for f in files if f.endswith(".properties") for l in file(f).readlines() if "=" in l and not l.startswith("#") ] |
| props = dict( propsinxml + propsinpropfiles ) |
| props["base.dir"] = '.' |
| props["p.base.dir"] = '.' |
| |
| result = [] |
| for name,target in targets.items(): |
| sourcedir = target.getElementsByTagName("compile-java")[0].getAttribute("top.dir") + "/src" |
| classdir = "${classes.dir}/" + target.getElementsByTagName("compile-java")[0].getAttribute("jar.name") |
| jarpath = "${jar.dir}/" + target.getElementsByTagName("compile-java")[0].getAttribute("jar.name") |
| def lookup(matchobject): return props[matchobject.group(1)] |
| while "$" in sourcedir: sourcedir = re.sub("\${(.+?)}",lookup,sourcedir) |
| while "$" in classdir: classdir = re.sub("\${(.+?)}",lookup,classdir) |
| while "$" in jarpath: jarpath= re.sub("\${(.+?)}",lookup,jarpath) |
| dependencies = [ dep.strip() for dep in target.getAttribute("depends").split(",") if dep.strip() in targets ] |
| result.append([str(name),str(relpath(sourcedir)),str(relpath(classdir)),str(relpath(jarpath)),[str(s) for s in dependencies]]) |
| # hardcoded here because the discovery process does not get it |
| result.append( ["build-console-viewer","console-viewer/src", "target/classes/console-viewer", "target/jar/VMOpsConsoleApplet.jar", ["compile-utils","compile-console-common"] ] ) |
| return result,props |
| Utils.discover_ant_targets_and_properties = discover_ant_targets_and_properties |
| |
| # this snippet of code runs a list of ant targets |
| # then it expects a certain set of JAR files to be output in the artifacts/default/ant/jar directory |
| # this set of jar files is defined here in the variable jartgts, and must match the definitions at the bottom of |
| # build/package.xml and build/premium/package-premium.xml |
| # this is NOT a task for a task generator -- it is a plain function. |
| # If you want to use it as a task function in a task generator, use a lambda x: runant("targetname") |
| def runant(tsk): |
| |
| environ = dict(os.environ) |
| environ["CATALINA_HOME"] = tsk.env.TOMCATHOME |
| if tsk.generator.env.DISTRO == "Windows": |
| stanzas = [ |
| "ant", |
| "-Dthirdparty.classpath=\"%s\""%(tsk.env.CLASSPATH.replace(os.pathsep,",")), |
| ] |
| else: |
| stanzas = [ |
| "ant", |
| "-Dthirdparty.classpath=%s"%(tsk.env.CLASSPATH.replace(os.pathsep,",")), |
| ] |
| stanzas += tsk.generator.antargs |
| ret = Utils.exec_command(" ".join(stanzas),cwd=tsk.generator.bld.srcnode.abspath(),env=environ,log=True) |
| if ret != 0: raise Utils.WafError("Ant command %s failed with error value %s"%(stanzas,ret)) |
| return ret |
| Utils.runant = runant |
| |
| @throws_command_errors |
| def run_java(classname,classpath,options=None,arguments=None): |
| if not options: options = [] |
| if not arguments: arguments = [] |
| if type(classpath) in [list,tuple]: classpath = pathsep.join(classpath) |
| |
| Utils.pprint("BLUE","Run-time CLASSPATH:") |
| for v in classpath.split(pathsep): Utils.pprint("BLUE"," %s"%v) |
| |
| cmd = ["java","-classpath",classpath] + options + [classname] + arguments |
| Utils.pprint("BLUE"," ".join([ _trm(x,32) for x in cmd ])) |
| _check_call(cmd) |
| |
| # this will enforce the after= ordering constraints in the javac task generators |
| from TaskGen import after, feature |
| @feature('*') |
| @after('apply_core', 'apply_java', 'apply_subst') |
| def process_after(self): |
| lst = self.to_list(getattr(self, 'after', [])) |
| for x in lst: |
| obj = self.bld.name_to_obj(x,self.bld.env) |
| if not obj: break |
| obj.post() |
| for a in obj.tasks: |
| for b in self.tasks: |
| b.set_run_after(a) |
| |
| Build.BuildContext.process_after = staticmethod(process_after) |
| |
| def _getbuildcontext(): |
| ctx = Build.BuildContext() |
| ctx.load_dirs(_abspath(srcdir),_abspath(blddir)) |
| ctx.load_envs() |
| return ctx |
| |
| def _install_files_filtered(self,destdir,listoffiles,**kwargs): |
| if "cwd" in kwargs: cwd = kwargs["cwd"] |
| else: cwd = self.path |
| if isinstance(listoffiles,str) and '**' in listoffiles: |
| listoffiles = cwd.ant_glob(listoffiles,flat=True) |
| elif isinstance(listoffiles,str) and '*' in listoffiles: |
| listoffiles = [ n for x in listoffiles.split() for n in _glob(cwd.abspath() + os.sep + x.replace("/",os.sep)) ] |
| listoffiles = Utils.to_list(listoffiles)[:] |
| listoffiles = [ x for x in listoffiles if not ( x.endswith("~") or x == "override" or "%soverride"%os.sep in x ) ] |
| for n,f in enumerate(listoffiles): |
| f = os.path.abspath(f) |
| f = dev_override(f) |
| if _isdir(f): continue |
| if f.endswith(".in"): |
| source = f ; target = f[:-3] |
| tgen = self(features='subst', source=source[len(self.path.abspath())+1:], target=target[len(self.path.abspath())+1:], name="filtered_%s"%source) |
| tgen.dict = self.env.get_merged_dict() |
| else: |
| source = f ; target = f |
| listoffiles[n] = target[len(cwd.abspath())+1:] |
| if "postpone" not in kwargs: kwargs["postpone"] = True |
| ret = self.install_files(destdir,listoffiles,**kwargs) |
| return ret |
| Build.BuildContext.install_files_filtered = _install_files_filtered |
| |
| def _substitute(self,listoffiles,install_to=None,cwd=None,dict=None,name=None,**kwargs): |
| if cwd is None: cwd = self.path |
| tgenkwargs = {} |
| if name is not None: tgenkwargs["name"] = name |
| if isinstance(listoffiles,str) and '**' in listoffiles: |
| listoffiles = cwd.ant_glob(listoffiles,flat=True) |
| elif isinstance(listoffiles,str) and '*' in listoffiles: |
| listoffiles = [ n for x in listoffiles.split() for n in _glob(cwd.abspath() + os.sep + x.replace("/",os.sep)) ] |
| for src in Utils.to_list(listoffiles): |
| tgt = src + ".subst" |
| inst = src # Utils.relpath(src,relative_to) <- disabled |
| |
| # Use cwd path when creating task and shift back later |
| tmp = self.path |
| self.path = cwd |
| tgen = self(features='subst', source=src, target=tgt, **tgenkwargs) |
| self.path = tmp |
| |
| if dict is not None: tgen.dict = dict |
| else: tgen.dict = self.env.get_merged_dict() |
| self.path.find_or_declare(tgt) |
| if install_to is not None: self.install_as("%s/%s"%(install_to,inst), tgt, cwd=cwd, **kwargs) |
| Build.BuildContext.substitute = _substitute |
| |
| def set_options(opt): |
| """Register command line options""" |
| opt.tool_options('gnu_dirs') |
| opt.tool_options('python') |
| opt.tool_options('tar',tooldir='tools/waf') |
| opt.tool_options('mkisofs',tooldir='tools/waf') |
| if Options.platform not in ['darwin','win32']: opt.tool_options('usermgmt',tooldir='tools/waf') |
| if Options.platform not in ['darwin','win32']: opt.tool_options('javadir',tooldir='tools/waf') |
| opt.tool_options('tomcat',tooldir='tools/waf') |
| if Options.platform not in ['darwin',"win32"]: opt.tool_options('compiler_cc') |
| |
| inst_dir = opt.get_option_group('--srcdir') |
| inst_dir.add_option('--with-db-host', |
| help = 'Database host to use for waf deploydb [Default: 127.0.0.1]', |
| default = '127.0.0.1', |
| dest = 'DBHOST') |
| inst_dir.add_option('--with-db-user', |
| help = 'Database user to use for waf deploydb [Default: root]', |
| default = 'root', |
| dest = 'DBUSER') |
| inst_dir.add_option('--with-db-pw', |
| help = 'Database password to use for waf deploydb [Default: ""]', |
| default = '', |
| dest = 'DBPW') |
| inst_dir.add_option('--tomcat-user', |
| help = 'UNIX user that the management server initscript will switch to [Default: <autodetected>]', |
| default = '', |
| dest = 'MSUSER') |
| inst_dir.add_option('--no-dep-check', |
| action='store_true', |
| help = 'Skip dependency check and assume JARs already exist', |
| default = False, |
| dest = 'NODEPCHECK') |
| inst_dir.add_option('--fast', |
| action='store_true', |
| help = 'does ---no-dep-check', |
| default = False, |
| dest = 'NODEPCHECK') |
| inst_dir = opt.get_option_group('--force') |
| inst_dir.add_option('--preserve-config', |
| action='store_true', |
| help = 'do not install configuration files', |
| default = False, |
| dest = 'PRESERVECONFIG') |
| |
| debugopts = optparse.OptionGroup(opt.parser,'run/debug options') |
| opt.add_option_group(debugopts) |
| debugopts.add_option('--debug-port', |
| help = 'Port on which the debugger will listen when running waf debug [Default: 8787]', |
| default = '8787', |
| dest = 'DEBUGPORT') |
| debugopts.add_option('--debug-suspend', |
| action='store_true', |
| help = 'Suspend the process upon startup so that a debugger can attach and set breakpoints', |
| default = False, |
| dest = 'DEBUGSUSPEND') |
| debugopts.add_option('--run-verbose', |
| action='store_true', |
| help = 'Run Tomcat in verbose mode (java option -verbose)', |
| default = False, |
| dest = 'RUNVERBOSE') |
| |
| rpmopts = optparse.OptionGroup(opt.parser,'RPM/DEB build options') |
| opt.add_option_group(rpmopts) |
| rpmopts.add_option('--build-number', |
| help = 'Build number [Default: SVN revision number for builds from checkouts, or empty for builds from source releases]', |
| default = '', |
| dest = 'BUILDNUMBER') |
| rpmopts.add_option('--package-version', |
| help = 'package version', |
| default = '', |
| dest = 'VERNUM') |
| rpmopts.add_option('--release-version', |
| help = 'release version', |
| default = '', |
| dest = 'RELEASENUM') |
| rpmopts.add_option('--prerelease', |
| help = 'Branch name to append to the release number (if specified, alter release number to be a prerelease); this option requires --build-number=X [Default: nothing]', |
| default = '', |
| dest = 'PRERELEASE') |
| rpmopts.add_option('--skip-dist', |
| action='store_true', |
| help = 'Normally, dist() is called during package build. This makes the package build assume that a distribution tarball has already been made, and use that. This option is also valid during distcheck and dist.', |
| default = False, |
| dest = 'DONTDIST') |
| |
| distopts = optparse.OptionGroup(opt.parser,'dist options') |
| opt.add_option_group(distopts) |
| distopts.add_option('--oss', |
| help = 'Only include open source components', |
| action = 'store_true', |
| default = False, |
| dest = 'OSS') |
| |
| def showconfig(conf): |
| """prints out the current configure environment configuration""" |
| conf = _getbuildcontext() |
| |
| Utils.pprint("WHITE","Build environment:") |
| for key,val in sorted(conf.env.get_merged_dict().items()): |
| if "CLASSPATH" in key: |
| Utils.pprint("BLUE"," %s:"%key) |
| for v in val.split(pathsep): |
| Utils.pprint("BLUE"," %s"%v) |
| continue |
| Utils.pprint("BLUE"," %s: %s"%(key,val)) |
| |
| def _getconfig(self): |
| lines = [] |
| for key,val in sorted(self.env.get_merged_dict().items()): |
| if "CLASSPATH" in key: |
| lines.append(" %s:"%key) |
| for v in val.split(pathsep): |
| lines.append(" %s"%v) |
| continue |
| lines.append(" %s: %s"%(key,val)) |
| return "\n".join(lines) |
| Build.BuildContext.getconfig = _getconfig |
| |
| def list_targets(ctx): |
| """return the list of buildable and installable targets""" |
| |
| bld = Build.BuildContext() |
| proj = Environment.Environment(Options.lockfile) |
| bld.load_dirs(proj['srcdir'], proj['blddir']) |
| bld.load_envs() |
| |
| bld.add_subdirs([os.path.split(Utils.g_module.root_path)[0]]) |
| |
| names = set([]) |
| for x in bld.all_task_gen: |
| try: |
| names.add(x.name or x.target) |
| except AttributeError: |
| pass |
| |
| lst = list(names) |
| lst.sort() |
| for name in lst: |
| print(name) |
| |
| def decorate_dist(f): |
| def dist(appname='',version=''): |
| '''makes a tarball for redistributing the sources -- if --skip-dist is specified, does nothing''' |
| if Options.options.DONTDIST: |
| if not appname: appname=Utils.g_module.APPNAME |
| if not version: version=Utils.g_module.VERSION |
| tmp_folder=appname+'-'+version |
| if Scripting.g_gz in['gz','bz2']: |
| arch_name=tmp_folder+'.tar.'+Scripting.g_gz |
| else: |
| arch_name=tmp_folder+'.'+'zip' |
| Logs.info('New archive skipped: %s'%(arch_name)) |
| return arch_name |
| else: |
| return f(appname,version) |
| return dist |
| Scripting.dist = decorate_dist(Scripting.dist) |
| |
| def dist_hook(): |
| # Clean the GARBAGE that clogs our repo to the tune of 300 MB |
| # so downloaders won't have to cry every time they download a "source" |
| # package over 90 MB in size |
| [ shutil.rmtree(f) for f in _glob(_join("*","bin")) if _isdir(f) ] |
| [ shutil.rmtree(f) for f in _glob(_join("cloudstack-proprietary","thirdparty","*")) if _isdir(f) ] |
| [ shutil.rmtree(f) for f in [ _join("cloudstack-proprietary","tools") ] if _isdir(f) ] |
| |
| if Options.options.OSS: |
| [ shutil.rmtree(f) for f in "cloudstack-proprietary".split() if _exists(f) ] |
| |
| stdout = svninfo("..") or allgitinfo() |
| if stdout: |
| f = file("sccs-info","w") |
| f.write(stdout) |
| f.flush() |
| f.close() |
| else: |
| # No SVN available |
| if _exists("sccs-info"): |
| # If the file already existed, we preserve it |
| return |
| else: |
| f = file("sccs-info","w") |
| f.write("No revision control information could be detected when the source distribution was built.") |
| f.flush() |
| f.close() |
| |
| def bindist(ctx): |
| """creates a binary distribution that, when unzipped in the root directory of a machine, deploys the entire stack""" |
| ctx = _getbuildcontext() |
| |
| if Options.options.VERNUM: |
| VERSION = Options.options.VERNUM |
| |
| tarball = "%s-bindist-%s.tar.%s"%(APPNAME,VERSION,Scripting.g_gz) |
| zf = _join(ctx.bldnode.abspath(),tarball) |
| Options.options.destdir = _join(ctx.bldnode.abspath(),"bindist-destdir") |
| Scripting.install(ctx) |
| |
| if _exists(zf): _unlink(zf) |
| Utils.pprint("GREEN","Creating %s"%(zf)) |
| z = tarfile.open(zf,"w:bz2") |
| cwd = _getcwd() |
| _chdir(Options.options.destdir) |
| z.add(".") |
| z.close() |
| _chdir(cwd) |
| |
| @throws_command_errors |
| def deb(context): |
| raise Utils.WafError("Debian packages are no longer build with waf. Use dpkg-buildpackage instead.") |
| |
| @throws_command_errors |
| def rpm(context): |
| buildnumber = Utils.getbuildnumber() |
| if buildnumber: buildnumber = ["--define","_build_number %s"%buildnumber] |
| else: buildnumber = [] |
| |
| if Options.options.PRERELEASE: |
| if not buildnumber: |
| raise Utils.WafError("Please specify a build number to go along with --prerelease") |
| prerelease = ["--define","_prerelease %s"%Options.options.PRERELEASE] |
| else: prerelease = [] |
| |
| if Options.options.RELEASENUM: |
| release = Options.options.RELEASENUM |
| else: release = "1" |
| |
| releasever = ["--define", "_rel %s" % release] |
| |
| if Options.options.VERNUM: |
| ver = Options.options.VERNUM |
| else: ver = SHORTVERSION |
| |
| packagever = ["--define", "_ver %s" % ver] |
| |
| # FIXME wrap the source tarball in POSIX locking! |
| if not Options.options.blddir: outputdir = _join(context.curdir,blddir,"rpmbuild") |
| else: outputdir = _join(_abspath(Options.options.blddir),"rpmbuild") |
| Utils.pprint("GREEN","Building RPMs") |
| |
| tarball = Scripting.dist('', ver) |
| sourcedir = _join(outputdir,"SOURCES") |
| |
| if _exists(sourcedir): shutil.rmtree(sourcedir) |
| for a in ["RPMS/noarch","SRPMS","BUILD","SPECS","SOURCES"]: mkdir_p(_join(outputdir,a)) |
| shutil.move(tarball,_join(sourcedir,tarball)) |
| |
| specfile = "%s.spec"%APPNAME |
| checkdeps = lambda: c(["rpmbuild","--define","_topdir %s"%outputdir,"--nobuild",specfile]+packagever+releasever) |
| dorpm = lambda: c(["rpmbuild","--define","_topdir %s"%outputdir,"-bb",specfile]+buildnumber+prerelease+packagever+releasever) |
| try: checkdeps() |
| except (CalledProcessError,OSError),e: |
| Utils.pprint("YELLOW","Dependencies might be missing. Trying to auto-install them...") |
| installrpmdeps(context) |
| dorpm() |
| |
| def uninstallrpms(context): |
| """uninstalls any Cloud Stack RPMs on this system""" |
| Utils.pprint("GREEN","Uninstalling any installed RPMs") |
| cmd = "rpm -qa | grep %s- | xargs -r sudo rpm -e"%APPNAME |
| Utils.pprint("BLUE",cmd) |
| system(cmd) |
| |
| def viewrpmdeps(context): |
| """shows all the necessary dependencies to build the RPM packages of the stack""" |
| for dep in getrpmdeps(): print dep |
| |
| @throws_command_errors |
| def installrpmdeps(context): |
| """installs all the necessary dependencies to build the RPM packages of the stack""" |
| runnable = ["sudo","yum","install","-y"]+list(getrpmdeps()) |
| Utils.pprint("GREEN","Installing RPM build dependencies") |
| Utils.pprint("BLUE"," ".join(runnable)) |
| _check_call(runnable) |
| |
| @throws_command_errors |
| def deploydb(ctx,virttech=None): |
| if not virttech: raise Utils.WafError('use deploydb_xenserver, deploydb_vmware or deploydb_kvm rather than deploydb') |
| |
| ctx = _getbuildcontext() |
| setupdatabases = _join(ctx.env.BINDIR,"cloud-setup-databases") |
| serversetup = _join(ctx.env.SETUPDATADIR,"server-setup.xml") |
| |
| if not _exists(setupdatabases): # Needs install! |
| Scripting.install(ctx) |
| |
| cmd = [ |
| ctx.env.PYTHON, |
| setupdatabases, |
| "cloud@%s"%ctx.env.DBHOST, |
| virttech, |
| "--auto=%s"%serversetup, |
| "--deploy-as=%s:%s"%(ctx.env.DBUSER,ctx.env.DBPW), |
| ] |
| |
| Utils.pprint("BLUE"," ".join(cmd)) |
| retcode = Utils.exec_command(cmd,shell=False,stdout=None,stderr=None,log=True) |
| if retcode: raise CalledProcessError(retcode,cmd) |
| |
| def deploydb_xenserver(ctx): |
| """re-deploys the database using the MySQL connection information and the XenServer templates.sql""" |
| return deploydb(ctx,"xenserver") |
| def deploydb_kvm(ctx): |
| """re-deploys the database using the MySQL connection information and the KVM templates.sql""" |
| return deploydb(ctx,"kvm") |
| def deploydb_vmware(ctx): |
| """re-deploys the database using the MySQL connection information and the KVM templates.sql""" |
| return deploydb(ctx,"vmware") |
| |
| def run(args): |
| """runs the management server""" |
| conf = _getbuildcontext() |
| |
| runverbose = [] |
| if Options.options.RUNVERBOSE: runverbose = ['-verbose'] |
| if args == "debug": |
| suspend = "n" |
| if Options.options.DEBUGSUSPEND: suspend = "y" |
| debugargs = [ |
| "-Xdebug","-Xrunjdwp:transport=dt_socket,address=%s,server=y,suspend=%s"%( |
| Options.options.DEBUGPORT,suspend), |
| "-ea"] |
| Utils.pprint("GREEN","Starting Tomcat in debug mode") |
| else: |
| Utils.pprint("GREEN","Starting Tomcat in foreground mode") |
| debugargs = [] |
| |
| options = runverbose + debugargs + [ |
| "-Dcatalina.base=" + conf.env.MSENVIRON, |
| "-Dcatalina.home=" + conf.env.MSENVIRON, |
| "-Djava.io.tmpdir="+_join(conf.env.MSENVIRON,"temp"), ] |
| |
| if not _exists(_join(conf.env.BINDIR,"cloud-setup-databases")): Scripting.install(conf) |
| |
| cp = [conf.env.MSCONF] |
| cp += _glob(_join(conf.env.MSENVIRON,'bin',"*.jar")) |
| cp += _glob(_join(conf.env.MSENVIRON,'lib',"*.jar")) |
| cp += _glob( _join ( conf.env.PREMIUMJAVADIR , "*" ) ) |
| cp += [conf.env.SYSTEMCLASSPATH] |
| cp += [conf.env.DEPSCLASSPATH] |
| cp += [conf.env.MSCLASSPATH] |
| |
| # FIXME Make selectable at runtime |
| #plugins = _glob( _join(conf.env.PLUGINJAVADIR,"*") ) |
| #if plugins: cp = plugins + cp |
| #vendorconfs = _glob( _join(conf.env.MSCONF,"vendor","*") ) |
| #if vendorconfs: cp = plugins + cp |
| |
| run_java("org.apache.catalina.startup.Bootstrap",cp,options,["start"]) |
| |
| def debug(ctx): |
| """runs the management server in debug mode""" |
| run("debug") |
| |
| @throws_command_errors |
| def run_agent(args): |
| """runs the agent""" # FIXME: make this use the run/debug options |
| conf = _getbuildcontext() |
| if not _exists(_join(conf.env.LIBEXECDIR,"agent-runner")): Scripting.install(conf) |
| _check_call("sudo",[_join(conf.env.LIBEXECDIR,"agent-runner")]) |
| |
| @throws_command_errors |
| #def run_console_proxy(args): |
| # """runs the console proxy""" # FIXME: make this use the run/debug options |
| # conf = _getbuildcontext() |
| # if not _exists(_join(conf.env.LIBEXECDIR,"console-proxy-runner")): Scripting.install(conf) |
| # _check_call("sudo",[_join(conf.env.LIBEXECDIR,"console-proxy-runner")]) |
| |
| def simulate_agent(args): |
| """runs the agent simulator, compiling and installing files as needed |
| - Any parameter specified after the simulate_agent is appended to |
| the java command line. To inhibit waf from interpreting the |
| command-line options that you specify to the agent, put a -- |
| (double-dash) between the waf simulate_agent and the options, like this: |
| |
| python waf simulate_agent -- -z KY -p KY |
| """ |
| |
| # to get this to work smoothly from the configure onwards, you need to |
| # create an override directory in java/agent/conf, then add an agent.properties |
| # there, with the correct configuration that you desire |
| # that is it -- you are now ready to simulate_agent |
| conf = _getbuildcontext() |
| args = sys.argv[sys.argv.index("simulate_agent")+1:] |
| if '--' in args: args.remove('--') |
| |
| cp = [conf.env.AGENTSYSCONFDIR] |
| cp += _glob( _join ( conf.env.PREMIUMJAVADIR , "*" ) ) |
| cp += [conf.env.SYSTEMCLASSPATH] |
| cp += [conf.env.DEPSCLASSPATH] |
| cp += [conf.env.AGENTSIMULATORCLASSPATH] |
| |
| if not _exists(_join(conf.env.LIBEXECDIR,"agent-runner")): Scripting.install(conf) |
| |
| run_java("com.cloud.agent.AgentSimulator",cp,arguments=args) |
| |