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 
115  repoRoot,
116  projPath,
117  runCommand,
118  runPath,
119  libName,
120  currentVersion,
121  targetVersion,
122  currentEnv,
123  targetEnv,
124  commandId='cmd-001',
125  timestamp=None,
126  writePatch=False,
127 ):
128  repoRoot=os.path.abspath(repoRoot)
129  timestamp=timestamp or datetime.now().strftime('%Y%m%d-%H%M%S')
130  projectSlug=slugifyProjectName(projPath)
131  runsRoot=os.path.join(repoRoot,'PCARTRuns','runs')
132  os.makedirs(runsRoot, exist_ok=True)
133  runId,runRoot=_nextRunId(runsRoot,projectSlug,timestamp)
134 
135  workspaceRoot=os.path.join(runRoot,commandId)
136  os.mkdir(workspaceRoot)
137  copyRoot=os.path.join(workspaceRoot,'Copy')
138  dynamicRoot=os.path.join(workspaceRoot,'Dynamic')
139  dataDir=os.path.join(workspaceRoot,'data')
140  tempDir=os.path.join(workspaceRoot,'temp')
141  internalReportDir=os.path.join(workspaceRoot,'Report')
142  reportRoot=os.path.join(repoRoot,'Report','runs',runId,commandId)
143  metadataPath=os.path.join(workspaceRoot,'metadata.json')
144 
145  for path in (
146  copyRoot,
147  dynamicRoot,
148  dataDir,
149  tempDir,
150  internalReportDir,
151  reportRoot,
152  os.path.join(reportRoot,'patches'),
153  os.path.join(reportRoot,'fixed_project'),
154  ):
155  os.makedirs(path,exist_ok=True)
156 
157  workspace=RunWorkspace(repo_root=repoRoot,run_id=runId,command_id=commandId,run_root=runRoot,workspace_root=workspaceRoot,copy_root=copyRoot,dynamic_root=dynamicRoot,data_dir=dataDir,temp_dir=tempDir,internal_report_dir=internalReportDir,report_root=reportRoot,metadata_path=metadataPath)
159  workspace,
160  {
161  'project_slug': projectSlug,
162  'project_path': projPath,
163  'run_command': runCommand,
164  'run_file_path': runPath,
165  'lib_name': libName,
166  'current_version': currentVersion,
167  'target_version': targetVersion,
168  'current_env': currentEnv,
169  'target_env': targetEnv,
170  'write_patch': writePatch,
171  },
172  )
173  return workspace
174 
175 
176 
182 def writeMetadata(workspace,metadata):
183  content=asdict(workspace)
184  content.update(metadata)
185  with open(workspace.metadata_path,'w',encoding='utf-8') as fw:
186  json.dump(content,fw,ensure_ascii=False,indent=2)
187 
188 
189 
197 def getRuntimePaths(workspace):
198  return {
199  'workspace_root': workspace.workspace_root,
200  'copy_root': workspace.copy_root,
201  'dynamic_root': workspace.dynamic_root,
202  'data_dir': workspace.data_dir,
203  'temp_dir': workspace.temp_dir,
204  'report_dir': workspace.internal_report_dir,
205  }
206 
207 
208 
214 @contextmanager
215 def workspaceCwd(path):
216  previous=os.getcwd()
217  os.chdir(path)
218  try:
219  yield
220  finally:
221  os.chdir(previous)
222 
223 
224 
229 def exportRunReport(workspace):
230  os.makedirs(workspace.report_root, exist_ok=True)
231  os.makedirs(os.path.join(workspace.report_root,'patches'),exist_ok=True)
232  os.makedirs(os.path.join(workspace.report_root,'fixed_project'),exist_ok=True)
233  if not os.path.isdir(workspace.internal_report_dir):
234  return
235  for name in os.listdir(workspace.internal_report_dir):
236  source=os.path.join(workspace.internal_report_dir,name)
237  target=os.path.join(workspace.report_root,name)
238  if os.path.isdir(source):
239  if os.path.exists(target):
240  shutil.rmtree(target)
241  shutil.copytree(source,target)
242  else:
243  shutil.copy2(source,target)
244 
245 
246 
254 def cleanupRunWorkspace(workspace):
255  runsRoot=os.path.realpath(os.path.join(workspace.repo_root,'PCARTRuns','runs'))
256  runRoot=os.path.realpath(workspace.run_root)
257  normalizedRunsRoot=os.path.normcase(os.path.normpath(runsRoot))
258  normalizedParent=os.path.normcase(os.path.normpath(os.path.dirname(runRoot)))
259 
260  if normalizedParent!=normalizedRunsRoot:
261  raise ValueError(f'Refuse to remove workspace outside PCARTRuns/runs: {runRoot}')
262 
263  if os.path.isdir(runRoot):
264  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:254
def exportRunReport(workspace)
Export internal report files to user-visible report directory 将工作区内部报告导出到用户可见报告目录
Definition: workspace.py:229
def slugifyProjectName(projPath)
Convert project path/name to a filesystem-safe slug 将项目路径或项目名转换为可作为目录名使用的slug.
Definition: workspace.py:61
def workspaceCwd(path)
Definition: workspace.py:215
def createRunWorkspace(repoRoot, projPath, runCommand, runPath, libName, currentVersion, targetVersion, currentEnv, targetEnv, commandId='cmd-001', timestamp=None, writePatch=False)
Create an isolated workspace for one PCART run command 为一次PCART运行命令创建隔离工作区
Definition: workspace.py:127
def getRuntimePaths(workspace)
Return runtime artifact paths for the current execution 返回当前执行使用的运行产物路径
Definition: workspace.py:197
def writeMetadata(workspace, metadata)
Write workspace metadata 写入运行工作区元数据
Definition: workspace.py:182