markdown:
|
|
|
|
|
|
1 """scons.Node.FS 2 3 File system nodes. 4 5 These Nodes represent the canonical external objects that people think 6 of when they think of building software: files and directories. 7 8 This holds a "default_fs" variable that should be initialized with an FS 9 that can be used by scripts or modules looking for the canonical default. 10 11 """ 12 13 # 14 # Copyright (c) 2001 - 2014 The SCons Foundation 15 # 16 # Permission is hereby granted, free of charge, to any person obtaining 17 # a copy of this software and associated documentation files (the 18 # "Software"), to deal in the Software without restriction, including 19 # without limitation the rights to use, copy, modify, merge, publish, 20 # distribute, sublicense, and/or sell copies of the Software, and to 21 # permit persons to whom the Software is furnished to do so, subject to 22 # the following conditions: 23 # 24 # The above copyright notice and this permission notice shall be included 25 # in all copies or substantial portions of the Software. 26 # 27 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 28 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 29 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 30 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 31 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 32 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 33 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 34 35 [__revision__] = "src/engine/SCons/Node/FS.py 2014/09/27 12:51:43 garyo" 36 37 import fnmatch 38 import os 39 import re 40 import shutil 41 import [stat] 42 import sys 43 import time 44 import codecs 45 46 import [SCons] . [Action] 47 import [SCons] . [Debug] 48 from [SCons] . [Debug] import [logInstanceCreation] 49 import [SCons] . [Errors] 50 import [SCons] . [Memoize] 51 import [SCons] . [Node] 52 import [SCons] . [Node] . [Alias] 53 import [SCons] . [Subst] 54 import [SCons] . [Util] 55 import [SCons] . [Warnings] 56 57 from [SCons] . [Debug] import [Trace] 58 59 [do_store_info] = True 60 [print_duplicate] = 0 61 62 63 [-] class [EntryProxyAttributeError] ( AttributeError ) : 64 """ 65 An AttributeError subclass for recording and displaying the name 66 of the underlying Entry involved in an AttributeError exception. 67 """ 69 AttributeError . [__init__] ( self ) 70 self . entry_proxy = entry_proxy 71 self . attribute = attribute 78 79 # The max_drift value: by default, use a cached signature value for 80 # any file that's been untouched for more than two days. 81 [default_max_drift] = 2 * 24 * 60 * 60 82 83 # 84 # We stringify these file system Nodes a lot. Turning a file system Node 85 # into a string is non-trivial, because the final string representation 86 # can depend on a lot of factors: whether it's a derived target or not, 87 # whether it's linked to a repository or source directory, and whether 88 # there's duplication going on. The normal technique for optimizing 89 # calculations like this is to memoize (cache) the string value, so you 90 # only have to do the calculation once. 91 # 92 # A number of the above factors, however, can be set after we've already 93 # been asked to return a string for a Node, because a Repository() or 94 # VariantDir() call or the like may not occur until later in SConscript 95 # files. So this variable controls whether we bother trying to save 96 # string values for Nodes. The wrapper interface can set this whenever 97 # they're done mucking with Repository and VariantDir and the other stuff, 98 # to let this module know it can start returning saved string values 99 # for Nodes. 100 # 101 [Save_Strings] = None 102 103 [-] def [save_strings] ( val ) : 104 global [Save_Strings] 105 [Save_Strings] = val 106 107 # 108 # Avoid unnecessary function calls by recording a Boolean value that 109 # tells us whether or not os.path.splitdrive() actually does anything 110 # on this system, and therefore whether we need to bother calling it 111 # when looking up path names in various methods below. 112 # 113 114 [do_splitdrive] = None 115 [_my_splitdrive] = None 116 117 [-] def [initialize_do_splitdrive] ( ) : 118 global [do_splitdrive] 119 global [has_unc] 120 drive , [path] = os . [path] . splitdrive ( 'X:/foo' ) 121 [has_unc] = hasattr ( os . [path] , 'splitunc' ) 122 123 [do_splitdrive] = not not drive or [has_unc] 124 125 global [_my_splitdrive] 126 if [has_unc] : 127 def splitdrive ( p ) : 128 if p [ 1 : 2 ] == ':' : 129 return p [ : 2 ] , p [ 2 : ] 130 if p [ 0 : 2 ] == '//' : 131 # Note that we leave a leading slash in the path 132 # because UNC paths are always absolute. 133 return '//' , p [ 1 : ] 134 return '' , p 135 else : 136 def splitdrive ( p ) : 137 if p [ 1 : 2 ] == ':' : 138 return p [ : 2 ] , p [ 2 : ] 139 return '' , p 140 [_my_splitdrive] = splitdrive 141 142 # Keep some commonly used values in global variables to skip to 143 # module look-up costs. 144 global [OS_SEP] 145 global [UNC_PREFIX] 146 global [os_sep_is_slash] 147 148 [OS_SEP] = os . sep 149 [UNC_PREFIX] = [OS_SEP] + [OS_SEP] 150 [os_sep_is_slash] = [OS_SEP] == '/' 151 152 [initialize_do_splitdrive] ( ) 153 154 # Used to avoid invoking os.path.normpath if not necessary. 155 [needs_normpath_check] = re . compile ( 156 r''' 157 # We need to renormalize the path if it contains any consecutive 158 # '/' characters. 159 .*// | 160 161 # We need to renormalize the path if it contains a '..' directory. 162 # Note that we check for all the following cases: 163 # 164 # a) The path is a single '..' 165 # b) The path starts with '..'. E.g. '../' or '../moredirs' 166 # but we not match '..abc/'. 167 # c) The path ends with '..'. E.g. '/..' or 'dirs/..' 168 # d) The path contains a '..' in the middle. 169 # E.g. dirs/../moredirs 170 171 (.*/)?\.\.(?:/|$) | 172 173 # We need to renormalize the path if it contains a '.' 174 # directory, but NOT if it is a single '.' '/' characters. We 175 # do not want to match a single '.' because this case is checked 176 # for explicitely since this is common enough case. 177 # 178 # Note that we check for all the following cases: 179 # 180 # a) We don't match a single '.' 181 # b) We match if the path starts with '.'. E.g. './' or 182 # './moredirs' but we not match '.abc/'. 183 # c) We match if the path ends with '.'. E.g. '/.' or 184 # 'dirs/.' 185 # d) We match if the path contains a '.' in the middle. 186 # E.g. dirs/./moredirs 187 188 \./|.*/\.(?:/|$) 189 190 ''' , 191 re . VERBOSE 192 ) 193 [needs_normpath_match] = [needs_normpath_check] . match 194 195 # 196 # SCons.Action objects for interacting with the outside world. 197 # 198 # The Node.FS methods in this module should use these actions to 199 # create and/or remove files and directories; they should *not* use 200 # os.{link,symlink,unlink,mkdir}(), etc., directly. 201 # 202 # Using these SCons.Action objects ensures that descriptions of these 203 # external activities are properly displayed, that the displays are 204 # suppressed when the -s (silent) option is used, and (most importantly) 205 # the actions are disabled when the the -n option is used, in which case 206 # there should be *no* changes to the external file system(s)... 207 # 208 209 if hasattr ( os , 'link' ) : 210 [-] def [_hardlink_func] ( fs , src , dst ) : 211 # If the source is a symlink, we can't just hard-link to it 212 # because a relative symlink may point somewhere completely 213 # different. We must disambiguate the symlink and then 214 # hard-link the final destination file. 215 while [fs] . [islink] ( src ) : 216 [link] = [fs] . [readlink] ( src ) 217 if not os . [path] . isabs ( [link] ) : 218 src = [link] 219 else : 220 src = os . [path] . join ( os . [path] . dirname ( src ) , [link] ) 221 [fs] . [link] ( src , dst ) 222 else : 223 [_hardlink_func] = None 224 225 if hasattr ( os , 'symlink' ) : 226 [-] def [_softlink_func] ( fs , src , dst ) : 228 else : 229 [_softlink_func] = None 230 231 [-] def [_copy_func] ( fs , src , dest ) : 232 shutil . [copy2] ( src , dest ) 233 st = [fs] . [stat] ( src ) 234 [fs] . [chmod] ( dest , [stat] . S_IMODE ( st [ [stat] . ST_MODE ] ) | [stat] . S_IWRITE ) 235 236 237 [Valid_Duplicates] = [ 'hard-soft-copy' , 'soft-hard-copy' , 238 'hard-copy' , 'soft-copy' , 'copy' ] 239 240 [Link_Funcs] = [ ] # contains the callables of the specified duplication style 241 242 [-] def [set_duplicate] ( duplicate ) : 243 # Fill in the Link_Funcs list according to the argument 244 # (discarding those not available on the platform). 245 246 # Set up the dictionary that maps the argument names to the 247 # underlying implementations. We do this inside this function, 248 # not in the top-level module code, so that we can remap os.link 249 # and os.symlink for testing purposes. 250 link_dict = { 251 'hard' : [_hardlink_func] , 252 'soft' : [_softlink_func] , 253 'copy' : [_copy_func] 254 } 255 256 if not duplicate in [Valid_Duplicates] : 257 raise [SCons] . [Errors] . [InternalError] ( "The argument of set_duplicate " 258 "should be in Valid_Duplicates" ) 259 global [Link_Funcs] 260 [Link_Funcs] = [ ] 261 for func in duplicate . split ( '-' ) : 262 if link_dict [ func ] : 263 [Link_Funcs] . [append] ( link_dict [ func ] ) 264 266 # Relative paths cause problems with symbolic links, so 267 # we use absolute paths, which may be a problem for people 268 # who want to move their soft-linked src-trees around. Those 269 # people should use the 'hard-copy' mode, softlinks cannot be 270 # used for that; at least I have no idea how ... 271 src = source [ 0 ] . abspath 272 dest = target [ 0 ] . abspath 273 dir , file = os . [path] . split ( dest ) 274 if dir and not target [ 0 ] . [fs] . [isdir] ( dir ) : 275 os . [makedirs] ( dir ) 276 if not [Link_Funcs] : 277 # Set a default order of link functions. 278 [set_duplicate] ( 'hard-soft-copy' ) 279 [fs] = source [ 0 ] . [fs] 280 # Now link the files with the previously specified order. 281 for func in [Link_Funcs] : 282 try : 283 func ( [fs] , src , dest ) 284 break 285 except ( IOError , OSError ) : 286 # An OSError indicates something happened like a permissions 287 # problem or an attempt to symlink across file-system 288 # boundaries. An IOError indicates something like the file 289 # not existing. In either case, keeping trying additional 290 # functions in the list and only raise an error if the last 291 # one failed. 292 if func == [Link_Funcs] [ - 1 ] : 293 # exception of the last link method (copy) are fatal 294 raise 295 return 0 296 297 [Link] = [SCons] . [Action] . [Action] ( [LinkFunc] , None ) 298 [-] def [LocalString] ( target , source , env ) : 300 301 [LocalCopy] = [SCons] . [Action] . [Action] ( [LinkFunc] , [LocalString] ) 302 303 [-] def [UnlinkFunc] ( target , source , env ) : 307 308 [Unlink] = [SCons] . [Action] . [Action] ( [UnlinkFunc] , None ) 309 315 316 [Mkdir] = [SCons] . [Action] . [Action] ( [MkdirFunc] , None , presub = None ) 317 318 [MkdirBuilder] = None 319 320 [-] def [get_MkdirBuilder] ( ) : 321 global [MkdirBuilder] 322 if [MkdirBuilder] is None : 323 import [SCons] . [Builder] 324 import [SCons] . [Defaults] 325 # "env" will get filled in by Executor.get_build_env() 326 # calling SCons.Defaults.DefaultEnvironment() when necessary. 327 [MkdirBuilder] = [SCons] . [Builder] . [Builder] ( action = [Mkdir] , 328 env = None , 329 [explain] = None , 330 is_explicit = None , 331 target_scanner = [SCons] . [Defaults] . [DirEntryScanner] , 332 name = "MkdirBuilder" ) 333 return [MkdirBuilder] 334 337 338 [_null] = [_Null] ( ) 339 340 [DefaultSCCSBuilder] = None 341 [DefaultRCSBuilder] = None 342 343 [-] def [get_DefaultSCCSBuilder] ( ) : 344 global [DefaultSCCSBuilder] 345 if [DefaultSCCSBuilder] is None : 346 import [SCons] . [Builder] 347 # "env" will get filled in by Executor.get_build_env() 348 # calling SCons.Defaults.DefaultEnvironment() when necessary. 349 act = [SCons] . [Action] . [Action] ( '$SCCSCOM' , '$SCCSCOMSTR' ) 350 [DefaultSCCSBuilder] = [SCons] . [Builder] . [Builder] ( action = act , 351 env = None , 352 name = "DefaultSCCSBuilder" ) 353 return [DefaultSCCSBuilder] 354 355 [-] def [get_DefaultRCSBuilder] ( ) : 356 global [DefaultRCSBuilder] 357 if [DefaultRCSBuilder] is None : 358 import [SCons] . [Builder] 359 # "env" will get filled in by Executor.get_build_env() 360 # calling SCons.Defaults.DefaultEnvironment() when necessary. 361 act = [SCons] . [Action] . [Action] ( '$RCS_COCOM' , '$RCS_COCOMSTR' ) 362 [DefaultRCSBuilder] = [SCons] . [Builder] . [Builder] ( action = act , 363 env = None , 364 name = "DefaultRCSBuilder" ) 365 return [DefaultRCSBuilder] 366 367 # Cygwin's os.path.normcase pretends it's on a case-sensitive filesystem. 368 [_is_cygwin] = sys . platform == "cygwin" 369 if os . [path] . normcase ( "TeSt" ) == os . [path] . normpath ( "TeSt" ) and not [_is_cygwin] : 370 [-] def [_my_normcase] ( x ) : 371 return [x] 372 else : 373 [-] def [_my_normcase] ( x ) : 374 return [x] . upper ( ) 375 376 377 378 [-] class [DiskChecker] ( object ) : 391 392 [-] def [do_diskcheck_match] ( node , predicate , errorfmt ) : 393 [result] = predicate ( ) 394 try : 395 # If calling the predicate() cached a None value from stat(), 396 # remove it so it doesn't interfere with later attempts to 397 # build this Node as we walk the DAG. (This isn't a great way 398 # to do this, we're reaching into an interface that doesn't 399 # really belong to us, but it's all about performance, so 400 # for now we'll just document the dependency...) 401 if node . _memo [ 'stat' ] is None : 402 del node . _memo [ 'stat' ] 403 except ( AttributeError , KeyError ) : 404 pass 405 if [result] : 406 raise TypeError ( errorfmt % node . abspath ) 407 408 [-] def [ignore_diskcheck_match] ( node , predicate , errorfmt ) : 410 411 [-] def [do_diskcheck_rcs] ( node , name ) : 412 try : 413 rcs_dir = node . rcs_dir 414 except AttributeError : 415 if node . [entry_exists_on_disk] ( 'RCS' ) : 416 rcs_dir = node . [Dir] ( 'RCS' ) 417 else : 418 rcs_dir = None 419 node . rcs_dir = rcs_dir 420 if rcs_dir : 421 return rcs_dir . [entry_exists_on_disk] ( name + ',v' ) 422 return None 423 424 [-] def [ignore_diskcheck_rcs] ( node , name ) : 426 427 [-] def [do_diskcheck_sccs] ( node , name ) : 428 try : 429 sccs_dir = node . sccs_dir 430 except AttributeError : 431 if node . [entry_exists_on_disk] ( 'SCCS' ) : 432 sccs_dir = node . [Dir] ( 'SCCS' ) 433 else : 434 sccs_dir = None 435 node . sccs_dir = sccs_dir 436 if sccs_dir : 437 return sccs_dir . [entry_exists_on_disk] ( 's.' + name ) 438 return None 439 440 [-] def [ignore_diskcheck_sccs] ( node , name ) : 442 443 [diskcheck_match] = [DiskChecker] ( 'match' , [do_diskcheck_match] , [ignore_diskcheck_match] ) 444 [diskcheck_rcs] = [DiskChecker] ( 'rcs' , [do_diskcheck_rcs] , [ignore_diskcheck_rcs] ) 445 [diskcheck_sccs] = [DiskChecker] ( 'sccs' , [do_diskcheck_sccs] , [ignore_diskcheck_sccs] ) 446 447 [diskcheckers] = [ 448 [diskcheck_match] , 449 [diskcheck_rcs] , 450 [diskcheck_sccs] , 451 ] 452 453 [-] def [set_diskcheck] ( list ) : 454 for dc in [diskcheckers] : 455 dc . [set] ( list ) 456 457 [-] def [diskcheck_types] ( ) : 458 return [ dc . type for dc in [diskcheckers] ] 459 460 461 462 [-] class [EntryProxy] ( SCons . Util . Proxy ) : 463 464 [__str__] = [SCons] . [Util] . [Delegate] ( '__str__' ) 465 466 [-] def [__get_abspath] ( self ) : 467 entry = self . [get] ( ) 468 return [SCons] . [Subst] . [SpecialAttrWrapper] ( entry . [get_abspath] ( ) , 469 entry . name + "_abspath" ) 470 471 [-] def [__get_filebase] ( self ) : 472 name = self . [get] ( ) . name 473 return [SCons] . [Subst] . [SpecialAttrWrapper] ( [SCons] . [Util] . [splitext] ( name ) [ 0 ] , 474 name + "_filebase" ) 475 476 [-] def [__get_suffix] ( self ) : 477 name = self . [get] ( ) . name 478 return [SCons] . [Subst] . [SpecialAttrWrapper] ( [SCons] . [Util] . [splitext] ( name ) [ 1 ] , 479 name + "_suffix" ) 480 481 [-] def [__get_file] ( self ) : 482 name = self . [get] ( ) . name 483 return [SCons] . [Subst] . [SpecialAttrWrapper] ( name , name + "_file" ) 484 485 [-] def [__get_base_path] ( self ) : 486 """Return the file's directory and file name, with the 487 suffix stripped.""" 488 entry = self . [get] ( ) 489 return [SCons] . [Subst] . [SpecialAttrWrapper] ( [SCons] . [Util] . [splitext] ( entry . [get_path] ( ) ) [ 0 ] , 490 entry . name + "_base" ) 491 492 [-] def [__get_posix_path] ( self ) : 493 """Return the path with / as the path separator, 494 regardless of platform.""" 495 if [os_sep_is_slash] : 496 return self 497 else : 498 entry = self . [get] ( ) 499 r = entry . [get_path] ( ) . replace ( [OS_SEP] , '/' ) 500 return [SCons] . [Subst] . [SpecialAttrWrapper] ( r , entry . name + "_posix" ) 501 502 [-] def [__get_windows_path] ( self ) : 503 """Return the path with \ as the path separator, 504 regardless of platform.""" 505 if [OS_SEP] == '\\' : 506 return self 507 else : 508 entry = self . [get] ( ) 509 r = entry . [get_path] ( ) . replace ( [OS_SEP] , '\\' ) 510 return [SCons] . [Subst] . [SpecialAttrWrapper] ( r , entry . name + "_windows" ) 511 512 [-] def [__get_srcnode] ( self ) : 513 return [EntryProxy] ( self . [get] ( ) . [srcnode] ( ) ) 514 515 [-] def [__get_srcdir] ( self ) : 516 """Returns the directory containing the source node linked to this 517 node via VariantDir(), or the directory of this node if not linked.""" 518 return [EntryProxy] ( self . [get] ( ) . [srcnode] ( ) . dir ) 519 520 [-] def [__get_rsrcnode] ( self ) : 521 return [EntryProxy] ( self . [get] ( ) . [srcnode] ( ) . [rfile] ( ) ) 522 523 [-] def [__get_rsrcdir] ( self ) : 524 """Returns the directory containing the source node linked to this 525 node via VariantDir(), or the directory of this node if not linked.""" 526 return [EntryProxy] ( self . [get] ( ) . [srcnode] ( ) . [rfile] ( ) . dir ) 527 529 return [EntryProxy] ( self . [get] ( ) . dir ) 530 531 [dictSpecialAttrs] = { "base" : [__get_base_path] , 532 "posix" : [__get_posix_path] , 533 "windows" : [__get_windows_path] , 534 "win32" : [__get_windows_path] , 535 "srcpath" : [__get_srcnode] , 536 "srcdir" : [__get_srcdir] , 537 "dir" : [__get_dir] , 538 "abspath" : [__get_abspath] , 539 "filebase" : [__get_filebase] , 540 "suffix" : [__get_suffix] , 541 "file" : [__get_file] , 542 "rsrcpath" : [__get_rsrcnode] , 543 "rsrcdir" : [__get_rsrcdir] , 544 } 545 546 [-] def [__getattr__] ( self , name ) : 547 # This is how we implement the "special" attributes 548 # such as base, posix, srcdir, etc. 549 try : 550 attr_function = self . [dictSpecialAttrs] [ name ] 551 except KeyError : 552 try : 553 attr = [SCons] . [Util] . [Proxy] . [__getattr__] ( self , name ) 554 except AttributeError , [e] : 555 # Raise our own AttributeError subclass with an 556 # overridden __str__() method that identifies the 557 # name of the entry that caused the exception. 558 raise [EntryProxyAttributeError] ( self , name ) 559 return attr 560 else : 561 return attr_function ( self ) 562 564 """A generic class for file system entries. This class is for 565 when we don't know yet whether the entry being looked up is a file 566 or a directory. Instances of this class can morph into either 567 Dir or File objects by a later, more precise lookup. 568 569 Note: this class does not define __cmp__ and __hash__ for 570 efficiency reasons. SCons does a lot of comparing of 571 Node.FS.{Base,Entry,File,Dir} objects, so those operations must be 572 as fast as possible, which means we want to use Python's built-in 573 object identity comparisons. 574 """ 575 576 [memoizer_counters] = [ ] 577 579 """Initialize a generic Node.FS.Base object. 580 581 Call the superclass initialization, take care of setting up 582 our relative and absolute paths, identify our parent 583 directory, and indicate that this node should use 584 signatures.""" 585 if [SCons] . [Debug] . [track_instances] : [logInstanceCreation] ( self , 'Node.FS.Base' ) 586 [SCons] . [Node] . [Node] . [__init__] ( self ) 587 588 # Filenames and paths are probably reused and are intern'ed to 589 # save some memory. 590 591 #: Filename with extension as it was specified when the object was 592 #: created; to obtain filesystem path, use Python str() function 593 self . name = [SCons] . [Util] . silent_intern ( name ) 594 #: Cached filename extension 595 self . suffix = [SCons] . [Util] . silent_intern ( [SCons] . [Util] . [splitext] ( name ) [ 1 ] ) 596 self . [fs] = [fs] #: Reference to parent Node.FS object 597 598 assert directory , "A directory must be provided" 599 600 self . abspath = [SCons] . [Util] . silent_intern ( directory . [entry_abspath] ( name ) ) 601 self . labspath = [SCons] . [Util] . silent_intern ( directory . [entry_labspath] ( name ) ) 602 if directory . [path] == '.' : 603 self . [path] = [SCons] . [Util] . silent_intern ( name ) 604 else : 605 self . [path] = [SCons] . [Util] . silent_intern ( directory . [entry_path] ( name ) ) 606 if directory . tpath == '.' : 607 self . tpath = [SCons] . [Util] . silent_intern ( name ) 608 else : 609 self . tpath = [SCons] . [Util] . silent_intern ( directory . [entry_tpath] ( name ) ) 610 self . path_elements = directory . path_elements + [ self ] 611 612 self . dir = directory 613 self . cwd = None # will hold the SConscript directory for target nodes 614 self . duplicate = directory . duplicate 615 616 [-] def [str_for_display] ( self ) : 617 return '"' + self . [__str__] ( ) + '"' 618 619 [-] def [must_be_same] ( self , klass ) : 620 """ 621 This node, which already existed, is being looked up as the 622 specified klass. Raise an exception if it isn't. 623 """ 624 if isinstance ( self , klass ) or klass is [Entry] : 625 return 626 raise TypeError ( "Tried to lookup %s '%s' as a %s." %\ 627 ( self . __class__ . __name__ , self . [path] , klass . __name__ ) ) 628 631 632 [-] def [get_suffix] ( self ) : 634 637 639 """A Node.FS.Base object's string representation is its path 640 name.""" 641 global [Save_Strings] 642 if [Save_Strings] : 643 return self . [_save_str] ( ) 644 return self . [_get_str] ( ) 645 646 [memoizer_counters] . [append] ( [SCons] . [Memoize] . [CountValue] ( '_save_str' ) ) 647 649 try : 650 return self . _memo [ '_save_str' ] 651 except KeyError : 652 pass 653 [result] = sys . intern ( self . [_get_str] ( ) ) 654 self . _memo [ '_save_str' ] = [result] 655 return [result] 656 658 global [Save_Strings] 659 if self . duplicate or self . [is_derived] ( ) : 660 return self . [get_path] ( ) 661 [srcnode] = self . [srcnode] ( ) 662 if [srcnode] . [stat] ( ) is None and self . [stat] ( ) is not None : 663 [result] = self . [get_path] ( ) 664 else : 665 [result] = [srcnode] . [get_path] ( ) 666 if not [Save_Strings] : 667 # We're not at the point where we're saving the string 668 # representations of FS Nodes (because we haven't finished 669 # reading the SConscript files and need to have str() return 670 # things relative to them). That also means we can't yet 671 # cache values returned (or not returned) by stat(), since 672 # Python code in the SConscript files might still create 673 # or otherwise affect the on-disk file. So get rid of the 674 # values that the underlying stat() method saved. 675 try : del self . _memo [ 'stat' ] 676 except KeyError : pass 677 if self is not [srcnode] : 678 try : del [srcnode] . _memo [ 'stat' ] 679 except KeyError : pass 680 return [result] 681 682 [rstr] = [__str__] 683 684 [memoizer_counters] . [append] ( [SCons] . [Memoize] . [CountValue] ( 'stat' ) ) 685 687 try : return self . _memo [ 'stat' ] 688 except KeyError : pass 689 try : [result] = self . [fs] . [stat] ( self . abspath ) 690 except os . error : [result] = None 691 self . _memo [ 'stat' ] = [result] 692 return [result] 693 695 return self . [stat] ( ) is not None 696 699 704 709 713 717 718 if hasattr ( os , 'symlink' ) : 720 try : st = self . [fs] . [lstat] ( self . abspath ) 721 except os . error : return 0 722 return [stat] . S_ISLNK ( st [ [stat] . ST_MODE ] ) 723 else : 726 728 if self is dir : 729 return 1 730 else : 731 return self . dir . [is_under] ( dir ) 732 735 737 """If this node is in a build path, return the node 738 corresponding to its source file. Otherwise, return 739 ourself. 740 """ 741 [srcdir_list] = self . dir . [srcdir_list] ( ) 742 if [srcdir_list] : 743 [srcnode] = [srcdir_list] [ 0 ] . [Entry] ( self . name ) 744 [srcnode] . [must_be_same] ( self . __class__ ) 745 return [srcnode] 746 return self 747 749 """Return path relative to the current working directory of the 750 Node.FS.Base object that owns us.""" 751 if not dir : 752 dir = self . [fs] . [getcwd] ( ) 753 if self == dir : 754 return '.' 755 path_elems = self . path_elements 756 pathname = '' 757 try : i = path_elems . [index] ( dir ) 758 except ValueError : 759 for p in path_elems [ : - 1 ] : 760 pathname += p . dirname 761 else : 762 for p in path_elems [ i + 1 : - 1 ] : 763 pathname += p . dirname 764 return pathname + path_elems [ - 1 ] . name 765 766 [-] def [set_src_builder] ( self , builder ) : 767 """Set the source code builder for this node.""" 768 self . sbuilder = builder 769 if not self . [has_builder] ( ) : 770 self . [builder_set] ( builder ) 771 772 [-] def [src_builder] ( self ) : 773 """Fetch the source code builder for this node. 774 775 If there isn't one, we cache the source code builder specified 776 for the directory (which in turn will cache the value from its 777 parent directory, and so on up to the file system root). 778 """ 779 try : 780 scb = self . sbuilder 781 except AttributeError : 782 scb = self . dir . [src_builder] ( ) 783 self . sbuilder = scb 784 return scb 785 786 [-] def [get_abspath] ( self ) : 789 790 [-] def [for_signature] ( self ) : 791 # Return just our name. Even an absolute path would not work, 792 # because that can change thanks to symlinks or remapped network 793 # paths. 794 return self . name 795 796 [-] def [get_subst_proxy] ( self ) : 797 try : 798 return self . _proxy 799 except AttributeError : 800 ret = [EntryProxy] ( self ) 801 self . _proxy = ret 802 return ret 803 804 [-] def [target_from_source] ( self , prefix , suffix , splitext = [SCons] . [Util] . [splitext] ) : 805 """ 806 807 Generates a target entry that corresponds to this entry (usually 808 a source file) with the specified prefix and suffix. 809 810 Note that this method can be overridden dynamically for generated 811 files that need different behavior. See Tool/swig.py for 812 an example. 813 """ 814 return self . dir . [Entry] ( prefix + [splitext] ( self . name ) [ 0 ] + suffix ) 815 816 [-] def [_Rfindalldirs_key] ( self , pathlist ) : 818 819 [memoizer_counters] . [append] ( [SCons] . [Memoize] . [CountDict] ( 'Rfindalldirs' , [_Rfindalldirs_key] ) ) 820 821 [-] def [Rfindalldirs] ( self , pathlist ) : 822 """ 823 Return all of the directories for a given path list, including 824 corresponding "backing" directories in any repositories. 825 826 The Node lookups are relative to this Node (typically a 827 directory), so memoizing result saves cycles from looking 828 up the same path for each target in a given directory. 829 """ 830 try : 831 memo_dict = self . _memo [ 'Rfindalldirs' ] 832 except KeyError : 833 memo_dict = { } 834 self . _memo [ 'Rfindalldirs' ] = memo_dict 835 else : 836 try : 837 return memo_dict [ pathlist ] 838 except KeyError : 839 pass 840 841 create_dir_relative_to_self = self . [Dir] 842 [result] = [ ] 843 for [path] in pathlist : 844 if isinstance ( [path] , [SCons] . [Node] . [Node] ) : 845 [result] . [append] ( [path] ) 846 else : 847 dir = create_dir_relative_to_self ( [path] ) 848 [result] . [extend] ( dir . [get_all_rdirs] ( ) ) 849 850 memo_dict [ pathlist ] = [result] 851 852 return [result] 853 855 """Search for a list of directories in the Repository list.""" 856 cwd = self . cwd or self . [fs] . _cwd 857 return cwd . [Rfindalldirs] ( pathlist ) 858 859 [memoizer_counters] . [append] ( [SCons] . [Memoize] . [CountValue] ( 'rentry' ) ) 860 862 try : 863 return self . _memo [ 'rentry' ] 864 except KeyError : 865 pass 866 [result] = self 867 if not self . [exists] ( ) : 868 norm_name = [_my_normcase] ( self . name ) 869 for dir in self . dir . [get_all_rdirs] ( ) : 870 try : 871 node = dir . entries [ norm_name ] 872 except KeyError : 873 if dir . [entry_exists_on_disk] ( self . name ) : 874 [result] = dir . [Entry] ( self . name ) 875 break 876 self . _memo [ 'rentry' ] = [result] 877 return [result] 878 881 883 """This is the class for generic Node.FS entries--that is, things 884 that could be a File or a Dir, but we're just not sure yet. 885 Consequently, the methods in this class really exist just to 886 transform their associated object into the right class when the 887 time comes, and then call the same-named method in the transformed 888 class.""" 889 890 [-] def [diskcheck_match] ( self ) : 892 893 [-] def [disambiguate] ( self , must_exist = None ) : 894 """ 895 """ 896 if self . [isdir] ( ) : 897 self . __class__ = [Dir] 898 self . [_morph] ( ) 899 elif self . [isfile] ( ) : 900 self . __class__ = [File] 901 self . [_morph] ( ) 902 self . [clear] ( ) 903 else : 904 # There was nothing on-disk at this location, so look in 905 # the src directory. 906 # 907 # We can't just use self.srcnode() straight away because 908 # that would create an actual Node for this file in the src 909 # directory, and there might not be one. Instead, use the 910 # dir_on_disk() method to see if there's something on-disk 911 # with that name, in which case we can go ahead and call 912 # self.srcnode() to create the right type of entry. 913 srcdir = self . dir . [srcnode] ( ) 914 if srcdir != self . dir and\ 915 srcdir . [entry_exists_on_disk] ( self . name ) and\ 916 self . [srcnode] ( ) . [isdir] ( ) : 917 self . __class__ = [Dir] 918 self . [_morph] ( ) 919 elif must_exist : 920 [msg] = "No such file or directory: '%s'" % self . abspath 921 raise [SCons] . [Errors] . [UserError] ( [msg] ) 922 else : 923 self . __class__ = [File] 924 self . [_morph] ( ) 925 self . [clear] ( ) 926 return self 927 929 """We're a generic Entry, but the caller is actually looking for 930 a File at this point, so morph into one.""" 931 self . __class__ = [File] 932 self . [_morph] ( ) 933 self . [clear] ( ) 934 return [File] . [rfile] ( self ) 935 936 [-] def [scanner_key] ( self ) : 937 return self . [get_suffix] ( ) 938 939 [-] def [get_contents] ( self ) : 940 """Fetch the contents of the entry. Returns the exact binary 941 contents of the file.""" 942 try : 943 self = self . [disambiguate] ( must_exist = 1 ) 944 except [SCons] . [Errors] . [UserError] : 945 # There was nothing on disk with which to disambiguate 946 # this entry. Leave it as an Entry, but return a null 947 # string so calls to get_contents() in emitters and the 948 # like (e.g. in qt.py) don't have to disambiguate by hand 949 # or catch the exception. 950 return '' 951 else : 952 return self . [get_contents] ( ) 953 954 [-] def [get_text_contents] ( self ) : 955 """Fetch the decoded text contents of a Unicode encoded Entry. 956 957 Since this should return the text contents from the file 958 system, we check to see into what sort of subclass we should 959 morph this Entry.""" 960 try : 961 self = self . [disambiguate] ( must_exist = 1 ) 962 except [SCons] . [Errors] . [UserError] : 963 # There was nothing on disk with which to disambiguate 964 # this entry. Leave it as an Entry, but return a null 965 # string so calls to get_text_contents() in emitters and 966 # the like (e.g. in qt.py) don't have to disambiguate by 967 # hand or catch the exception. 968 return '' 969 else : 970 return self . [get_text_contents] ( ) 971 972 [-] def [must_be_same] ( self , klass ) : 973 """Called to make sure a Node is a Dir. Since we're an 974 Entry, we can morph into one.""" 975 if self . __class__ is not klass : 976 self . __class__ = klass 977 self . [_morph] ( ) 978 self . [clear] ( ) 979 980 # The following methods can get called before the Taskmaster has 981 # had a chance to call disambiguate() directly to see if this Entry 982 # should really be a Dir or a File. We therefore use these to call 983 # disambiguate() transparently (from our caller's point of view). 984 # 985 # Right now, this minimal set of methods has been derived by just 986 # looking at some of the methods that will obviously be called early 987 # in any of the various Taskmasters' calling sequences, and then 988 # empirically figuring out which additional methods are necessary 989 # to make various tests pass. 990 992 """Return if the Entry exists. Check the file system to see 993 what we should turn into first. Assume a file if there's no 994 directory.""" 995 return self . [disambiguate] ( ) . [exists] ( ) 996 998 [d] = self . [disambiguate] ( ) 999 if [d] . __class__ is [Entry] : 1000 raise Exception ( "rel_path() could not disambiguate File/Dir" ) 1001 return [d] . [rel_path] ( other ) 1002 1004 return self . [disambiguate] ( ) . [new_ninfo] ( ) 1005 1006 [-] def [changed_since_last_build] ( self , target , prev_ni ) : 1007 return self . [disambiguate] ( ) . [changed_since_last_build] ( target , prev_ni ) 1008 1010 return self . [disambiguate] ( ) . [_glob1] ( pattern , ondisk , source , strings ) 1011 1012 [-] def [get_subst_proxy] ( self ) : 1013 return self . [disambiguate] ( ) . [get_subst_proxy] ( ) 1014 1015 # This is for later so we can differentiate between Entry the class and Entry 1016 # the method of the FS class. 1017 _classEntry = [Entry] 1018 1019 1021 1022 if [SCons] . [Memoize] . [use_memoizer] : 1023 [__metaclass__] = [SCons] . [Memoize] . [Memoized_Metaclass] 1024 1025 # This class implements an abstraction layer for operations involving 1026 # a local file system. Essentially, this wraps any function in 1027 # the os, os.path or shutil modules that we use to actually go do 1028 # anything with or to the local file system. 1029 # 1030 # Note that there's a very good chance we'll refactor this part of 1031 # the architecture in some way as we really implement the interface(s) 1032 # for remote file system Nodes. For example, the right architecture 1033 # might be to have this be a subclass instead of a base class. 1034 # Nevertheless, we're using this as a first step in that direction. 1035 # 1036 # We're not using chdir() yet because the calling subclass method 1037 # needs to use os.chdir() directly to avoid recursion. Will we 1038 # really need this one? 1039 #def chdir(self, path): 1040 # return os.chdir(path) 1044 return shutil . [copy] ( src , dst ) 1046 return shutil . [copy2] ( src , dst ) 1058 return os . [link] ( src , dst ) 1068 return os . [rename] ( old , new ) 1072 return os . [symlink] ( src , dst ) 1077 1078 if hasattr ( os , 'symlink' ) : 1081 else : 1084 1085 if hasattr ( os , 'readlink' ) : 1087 return os . [readlink] ( file ) 1088 else : 1091 1092 1093 #class RemoteFS: 1094 # # Skeleton for the obvious methods we might need from the 1095 # # abstraction layer for a remote filesystem. 1096 # def upload(self, local_src, remote_dst): 1097 # pass 1098 # def download(self, remote_src, local_dst): 1099 # pass 1100 1101 1103 1104 [memoizer_counters] = [ ] 1105 1107 """Initialize the Node.FS subsystem. 1108 1109 The supplied path is the top of the source tree, where we 1110 expect to find the top-level build file. If no path is 1111 supplied, the current directory is the default. 1112 1113 The path argument must be a valid absolute path. 1114 """ 1115 if [SCons] . [Debug] . [track_instances] : [logInstanceCreation] ( self , 'Node.FS' ) 1116 1117 self . _memo = { } 1118 1119 self . Root = { } 1120 self . SConstruct_dir = None 1121 self . max_drift = [default_max_drift] 1122 1123 self . Top = None 1124 if [path] is None : 1125 self . pathTop = os . [getcwd] ( ) 1126 else : 1127 self . pathTop = [path] 1128 self . defaultDrive = [_my_normcase] ( [_my_splitdrive] ( self . pathTop ) [ 0 ] ) 1129 1130 self . Top = self . [Dir] ( self . pathTop ) 1131 self . Top . [path] = '.' 1132 self . Top . tpath = '.' 1133 self . _cwd = self . Top 1134 1135 [DirNodeInfo] . [fs] = self 1136 [FileNodeInfo] . [fs] = self 1137 1138 [-] def [set_SConstruct_dir] ( self , dir ) : 1140 1141 [-] def [get_max_drift] ( self ) : 1143 1144 [-] def [set_max_drift] ( self , max_drift ) : 1146 1152 1154 """Change the current working directory for lookups. 1155 If change_os_dir is true, we will also change the "real" cwd 1156 to match. 1157 """ 1158 curr = self . _cwd 1159 try : 1160 if dir is not None : 1161 self . _cwd = dir 1162 if change_os_dir : 1163 os . [chdir] ( dir . abspath ) 1164 except OSError : 1165 self . _cwd = curr 1166 raise 1167 1169 """ 1170 Returns the root directory for the specified drive, creating 1171 it if necessary. 1172 """ 1173 drive = [_my_normcase] ( drive ) 1174 try : 1175 return self . Root [ drive ] 1176 except KeyError : 1177 root = [RootDir] ( drive , self ) 1178 self . Root [ drive ] = root 1179 if not drive : 1180 self . Root [ self . defaultDrive ] = root 1181 elif drive == self . defaultDrive : 1182 self . Root [ '' ] = root 1183 return root 1184 1186 """ 1187 The generic entry point for Node lookup with user-supplied data. 1188 1189 This translates arbitrary input into a canonical Node.FS object 1190 of the specified fsclass. The general approach for strings is 1191 to turn it into a fully normalized absolute path and then call 1192 the root directory's lookup_abs() method for the heavy lifting. 1193 1194 If the path name begins with '#', it is unconditionally 1195 interpreted relative to the top-level directory of this FS. '#' 1196 is treated as a synonym for the top-level SConstruct directory, 1197 much like '~' is treated as a synonym for the user's home 1198 directory in a UNIX shell. So both '#foo' and '#/foo' refer 1199 to the 'foo' subdirectory underneath the top-level SConstruct 1200 directory. 1201 1202 If the path name is relative, then the path is looked up relative 1203 to the specified directory, or the current directory (self._cwd, 1204 typically the SConscript directory) if the specified directory 1205 is None. 1206 """ 1207 if isinstance ( p , [Base] ) : 1208 # It's already a Node.FS object. Make sure it's the right 1209 # class and return. 1210 p . [must_be_same] ( fsclass ) 1211 return p 1212 # str(p) in case it's something like a proxy object 1213 p = str ( p ) 1214 1215 if not [os_sep_is_slash] : 1216 p = p . replace ( [OS_SEP] , '/' ) 1217 1218 if p [ 0 : 1 ] == '#' : 1219 # There was an initial '#', so we strip it and override 1220 # whatever directory they may have specified with the 1221 # top-level SConstruct directory. 1222 p = p [ 1 : ] 1223 directory = self . Top 1224 1225 # There might be a drive letter following the 1226 # '#'. Although it is not described in the SCons man page, 1227 # the regression test suite explicitly tests for that 1228 # syntax. It seems to mean the following thing: 1229 # 1230 # Assuming the the SCons top dir is in C:/xxx/yyy, 1231 # '#X:/toto' means X:/xxx/yyy/toto. 1232 # 1233 # i.e. it assumes that the X: drive has a directory 1234 # structure similar to the one found on drive C:. 1235 if [do_splitdrive] : 1236 drive , p = [_my_splitdrive] ( p ) 1237 if drive : 1238 root = self . [get_root] ( drive ) 1239 else : 1240 root = directory . root 1241 else : 1242 root = directory . root 1243 1244 # We can only strip trailing after splitting the drive 1245 # since the drive might the UNC '//' prefix. 1246 p = p . strip ( '/' ) 1247 1248 needs_normpath = [needs_normpath_match] ( p ) 1249 1250 # The path is relative to the top-level SCons directory. 1251 if p in ( '' , '.' ) : 1252 p = directory . labspath 1253 else : 1254 p = directory . labspath + '/' + p 1255 else : 1256 if [do_splitdrive] : 1257 drive , p = [_my_splitdrive] ( p ) 1258 if drive and not p : 1259 # This causes a naked drive letter to be treated 1260 # as a synonym for the root directory on that 1261 # drive. 1262 p = '/' 1263 else : 1264 drive = '' 1265 1266 # We can only strip trailing '/' since the drive might the 1267 # UNC '//' prefix. 1268 if p != '/' : 1269 p = p . rstrip ( '/' ) 1270 1271 needs_normpath = [needs_normpath_match] ( p ) 1272 1273 if p [ 0 : 1 ] == '/' : 1274 # Absolute path 1275 root = self . [get_root] ( drive ) 1276 else : 1277 # This is a relative lookup or to the current directory 1278 # (the path name is not absolute). Add the string to the 1279 # appropriate directory lookup path, after which the whole 1280 # thing gets normalized. 1281 if directory : 1282 if not isinstance ( directory , [Dir] ) : 1283 directory = self . [Dir] ( directory ) 1284 else : 1285 directory = self . _cwd 1286 1287 if p in ( '' , '.' ) : 1288 p = directory . labspath 1289 else : 1290 p = directory . labspath + '/' + p 1291 1292 if drive : 1293 root = self . [get_root] ( drive ) 1294 else : 1295 root = directory . root 1296 1297 if needs_normpath is not None : 1298 # Normalize a pathname. Will return the same result for 1299 # equivalent paths. 1300 # 1301 # We take advantage of the fact that we have an absolute 1302 # path here for sure. In addition, we know that the 1303 # components of lookup path are separated by slashes at 1304 # this point. Because of this, this code is about 2X 1305 # faster than calling os.path.normpath() followed by 1306 # replacing os.sep with '/' again. 1307 ins = p . split ( '/' ) [ 1 : ] 1308 outs = [ ] 1309 for [d] in ins : 1310 if [d] == '..' : 1311 try : 1312 outs . pop ( ) 1313 except IndexError : 1314 pass 1315 elif [d] not in ( '' , '.' ) : 1316 outs . [append] ( [d] ) 1317 p = '/' + '/' . join ( outs ) 1318 1319 return root . [_lookup_abs] ( p , fsclass , create ) 1320 1322 """Look up or create a generic Entry node with the specified name. 1323 If the name is a relative path (begins with ./, ../, or a file 1324 name), then it is looked up relative to the supplied directory 1325 node, or to the top level directory of the FS (supplied at 1326 construction time) if no directory is supplied. 1327 """ 1328 return self . [_lookup] ( name , directory , [Entry] , create ) 1329 1331 """Look up or create a File node with the specified name. If 1332 the name is a relative path (begins with ./, ../, or a file name), 1333 then it is looked up relative to the supplied directory node, 1334 or to the top level directory of the FS (supplied at construction 1335 time) if no directory is supplied. 1336 1337 This method will raise TypeError if a directory is found at the 1338 specified path. 1339 """ 1340 return self . [_lookup] ( name , directory , [File] , create ) 1341 1343 """Look up or create a Dir node with the specified name. If 1344 the name is a relative path (begins with ./, ../, or a file name), 1345 then it is looked up relative to the supplied directory node, 1346 or to the top level directory of the FS (supplied at construction 1347 time) if no directory is supplied. 1348 1349 This method will raise TypeError if a normal file is found at the 1350 specified path. 1351 """ 1352 return self . [_lookup] ( name , directory , [Dir] , create ) 1353 1354 [-] def [VariantDir] ( self , variant_dir , src_dir , duplicate = 1 ) : 1355 """Link the supplied variant directory to the source directory 1356 for purposes of building files.""" 1357 1358 if not isinstance ( src_dir , [SCons] . [Node] . [Node] ) : 1359 src_dir = self . [Dir] ( src_dir ) 1360 if not isinstance ( variant_dir , [SCons] . [Node] . [Node] ) : 1361 variant_dir = self . [Dir] ( variant_dir ) 1362 if src_dir . [is_under] ( variant_dir ) : 1363 raise [SCons] . [Errors] . [UserError] ( "Source directory cannot be under variant directory." ) 1364 if variant_dir . srcdir : 1365 if variant_dir . srcdir == src_dir : 1366 return # We already did this. 1367 raise [SCons] . [Errors] . [UserError] ( "'%s' already has a source directory: '%s'." % ( variant_dir , variant_dir . srcdir ) ) 1368 variant_dir . [link] ( src_dir , duplicate ) 1369 1370 [-] def [Repository] ( self , * dirs ) : 1371 """Specify Repository directories to search.""" 1372 for [d] in dirs : 1373 if not isinstance ( [d] , [SCons] . [Node] . [Node] ) : 1374 [d] = self . [Dir] ( [d] ) 1375 self . Top . [addRepository] ( [d] ) 1376 1377 [-] def [variant_dir_target_climb] ( self , orig , dir , tail ) : 1378 """Create targets in corresponding variant directories 1379 1380 Climb the directory tree, and look up path names 1381 relative to any linked variant directories we find. 1382 1383 Even though this loops and walks up the tree, we don't memoize 1384 the return value because this is really only used to process 1385 the command-line targets. 1386 """ 1387 targets = [ ] 1388 message = None 1389 [fmt] = "building associated VariantDir targets: %s" 1390 start_dir = dir 1391 while dir : 1392 for bd in dir . variant_dirs : 1393 if start_dir . [is_under] ( bd ) : 1394 # If already in the build-dir location, don't reflect 1395 return [ orig ] , [fmt] % str ( orig ) 1396 p = os . [path] . join ( bd . [path] , * tail ) 1397 targets . [append] ( self . [Entry] ( p ) ) 1398 tail = [ dir . name ] + tail 1399 dir = dir . [up] ( ) 1400 if targets : 1401 message = [fmt] % ' ' . join ( map ( str , targets ) ) 1402 return targets , message 1403 1413 1414 [-] class [DirNodeInfo] ( SCons . Node . NodeInfoBase ) : 1415 # This should get reset by the FS initialization. 1416 [current_version_id] = 1 1417 1418 [fs] = None 1419 1420 [-] def [str_to_node] ( self , s ) : 1421 top = self . [fs] . Top 1422 root = top . root 1423 if [do_splitdrive] : 1424 drive , s = [_my_splitdrive] ( s ) 1425 if drive : 1426 root = self . [fs] . [get_root] ( drive ) 1427 if not os . [path] . isabs ( s ) : 1428 s = top . labspath + '/' + s 1429 return root . [_lookup_abs] ( s , [Entry] ) 1430 1431 [-] class [DirBuildInfo] ( SCons . Node . BuildInfoBase ) : 1432 [current_version_id] = 1 1433 1434 [glob_magic_check] = re . compile ( '[*?[]' ) 1435 1436 [-] def [has_glob_magic] ( s ) : 1437 return [glob_magic_check] . search ( s ) is not None 1438 1440 """A class for directories in a file system. 1441 """ 1442 1443 [memoizer_counters] = [ ] 1444 1445 NodeInfo = [DirNodeInfo] 1446 BuildInfo = [DirBuildInfo] 1447 1449 if [SCons] . [Debug] . [track_instances] : [logInstanceCreation] ( self , 'Node.FS.Dir' ) 1450 [Base] . [__init__] ( self , name , directory , [fs] ) 1451 self . [_morph] ( ) 1452 1454 """Turn a file system Node (either a freshly initialized directory 1455 object or a separate Entry object) into a proper directory object. 1456 1457 Set up this directory's entries and hook it into the file 1458 system tree. Specify that directories (this Node) don't use 1459 signatures for calculating whether they're current. 1460 """ 1461 1462 self . repositories = [ ] 1463 self . srcdir = None 1464 1465 self . entries = { } 1466 self . entries [ '.' ] = self 1467 self . entries [ '..' ] = self . dir 1468 self . cwd = self 1469 self . searched = 0 1470 self . _sconsign = None 1471 self . variant_dirs = [ ] 1472 self . root = self . dir . root 1473 1474 # For directories, we make a difference between the directory 1475 # 'name' and the directory 'dirname'. The 'name' attribute is 1476 # used when we need to print the 'name' of the directory or 1477 # when we it is used as the last part of a path. The 'dirname' 1478 # is used when the directory is not the last element of the 1479 # path. The main reason for making that distinction is that 1480 # for RoorDir's the dirname can not be easily inferred from 1481 # the name. For example, we have to add a '/' after a drive 1482 # letter but not after a UNC path prefix ('//'). 1483 self . dirname = self . name + [OS_SEP] 1484 1485 # Don't just reset the executor, replace its action list, 1486 # because it might have some pre-or post-actions that need to 1487 # be preserved. 1488 # 1489 # But don't reset the executor if there is a non-null executor 1490 # attached already. The existing executor might have other 1491 # targets, in which case replacing the action list with a 1492 # Mkdir action is a big mistake. 1493 if not hasattr ( self , 'executor' ) : 1494 self . builder = [get_MkdirBuilder] ( ) 1495 self . [get_executor] ( ) . [set_action_list] ( self . builder . action ) 1496 else : 1497 # Prepend MkdirBuilder action to existing action list 1498 l = self . [get_executor] ( ) . action_list 1499 a = [get_MkdirBuilder] ( ) . action 1500 l . [insert] ( 0 , a ) 1501 self . [get_executor] ( ) . [set_action_list] ( l ) 1502 1503 [-] def [diskcheck_match] ( self ) : 1504 [diskcheck_match] ( self , self . [isfile] , 1505 "File %s found where directory expected." ) 1506 1507 [-] def [__clearRepositoryCache] ( self , duplicate = None ) : 1508 """Called when we change the repository(ies) for a directory. 1509 This clears any cached information that is invalidated by changing 1510 the repository.""" 1511 1512 for node in self . entries . [values] ( ) : 1513 if node != self . dir : 1514 if node != self and isinstance ( node , [Dir] ) : 1515 node . [__clearRepositoryCache] ( duplicate ) 1516 else : 1517 node . [clear] ( ) 1518 try : 1519 del node . _srcreps 1520 except AttributeError : 1521 pass 1522 if duplicate is not None : 1523 node . duplicate = duplicate 1524 1525 [-] def [__resetDuplicate] ( self , node ) : 1526 if node != self : 1527 node . duplicate = node . [get_dir] ( ) . duplicate 1528 1530 """ 1531 Looks up or creates an entry node named 'name' relative to 1532 this directory. 1533 """ 1534 return self . [fs] . [Entry] ( name , self ) 1535 1537 """ 1538 Looks up or creates a directory node named 'name' relative to 1539 this directory. 1540 """ 1541 return self . [fs] . [Dir] ( name , self , create ) 1542 1544 """ 1545 Looks up or creates a file node named 'name' relative to 1546 this directory. 1547 """ 1548 return self . [fs] . [File] ( name , self ) 1549 1551 """Set this directory as the variant directory for the 1552 supplied source directory.""" 1553 self . srcdir = srcdir 1554 self . duplicate = duplicate 1555 self . [__clearRepositoryCache] ( duplicate ) 1556 srcdir . variant_dirs . [append] ( self ) 1557 1558 [-] def [getRepositories] ( self ) : 1559 """Returns a list of repositories for this directory. 1560 """ 1561 if self . srcdir and not self . duplicate : 1562 return self . srcdir . [get_all_rdirs] ( ) + self . repositories 1563 return self . repositories 1564 1565 [memoizer_counters] . [append] ( [SCons] . [Memoize] . [CountValue] ( 'get_all_rdirs' ) ) 1566 1567 [-] def [get_all_rdirs] ( self ) : 1568 try : 1569 return list ( self . _memo [ 'get_all_rdirs' ] ) 1570 except KeyError : 1571 pass 1572 1573 [result] = [ self ] 1574 fname = '.' 1575 dir = self 1576 while dir : 1577 for rep in dir . [getRepositories] ( ) : 1578 [result] . [append] ( rep . [Dir] ( fname ) ) 1579 if fname == '.' : 1580 fname = dir . name 1581 else : 1582 fname = dir . name + [OS_SEP] + fname 1583 dir = dir . [up] ( ) 1584 1585 self . _memo [ 'get_all_rdirs' ] = list ( [result] ) 1586 1587 return [result] 1588 1589 [-] def [addRepository] ( self , dir ) : 1590 if dir != self and not dir in self . repositories : 1591 self . repositories . [append] ( dir ) 1592 dir . tpath = '.' 1593 self . [__clearRepositoryCache] ( ) 1594 1597 1598 [-] def [_rel_path_key] ( self , other ) : 1600 1601 [memoizer_counters] . [append] ( [SCons] . [Memoize] . [CountDict] ( 'rel_path' , [_rel_path_key] ) ) 1602 1604 """Return a path to "other" relative to this directory. 1605 """ 1606 1607 # This complicated and expensive method, which constructs relative 1608 # paths between arbitrary Node.FS objects, is no longer used 1609 # by SCons itself. It was introduced to store dependency paths 1610 # in .sconsign files relative to the target, but that ended up 1611 # being significantly inefficient. 1612 # 1613 # We're continuing to support the method because some SConstruct 1614 # files out there started using it when it was available, and 1615 # we're all about backwards compatibility.. 1616 1617 try : 1618 memo_dict = self . _memo [ 'rel_path' ] 1619 except KeyError : 1620 memo_dict = { } 1621 self . _memo [ 'rel_path' ] = memo_dict 1622 else : 1623 try : 1624 return memo_dict [ other ] 1625 except KeyError : 1626 pass 1627 1628 if self is other : 1629 [result] = '.' 1630 1631 elif not other in self . path_elements : 1632 try : 1633 other_dir = other . [get_dir] ( ) 1634 except AttributeError : 1635 [result] = str ( other ) 1636 else : 1637 if other_dir is None : 1638 [result] = other . name 1639 else : 1640 dir_rel_path = self . [rel_path] ( other_dir ) 1641 if dir_rel_path == '.' : 1642 [result] = other . name 1643 else : 1644 [result] = dir_rel_path + [OS_SEP] + other . name 1645 else : 1646 i = self . path_elements . [index] ( other ) + 1 1647 1648 path_elems = [ '..' ] * ( len ( self . path_elements ) - i )\ 1649 + [ n . name for n in other . path_elements [ i : ] ] 1650 1651 [result] = [OS_SEP] . join ( path_elems ) 1652 1653 memo_dict [ other ] = [result] 1654 1655 return [result] 1656 1657 [-] def [get_env_scanner] ( self , env , kw = { } ) : 1658 import [SCons] . [Defaults] 1659 return [SCons] . [Defaults] . [DirEntryScanner] 1660 1661 [-] def [get_target_scanner] ( self ) : 1662 import [SCons] . [Defaults] 1663 return [SCons] . [Defaults] . [DirEntryScanner] 1664 1665 [-] def [get_found_includes] ( self , env , scanner , path ) : 1666 """Return this directory's implicit dependencies. 1667 1668 We don't bother caching the results because the scan typically 1669 shouldn't be requested more than once (as opposed to scanning 1670 .h file contents, which can be requested as many times as the 1671 files is #included by other files). 1672 """ 1673 if not scanner : 1674 return [ ] 1675 # Clear cached info for this Dir. If we already visited this 1676 # directory on our walk down the tree (because we didn't know at 1677 # that point it was being used as the source for another Node) 1678 # then we may have calculated build signature before realizing 1679 # we had to scan the disk. Now that we have to, though, we need 1680 # to invalidate the old calculated signature so that any node 1681 # dependent on our directory structure gets one that includes 1682 # info about everything on disk. 1683 self . [clear] ( ) 1684 return scanner ( self , env , [path] ) 1685 1686 # 1687 # Taskmaster interface subsystem 1688 # 1689 1692 1694 """A null "builder" for directories.""" 1695 global [MkdirBuilder] 1696 if self . builder is not [MkdirBuilder] : 1697 [SCons] . [Node] . [Node] . [build] ( self , ** kw ) 1698 1699 # 1700 # 1701 # 1702 1704 """Create this directory, silently and without worrying about 1705 whether the builder is the default or not.""" 1706 listDirs = [ ] 1707 parent = self 1708 while parent : 1709 if parent . [exists] ( ) : 1710 break 1711 listDirs . [append] ( parent ) 1712 p = parent . [up] ( ) 1713 if p is None : 1714 # Don't use while: - else: for this condition because 1715 # if so, then parent is None and has no .path attribute. 1716 raise [SCons] . [Errors] . [StopError] ( parent . [path] ) 1717 parent = p 1718 listDirs . [reverse] ( ) 1719 for dirnode in listDirs : 1720 try : 1721 # Don't call dirnode.build(), call the base Node method 1722 # directly because we definitely *must* create this 1723 # directory. The dirnode.build() method will suppress 1724 # the build if it's the default builder. 1725 [SCons] . [Node] . [Node] . [build] ( dirnode ) 1726 dirnode . [get_executor] ( ) . [nullify] ( ) 1727 # The build() action may or may not have actually 1728 # created the directory, depending on whether the -n 1729 # option was used or not. Delete the _exists and 1730 # _rexists attributes so they can be reevaluated. 1731 dirnode . [clear] ( ) 1732 except OSError : 1733 pass 1734 1735 [-] def [multiple_side_effect_has_builder] ( self ) : 1736 global [MkdirBuilder] 1737 return self . builder is not [MkdirBuilder] and self . [has_builder] ( ) 1738 1739 [-] def [alter_targets] ( self ) : 1740 """Return any corresponding targets in a variant directory. 1741 """ 1742 return self . [fs] . [variant_dir_target_climb] ( self , self , [ ] ) 1743 1744 [-] def [scanner_key] ( self ) : 1747 1748 [-] def [get_text_contents] ( self ) : 1749 """We already emit things in text, so just return the binary 1750 version.""" 1751 return self . [get_contents] ( ) 1752 1753 [-] def [get_contents] ( self ) : 1754 """Return content signatures and names of all our children 1755 separated by new-lines. Ensure that the nodes are sorted.""" 1756 contents = [ ] 1757 for node in sorted ( self . [children] ( ) , key = lambda t : t . name ) : 1758 contents . [append] ( '%s %s\n' % ( node . [get_csig] ( ) , node . name ) ) 1759 return '' . join ( contents ) 1760 1762 """Compute the content signature for Directory nodes. In 1763 general, this is not needed and the content signature is not 1764 stored in the DirNodeInfo. However, if get_contents on a Dir 1765 node is called which has a child directory, the child 1766 directory should return the hash of its contents.""" 1767 contents = self . [get_contents] ( ) 1768 return [SCons] . [Util] . MD5signature ( contents ) 1769 1770 [-] def [do_duplicate] ( self , src ) : 1772 1773 [changed_since_last_build] = [SCons] . [Node] . [Node] . [state_has_changed] 1774 1775 [-] def [is_up_to_date] ( self ) : 1776 """If any child is not up-to-date, then this directory isn't, 1777 either.""" 1778 if self . builder is not [MkdirBuilder] and not self . [exists] ( ) : 1779 return 0 1780 [up_to_date] = [SCons] . [Node] . [up_to_date] 1781 for kid in self . [children] ( ) : 1782 if kid . [get_state] ( ) > [up_to_date] : 1783 return 0 1784 return 1 1785 1787 if not self . [exists] ( ) : 1788 norm_name = [_my_normcase] ( self . name ) 1789 for dir in self . dir . [get_all_rdirs] ( ) : 1790 try : node = dir . entries [ norm_name ] 1791 except KeyError : node = dir . [dir_on_disk] ( self . name ) 1792 if node and node . [exists] ( ) and\ 1793 ( isinstance ( dir , [Dir] ) or isinstance ( dir , [Entry] ) ) : 1794 return node 1795 return self 1796 1798 """Return the .sconsign file info for this directory, 1799 creating it first if necessary.""" 1800 if not self . _sconsign : 1801 import [SCons] . [SConsign] 1802 self . _sconsign = [SCons] . [SConsign] . ForDirectory ( self ) 1803 return self . _sconsign 1804 1806 """Dir has a special need for srcnode()...if we 1807 have a srcdir attribute set, then that *is* our srcnode.""" 1808 if self . srcdir : 1809 return self . srcdir 1810 return [Base] . [srcnode] ( self ) 1811 1812 [-] def [get_timestamp] ( self ) : 1813 """Return the latest timestamp from among our children""" 1814 stamp = 0 1815 for kid in self . [children] ( ) : 1816 if kid . [get_timestamp] ( ) > stamp : 1817 stamp = kid . [get_timestamp] ( ) 1818 return stamp 1819 1820 [-] def [entry_abspath] ( self , name ) : 1821 return self . abspath + [OS_SEP] + name 1822 1823 [-] def [entry_labspath] ( self , name ) : 1825 1826 [-] def [entry_path] ( self , name ) : 1828 1829 [-] def [entry_tpath] ( self , name ) : 1830 return self . tpath + [OS_SEP] + name 1831 1832 [-] def [entry_exists_on_disk] ( self , name ) : 1833 try : 1834 [d] = self . on_disk_entries 1835 except AttributeError : 1836 [d] = { } 1837 try : 1838 entries = os . [listdir] ( self . abspath ) 1839 except OSError : 1840 pass 1841 else : 1842 for entry in map ( [_my_normcase] , entries ) : 1843 [d] [ entry ] = True 1844 self . on_disk_entries = [d] 1845 if sys . platform == 'win32' or sys . platform == 'cygwin' : 1846 name = [_my_normcase] ( name ) 1847 [result] = [d] . [get] ( name ) 1848 if [result] is None : 1849 # Belt-and-suspenders for Windows: check directly for 1850 # 8.3 file names that don't show up in os.listdir(). 1851 [result] = os . [path] . [exists] ( self . abspath + [OS_SEP] + name ) 1852 [d] [ name ] = [result] 1853 return [result] 1854 else : 1855 return name in [d] 1856 1857 [memoizer_counters] . [append] ( [SCons] . [Memoize] . [CountValue] ( 'srcdir_list' ) ) 1858 1859 [-] def [srcdir_list] ( self ) : 1860 try : 1861 return self . _memo [ 'srcdir_list' ] 1862 except KeyError : 1863 pass 1864 1865 [result] = [ ] 1866 1867 dirname = '.' 1868 dir = self 1869 while dir : 1870 if dir . srcdir : 1871 [result] . [append] ( dir . srcdir . [Dir] ( dirname ) ) 1872 dirname = dir . name + [OS_SEP] + dirname 1873 dir = dir . [up] ( ) 1874 1875 self . _memo [ 'srcdir_list' ] = [result] 1876 1877 return [result] 1878 1879 [-] def [srcdir_duplicate] ( self , name ) : 1880 for dir in self . [srcdir_list] ( ) : 1881 if self . [is_under] ( dir ) : 1882 # We shouldn't source from something in the build path; 1883 # variant_dir is probably under src_dir, in which case 1884 # we are reflecting. 1885 break 1886 if dir . [entry_exists_on_disk] ( name ) : 1887 [srcnode] = dir . [Entry] ( name ) . [disambiguate] ( ) 1888 if self . duplicate : 1889 node = self . [Entry] ( name ) . [disambiguate] ( ) 1890 node . [do_duplicate] ( [srcnode] ) 1891 return node 1892 else : 1893 return [srcnode] 1894 return None 1895 1896 [-] def [_srcdir_find_file_key] ( self , filename ) : 1898 1899 [memoizer_counters] . [append] ( [SCons] . [Memoize] . [CountDict] ( 'srcdir_find_file' , [_srcdir_find_file_key] ) ) 1900 1901 [-] def [srcdir_find_file] ( self , filename ) : 1902 try : 1903 memo_dict = self . _memo [ 'srcdir_find_file' ] 1904 except KeyError : 1905 memo_dict = { } 1906 self . _memo [ 'srcdir_find_file' ] = memo_dict 1907 else : 1908 try : 1909 return memo_dict [ filename ] 1910 except KeyError : 1911 pass 1912 1913 def func ( node ) : 1914 if ( isinstance ( node , [File] ) or isinstance ( node , [Entry] ) ) and\ 1915 ( node . [is_derived] ( ) or node . [exists] ( ) ) : 1916 return node 1917 return None 1918 1919 norm_name = [_my_normcase] ( filename ) 1920 1921 for [rdir] in self . [get_all_rdirs] ( ) : 1922 try : node = [rdir] . entries [ norm_name ] 1923 except KeyError : node = [rdir] . [file_on_disk] ( filename ) 1924 else : node = func ( node ) 1925 if node : 1926 [result] = ( node , self ) 1927 memo_dict [ filename ] = [result] 1928 return [result] 1929 1930 for srcdir in self . [srcdir_list] ( ) : 1931 for [rdir] in srcdir . [get_all_rdirs] ( ) : 1932 try : node = [rdir] . entries [ norm_name ] 1933 except KeyError : node = [rdir] . [file_on_disk] ( filename ) 1934 else : node = func ( node ) 1935 if node : 1936 [result] = ( [File] ( filename , self , self . [fs] ) , srcdir ) 1937 memo_dict [ filename ] = [result] 1938 return [result] 1939 1940 [result] = ( None , None ) 1941 memo_dict [ filename ] = [result] 1942 return [result] 1943 1944 [-] def [dir_on_disk] ( self , name ) : 1945 if self . [entry_exists_on_disk] ( name ) : 1946 try : return self . [Dir] ( name ) 1947 except TypeError : pass 1948 node = self . [srcdir_duplicate] ( name ) 1949 if isinstance ( node , [File] ) : 1950 return None 1951 return node 1952 1953 [-] def [file_on_disk] ( self , name ) : 1954 if self . [entry_exists_on_disk] ( name ) or\ 1955 [diskcheck_rcs] ( self , name ) or\ 1956 [diskcheck_sccs] ( self , name ) : 1957 try : return self . [File] ( name ) 1958 except TypeError : pass 1959 node = self . [srcdir_duplicate] ( name ) 1960 if isinstance ( node , [Dir] ) : 1961 return None 1962 return node 1963 1965 """ 1966 Walk this directory tree by calling the specified function 1967 for each directory in the tree. 1968 1969 This behaves like the os.path.walk() function, but for in-memory 1970 Node.FS.Dir objects. The function takes the same arguments as 1971 the functions passed to os.path.walk(): 1972 1973 func(arg, dirname, fnames) 1974 1975 Except that "dirname" will actually be the directory *Node*, 1976 not the string. The '.' and '..' entries are excluded from 1977 fnames. The fnames list may be modified in-place to filter the 1978 subdirectories visited or otherwise impose a specific order. 1979 The "arg" argument is always passed to func() and may be used 1980 in any way (or ignored, passing None is common). 1981 """ 1982 entries = self . entries 1983 names = list ( entries . [keys] ( ) ) 1984 names . [remove] ( '.' ) 1985 names . [remove] ( '..' ) 1986 func ( arg , self , names ) 1987 for dirname in [ n for n in names if isinstance ( entries [ n ] , [Dir] ) ] : 1988 entries [ dirname ] . [walk] ( func , arg ) 1989 1991 """ 1992 Returns a list of Nodes (or strings) matching a specified 1993 pathname pattern. 1994 1995 Pathname patterns follow UNIX shell semantics: * matches 1996 any-length strings of any characters, ? matches any character, 1997 and [] can enclose lists or ranges of characters. Matches do 1998 not span directory separators. 1999 2000 The matches take into account Repositories, returning local 2001 Nodes if a corresponding entry exists in a Repository (either 2002 an in-memory Node or something on disk). 2003 2004 By defafult, the glob() function matches entries that exist 2005 on-disk, in addition to in-memory Nodes. Setting the "ondisk" 2006 argument to False (or some other non-true value) causes the glob() 2007 function to only match in-memory Nodes. The default behavior is 2008 to return both the on-disk and in-memory Nodes. 2009 2010 The "source" argument, when true, specifies that corresponding 2011 source Nodes must be returned if you're globbing in a build 2012 directory (initialized with VariantDir()). The default behavior 2013 is to return Nodes local to the VariantDir(). 2014 2015 The "strings" argument, when true, returns the matches as strings, 2016 not Nodes. The strings are path names relative to this directory. 2017 2018 The underlying algorithm is adapted from the glob.glob() function 2019 in the Python library (but heavily modified), and uses fnmatch() 2020 under the covers. 2021 """ 2022 dirname , basename = os . [path] . split ( pathname ) 2023 if not dirname : 2024 return sorted ( self . [_glob1] ( basename , ondisk , source , strings ) , 2025 key = lambda t : str ( t ) ) 2026 if [has_glob_magic] ( dirname ) : 2027 list = self . [glob] ( dirname , ondisk , source , strings = False ) 2028 else : 2029 list = [ self . [Dir] ( dirname , create = True ) ] 2030 [result] = [ ] 2031 for dir in list : 2032 r = dir . [_glob1] ( basename , ondisk , source , strings ) 2033 if strings : 2034 r = [ os . [path] . join ( str ( dir ) , [x] ) for [x] in r ] 2035 [result] . [extend] ( r ) 2036 return sorted ( [result] , key = lambda a : str ( a ) ) 2037 2039 """ 2040 Globs for and returns a list of entry names matching a single 2041 pattern in this directory. 2042 2043 This searches any repositories and source directories for 2044 corresponding entries and returns a Node (or string) relative 2045 to the current directory if an entry is found anywhere. 2046 2047 TODO: handle pattern with no wildcard 2048 """ 2049 search_dir_list = self . [get_all_rdirs] ( ) 2050 for srcdir in self . [srcdir_list] ( ) : 2051 search_dir_list . [extend] ( srcdir . [get_all_rdirs] ( ) ) 2052 2053 selfEntry = self . [Entry] 2054 names = [ ] 2055 for dir in search_dir_list : 2056 # We use the .name attribute from the Node because the keys of 2057 # the dir.entries dictionary are normalized (that is, all upper 2058 # case) on case-insensitive systems like Windows. 2059 node_names = [ v . name for k , v in dir . entries . [items] ( ) 2060 if k not in ( '.' , '..' ) ] 2061 names . [extend] ( node_names ) 2062 if not strings : 2063 # Make sure the working directory (self) actually has 2064 # entries for all Nodes in repositories or variant dirs. 2065 for name in node_names : selfEntry ( name ) 2066 if ondisk : 2067 try : 2068 disk_names = os . [listdir] ( dir . abspath ) 2069 except os . error : 2070 continue 2071 names . [extend] ( disk_names ) 2072 if not strings : 2073 # We're going to return corresponding Nodes in 2074 # the local directory, so we need to make sure 2075 # those Nodes exist. We only want to create 2076 # Nodes for the entries that will match the 2077 # specified pattern, though, which means we 2078 # need to filter the list here, even though 2079 # the overall list will also be filtered later, 2080 # after we exit this loop. 2081 if pattern [ 0 ] != '.' : 2082 #disk_names = [ d for d in disk_names if d[0] != '.' ] 2083 disk_names = [ [x] for [x] in disk_names if [x] [ 0 ] != '.' ] 2084 disk_names = fnmatch . filter ( disk_names , pattern ) 2085 dirEntry = dir . [Entry] 2086 for name in disk_names : 2087 # Add './' before disk filename so that '#' at 2088 # beginning of filename isn't interpreted. 2089 name = './' + name 2090 node = dirEntry ( name ) . [disambiguate] ( ) 2091 n = selfEntry ( name ) 2092 if n . __class__ != node . __class__ : 2093 n . __class__ = node . __class__ 2094 n . [_morph] ( ) 2095 2096 names = [set] ( names ) 2097 if pattern [ 0 ] != '.' : 2098 #names = [ n for n in names if n[0] != '.' ] 2099 names = [ [x] for [x] in names if [x] [ 0 ] != '.' ] 2100 names = fnmatch . filter ( names , pattern ) 2101 2102 if strings : 2103 return names 2104 2105 #return [ self.entries[_my_normcase(n)] for n in names ] 2106 return [ self . entries [ [_my_normcase] ( n ) ] for n in names ] 2107 2109 """A class for the root directory of a file system. 2110 2111 This is the same as a Dir class, except that the path separator 2112 ('/' or '\\') is actually part of the name, so we don't need to 2113 add a separator when creating the path names of entries within 2114 this directory. 2115 """ 2117 if [SCons] . [Debug] . [track_instances] : [logInstanceCreation] ( self , 'Node.FS.RootDir' ) 2118 # We're going to be our own parent directory (".." entry and .dir 2119 # attribute) so we have to set up some values so Base.__init__() 2120 # won't gag won't it calls some of our methods. 2121 self . abspath = '' 2122 self . labspath = '' 2123 self . [path] = '' 2124 self . tpath = '' 2125 self . path_elements = [ ] 2126 self . duplicate = 0 2127 self . root = self 2128 2129 # Handle all the types of drives: 2130 if drive == '' : 2131 # No drive, regular UNIX root or Windows default drive. 2132 name = [OS_SEP] 2133 dirname = [OS_SEP] 2134 elif drive == '//' : 2135 # UNC path 2136 name = [UNC_PREFIX] 2137 dirname = [UNC_PREFIX] 2138 else : 2139 # Windows drive letter 2140 name = drive 2141 dirname = drive + [OS_SEP] 2142 2143 [Base] . [__init__] ( self , name , self , [fs] ) 2144 2145 # Now set our paths to what we really want them to be. The 2146 # name should already contain any necessary separators, such 2147 # as the initial drive letter (the name) plus the directory 2148 # separator, except for the "lookup abspath," which does not 2149 # have the drive letter. 2150 self . abspath = dirname 2151 self . labspath = '' 2152 self . [path] = dirname 2153 self . tpath = dirname 2154 self . [_morph] ( ) 2155 2156 # Must be reset after Dir._morph() is invoked... 2157 self . dirname = dirname 2158 2159 self . _lookupDict = { } 2160 2161 self . _lookupDict [ '' ] = self 2162 self . _lookupDict [ '/' ] = self 2163 2164 # The // entry is necessary because os.path.normpath() 2165 # preserves double slashes at the beginning of a path on Posix 2166 # platforms. 2167 if not [has_unc] : 2168 self . _lookupDict [ '//' ] = self 2169 2170 [-] def [must_be_same] ( self , klass ) : 2171 if klass is [Dir] : 2172 return 2173 [Base] . [must_be_same] ( self , klass ) 2174 2175 [-] def [_lookup_abs] ( self , p , klass , create = 1 ) : 2176 """ 2177 Fast (?) lookup of a *normalized* absolute path. 2178 2179 This method is intended for use by internal lookups with 2180 already-normalized path data. For general-purpose lookups, 2181 use the FS.Entry(), FS.Dir() or FS.File() methods. 2182 2183 The caller is responsible for making sure we're passed a 2184 normalized absolute path; we merely let Python's dictionary look 2185 up and return the One True Node.FS object for the path. 2186 2187 If a Node for the specified "p" doesn't already exist, and 2188 "create" is specified, the Node may be created after recursive 2189 invocation to find or create the parent directory or directories. 2190 """ 2191 k = [_my_normcase] ( p ) 2192 try : 2193 [result] = self . _lookupDict [ k ] 2194 except KeyError : 2195 if not create : 2196 [msg] = "No such file or directory: '%s' in '%s' (and create is False)" % ( p , str ( self ) ) 2197 raise [SCons] . [Errors] . [UserError] ( [msg] ) 2198 # There is no Node for this path name, and we're allowed 2199 # to create it. 2200 # (note: would like to use p.rsplit('/',1) here but 2201 # that's not in python 2.3) 2202 # e.g.: dir_name, file_name = p.rsplit('/',1) 2203 last_slash = p . rindex ( '/' ) 2204 if ( last_slash >= 0 ) : 2205 dir_name = p [ : last_slash ] 2206 file_name = p [ last_slash + 1 : ] 2207 else : 2208 dir_name = p # shouldn't happen, just in case 2209 file_name = '' 2210 2211 dir_node = self . [_lookup_abs] ( dir_name , [Dir] ) 2212 [result] = klass ( file_name , dir_node , self . [fs] ) 2213 2214 # Double-check on disk (as configured) that the Node we 2215 # created matches whatever is out there in the real world. 2216 [result] . [diskcheck_match] ( ) 2217 2218 self . _lookupDict [ k ] = [result] 2219 dir_node . entries [ [_my_normcase] ( file_name ) ] = [result] 2220 dir_node . implicit = None 2221 else : 2222 # There is already a Node for this path name. Allow it to 2223 # complain if we were looking for an inappropriate type. 2224 [result] . [must_be_same] ( klass ) 2225 return [result] 2226 2229 2230 [-] def [entry_abspath] ( self , name ) : 2232 2233 [-] def [entry_labspath] ( self , name ) : 2235 2236 [-] def [entry_path] ( self , name ) : 2237 return self . [path] + name 2238 2239 [-] def [entry_tpath] ( self , name ) : 2241 2247 2250 2253 2254 [-] def [src_builder] ( self ) : 2255 return [_null] 2256 2257 [-] class [FileNodeInfo] ( SCons . Node . NodeInfoBase ) : 2258 [current_version_id] = 1 2259 2260 [field_list] = [ 'csig' , 'timestamp' , 'size' ] 2261 2262 # This should get reset by the FS initialization. 2263 [fs] = None 2264 2265 [-] def [str_to_node] ( self , s ) : 2266 top = self . [fs] . Top 2267 root = top . root 2268 if [do_splitdrive] : 2269 drive , s = [_my_splitdrive] ( s ) 2270 if drive : 2271 root = self . [fs] . [get_root] ( drive ) 2272 if not os . [path] . isabs ( s ) : 2273 s = top . labspath + '/' + s 2274 return root . [_lookup_abs] ( s , [Entry] ) 2275 2276 [-] class [FileBuildInfo] ( SCons . Node . BuildInfoBase ) : 2277 [current_version_id] = 1 2278 2279 [-] def [convert_to_sconsign] ( self ) : 2280 """ 2281 Converts this FileBuildInfo object for writing to a .sconsign file 2282 2283 This replaces each Node in our various dependency lists with its 2284 usual string representation: relative to the top-level SConstruct 2285 directory, or an absolute path if it's outside. 2286 """ 2287 if [os_sep_is_slash] : 2288 node_to_str = str 2289 else : 2290 def node_to_str ( n ) : 2291 try : 2292 s = n . [path] 2293 except AttributeError : 2294 s = str ( n ) 2295 else : 2296 s = s . replace ( [OS_SEP] , '/' ) 2297 return s 2298 for attr in [ 'bsources' , 'bdepends' , 'bimplicit' ] : 2299 try : 2300 val = getattr ( self , attr ) 2301 except AttributeError : 2302 pass 2303 else : 2304 setattr ( self , attr , list ( map ( node_to_str , val ) ) ) 2305 [-] def [convert_from_sconsign] ( self , dir , name ) : 2306 """ 2307 Converts a newly-read FileBuildInfo object for in-SCons use 2308 2309 For normal up-to-date checking, we don't have any conversion to 2310 perform--but we're leaving this method here to make that clear. 2311 """ 2312 pass 2313 [-] def [prepare_dependencies] ( self ) : 2314 """ 2315 Prepares a FileBuildInfo object for explaining what changed 2316 2317 The bsources, bdepends and bimplicit lists have all been 2318 stored on disk as paths relative to the top-level SConstruct 2319 directory. Convert the strings to actual Nodes (for use by the 2320 --debug=explain code and --implicit-cache). 2321 """ 2322 attrs = [ 2323 ( 'bsources' , 'bsourcesigs' ) , 2324 ( 'bdepends' , 'bdependsigs' ) , 2325 ( 'bimplicit' , 'bimplicitsigs' ) , 2326 ] 2327 for ( nattr , sattr ) in attrs : 2328 try : 2329 strings = getattr ( self , nattr ) 2330 nodeinfos = getattr ( self , sattr ) 2331 except AttributeError : 2332 continue 2333 nodes = [ ] 2334 for s , ni in zip ( strings , nodeinfos ) : 2335 if not isinstance ( s , [SCons] . [Node] . [Node] ) : 2336 s = ni . [str_to_node] ( s ) 2337 nodes . [append] ( s ) 2338 setattr ( self , nattr , nodes ) 2340 [result] = [ ] 2341 bkids = self . bsources + self . bdepends + self . bimplicit 2342 bkidsigs = self . bsourcesigs + self . bdependsigs + self . bimplicitsigs 2343 for bkid , bkidsig in zip ( bkids , bkidsigs ) : 2344 [result] . [append] ( str ( bkid ) + ': ' + 2345 ' ' . join ( bkidsig . [format] ( names = names ) ) ) 2346 [result] . [append] ( '%s [%s]' % ( self . bactsig , self . bact ) ) 2347 return '\n' . join ( [result] ) 2348 2350 """A class for files in a file system. 2351 """ 2352 2353 [memoizer_counters] = [ ] 2354 2355 NodeInfo = [FileNodeInfo] 2356 BuildInfo = [FileBuildInfo] 2357 2358 [md5_chunksize] = 64 2359 2360 [-] def [diskcheck_match] ( self ) : 2361 [diskcheck_match] ( self , self . [isdir] , 2362 "Directory %s found where file expected." ) 2363 2365 if [SCons] . [Debug] . [track_instances] : [logInstanceCreation] ( self , 'Node.FS.File' ) 2366 [Base] . [__init__] ( self , name , directory , [fs] ) 2367 self . [_morph] ( ) 2368 2370 """Create an entry node named 'name' relative to 2371 the directory of this file.""" 2372 return self . dir . [Entry] ( name ) 2373 2375 """Create a directory node named 'name' relative to 2376 the directory of this file.""" 2377 return self . dir . [Dir] ( name , create = create ) 2378 2380 """Create a list of directories relative to the SConscript 2381 directory of this file.""" 2382 return [ self . [Dir] ( p ) for p in pathlist ] 2383 2385 """Create a file node named 'name' relative to 2386 the directory of this file.""" 2387 return self . dir . [File] ( name ) 2388 2389 #def generate_build_dict(self): 2390 # """Return an appropriate dictionary of values for building 2391 # this File.""" 2392 # return {'Dir' : self.Dir, 2393 # 'File' : self.File, 2394 # 'RDirs' : self.RDirs} 2395 2397 """Turn a file system node into a File object.""" 2398 self . scanner_paths = { } 2399 if not hasattr ( self , '_local' ) : 2400 self . _local = 0 2401 if not hasattr ( self , 'released_target_info' ) : 2402 self . released_target_info = False 2403 2404 # If there was already a Builder set on this entry, then 2405 # we need to make sure we call the target-decider function, 2406 # not the source-decider. Reaching in and doing this by hand 2407 # is a little bogus. We'd prefer to handle this by adding 2408 # an Entry.builder_set() method that disambiguates like the 2409 # other methods, but that starts running into problems with the 2410 # fragile way we initialize Dir Nodes with their Mkdir builders, 2411 # yet still allow them to be overridden by the user. Since it's 2412 # not clear right now how to fix that, stick with what works 2413 # until it becomes clear... 2414 if self . [has_builder] ( ) : 2415 self . [changed_since_last_build] = self . [decide_target] 2416 2417 [-] def [scanner_key] ( self ) : 2418 return self . [get_suffix] ( ) 2419 2420 [-] def [get_contents] ( self ) : 2421 if not self . [rexists] ( ) : 2422 return '' 2423 fname = self . [rfile] ( ) . abspath 2424 try : 2425 contents = [open] ( fname , "rb" ) . [read] ( ) 2426 except [EnvironmentError] , [e] : 2427 if not [e] . filename : 2428 [e] . filename = fname 2429 raise 2430 return contents 2431 2432 # This attempts to figure out what the encoding of the text is 2433 # based upon the BOM bytes, and then decodes the contents so that 2434 # it's a valid python string. 2435 [-] def [get_text_contents] ( self ) : 2436 contents = self . [get_contents] ( ) 2437 # The behavior of various decode() methods and functions 2438 # w.r.t. the initial BOM bytes is different for different 2439 # encodings and/or Python versions. ('utf-8' does not strip 2440 # them, but has a 'utf-8-sig' which does; 'utf-16' seems to 2441 # strip them; etc.) Just sidestep all the complication by 2442 # explicitly stripping the BOM before we decode(). 2443 if contents . startswith ( codecs . BOM_UTF8 ) : 2444 return contents [ len ( codecs . BOM_UTF8 ) : ] . decode ( 'utf-8' ) 2445 if contents . startswith ( codecs . BOM_UTF16_LE ) : 2446 return contents [ len ( codecs . BOM_UTF16_LE ) : ] . decode ( 'utf-16-le' ) 2447 if contents . startswith ( codecs . BOM_UTF16_BE ) : 2448 return contents [ len ( codecs . BOM_UTF16_BE ) : ] . decode ( 'utf-16-be' ) 2449 return contents 2450 2451 [-] def [get_content_hash] ( self ) : 2452 """ 2453 Compute and return the MD5 hash for this file. 2454 """ 2455 if not self . [rexists] ( ) : 2456 return [SCons] . [Util] . MD5signature ( '' ) 2457 fname = self . [rfile] ( ) . abspath 2458 try : 2459 cs = [SCons] . [Util] . MD5filesignature ( fname , 2460 chunksize = [SCons] . [Node] . [FS] . [File] . [md5_chunksize] * 1024 ) 2461 except [EnvironmentError] , [e] : 2462 if not [e] . filename : 2463 [e] . filename = fname 2464 raise 2465 return cs 2466 2467 2468 [memoizer_counters] . [append] ( [SCons] . [Memoize] . [CountValue] ( 'get_size' ) ) 2469 2471 try : 2472 return self . _memo [ 'get_size' ] 2473 except KeyError : 2474 pass 2475 2476 if self . [rexists] ( ) : 2477 size = self . [rfile] ( ) . [getsize] ( ) 2478 else : 2479 size = 0 2480 2481 self . _memo [ 'get_size' ] = size 2482 2483 return size 2484 2485 [memoizer_counters] . [append] ( [SCons] . [Memoize] . [CountValue] ( 'get_timestamp' ) ) 2486 2487 [-] def [get_timestamp] ( self ) : 2488 try : 2489 return self . _memo [ 'get_timestamp' ] 2490 except KeyError : 2491 pass 2492 2493 if self . [rexists] ( ) : 2494 timestamp = self . [rfile] ( ) . [getmtime] ( ) 2495 else : 2496 timestamp = 0 2497 2498 self . _memo [ 'get_timestamp' ] = timestamp 2499 2500 return timestamp 2501 2502 [-] def [store_info] ( self ) : 2503 # Merge our build information into the already-stored entry. 2504 # This accomodates "chained builds" where a file that's a target 2505 # in one build (SConstruct file) is a source in a different build. 2506 # See test/chained-build.py for the use case. 2507 if [do_store_info] : 2508 self . dir . [sconsign] ( ) . [store_info] ( self . name , self ) 2509 2510 [convert_copy_attrs] = [ 2511 'bsources' , 2512 'bimplicit' , 2513 'bdepends' , 2514 'bact' , 2515 'bactsig' , 2516 'ninfo' , 2517 ] 2518 2519 2520 [convert_sig_attrs] = [ 2521 'bsourcesigs' , 2522 'bimplicitsigs' , 2523 'bdependsigs' , 2524 ] 2525 2526 [-] def [convert_old_entry] ( self , old_entry ) : 2527 # Convert a .sconsign entry from before the Big Signature 2528 # Refactoring, doing what we can to convert its information 2529 # to the new .sconsign entry format. 2530 # 2531 # The old format looked essentially like this: 2532 # 2533 # BuildInfo 2534 # .ninfo (NodeInfo) 2535 # .bsig 2536 # .csig 2537 # .timestamp 2538 # .size 2539 # .bsources 2540 # .bsourcesigs ("signature" list) 2541 # .bdepends 2542 # .bdependsigs ("signature" list) 2543 # .bimplicit 2544 # .bimplicitsigs ("signature" list) 2545 # .bact 2546 # .bactsig 2547 # 2548 # The new format looks like this: 2549 # 2550 # .ninfo (NodeInfo) 2551 # .bsig 2552 # .csig 2553 # .timestamp 2554 # .size 2555 # .binfo (BuildInfo) 2556 # .bsources 2557 # .bsourcesigs (NodeInfo list) 2558 # .bsig 2559 # .csig 2560 # .timestamp 2561 # .size 2562 # .bdepends 2563 # .bdependsigs (NodeInfo list) 2564 # .bsig 2565 # .csig 2566 # .timestamp 2567 # .size 2568 # .bimplicit 2569 # .bimplicitsigs (NodeInfo list) 2570 # .bsig 2571 # .csig 2572 # .timestamp 2573 # .size 2574 # .bact 2575 # .bactsig 2576 # 2577 # The basic idea of the new structure is that a NodeInfo always 2578 # holds all available information about the state of a given Node 2579 # at a certain point in time. The various .b*sigs lists can just 2580 # be a list of pointers to the .ninfo attributes of the different 2581 # dependent nodes, without any copying of information until it's 2582 # time to pickle it for writing out to a .sconsign file. 2583 # 2584 # The complicating issue is that the *old* format only stored one 2585 # "signature" per dependency, based on however the *last* build 2586 # was configured. We don't know from just looking at it whether 2587 # it was a build signature, a content signature, or a timestamp 2588 # "signature". Since we no longer use build signatures, the 2589 # best we can do is look at the length and if it's thirty two, 2590 # assume that it was (or might have been) a content signature. 2591 # If it was actually a build signature, then it will cause a 2592 # rebuild anyway when it doesn't match the new content signature, 2593 # but that's probably the best we can do. 2594 import [SCons] . [SConsign] 2595 new_entry = [SCons] . [SConsign] . [SConsignEntry] ( ) 2596 new_entry . binfo = self . [new_binfo] ( ) 2597 binfo = new_entry . binfo 2598 for attr in self . [convert_copy_attrs] : 2599 try : 2600 value = getattr ( old_entry , attr ) 2601 except AttributeError : 2602 continue 2603 setattr ( binfo , attr , value ) 2604 delattr ( old_entry , attr ) 2605 for attr in self . [convert_sig_attrs] : 2606 try : 2607 sig_list = getattr ( old_entry , attr ) 2608 except AttributeError : 2609 continue 2610 value = [ ] 2611 for sig in sig_list : 2612 ninfo = self . [new_ninfo] ( ) 2613 if len ( sig ) == 32 : 2614 ninfo . csig = sig 2615 else : 2616 ninfo . timestamp = sig 2617 value . [append] ( ninfo ) 2618 setattr ( binfo , attr , value ) 2619 delattr ( old_entry , attr ) 2620 return new_entry 2621 2622 [memoizer_counters] . [append] ( [SCons] . [Memoize] . [CountValue] ( 'get_stored_info' ) ) 2623 2624 [-] def [get_stored_info] ( self ) : 2625 try : 2626 return self . _memo [ 'get_stored_info' ] 2627 except KeyError : 2628 pass 2629 2630 try : 2631 sconsign_entry = self . dir . [sconsign] ( ) . [get_entry] ( self . name ) 2632 except ( KeyError , [EnvironmentError] ) : 2633 import [SCons] . [SConsign] 2634 sconsign_entry = [SCons] . [SConsign] . [SConsignEntry] ( ) 2635 sconsign_entry . binfo = self . [new_binfo] ( ) 2636 sconsign_entry . ninfo = self . [new_ninfo] ( ) 2637 else : 2638 if isinstance ( sconsign_entry , [FileBuildInfo] ) : 2639 # This is a .sconsign file from before the Big Signature 2640 # Refactoring; convert it as best we can. 2641 sconsign_entry = self . [convert_old_entry] ( sconsign_entry ) 2642 try : 2643 delattr ( sconsign_entry . ninfo , 'bsig' ) 2644 except AttributeError : 2645 pass 2646 2647 self . _memo [ 'get_stored_info' ] = sconsign_entry 2648 2649 return sconsign_entry 2650 2651 [-] def [get_stored_implicit] ( self ) : 2652 binfo = self . [get_stored_info] ( ) . binfo 2653 binfo . [prepare_dependencies] ( ) 2654 try : return binfo . bimplicit 2655 except AttributeError : return None 2656 2658 return self . dir . [rel_path] ( other ) 2659 2660 [-] def [_get_found_includes_key] ( self , env , scanner , path ) : 2661 return ( id ( env ) , id ( scanner ) , [path] ) 2662 2663 [memoizer_counters] . [append] ( [SCons] . [Memoize] . [CountDict] ( 'get_found_includes' , [_get_found_includes_key] ) ) 2664 2665 [-] def [get_found_includes] ( self , env , scanner , path ) : 2666 """Return the included implicit dependencies in this file. 2667 Cache results so we only scan the file once per path 2668 regardless of how many times this information is requested. 2669 """ 2670 memo_key = ( id ( env ) , id ( scanner ) , [path] ) 2671 try : 2672 memo_dict = self . _memo [ 'get_found_includes' ] 2673 except KeyError : 2674 memo_dict = { } 2675 self . _memo [ 'get_found_includes' ] = memo_dict 2676 else : 2677 try : 2678 return memo_dict [ memo_key ] 2679 except KeyError : 2680 pass 2681 2682 if scanner : 2683 # result = [n.disambiguate() for n in scanner(self, env, path)] 2684 [result] = scanner ( self , env , [path] ) 2685 [result] = [ N . [disambiguate] ( ) for N in [result] ] 2686 else : 2687 [result] = [ ] 2688 2689 memo_dict [ memo_key ] = [result] 2690 2691 return [result] 2692 2693 [-] def [_createDir] ( self ) : 2694 # ensure that the directories for this node are 2695 # created. 2696 self . dir . [_create] ( ) 2697 2698 [-] def [push_to_cache] ( self ) : 2699 """Try to push the node into a cache 2700 """ 2701 # This should get called before the Nodes' .built() method is 2702 # called, which would clear the build signature if the file has 2703 # a source scanner. 2704 # 2705 # We have to clear the local memoized values *before* we push 2706 # the node to cache so that the memoization of the self.exists() 2707 # return value doesn't interfere. 2708 if self . nocache : 2709 return 2710 self . [clear_memoized_values] ( ) 2711 if self . [exists] ( ) : 2712 self . [get_build_env] ( ) . [get_CacheDir] ( ) . [push] ( self ) 2713 2714 [-] def [retrieve_from_cache] ( self ) : 2715 """Try to retrieve the node's content from a cache 2716 2717 This method is called from multiple threads in a parallel build, 2718 so only do thread safe stuff here. Do thread unsafe stuff in 2719 built(). 2720 2721 Returns true if the node was successfully retrieved. 2722 """ 2723 if self . nocache : 2724 return None 2725 if not self . [is_derived] ( ) : 2726 return None 2727 return self . [get_build_env] ( ) . [get_CacheDir] ( ) . [retrieve] ( self ) 2728 2730 if self . [exists] ( ) and self . executor is not None : 2731 self . [get_build_env] ( ) . [get_CacheDir] ( ) . [push_if_forced] ( self ) 2732 2733 ninfo = self . [get_ninfo] ( ) 2734 2735 csig = self . [get_max_drift_csig] ( ) 2736 if csig : 2737 ninfo . csig = csig 2738 2739 ninfo . timestamp = self . [get_timestamp] ( ) 2740 ninfo . size = self . [get_size] ( ) 2741 2742 if not self . [has_builder] ( ) : 2743 # This is a source file, but it might have been a target file 2744 # in another build that included more of the DAG. Copy 2745 # any build information that's stored in the .sconsign file 2746 # into our binfo object so it doesn't get lost. 2747 old = self . [get_stored_info] ( ) 2748 self . [get_binfo] ( ) . __dict__ . [update] ( old . binfo . __dict__ ) 2749 2750 self . [store_info] ( ) 2751 2752 [-] def [release_target_info] ( self ) : 2753 """Called just after this node has been marked 2754 up-to-date or was built completely. 2755 2756 This is where we try to release as many target node infos 2757 as possible for clean builds and update runs, in order 2758 to minimize the overall memory consumption. 2759 2760 We'd like to remove a lot more attributes like self.sources 2761 and self.sources_set, but they might get used 2762 in a next build step. For example, during configuration 2763 the source files for a built *.o file are used to figure out 2764 which linker to use for the resulting Program (gcc vs. g++)! 2765 That's why we check for the 'keep_targetinfo' attribute, 2766 config Nodes and the Interactive mode just don't allow 2767 an early release of most variables. 2768 2769 In the same manner, we can't simply remove the self.attributes 2770 here. The smart linking relies on the shared flag, and some 2771 parts of the java Tool use it to transport information 2772 about nodes... 2773 2774 @see: built() and Node.release_target_info() 2775 """ 2776 if ( self . released_target_info or [SCons] . [Node] . [interactive] ) : 2777 return 2778 2779 if not hasattr ( self . attributes , 'keep_targetinfo' ) : 2780 # Cache some required values, before releasing 2781 # stuff like env, executor and builder... 2782 self . [changed] ( allowcache = True ) 2783 self . [get_contents_sig] ( ) 2784 self . [get_build_env] ( ) 2785 # Now purge unneeded stuff to free memory... 2786 self . executor = None 2787 self . _memo . pop ( 'rfile' , None ) 2788 self . prerequisites = None 2789 # Cleanup lists, but only if they're empty 2790 if not len ( self . ignore_set ) : 2791 self . ignore_set = None 2792 if not len ( self . implicit_set ) : 2793 self . implicit_set = None 2794 if not len ( self . depends_set ) : 2795 self . depends_set = None 2796 if not len ( self . ignore ) : 2797 self . ignore = None 2798 if not len ( self . depends ) : 2799 self . depends = None 2800 # Mark this node as done, we only have to release 2801 # the memory once... 2802 self . released_target_info = True 2803 2804 [-] def [find_src_builder] ( self ) : 2805 if self . [rexists] ( ) : 2806 return None 2807 scb = self . dir . [src_builder] ( ) 2808 if scb is [_null] : 2809 if [diskcheck_sccs] ( self . dir , self . name ) : 2810 scb = [get_DefaultSCCSBuilder] ( ) 2811 elif [diskcheck_rcs] ( self . dir , self . name ) : 2812 scb = [get_DefaultRCSBuilder] ( ) 2813 else : 2814 scb = None 2815 if scb is not None : 2816 try : 2817 b = self . builder 2818 except AttributeError : 2819 b = None 2820 if b is None : 2821 self . [builder_set] ( scb ) 2822 return scb 2823 2824 [-] def [has_src_builder] ( self ) : 2825 """Return whether this Node has a source builder or not. 2826 2827 If this Node doesn't have an explicit source code builder, this 2828 is where we figure out, on the fly, if there's a transparent 2829 source code builder for it. 2830 2831 Note that if we found a source builder, we also set the 2832 self.builder attribute, so that all of the methods that actually 2833 *build* this file don't have to do anything different. 2834 """ 2835 try : 2836 scb = self . sbuilder 2837 except AttributeError : 2838 scb = self . sbuilder = self . [find_src_builder] ( ) 2839 return scb is not None 2840 2841 [-] def [alter_targets] ( self ) : 2842 """Return any corresponding targets in a variant directory. 2843 """ 2844 if self . [is_derived] ( ) : 2845 return [ ] , None 2846 return self . [fs] . [variant_dir_target_climb] ( self , self . dir , [ self . name ] ) 2847 2848 [-] def [_rmv_existing] ( self ) : 2849 self . [clear_memoized_values] ( ) 2850 if [print_duplicate] : 2851 "dup: removing existing target %s" % self 2852 [e] = [Unlink] ( self , [ ] , None ) 2853 if isinstance ( [e] , [SCons] . [Errors] . [BuildError] ) : 2854 raise [e] 2855 2856 # 2857 # Taskmaster interface subsystem 2858 # 2859 2860 [-] def [make_ready] ( self ) : 2861 self . [has_src_builder] ( ) 2862 self . [get_binfo] ( ) 2863 2865 """Prepare for this file to be created.""" 2866 [SCons] . [Node] . [Node] . [prepare] ( self ) 2867 2868 if self . [get_state] ( ) != [SCons] . [Node] . [up_to_date] : 2869 if self . [exists] ( ) : 2870 if self . [is_derived] ( ) and not self . precious : 2871 self . [_rmv_existing] ( ) 2872 else : 2873 try : 2874 self . [_createDir] ( ) 2875 except [SCons] . [Errors] . [StopError] , drive : 2876 desc = "No drive `%s' for target `%s'." % ( drive , self ) 2877 raise [SCons] . [Errors] . [StopError] ( desc ) 2878 2879 # 2880 # 2881 # 2882 2884 """Remove this file.""" 2885 if self . [exists] ( ) or self . [islink] ( ) : 2886 self . [fs] . [unlink] ( self . [path] ) 2887 return 1 2888 return None 2889 2890 [-] def [do_duplicate] ( self , src ) : 2891 self . [_createDir] ( ) 2892 if [print_duplicate] : 2893 "dup: relinking variant '%s' from '%s'" % ( self , src ) 2894 [Unlink] ( self , None , None ) 2895 [e] = [Link] ( self , src , None ) 2896 if isinstance ( [e] , [SCons] . [Errors] . [BuildError] ) : 2897 desc = "Cannot duplicate `%s' in `%s': %s." % ( src . [path] , self . dir . [path] , [e] . errstr ) 2898 raise [SCons] . [Errors] . [StopError] ( desc ) 2899 self . linked = 1 2900 # The Link() action may or may not have actually 2901 # created the file, depending on whether the -n 2902 # option was used or not. Delete the _exists and 2903 # _rexists attributes so they can be reevaluated. 2904 self . [clear] ( ) 2905 2906 [memoizer_counters] . [append] ( [SCons] . [Memoize] . [CountValue] ( 'exists' ) ) 2907 2909 try : 2910 return self . _memo [ 'exists' ] 2911 except KeyError : 2912 pass 2913 # Duplicate from source path if we are set up to do this. 2914 if self . duplicate and not self . [is_derived] ( ) and not self . linked : 2915 src = self . [srcnode] ( ) 2916 if src is not self : 2917 # At this point, src is meant to be copied in a variant directory. 2918 src = src . [rfile] ( ) 2919 if src . abspath != self . abspath : 2920 if src . [exists] ( ) : 2921 self . [do_duplicate] ( src ) 2922 # Can't return 1 here because the duplication might 2923 # not actually occur if the -n option is being used. 2924 else : 2925 # The source file does not exist. Make sure no old 2926 # copy remains in the variant directory. 2927 if [print_duplicate] : 2928 "dup: no src for %s, unlinking old variant copy" % self 2929 if [Base] . [exists] ( self ) or self . [islink] ( ) : 2930 self . [fs] . [unlink] ( self . [path] ) 2931 # Return None explicitly because the Base.exists() call 2932 # above will have cached its value if the file existed. 2933 self . _memo [ 'exists' ] = None 2934 return None 2935 [result] = [Base] . [exists] ( self ) 2936 self . _memo [ 'exists' ] = [result] 2937 return [result] 2938 2939 # 2940 # SIGNATURE SUBSYSTEM 2941 # 2942 2943 [-] def [get_max_drift_csig] ( self ) : 2944 """ 2945 Returns the content signature currently stored for this node 2946 if it's been unmodified longer than the max_drift value, or the 2947 max_drift value is 0. Returns None otherwise. 2948 """ 2949 old = self . [get_stored_info] ( ) 2950 mtime = self . [get_timestamp] ( ) 2951 2952 max_drift = self . [fs] . max_drift 2953 if max_drift > 0 : 2954 if ( time . time ( ) - mtime ) > max_drift : 2955 try : 2956 n = old . ninfo 2957 if n . timestamp and n . csig and n . timestamp == mtime : 2958 return n . csig 2959 except AttributeError : 2960 pass 2961 elif max_drift == 0 : 2962 try : 2963 return old . ninfo . csig 2964 except AttributeError : 2965 pass 2966 2967 return None 2968 2970 """ 2971 Generate a node's content signature, the digested signature 2972 of its content. 2973 2974 node - the node 2975 cache - alternate node to use for the signature cache 2976 returns - the content signature 2977 """ 2978 ninfo = self . [get_ninfo] ( ) 2979 try : 2980 return ninfo . csig 2981 except AttributeError : 2982 pass 2983 2984 csig = self . [get_max_drift_csig] ( ) 2985 if csig is None : 2986 2987 try : 2988 if self . [get_size] ( ) < [SCons] . [Node] . [FS] . [File] . [md5_chunksize] : 2989 contents = self . [get_contents] ( ) 2990 else : 2991 csig = self . [get_content_hash] ( ) 2992 except IOError : 2993 # This can happen if there's actually a directory on-disk, 2994 # which can be the case if they've disabled disk checks, 2995 # or if an action with a File target actually happens to 2996 # create a same-named directory by mistake. 2997 csig = '' 2998 else : 2999 if not csig : 3000 csig = [SCons] . [Util] . MD5signature ( contents ) 3001 3002 ninfo . csig = csig 3003 3004 return csig 3005 3006 # 3007 # DECISION SUBSYSTEM 3008 # 3009 3010 [-] def [builder_set] ( self , builder ) : 3011 [SCons] . [Node] . [Node] . [builder_set] ( self , builder ) 3012 self . [changed_since_last_build] = self . [decide_target] 3013 3015 """Called just after this File node is successfully built. 3016 3017 Just like for 'release_target_info' we try to release 3018 some more target node attributes in order to minimize the 3019 overall memory consumption. 3020 3021 @see: release_target_info 3022 """ 3023 3024 [SCons] . [Node] . [Node] . [built] ( self ) 3025 3026 if ( not [SCons] . [Node] . [interactive] and 3027 not hasattr ( self . attributes , 'keep_targetinfo' ) ) : 3028 # Ensure that the build infos get computed and cached... 3029 self . [store_info] ( ) 3030 # ... then release some more variables. 3031 self . _specific_sources = False 3032 self . labspath = None 3033 self . [_save_str] ( ) 3034 self . cwd = None 3035 3036 self . scanner_paths = None 3037 3039 """ 3040 Returns if the node is up-to-date with respect to the BuildInfo 3041 stored last time it was built. 3042 3043 For File nodes this is basically a wrapper around Node.changed(), 3044 but we allow the return value to get cached after the reference 3045 to the Executor got released in release_target_info(). 3046 3047 @see: Node.changed() 3048 """ 3049 if node is None : 3050 try : 3051 return self . _memo [ 'changed' ] 3052 except KeyError : 3053 pass 3054 3055 has_changed = [SCons] . [Node] . [Node] . [changed] ( self , node ) 3056 if allowcache : 3057 self . _memo [ 'changed' ] = has_changed 3058 return has_changed 3059 3060 [-] def [changed_content] ( self , target , prev_ni ) : 3061 cur_csig = self . [get_csig] ( ) 3062 try : 3063 return cur_csig != prev_ni . csig 3064 except AttributeError : 3065 return 1 3066 3067 [-] def [changed_state] ( self , target , prev_ni ) : 3068 return self . state != [SCons] . [Node] . [up_to_date] 3069 3070 [-] def [changed_timestamp_then_content] ( self , target , prev_ni ) : 3071 if not self . [changed_timestamp_match] ( target , prev_ni ) : 3072 try : 3073 self . [get_ninfo] ( ) . csig = prev_ni . csig 3074 except AttributeError : 3075 pass 3076 return False 3077 return self . [changed_content] ( target , prev_ni ) 3078 3079 [-] def [changed_timestamp_newer] ( self , target , prev_ni ) : 3080 try : 3081 return self . [get_timestamp] ( ) > target . [get_timestamp] ( ) 3082 except AttributeError : 3083 return 1 3084 3085 [-] def [changed_timestamp_match] ( self , target , prev_ni ) : 3086 try : 3087 return self . [get_timestamp] ( ) != prev_ni . timestamp 3088 except AttributeError : 3089 return 1 3090 3091 [-] def [decide_source] ( self , target , prev_ni ) : 3092 return target . [get_build_env] ( ) . [decide_source] ( self , target , prev_ni ) 3093 3094 [-] def [decide_target] ( self , target , prev_ni ) : 3095 return target . [get_build_env] ( ) . [decide_target] ( self , target , prev_ni ) 3096 3097 # Initialize this Node's decider function to decide_source() because 3098 # every file is a source file until it has a Builder attached... 3099 [changed_since_last_build] = [decide_source] 3100 3101 [-] def [is_up_to_date] ( self ) : 3102 T = 0 3103 if T : [Trace] ( 'is_up_to_date(%s):' % self ) 3104 if not self . [exists] ( ) : 3105 if T : [Trace] ( ' not self.exists():' ) 3106 # The file doesn't exist locally... 3107 r = self . [rfile] ( ) 3108 if r != self : 3109 # ...but there is one in a Repository... 3110 if not self . [changed] ( r ) : 3111 if T : [Trace] ( ' changed(%s):' % r ) 3112 # ...and it's even up-to