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.
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}"
17 # A project defines it name, its guid and its dependencies.
21 self
.type = UNKNOWN_GUID
28 def ScanSlnFile(filename
):
29 """Scan a Visual Studio .sln and extract the project dependencies."""
31 sln
= open(filename
, "r")
33 sys
.stderr
.write("Unable to open " + filename
+ " for reading.\n")
38 line
= sln
.readline().strip()
42 if line
.startswith('Project("{'):
43 # Project definition line looks like
44 # Project("$TypeGuid") = "$ProjectName", "$ProjectPath", "$ProjectGuid"$
45 items
= line
.split('"')
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
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()
61 # We are done parsing.
66 def sln_deps(filename
, project_to_scan
, reverse
):
67 """Displays the project's dependencies."""
68 project_to_scan
= project_to_scan
.lower()
70 projects
= ScanSlnFile(filename
)
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
85 for project
in projects
.itervalues():
86 if project
.type == FOLDER_GUID
:
88 if project_to_scan
and project
.name
.lower() != project_to_scan
:
91 deps_name
= [projects
[d
].name
for d
in project
.deps
]
92 print "\n".join(str(" " + name
) for name
in sorted(deps_name
,
98 usage
= "usage: %prog [options] solution [project]"
100 description
= ("Display the dependencies of a project in human readable"
101 " form. [project] is optional. If omited, all projects are"
104 option_parser
= optparse
.OptionParser(usage
= usage
,
105 version
="%prog " + __version__
,
106 description
= description
)
107 option_parser
.add_option("-r",
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")
119 project_to_scan
= args
[1]
120 return sln_deps(args
[0], project_to_scan
, options
.reverse
)
123 if __name__
== '__main__':