auto-coder 0.1.326__py3-none-any.whl → 0.1.328__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of auto-coder might be problematic. Click here for more details.
- {auto_coder-0.1.326.dist-info → auto_coder-0.1.328.dist-info}/METADATA +1 -1
- {auto_coder-0.1.326.dist-info → auto_coder-0.1.328.dist-info}/RECORD +28 -16
- autocoder/common/__init__.py +5 -0
- autocoder/common/auto_coder_lang.py +16 -0
- autocoder/common/stream_out_type.py +6 -0
- autocoder/common/v2/code_editblock_manager.py +92 -8
- autocoder/compilers/__init__.py +51 -0
- autocoder/compilers/base_compiler.py +107 -0
- autocoder/compilers/compiler_config_api.py +365 -0
- autocoder/compilers/compiler_config_manager.py +305 -0
- autocoder/compilers/compiler_factory.py +271 -0
- autocoder/compilers/java_compiler.py +680 -0
- autocoder/compilers/models.py +210 -0
- autocoder/compilers/provided_compiler.py +343 -0
- autocoder/compilers/python_compiler.py +413 -0
- autocoder/compilers/reactjs_compiler.py +491 -0
- autocoder/compilers/shadow_compiler.py +42 -0
- autocoder/compilers/vue_compiler.py +548 -0
- autocoder/events/event_content.py +29 -0
- autocoder/index/index.py +43 -9
- autocoder/memory/active_context_manager.py +3 -3
- autocoder/memory/active_package.py +2 -2
- autocoder/shadows/shadow_manager.py +251 -4
- autocoder/version.py +1 -1
- {auto_coder-0.1.326.dist-info → auto_coder-0.1.328.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.326.dist-info → auto_coder-0.1.328.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.326.dist-info → auto_coder-0.1.328.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.326.dist-info → auto_coder-0.1.328.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"""
|
|
2
|
+
用于表示代码编译结果的 Pydantic 模型。
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from typing import List, Dict, Any, Optional, Union
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from pydantic import BaseModel, Field
|
|
9
|
+
|
|
10
|
+
class CompilationErrorSeverity(str, Enum):
|
|
11
|
+
"""编译错误严重性的枚举"""
|
|
12
|
+
ERROR = "error" # 错误
|
|
13
|
+
WARNING = "warning" # 警告
|
|
14
|
+
INFO = "info" # 信息
|
|
15
|
+
|
|
16
|
+
class CompilationErrorPosition(BaseModel):
|
|
17
|
+
"""文件中编译错误的位置"""
|
|
18
|
+
line: int = Field(..., description="发现错误的行号(从1开始)")
|
|
19
|
+
column: Optional[int] = Field(None, description="发现错误的列号(从1开始)")
|
|
20
|
+
end_line: Optional[int] = Field(None, description="错误的结束行号")
|
|
21
|
+
end_column: Optional[int] = Field(None, description="错误的结束列号")
|
|
22
|
+
|
|
23
|
+
def to_str(self) -> str:
|
|
24
|
+
"""将位置转换为人类可读的字符串"""
|
|
25
|
+
result = f"第 {self.line} 行"
|
|
26
|
+
if self.column is not None:
|
|
27
|
+
result += f",第 {self.column} 列"
|
|
28
|
+
if self.end_line is not None and (self.end_line != self.line or self.end_column is not None):
|
|
29
|
+
result += f" 到第 {self.end_line} 行"
|
|
30
|
+
if self.end_column is not None:
|
|
31
|
+
result += f",第 {self.end_column} 列"
|
|
32
|
+
return result
|
|
33
|
+
|
|
34
|
+
class CompilationError(BaseModel):
|
|
35
|
+
"""单个编译错误的表示"""
|
|
36
|
+
code: Optional[str] = Field(None, description="错误代码或标识符")
|
|
37
|
+
message: str = Field(..., description="错误的人类可读描述")
|
|
38
|
+
severity: CompilationErrorSeverity = Field(..., description="错误的严重性级别")
|
|
39
|
+
position: CompilationErrorPosition = Field(..., description="错误在文件中的位置")
|
|
40
|
+
file_path: str = Field(..., description="发现错误的文件路径")
|
|
41
|
+
source: Optional[str] = Field(None, description="发现错误的源代码片段")
|
|
42
|
+
|
|
43
|
+
def to_str(self, show_file_path: bool = True) -> str:
|
|
44
|
+
"""
|
|
45
|
+
将错误转换为人类可读的字符串
|
|
46
|
+
|
|
47
|
+
参数:
|
|
48
|
+
show_file_path: 是否在输出中包含文件路径
|
|
49
|
+
|
|
50
|
+
返回:
|
|
51
|
+
错误的格式化字符串表示
|
|
52
|
+
"""
|
|
53
|
+
parts = []
|
|
54
|
+
|
|
55
|
+
if show_file_path:
|
|
56
|
+
parts.append(f"{self.file_path}:{self.position.line}")
|
|
57
|
+
|
|
58
|
+
parts.append(f"[{self.severity.value.upper()}] {self.message}")
|
|
59
|
+
|
|
60
|
+
if self.code:
|
|
61
|
+
parts.append(f"({self.code})")
|
|
62
|
+
|
|
63
|
+
result = " ".join(parts)
|
|
64
|
+
|
|
65
|
+
if self.source:
|
|
66
|
+
# 为了更好的可读性,缩进源代码
|
|
67
|
+
indented_source = "\n ".join(self.source.splitlines())
|
|
68
|
+
result += f"\n {indented_source}"
|
|
69
|
+
|
|
70
|
+
return result
|
|
71
|
+
|
|
72
|
+
class FileCompilationResult(BaseModel):
|
|
73
|
+
"""单个文件的编译结果"""
|
|
74
|
+
file_path: str = Field(..., description="被编译的文件路径")
|
|
75
|
+
success: bool = Field(True, description="编译是否成功完成")
|
|
76
|
+
language: str = Field(..., description="被编译的语言/文件类型")
|
|
77
|
+
errors: List[CompilationError] = Field(default_factory=list, description="发现的编译错误列表")
|
|
78
|
+
error_message: Optional[str] = Field(None, description="如果编译失败,错误消息")
|
|
79
|
+
warning_count: int = Field(0, description="发现的警告数量")
|
|
80
|
+
error_count: int = Field(0, description="发现的错误数量")
|
|
81
|
+
info_count: int = Field(0, description="发现的信息性问题数量")
|
|
82
|
+
execution_time_ms: Optional[int] = Field(None, description="编译文件所花费的时间(毫秒)")
|
|
83
|
+
output_file: Optional[str] = Field(None, description="编译输出的文件路径")
|
|
84
|
+
|
|
85
|
+
def to_str(self, show_file_path_in_errors: bool = False) -> str:
|
|
86
|
+
"""
|
|
87
|
+
将文件编译结果转换为人类可读的字符串
|
|
88
|
+
|
|
89
|
+
参数:
|
|
90
|
+
show_file_path_in_errors: 是否在单个错误中包含文件路径
|
|
91
|
+
|
|
92
|
+
返回:
|
|
93
|
+
文件编译结果的格式化字符串表示
|
|
94
|
+
"""
|
|
95
|
+
if not self.success:
|
|
96
|
+
return f"编译 {self.file_path} 时出错: {self.error_message or '未知错误'}"
|
|
97
|
+
|
|
98
|
+
result = [f"{self.file_path} 的编译结果 ({self.language}):"]
|
|
99
|
+
|
|
100
|
+
# 摘要信息
|
|
101
|
+
if self.success and self.error_count == 0 and self.warning_count == 0:
|
|
102
|
+
result.append("编译成功")
|
|
103
|
+
if self.output_file:
|
|
104
|
+
result.append(f"输出文件: {self.output_file}")
|
|
105
|
+
else:
|
|
106
|
+
summary = []
|
|
107
|
+
if self.error_count > 0:
|
|
108
|
+
summary.append(f"{self.error_count} 个错误")
|
|
109
|
+
if self.warning_count > 0:
|
|
110
|
+
summary.append(f"{self.warning_count} 个警告")
|
|
111
|
+
if self.info_count > 0:
|
|
112
|
+
summary.append(f"{self.info_count} 个信息")
|
|
113
|
+
|
|
114
|
+
if summary:
|
|
115
|
+
result.append("发现 " + ",".join(summary))
|
|
116
|
+
|
|
117
|
+
if self.execution_time_ms is not None:
|
|
118
|
+
result.append(f"执行时间: {self.execution_time_ms}毫秒")
|
|
119
|
+
|
|
120
|
+
# 添加单个错误
|
|
121
|
+
if self.errors:
|
|
122
|
+
result.append("\n错误:")
|
|
123
|
+
for error in self.errors:
|
|
124
|
+
error_str = error.to_str(show_file_path=show_file_path_in_errors)
|
|
125
|
+
# 缩进错误描述的每一行
|
|
126
|
+
indented_error = "\n ".join(error_str.splitlines())
|
|
127
|
+
result.append(f" {indented_error}")
|
|
128
|
+
|
|
129
|
+
return "\n".join(result)
|
|
130
|
+
|
|
131
|
+
class ProjectCompilationResult(BaseModel):
|
|
132
|
+
"""整个项目的编译结果"""
|
|
133
|
+
project_path: str = Field(..., description="被编译的项目路径")
|
|
134
|
+
file_results: Dict[str, FileCompilationResult] = Field(default_factory=dict, description="文件路径到其编译结果的映射")
|
|
135
|
+
total_files: int = Field(0, description="编译的文件总数")
|
|
136
|
+
files_with_errors: int = Field(0, description="至少有一个错误的文件数量")
|
|
137
|
+
total_errors: int = Field(0, description="所有文件中发现的错误总数")
|
|
138
|
+
total_warnings: int = Field(0, description="所有文件中的警告总数")
|
|
139
|
+
total_infos: int = Field(0, description="所有文件中的信息性问题总数")
|
|
140
|
+
success: bool = Field(True, description="整个项目的编译过程是否成功完成")
|
|
141
|
+
error_message: Optional[str] = Field(None, description="如果编译失败,错误消息")
|
|
142
|
+
output_directory: Optional[str] = Field(None, description="编译输出的目录路径")
|
|
143
|
+
|
|
144
|
+
def to_str(self, include_all_files: bool = True, include_errors: bool = True) -> str:
|
|
145
|
+
"""
|
|
146
|
+
将项目编译结果转换为人类可读的字符串
|
|
147
|
+
|
|
148
|
+
参数:
|
|
149
|
+
include_all_files: 是否包含没有错误的文件的结果
|
|
150
|
+
include_errors: 是否包含单个错误的详细信息
|
|
151
|
+
|
|
152
|
+
返回:
|
|
153
|
+
项目编译结果的格式化字符串表示
|
|
154
|
+
"""
|
|
155
|
+
result = [f"项目编译结果 ({datetime.now().strftime('%Y-%m-%d %H:%M:%S')})"]
|
|
156
|
+
|
|
157
|
+
result.append(f"项目: {self.project_path}")
|
|
158
|
+
|
|
159
|
+
if not self.success:
|
|
160
|
+
result.append(f"错误: {self.error_message or '未知错误'}")
|
|
161
|
+
|
|
162
|
+
# 摘要信息
|
|
163
|
+
result.append(f"编译的文件: {self.total_files}")
|
|
164
|
+
|
|
165
|
+
if self.success and self.total_errors == 0:
|
|
166
|
+
result.append("编译成功完成")
|
|
167
|
+
if self.output_directory:
|
|
168
|
+
result.append(f"输出目录: {self.output_directory}")
|
|
169
|
+
else:
|
|
170
|
+
result.append(f"有错误的文件: {self.files_with_errors}")
|
|
171
|
+
result.append(f"总错误数: {self.total_errors} ({self.total_errors} 个错误, {self.total_warnings} 个警告, {self.total_infos} 个信息)")
|
|
172
|
+
|
|
173
|
+
# 添加每个文件的结果
|
|
174
|
+
if self.file_results:
|
|
175
|
+
result.append("\n按文件的结果:")
|
|
176
|
+
|
|
177
|
+
for file_path, file_result in sorted(self.file_results.items()):
|
|
178
|
+
# 如果请求,跳过没有错误的文件
|
|
179
|
+
if not include_all_files and not (file_result.error_count + file_result.warning_count + file_result.info_count) > 0:
|
|
180
|
+
continue
|
|
181
|
+
|
|
182
|
+
if include_errors:
|
|
183
|
+
file_str = file_result.to_str(show_file_path_in_errors=False)
|
|
184
|
+
# 缩进文件结果的每一行
|
|
185
|
+
indented_file = "\n ".join(file_str.splitlines())
|
|
186
|
+
result.append(f" {indented_file}")
|
|
187
|
+
else:
|
|
188
|
+
# 每个文件只有一行摘要
|
|
189
|
+
error_count = file_result.error_count + file_result.warning_count + file_result.info_count
|
|
190
|
+
if error_count > 0:
|
|
191
|
+
result.append(f" {file_path}: {error_count} 个问题 ({file_result.error_count} 个错误, {file_result.warning_count} 个警告)")
|
|
192
|
+
else:
|
|
193
|
+
result.append(f" {file_path}: 编译成功")
|
|
194
|
+
|
|
195
|
+
# 在文件之间添加分隔符以提高可读性
|
|
196
|
+
result.append("")
|
|
197
|
+
|
|
198
|
+
return "\n".join(result)
|
|
199
|
+
|
|
200
|
+
def get_file_result(self, file_path: str) -> Optional[FileCompilationResult]:
|
|
201
|
+
"""
|
|
202
|
+
获取特定文件的编译结果
|
|
203
|
+
|
|
204
|
+
参数:
|
|
205
|
+
file_path: 文件路径
|
|
206
|
+
|
|
207
|
+
返回:
|
|
208
|
+
文件的编译结果,如果文件未被编译则返回None
|
|
209
|
+
"""
|
|
210
|
+
return self.file_results.get(file_path)
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module for compiling code based on a provided YAML configuration.
|
|
3
|
+
This module reads from a compiler.yml file and runs the specified compilation command.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import subprocess
|
|
8
|
+
import re
|
|
9
|
+
import yaml
|
|
10
|
+
from typing import Dict, List, Any, Optional, Union
|
|
11
|
+
import time
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from autocoder.compilers.base_compiler import BaseCompiler
|
|
15
|
+
from autocoder.compilers.models import (
|
|
16
|
+
CompilationError,
|
|
17
|
+
FileCompilationResult,
|
|
18
|
+
ProjectCompilationResult,
|
|
19
|
+
CompilationErrorPosition,
|
|
20
|
+
CompilationErrorSeverity
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ProvidedCompiler(BaseCompiler):
|
|
25
|
+
"""
|
|
26
|
+
A compiler that uses a provided YAML configuration to execute compilation commands.
|
|
27
|
+
It reads the configuration, runs the command, and processes the output based on
|
|
28
|
+
extraction patterns defined in the YAML.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, verbose: bool = False, config_path: Optional[str] = None):
|
|
32
|
+
"""
|
|
33
|
+
Initialize the ProvidedCompiler.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
verbose (bool): Whether to display verbose output.
|
|
37
|
+
config_path (Optional[str]): Path to the compiler.yml file. If None, will look in .auto-coder/projects/compiler.yml
|
|
38
|
+
"""
|
|
39
|
+
super().__init__(verbose)
|
|
40
|
+
self.config_path = config_path or os.path.join(".auto-coder","projects","compiler.yml")
|
|
41
|
+
self.config = None
|
|
42
|
+
|
|
43
|
+
def get_supported_extensions(self) -> List[str]:
|
|
44
|
+
"""
|
|
45
|
+
Get the list of file extensions supported by this compiler.
|
|
46
|
+
This is a generic compiler, so it returns an empty list as it doesn't target specific file types.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
List[str]: List of supported file extensions.
|
|
50
|
+
"""
|
|
51
|
+
return []
|
|
52
|
+
|
|
53
|
+
def _check_dependencies(self) -> bool:
|
|
54
|
+
"""
|
|
55
|
+
Check if required dependencies are installed.
|
|
56
|
+
For the provided compiler, we check if the compiler.yml file exists.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
bool: True if all dependencies are available, False otherwise.
|
|
60
|
+
"""
|
|
61
|
+
return os.path.exists(self.config_path)
|
|
62
|
+
|
|
63
|
+
def _load_config(self) -> bool:
|
|
64
|
+
"""
|
|
65
|
+
Load the compiler configuration from YAML file.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
bool: True if configuration was loaded successfully, False otherwise.
|
|
69
|
+
"""
|
|
70
|
+
if not self._check_dependencies():
|
|
71
|
+
if self.verbose:
|
|
72
|
+
print(f"Configuration file not found: {self.config_path}")
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
with open(self.config_path, 'r', encoding='utf-8') as f:
|
|
77
|
+
self.config = yaml.safe_load(f)
|
|
78
|
+
|
|
79
|
+
if not self.config or 'compilers' not in self.config:
|
|
80
|
+
if self.verbose:
|
|
81
|
+
print(f"Invalid configuration file: 'compilers' section not found")
|
|
82
|
+
return False
|
|
83
|
+
|
|
84
|
+
return True
|
|
85
|
+
except Exception as e:
|
|
86
|
+
if self.verbose:
|
|
87
|
+
print(f"Error loading configuration: {str(e)}")
|
|
88
|
+
return False
|
|
89
|
+
|
|
90
|
+
def _run_compilation_command(self, project_path:str, compiler_config: Dict[str, Any]) -> Dict[str, Any]:
|
|
91
|
+
"""
|
|
92
|
+
Run the compilation command specified in the configuration.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
compiler_config (Dict[str, Any]): Compiler configuration from YAML.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
Dict[str, Any]: Dictionary containing compilation results.
|
|
99
|
+
"""
|
|
100
|
+
result = {
|
|
101
|
+
'success': True,
|
|
102
|
+
'errors': [],
|
|
103
|
+
'error_count': 0,
|
|
104
|
+
'warning_count': 0,
|
|
105
|
+
'info_count': 0,
|
|
106
|
+
'raw_output': "",
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
working_dir = os.path.join(project_path,compiler_config.get('working_dir', '.'))
|
|
111
|
+
command = compiler_config.get('command')
|
|
112
|
+
args = compiler_config.get('args', [])
|
|
113
|
+
extract_regex = compiler_config.get('extract_regex')
|
|
114
|
+
|
|
115
|
+
if not command:
|
|
116
|
+
result['success'] = False
|
|
117
|
+
result['error_message'] = "No command specified in configuration"
|
|
118
|
+
return result
|
|
119
|
+
|
|
120
|
+
# Create the full command with arguments
|
|
121
|
+
full_command = [command] + args
|
|
122
|
+
|
|
123
|
+
# Record start time
|
|
124
|
+
start_time = time.time()
|
|
125
|
+
|
|
126
|
+
# Run the command
|
|
127
|
+
try:
|
|
128
|
+
# Ensure the working directory exists
|
|
129
|
+
os.makedirs(os.path.abspath(working_dir), exist_ok=True)
|
|
130
|
+
|
|
131
|
+
# Run the command in the specified working directory
|
|
132
|
+
process = subprocess.run(
|
|
133
|
+
full_command,
|
|
134
|
+
stdout=subprocess.PIPE,
|
|
135
|
+
stderr=subprocess.PIPE,
|
|
136
|
+
text=True,
|
|
137
|
+
cwd=working_dir
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# Combine stdout and stderr
|
|
141
|
+
output = process.stdout + process.stderr
|
|
142
|
+
result['raw_output'] = output
|
|
143
|
+
|
|
144
|
+
# Set success based on return code
|
|
145
|
+
result['success'] = process.returncode == 0
|
|
146
|
+
|
|
147
|
+
# If unsuccessful and no error message is set
|
|
148
|
+
if not result['success'] and not result.get('error_message'):
|
|
149
|
+
result['error_message'] = f"Command failed with exit code {process.returncode}"
|
|
150
|
+
|
|
151
|
+
# Extract errors using regex if provided
|
|
152
|
+
if extract_regex and output:
|
|
153
|
+
errors = self._extract_errors(
|
|
154
|
+
output, extract_regex, working_dir)
|
|
155
|
+
result['errors'] = errors
|
|
156
|
+
result['error_count'] = sum(
|
|
157
|
+
1 for e in errors if e.severity == CompilationErrorSeverity.ERROR)
|
|
158
|
+
result['warning_count'] = sum(
|
|
159
|
+
1 for e in errors if e.severity == CompilationErrorSeverity.WARNING)
|
|
160
|
+
result['info_count'] = sum(
|
|
161
|
+
1 for e in errors if e.severity == CompilationErrorSeverity.INFO)
|
|
162
|
+
elif not result['success']:
|
|
163
|
+
result['errors'] = [CompilationError(
|
|
164
|
+
file_path="",
|
|
165
|
+
message=result['raw_output'],
|
|
166
|
+
severity=CompilationErrorSeverity.ERROR,
|
|
167
|
+
position=CompilationErrorPosition(
|
|
168
|
+
line=-1
|
|
169
|
+
))]
|
|
170
|
+
except subprocess.SubprocessError as e:
|
|
171
|
+
result['success'] = False
|
|
172
|
+
result['error_message'] = f"Error executing command: {str(e)}"
|
|
173
|
+
|
|
174
|
+
# Calculate execution time
|
|
175
|
+
result['execution_time_ms'] = int(
|
|
176
|
+
(time.time() - start_time) * 1000)
|
|
177
|
+
|
|
178
|
+
except Exception as e:
|
|
179
|
+
result['success'] = False
|
|
180
|
+
result['error_message'] = f"Unexpected error: {str(e)}"
|
|
181
|
+
|
|
182
|
+
return result
|
|
183
|
+
|
|
184
|
+
def _extract_errors(self, output: str, regex_pattern: str, base_path: str) -> List[CompilationError]:
|
|
185
|
+
"""
|
|
186
|
+
Extract errors from command output using the provided regex pattern.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
output (str): Command output text.
|
|
190
|
+
regex_pattern (str): Regular expression to extract errors.
|
|
191
|
+
base_path (str): Base path for file references.
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
List[CompilationError]: List of extracted compilation errors.
|
|
195
|
+
"""
|
|
196
|
+
errors = []
|
|
197
|
+
|
|
198
|
+
try:
|
|
199
|
+
pattern = re.compile(regex_pattern)
|
|
200
|
+
matches = pattern.finditer(output)
|
|
201
|
+
|
|
202
|
+
for match in matches:
|
|
203
|
+
match_str = match.group(0)
|
|
204
|
+
errors.append(CompilationError(
|
|
205
|
+
message=match_str,
|
|
206
|
+
severity=CompilationErrorSeverity.ERROR,
|
|
207
|
+
position=CompilationErrorPosition(
|
|
208
|
+
file_path="",
|
|
209
|
+
line=-1,
|
|
210
|
+
column=-1
|
|
211
|
+
)
|
|
212
|
+
))
|
|
213
|
+
except Exception as e:
|
|
214
|
+
# If regex parsing fails, create a generic error
|
|
215
|
+
if self.verbose:
|
|
216
|
+
print(f"Error parsing regex: {str(e)}")
|
|
217
|
+
|
|
218
|
+
return errors
|
|
219
|
+
|
|
220
|
+
def compile_file(self, file_path: str) -> Dict[str, Any]:
|
|
221
|
+
"""
|
|
222
|
+
This compiler doesn't support compiling individual files directly.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
file_path (str): Path to the file to compile.
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
Dict[str, Any]: Error indicating that file compilation is not supported.
|
|
229
|
+
"""
|
|
230
|
+
return {
|
|
231
|
+
'success': False,
|
|
232
|
+
'error_message': "ProvidedCompiler does not support compiling individual files.",
|
|
233
|
+
'file_path': file_path,
|
|
234
|
+
'language': 'unknown'
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
def compile_project(self, project_path: str,target_compiler_name:Optional[str] = None) -> ProjectCompilationResult:
|
|
238
|
+
"""
|
|
239
|
+
Compile a project using configuration from compiler.yml.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
project_path (str): Path to the project directory.
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
Dict[str, Any]: Dictionary containing compilation results.
|
|
246
|
+
"""
|
|
247
|
+
# Create a project compilation result
|
|
248
|
+
result = ProjectCompilationResult(
|
|
249
|
+
project_path=project_path,
|
|
250
|
+
success=True
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
# Load configuration
|
|
254
|
+
if not self._load_config():
|
|
255
|
+
result.success = False
|
|
256
|
+
result.error_message = f"Failed to load configuration from {self.config_path}"
|
|
257
|
+
return result
|
|
258
|
+
|
|
259
|
+
target_compiler_config = None
|
|
260
|
+
if target_compiler_name:
|
|
261
|
+
for compiler_config in self.config.get('compilers', []):
|
|
262
|
+
if compiler_config.get("name","") == target_compiler_name:
|
|
263
|
+
target_compiler_config = compiler_config
|
|
264
|
+
break
|
|
265
|
+
|
|
266
|
+
if not target_compiler_config:
|
|
267
|
+
result.success = False
|
|
268
|
+
result.error_message = f"Compiler {target_compiler_name} not found in configuration"
|
|
269
|
+
return result
|
|
270
|
+
|
|
271
|
+
if self.verbose:
|
|
272
|
+
print(f"Running compiler: {target_compiler_name}")
|
|
273
|
+
|
|
274
|
+
# Run the compilation command
|
|
275
|
+
compile_result = self._run_compilation_command(project_path, target_compiler_config)
|
|
276
|
+
compile_errors:List[CompilationError] = compile_result['errors']
|
|
277
|
+
error_count = len(compile_errors)
|
|
278
|
+
|
|
279
|
+
result = ProjectCompilationResult(
|
|
280
|
+
project_path=project_path,
|
|
281
|
+
success=compile_result['success'],
|
|
282
|
+
error_message=compile_result['error_message'],
|
|
283
|
+
file_results={
|
|
284
|
+
"1":FileCompilationResult(
|
|
285
|
+
file_path="1",
|
|
286
|
+
language="unknown",
|
|
287
|
+
errors=compile_errors,
|
|
288
|
+
warning_count= 0,
|
|
289
|
+
error_count= error_count,
|
|
290
|
+
info_count=0,
|
|
291
|
+
execution_time_ms=compile_result['execution_time_ms'],
|
|
292
|
+
output_file=None
|
|
293
|
+
)
|
|
294
|
+
},
|
|
295
|
+
total_errors=error_count,
|
|
296
|
+
total_warnings=0,
|
|
297
|
+
total_infos=0,
|
|
298
|
+
total_files= -1 ,
|
|
299
|
+
files_with_errors=error_count
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
return result
|
|
303
|
+
|
|
304
|
+
def format_compile_result(self, compile_result: Union[ProjectCompilationResult, FileCompilationResult]) -> str:
|
|
305
|
+
"""
|
|
306
|
+
Format compilation results into a human-readable string.
|
|
307
|
+
|
|
308
|
+
Args:
|
|
309
|
+
compile_result (Dict[str, Any]): The compilation result dictionary.
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
str: A formatted string representation of the compilation results.
|
|
313
|
+
"""
|
|
314
|
+
if isinstance(compile_result, dict) and 'project_path' in compile_result:
|
|
315
|
+
# This is a project compilation result
|
|
316
|
+
project_result = ProjectCompilationResult(**compile_result)
|
|
317
|
+
return project_result.to_str()
|
|
318
|
+
elif isinstance(compile_result, dict) and 'file_path' in compile_result:
|
|
319
|
+
# This is a file compilation result
|
|
320
|
+
file_result = FileCompilationResult(**compile_result)
|
|
321
|
+
return file_result.to_str()
|
|
322
|
+
else:
|
|
323
|
+
# For raw dictionary results
|
|
324
|
+
if compile_result.get('success', False):
|
|
325
|
+
return "Compilation successful"
|
|
326
|
+
else:
|
|
327
|
+
return f"Compilation failed: {compile_result.get('error_message', 'Unknown error')}"
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def compile_with_provided_config(project_path: str, config_path: Optional[str] = None, verbose: bool = False) -> Dict[str, Any]:
|
|
331
|
+
"""
|
|
332
|
+
Utility function to compile a project using the provided configuration.
|
|
333
|
+
|
|
334
|
+
Args:
|
|
335
|
+
project_path (str): Path to the project directory.
|
|
336
|
+
config_path (Optional[str]): Path to the compiler.yml file. If None, will look in .auto-coder/projects/compiler.yml
|
|
337
|
+
verbose (bool): Whether to display verbose output.
|
|
338
|
+
|
|
339
|
+
Returns:
|
|
340
|
+
Dict[str, Any]: A dictionary containing compilation results.
|
|
341
|
+
"""
|
|
342
|
+
compiler = ProvidedCompiler(verbose=verbose, config_path=config_path)
|
|
343
|
+
return compiler.compile_project(project_path)
|