blob: 54ca1b0418621dce102bf9fa572dd87831dc6b75 [file] [log] [blame]
ehmaldonado01653b12016-12-08 07:27:37 -08001#!/usr/bin/env python
2
3# Copyright (c) 2016 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
11import os
12import re
13import shutil
14import subprocess
15import sys
16import tempfile
17
18from collections import defaultdict
19
20TARGET_RE = re.compile(
21 r'(?P<indentation_level>\s*)\w*\("(?P<target_name>\w*)"\) {$')
22
23class TemporaryDirectory(object):
24 def __init__(self):
25 self._closed = False
26 self._name = None
27 self._name = tempfile.mkdtemp()
28
29 def __enter__(self):
30 return self._name
31
32 def __exit__(self, exc, value, tb):
33 if self._name and not self._closed:
34 shutil.rmtree(self._name)
35 self._closed = True
36
37
38def Run(cmd):
39 print 'Running:', ' '.join(cmd)
40 sub = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
41 return sub.communicate()
42
43def FixErrors(filename, missing_deps, deleted_sources):
44 with open(filename) as f:
45 lines = f.readlines()
46
47 fixed_file = ''
48 indentation_level = None
49 for line in lines:
50 match = TARGET_RE.match(line)
51 if match:
52 target = match.group('target_name')
53 if target in missing_deps:
54 indentation_level = match.group('indentation_level')
55 elif indentation_level is not None:
56 match = re.match(indentation_level + '}$', line)
57 if match:
58 line = ('deps = [\n' +
59 ''.join(' "' + dep + '",\n' for dep in missing_deps[target]) +
60 ']\n') + line
61 indentation_level = None
62 elif line.strip().startswith('deps'):
63 is_empty_deps = line.strip() == 'deps = []'
64 line = 'deps = [\n' if is_empty_deps else line
65 line += ''.join(' "' + dep + '",\n' for dep in missing_deps[target])
66 line += ']\n' if is_empty_deps else ''
67 indentation_level = None
68
69 if line.strip() not in deleted_sources:
70 fixed_file += line
71
72 with open(filename, 'w') as f:
73 f.write(fixed_file)
74
75 Run(['gn', 'format', filename])
76
77def Rebase(base_path, dependency_path, dependency):
78 base_path = base_path.split(os.path.sep)
79 dependency_path = dependency_path.split(os.path.sep)
80
81 first_difference = None
82 shortest_length = min(len(dependency_path), len(base_path))
83 for i in range(shortest_length):
84 if dependency_path[i] != base_path[i]:
85 first_difference = i
86 break
87
88 first_difference = first_difference or shortest_length
89 base_path = base_path[first_difference:]
90 dependency_path = dependency_path[first_difference:]
91 return (os.path.sep.join((['..'] * len(base_path)) + dependency_path) +
92 ':' + dependency)
93
94def main():
95 deleted_sources = set()
96 errors_by_file = defaultdict(lambda: defaultdict(set))
97
98 with TemporaryDirectory() as tmp_dir:
99 mb_gen_command = ([
100 'tools/mb/mb.py', 'gen',
101 tmp_dir,
102 '--config-file', 'webrtc/build/mb_config.pyl',
103 ] + sys.argv[1:])
104
105 mb_output = Run(mb_gen_command)
106 errors = mb_output[0].split('ERROR')[1:]
107
108 if mb_output[1]:
109 print mb_output[1]
110 return 1
111
112 for error in errors:
113 error = error.splitlines()
114 target_msg = 'The target:'
115 if target_msg not in error:
116 target_msg = 'It is not in any dependency of'
117 if target_msg not in error:
118 print '\n'.join(error)
119 continue
120 index = error.index(target_msg) + 1
121 path, target = error[index].strip().split(':')
122 if error[index+1] in ('is including a file from the target:',
123 'The include file is in the target(s):'):
124 dep = error[index+2].strip()
125 dep_path, dep = dep.split(':')
126 dep = Rebase(path, dep_path, dep)
127 path = os.path.join(path[2:], 'BUILD.gn')
128 errors_by_file[path][target].add(dep)
129 elif error[index+1] == 'has a source file:':
130 deleted_file = '"' + os.path.basename(error[index+2].strip()) + '",'
131 deleted_sources.add(deleted_file)
132 else:
133 print '\n'.join(error)
134 continue
135
136 for path, missing_deps in errors_by_file.items():
137 FixErrors(path, missing_deps, deleted_sources)
138
139 return 0
140
141if __name__ == '__main__':
142 sys.exit(main())