midori/waf-modules/wafadmin/Scripting.py
2013-10-23 20:26:27 -07:00

414 lines
12 KiB
Python

#! /usr/bin/env python
# encoding: utf-8
import os,sys,shutil,traceback,datetime,inspect,errno
import Utils,Configure,Build,Logs,Options,Environment,Task
from Logs import error,warn,info
from Constants import*
g_gz='bz2'
commands=[]
def prepare_impl(t,cwd,ver,wafdir):
Options.tooldir=[t]
Options.launch_dir=cwd
if'--version'in sys.argv:
opt_obj=Options.Handler()
opt_obj.curdir=cwd
opt_obj.parse_args()
sys.exit(0)
msg1='Waf: Please run waf from a directory containing a file named "%s" or run distclean'%WSCRIPT_FILE
build_dir_override=None
candidate=None
lst=os.listdir(cwd)
search_for_candidate=True
if WSCRIPT_FILE in lst:
candidate=cwd
elif'configure'in sys.argv and not WSCRIPT_BUILD_FILE in lst:
calldir=os.path.abspath(os.path.dirname(sys.argv[0]))
if WSCRIPT_FILE in os.listdir(calldir):
candidate=calldir
search_for_candidate=False
else:
error('arg[0] directory does not contain a wscript file')
sys.exit(1)
build_dir_override=cwd
while search_for_candidate:
if len(cwd)<=3:
break
dirlst=os.listdir(cwd)
if WSCRIPT_FILE in dirlst:
candidate=cwd
if'configure'in sys.argv and candidate:
break
if Options.lockfile in dirlst:
env=Environment.Environment()
try:
env.load(os.path.join(cwd,Options.lockfile))
except:
error('could not load %r'%Options.lockfile)
try:
os.stat(env['cwd'])
except:
candidate=cwd
else:
candidate=env['cwd']
break
cwd=os.path.dirname(cwd)
if not candidate:
if'-h'in sys.argv or'--help'in sys.argv:
warn('No wscript file found: the help message may be incomplete')
opt_obj=Options.Handler()
opt_obj.curdir=cwd
opt_obj.parse_args()
else:
error(msg1)
sys.exit(0)
try:
os.chdir(candidate)
except OSError:
raise Utils.WafError("the folder %r is unreadable"%candidate)
Utils.set_main_module(os.path.join(candidate,WSCRIPT_FILE))
if build_dir_override:
d=getattr(Utils.g_module,BLDDIR,None)
if d:
msg=' Overriding build directory %s with %s'%(d,build_dir_override)
warn(msg)
Utils.g_module.blddir=build_dir_override
def set_def(obj,name=''):
n=name or obj.__name__
if not n in Utils.g_module.__dict__:
setattr(Utils.g_module,n,obj)
for k in[dist,distclean,distcheck,clean,install,uninstall]:
set_def(k)
set_def(Configure.ConfigurationContext,'configure_context')
for k in['build','clean','install','uninstall']:
set_def(Build.BuildContext,k+'_context')
opt_obj=Options.Handler(Utils.g_module)
opt_obj.curdir=candidate
try:
f=Utils.g_module.set_options
except AttributeError:
pass
else:
opt_obj.sub_options([''])
opt_obj.parse_args()
if not'init'in Utils.g_module.__dict__:
Utils.g_module.init=Utils.nada
if not'shutdown'in Utils.g_module.__dict__:
Utils.g_module.shutdown=Utils.nada
main()
def prepare(t,cwd,ver,wafdir):
if WAFVERSION!=ver:
msg='Version mismatch: waf %s <> wafadmin %s (wafdir %s)'%(ver,WAFVERSION,wafdir)
print('\033[91mError: %s\033[0m'%msg)
sys.exit(1)
try:
prepare_impl(t,cwd,ver,wafdir)
except Utils.WafError,e:
error(str(e))
sys.exit(1)
except KeyboardInterrupt:
Utils.pprint('RED','Interrupted')
sys.exit(68)
def main():
global commands
commands=Options.arg_line[:]
while commands:
x=commands.pop(0)
ini=datetime.datetime.now()
if x=='configure':
fun=configure
elif x=='build':
fun=build
else:
fun=getattr(Utils.g_module,x,None)
if not fun:
raise Utils.WscriptError('No such command %r'%x)
ctx=getattr(Utils.g_module,x+'_context',Utils.Context)()
if x in['init','shutdown','dist','distclean','distcheck']:
try:
fun(ctx)
except TypeError:
fun()
else:
fun(ctx)
ela=''
if not Options.options.progress_bar:
ela=' (%s)'%Utils.get_elapsed_time(ini)
if x!='init'and x!='shutdown':
info('%r finished successfully%s'%(x,ela))
if not commands and x!='shutdown':
commands.append('shutdown')
def configure(conf):
src=getattr(Options.options,SRCDIR,None)
if not src:src=getattr(Utils.g_module,SRCDIR,None)
if not src:src=getattr(Utils.g_module,'top',None)
if not src:
src='.'
incomplete_src=1
src=os.path.abspath(src)
bld=getattr(Options.options,BLDDIR,None)
if not bld:bld=getattr(Utils.g_module,BLDDIR,None)
if not bld:bld=getattr(Utils.g_module,'out',None)
if not bld:
bld='build'
incomplete_bld=1
if bld=='.':
raise Utils.WafError('Setting blddir="." may cause distclean problems')
bld=os.path.abspath(bld)
try:os.makedirs(bld)
except OSError:pass
targets=Options.options.compile_targets
Options.options.compile_targets=None
Options.is_install=False
conf.srcdir=src
conf.blddir=bld
conf.post_init()
if'incomplete_src'in vars():
conf.check_message_1('Setting srcdir to')
conf.check_message_2(src)
if'incomplete_bld'in vars():
conf.check_message_1('Setting blddir to')
conf.check_message_2(bld)
conf.sub_config([''])
conf.store()
env=Environment.Environment()
env[BLDDIR]=bld
env[SRCDIR]=src
env['argv']=sys.argv
env['commands']=Options.commands
env['options']=Options.options.__dict__
env['hash']=conf.hash
env['files']=conf.files
env['environ']=dict(conf.environ)
env['cwd']=os.path.split(Utils.g_module.root_path)[0]
if Utils.g_module.root_path!=src:
env.store(os.path.join(src,Options.lockfile))
env.store(Options.lockfile)
Options.options.compile_targets=targets
def clean(bld):
'''removes the build files'''
try:
proj=Environment.Environment(Options.lockfile)
except IOError:
raise Utils.WafError('Nothing to clean (project not configured)')
bld.load_dirs(proj[SRCDIR],proj[BLDDIR])
bld.load_envs()
bld.is_install=0
bld.add_subdirs([os.path.split(Utils.g_module.root_path)[0]])
try:
bld.clean()
finally:
bld.save()
def check_configured(bld):
if not Configure.autoconfig:
return bld
conf_cls=getattr(Utils.g_module,'configure_context',Utils.Context)
bld_cls=getattr(Utils.g_module,'build_context',Utils.Context)
def reconf(proj):
back=(Options.commands,Options.options.__dict__,Logs.zones,Logs.verbose)
Options.commands=proj['commands']
Options.options.__dict__=proj['options']
conf=conf_cls()
conf.environ=proj['environ']
configure(conf)
(Options.commands,Options.options.__dict__,Logs.zones,Logs.verbose)=back
try:
proj=Environment.Environment(Options.lockfile)
except IOError:
conf=conf_cls()
configure(conf)
else:
try:
bld=bld_cls()
bld.load_dirs(proj[SRCDIR],proj[BLDDIR])
bld.load_envs()
except Utils.WafError:
reconf(proj)
return bld_cls()
try:
proj=Environment.Environment(Options.lockfile)
except IOError:
raise Utils.WafError('Auto-config: project does not configure (bug)')
h=0
try:
for file in proj['files']:
if file.endswith('configure'):
h=hash((h,Utils.readf(file)))
else:
mod=Utils.load_module(file)
h=hash((h,mod.waf_hash_val))
except(OSError,IOError):
warn('Reconfiguring the project: a file is unavailable')
reconf(proj)
else:
if(h!=proj['hash']):
warn('Reconfiguring the project: the configuration has changed')
reconf(proj)
return bld_cls()
def install(bld):
'''installs the build files'''
bld=check_configured(bld)
Options.commands['install']=True
Options.commands['uninstall']=False
Options.is_install=True
bld.is_install=INSTALL
build_impl(bld)
bld.install()
def uninstall(bld):
'''removes the installed files'''
Options.commands['install']=False
Options.commands['uninstall']=True
Options.is_install=True
bld.is_install=UNINSTALL
try:
def runnable_status(self):
return SKIP_ME
setattr(Task.Task,'runnable_status_back',Task.Task.runnable_status)
setattr(Task.Task,'runnable_status',runnable_status)
build_impl(bld)
bld.install()
finally:
setattr(Task.Task,'runnable_status',Task.Task.runnable_status_back)
def build(bld):
bld=check_configured(bld)
Options.commands['install']=False
Options.commands['uninstall']=False
Options.is_install=False
bld.is_install=0
return build_impl(bld)
def build_impl(bld):
try:
proj=Environment.Environment(Options.lockfile)
except IOError:
raise Utils.WafError("Project not configured (run 'waf configure' first)")
bld.load_dirs(proj[SRCDIR],proj[BLDDIR])
bld.load_envs()
info("Waf: Entering directory `%s'"%bld.bldnode.abspath())
bld.add_subdirs([os.path.split(Utils.g_module.root_path)[0]])
bld.pre_build()
try:
bld.compile()
finally:
if Options.options.progress_bar:print('')
info("Waf: Leaving directory `%s'"%bld.bldnode.abspath())
bld.post_build()
bld.install()
excludes='.bzr .bzrignore .git .gitignore .svn CVS .cvsignore .arch-ids {arch} SCCS BitKeeper .hg _MTN _darcs Makefile Makefile.in config.log .gitattributes .hgignore .hgtags'.split()
dist_exts='~ .rej .orig .pyc .pyo .bak .tar.bz2 tar.gz .zip .swp'.split()
def dont_dist(name,src,build_dir):
global excludes,dist_exts
if(name.startswith(',,')or name.startswith('++')or name.startswith('.waf')or(src=='.'and name==Options.lockfile)or name in excludes or name==build_dir):
return True
for ext in dist_exts:
if name.endswith(ext):
return True
return False
def copytree(src,dst,build_dir):
names=os.listdir(src)
os.makedirs(dst)
for name in names:
srcname=os.path.join(src,name)
dstname=os.path.join(dst,name)
if dont_dist(name,src,build_dir):
continue
if os.path.isdir(srcname):
copytree(srcname,dstname,build_dir)
else:
shutil.copy2(srcname,dstname)
def distclean(ctx=None):
'''removes the build directory'''
global commands
lst=os.listdir('.')
for f in lst:
if f==Options.lockfile:
try:
proj=Environment.Environment(f)
except:
Logs.warn('could not read %r'%f)
continue
try:
shutil.rmtree(proj[BLDDIR])
except IOError:
pass
except OSError,e:
if e.errno!=errno.ENOENT:
Logs.warn('project %r cannot be removed'%proj[BLDDIR])
try:
os.remove(f)
except OSError,e:
if e.errno!=errno.ENOENT:
Logs.warn('file %r cannot be removed'%f)
if not commands and f.startswith('.waf'):
shutil.rmtree(f,ignore_errors=True)
def dist(appname='',version=''):
'''makes a tarball for redistributing the sources'''
import tarfile
if not appname:appname=Utils.g_module.APPNAME
if not version:version=Utils.g_module.VERSION
tmp_folder=appname+'-'+version
if g_gz in['gz','bz2']:
arch_name=tmp_folder+'.tar.'+g_gz
else:
arch_name=tmp_folder+'.'+'zip'
try:
shutil.rmtree(tmp_folder)
except(OSError,IOError):
pass
try:
os.remove(arch_name)
except(OSError,IOError):
pass
blddir=getattr(Utils.g_module,BLDDIR,None)
if not blddir:
blddir=getattr(Utils.g_module,'out',None)
copytree('.',tmp_folder,blddir)
dist_hook=getattr(Utils.g_module,'dist_hook',None)
if dist_hook:
back=os.getcwd()
os.chdir(tmp_folder)
try:
dist_hook()
finally:
os.chdir(back)
if g_gz in['gz','bz2']:
tar=tarfile.open(arch_name,'w:'+g_gz)
tar.add(tmp_folder)
tar.close()
else:
Utils.zip_folder(tmp_folder,arch_name,tmp_folder)
try:from hashlib import sha1 as sha
except ImportError:from sha import sha
try:
digest=" (sha=%r)"%sha(Utils.readf(arch_name)).hexdigest()
except:
digest=''
info('New archive created: %s%s'%(arch_name,digest))
if os.path.exists(tmp_folder):shutil.rmtree(tmp_folder)
return arch_name
def distcheck(appname='',version='',subdir=''):
'''checks if the sources compile (tarball from 'dist')'''
import tempfile,tarfile
if not appname:appname=Utils.g_module.APPNAME
if not version:version=Utils.g_module.VERSION
waf=os.path.abspath(sys.argv[0])
tarball=dist(appname,version)
path=appname+'-'+version
if os.path.exists(path):
shutil.rmtree(path)
t=tarfile.open(tarball)
for x in t:t.extract(x)
t.close()
if subdir:
build_path=os.path.join(path,subdir)
else:
build_path=path
instdir=tempfile.mkdtemp('.inst','%s-%s'%(appname,version))
ret=Utils.pproc.Popen([waf,'configure','build','install','uninstall','--destdir='+instdir],cwd=build_path).wait()
if ret:
raise Utils.WafError('distcheck failed with code %i'%ret)
if os.path.exists(instdir):
raise Utils.WafError('distcheck succeeded, but files were left in %s'%instdir)
shutil.rmtree(path)
def add_subdir(dir,bld):
bld.recurse(dir,'build')