(build_dir, ninja_path, build_steps)
return total
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.
Crudely extracts all the subninja and build referenced in ninja_path.
Crudely extracts all the subninja and build referenced in ninja_path .
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
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