Finish auto-converting most of the gyp files.

I've also started writing down which ones need manual work.

Change-Id: I442782e1e3352e0de32b612f1bd2c167f231495a
diff --git a/doc/gyp_to_bazel.py b/doc/gyp_to_bazel.py
index b3da95b..85f7835 100755
--- a/doc/gyp_to_bazel.py
+++ b/doc/gyp_to_bazel.py
@@ -15,6 +15,7 @@
 import os
 import yaml
 import collections
+import re
 
 '''Converts a Gyp filename to its Bazel equivalent.
 
@@ -60,8 +61,24 @@
   if target[0] == ':':
     return target
 
+  # These thin wrappers won't be copied.
   if target == '<(AOS)/build/aos.gyp:logging':
     return '//aos/common/logging'
+  if target == '<(AOS)/build/aos.gyp:logging_interface':
+    return '//aos/common/logging:logging_interface'
+
+  # These are getting moved to the right place manually.
+  if target == '<(AOS)/common/common.gyp:condition':
+    return '//aos/linux_code/ipc_lib:condition'
+  if target == '<(AOS)/common/common.gyp:mutex':
+    return '//aos/linux_code/ipc_lib:mutex'
+  if target == '<(AOS)/common/common.gyp:event':
+    return '//aos/linux_code/ipc_lib:event'
+
+  # By building ..., we can mostly ignore these.
+  if (target == '<(AOS)/build/aos_all.gyp:Prime' or
+      target == '../../frc971/frc971.gyp:All'):
+    return '//aos:prime_binaries'
 
   split = target.split(':')
   if len(split) != 2:
@@ -95,6 +112,9 @@
   def add_dep(self, bazel_dep):
     self.__deps.append(bazel_dep)
 
+  def _type(self):
+    return self.__type
+
   '''Returns a collections.OrderedDict with all of the attributes on the
   Bazel rule this represents.
 
@@ -144,17 +164,30 @@
     super(CcBuildTarget, self).__init__(type, name)
 
     self.__srcs = []
+    self.__hdrs = []
     self.__deps = []
+    self.__tags = []
 
   def add_src(self, src):
     self.__srcs.append(src)
 
+  def add_hdr(self, hdr):
+    self.__hdrs.append(hdr)
+
   def add_dep(self, dep):
     self.__deps.append(dep)
 
+  def add_tag(self, tag):
+    if self._type() != 'cc_test':
+      raise RuntimeError(
+        'Trying to add tag %s to non-test type %s' % (tag, self._type()))
+    self.__tags.append(tag)
+
   def attrs(self):
     r = super(CcBuildTarget, self).attrs();
     r['srcs'] = self.__srcs
+    r['hdrs'] = self.__hdrs
+    r['tags'] = self.__tags
     r['deps'] = self.__deps
     return r
 
@@ -179,18 +212,29 @@
     super(QueueTarget, self).__init__('queue_library', name)
 
     self.__srcs = []
+    self.__deps = []
 
   def add_src(self, src):
     self.__srcs.append(src)
 
+  def add_dep(self, dep):
+    self.__deps.append(dep)
+
   def loads(self):
-    return set((('aos/build/queues', 'queue_library'),))
+    return set((('/aos/build/queues', 'queue_library'),))
 
   def attrs(self):
     r = super(QueueTarget, self).attrs();
     r['srcs'] = self.__srcs
+    r['deps'] = self.__deps
     return r
 
+def _warn_attr(keys_to_handle, name, gyp_file_name, attr):
+  if attr in keys_to_handle:
+    print('Target %s in %s has %s' % (name, gyp_file_name, attr),
+          file=sys.stderr)
+    keys_to_handle.remove(attr)
+
 def main(argv):
   for d in argv:
     build_targets = []
@@ -208,32 +252,96 @@
       targets = gyp['targets']
       for gyp_target in targets:
         target = None
+        keys_to_handle = set(gyp_target.keys())
+        if 'export_dependent_settings' in gyp_target:
+          keys_to_handle.remove('export_dependent_settings')
         name = gyp_target['target_name']
+        keys_to_handle.remove('target_name')
+        _warn_attr(keys_to_handle, name, gyp_file_name, 'actions')
+        _warn_attr(keys_to_handle, name, gyp_file_name, 'conditions')
+        _warn_attr(keys_to_handle, name, gyp_file_name, 'copies')
+        _warn_attr(keys_to_handle, name, gyp_file_name, 'hard_dependency')
+        _warn_attr(keys_to_handle, name, gyp_file_name,
+                   'direct_dependent_settings')
+
+        # These are getting moved to the right place manually.
+        if gyp_file_name == 'aos/common/common.gyp':
+          if name == 'condition' or name == 'mutex' or name == 'event':
+            continue
+        # By building ..., this becomes irrelevant.
+        if gyp_file_name == 'frc971/frc971.gyp':
+          if name == 'All':
+            continue
+
+        if 'variables' in gyp_target:
+          if 'no_rsync' in gyp_target['variables']:
+            del gyp_target['variables']['no_rsync']
+
         type = gyp_target['type']
