Add "tulsi_deps" to "_TULSI_COMPILE_DEPS".

Add a new special attribute, "tulsi_deps", to the list of rule
attributes that Tulsi aspects propagate along. The new attribute
name is an escape hatch intended for custom rule creators who use
non-standard attribute names for rule dependencies and want those
dependencies to show up in Xcode.

PiperOrigin-RevId: 195271410
diff --git a/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl b/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl
index 6950d09..950e916 100644
--- a/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl
+++ b/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl
@@ -44,6 +44,10 @@
     "_implicit_tests",  # test_suites without a `tests` attr have an '$implicit_tests' attr instead.
     "test_bundle",
     "test_host",
+    # Special attribute name which serves as an escape hatch intended for custom
+    # rule creators who use non-standard attribute names for rule dependencies
+    # and want those dependencies to show up in Xcode.
+    "tulsi_deps",
     "watch_application",
     "xctest_app",
 ]
@@ -115,20 +119,15 @@
 ]
 
 def _dict_omitting_none(**kwargs):
-  """Creates a dict from the args, dropping keys with None or [] values."""
-  return {name: kwargs[name]
-          for name in kwargs
-          # Skylark doesn't support "is"; comparison is explicit for correctness.
-          # pylint: disable=g-equals-none,g-explicit-bool-comparison
-          if kwargs[name] != None and kwargs[name] != []
-         }
+    """Creates a dict from the args, dropping keys with None or [] values."""
+    return {name: kwargs[name] for name in kwargs if kwargs[name] != None and kwargs[name] != []}
 
 def _struct_omitting_none(**kwargs):
-  """Creates a struct from the args, dropping keys with None or [] values."""
-  return struct(**_dict_omitting_none(**kwargs))
+    """Creates a struct from the args, dropping keys with None or [] values."""
+    return struct(**_dict_omitting_none(**kwargs))
 
 def _convert_outpath_to_symlink_path(path):
-  """Converts full output paths to their tulsi-symlink equivalents.
+    """Converts full output paths to their tulsi-symlink equivalents.
 
   Bazel output paths are unstable, prone to change with architecture,
   platform or flag changes. Therefore we can't rely on them to supply to Xcode.
@@ -161,171 +160,181 @@
   Returns:
     A string that is the original path modified according to the rules.
   """
-  # Transform paths of the form:
-  #   bazel-[whatever]/[platform-config]/symlink[/.*]
-  # to:
-  #   _tulsi-includes/x/x/symlink[/.*]
-  first_dash = path.find('-')
-  components = path.split('/')
-  if (len(components) > 2 and
-      first_dash >= 0 and
-      first_dash < len(components[0])):
-    return '_tulsi-includes/x/x/' + '/'.join(components[3:])
-  return path
+
+    # Transform paths of the form:
+    #   bazel-[whatever]/[platform-config]/symlink[/.*]
+    # to:
+    #   _tulsi-includes/x/x/symlink[/.*]
+    first_dash = path.find("-")
+    components = path.split("/")
+    if (len(components) > 2 and
+        first_dash >= 0 and
+        first_dash < len(components[0])):
+        return ("_tulsi-includes/x/x/" + "/".join(components[3:]))
+    return path
 
 def _is_bazel_external_file(f):
-  """Returns True if the given file is a Bazel external file."""
-  return f.path.startswith('external/')
+    """Returns True if the given file is a Bazel external file."""
+    return f.path.startswith("external/")
 
 def _file_metadata(f):
-  """Returns metadata about a given File."""
-  if not f:
-    return None
+    """Returns metadata about a given File."""
+    if not f:
+        return None
 
-  # Special case handling for Bazel external files which have a path that starts
-  # with 'external/' but their short_path and root.path have no mention of being
-  # external.
-  out_path = f.path if _is_bazel_external_file(f) else f.short_path
-  if not f.is_source:
-    root_path = f.root.path
-    symlink_path = _convert_outpath_to_symlink_path(root_path)
-    if symlink_path == root_path:
-      # The root path should always be bazel-out/... and thus is expected to be
-      # updated.
-      print('Unexpected root path "%s". Please report.' % root_path)
-      root_execution_path_fragment = root_path
+        # Special case handling for Bazel external files which have a path that starts
+        # with 'external/' but their short_path and root.path have no mention of being
+        # external.
+
+    out_path = f.path if _is_bazel_external_file(f) else f.short_path
+    if not f.is_source:
+        root_path = f.root.path
+        symlink_path = _convert_outpath_to_symlink_path(root_path)
+        if symlink_path == root_path:
+            # The root path should always be bazel-out/... and thus is expected to be
+            # updated.
+            print("Unexpected root path \"%s\". Please report." % root_path)
+            root_execution_path_fragment = root_path
+        else:
+            root_execution_path_fragment = symlink_path
     else:
-      root_execution_path_fragment = symlink_path
-  else:
-    root_execution_path_fragment = None
+        root_execution_path_fragment = None
 
-  # At the moment (Oct. 2016), Bazel disallows most files without extensions.
-  # As a temporary hack, Tulsi treats File instances pointing at extension-less
-  # paths as directories. This is extremely fragile and must be replaced with
-  # logic properly homed in Bazel.
-  is_dir = (f.basename.find('.') == -1)
+        # At the moment (Oct. 2016), Bazel disallows most files without extensions.
+        # As a temporary hack, Tulsi treats File instances pointing at extension-less
+        # paths as directories. This is extremely fragile and must be replaced with
+        # logic properly homed in Bazel.
 
-  return _struct_omitting_none(
-      path=out_path,
-      src=f.is_source,
-      root=root_execution_path_fragment,
-      is_dir=is_dir
-  )
+    is_dir = (f.basename.find(".") == -1)
 
-def _file_metadata_by_replacing_path(f, new_path, new_is_dir=None):
-  """Returns a copy of the f _file_metadata struct with the given path."""
-  root_path = _get_opt_attr(f, 'rootPath')
-  if new_is_dir == None:
-    new_is_dir = f.is_dir
+    return _struct_omitting_none(
+        path = out_path,
+        src = f.is_source,
+        root = root_execution_path_fragment,
+        is_dir = is_dir,
+    )
 
-  return _struct_omitting_none(
-      path=new_path,
-      src=f.src,
-      root=root_path,
-      is_dir=new_is_dir
-  )
+def _file_metadata_by_replacing_path(f, new_path, new_is_dir = None):
+    """Returns a copy of the f _file_metadata struct with the given path."""
+    root_path = _get_opt_attr(f, "rootPath")
+    if new_is_dir == None:
+        new_is_dir = f.is_dir
+
+    return _struct_omitting_none(
+        path = new_path,
+        src = f.src,
+        root = root_path,
+        is_dir = new_is_dir,
+    )
 
 def _depset_to_file_metadata_list(a_depset):
-  """"Converts a depset of files into a list of _file_metadata structs."""
-  return [_file_metadata(f) for f in a_depset.to_list()]
+    """"Converts a depset of files into a list of _file_metadata structs."""
+    return [_file_metadata(f) for f in a_depset.to_list()]
 
 def _collect_artifacts(obj, attr_path):
-  """Returns a list of Artifact objects for the attr_path in obj."""
-  return [f for src in _getattr_as_list(obj, attr_path)
-          for f in _get_opt_attr(src, 'files')]
+    """Returns a list of Artifact objects for the attr_path in obj."""
+    return [f for src in _getattr_as_list(obj, attr_path) for f in _get_opt_attr(src, "files")]
 
