Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(568)

Side by Side Diff: build/scan_sources.py

Issue 8037013: Create scanning script to determine header dependencies. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:executable
+ *
OLDNEW
(Empty)
1 #!/usr/bin/python
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 import os
7 import re
8 import sys
9
10 """
bradn 2011/09/26 06:21:57 Pull this up onto the line with the """ (per style
noelallen1 2011/09/30 01:12:45 Done.
11 Header Scanner.
12
13 This module will scan a set of input sources for include dependencies. Use
14 the command-line switch -Ixxxx to add include paths.
15 """
16
17
bradn 2011/09/26 06:21:57 Extra cr here.
noelallen1 2011/09/30 01:12:45 Done.
18
19 class Resolver(object):
20 """
21 The Resolver object provides a mechanism to to find and convert a source or
22 include filename into a relative path based on provided search paths.
23 """
24 def __init__(self):
25 self.search_dirs = []
26 self.AddDir('.')
bradn 2011/09/26 06:21:57 This is adding cwd to the search order (the cwd wh
noelallen1 2011/09/30 01:12:45 Removed, I force you to specify it now.
27 self.cwd = os.path.realpath(os.getcwd())
bradn 2011/09/26 06:21:57 I've noticed you used realpath throughout. I actua
noelallen1 2011/09/30 01:12:45 I use realpath so that two links to the same locat
28 self.offs = len(self.cwd)
29
30 def AddDir(self, pathname):
31 """Add an include search path."""
32 pathname = os.path.realpath(pathname)
33 if pathname not in self.search_dirs:
34 if os.path.isdir(pathname):
35 self.search_dirs.append(pathname)
36 print 'Added dir: %s' % pathname
bradn 2011/09/26 06:21:57 Leftover? I assume these are something you want in
noelallen1 2011/09/30 01:12:45 Not sure what we should do here. We "failed" beca
37 else:
38 print 'Not a directory: %s' % pathname
39 return False
40 return True
41
42 def ToRelative(self, filepath):
43 """Returns a relative path from CWD to filepath."""
44 filepath = os.path.realpath(filepath)
45 basepath = self.cwd
46 path_parts = filepath.split(os.sep)
47 base_parts = basepath.split(os.sep)
48 print "filepath vs basepath"
49 print " %s\n %s\n" % (filepath, basepath)
bradn 2011/09/26 06:21:57 Leftover?
noelallen1 2011/09/30 01:12:45 Done.
50 while path_parts and base_parts and path_parts[0] == base_parts[0]:
51 path_parts = path_parts[1:]
52 base_parts = base_parts[1:]
53 rel_parts = ['..'] * len(base_parts) + path_parts
54 return os.sep.join(rel_parts)
55
56 def FindFile(self, filename):
57 """Search for <filename> across the search directories, and if found,
58 return the filepath relative to the CWD if found or None. """
59 if filename[0] == os.path.sep:
bradn 2011/09/26 06:21:57 os.path.isabs(filename)
noelallen1 2011/09/30 01:12:45 Done.
60 if os.path.exists(filename):
61 return self.ToRelative(filename)
62 return None
63 for pathname in self.search_dirs:
64 fullname = os.path.join(pathname, filename)
65 if os.path.exists(fullname):
66 return self.ToRelative(fullname)
67 return None
68
69
70 class Scanner(object):
71 """
bradn 2011/09/26 06:21:57 Give a one line description per the style guide.
72 Scanner does the regular expression work, loading and scanning the source
73 files for the key '#include' to find dependencies.
74 """
75 def __init__(self, parent):
76 regex = r'(?P<inc>\#include [<"].+[>"])'
bradn 2011/09/26 06:21:57 You did P<inc> but never used that group name.
bradn 2011/09/26 06:21:57 .+ -> [^>"]+
77 self.work_q = parent
bradn 2011/09/26 06:21:57 So include <> vs include "" have different behavio
noelallen1 2011/09/30 01:12:45 Done.
78 self.parser = re.compile(regex)
79
80 def GetIncludes(self, data):
81 """Generate a list of includes."""
82 out = []
83 for token in self.parser.split(data):
bradn 2011/09/26 06:21:57 Split's a little weird, I'd use findall here as if
84 if len(token) > 8 and token[0:8] == '#include':
85 filepath = token.split()[1]
86 out.append(filepath[1:-1])
87 return out
88
89 def Scan(self, filename):
90 """Attempt to scan the given file for a list of includes."""
91 try:
92 data = open(filename).read()
93 return self.GetIncludes(data)
94 except:
bradn 2011/09/26 06:21:57 Technically the style guide forbids carte-blanc ex
95 return []
96
97
98 class WorkQueue(object):
99 """
bradn 2011/09/26 06:21:57 Pull out the first sentence as a one line descript
100 WorkQueue contains provides a queue of files to be processed. The scanner
101 will attempt to push new items into the queue, which will be ignored if the
102 item is already in the queue. If the item is new, it will be added to the
103 work list, which is drained by the scanner.
104 """
105 def __init__(self, resolver):
106 self.added_set = set()
107 self.todo_list = list()
108 self.scanner = Scanner(self)
109 self.resolver = resolver
110
111 def PushIfNew(self, filename):
112 """Add this dependency to the list of not already there."""
113 resolved_name = self.resolver.FindFile(filename)
114 if not resolved_name:
115 return
116 if resolved_name in self.added_set:
117 return
118 self.todo_list.append(resolved_name)
119 self.added_set |= set([resolved_name])
bradn 2011/09/26 06:21:57 -> self.added_set.add(resolved_name)
noelallen1 2011/09/30 01:12:45 Done.
120
121 def PopIfAvail(self):
122 """Fetch the next dependency to search."""
123 if not self.todo_list:
124 return None
125 return self.todo_list.pop()
126
127 def Run(self):
128 """Search through the available dependencies until the list becomes empty.
129 The list must be primed with one or more source files to search."""
130 scan_name = self.PopIfAvail()
131 while scan_name:
132 includes = self.scanner.Scan(scan_name)
133 for include_file in includes:
134 self.PushIfNew(include_file)
135 scan_name = self.PopIfAvail()
136
137 sorted_list = sorted(self.added_set)
138 for pathname in sorted_list:
139 print pathname
140
141
142 def Main(argv):
143 resolver = Resolver()
144 files = []
145 failed = False
146 for arg in argv[1:]:
147 if len(arg) > 2 and arg[0:2] == '-I':
bradn 2011/09/26 06:21:57 Style guide calls for consistent use of single or
bradn 2011/09/26 06:21:57 I'm all for avoiding optparse when possible, but I
noelallen1 2011/09/30 01:12:45 Done.
noelallen1 2011/09/30 01:12:45 Done.
148 if not resolver.AddDir(arg[2:]):
149 print "Failed to add path: %s" % arg[2:]
150 failed = True
151 else:
152 files.append(arg)
153
154 if failed: return -1
155 workQ = WorkQueue(resolver)
156 for filename in files:
157 workQ.PushIfNew(filename)
158 workQ.Run()
159 return 0
160
bradn 2011/09/26 06:21:57 Style guide is a little vague, but most places see
noelallen1 2011/09/30 01:12:45 Done.
161 if __name__ == '__main__':
162 sys.exit(Main(sys.argv))
163
bradn 2011/09/26 06:21:57 Drop trailing line.
noelallen1 2011/09/30 01:12:45 Done.
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698