Merge from Chromium at DEPS revision 288042

This commit was generated by merge_to_master.py.

Change-Id: Ic58fbacc9200ce8e802d915ee6c5bdbcb9b3b309
diff --git a/grit/format/resource_map.py b/grit/format/resource_map.py
index b5a7b45..37ac54a 100644
--- a/grit/format/resource_map.py
+++ b/grit/format/resource_map.py
@@ -109,18 +109,18 @@
   tids = rc_header.GetIds(root)
   seen = set()
   active_descendants = [item for item in root.ActiveDescendants()]
+  output_all_resource_defines = root.ShouldOutputAllResourceDefines()
   for item in root:
-    if isinstance(item, (include.IncludeNode,
-                         structure.StructureNode,
-                         message.MessageNode)):
-      key = get_key(item)
-      tid = item.attrs['name']
-      if tid in tids and key not in seen:
-        seen.add(key)
-        # For messages, only include the active ones
-        if not isinstance(item, message.MessageNode) \
-            or item in active_descendants:
-          yield '  {"%s", %s},\n' % (key, tid)
+    if not item.IsResourceMapSource():
+      continue
+    key = get_key(item)
+    tid = item.attrs['name']
+    if tid not in tids or key in seen:
+      continue
+    seen.add(key)
+    if item.GeneratesResourceMapEntry(output_all_resource_defines,
+                                      item in active_descendants):
+      yield '  {"%s", %s},\n' % (key, tid)
   yield _FormatSourceFooter(root)
 
 
diff --git a/grit/format/resource_map_unittest.py b/grit/format/resource_map_unittest.py
index 8f162b5..cc6a79b 100644
--- a/grit/format/resource_map_unittest.py
+++ b/grit/format/resource_map_unittest.py
@@ -94,6 +94,65 @@
 };
 const size_t kTheRcHeaderSize = arraysize(kTheRcHeader);''', output)
 
+  def testFormatResourceMapOutputAllEqualsFalse(self):
+    grd = grd_reader.Parse(StringIO.StringIO(
+      '''<?xml version="1.0" encoding="UTF-8"?>
+      <grit latest_public_release="2" source_lang_id="en" current_release="3"
+            base_dir="." output_all_resource_defines="false">
+        <outputs>
+          <output type="rc_header" filename="the_rc_header.h" />
+          <output type="resource_map_header"
+                  filename="the_resource_map_header.h" />
+          <output type="resource_map_source"
+                  filename="the_resource_map_header.cc" />
+        </outputs>
+        <release seq="3">
+          <structures first_id="300">
+            <structure type="chrome_scaled_image" name="IDR_KLONKMENU"
+                       file="foo.png" />
+            <if expr="False">
+              <structure type="chrome_scaled_image" name="IDR_MISSING"
+                         file="bar.png" />
+            </if>
+         </structures>
+        </release>
+      </grit>'''), util.PathFromRoot('.'))
+    grd.SetOutputLanguage('en')
+    grd.RunGatherers()
+    output = util.StripBlankLinesAndComments(''.join(
+        resource_map.GetFormatter('resource_map_header')(grd, 'en', '.')))
+    self.assertEqual('''\
+#include <stddef.h>
+#ifndef GRIT_RESOURCE_MAP_STRUCT_
+#define GRIT_RESOURCE_MAP_STRUCT_
+struct GritResourceMap {
+  const char* const name;
+  int value;
+};
+#endif // GRIT_RESOURCE_MAP_STRUCT_
+extern const GritResourceMap kTheRcHeader[];
+extern const size_t kTheRcHeaderSize;''', output)
+    output = util.StripBlankLinesAndComments(''.join(
+        resource_map.GetFormatter('resource_map_source')(grd, 'en', '.')))
+    self.assertEqual('''\
+#include "the_resource_map_header.h"
+#include "base/basictypes.h"
+#include "the_rc_header.h"
+const GritResourceMap kTheRcHeader[] = {
+  {"IDR_KLONKMENU", IDR_KLONKMENU},
+};
+const size_t kTheRcHeaderSize = arraysize(kTheRcHeader);''', output)
+    output = util.StripBlankLinesAndComments(''.join(
+        resource_map.GetFormatter('resource_map_source')(grd, 'en', '.')))
+    self.assertEqual('''\
+#include "the_resource_map_header.h"
+#include "base/basictypes.h"
+#include "the_rc_header.h"
+const GritResourceMap kTheRcHeader[] = {
+  {"IDR_KLONKMENU", IDR_KLONKMENU},
+};
+const size_t kTheRcHeaderSize = arraysize(kTheRcHeader);''', output)
+
   def testFormatStringResourceMap(self):
     grd = grd_reader.Parse(StringIO.StringIO(
       '''<?xml version="1.0" encoding="UTF-8"?>
