Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
In some of visual studio solution I met, there are very much more projects inside. This is a simple script to extract and simplify the dependencies and generate VBA of Visio to draw the diagram better visualization.
import re
import os
import sys
def vba_vso_name(text):
ans = text.replace(' ', '_').replace('.', '_')
assert re.compile(r'^\w*$').match(ans)
return ans
def generate_VBA(d_dir_dep):
VBA = r'''
Sub aaa()
Dim vsoPages As Visio.Pages
Dim vsoPage As Visio.Page
Dim vsoDocument As Visio.Document
Dim Textline As String
Dim vsoShape As Visio.Shape
'''
for i,x in enumerate(list(d_dir_dep.keys())):
vsoname = vba_vso_name(x)
VBA += rf'''
Set {vsoname} = ActivePage.DrawRectangle({2*0}, {11.3-0.3*i}, {2*0} + 4, {11.0 - 0.3*i})
{vsoname}.Text = "{x}"
{vsoname}.CellsSRC(visSectionCharacter, 0, visCharacterSize).FormulaU = "MIN(1,Height/TEXTHEIGHT(TheText,Width))*13&""pt"""
'''
for x in d_dir_dep:
for y in d_dir_dep[x]:
xname = vba_vso_name(x)
yname = vba_vso_name(y)
VBA += rf'''
Set conn = ActivePage.Drop(Visio.Application.ConnectorToolDataObject, 1, 4)
conn.Cells("BeginX").GlueTo {xname}.Cells("PinX")
conn.Cells("EndX").GlueTo {yname}.Cells("PinX")
'''
VBA += r'''
End Sub
'''
return VBA
def main():
sln_path = sys.argv[1] if len(sys.argv) > 1 else None
if not sln_path:
print(f'usage: main.py /path/to/*.sln')
exit(1)
with open(sln_path, 'rt') as f:
all_projectes = f.readlines()
all_projectes = [re.compile(fr'^Project.* = (.*csproj.*)$').match(x) for x in all_projectes]
all_projectes = [x.group(1) for x in all_projectes if x]
all_projectes = [x for x in all_projectes if x]
all_projectes = [x.split(',') for x in all_projectes]
all_projectes = [[y.split('"')[1] for y in x] for x in all_projectes]
all_projectes = [(x, os.path.join(os.path.dirname(sln_path), proj_path)) for x,proj_path,_ in all_projectes]
all_projectes = [(x, os.path.abspath(proj_path)) for x,proj_path in all_projectes]
d_path_projname = {proj_path: proj_name for proj_name,proj_path in all_projectes}
d_direct_dep = {}
for proj_name,proj_path in all_projectes:
d_direct_dep[proj_name] = set()
with open(proj_path, 'rt') as pf:
deps = pf.readlines()
deps = [line for line in deps if '<ProjectReference Include=' in line]
deps = [line.split('ProjectReference Include="')[1].split('"')[0] for line in deps]
deps = [os.path.join(os.path.dirname(proj_path), line) for line in deps]
deps = [os.path.abspath(line) for line in deps]
d_direct_dep[proj_name] = set(d_path_projname[y] for y in deps if y in d_path_projname)
d_all_dep = {}
for x in d_direct_dep:
d_all_dep[x] = set()
queue = list(d_direct_dep[x])
while queue:
head,queue = queue[0],queue[1:]
d_all_dep[x].add(head)
for nn in d_direct_dep[head]:
if nn not in d_all_dep[x]:
queue.append(nn)
for x in d_direct_dep:
for y in list(d_direct_dep[x]):
if any(y in d_all_dep[z] for z in d_direct_dep[x]):
d_direct_dep[x].remove(y)
d_direct_dep = {x:d_direct_dep[x] for x in d_direct_dep if 'test' not in x.lower()}
d_direct_dep = {x:[y for y in d_direct_dep[x] if y in d_direct_dep.keys()] for x in d_direct_dep}
for x in sorted(d_direct_dep.keys()):
print(x, '-->', d_direct_dep[x])
print(generate_VBA(d_direct_dep))
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment