PCART  v1.4
Automated Repair of Python API Parameter Compatibility Issues
workspace.py
Go to the documentation of this file.
1 
15 
16 
17 import json
18 import os
19 import re
20 import shutil
21 from contextlib import contextmanager
22 from dataclasses import asdict,dataclass
23 from datetime import datetime
24 
25 
26 
32 @dataclass
34  repo_root: str
35  run_id: str
36  command_id: str
37  run_root: str
38  workspace_root: str
39  copy_root: str
40  dynamic_root: str
41  data_dir: str
42  temp_dir: str
43  internal_report_dir: str
44  report_root: str
45  metadata_path: str
46 
47 
48 
53  return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
54 
55 
56 
61 def slugifyProjectName(projPath):
62  normalized=str(projPath).strip().rstrip('/\\')
63  if not normalized:
64  return 'project'
65  name=re.split(r'[\\/]+',normalized)[-1]
66  slug=re.sub(r'[^A-Za-z0-9._-]+','-',name).strip('.-_')
67  return slug or 'project'
68 
69 
70 
81 def _nextRunId(runsRoot,projectSlug,timestamp):
82  prefix=f'{projectSlug}__{timestamp}'
83  for index in range(1, 1000):
84  runId=f'{prefix}-{index:03d}'
85  runRoot=os.path.join(runsRoot,runId)
86  try:
87  os.mkdir(runRoot)
88  return runId, runRoot
89  except FileExistsError:
90  continue
91  raise RuntimeError(f'Cannot allocate run id for {prefix}')
92 
93 
94 
114  repoRoot,
115  projPath,
116  runCommand,
117  runPath,
118  libName,
119  currentVersion,
120  targetVersion,
121  currentEnv,
122  targetEnv,
123  commandId='cmd-001',
124  timestamp=None,
125 ):
126  repoRoot=os.path.abspath(repoRoot)
127  timestamp=timestamp or datetime.now().strftime('%Y%m%d-%H%M%S')
128  projectSlug=slugifyProjectName(projPath)
129  runsRoot=os.path.join(repoRoot,'PCARTRuns','runs')
130  os.makedirs(runsRoot, exist_ok=True)
131  runId,runRoot=_nextRunId(runsRoot,projectSlug,timestamp)
132 
133  workspaceRoot=os.path.join(runRoot,commandId)
134  os.mkdir(workspaceRoot)
135  copyRoot=os.path.join(workspaceRoot,'Copy')
136  dynamicRoot=os.path.join(workspaceRoot,'Dynamic')
137  dataDir=os.path.join(workspaceRoot,'data')
138  tempDir=os.path.join(workspaceRoot,'temp')
139  internalReportDir=os.path.join(workspaceRoot,'Report')
140  reportRoot=os.path.join(repoRoot,'Report','runs',runId,commandId)
141  metadataPath=os.path.join(workspaceRoot,'metadata.json')
142 
143  for path in (
144  copyRoot,
145  dynamicRoot,
146  dataDir,
147  tempDir,
148  internalReportDir,
149  reportRoot,
150  os.path.join(reportRoot,'patches'),
151  os.path.join(reportRoot,'fixed_project'),
152  ):
153  os.makedirs(path,exist_ok=True)
154 
155  workspace=RunWorkspace(
156  repo_root=repoRoot,
157  run_id=runId,
158  command_id=commandId,
159  run_root=runRoot,
160  workspace_root=workspaceRoot,
161  copy_root=copyRoot,
162  dynamic_root=dynamicRoot,
163  data_dir=dataDir,
164  temp_dir=tempDir,
165  internal_report_dir=internalReportDir,
166  report_root=reportRoot,
167  metadata_path=metadataPath,
168  )
170  workspace,
171  {
172  'project_slug': projectSlug,
173  'project_path': projPath,
174  'run_command': runCommand,
175  'run_file_path': runPath,
176  'lib_name': libName,
177  'current_version': currentVersion,
178  'target_version': targetVersion,
179  'current_env': currentEnv,
180  'target_env': targetEnv,
181  },
182  )
183  return workspace
184 
185 
186 
192 def writeMetadata(workspace,metadata):
193  content=asdict(workspace)
194  content.update(metadata)
195  with open(workspace.metadata_path,'w',encoding='utf-8') as fw:
196  json.dump(content,fw,ensure_ascii=False,indent=2)
197 
198 
199 
207 def getRuntimePaths(workspace):
208  return {
209  'workspace_root': workspace.workspace_root,
210  'copy_root': workspace.copy_root,
211  'dynamic_root': workspace.dynamic_root,
212  'data_dir': workspace.data_dir,
213  'temp_dir': workspace.temp_dir,
214  'report_dir': workspace.internal_report_dir,
215  }
216 
217 
218 
224 @contextmanager
225 def workspaceCwd(path):
226  previous=os.getcwd()
227  os.chdir(path)
228  try:
229  yield
230  finally:
231  os.chdir(previous)
232 
233 
234 
239 def exportRunReport(workspace):
240  os.makedirs(workspace.report_root, exist_ok=True)
241  os.makedirs(os.path.join(workspace.report_root,'patches'),exist_ok=True)
242  os.makedirs(os.path.join(workspace.report_root,'fixed_project'),exist_ok=True)
243  if not os.path.isdir(workspace.internal_report_dir):
244  return
245  for name in os.listdir(workspace.internal_report_dir):
246  source=os.path.join(workspace.internal_report_dir,name)
247  target=os.path.join(workspace.report_root,name)
248  if os.path.isdir(source):
249  if os.path.exists(target):
250  shutil.rmtree(target)
251  shutil.copytree(source,target)
252  else:
253  shutil.copy2(source,target)
254 
255 
256 
264 def cleanupRunWorkspace(workspace):
265  runsRoot=os.path.realpath(
266  os.path.join(workspace.repo_root,'PCARTRuns','runs')
267  )
268  runRoot=os.path.realpath(workspace.run_root)
269  normalizedRunsRoot=os.path.normcase(os.path.normpath(runsRoot))
270  normalizedParent=os.path.normcase(
271  os.path.normpath(os.path.dirname(runRoot))
272  )
273 
274  if normalizedParent!=normalizedRunsRoot:
275  raise ValueError(
276  f'Refuse to remove workspace outside PCARTRuns/runs: {runRoot}'
277  )
278 
279  if os.path.isdir(runRoot):
280  shutil.rmtree(runRoot)
Run workspace path object PCART单次运行的工作区路径对象
Definition: workspace.py:33
def getRepoRoot()
Get PCART repository root path 获取PCART仓库根目录路径
Definition: workspace.py:52
def cleanupRunWorkspace(workspace)
Remove one completed PCART run workspace 删除一次已完成的PCART运行工作区
Definition: workspace.py:264
def exportRunReport(workspace)
Export internal report files to user-visible report directory 将工作区内部报告导出到用户可见报告目录
Definition: workspace.py:239
def slugifyProjectName(projPath)
Convert project path/name to a filesystem-safe slug 将项目路径或项目名转换为可作为目录名使用的slug.
Definition: workspace.py:61
def workspaceCwd(path)
Definition: workspace.py:225
def createRunWorkspace(repoRoot, projPath, runCommand, runPath, libName, currentVersion, targetVersion, currentEnv, targetEnv, commandId='cmd-001', timestamp=None)
Create an isolated workspace for one PCART run command 为一次PCART运行命令创建隔离工作区
Definition: workspace.py:125
def getRuntimePaths(workspace)
Return runtime artifact paths for the current execution 返回当前执行使用的运行产物路径
Definition: workspace.py:207
def writeMetadata(workspace, metadata)
Write workspace metadata 写入运行工作区元数据
Definition: workspace.py:192