-def _collect_files(obj, attr_path, convert_to_metadata=True):
-  """Returns a list of artifact_location's for the attr_path in obj."""
-  if convert_to_metadata:
-    return [_file_metadata(f) for f in _collect_artifacts(obj, attr_path)]
-  else:
-    return _collect_artifacts(obj, attr_path)
+def _collect_files(obj, attr_path, convert_to_metadata = True):
+    """Returns a list of artifact_location's for the attr_path in obj."""
+    if convert_to_metadata:
+        return [_file_metadata(f) for f in _collect_artifacts(obj, attr_path)]
+    else:
+        return _collect_artifacts(obj, attr_path)
 
 def _collect_first_file(obj, attr_path):
-  """Returns a the first artifact_location for the attr_path in obj."""
-  files = _collect_files(obj, attr_path)
-  if not files:
-    return None
-  return files[0]
+    """Returns a the first artifact_location for the attr_path in obj."""
+    files = _collect_files(obj, attr_path)
+    if not files:
+        return None
+    return files[0]
 
-def _collect_supporting_files(rule_attr, convert_to_metadata=True):
-  """Extracts 'supporting' files from the given rule attributes."""
-  all_files = []
-  for attr in _SUPPORTING_FILE_ATTRIBUTES:
-    all_files += _collect_files(rule_attr, attr,
-                                convert_to_metadata=convert_to_metadata)
-  return all_files
+def _collect_supporting_files(rule_attr, convert_to_metadata = True):
+    """Extracts 'supporting' files from the given rule attributes."""
+    all_files = []
+    for attr in _SUPPORTING_FILE_ATTRIBUTES:
+        all_files += _collect_files(
+            rule_attr,
+            attr,
+            convert_to_metadata = convert_to_metadata,
+        )
+    return all_files
 
 def _collect_bundle_paths(rule_attr, bundle_attributes, bundle_ext):
-  """Extracts subpaths with the given bundle_ext for the given attributes."""
-  discovered_paths = depset()
-  bundles = []
-  if not bundle_ext.endswith('/'):
-    bundle_ext += '/'
-  bundle_ext_len = len(bundle_ext) - 1
+    """Extracts subpaths with the given bundle_ext for the given attributes."""
+    discovered_paths = depset()
+    bundles = []
+    if not bundle_ext.endswith("/"):
+        bundle_ext += "/"
+    bundle_ext_len = len(bundle_ext) - 1
 
-  for attr in bundle_attributes:
-    for f in _collect_files(rule_attr, attr):
-      end = f.path.find(bundle_ext)
-      if end < 0:
-        continue
-      end += bundle_ext_len
+    for attr in bundle_attributes:
+        for f in _collect_files(rule_attr, attr):
+            end = f.path.find(bundle_ext)
+            if end < 0:
+                continue
+            end += bundle_ext_len
 
-      path = f.path[:end]
-      root_path = _get_opt_attr(f, 'rootPath')
-      full_path = str(root_path) + ':' + path
-      if full_path in discovered_paths:
-        continue
-      discovered_paths += [full_path]
-      # Generally Xcode treats bundles as special files so they should not be
-      # flagged as directories.
-      bundles.append(_file_metadata_by_replacing_path(f, path, False))
-  return bundles
+            path = f.path[:end]
+            root_path = _get_opt_attr(f, "rootPath")
+            full_path = str(root_path) + ":" + path
+            if full_path in discovered_paths:
+                continue
+            discovered_paths += [full_path]
+
+            # Generally Xcode treats bundles as special files so they should not be
+            # flagged as directories.
+            bundles.append(_file_metadata_by_replacing_path(f, path, False))
+    return bundles
 
 def _collect_asset_catalogs(rule_attr):
-  """Extracts xcassets directories from the given rule attributes."""
-  attrs = ['app_asset_catalogs', 'asset_catalogs']
-  bundles = _collect_bundle_paths(rule_attr, attrs, '.xcassets')
-  bundles.extend(_collect_bundle_paths(rule_attr, attrs, '.xcstickers'))
+    """Extracts xcassets directories from the given rule attributes."""
+    attrs = ["app_asset_catalogs", "asset_catalogs"]
+    bundles = _collect_bundle_paths(rule_attr, attrs, ".xcassets")
+    bundles.extend(_collect_bundle_paths(rule_attr, attrs, ".xcstickers"))
 
-  return bundles
+    return bundles
 
 def _collect_bundle_imports(rule_attr):
-  """Extracts bundle directories from the given rule attributes."""
-  return _collect_bundle_paths(rule_attr,
-                               ['bundle_imports', 'settings_bundle'],
-                               '.bundle')
+    """Extracts bundle directories from the given rule attributes."""
+    return _collect_bundle_paths(
+        rule_attr,
+        ["bundle_imports", "settings_bundle"],
+        ".bundle",
+    )
 
 def _collect_framework_imports(rule_attr):
-  """Extracts framework directories from the given rule attributes."""
-  return _collect_bundle_paths(rule_attr,
-                               ['framework_imports'],
-                               '.framework')
+    """Extracts framework directories from the given rule attributes."""
+    return _collect_bundle_paths(
+        rule_attr,
+        ["framework_imports"],
+        ".framework",
+    )
 
 def _collect_xcdatamodeld_files(obj, attr_path):
-  """Returns artifact_location's for xcdatamodeld's for attr_path in obj."""
-  files = _collect_files(obj, attr_path)
-  if not files:
-    return []
-  discovered_paths = depset()
-  datamodelds = []
-  for f in files:
-    end = f.path.find('.xcdatamodel/')
-    if end < 0:
-      continue
-    end += 12
+    """Returns artifact_location's for xcdatamodeld's for attr_path in obj."""
+    files = _collect_files(obj, attr_path)
+    if not files:
+        return []
+    discovered_paths = depset()
+    datamodelds = []
+    for f in files:
+        end = f.path.find(".xcdatamodel/")
+        if end < 0:
+            continue
+        end += 12
 
-    path = f.path[:end]
-    root_path = _get_opt_attr(f, 'rootPath')
-    full_path = str(root_path) + ':' + path
-    if full_path in discovered_paths:
-      continue
-    discovered_paths += [full_path]
-    datamodelds.append(_file_metadata_by_replacing_path(f, path, False))
-  return datamodelds
+        path = f.path[:end]
+        root_path = _get_opt_attr(f, "rootPath")
+        full_path = str(root_path) + ":" + path
+        if full_path in discovered_paths:
+            continue
+        discovered_paths += [full_path]
+        datamodelds.append(_file_metadata_by_replacing_path(f, path, False))
+    return datamodelds
 
 def _collect_dependency_labels(rule, filter, attr_list):
-  """Collects Bazel labels for a list of dependency attributes.
+    """Collects Bazel labels for a list of dependency attributes.
 
   Args:
     rule: The Bazel rule whose dependencies should be collected.
