parameters: (build_dir, ninja_path, build_steps)
return_statement: return total
docstring: Crudely extracts all the subninja and build referenced in ninja_path.
  
    In particular, it ignores rule and variable declarations. The goal is to be
    performant (well, as much as python can be performant) which is currently in
    the <200ms range for a complete chromium tree. As such the code is laid out
    for performance instead of readability.
docstring_summary: Crudely extracts all the subninja and build referenced in ninja_path.
docstring_tokens: Crudely extracts all the subninja and build referenced in ninja_path .
function: def load_ninja_recursively(build_dir, ninja_path, build_steps):
    """Crudely extracts all the subninja and build referenced in ninja_path.
  
    In particular, it ignores rule and variable declarations. The goal is to be
    performant (well, as much as python can be performant) which is currently in
    the <200ms range for a complete chromium tree. As such the code is laid out
    for performance instead of readability.
    """
    logging.debug('Loading %s', ninja_path)
    try:
      with open(os.path.join(build_dir, ninja_path), 'rb') as f:
        line = None
        merge_line = ''
        subninja = []
        for line in f:
          line = line.rstrip()
          if not line:
            continue
  
          if line[-1] == '$':
            # The next line needs to be merged in.
            merge_line += line[:-1]
            continue
  
          if merge_line:
            line = merge_line + line
            merge_line = ''
  
          statement = line[:line.find(' ')]
          if statement == 'build':
            # Save the dependency list as a raw string. Only the lines needed will
            # be processed with raw_build_to_deps(). This saves a good 70ms of
            # processing time.
            build_target, dependencies = line[6:].split(': ', 1)
            # Interestingly, trying to be smart and only saving the build steps
            # with the intended extensions ('', '.stamp', '.so') slows down
            # parsing even if 90% of the build rules can be skipped.
            # On Windows, a single step may generate two target, so split items
            # accordingly. It has only been seen for .exe/.exe.pdb combos.
            for i in build_target.strip().split():
              build_steps[i] = dependencies
          elif statement == 'subninja':
            subninja.append(line[9:])
    except IOError:
      print >> sys.stderr, 'Failed to open %s' % ninja_path
      raise
  
    total = 1
    for rel_path in subninja:
      try:
        # Load each of the files referenced.
        # TODO(maruel): Skip the files known to not be needed. It saves an aweful
        # lot of processing time.
        total += load_ninja_recursively(build_dir, rel_path, build_steps)
      except IOError:
        print >> sys.stderr, '... as referenced by %s' % ninja_path
        raise
    return total
function_tokens: def load_ninja_recursively ( build_dir , ninja_path , build_steps ) : logging . debug ( 'Loading %s' , ninja_path ) try : with open ( os . path . join ( build_dir , ninja_path ) , 'rb' ) as f : line = None merge_line = '' subninja = [ ] for line in f : line = line . rstrip ( ) if not line : continue if line [ - 1 ] == '$' : # The next line needs to be merged in. merge_line += line [ : - 1 ] continue if merge_line : line = merge_line + line merge_line = '' statement = line [ : line . find ( ' ' ) ] if statement == 'build' : # Save the dependency list as a raw string. Only the lines needed will # be processed with raw_build_to_deps(). This saves a good 70ms of # processing time. build_target , dependencies = line [ 6 : ] . split ( ': ' , 1 ) # Interestingly, trying to be smart and only saving the build steps # with the intended extensions ('', '.stamp', '.so') slows down # parsing even if 90% of the build rules can be skipped. # On Windows, a single step may generate two target, so split items # accordingly. It has only been seen for .exe/.exe.pdb combos. for i in build_target . strip ( ) . split ( ) : build_steps [ i ] = dependencies elif statement == 'subninja' : subninja . append ( line [ 9 : ] ) except IOError : print >> sys . stderr , 'Failed to open %s' % ninja_path raise total = 1 for rel_path in subninja : try : # Load each of the files referenced. # TODO(maruel): Skip the files known to not be needed. It saves an aweful # lot of processing time. total += load_ninja_recursively ( build_dir , rel_path , build_steps ) except IOError : print >> sys . stderr , '... as referenced by %s' % ninja_path raise return total