1# Copyright 2020 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Provide filters for libchrome tools."""
6
7import re
8
9# Libchrome wants WANT but not WANT_EXCLUDE
10# aka files matching WANT will be copied from upstream_files
11WANT = [
12    re.compile(rb'base/((?!(allocator|third_party)/).*$)'),
13    re.compile(
14        rb'base/allocator/(allocator_shim.cc|allocator_shim_override_linker_wrapped_symbols.h|allocator_shim_override_cpp_symbols.h|allocator_shim_override_libc_symbols.h|allocator_shim_default_dispatch_to_glibc.cc|allocator_shim.h|allocator_shim_default_dispatch_to_linker_wrapped_symbols.cc|allocator_extension.cc|allocator_extension.h|allocator_shim_internals.h)$'
15    ),
16    re.compile(rb'base/third_party/(dynamic_annotation|icu|nspr|valgrind)'),
17    re.compile(rb'build/(android/(gyp/util|pylib/([^/]*$|constants))|[^/]*\.(h|py)$)'),
18    re.compile(rb'mojo/'),
19    re.compile(rb'dbus/'),
20    re.compile(rb'ipc/.*(\.cc|\.h|\.mojom)$'),
21    re.compile(rb'ui/gfx/(gfx_export.h|geometry|range)'),
22    re.compile(rb'testing/[^/]*\.(cc|h)$'),
23    re.compile(rb'third_party/(jinja2|markupsafe|ply)'),
24    re.compile(
25        rb'components/(json_schema|policy/core/common/[^/]*$|policy/policy_export.h|timers)'
26    ),
27    re.compile(
28        rb'device/bluetooth/bluetooth_(common|advertisement|uuid|export)\.*(h|cc)'
29    ),
30    re.compile(
31        rb'device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.(h|cc)'
32    ),
33]
34
35# WANT_EXCLUDE will be excluded from WANT
36WANT_EXCLUDE = [
37    re.compile(rb'(.*/)?BUILD.gn$'),
38    re.compile(rb'(.*/)?PRESUBMIT.py$'),
39    re.compile(rb'(.*/)?OWNERS$'),
40    re.compile(rb'(.*/)?SECURITY_OWNERS$'),
41    re.compile(rb'(.*/)?DEPS$'),
42    re.compile(rb'base/(.*/)?(ios|win|fuchsia|mac|openbsd|freebsd|nacl)/.*'),
43    re.compile(rb'.*_(ios|win|mac|fuchsia|openbsd|freebsd|nacl)[_./]'),
44    re.compile(rb'.*/(ios|win|mac|fuchsia|openbsd|freebsd|nacl)_'),
45    re.compile(rb'dbus/(test_serv(er|ice)\.cc|test_service\.h)$')
46]
47
48# Files matching KEEP should not be touched.
49# aka files matching KEEP will keep its our_files version,
50# and it will be kept even it doesn't exist in upstream.
51# KEEP-KEEP_EXCLUDE must NOT intersect with WANT-WANT_EXCLUDE
52KEEP = [
53    re.compile(
54        b'(Android.bp|BUILD.gn|crypto|libchrome_tools|MODULE_LICENSE_BSD|NOTICE|OWNERS|PRESUBMIT.cfg|soong|testrunner.cc|third_party)(/.*)?$'
55    ),
56    re.compile(rb'[^/]*$'),
57    re.compile(rb'.*buildflags.h'),
58    re.compile(rb'base/android/java/src/org/chromium/base/BuildConfig.java'),
59    re.compile(rb'testing/(gmock|gtest)/'),
60    re.compile(rb'base/third_party/(libevent|symbolize)'),
61]
62
63# KEEP_EXCLUDE wil be excluded from KEEP.
64KEEP_EXCLUDE = [
65    re.compile(rb'third_party/(jinja2|markupsafe|ply)'),
66]
67
68
69def _want_file(path):
70    """Returns whether the path wants to be a new file."""
71    wanted = False
72    for want_file_regex in WANT:
73        if want_file_regex.match(path):
74            wanted = True
75            break
76    for exclude_file_regex in WANT_EXCLUDE:
77        if exclude_file_regex.match(path):
78            wanted = False
79            break
80    return wanted
81
82
83def _keep_file(path):
84    """Returns whether the path wants to be kept untouched in local files."""
85    keep = False
86    for keep_file_regex in KEEP:
87        if keep_file_regex.match(path):
88            keep = True
89            break
90    for exclude_file_regex in KEEP_EXCLUDE:
91        if exclude_file_regex.match(path):
92            keep = False
93            break
94    return keep
95
96
97def filter_file(our_files, upstream_files):
98    """Generates a list of files we want based on hard-coded rules.
99
100    File list must be a list of GitFile.
101
102    Args:
103        our_files: files in Chromium OS libchrome repository.
104        upstream_files: files in Chromium browser repository.
105    """
106
107    files = []
108    for upstream_file in upstream_files:
109      if _want_file(upstream_file.path):
110            files.append(upstream_file)
111    for our_file in our_files:
112      if _keep_file(our_file.path):
113            files.append(our_file)
114    return files
115
116
117def filter_diff(diff):
118    """Returns a subset of diff, after running filters.
119
120    Args:
121        diff: diff to filter. diff contains list of utils.GitDiffTree
122    """
123    filtered = []
124    for change in diff:
125        path = change.file.path
126        if _want_file(path):
127            assert not _keep_file(path)
128            filtered.append(change)
129    return filtered
130