diff --git a/grit/node/base.py b/grit/node/base.py
index 3de51b6..a40794b 100644
--- a/grit/node/base.py
+++ b/grit/node/base.py
@@ -590,6 +590,21 @@
     '''Whether we need to expand variables on a given node.'''
     return False
 
+  def IsResourceMapSource(self):
+    '''Whether this node is a resource map source.'''
+    return False
+
+  def GeneratesResourceMapEntry(self, output_all_resource_defines,
+                                is_active_descendant):
+    '''Whether this node should output a resource map entry.
+
+    Args:
+      output_all_resource_defines: The value of output_all_resource_defines for
+                                   the root node.
+      is_active_descendant: Whether the current node is an active descendant
+                            from the root node.'''
+    return False
+
 
 class ContentNode(Node):
   '''Convenience baseclass for nodes that can have content.'''
diff --git a/grit/node/include.py b/grit/node/include.py
index 9c3685f..0f114c3 100644
--- a/grit/node/include.py
+++ b/grit/node/include.py
@@ -113,6 +113,14 @@
          self.ToRealPath(self.GetInputPath()),
          allow_external_script=allow_external_script)
 
+  def IsResourceMapSource(self):
+    return True
+
+  def GeneratesResourceMapEntry(self, output_all_resource_defines,
+                                is_active_descendant):
+    # includes always generate resource entries.
+    return True
+
   @staticmethod
   def Construct(parent, name, type, file, translateable=True,
                 filenameonly=False, mkoutput=False, relativepath=False):
diff --git a/grit/node/message.py b/grit/node/message.py
index ca80f41..48cd1c7 100644
--- a/grit/node/message.py
+++ b/grit/node/message.py
@@ -224,6 +224,13 @@
     message = self.ws_at_start + self.Translate(lang) + self.ws_at_end
     return id, util.Encode(message, encoding)
 
+  def IsResourceMapSource(self):
+    return True
+
+  def GeneratesResourceMapEntry(self, output_all_resource_defines,
+                                is_active_descendant):
+    return is_active_descendant
+
   @staticmethod
   def Construct(parent, message, name, desc='', meaning='', translateable=True):
     '''Constructs a new message node that is a child of 'parent', with the
diff --git a/grit/node/structure.py b/grit/node/structure.py
index 48968f6..7ccd2fb 100644
--- a/grit/node/structure.py
+++ b/grit/node/structure.py
@@ -332,6 +332,15 @@
 
     return filename
 
+  def IsResourceMapSource(self):
+    return True
+
+  def GeneratesResourceMapEntry(self, output_all_resource_defines,
+                                is_active_descendant):
+    if output_all_resource_defines:
+      return True
+    return is_active_descendant
+
   @staticmethod
   def Construct(parent, name, type, file, encoding='cp1252'):
     '''Creates a new node which is a child of 'parent', with attributes set
diff --git a/grit/tool/build.py b/grit/tool/build.py
index 87ee412..537e2c6 100644
--- a/grit/tool/build.py
+++ b/grit/tool/build.py
@@ -63,6 +63,20 @@
 
 Options:
 
+  -a FILE           Assert that the given file is an output. There can be
+                    multiple "-a" flags listed for multiple outputs. If a "-a"
+                    or "--assert-file-list" argument is present, then the list
+                    of asserted files must match the output files or the tool
+                    will fail. The use-case is for the build system to maintain
+                    separate lists of output files and to catch errors if the
+                    build system's list and the grit list are out-of-sync.
+
+  --assert-file-list  Provide a file listing multiple asserted output files.
+                    There is one file name per line. This acts like specifying
+                    each file with "-a" on the command line, but without the
+                    possibility of running into OS line-length limits for very
+                    long lists.
+
   -o OUTPUTDIR      Specify what directory output paths are relative to.
                     Defaults to the current directory.
 
@@ -104,13 +118,20 @@
     self.output_directory = '.'
     first_ids_file = None
     whitelist_filenames = []
+    assert_output_files = []
     target_platform = None
     depfile = None
     depdir = None
     rc_header_format = None
-    (own_opts, args) = getopt.getopt(args, 'o:D:E:f:w:t:h:', ('depdir=','depfile='))
+    (own_opts, args) = getopt.getopt(args, 'a:o:D:E:f:w:t:h:',
+        ('depdir=','depfile=','assert-file-list='))
     for (key, val) in own_opts:
-      if key == '-o':
+      if key == '-a':
+        assert_output_files.append(val)
+      elif key == '--assert-file-list':
+        with open(val) as f:
+          assert_output_files += f.read().splitlines()
+      elif key == '-o':
         self.output_directory = val
       elif key == '-D':
         name, val = util.ParseDefine(val)
@@ -166,8 +187,12 @@
     self.res.RunGatherers()
     self.Process()
 
+    if assert_output_files:
+      if not self.CheckAssertedOutputFiles(assert_output_files):
+        return 2
+
     if depfile and depdir:
-      self.GenerateDepfile(opts.input, depfile, depdir)
+      self.GenerateDepfile(depfile, depdir)
 
     return 0
 
