[build] Handle subdirectory BUILD files (#30292)

* progress

* progress

* progress

* progress

* Automated change: Fix sanity tests

* progress

* progress

* progress

* progress

* fixes

* fix

* progress

* progress

* progress

* progress

* Automated change: Fix sanity tests

* fix

* handle relative paths

* [build] Handle subdirectory BUILD files

* Automated change: Fix sanity tests

* fix

Co-authored-by: ctiller <ctiller@users.noreply.github.com>
diff --git a/test/core/uri/BUILD b/test/core/uri/BUILD
index bf8d369..6a8dddb 100644
--- a/test/core/uri/BUILD
+++ b/test/core/uri/BUILD
@@ -24,11 +24,14 @@
     srcs = ["uri_fuzzer_test.cc"],
     corpus = "uri_corpus",
     language = "C++",
-    tags = ["no_windows"],
+    tags = [
+        "no_windows",
+    ],
     deps = [
-        "//:gpr",
-        "//:grpc",
-        "//test/core/util:grpc_test_util",
+        "//:exec_ctx",
+        "//:gpr_base",
+        "//:grpc_trace",
+        "//:uri_parser",
     ],
 )
 
@@ -37,6 +40,7 @@
     srcs = ["uri_parser_test.cc"],
     external_deps = ["gtest"],
     language = "C++",
+    tags = ["nofixdeps"],
     deps = [
         "//:grpc",
         "//test/core/util:grpc_test_util",
diff --git a/tools/distrib/fix_build_deps.py b/tools/distrib/fix_build_deps.py
index 39a5ad0..4fe62f1 100755
--- a/tools/distrib/fix_build_deps.py
+++ b/tools/distrib/fix_build_deps.py
@@ -246,6 +246,7 @@
 
 num_cc_libraries = 0
 num_opted_out_cc_libraries = 0
+parsing_path = None
 
 
 def grpc_cc_library(name,
@@ -260,6 +261,9 @@
     global args
     global num_cc_libraries
     global num_opted_out_cc_libraries
+    global parsing_path
+    assert (parsing_path is not None)
+    name = '//%s:%s' % (parsing_path, name)
     num_cc_libraries += 1
     if select_deps or 'nofixdeps' in tags:
         if args.whats_left and not select_deps and 'nofixdeps' not in tags:
@@ -280,14 +284,15 @@
     original_deps[name] = frozenset(deps)
     original_external_deps[name] = frozenset(external_deps)
     for src in hdrs + public_hdrs + srcs:
-        for line in open(src):
+        for line in open('%s%s' %
+                         ((parsing_path + '/' if parsing_path else ''), src)):
             m = re.search(r'#include <(.*)>', line)
             if m:
                 inc.add(m.group(1))
             m = re.search(r'#include "(.*)"', line)
             if m:
                 inc.add(m.group(1))
-            if 'grpc::g_glip' in line or 'grpc:g_core_codegen_interface' in line:
+            if 'grpc::g_glip' in line or 'grpc::g_core_codegen_interface' in line:
                 needs_codegen_base_src.add(name)
     consumes[name] = list(inc)
 
@@ -360,22 +365,42 @@
                     help='show what is left to opt in')
 args = parser.parse_args()
 
-exec(
-    open('BUILD', 'r').read(), {
-        'load': lambda filename, *args: None,
-        'licenses': lambda licenses: None,
-        'package': lambda **kwargs: None,
-        'exports_files': lambda files: None,
-        'config_setting': lambda **kwargs: None,
-        'selects': FakeSelects(),
-        'python_config_settings': lambda **kwargs: None,
-        'grpc_cc_library': grpc_cc_library,
-        'select': lambda d: d["//conditions:default"],
-        'grpc_upb_proto_library': lambda name, **kwargs: None,
-        'grpc_upb_proto_reflection_library': lambda name, **kwargs: None,
-        'grpc_generate_one_off_targets': lambda: None,
-        'filegroup': lambda name, **kwargs: None,
-    }, {})
+for dirname in ["", "test/core/uri"]:
+    parsing_path = dirname
+    exec(
+        open('%sBUILD' % (dirname + '/' if dirname else ''), 'r').read(), {
+            'load': lambda filename, *args: None,
+            'licenses': lambda licenses: None,
+            'package': lambda **kwargs: None,
+            'exports_files': lambda files: None,
+            'config_setting': lambda **kwargs: None,
+            'selects': FakeSelects(),
+            'python_config_settings': lambda **kwargs: None,
+            'grpc_cc_library': grpc_cc_library,
+            'grpc_cc_test': grpc_cc_library,
+            'grpc_fuzzer': grpc_cc_library,
+            'select': lambda d: d["//conditions:default"],
+            'grpc_upb_proto_library': lambda name, **kwargs: None,
+            'grpc_upb_proto_reflection_library': lambda name, **kwargs: None,
+            'grpc_generate_one_off_targets': lambda: None,
+            'grpc_package': lambda **kwargs: None,
+            'filegroup': lambda name, **kwargs: None,
+        }, {})
+    parsing_path = None
+
+if args.whats_left:
+    print("{}/{} libraries are opted in".format(
+        num_cc_libraries - num_opted_out_cc_libraries, num_cc_libraries))
+
+
+def make_relative_path(dep, lib):
+    if lib is None:
+        return dep
+    lib_path = lib[:lib.rfind(':') + 1]
+    if dep.startswith(lib_path):
+        return dep[len(lib_path):]
+    return dep
+
 
 if args.whats_left:
     print("{}/{} libraries are opted in".format(
@@ -386,20 +411,23 @@
 # problem. (models the list monad in Haskell!)
 class Choices:
 
-    def __init__(self):
+    def __init__(self, library):
+        self.library = library
         self.to_add = []
         self.to_remove = []
 
     def add_one_of(self, choices):
         if not choices:
             return
-        self.to_add.append(tuple(choices))
+        self.to_add.append(
+            tuple(
+                make_relative_path(choice, self.library) for choice in choices))
 
     def add(self, choice):
         self.add_one_of([choice])
 
     def remove(self, remove):
-        self.to_remove.append(remove)
+        self.to_remove.append(make_relative_path(remove, self.library))
 
     def best(self, scorer):
         choices = set()
@@ -428,8 +456,8 @@
 def make_library(library):
     error = False
     hdrs = sorted(consumes[library])
-    deps = Choices()
-    external_deps = Choices()
+    deps = Choices(library)
+    external_deps = Choices(None)
     for hdr in hdrs:
         if hdr == 'src/core/lib/profiling/stap_probes.h':
             continue
@@ -527,9 +555,8 @@
     if lib_error:
         error = True
         continue
-    target = ':' + library
-    buildozer_set_list('external_deps', external_deps, target, via='deps')
-    buildozer_set_list('deps', deps, target)
+    buildozer_set_list('external_deps', external_deps, library, via='deps')
+    buildozer_set_list('deps', deps, library)
 
 if buildozer_commands:
     ok_statuses = (0, 3)