@@ -336,28 +345,26 @@
   Returns:
     A list of the Bazel labels of dependencies of the given rule.
   """
-  attr = rule.attr
-  deps = [dep
-          for attribute in attr_list
-          for dep in _filter_deps(filter, _getattr_as_list(attr, attribute))]
-  return [dep.label for dep in deps if hasattr(dep, 'label')]
+    attr = rule.attr
+    deps = [dep for attribute in attr_list for dep in _filter_deps(filter, _getattr_as_list(attr, attribute))]
+    return [dep.label for dep in deps if hasattr(dep, "label")]
 
 def _get_opt_attr(obj, attr_path):
-  """Returns the value at attr_path on the given object if it is set."""
-  attr_path = attr_path.split('.')
-  for a in attr_path:
-    if not obj or not hasattr(obj, a):
-      return None
-    obj = getattr(obj, a)
-  return obj
+    """Returns the value at attr_path on the given object if it is set."""
+    attr_path = attr_path.split(".")
+    for a in attr_path:
+        if not obj or not hasattr(obj, a):
+            return None
+        obj = getattr(obj, a)
+    return obj
 
 def _get_label_attr(obj, attr_path):
-  """Returns the value at attr_path as a label string if it is set."""
-  label = _get_opt_attr(obj, attr_path)
-  return str(label) if label else None
+    """Returns the value at attr_path as a label string if it is set."""
+    label = _get_opt_attr(obj, attr_path)
+    return str(label) if label else None
 
 def _getattr_as_list(obj, attr_path):
-  """Returns the value at attr_path as a list.
+    """Returns the value at attr_path as a list.
 
   This handles normalization of attributes containing a single value for use in
   methods expecting a list of values.
@@ -371,374 +378,376 @@
     A list of values for obj at attr_path or [] if the struct has
     no such attribute.
   """
-  val = _get_opt_attr(obj, attr_path)
-  if not val:
-    return []
+    val = _get_opt_attr(obj, attr_path)
+    if not val:
+        return []
 
-  if type(val) == 'list':
-    return val
-  return [val]
+    if type(val) == "list":
+        return val
+    return [val]
 
 def _extract_defines_from_option_list(lst):
-  """Extracts preprocessor defines from a list of -D strings."""
-  defines = []
-  for item in lst:
-    if item.startswith('-D'):
-      defines.append(item[2:])
-  return defines
+    """Extracts preprocessor defines from a list of -D strings."""
+    defines = []
+    for item in lst:
+        if item.startswith("-D"):
+            defines.append(item[2:])
+    return defines
 
 def _extract_compiler_defines(ctx):
-  """Extracts preprocessor defines from compiler fragments."""
-  defines = []
+    """Extracts preprocessor defines from compiler fragments."""
+    defines = []
 
-  cpp_fragment = _get_opt_attr(ctx.fragments, 'cpp')
-  if cpp_fragment:
-    c_options = _get_opt_attr(cpp_fragment, 'c_options')
-    defines += _extract_defines_from_option_list(c_options)
+    cpp_fragment = _get_opt_attr(ctx.fragments, "cpp")
+    if cpp_fragment:
+        c_options = _get_opt_attr(cpp_fragment, "c_options")
+        defines += _extract_defines_from_option_list(c_options)
 
-    compiler_options = cpp_fragment.compiler_options([])
-    defines += _extract_defines_from_option_list(compiler_options)
+        compiler_options = cpp_fragment.compiler_options([])
+        defines += _extract_defines_from_option_list(compiler_options)
 
-    unfiltered = cpp_fragment.unfiltered_compiler_options([])
-    defines += _extract_defines_from_option_list(unfiltered)
+        unfiltered = cpp_fragment.unfiltered_compiler_options([])
+        defines += _extract_defines_from_option_list(unfiltered)
 
-    cxx = cpp_fragment.cxx_options([])
-    defines += _extract_defines_from_option_list(cxx)
+        cxx = cpp_fragment.cxx_options([])
+        defines += _extract_defines_from_option_list(cxx)
 
-  objc_fragment = _get_opt_attr(ctx.fragments, 'objc')
-  if objc_fragment:
-    objc_copts = _get_opt_attr(objc_fragment, 'copts')
-    defines += _extract_defines_from_option_list(objc_copts)
+    objc_fragment = _get_opt_attr(ctx.fragments, "objc")
+    if objc_fragment:
+        objc_copts = _get_opt_attr(objc_fragment, "copts")
+        defines += _extract_defines_from_option_list(objc_copts)
 
-  return defines
+    return defines
 
 def _collect_secondary_artifacts(target, ctx):
-  """Returns a list of file metadatas for implicit outputs of 'rule'."""
-  artifacts = []
-  rule = ctx.rule
-  if rule.kind in _MERGEDINFOPLIST_GENERATING_RULES:
-    bin_dir = _convert_outpath_to_symlink_path(ctx.bin_dir.path)
-    package = target.label.package
-    basename = target.label.name
-    artifacts.append(_struct_omitting_none(
-        path='%s/%s-MergedInfo.plist' % (package, basename),
-        src=False,
-        root=bin_dir
-    ))
+    """Returns a list of file metadatas for implicit outputs of 'rule'."""
+    artifacts = []
+    rule = ctx.rule
+    if rule.kind in _MERGEDINFOPLIST_GENERATING_RULES:
+        bin_dir = _convert_outpath_to_symlink_path(ctx.bin_dir.path)
+        package = target.label.package
+        basename = target.label.name
+        artifacts.append(_struct_omitting_none(
+            path = "%s/%s-MergedInfo.plist" % (package, basename),
+            src = False,
+            root = bin_dir,
+        ))
 
-  return artifacts
+    return artifacts
 
 def _extract_generated_sources(target):
-  """Returns (source_metadatas, includes) generated by the given target."""
-  file_metadatas = []
-  objc_provider = _get_opt_attr(target, 'objc')
-  if hasattr(objc_provider, 'source') and hasattr(objc_provider, 'header'):
-    all_files = depset(objc_provider.source)
-    all_files += objc_provider.header
-    file_metadatas = [_file_metadata(f) for f in all_files]
+    """Returns (source_metadatas, includes) generated by the given target."""
+    file_metadatas = []
+    objc_provider = _get_opt_attr(target, "objc")
+    if hasattr(objc_provider, "source") and hasattr(objc_provider, "header"):
+        all_files = depset(objc_provider.source)
+        all_files += objc_provider.header
+        file_metadatas = [_file_metadata(f) for f in all_files]
 
-  return file_metadatas
+    return file_metadatas
 
 def _get_deployment_info(target, ctx):
-  """Returns (platform_type, minimum_os_version) for the given target."""
-  platform_type = _get_platform_type(ctx)
+    """Returns (platform_type, minimum_os_version) for the given target."""
+    platform_type = _get_platform_type(ctx)
 
-  if AppleBundleInfo in target:
-    apple_bundle_provider = target[AppleBundleInfo]
-    minimum_os_version = apple_bundle_provider.minimum_os_version
-    return (platform_type, minimum_os_version)
-  return (platform_type, _minimum_os_for_platform(ctx, platform_type))
+    if AppleBundleInfo in target:
+        apple_bundle_provider = target[AppleBundleInfo]
+        minimum_os_version = apple_bundle_provider.minimum_os_version
+        return (platform_type, minimum_os_version)
+    return (platform_type, _minimum_os_for_platform(ctx, platform_type))
 
 def _get_platform_type(ctx):
-  """Return the current apple_common.platform_type as a string."""
-  current_platform = (_get_opt_attr(ctx, 'rule.attr.platform_type')
-                      or _get_opt_attr(ctx, 'rule.attr._platform_type'))
-  if not current_platform:
-    apple_frag = _get_opt_attr(ctx.fragments, 'apple')
-    current_platform = str(apple_frag.single_arch_platform.platform_type)
-  return current_platform
+    """Return the current apple_common.platform_type as a string."""
+    current_platform = (_get_opt_attr(ctx, "rule.attr.platform_type") or
+                        _get_opt_attr(ctx, "rule.attr._platform_type"))
+    if not current_platform:
+        apple_frag = _get_opt_attr(ctx.fragments, "apple")
+        current_platform = str(apple_frag.single_arch_platform.platform_type)
+    return current_platform
 
 def _minimum_os_for_platform(ctx, platform_type_str):