+        keys_to_handle.remove('type')
         if (type in ['static_library', 'executable'] and
             not 'includes' in gyp_target):
           cc_type = {
               'static_library': 'cc_library',
               'executable': 'cc_binary',
             }[type]
+          if re.match('.*_test$', name) and cc_type == 'cc_binary':
+            cc_type = 'cc_test'
           target = CcBuildTarget(cc_type, name)
 
-          for dep in gyp_target['dependencies']:
-            target.add_dep(gyp_target_to_bazel(gyp_file_name, dep))
-          for src in gyp_target['sources']:
-            target.add_src(src)
+          if 'dependencies' in gyp_target:
+            for dep in gyp_target['dependencies']:
+              target.add_dep(gyp_target_to_bazel(gyp_file_name, dep))
+            keys_to_handle.remove('dependencies')
+          if 'sources' in gyp_target:
+            for src in gyp_target['sources']:
+              # In //aos/common:queue_types, this will get dealt with manually
+              # along with the actions.
+              if src == '<(print_field_cc)':
+                continue
+
+              if '/' in src:
+                raise RuntimeError(
+                  'Bad folder for %s in target %s in %s' % (src, name,
+                                                            gyp_file_name))
+
+              target.add_src(src)
+
+              # This is sort of a heuristic: if there's a header file matching
+              # the source file, add it as an hdr. This is going to require some
+              # manual cleanup, but it'll be close.
+              src_filename = os.path.join(os.path.dirname(gyp_file_name), src)
+              if not os.path.exists(src_filename):
+                raise RuntimeError(
+                  'Can not find source %s in target %s' % (src_filename,
+                                                           name))
+              header = src_filename.rsplit('.', 2)[0] + '.h'
+              if os.path.exists(header):
+                target.add_hdr(src.rsplit('.', 2)[0] + '.h')
+            keys_to_handle.remove('sources')
+          if 'variables' in gyp_target:
+            vars = gyp_target['variables']
+            if 'is_special_test' in vars:
+              if vars['is_special_test'] != 1:
+                raise RuntimeError(
+                  'Unexpected is_special_test value in target %s' % name)
+              target.add_tag('manual')
+              del vars['is_special_test']
         elif type == 'none':
           target = FilegroupTarget(name)
           for dep in gyp_target['dependencies']:
             target.add_src(gyp_target_to_bazel(gyp_file_name, dep))
+          keys_to_handle.remove('dependencies')
         elif 'includes' in gyp_target:
           includes = gyp_target['includes']
+          keys_to_handle.remove('includes')
           if len(includes) != 1:
             raise RuntimeError(
               'Not sure how to handle multiple includes in %s' % gyp_target)
           include = gyp_file_to_bazel(gyp_file_name, includes[0])
           if include == '//aos/build/queues.gypi':
             vars = gyp_target['variables']
+            keys_to_handle.remove('variables')
             if 'header_path' not in vars:
               raise RuntimeError(
                 'No header_path for target %s in %s' % (name, gyp_file_name))
@@ -253,6 +361,11 @@
                                                                 name,
                                                                 gyp_file_name))
               target.add_src(src)
+            keys_to_handle.remove('sources')
+            if 'dependencies' in gyp_target:
+              for dep in gyp_target['dependencies']:
+                target.add_dep(gyp_target_to_bazel(gyp_file_name, dep))
+              keys_to_handle.remove('dependencies')
           else:
             raise RuntimeError(
               'Unknown include %s for target %s in %s' % (include, name,
@@ -263,8 +376,31 @@
 
         if not target:
           raise
+
+        if (gyp_file_name == 'y2015/http_status/http_status.gyp' and
+            name == 'http_status'):
+          # We'll handle these manually.
+          keys_to_handle.remove('include_dirs')
+        if (gyp_file_name == 'aos/common/common.gyp' and
+            name == 'queue_types'):
+          # These will get handled manually as part of dealing with the
+          # actions.
+          keys_to_handle.remove('variables')
+
+        # If there were variables but they all got deleted, then we don't
+        # actually have any more to handle.
+        if 'variables' in keys_to_handle and not gyp_target['variables']:
+          keys_to_handle.remove('variables')
+        if keys_to_handle:
+          raise RuntimeError(
+            'Unhandled keys for target %s in %s: %s' % (name, gyp_file_name,
+                                                        keys_to_handle))
         build_targets.append(target)
 
+    if not build_targets:
+      print('No output targets for %s' % d, file=sys.stderr)
+      continue
+
     with open(os.path.join(d, 'BUILD'), 'w') as build_file:
       build_file.write(
           'package(default_visibility = [\'//visibility:public\'])\n')