repohooks: Support --exclude-dirs in aosp_license

So that the project can exclude some dirs for this check. Example usage:

```
[Builtin Hooks Options]
aosp_license = --exclude-dirs=path1,path2
```

Bug: 370907797
Test: Manually verified with the above example.
Change-Id: I09ecf39e0919697fcb29c9c095148696ef317f21
Reviewed-on: https://android-review.googlesource.com/c/platform/tools/repohooks/+/3290184
Autosubmit: Jie Jiang <jiejiang@google.com>
Reviewed-by: Tim Bain <tbain@google.com>
Performance: CrystalBall Performance Presubmit <android-crystalball-presubmit-eng@google.com>
Presubmit-Verified: Treehugger Robot <android-test-infra-workplan-finisher@system.gserviceaccount.com>
Lint: Lint 🤖 <ayeaye-gerrit@google.com>
diff --git a/rh/hooks.py b/rh/hooks.py
index 2117890..5dc7911 100644
--- a/rh/hooks.py
+++ b/rh/hooks.py
@@ -345,7 +345,12 @@
 
 def check_aosp_license(project, commit, _desc, diff, options=None):
     """Checks that if all new added files has AOSP licenses"""
-    # TODO(b/370907797): Support option to exclude files with certain patterns.
+
+    exclude_dir_args = [x for x in options.args()
+                        if x.startswith('--exclude-dirs=')]
+    exclude_dirs = [x[len('--exclude-dirs='):].split(',')
+                    for x in exclude_dir_args]
+    exclude_list = [fr'^{x}/.*$' for dir_list in exclude_dirs for x in dir_list]
 
     # Filter diff based on extension.
     include_list = [
@@ -364,7 +369,7 @@
         r".*\.bp$",
         r".*\.xml$",
     ]
-    diff = _filter_diff(diff, include_list)
+    diff = _filter_diff(diff, include_list, exclude_list)
 
     # Only check the new-added files.
     diff = [d for d in diff if d.status == 'A']
@@ -373,7 +378,7 @@
         return None
 
     cmd = [get_helper_path('check_aosp_license.py'), '--commit_hash', commit]
-    cmd += options.args(('${PREUPLOAD_FILES}',), diff)
+    cmd += HookOptions.expand_vars(('${PREUPLOAD_FILES}',), diff)
     return _check_cmd('aosp_license', project, commit, cmd)
 
 
diff --git a/rh/hooks_unittest.py b/rh/hooks_unittest.py
index 2cd52bf..1fc0c15 100755
--- a/rh/hooks_unittest.py
+++ b/rh/hooks_unittest.py
@@ -391,6 +391,30 @@
             self.project, 'commit', 'desc', diff, options=self.options)
         self.assertIsNotNone(ret)
 
+        # No result since all paths are excluded.
+        diff = [
+            rh.git.RawDiffEntry(file='a/a.bp', status='A'),
+            rh.git.RawDiffEntry(file='b/a.bp', status='A'),
+            rh.git.RawDiffEntry(file='c/d/a.bp', status='A'),
+        ]
+        ret = rh.hooks.check_aosp_license(
+            self.project, 'commit', 'desc', diff,
+            options=rh.hooks.HookOptions('hook name',
+                ['--exclude-dirs=a,b', '--exclude-dirs=c/d'], {})
+        )
+        self.assertIsNone(ret)
+
+        # Make sure that `--exclude-dir` doesn't match the path in the middle.
+        diff = [
+            rh.git.RawDiffEntry(file='a/b/c.bp', status='A'),
+        ]
+        ret = rh.hooks.check_aosp_license(
+            self.project, 'commit', 'desc', diff,
+            options=rh.hooks.HookOptions('hook name', ['--exclude-dirs=b'], {})
+        )
+        self.assertIsNotNone(ret)
+
+
     def test_bpfmt(self, mock_check, _mock_run):
         """Verify the bpfmt builtin hook."""
         # First call should do nothing as there are no files to check.