-  """Extracts the minimum OS version for the given apple_common.platform."""
-  min_os = _get_opt_attr(ctx, 'rule.attr.minimum_os_version')
-  if min_os:
-    return min_os
+    """Extracts the minimum OS version for the given apple_common.platform."""
+    min_os = _get_opt_attr(ctx, "rule.attr.minimum_os_version")
+    if min_os:
+        return min_os
 
-  platform_type = getattr(apple_common.platform_type, platform_type_str)
-  min_os = (ctx.attr._tulsi_xcode_config[apple_common.XcodeVersionConfig]
-            .minimum_os_for_platform_type(platform_type))
+    platform_type = getattr(apple_common.platform_type, platform_type_str)
+    min_os = (ctx.attr._tulsi_xcode_config[apple_common.XcodeVersionConfig].minimum_os_for_platform_type(platform_type))
 
-  if not min_os:
-    return None
+    if not min_os:
+        return None
 
-  # Convert the DottedVersion to a string suitable for inclusion in a struct.
-  return str(min_os)
+        # Convert the DottedVersion to a string suitable for inclusion in a struct.
+    return str(min_os)
 
 def _collect_swift_modules(target):
-  """Returns a depset of Swift modules found on the given target."""
-  swift_modules = depset()
-  if SwiftInfo in target:
-    swift_info = target[SwiftInfo]
-    for modules in _getattr_as_list(swift_info, 'transitive_modules'):
-      swift_modules += modules
-  return swift_modules
+    """Returns a depset of Swift modules found on the given target."""
+    swift_modules = depset()
+    if SwiftInfo in target:
+        swift_info = target[SwiftInfo]
+        for modules in _getattr_as_list(swift_info, "transitive_modules"):
+            swift_modules += modules
+    return swift_modules
 
 def _collect_module_maps(target):
-  """Returns a depset of Clang module maps found on the given target."""
-  maps = depset()
-  if SwiftInfo in target:
-    for module_maps in _getattr_as_list(target, 'objc.module_map'):
-      maps += module_maps
-  return maps
+    """Returns a depset of Clang module maps found on the given target."""
+    maps = depset()
+    if SwiftInfo in target:
+        for module_maps in _getattr_as_list(target, "objc.module_map"):
+            maps += module_maps
+    return maps
 
-# TODO(b/64490743): Add these files to the Xcode project.
+    # TODO(b/64490743): Add these files to the Xcode project.
+
 def _collect_swift_header(target):
-  """Returns a depset of Swift generated headers found on the given target."""
-  headers = depset()
-  # swift_* targets put the generated header into their objc provider HEADER
-  # field.
-  if SwiftInfo in target and hasattr(target, 'objc'):
-    headers += target.objc.header
-  return headers
+    """Returns a depset of Swift generated headers found on the given target."""
+    headers = depset()
+
+    # swift_* targets put the generated header into their objc provider HEADER
+    # field.
+    if SwiftInfo in target and hasattr(target, "objc"):
+        headers += target.objc.header
+    return headers
 
 def _target_filtering_info(ctx):
-  """Returns filtering information for test rules."""
-  rule = ctx.rule
+    """Returns filtering information for test rules."""
+    rule = ctx.rule
 
-  # TODO(b/72406542): Clean this up to use a test provider if possible.
-  if rule.kind.endswith('_test'):
-    # Note that a test's size is considered a tag for filtering purposes.
-    size = _getattr_as_list(rule, 'attr.size')
-    tags = _getattr_as_list(rule, 'attr.tags')
-    return struct(tags=tags + size)
-  else:
-    return None
+    # TODO(b/72406542): Clean this up to use a test provider if possible.
+    if rule.kind.endswith("_test"):
+        # Note that a test's size is considered a tag for filtering purposes.
+        size = _getattr_as_list(rule, "attr.size")
+        tags = _getattr_as_list(rule, "attr.tags")
+        return struct(tags = tags + size)
+    else:
+        return None
 
 def _tulsi_sources_aspect(target, ctx):
-  """Extracts information from a given rule, emitting it as a JSON struct."""
-  rule = ctx.rule
-  target_kind = rule.kind
-  rule_attr = _get_opt_attr(rule, 'attr')
-  filter = _filter_for_rule(rule)
+    """Extracts information from a given rule, emitting it as a JSON struct."""
+    rule = ctx.rule
+    target_kind = rule.kind
+    rule_attr = _get_opt_attr(rule, "attr")
+    filter = _filter_for_rule(rule)
 
-  tulsi_info_files = depset()
-  transitive_attributes = dict()
-  for attr_name in _TULSI_COMPILE_DEPS:
-    deps = _getattr_as_list(rule_attr, attr_name)
-    for dep in _filter_deps(filter, deps):
-      if hasattr(dep, 'tulsi_info_files'):
-        tulsi_info_files += dep.tulsi_info_files
-      if hasattr(dep, 'transitive_attributes'):
-        transitive_attributes += dep.transitive_attributes
+    tulsi_info_files = depset()
+    transitive_attributes = dict()
+    for attr_name in _TULSI_COMPILE_DEPS:
+        deps = _getattr_as_list(rule_attr, attr_name)
+        for dep in _filter_deps(filter, deps):
+            if hasattr(dep, "tulsi_info_files"):
+                tulsi_info_files += dep.tulsi_info_files
+            if hasattr(dep, "transitive_attributes"):
+                transitive_attributes += dep.transitive_attributes
 
-  artifacts = _get_opt_attr(target, 'files')
-  if artifacts:
-    # Ignore any generated Xcode projects as they are not useful to Tulsi.
-    artifacts = [_file_metadata(f)
-                 for f in artifacts
-                 if not f.short_path.endswith('project.pbxproj')]
-  else:
-    # artifacts may be an empty set type, in which case it must be explicitly
-    # set to None to allow Skylark's serialization to work.
-    artifacts = None
+    artifacts = _get_opt_attr(target, "files")
+    if artifacts:
+        # Ignore any generated Xcode projects as they are not useful to Tulsi.
+        artifacts = [_file_metadata(f) for f in artifacts if not f.short_path.endswith("project.pbxproj")]
+    else:
+        # artifacts may be an empty set type, in which case it must be explicitly
+        # set to None to allow Skylark's serialization to work.
+        artifacts = None
 
-  srcs = (_collect_files(rule, 'attr.srcs') +
-          _collect_files(rule, 'attr.hdrs') +
-          _collect_files(rule, 'attr.textual_hdrs'))
-  generated_files = []
-  generated_non_arc_files = []
-  if target_kind in _SOURCE_GENERATING_RULES:
-    generated_files = _extract_generated_sources(target)
-  elif target_kind in _NON_ARC_SOURCE_GENERATING_RULES:
-    generated_non_arc_files = _extract_generated_sources(target)
+    srcs = (_collect_files(rule, "attr.srcs") +
+            _collect_files(rule, "attr.hdrs") +
+            _collect_files(rule, "attr.textual_hdrs"))
+    generated_files = []
+    generated_non_arc_files = []
+    if target_kind in _SOURCE_GENERATING_RULES:
+        generated_files = _extract_generated_sources(target)
+    elif target_kind in _NON_ARC_SOURCE_GENERATING_RULES:
+        generated_non_arc_files = _extract_generated_sources(target)
 