@@ -324,7 +349,31 @@
       print self.res.UberClique().missing_translations_
       sys.exit(-1)
 
-  def GenerateDepfile(self, input_filename, depfile, depdir):
+
+  def CheckAssertedOutputFiles(self, assert_output_files):
+    '''Checks that the asserted output files are specified in the given list.
+
+    Returns true if the asserted files are present. If they are not, returns
+    False and prints the failure.
+    '''
+    # Compare the absolute path names, sorted.
+    asserted = sorted([os.path.abspath(i) for i in assert_output_files])
+    actual = sorted([
+        os.path.abspath(os.path.join(self.output_directory, i.GetFilename()))
+        for i in self.res.GetOutputFiles()])
+
+    if asserted != actual:
+      print '''Asserted file list does not match.
+
+Expected output files: %s
+
+Actual output files: %s
+''' % (asserted, actual)
+      return False
+    return True
+
+
+  def GenerateDepfile(self, depfile, depdir):
     '''Generate a depfile that contains the imlicit dependencies of the input
     grd. The depfile will be in the same format as a makefile, and will contain
     references to files relative to |depdir|. It will be put in |depfile|.
@@ -343,19 +392,27 @@
     from the directory src/ we will generate a depfile ../out/gen/blah.grd.d
     that has the contents
 
-      gen/blah.grd.d: ../src/input1.xtb ../src/input2.xtb
+      gen/blah.h: ../src/input1.xtb ../src/input2.xtb
+
+    Where "gen/blah.h" is the first output (Ninja expects the .d file to list
+    the first output in cases where there is more than one).
 
     Note that all paths in the depfile are relative to ../out, the depdir.
     '''
     depfile = os.path.abspath(depfile)
     depdir = os.path.abspath(depdir)
+    infiles = self.res.GetInputFiles()
+
+    # Get the first output file relative to the depdir.
+    outputs = self.res.GetOutputFiles()
+    output_file = os.path.relpath(os.path.join(
+          self.output_directory, outputs[0].GetFilename()), depdir)
+
     # The path prefix to prepend to dependencies in the depfile.
     prefix = os.path.relpath(os.getcwd(), depdir)
-    # The path that the depfile refers to itself by.
-    self_ref_depfile = os.path.relpath(depfile, depdir)
-    infiles = self.res.GetInputFiles()
     deps_text = ' '.join([os.path.join(prefix, i) for i in infiles])
-    depfile_contents = self_ref_depfile + ': ' + deps_text
+
+    depfile_contents = output_file + ': ' + deps_text
     self.MakeDirectoriesTo(depfile)
     outfile = self.fo_create(depfile, 'wb')
     outfile.writelines(depfile_contents)
diff --git a/grit/tool/build_unittest.py b/grit/tool/build_unittest.py
index fd640f7..debe4d4 100644
--- a/grit/tool/build_unittest.py
+++ b/grit/tool/build_unittest.py
@@ -49,15 +49,41 @@
     self.failUnless(os.path.isfile(expected_dep_file))
     with open(expected_dep_file) as f:
       line = f.readline()
-      (dep_file_name, deps_string) = line.split(': ')
+      (dep_output_file, deps_string) = line.split(': ')
       deps = deps_string.split(' ')
-      self.failUnlessEqual(os.path.abspath(expected_dep_file),
-          os.path.abspath(os.path.join(output_dir, dep_file_name)),
-          "depfile should refer to itself as the depended upon file")
+
+      self.failUnlessEqual("resource.h", dep_output_file)
       self.failUnlessEqual(1, len(deps))
       self.failUnlessEqual(deps[0],
           util.PathFromRoot('grit/testdata/substitute.xmb'))
 
+  def testAssertOutputs(self):
+    output_dir = tempfile.mkdtemp()
+    class DummyOpts(object):
+      def __init__(self):
+        self.input = util.PathFromRoot('grit/testdata/substitute.grd')
+        self.verbose = False
+        self.extra_verbose = False
+
+    # Incomplete output file list should fail.
+    builder_fail = build.RcBuilder()
+    self.failUnlessEqual(2,
+        builder_fail.Run(DummyOpts(), [
+            '-o', output_dir,
+            '-a', os.path.abspath(
+                os.path.join(output_dir, 'en_generated_resources.rc'))]))
+
+    # Complete output file list should succeed.
+    builder_ok = build.RcBuilder()
+    self.failUnlessEqual(0,
+        builder_ok.Run(DummyOpts(), [
+            '-o', output_dir,
+            '-a', os.path.abspath(
+                os.path.join(output_dir, 'en_generated_resources.rc')),
+            '-a', os.path.abspath(
+                os.path.join(output_dir, 'sv_generated_resources.rc')),
+            '-a', os.path.abspath(
+                os.path.join(output_dir, 'resource.h'))]))
 
 if __name__ == '__main__':
   unittest.main()