OLD | NEW |
| (Empty) |
1 #!/usr/bin/env 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 copy | |
7 import optparse | |
8 | |
9 __version__ = "1.0" | |
10 | |
11 # Constants used by Visual Studio. | |
12 UNKNOWN_GUID = "{00000000-0000-0000-0000-000000000000}" | |
13 FOLDER_GUID = "{2150E333-8FDC-42A3-9474-1A3956D46DE8}" | |
14 C_PROJECT_GUID = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}" | |
15 CSHARP_PROJECT_GUID = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}" | |
16 | |
17 # A project defines it name, its guid and its dependencies. | |
18 class Project: | |
19 def __init__(self): | |
20 self.name = "" | |
21 self.type = UNKNOWN_GUID | |
22 self.deps = [] | |
23 | |
24 def __str__(self): | |
25 return self.name | |
26 | |
27 | |
28 def ScanSlnFile(filename): | |
29 """Scan a Visual Studio .sln and extract the project dependencies.""" | |
30 try: | |
31 sln = open(filename, "r") | |
32 except IOError: | |
33 sys.stderr.write("Unable to open " + filename + " for reading.\n") | |
34 return 1 | |
35 projects = {} | |
36 project = None | |
37 while 1: | |
38 line = sln.readline().strip() | |
39 if not line: | |
40 break | |
41 | |
42 if line.startswith('Project("{'): | |
43 # Project definition line looks like | |
44 # Project("$TypeGuid") = "$ProjectName", "$ProjectPath", "$ProjectGuid"$ | |
45 items = line.split('"') | |
46 project = Project() | |
47 project.name = items[3] | |
48 project.path = items[5] | |
49 project.guid = items[7] | |
50 project.type = items[1] | |
51 projects[items[7]] = project | |
52 | |
53 # Start of a dependency group. | |
54 if line == "ProjectSection(ProjectDependencies) = postProject": | |
55 line = sln.readline().strip() | |
56 # End of a dependency group. | |
57 while line and line != "EndProjectSection": | |
58 project.deps.append(line[:len(project.guid)]) | |
59 line = sln.readline().strip() | |
60 | |
61 # We are done parsing. | |
62 sln.close() | |
63 return projects | |
64 | |
65 | |
66 def sln_deps(filename, project_to_scan, reverse): | |
67 """Displays the project's dependencies.""" | |
68 project_to_scan = project_to_scan.lower() | |
69 | |
70 projects = ScanSlnFile(filename) | |
71 | |
72 if reverse: | |
73 # Inverse the dependencies map so they are displayed in the reverse order. | |
74 # First, create a copy of the map. | |
75 projects_reversed = copy.deepcopy(projects) | |
76 for project_reversed in projects_reversed.itervalues(): | |
77 project_reversed.deps = [] | |
78 # Then, assign reverse dependencies. | |
79 for project in projects.itervalues(): | |
80 for dep in project.deps: | |
81 projects_reversed[dep].deps.append(project.guid) | |
82 projects = projects_reversed | |
83 | |
84 # Print the results. | |
85 for project in projects.itervalues(): | |
86 if project.type == FOLDER_GUID: | |
87 continue | |
88 if project_to_scan and project.name.lower() != project_to_scan: | |
89 continue | |
90 print project.name | |
91 deps_name = [projects[d].name for d in project.deps] | |
92 print "\n".join(str(" " + name) for name in sorted(deps_name, | |
93 key=str.lower)) | |
94 return 0 | |
95 | |
96 | |
97 def main(): | |
98 usage = "usage: %prog [options] solution [project]" | |
99 | |
100 description = ("Display the dependencies of a project in human readable" | |
101 " form. [project] is optional. If omited, all projects are" | |
102 " listed.") | |
103 | |
104 option_parser = optparse.OptionParser(usage = usage, | |
105 version="%prog " + __version__, | |
106 description = description) | |
107 option_parser.add_option("-r", | |
108 "--reverse", | |
109 dest="reverse", | |
110 action="store_true", | |
111 default=False, | |
112 help="Display the reverse dependencies") | |
113 options, args = option_parser.parse_args() | |
114 if len(args) != 1 and len(args) != 2: | |
115 option_parser.error("incorrect number of arguments") | |
116 | |
117 project_to_scan = "" | |
118 if len(args) == 2: | |
119 project_to_scan = args[1] | |
120 return sln_deps(args[0], project_to_scan, options.reverse) | |
121 | |
122 | |
123 if __name__ == '__main__': | |
124 sys.exit(main()) | |
OLD | NEW |