-  swift_transitive_modules = depset(
-      [_file_metadata(f)
-       for f in _collect_swift_modules(target)])
+    swift_transitive_modules = depset(
+        [_file_metadata(f) for f in _collect_swift_modules(target)],
+    )
 
-  # Collect ObjC module maps dependencies for Swift targets.
-  objc_module_maps = depset(
-      [_file_metadata(f)
-       for f in _collect_module_maps(target)])
+    # Collect ObjC module maps dependencies for Swift targets.
+    objc_module_maps = depset(
+        [_file_metadata(f) for f in _collect_module_maps(target)],
+    )
 
-  # Collect the dependencies of this rule, dropping any .jar files (which may be
-  # created as artifacts of java/j2objc rules).
-  dep_labels = _collect_dependency_labels(rule, filter, _TULSI_COMPILE_DEPS)
-  compile_deps = [str(d) for d in dep_labels if not d.name.endswith('.jar')]
+    # Collect the dependencies of this rule, dropping any .jar files (which may be
+    # created as artifacts of java/j2objc rules).
+    dep_labels = _collect_dependency_labels(rule, filter, _TULSI_COMPILE_DEPS)
+    compile_deps = [str(d) for d in dep_labels if not d.name.endswith(".jar")]
 
-  binary_rule = _get_opt_attr(rule_attr, 'binary')
-  if binary_rule and type(binary_rule) == 'list':
-    binary_rule = binary_rule[0]
+    binary_rule = _get_opt_attr(rule_attr, "binary")
+    if binary_rule and type(binary_rule) == "list":
+        binary_rule = binary_rule[0]
 
-  supporting_files = (_collect_supporting_files(rule_attr) +
-                      _collect_asset_catalogs(rule_attr) +
-                      _collect_bundle_imports(rule_attr))
+    supporting_files = (_collect_supporting_files(rule_attr) +
+                        _collect_asset_catalogs(rule_attr) +
+                        _collect_bundle_imports(rule_attr))
 
-  copts_attr = _get_opt_attr(rule_attr, 'copts')
-  is_swift_library = target_kind == 'swift_library'
+    copts_attr = _get_opt_attr(rule_attr, "copts")
+    is_swift_library = target_kind == "swift_library"
 
-  # Keys for attribute and inheritable_attributes keys must be kept in sync
-  # with defines in Tulsi's RuleEntry.
-  attributes = _dict_omitting_none(
-      binary=_get_label_attr(binary_rule, 'label'),
-      copts=None if is_swift_library else copts_attr,
-      swiftc_opts=copts_attr if is_swift_library else None,
-      datamodels=_collect_xcdatamodeld_files(rule_attr, 'datamodels'),
-      supporting_files=supporting_files,
-      xctest_app=_get_label_attr(rule_attr, 'xctest_app.label'),
-      test_host=_get_label_attr(rule_attr, 'test_host.label'),
-      test_bundle=_get_label_attr(rule_attr, 'test_bundle.label'),
-  )
+    # Keys for attribute and inheritable_attributes keys must be kept in sync
+    # with defines in Tulsi's RuleEntry.
+    attributes = _dict_omitting_none(
+        binary = _get_label_attr(binary_rule, "label"),
+        copts = None if is_swift_library else copts_attr,
+        swiftc_opts = copts_attr if is_swift_library else None,
+        datamodels = _collect_xcdatamodeld_files(rule_attr, "datamodels"),
+        supporting_files = supporting_files,
+        xctest_app = _get_label_attr(rule_attr, "xctest_app.label"),
+        test_host = _get_label_attr(rule_attr, "test_host.label"),
+        test_bundle = _get_label_attr(rule_attr, "test_bundle.label"),
+    )
 
-  # Inheritable attributes are pulled up through dependencies of type 'binary'
-  # to simplify handling in Tulsi (so it appears as though bridging_header is
-  # defined on an ios_application rather than its associated objc_binary, for
-  # example).
-  inheritable_attributes = _dict_omitting_none(
-      bridging_header=_collect_first_file(rule_attr, 'bridging_header'),
-      compiler_defines=_extract_compiler_defines(ctx),
-      enable_modules=_get_opt_attr(rule_attr, 'enable_modules'),
-      launch_storyboard=_collect_first_file(rule_attr, 'launch_storyboard'),
-      pch=_collect_first_file(rule_attr, 'pch'),
-  )
+    # Inheritable attributes are pulled up through dependencies of type 'binary'
+    # to simplify handling in Tulsi (so it appears as though bridging_header is
+    # defined on an ios_application rather than its associated objc_binary, for
+    # example).
+    inheritable_attributes = _dict_omitting_none(
+        bridging_header = _collect_first_file(rule_attr, "bridging_header"),
+        compiler_defines = _extract_compiler_defines(ctx),
+        enable_modules = _get_opt_attr(rule_attr, "enable_modules"),
+        launch_storyboard = _collect_first_file(rule_attr, "launch_storyboard"),
+        pch = _collect_first_file(rule_attr, "pch"),
+    )
 
-  # Merge any attributes on the "binary" dependency into this container rule.
-  binary_attributes = _get_opt_attr(binary_rule, 'inheritable_attributes')
-  if binary_attributes:
-    inheritable_attributes = binary_attributes + inheritable_attributes
+    # Merge any attributes on the "binary" dependency into this container rule.
+    binary_attributes = _get_opt_attr(binary_rule, "inheritable_attributes")
+    if binary_attributes:
+        inheritable_attributes = binary_attributes + inheritable_attributes
 
-  extensions = [str(t.label) for t in _getattr_as_list(rule_attr, 'extensions')]
-  # Tulsi considers WatchOS apps and extensions as an "extension"
-  if target_kind == 'watchos_application':
-    watch_ext = _get_label_attr(rule_attr, 'extension.label')
-    extensions.append(watch_ext)
-  if target_kind == 'ios_application':
-    watch_app = _get_label_attr(rule_attr, 'watch_application.label')
-    if watch_app:
-      extensions.append(watch_app)
+    extensions = [str(t.label) for t in _getattr_as_list(rule_attr, "extensions")]
 
-  # Collect bundle related information.
-  if AppleBundleInfo in target:
-    apple_bundle_provider = target[AppleBundleInfo]
+    # Tulsi considers WatchOS apps and extensions as an "extension"
+    if target_kind == "watchos_application":
+        watch_ext = _get_label_attr(rule_attr, "extension.label")
+        extensions.append(watch_ext)
+    if target_kind == "ios_application":
+        watch_app = _get_label_attr(rule_attr, "watch_application.label")
+        if watch_app:
+            extensions.append(watch_app)
 
-    bundle_name = apple_bundle_provider.bundle_name
-    bundle_id = apple_bundle_provider.bundle_id
-    product_type = apple_bundle_provider.product_type
+            # Collect bundle related information.
+    if AppleBundleInfo in target:
+        apple_bundle_provider = target[AppleBundleInfo]
 
-    # We only need the infoplist from iOS extension targets.
-    infoplist = apple_bundle_provider.infoplist if IosExtensionBundleInfo in target else None
-  else:
-    bundle_name = None
-    # For macos_command_line_application, which does not have a AppleBundleInfo
-    # provider but does have a bundle_id attribute for use in the Info.plist.
-    bundle_id = _get_opt_attr(rule_attr, 'bundle_id')
-    product_type = None
-    infoplist = None
+        bundle_name = apple_bundle_provider.bundle_name
+        bundle_id = apple_bundle_provider.bundle_id
+        product_type = apple_bundle_provider.product_type
 
