update_crate_tests: fail gracefully

Allow this script to accept a path to the crate being updated.
This allows it to be run separately from cargo2android.

Also, fail gracefully on error. TEST_MAPPING update failures should
not block crate updates.

Test: tools/external_updater/updater.sh update rust/crates/libc
Bug: 179132533
Change-Id: I3a4229f479ab3d2793df16b470f0a0632b9ee495
diff --git a/scripts/update_crate_tests.py b/scripts/update_crate_tests.py
index bfcc4cf..09d7096 100755
--- a/scripts/update_crate_tests.py
+++ b/scripts/update_crate_tests.py
@@ -33,22 +33,31 @@
     ]
 
 class Env(object):
-    def __init__(self):
+    def __init__(self, path):
         try:
             self.ANDROID_BUILD_TOP = os.environ['ANDROID_BUILD_TOP']
         except:
             sys.exit('ERROR: this script must be run from an Android tree.')
-        self.cwd = os.getcwd()
-        self.cwd_relative = self.cwd.split(self.ANDROID_BUILD_TOP)[1]
+        if path == None:
+            self.cwd = os.getcwd()
+        else:
+            self.cwd = path
+        try:
+            self.cwd_relative = self.cwd.split(self.ANDROID_BUILD_TOP)[1]
+        except:
+            sys.exit("Exit if we're not being run from a Rust dir.")
 
 class Bazel(object):
     # set up the Bazel queryview
     def __init__(self, env):
         os.chdir(env.ANDROID_BUILD_TOP)
-        if not os.path.exists("out/soong/queryview"):
-            print("Building Bazel Queryview. This can take a couple of minutes...")
-            cmd = "./build/soong/soong_ui.bash --build-mode --all-modules --dir=. queryview"
-            subprocess.check_output(cmd, shell=True)
+        print("Building Bazel Queryview. This can take a couple of minutes...")
+        cmd = "./build/soong/soong_ui.bash --build-mode --all-modules --dir=. queryview"
+        try:
+            out = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
+        except subprocess.CalledProcessError as e:
+            print("Error: Unable to update TEST_MAPPING due to the following build error:")
+            sys.exit(e.output)
         os.chdir(env.cwd)
 
     def path(self):
@@ -90,7 +99,6 @@
     # Return all reverse dependency tests for modules in this package.
     def query_rdep_tests(self, modules):
         rdep_tests = set()
-        print("Querying tests that depend on this crate for TEST_MAPPING. This can take a couple of minutes...")
         for module in modules:
             for rdep in self.query_rdeps(module):
                 rule_type, tmp, mod = rdep.split(" ")
@@ -110,8 +118,8 @@
 
 
 class TestMapping(object):
-    def __init__(self):
-        self.env = Env()
+    def __init__(self, path):
+        self.env = Env(path)
         self.bazel = Bazel(self.env)
 
     def create_test_mapping(self, path):
@@ -141,12 +149,17 @@
 
     def write_test_mapping(self, test_mapping):
         with open("TEST_MAPPING", "w") as json_file:
-            json_file.write("// Generated by cargo2android.py for tests that depend on this crate.\n")
+            json_file.write("// Generated by update_crate_tests.py for tests that depend on this crate.\n")
             json.dump(test_mapping, json_file, indent=2, separators=(',', ': '), sort_keys=True)
             json_file.write("\n")
+        print("TEST_MAPPING successfully updated!")
 
 def main():
-    TestMapping().create_test_mapping(None)
+    if len(sys.argv) == 2:
+        path = sys.argv[1]
+    else:
+        path = None
+    TestMapping(path).create_test_mapping(None)
 
 if __name__ == '__main__':
   main()