blob: 5ef70b5eff5a13276030bc0a4774feba9a6614bc [file] [log] [blame]
Artem Titov4103b382018-05-18 13:33:51 +02001#!/usr/bin/env python
2
3# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
4#
5# Use of this source code is governed by a BSD-style license
6# that can be found in the LICENSE file in the root of the source
7# tree. An additional intellectual property rights grant can be found
8# in the file PATENTS. All contributing project authors may
9# be found in the AUTHORS file in the root of the source tree.
10
11
12import json
13import logging
14import os.path
15import subprocess
16import sys
17import re
18
19
20def CheckThirdPartyDirectory(input_api, output_api):
21 # We have to put something in black_list here that won't blacklist
22 # third_party/* because otherwise default black list will be used. Default
23 # list contains third_party, so source set will become empty.
24 third_party_sources = lambda x: (
25 input_api.FilterSourceFile(x, white_list=(r'^third_party[\\\/].+',),
26 black_list=(r'^_',)))
27
28 webrtc_owned_deps_list_path = input_api.os_path.join(
29 input_api.PresubmitLocalPath(),
30 'THIRD_PARTY_WEBRTC_DEPS.json')
31 chromium_owned_deps_list_path = input_api.os_path.join(
32 input_api.PresubmitLocalPath(),
33 'THIRD_PARTY_CHROMIUM_DEPS.json')
34 webrtc_owned_deps = _LoadDepsList(webrtc_owned_deps_list_path)
35 chromium_owned_deps = _LoadDepsList(chromium_owned_deps_list_path)
36 chromium_added_deps = GetChromiumOwnedAddedDeps(input_api)
37
38 results = []
39 results.extend(CheckNoNotOwned3ppDeps(input_api, output_api,
40 webrtc_owned_deps, chromium_owned_deps))
41 results.extend(CheckNoBothOwned3ppDeps(output_api, webrtc_owned_deps,
42 chromium_owned_deps))
43 results.extend(CheckNoChangesInAutoImportedDeps(input_api, output_api,
44 webrtc_owned_deps,
45 chromium_owned_deps,
46 chromium_added_deps,
47 third_party_sources))
48 return results
49
50
51def GetChromiumOwnedAddedDeps(input_api):
52 """Return list of deps that were added into chromium owned deps list."""
53
54 chromium_owned_deps_list_source = lambda x: (
55 input_api.FilterSourceFile(x,
56 white_list=('THIRD_PARTY_CHROMIUM_DEPS.json',),
57 black_list=(r'^_',)))
58
59 chromium_owned_deps_list = input_api.AffectedFiles(
60 file_filter=chromium_owned_deps_list_source)
61 modified_deps_file = next(iter(chromium_owned_deps_list), None)
62 if not modified_deps_file:
63 return []
64 if modified_deps_file.Action() != 'M':
65 return []
66 prev_json = json.loads('\n'.join(modified_deps_file.OldContents()))
67 new_json = json.loads('\n'.join(modified_deps_file.NewContents()))
68 prev_deps_set = set(prev_json.get('dependencies', []))
69 new_deps_set = set(new_json.get('dependencies', []))
70 return list(new_deps_set.difference(prev_deps_set))
71
72
73def CheckNoNotOwned3ppDeps(input_api, output_api,
74 webrtc_owned_deps, chromium_owned_deps):
75 """Checks that there are no any not owned third_party deps."""
76 error_msg = ('Third party dependency [{}] have to be specified either in '
77 'THIRD_PARTY_WEBRTC_DEPS.json or in '
78 'THIRD_PARTY_CHROMIUM_DEPS.json.\n'
79 'If you want to add chromium-specific'
80 'dependency you can run this command (better in separate CL): \n'
81 './tools_webrtc/autoroller/checkin_chromium_dep.py -d {}\n'
82 'If you want to add WebRTC-specific dependency just add it into '
83 'THIRD_PARTY_WEBRTC_DEPS.json manually')
84
85 third_party_dir = os.path.join(input_api.PresubmitLocalPath(), 'third_party')
86 os.listdir(third_party_dir)
87 stdout, _ = _RunCommand(['git', 'ls-tree', '--name-only', 'HEAD'],
88 working_dir=third_party_dir)
89 not_owned_deps = set()
90 results = []
91 for dep_name in stdout.split('\n'):
92 dep_name = dep_name.strip()
93 if len(dep_name) == 0:
94 continue
95 if dep_name == '.gitignore':
96 continue
97 if (dep_name not in webrtc_owned_deps
98 and dep_name not in chromium_owned_deps):
99 results.append(
100 output_api.PresubmitError(error_msg.format(dep_name, dep_name)))
101 not_owned_deps.add(dep_name)
102 return results
103
104
105def CheckNoBothOwned3ppDeps(output_api, webrtc_owned_deps, chromium_owned_deps):
106 """Checks that there are no any not owned third_party deps."""
107 error_msg = ('Third party dependencies {} can\'t be a WebRTC- and '
108 'Chromium-specific dependency at the same time. '
109 'Remove them from one of these files: '
110 'THIRD_PARTY_WEBRTC_DEPS.json or THIRD_PARTY_CHROMIUM_DEPS.json')
111
112 both_owned_deps = set(chromium_owned_deps).intersection(
113 set(webrtc_owned_deps))
114 results = []
115 if both_owned_deps:
116 results.append(output_api.PresubmitError(error_msg.format(
117 json.dumps(list(both_owned_deps)))))
118 return results
119
120
121def CheckNoChangesInAutoImportedDeps(input_api, output_api,
122 webrtc_owned_deps, chromium_owned_deps, chromium_added_deps,
123 third_party_sources):
124 """Checks that there are no changes in deps imported by autoroller."""
125
126 error_msg = ('Changes in [{}] will be overridden during chromium third_party '
127 'autoroll. If you really want to change this code you have to '
128 'do it upstream in Chromium\'s third_party.')
129 results = []
130 for f in input_api.AffectedFiles(file_filter=third_party_sources):
131 file_path = f.LocalPath()
132 split = re.split(r'[\\\/]', file_path)
133 dep_name = split[1]
134 if (dep_name not in webrtc_owned_deps
135 and dep_name in chromium_owned_deps
136 and dep_name not in chromium_added_deps):
137 results.append(output_api.PresubmitError(error_msg.format(file_path)))
138 return results
139
140
141def _LoadDepsList(file_name):
142 with open(file_name, 'rb') as f:
143 content = json.load(f)
144 return content.get('dependencies', [])
145
146
147def _RunCommand(command, working_dir):
148 """Runs a command and returns the output from that command.
149
150 If the command fails (exit code != 0), the function will exit the process.
151
152 Returns:
153 A tuple containing the stdout and stderr outputs as strings.
154 """
155 env = os.environ.copy()
156 p = subprocess.Popen(command,
157 stdin=subprocess.PIPE,
158 stdout=subprocess.PIPE,
159 stderr=subprocess.PIPE, env=env,
160 cwd=working_dir, universal_newlines=True)
161 std_output, err_output = p.communicate()
162 p.stdout.close()
163 p.stderr.close()
164 if p.returncode != 0:
165 logging.error('Command failed: %s\n'
166 'stdout:\n%s\n'
167 'stderr:\n%s\n', ' '.join(command), std_output, err_output)
168 sys.exit(p.returncode)
169 return std_output, err_output