Skip to content

Commit 3d012cd

Browse files
committed
C#: Move the generator class to a helper file.
1 parent 8343ce0 commit 3d012cd

File tree

2 files changed

+204
-210
lines changed

2 files changed

+204
-210
lines changed

csharp/scripts/stubs/helpers.py

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import sys
22
import os
33
import subprocess
4+
import json
5+
import shutil
46

57
def run_cmd(cmd, msg="Failed to run command"):
68
print('Running ' + ' '.join(cmd))
@@ -49,3 +51,204 @@ def remove_files(path, ext):
4951
for file in os.listdir(path):
5052
if file.endswith(ext):
5153
os.remove(os.path.join(path, file))
54+
55+
def write_csproj_prefix(ioWrapper):
56+
ioWrapper.write('<Project Sdk="Microsoft.NET.Sdk">\n')
57+
ioWrapper.write(' <PropertyGroup>\n')
58+
ioWrapper.write(' <TargetFramework>net8.0</TargetFramework>\n')
59+
ioWrapper.write(' <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n')
60+
ioWrapper.write(' <OutputPath>bin\</OutputPath>\n')
61+
ioWrapper.write(
62+
' <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>\n')
63+
ioWrapper.write(' </PropertyGroup>\n\n')
64+
65+
class Generator:
66+
def __init__(self, thisScript, relativeWorkDir, template):
67+
# /input contains a dotnet project that's being extracted
68+
self.workDir = os.path.abspath(relativeWorkDir)
69+
os.makedirs(self.workDir)
70+
self.thisDir = os.path.abspath(os.path.dirname(thisScript))
71+
self.projectNameIn = "input"
72+
self.projectDirIn = os.path.join(self.workDir, self.projectNameIn)
73+
self.template = template
74+
print("\n* Creating new input project")
75+
self.run_cmd(['dotnet', 'new', self.template, "-f", "net8.0", "--language", "C#", '--name',
76+
self.projectNameIn, '--output', self.projectDirIn])
77+
remove_files(self.projectDirIn, '.cs')
78+
79+
def run_cmd(self, cmd, msg="Failed to run command"):
80+
run_cmd_cwd(cmd, self.workDir, msg)
81+
82+
def add_nuget(self, nuget, version="latest"):
83+
print("\n* Adding reference to package: " + nuget)
84+
cmd = ['dotnet', 'add', self.projectDirIn, 'package', nuget]
85+
if (version != "latest"):
86+
cmd.append('--version')
87+
cmd.append(version)
88+
self.run_cmd(cmd)
89+
90+
def make_stubs(self):
91+
# /output contains the output of the stub generation
92+
outputDirName = "output"
93+
outputDir = os.path.join(self.workDir, outputDirName)
94+
95+
# /output/raw contains the bqrs result from the query, the json equivalent
96+
rawOutputDirName = "raw"
97+
rawOutputDir = os.path.join(outputDir, rawOutputDirName)
98+
os.makedirs(rawOutputDir)
99+
100+
# /output/output contains a dotnet project with the generated stubs
101+
projectNameOut = "output"
102+
projectDirOut = os.path.join(outputDir, projectNameOut)
103+
104+
# /db contains the extracted QL DB
105+
dbName = 'db'
106+
dbDir = os.path.join(self.workDir, dbName)
107+
outputName = "stub"
108+
outputFile = os.path.join(projectDirOut, outputName + '.cs')
109+
bqrsFile = os.path.join(rawOutputDir, outputName + '.bqrs')
110+
jsonFile = os.path.join(rawOutputDir, outputName + '.json')
111+
112+
sdk_version = '8.0.100'
113+
print("\n* Creating new global.json file and setting SDK to " + sdk_version)
114+
self.run_cmd(['dotnet', 'new', 'globaljson', '--force', '--sdk-version', sdk_version, '--output', self.workDir])
115+
116+
print("\n* Running stub generator")
117+
run_cmd_cwd(['dotnet', 'run', '--project', self.thisDir + '/../../extractor/Semmle.Extraction.CSharp.DependencyStubGenerator/Semmle.Extraction.CSharp.DependencyStubGenerator.csproj'], self.projectDirIn)
118+
119+
print("\n* Creating new raw output project")
120+
rawSrcOutputDirName = 'src'
121+
rawSrcOutputDir = os.path.join(rawOutputDir, rawSrcOutputDirName)
122+
self.run_cmd(['dotnet', 'new', self.template, "--language", "C#",
123+
'--name', rawSrcOutputDirName, '--output', rawSrcOutputDir])
124+
remove_files(rawSrcOutputDir, '.cs')
125+
126+
# copy each file from projectDirIn to rawSrcOutputDir
127+
pathInfos = {}
128+
codeqlStubsDir = os.path.join(self.projectDirIn, 'codeql_csharp_stubs')
129+
for root, dirs, files in os.walk(codeqlStubsDir):
130+
for file in files:
131+
if file.endswith('.cs'):
132+
path = os.path.join(root, file)
133+
relPath, _ = os.path.splitext(os.path.relpath(path, codeqlStubsDir))
134+
origDllPath = "/" + relPath + ".dll"
135+
pathInfos[origDllPath] = os.path.join(rawSrcOutputDir, file)
136+
shutil.copy2(path, rawSrcOutputDir)
137+
138+
print("\n --> Generated stub files: " + rawSrcOutputDir)
139+
140+
print("\n* Formatting files")
141+
self.run_cmd(['dotnet', 'format', 'whitespace', rawSrcOutputDir])
142+
143+
print("\n --> Generated (formatted) stub files: " + rawSrcOutputDir)
144+
145+
print("\n* Processing project.assets.json to generate folder structure")
146+
stubsDirName = 'stubs'
147+
stubsDir = os.path.join(outputDir, stubsDirName)
148+
os.makedirs(stubsDir)
149+
150+
frameworksDirName = '_frameworks'
151+
frameworksDir = os.path.join(stubsDir, frameworksDirName)
152+
153+
frameworks = set()
154+
copiedFiles = set()
155+
156+
assetsJsonFile = os.path.join(self.projectDirIn, 'obj', 'project.assets.json')
157+
with open(assetsJsonFile) as json_data:
158+
data = json.load(json_data)
159+
if len(data['targets']) > 1:
160+
print("ERROR: More than one target found in " + assetsJsonFile)
161+
exit(1)
162+
target = list(data['targets'].keys())[0]
163+
print("Found target: " + target)
164+
for package in data['targets'][target].keys():
165+
parts = package.split('/')
166+
name = parts[0]
167+
version = parts[1]
168+
packageDir = os.path.join(stubsDir, name, version)
169+
if not os.path.exists(packageDir):
170+
os.makedirs(packageDir)
171+
print(' * Processing package: ' + name + '/' + version)
172+
with open(os.path.join(packageDir, name + '.csproj'), 'a') as pf:
173+
174+
write_csproj_prefix(pf)
175+
pf.write(' <ItemGroup>\n')
176+
177+
dlls = set()
178+
if 'compile' in data['targets'][target][package]:
179+
for dll in data['targets'][target][package]['compile']:
180+
dlls.add(
181+
(name + '/' + version + '/' + dll).lower())
182+
if 'runtime' in data['targets'][target][package]:
183+
for dll in data['targets'][target][package]['runtime']:
184+
dlls.add((name + '/' + version + '/' + dll).lower())
185+
186+
for pathInfo in pathInfos:
187+
for dll in dlls:
188+
if pathInfo.lower().endswith(dll):
189+
copiedFiles.add(pathInfo)
190+
shutil.copy2(pathInfos[pathInfo], packageDir)
191+
192+
if 'dependencies' in data['targets'][target][package]:
193+
for dependency in data['targets'][target][package]['dependencies'].keys():
194+
depVersion = data['targets'][target][package]['dependencies'][dependency]
195+
pf.write(' <ProjectReference Include="../../' +
196+
dependency + '/' + depVersion + '/' + dependency + '.csproj" />\n')
197+
198+
if 'frameworkReferences' in data['targets'][target][package]:
199+
if not os.path.exists(frameworksDir):
200+
os.makedirs(frameworksDir)
201+
for framework in data['targets'][target][package]['frameworkReferences']:
202+
frameworks.add(framework)
203+
frameworkDir = os.path.join(
204+
frameworksDir, framework)
205+
if not os.path.exists(frameworkDir):
206+
os.makedirs(frameworkDir)
207+
pf.write(' <ProjectReference Include="../../' +
208+
frameworksDirName + '/' + framework + '/' + framework + '.csproj" />\n')
209+
210+
pf.write(' <ProjectReference Include="../../' +
211+
frameworksDirName + '/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj" />\n')
212+
213+
pf.write(' </ItemGroup>\n')
214+
pf.write('</Project>\n')
215+
216+
# Processing references frameworks
217+
for framework in frameworks:
218+
with open(os.path.join(frameworksDir, framework, framework + '.csproj'), 'a') as pf:
219+
220+
write_csproj_prefix(pf)
221+
pf.write(' <ItemGroup>\n')
222+
pf.write(
223+
' <ProjectReference Include="../Microsoft.NETCore.App/Microsoft.NETCore.App.csproj" />\n')
224+
pf.write(' </ItemGroup>\n')
225+
pf.write('</Project>\n')
226+
227+
for pathInfo in pathInfos:
228+
if framework.lower() + '.ref' in pathInfo.lower():
229+
copiedFiles.add(pathInfo)
230+
shutil.copy2(pathInfos[pathInfo], os.path.join(
231+
frameworksDir, framework))
232+
233+
# Processing assemblies in Microsoft.NETCore.App.Ref
234+
frameworkDir = os.path.join(frameworksDir, 'Microsoft.NETCore.App')
235+
if not os.path.exists(frameworkDir):
236+
os.makedirs(frameworkDir)
237+
with open(os.path.join(frameworksDir, 'Microsoft.NETCore.App', 'Microsoft.NETCore.App.csproj'), 'a') as pf:
238+
write_csproj_prefix(pf)
239+
pf.write('</Project>\n')
240+
241+
for pathInfo in pathInfos:
242+
if 'microsoft.netcore.app.ref/' in pathInfo.lower():
243+
copiedFiles.add(pathInfo)
244+
shutil.copy2(pathInfos[pathInfo], frameworkDir)
245+
246+
for pathInfo in pathInfos:
247+
if pathInfo not in copiedFiles:
248+
print('Not copied to nuget or framework folder: ' + pathInfo)
249+
othersDir = os.path.join(stubsDir, 'others')
250+
if not os.path.exists(othersDir):
251+
os.makedirs(othersDir)
252+
shutil.copy2(pathInfos[pathInfo], othersDir)
253+
254+
print("\n --> Generated structured stub files: " + stubsDir)

0 commit comments

Comments
 (0)