-  # Collect Swift related attributes.
-  if SwiftInfo in target:
-    attributes['has_swift_info'] = True
-    transitive_attributes['swift_language_version'] = target[SwiftInfo].swift_version
-    transitive_attributes['has_swift_dependency'] = True
+        # We only need the infoplist from iOS extension targets.
+        infoplist = apple_bundle_provider.infoplist if IosExtensionBundleInfo in target else None
+    else:
+        bundle_name = None
 
-  all_attributes = attributes + inheritable_attributes + transitive_attributes
+        # For macos_command_line_application, which does not have a AppleBundleInfo
+        # provider but does have a bundle_id attribute for use in the Info.plist.
+        bundle_id = _get_opt_attr(rule_attr, "bundle_id")
+        product_type = None
+        infoplist = None
 
-  objc_provider = _get_opt_attr(target, 'objc')
-  target_includes = []
-  target_defines = []
-  if objc_provider:
-    target_includes = [_convert_outpath_to_symlink_path(x)
-                       for x in objc_provider.include]
-    target_defines = objc_provider.define.to_list()
+        # Collect Swift related attributes.
+    if SwiftInfo in target:
+        attributes["has_swift_info"] = True
+        transitive_attributes["swift_language_version"] = target[SwiftInfo].swift_version
+        transitive_attributes["has_swift_dependency"] = True
 
-  platform_type, os_deployment_target = _get_deployment_info(target, ctx)
-  non_arc_srcs = _collect_files(rule, 'attr.non_arc_srcs')
+    all_attributes = attributes + inheritable_attributes + transitive_attributes
 
-  # Collect test information.
-  if AppleTestInfo in target:
-    provider = target[AppleTestInfo]
-    srcs = _depset_to_file_metadata_list(provider.sources)
-    non_arc_srcs = _depset_to_file_metadata_list(provider.non_arc_sources)
-    target_includes = [_convert_outpath_to_symlink_path(x) for x in provider.includes.to_list()]
-    swift_transitive_modules = _depset_to_file_metadata_list(provider.swift_modules)
-    objc_module_maps = _depset_to_file_metadata_list(provider.module_maps)
-  else:
-    swift_transitive_modules = swift_transitive_modules.to_list()
-    objc_module_maps = objc_module_maps.to_list()
+    objc_provider = _get_opt_attr(target, "objc")
+    target_includes = []
+    target_defines = []
+    if objc_provider:
+        target_includes = [_convert_outpath_to_symlink_path(x) for x in objc_provider.include]
+        target_defines = objc_provider.define.to_list()
 
-  info = _struct_omitting_none(
-      artifacts=artifacts,
-      attr=_struct_omitting_none(**all_attributes),
-      build_file=ctx.build_file_path,
-      bundle_id=bundle_id,
-      bundle_name=bundle_name,
-      defines=target_defines,
-      deps=compile_deps,
-      extensions=extensions,
-      framework_imports=_collect_framework_imports(rule_attr),
-      generated_files=generated_files,
-      generated_non_arc_files=generated_non_arc_files,
-      includes=target_includes,
-      os_deployment_target=os_deployment_target,
-      label=str(target.label),
-      non_arc_srcs=non_arc_srcs,
-      secondary_product_artifacts=_collect_secondary_artifacts(target, ctx),
-      srcs=srcs,
-      swift_transitive_modules=swift_transitive_modules,
-      objc_module_maps=objc_module_maps,
-      type=target_kind,
-      infoplist=infoplist.basename if infoplist else None,
-      platform_type=platform_type,
-      product_type=product_type,
-  )
+    platform_type, os_deployment_target = _get_deployment_info(target, ctx)
+    non_arc_srcs = _collect_files(rule, "attr.non_arc_srcs")
 
-  # Create an action to write out this target's info.
-  output = ctx.new_file(target.label.name + '.tulsiinfo')
-  ctx.file_action(output, info.to_json())
-  tulsi_info_files += depset([output])
+    # Collect test information.
+    if AppleTestInfo in target:
+        provider = target[AppleTestInfo]
+        srcs = _depset_to_file_metadata_list(provider.sources)
+        non_arc_srcs = _depset_to_file_metadata_list(provider.non_arc_sources)
+        target_includes = [_convert_outpath_to_symlink_path(x) for x in provider.includes.to_list()]
+        swift_transitive_modules = _depset_to_file_metadata_list(provider.swift_modules)
+        objc_module_maps = _depset_to_file_metadata_list(provider.module_maps)
+    else:
+        swift_transitive_modules = swift_transitive_modules.to_list()
+        objc_module_maps = objc_module_maps.to_list()
 
-  if infoplist:
-    tulsi_info_files += [infoplist]
+    info = _struct_omitting_none(
+        artifacts = artifacts,
+        attr = _struct_omitting_none(**all_attributes),
+        build_file = ctx.build_file_path,
+        bundle_id = bundle_id,
+        bundle_name = bundle_name,
+        defines = target_defines,
+        deps = compile_deps,
+        extensions = extensions,
+        framework_imports = _collect_framework_imports(rule_attr),
+        generated_files = generated_files,
+        generated_non_arc_files = generated_non_arc_files,
+        includes = target_includes,
+        os_deployment_target = os_deployment_target,
+        label = str(target.label),
+        non_arc_srcs = non_arc_srcs,
+        secondary_product_artifacts = _collect_secondary_artifacts(target, ctx),
+        srcs = srcs,
+        swift_transitive_modules = swift_transitive_modules,
+        objc_module_maps = objc_module_maps,
+        type = target_kind,
+        infoplist = infoplist.basename if infoplist else None,
+        platform_type = platform_type,
+        product_type = product_type,
+    )
 
-  artifacts_depset = depset(artifacts) if artifacts else depset()
+    # Create an action to write out this target's info.
+    output = ctx.new_file(target.label.name + ".tulsiinfo")
+    ctx.file_action(output, info.to_json())
+    tulsi_info_files += depset([output])
 
-  return struct(
-      # Matches the --output_groups on the bazel commandline.
-      output_groups={
-          'tulsi-info': tulsi_info_files,
-      },
-      # The file actions used to save this rule's info and that of all of its
-      # transitive dependencies.
-      tulsi_info_files=tulsi_info_files,
-      # The inheritable attributes of this rule, expressed as a dict instead of
-      # a struct to allow easy joining.
-      inheritable_attributes=inheritable_attributes,
-      # Transitive info that should be applied to every rule that depends on
-      # this rule.
-      transitive_attributes=transitive_attributes,
-      # Artifacts from this rule.
-      artifacts=artifacts_depset,
-      # Filtering information for this target.
-      filtering_info=_target_filtering_info(ctx),
-  )
+    if infoplist:
+        tulsi_info_files += [infoplist]
+
+    artifacts_depset = depset(artifacts) if artifacts else depset()
+
+    return struct(
+        # Matches the --output_groups on the bazel commandline.
+        output_groups = {
+            "tulsi-info": tulsi_info_files,
+        },
+        # The file actions used to save this rule's info and that of all of its
+        # transitive dependencies.
+        tulsi_info_files = tulsi_info_files,
+        # The inheritable attributes of this rule, expressed as a dict instead of
+        # a struct to allow easy joining.
+        inheritable_attributes = inheritable_attributes,
+        # Transitive info that should be applied to every rule that depends on
+        # this rule.
+        transitive_attributes = transitive_attributes,
+        # Artifacts from this rule.
+        artifacts = artifacts_depset,
+        # Filtering information for this target.
+        filtering_info = _target_filtering_info(ctx),
+    )
 
 def _collect_bundle_info(target):
