pre-upload: Filter out enabled hooks from common hook list

Otherwise some hooks (such as cros_license_check) would run twice when
enabled with custom options, the second run without the requested
options.

Also refactor some of the code to make it cleaner.

BUG=chromium:541707
TEST=Ran a presubmit with cros_license_check options successfully.

Change-Id: I80e9d290434f42ed7927d175fbad153950678c4a
Signed-off-by: Filipe Brandenburger <filbranden@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/304869
Reviewed-by: Mike Frysinger <vapier@chromium.org>
diff --git a/pre-upload.py b/pre-upload.py
index 1d2c5b1..011457f 100755
--- a/pre-upload.py
+++ b/pre-upload.py
@@ -1378,13 +1378,21 @@
     config = ConfigParser.RawConfigParser()
 
   if presubmit:
-    hook_list = _COMMON_HOOKS
+    hooks = _COMMON_HOOKS
   else:
-    hook_list = _PATCH_DESCRIPTION_HOOKS + _COMMON_HOOKS
+    hooks = _PATCH_DESCRIPTION_HOOKS + _COMMON_HOOKS
 
   enabled_hooks, disabled_hooks = _get_override_hooks(config)
-  hooks = (list(enabled_hooks) +
-           [hook for hook in hook_list if hook not in disabled_hooks])
+  hooks = [hook for hook in hooks if hook not in disabled_hooks]
+
+  # If a list is both in _COMMON_HOOKS and also enabled explicitly through an
+  # override, keep the override only.  Note that the override may end up being
+  # a functools.partial, in which case we need to extract the .func to compare
+  # it to the common hooks.
+  unwrapped_hooks = [getattr(hook, 'func', hook) for hook in enabled_hooks]
+  hooks = [hook for hook in hooks if hook not in unwrapped_hooks]
+
+  hooks = list(enabled_hooks) + hooks
 
   if project in _PROJECT_SPECIFIC_HOOKS:
     hooks.extend(hook for hook in _PROJECT_SPECIFIC_HOOKS[project]