akmhoque | fa8ee9b | 2014-03-14 09:06:24 -0500 | [diff] [blame^] | 1 | #! /usr/bin/env python |
| 2 | # encoding: utf-8 |
| 3 | # WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file |
| 4 | |
| 5 | import os,shlex,shutil,traceback,errno,sys,stat |
| 6 | from waflib import Utils,Configure,Logs,Options,ConfigSet,Context,Errors,Build,Node |
| 7 | build_dir_override=None |
| 8 | no_climb_commands=['configure'] |
| 9 | default_cmd="build" |
| 10 | def waf_entry_point(current_directory,version,wafdir): |
| 11 | Logs.init_log() |
| 12 | if Context.WAFVERSION!=version: |
| 13 | Logs.error('Waf script %r and library %r do not match (directory %r)'%(version,Context.WAFVERSION,wafdir)) |
| 14 | sys.exit(1) |
| 15 | if'--version'in sys.argv: |
| 16 | Context.run_dir=current_directory |
| 17 | ctx=Context.create_context('options') |
| 18 | ctx.curdir=current_directory |
| 19 | ctx.parse_args() |
| 20 | sys.exit(0) |
| 21 | Context.waf_dir=wafdir |
| 22 | Context.launch_dir=current_directory |
| 23 | no_climb=os.environ.get('NOCLIMB',None) |
| 24 | if not no_climb: |
| 25 | for k in no_climb_commands: |
| 26 | if k in sys.argv: |
| 27 | no_climb=True |
| 28 | break |
| 29 | cur=current_directory |
| 30 | while cur: |
| 31 | lst=os.listdir(cur) |
| 32 | if Options.lockfile in lst: |
| 33 | env=ConfigSet.ConfigSet() |
| 34 | try: |
| 35 | env.load(os.path.join(cur,Options.lockfile)) |
| 36 | ino=os.stat(cur)[stat.ST_INO] |
| 37 | except Exception: |
| 38 | pass |
| 39 | else: |
| 40 | for x in[env.run_dir,env.top_dir,env.out_dir]: |
| 41 | if Utils.is_win32: |
| 42 | if cur==x: |
| 43 | load=True |
| 44 | break |
| 45 | else: |
| 46 | try: |
| 47 | ino2=os.stat(x)[stat.ST_INO] |
| 48 | except OSError: |
| 49 | pass |
| 50 | else: |
| 51 | if ino==ino2: |
| 52 | load=True |
| 53 | break |
| 54 | else: |
| 55 | Logs.warn('invalid lock file in %s'%cur) |
| 56 | load=False |
| 57 | if load: |
| 58 | Context.run_dir=env.run_dir |
| 59 | Context.top_dir=env.top_dir |
| 60 | Context.out_dir=env.out_dir |
| 61 | break |
| 62 | if not Context.run_dir: |
| 63 | if Context.WSCRIPT_FILE in lst: |
| 64 | Context.run_dir=cur |
| 65 | next=os.path.dirname(cur) |
| 66 | if next==cur: |
| 67 | break |
| 68 | cur=next |
| 69 | if no_climb: |
| 70 | break |
| 71 | if not Context.run_dir: |
| 72 | if'-h'in sys.argv or'--help'in sys.argv: |
| 73 | Logs.warn('No wscript file found: the help message may be incomplete') |
| 74 | Context.run_dir=current_directory |
| 75 | ctx=Context.create_context('options') |
| 76 | ctx.curdir=current_directory |
| 77 | ctx.parse_args() |
| 78 | sys.exit(0) |
| 79 | Logs.error('Waf: Run from a directory containing a file named %r'%Context.WSCRIPT_FILE) |
| 80 | sys.exit(1) |
| 81 | try: |
| 82 | os.chdir(Context.run_dir) |
| 83 | except OSError: |
| 84 | Logs.error('Waf: The folder %r is unreadable'%Context.run_dir) |
| 85 | sys.exit(1) |
| 86 | try: |
| 87 | set_main_module(Context.run_dir+os.sep+Context.WSCRIPT_FILE) |
| 88 | except Errors.WafError ,e: |
| 89 | Logs.pprint('RED',e.verbose_msg) |
| 90 | Logs.error(str(e)) |
| 91 | sys.exit(1) |
| 92 | except Exception ,e: |
| 93 | Logs.error('Waf: The wscript in %r is unreadable'%Context.run_dir,e) |
| 94 | traceback.print_exc(file=sys.stdout) |
| 95 | sys.exit(2) |
| 96 | try: |
| 97 | run_commands() |
| 98 | except Errors.WafError ,e: |
| 99 | if Logs.verbose>1: |
| 100 | Logs.pprint('RED',e.verbose_msg) |
| 101 | Logs.error(e.msg) |
| 102 | sys.exit(1) |
| 103 | except SystemExit: |
| 104 | raise |
| 105 | except Exception ,e: |
| 106 | traceback.print_exc(file=sys.stdout) |
| 107 | sys.exit(2) |
| 108 | except KeyboardInterrupt: |
| 109 | Logs.pprint('RED','Interrupted') |
| 110 | sys.exit(68) |
| 111 | def set_main_module(file_path): |
| 112 | Context.g_module=Context.load_module(file_path) |
| 113 | Context.g_module.root_path=file_path |
| 114 | def set_def(obj): |
| 115 | name=obj.__name__ |
| 116 | if not name in Context.g_module.__dict__: |
| 117 | setattr(Context.g_module,name,obj) |
| 118 | for k in[update,dist,distclean,distcheck,update]: |
| 119 | set_def(k) |
| 120 | if not'init'in Context.g_module.__dict__: |
| 121 | Context.g_module.init=Utils.nada |
| 122 | if not'shutdown'in Context.g_module.__dict__: |
| 123 | Context.g_module.shutdown=Utils.nada |
| 124 | if not'options'in Context.g_module.__dict__: |
| 125 | Context.g_module.options=Utils.nada |
| 126 | def parse_options(): |
| 127 | Context.create_context('options').execute() |
| 128 | if not Options.commands: |
| 129 | Options.commands=[default_cmd] |
| 130 | Options.commands=[x for x in Options.commands if x!='options'] |
| 131 | Logs.verbose=Options.options.verbose |
| 132 | Logs.init_log() |
| 133 | if Options.options.zones: |
| 134 | Logs.zones=Options.options.zones.split(',') |
| 135 | if not Logs.verbose: |
| 136 | Logs.verbose=1 |
| 137 | elif Logs.verbose>0: |
| 138 | Logs.zones=['runner'] |
| 139 | if Logs.verbose>2: |
| 140 | Logs.zones=['*'] |
| 141 | def run_command(cmd_name): |
| 142 | ctx=Context.create_context(cmd_name) |
| 143 | ctx.log_timer=Utils.Timer() |
| 144 | ctx.options=Options.options |
| 145 | ctx.cmd=cmd_name |
| 146 | ctx.execute() |
| 147 | return ctx |
| 148 | def run_commands(): |
| 149 | parse_options() |
| 150 | run_command('init') |
| 151 | while Options.commands: |
| 152 | cmd_name=Options.commands.pop(0) |
| 153 | ctx=run_command(cmd_name) |
| 154 | Logs.info('%r finished successfully (%s)'%(cmd_name,str(ctx.log_timer))) |
| 155 | run_command('shutdown') |
| 156 | def _can_distclean(name): |
| 157 | for k in'.o .moc .exe'.split(): |
| 158 | if name.endswith(k): |
| 159 | return True |
| 160 | return False |
| 161 | def distclean_dir(dirname): |
| 162 | for(root,dirs,files)in os.walk(dirname): |
| 163 | for f in files: |
| 164 | if _can_distclean(f): |
| 165 | fname=root+os.sep+f |
| 166 | try: |
| 167 | os.remove(fname) |
| 168 | except OSError: |
| 169 | Logs.warn('Could not remove %r'%fname) |
| 170 | for x in[Context.DBFILE,'config.log']: |
| 171 | try: |
| 172 | os.remove(x) |
| 173 | except OSError: |
| 174 | pass |
| 175 | try: |
| 176 | shutil.rmtree('c4che') |
| 177 | except OSError: |
| 178 | pass |
| 179 | def distclean(ctx): |
| 180 | '''removes the build directory''' |
| 181 | lst=os.listdir('.') |
| 182 | for f in lst: |
| 183 | if f==Options.lockfile: |
| 184 | try: |
| 185 | proj=ConfigSet.ConfigSet(f) |
| 186 | except IOError: |
| 187 | Logs.warn('Could not read %r'%f) |
| 188 | continue |
| 189 | if proj['out_dir']!=proj['top_dir']: |
| 190 | try: |
| 191 | shutil.rmtree(proj['out_dir']) |
| 192 | except IOError: |
| 193 | pass |
| 194 | except OSError ,e: |
| 195 | if e.errno!=errno.ENOENT: |
| 196 | Logs.warn('project %r cannot be removed'%proj[Context.OUT]) |
| 197 | else: |
| 198 | distclean_dir(proj['out_dir']) |
| 199 | for k in(proj['out_dir'],proj['top_dir'],proj['run_dir']): |
| 200 | try: |
| 201 | os.remove(os.path.join(k,Options.lockfile)) |
| 202 | except OSError ,e: |
| 203 | if e.errno!=errno.ENOENT: |
| 204 | Logs.warn('file %r cannot be removed'%f) |
| 205 | if f.startswith('.waf')and not Options.commands: |
| 206 | shutil.rmtree(f,ignore_errors=True) |
| 207 | class Dist(Context.Context): |
| 208 | '''creates an archive containing the project source code''' |
| 209 | cmd='dist' |
| 210 | fun='dist' |
| 211 | algo='tar.bz2' |
| 212 | ext_algo={} |
| 213 | def execute(self): |
| 214 | self.recurse([os.path.dirname(Context.g_module.root_path)]) |
| 215 | self.archive() |
| 216 | def archive(self): |
| 217 | import tarfile |
| 218 | arch_name=self.get_arch_name() |
| 219 | try: |
| 220 | self.base_path |
| 221 | except AttributeError: |
| 222 | self.base_path=self.path |
| 223 | node=self.base_path.make_node(arch_name) |
| 224 | try: |
| 225 | node.delete() |
| 226 | except Exception: |
| 227 | pass |
| 228 | files=self.get_files() |
| 229 | if self.algo.startswith('tar.'): |
| 230 | tar=tarfile.open(arch_name,'w:'+self.algo.replace('tar.','')) |
| 231 | for x in files: |
| 232 | self.add_tar_file(x,tar) |
| 233 | tar.close() |
| 234 | elif self.algo=='zip': |
| 235 | import zipfile |
| 236 | zip=zipfile.ZipFile(arch_name,'w',compression=zipfile.ZIP_DEFLATED) |
| 237 | for x in files: |
| 238 | archive_name=self.get_base_name()+'/'+x.path_from(self.base_path) |
| 239 | zip.write(x.abspath(),archive_name,zipfile.ZIP_DEFLATED) |
| 240 | zip.close() |
| 241 | else: |
| 242 | self.fatal('Valid algo types are tar.bz2, tar.gz or zip') |
| 243 | try: |
| 244 | from hashlib import sha1 as sha |
| 245 | except ImportError: |
| 246 | from sha import sha |
| 247 | try: |
| 248 | digest=" (sha=%r)"%sha(node.read()).hexdigest() |
| 249 | except Exception: |
| 250 | digest='' |
| 251 | Logs.info('New archive created: %s%s'%(self.arch_name,digest)) |
| 252 | def get_tar_path(self,node): |
| 253 | return node.abspath() |
| 254 | def add_tar_file(self,x,tar): |
| 255 | p=self.get_tar_path(x) |
| 256 | tinfo=tar.gettarinfo(name=p,arcname=self.get_tar_prefix()+'/'+x.path_from(self.base_path)) |
| 257 | tinfo.uid=0 |
| 258 | tinfo.gid=0 |
| 259 | tinfo.uname='root' |
| 260 | tinfo.gname='root' |
| 261 | fu=None |
| 262 | try: |
| 263 | fu=open(p,'rb') |
| 264 | tar.addfile(tinfo,fileobj=fu) |
| 265 | finally: |
| 266 | if fu: |
| 267 | fu.close() |
| 268 | def get_tar_prefix(self): |
| 269 | try: |
| 270 | return self.tar_prefix |
| 271 | except AttributeError: |
| 272 | return self.get_base_name() |
| 273 | def get_arch_name(self): |
| 274 | try: |
| 275 | self.arch_name |
| 276 | except AttributeError: |
| 277 | self.arch_name=self.get_base_name()+'.'+self.ext_algo.get(self.algo,self.algo) |
| 278 | return self.arch_name |
| 279 | def get_base_name(self): |
| 280 | try: |
| 281 | self.base_name |
| 282 | except AttributeError: |
| 283 | appname=getattr(Context.g_module,Context.APPNAME,'noname') |
| 284 | version=getattr(Context.g_module,Context.VERSION,'1.0') |
| 285 | self.base_name=appname+'-'+version |
| 286 | return self.base_name |
| 287 | def get_excl(self): |
| 288 | try: |
| 289 | return self.excl |
| 290 | except AttributeError: |
| 291 | self.excl=Node.exclude_regs+' **/waf-1.7.* **/.waf-1.7* **/waf3-1.7.* **/.waf3-1.7* **/*~ **/*.rej **/*.orig **/*.pyc **/*.pyo **/*.bak **/*.swp **/.lock-w*' |
| 292 | nd=self.root.find_node(Context.out_dir) |
| 293 | if nd: |
| 294 | self.excl+=' '+nd.path_from(self.base_path) |
| 295 | return self.excl |
| 296 | def get_files(self): |
| 297 | try: |
| 298 | files=self.files |
| 299 | except AttributeError: |
| 300 | files=self.base_path.ant_glob('**/*',excl=self.get_excl()) |
| 301 | return files |
| 302 | def dist(ctx): |
| 303 | '''makes a tarball for redistributing the sources''' |
| 304 | pass |
| 305 | class DistCheck(Dist): |
| 306 | fun='distcheck' |
| 307 | cmd='distcheck' |
| 308 | def execute(self): |
| 309 | self.recurse([os.path.dirname(Context.g_module.root_path)]) |
| 310 | self.archive() |
| 311 | self.check() |
| 312 | def check(self): |
| 313 | import tempfile,tarfile |
| 314 | t=None |
| 315 | try: |
| 316 | t=tarfile.open(self.get_arch_name()) |
| 317 | for x in t: |
| 318 | t.extract(x) |
| 319 | finally: |
| 320 | if t: |
| 321 | t.close() |
| 322 | cfg=[] |
| 323 | if Options.options.distcheck_args: |
| 324 | cfg=shlex.split(Options.options.distcheck_args) |
| 325 | else: |
| 326 | cfg=[x for x in sys.argv if x.startswith('-')] |
| 327 | instdir=tempfile.mkdtemp('.inst',self.get_base_name()) |
| 328 | ret=Utils.subprocess.Popen([sys.executable,sys.argv[0],'configure','install','uninstall','--destdir='+instdir]+cfg,cwd=self.get_base_name()).wait() |
| 329 | if ret: |
| 330 | raise Errors.WafError('distcheck failed with code %i'%ret) |
| 331 | if os.path.exists(instdir): |
| 332 | raise Errors.WafError('distcheck succeeded, but files were left in %s'%instdir) |
| 333 | shutil.rmtree(self.get_base_name()) |
| 334 | def distcheck(ctx): |
| 335 | '''checks if the project compiles (tarball from 'dist')''' |
| 336 | pass |
| 337 | def update(ctx): |
| 338 | '''updates the plugins from the *waflib/extras* directory''' |
| 339 | lst=Options.options.files.split(',') |
| 340 | if not lst: |
| 341 | lst=[x for x in Utils.listdir(Context.waf_dir+'/waflib/extras')if x.endswith('.py')] |
| 342 | for x in lst: |
| 343 | tool=x.replace('.py','') |
| 344 | try: |
| 345 | Configure.download_tool(tool,force=True,ctx=ctx) |
| 346 | except Errors.WafError: |
| 347 | Logs.error('Could not find the tool %s in the remote repository'%x) |
| 348 | def autoconfigure(execute_method): |
| 349 | def execute(self): |
| 350 | if not Configure.autoconfig: |
| 351 | return execute_method(self) |
| 352 | env=ConfigSet.ConfigSet() |
| 353 | do_config=False |
| 354 | try: |
| 355 | env.load(os.path.join(Context.top_dir,Options.lockfile)) |
| 356 | except Exception: |
| 357 | Logs.warn('Configuring the project') |
| 358 | do_config=True |
| 359 | else: |
| 360 | if env.run_dir!=Context.run_dir: |
| 361 | do_config=True |
| 362 | else: |
| 363 | h=0 |
| 364 | for f in env['files']: |
| 365 | h=hash((h,Utils.readf(f,'rb'))) |
| 366 | do_config=h!=env.hash |
| 367 | if do_config: |
| 368 | Options.commands.insert(0,self.cmd) |
| 369 | Options.commands.insert(0,'configure') |
| 370 | return |
| 371 | return execute_method(self) |
| 372 | return execute |
| 373 | Build.BuildContext.execute=autoconfigure(Build.BuildContext.execute) |