Chromium Code Reviews
|
| OLD | NEW |
|---|---|
| (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.
| |
| OLD | NEW |