-  """Returns Apple bundle info for the given target, None if not a bundle."""
-  if AppleBundleInfo in target:
-    apple_bundle = target[AppleBundleInfo]
-    has_dsym = (apple_common.AppleDebugOutputs in target)
-    return [struct(
-        archive_root=apple_bundle.archive_root,
-        bundle_name=apple_bundle.bundle_name,
-        bundle_extension=apple_bundle.bundle_extension,
-        has_dsym=has_dsym)]
+    """Returns Apple bundle info for the given target, None if not a bundle."""
+    if AppleBundleInfo in target:
+        apple_bundle = target[AppleBundleInfo]
+        has_dsym = (apple_common.AppleDebugOutputs in target)
+        return [struct(
+            archive_root = apple_bundle.archive_root,
+            bundle_name = apple_bundle.bundle_name,
+            bundle_extension = apple_bundle.bundle_extension,
+            has_dsym = has_dsym,
+        )]
 
-  return None
+    return None
 
-# Due to b/71744111 we have to manually re-create tag filtering for test_suite
-# rules.
+    # Due to b/71744111 we have to manually re-create tag filtering for test_suite
+    # rules.
+
 def _tags_conform_to_filter(tags, filter):
-  """Mirrors Bazel tag filtering for test_suites.
+    """Mirrors Bazel tag filtering for test_suites.
 
   This makes sure that the target has all of the required tags and none of
   the excluded tags before we include them within a test_suite.
