Add [Builtin Hooks Exclude Paths] section

There is currently no convenient option to enable a hook globally if
some projects will fail the processing. The recommended setup is to
enable the hook within each project's repository (using PREUPLOAD.cfg).
This creates inconsistencies for large codebase. Adds a new
configuration section to explicitly exclude some projects during the
processing of a hook.

The intent of this change is to enable rustfmt globally in AOSP,
except for some paths (e.g. external/, vendor/).

Test: Modified GLOBAL-PREUPLOAD.cfg to enable the new option,
  manually creates changes and review output of pre-upload.py
Bug: 160223496
Change-Id: I94dbbf0ce2e6b58c4d4b4fc89c56a2a87543d878
diff --git a/rh/config_unittest.py b/rh/config_unittest.py
index c8aceb9..4b27c5a 100755
--- a/rh/config_unittest.py
+++ b/rh/config_unittest.py
@@ -133,6 +133,19 @@
                           path)
 
 
+class LocalPreUploadFileTests(FileTestCase):
+    """Test for the LocalPreUploadFile class."""
+
+    def testInvalidSectionConfig(self):
+        """Reject local config that uses invalid sections."""
+        path = self._write_config("""[Builtin Hooks Exclude Paths]
+cpplint = external/ 'test directory' ^vendor/(?!google/)
+""")
+        self.assertRaises(rh.config.ValidationError,
+                          rh.config.LocalPreUploadFile,
+                          path)
+
+
 class PreUploadSettingsTests(FileTestCase):
     """Tests for the PreUploadSettings class."""
 
@@ -150,6 +163,13 @@
         self.assertEqual(config.builtin_hooks,
                          ['commit_msg_changeid_field', 'commit_msg_test_field'])
 
+    def testGlobalExcludeScope(self):
+        """Verify exclude scope is valid for global config."""
+        self._write_global_config("""[Builtin Hooks Exclude Paths]
+cpplint = external/ 'test directory' ^vendor/(?!google/)
+""")
+        rh.config.PreUploadSettings(global_paths=(self.tempdir,))
+
 
 if __name__ == '__main__':
     unittest.main()