@@ -755,158 +764,159 @@
 
   """
 
-  # None of the excluded tags can be present.
-  for exclude in filter.excluded_tags:
-    if exclude in tags:
-      return False
+    # None of the excluded tags can be present.
+    for exclude in filter.excluded_tags:
+        if exclude in tags:
+            return False
 
-  # All of the required tags must be present.
-  for required in filter.required_tags:
-    if required not in tags:
-      return False
+            # All of the required tags must be present.
+    for required in filter.required_tags:
+        if required not in tags:
+            return False
 
-  # All filters have been satisfied.
-  return True
+            # All filters have been satisfied.
+    return True
 
 def _filter_for_rule(rule):
-  """Returns a filter for test_suite rules and None for other rules."""
-  if rule.kind != 'test_suite':
-    return None
+    """Returns a filter for test_suite rules and None for other rules."""
+    if rule.kind != "test_suite":
+        return None
 
-  excluded_tags = []
-  required_tags = []
+    excluded_tags = []
+    required_tags = []
 
-  tags = _getattr_as_list(rule, 'attr.tags')
+    tags = _getattr_as_list(rule, "attr.tags")
 
-  for tag in tags:
-    if tag.startswith('-'):
-      excluded_tags.append(tag[1:])
-    elif tag.startswith('+'):
-      required_tags.append(tag[1:])
-    elif tag == 'manual':
-      # The manual tag is treated specially; it is ignored for filters.
-      continue
-    else:
-      required_tags.append(tag)
-  return struct(
-      excluded_tags=excluded_tags,
-      required_tags=required_tags,
-  )
+    for tag in tags:
+        if tag.startswith("-"):
+            excluded_tags.append(tag[1:])
+        elif tag.startswith("+"):
+            required_tags.append(tag[1:])
+        elif tag == "manual":
+            # The manual tag is treated specially; it is ignored for filters.
+            continue
+        else:
+            required_tags.append(tag)
+    return struct(
+        excluded_tags = excluded_tags,
+        required_tags = required_tags,
+    )
 
 def _filter_deps(filter, deps):
-  """Filters dep targets based on tags."""
-  if not filter:
-    return deps
+    """Filters dep targets based on tags."""
+    if not filter:
+        return deps
 
-  kept_deps = []
-  for dep in deps:
-    info = dep.filtering_info
-    # Only attempt to filter targets that support filtering.
-    # test_suites in a test_suite are not filtered, but their
-    # tests are.
-    if not info or _tags_conform_to_filter(info.tags, filter):
-      kept_deps.append(dep)
-  return kept_deps
+    kept_deps = []
+    for dep in deps:
+        info = dep.filtering_info
+
+        # Only attempt to filter targets that support filtering.
+        # test_suites in a test_suite are not filtered, but their
+        # tests are.
+        if not info or _tags_conform_to_filter(info.tags, filter):
+            kept_deps.append(dep)
+    return kept_deps
 
 def _tulsi_outputs_aspect(target, ctx):
-  """Collects outputs of each build invocation."""
+    """Collects outputs of each build invocation."""
 
-  rule = ctx.rule
-  target_kind = rule.kind
-  rule_attr = _get_opt_attr(rule, 'attr')
-  tulsi_generated_files = depset()
+    rule = ctx.rule
+    target_kind = rule.kind
+    rule_attr = _get_opt_attr(rule, "attr")
+    tulsi_generated_files = depset()
 
-  # A set of all bundles embedded into this target, including deps.
-  # We intentionally do not collect info about _current_ target to exclude the
-  # root target, which will be covered by other structs in this aspect, from the
-  # set.
-  embedded_bundles = depset()
+    # A set of all bundles embedded into this target, including deps.
+    # We intentionally do not collect info about _current_ target to exclude the
+    # root target, which will be covered by other structs in this aspect, from the
+    # set.
+    embedded_bundles = depset()
 
-  for attr_name in _TULSI_COMPILE_DEPS:
-    deps = _getattr_as_list(rule_attr, attr_name)
-    for dep in deps:
-      if hasattr(dep, 'tulsi_generated_files'):
-        tulsi_generated_files += dep.tulsi_generated_files
+    for attr_name in _TULSI_COMPILE_DEPS:
+        deps = _getattr_as_list(rule_attr, attr_name)
+        for dep in deps:
+            if hasattr(dep, "tulsi_generated_files"):
+                tulsi_generated_files += dep.tulsi_generated_files
 
-      # Retrieve the bundle info for embeddable attributes.
-      if attr_name not in _TULSI_NON_EMBEDDEDABLE_ATTRS:
-        dep_bundle_info = _collect_bundle_info(dep)
-        if dep_bundle_info:
-          embedded_bundles += dep_bundle_info
-      if hasattr(dep, 'transitive_embedded_bundles'):
-        embedded_bundles += dep.transitive_embedded_bundles
+                # Retrieve the bundle info for embeddable attributes.
+            if attr_name not in _TULSI_NON_EMBEDDEDABLE_ATTRS:
+                dep_bundle_info = _collect_bundle_info(dep)
+                if dep_bundle_info:
+                    embedded_bundles += dep_bundle_info
+            if hasattr(dep, "transitive_embedded_bundles"):
+                embedded_bundles += dep.transitive_embedded_bundles
 
-  artifact = None
-  bundle_name = None
-  archive_root = None
-  bundle_dir = None
-  if AppleBundleInfo in target:
-    bundle_info = target[AppleBundleInfo]
+    artifact = None
+    bundle_name = None
+    archive_root = None
+    bundle_dir = None
+    if AppleBundleInfo in target:
+        bundle_info = target[AppleBundleInfo]
 
-    artifact = bundle_info.archive.path
-    archive_root = bundle_info.archive_root
+        artifact = bundle_info.archive.path
+        archive_root = bundle_info.archive_root
 
-    bundle_name = bundle_info.bundle_name
-    bundle_dir = bundle_info.bundle_dir
-  elif target_kind == 'macos_command_line_application':
-    # Special support for macos_command_line_application which does not have an
-    # AppleBundleInfo provider.
+        bundle_name = bundle_info.bundle_name
+        bundle_dir = bundle_info.bundle_dir
+    elif target_kind == "macos_command_line_application":
+        # Special support for macos_command_line_application which does not have an
+        # AppleBundleInfo provider.
 
-    # Both the dSYM binary and executable binary don't have an extension, so
-    # pick the first extension-less file not in a DWARF folder.
-    artifacts = [x.path for x in target.files.to_list()
-                 if x.extension == ''
-                 and 'Contents/Resources/DWARF' not in x.path]
-    if len(artifacts) > 0:
-      artifact = artifacts[0]
+        # Both the dSYM binary and executable binary don't have an extension, so
+        # pick the first extension-less file not in a DWARF folder.
+        artifacts = [x.path for x in target.files.to_list() if x.extension == "" and
+                                                               "Contents/Resources/DWARF" not in x.path]
+        if len(artifacts) > 0:
+            artifact = artifacts[0]
 
-  # Collect generated files for bazel_build.py to copy under Tulsi root.
-  all_files = depset()
-  if target_kind in _SOURCE_GENERATING_RULES + _NON_ARC_SOURCE_GENERATING_RULES:
-    objc_provider = _get_opt_attr(target, 'objc')
-    if hasattr(objc_provider, 'source') and hasattr(objc_provider, 'header'):
-      all_files += objc_provider.source
-      all_files += objc_provider.header
+            # Collect generated files for bazel_build.py to copy under Tulsi root.
+    all_files = depset()
+    if target_kind in _SOURCE_GENERATING_RULES + _NON_ARC_SOURCE_GENERATING_RULES:
+        objc_provider = _get_opt_attr(target, "objc")
+        if hasattr(objc_provider, "source") and hasattr(objc_provider, "header"):
+            all_files += objc_provider.source
+            all_files += objc_provider.header
 
-  all_files += _collect_swift_header(target)
-  all_files += _collect_swift_modules(target)
-  all_files += _collect_module_maps(target)
-  all_files += (_collect_artifacts(rule, 'attr.srcs')
-                + _collect_artifacts(rule, 'attr.hdrs')
-                + _collect_artifacts(rule, 'attr.textual_hdrs'))
-  all_files += _collect_supporting_files(rule_attr, convert_to_metadata=False)
-  source_files = [x for x in target.files.to_list()
-                  if x.extension.lower() in _GENERATED_SOURCE_FILE_EXTENSIONS]
-  all_files = depset(source_files, transitive=[all_files])
+    all_files += _collect_swift_header(target)
+    all_files += _collect_swift_modules(target)
+    all_files += _collect_module_maps(target)
+    all_files += (_collect_artifacts(rule, "attr.srcs") +
+                  _collect_artifacts(rule, "attr.hdrs") +
+                  _collect_artifacts(rule, "attr.textual_hdrs"))
+    all_files += _collect_supporting_files(rule_attr, convert_to_metadata = False)
+    source_files = [x for x in target.files.to_list() if x.extension.lower() in _GENERATED_SOURCE_FILE_EXTENSIONS]
+    all_files = depset(source_files, transitive = [all_files])
 
-  tulsi_generated_files += depset(
-      [x for x in all_files.to_list() if not x.is_source])
+    tulsi_generated_files += depset(
+        [x for x in all_files.to_list() if not x.is_source],
+    )
 
-  has_dsym = False
-  if hasattr(ctx.fragments, 'objc'):
-    # Check the fragment directly, as macos_command_line_application does not
-    # propagate apple_common.AppleDebugOutputs.
-    has_dsym = ctx.fragments.objc.generate_dsym
+    has_dsym = False
+    if hasattr(ctx.fragments, "objc"):
+        # Check the fragment directly, as macos_command_line_application does not
+        # propagate apple_common.AppleDebugOutputs.
+        has_dsym = ctx.fragments.objc.generate_dsym
 
-  info = _struct_omitting_none(
-      artifact=artifact,
-      bundle_dir=bundle_dir,
-      archive_root=archive_root,
-      generated_sources=[(x.path, x.short_path) for x in tulsi_generated_files],
-      bundle_name=bundle_name,
-      embedded_bundles=embedded_bundles.to_list(),
-      has_dsym=has_dsym)
+    info = _struct_omitting_none(
+        artifact = artifact,
+        bundle_dir = bundle_dir,
+        archive_root = archive_root,
+        generated_sources = [(x.path, x.short_path) for x in tulsi_generated_files],
+        bundle_name = bundle_name,
+        embedded_bundles = embedded_bundles.to_list(),
+        has_dsym = has_dsym,
+    )
 
-  output = ctx.new_file(target.label.name + '.tulsiouts')
-  ctx.file_action(output, info.to_json())
+    output = ctx.new_file(target.label.name + ".tulsiouts")
+    ctx.file_action(output, info.to_json())
 
-  return struct(
-      output_groups={
-          'tulsi-outputs': [output],
-      },
-      tulsi_generated_files=tulsi_generated_files,
-      transitive_embedded_bundles=embedded_bundles
-  )
+    return struct(
+        output_groups = {
+            "tulsi-outputs": [output],
+        },
+        tulsi_generated_files = tulsi_generated_files,
+        transitive_embedded_bundles = embedded_bundles,
+    )
 
 tulsi_sources_aspect = aspect(
     attr_aspects = _TULSI_COMPILE_DEPS,
diff --git a/src/TulsiGeneratorIntegrationTests/Resources/ComplexSingle.bzl b/src/TulsiGeneratorIntegrationTests/Resources/ComplexSingle.bzl
index 18cd62b..6734ded 100644
--- a/src/TulsiGeneratorIntegrationTests/Resources/ComplexSingle.bzl
+++ b/src/TulsiGeneratorIntegrationTests/Resources/ComplexSingle.bzl
@@ -15,5 +15,5 @@
 """Mock Skylark file for testing."""
 
 def test_macro():
-  """A do-nothing macro for use in Tulsi tests."""
-  pass
+    """A do-nothing macro for use in Tulsi tests."""
+    pass
diff --git a/version.bzl b/version.bzl
index b5f187f..45203db 100644
--- a/version.bzl
+++ b/version.bzl
@@ -28,14 +28,14 @@
 )
 
 def fill_info_plist_impl(ctx):
-  ctx.actions.expand_template(
-      template = ctx.file.template,
-      output = ctx.outputs.out,
-      substitutions = {
-          "$(TULSI_VERSIONINFO_ABOUT)": TULSI_VERSIONINFO_ABOUT,
-          "$(PRODUCT_MODULE_NAME)": TULSI_PRODUCT_NAME,
-      },
-  )
+    ctx.actions.expand_template(
+        template = ctx.file.template,
+        output = ctx.outputs.out,
+        substitutions = {
+            "$(TULSI_VERSIONINFO_ABOUT)": TULSI_VERSIONINFO_ABOUT,
+            "$(PRODUCT_MODULE_NAME)": TULSI_PRODUCT_NAME,
+        },
+    )
 
 fill_info_plist = rule(
     attrs = {