multi-lang-build 0.2.2__tar.gz → 0.2.3__tar.gz
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.
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/PKG-INFO +1 -1
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/pyproject.toml +1 -1
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/src/multi_lang_build/__init__.py +1 -1
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/src/multi_lang_build/cli.py +17 -10
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/src/multi_lang_build/compiler/base.py +135 -22
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/src/multi_lang_build/compiler/go.py +54 -38
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/src/multi_lang_build/compiler/pnpm.py +83 -33
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/src/multi_lang_build/compiler/python.py +24 -15
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/.gitignore +0 -0
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/LICENSE +0 -0
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/README.md +0 -0
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/src/multi_lang_build/compiler/__init__.py +0 -0
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/src/multi_lang_build/mirror/__init__.py +0 -0
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/src/multi_lang_build/mirror/cli.py +0 -0
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/src/multi_lang_build/mirror/config.py +0 -0
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/src/multi_lang_build/py.typed +0 -0
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/src/multi_lang_build/register.py +0 -0
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/src/multi_lang_build/types.py +0 -0
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/tests/__init__.py +0 -0
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/tests/conftest.py +0 -0
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/tests/test_compiler.py +0 -0
- {multi_lang_build-0.2.2 → multi_lang_build-0.2.3}/tests/test_mirror.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: multi-lang-build
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Multi-language automated build tool with domestic mirror acceleration support
|
|
5
5
|
Project-URL: Homepage, https://github.com/example/multi-lang-build
|
|
6
6
|
Project-URL: Repository, https://github.com/example/multi-lang-build
|
|
@@ -7,7 +7,7 @@ from multi_lang_build.compiler.python import PythonCompiler
|
|
|
7
7
|
from multi_lang_build.mirror.config import MirrorConfig, get_mirror_config
|
|
8
8
|
from multi_lang_build.register import register_skill
|
|
9
9
|
|
|
10
|
-
__version__ = "0.2.
|
|
10
|
+
__version__ = "0.2.3"
|
|
11
11
|
__all__ = [
|
|
12
12
|
"BuildConfig",
|
|
13
13
|
"BuildResult",
|
|
@@ -61,7 +61,8 @@ Supported languages:
|
|
|
61
61
|
pnpm_parser.add_argument("--mirror/--no-mirror", default=True, help="Enable/disable mirror acceleration")
|
|
62
62
|
pnpm_parser.add_argument("--script", type=str, help="Run specific npm script")
|
|
63
63
|
pnpm_parser.add_argument("--install", action="store_true", help="Install dependencies only")
|
|
64
|
-
|
|
64
|
+
pnpm_parser.add_argument("--stream/--no-stream", dest="stream_output", default=True, help="Enable/disable real-time output streaming (default: enabled)")
|
|
65
|
+
|
|
65
66
|
go_parser = subparsers.add_parser(
|
|
66
67
|
"go",
|
|
67
68
|
help="Build Go projects",
|
|
@@ -75,7 +76,8 @@ Supported languages:
|
|
|
75
76
|
go_parser.add_argument("--test", action="store_true", help="Run tests instead of building")
|
|
76
77
|
go_parser.add_argument("--tidy", action="store_true", help="Run go mod tidy")
|
|
77
78
|
go_parser.add_argument("--all", action="store_true", help="Build all packages")
|
|
78
|
-
|
|
79
|
+
go_parser.add_argument("--stream/--no-stream", dest="stream_output", default=True, help="Enable/disable real-time output streaming (default: enabled)")
|
|
80
|
+
|
|
79
81
|
python_parser = subparsers.add_parser(
|
|
80
82
|
"python",
|
|
81
83
|
help="Build Python projects",
|
|
@@ -88,6 +90,7 @@ Supported languages:
|
|
|
88
90
|
python_parser.add_argument("--dev", action="store_true", help="Include development dependencies")
|
|
89
91
|
python_parser.add_argument("--poetry", action="store_true", help="Force using poetry")
|
|
90
92
|
python_parser.add_argument("--create-venv", type=Path, help="Create virtual environment at path")
|
|
93
|
+
python_parser.add_argument("--stream/--no-stream", dest="stream_output", default=True, help="Enable/disable real-time output streaming (default: enabled)")
|
|
91
94
|
|
|
92
95
|
mirror_parser = subparsers.add_parser(
|
|
93
96
|
"mirror",
|
|
@@ -175,9 +178,9 @@ Examples:
|
|
|
175
178
|
try:
|
|
176
179
|
if parsed_args.language == "pnpm":
|
|
177
180
|
from multi_lang_build.compiler.pnpm import PnpmCompiler
|
|
178
|
-
|
|
181
|
+
|
|
179
182
|
compiler = PnpmCompiler()
|
|
180
|
-
|
|
183
|
+
|
|
181
184
|
if parsed_args.script:
|
|
182
185
|
result = compiler.run_script(
|
|
183
186
|
parsed_args.source_dir,
|
|
@@ -194,13 +197,14 @@ Examples:
|
|
|
194
197
|
parsed_args.source_dir,
|
|
195
198
|
parsed_args.output,
|
|
196
199
|
mirror_enabled=parsed_args.mirror,
|
|
200
|
+
stream_output=parsed_args.stream_output,
|
|
197
201
|
)
|
|
198
|
-
|
|
202
|
+
|
|
199
203
|
elif parsed_args.language == "go":
|
|
200
204
|
from multi_lang_build.compiler.go import GoCompiler
|
|
201
|
-
|
|
205
|
+
|
|
202
206
|
compiler = GoCompiler()
|
|
203
|
-
|
|
207
|
+
|
|
204
208
|
if parsed_args.test:
|
|
205
209
|
result = compiler.run_tests(
|
|
206
210
|
parsed_args.source_dir,
|
|
@@ -216,6 +220,7 @@ Examples:
|
|
|
216
220
|
parsed_args.source_dir,
|
|
217
221
|
parsed_args.output,
|
|
218
222
|
mirror_enabled=parsed_args.mirror,
|
|
223
|
+
stream_output=parsed_args.stream_output,
|
|
219
224
|
)
|
|
220
225
|
else:
|
|
221
226
|
tags = parsed_args.tags.split(",") if parsed_args.tags else None
|
|
@@ -225,13 +230,14 @@ Examples:
|
|
|
225
230
|
mirror_enabled=parsed_args.mirror,
|
|
226
231
|
ldflags=parsed_args.ldflags,
|
|
227
232
|
tags=tags,
|
|
233
|
+
stream_output=parsed_args.stream_output,
|
|
228
234
|
)
|
|
229
|
-
|
|
235
|
+
|
|
230
236
|
elif parsed_args.language == "python":
|
|
231
237
|
from multi_lang_build.compiler.python import PythonCompiler
|
|
232
|
-
|
|
238
|
+
|
|
233
239
|
compiler = PythonCompiler()
|
|
234
|
-
|
|
240
|
+
|
|
235
241
|
if parsed_args.create_venv:
|
|
236
242
|
result = compiler.create_venv(
|
|
237
243
|
parsed_args.create_venv,
|
|
@@ -249,6 +255,7 @@ Examples:
|
|
|
249
255
|
parsed_args.source_dir,
|
|
250
256
|
parsed_args.output,
|
|
251
257
|
mirror_enabled=parsed_args.mirror,
|
|
258
|
+
stream_output=parsed_args.stream_output,
|
|
252
259
|
)
|
|
253
260
|
|
|
254
261
|
elif parsed_args.language == "mirror":
|
|
@@ -4,6 +4,8 @@ from abc import ABC, abstractmethod
|
|
|
4
4
|
from typing import TypeAlias, TypedDict, NotRequired
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
import time
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
class BuildConfig(TypedDict, total=False):
|
|
@@ -37,30 +39,30 @@ class CompilerInfo(TypedDict):
|
|
|
37
39
|
|
|
38
40
|
class CompilerBase(ABC):
|
|
39
41
|
"""Abstract base class for all language compilers."""
|
|
40
|
-
|
|
42
|
+
|
|
41
43
|
@property
|
|
42
44
|
@abstractmethod
|
|
43
45
|
def name(self) -> str:
|
|
44
46
|
"""Get the compiler name."""
|
|
45
47
|
...
|
|
46
|
-
|
|
48
|
+
|
|
47
49
|
@property
|
|
48
50
|
@abstractmethod
|
|
49
51
|
def version(self) -> str:
|
|
50
52
|
"""Get the compiler version."""
|
|
51
53
|
...
|
|
52
|
-
|
|
54
|
+
|
|
53
55
|
@property
|
|
54
56
|
@abstractmethod
|
|
55
57
|
def supported_mirrors(self) -> list[str]:
|
|
56
58
|
"""Get list of supported mirror configurations."""
|
|
57
59
|
...
|
|
58
|
-
|
|
60
|
+
|
|
59
61
|
@abstractmethod
|
|
60
62
|
def get_info(self) -> CompilerInfo:
|
|
61
63
|
"""Get compiler information."""
|
|
62
64
|
...
|
|
63
|
-
|
|
65
|
+
|
|
64
66
|
@abstractmethod
|
|
65
67
|
def build(
|
|
66
68
|
self,
|
|
@@ -70,33 +72,35 @@ class CompilerBase(ABC):
|
|
|
70
72
|
environment: dict[str, str] | None = None,
|
|
71
73
|
mirror_enabled: bool = True,
|
|
72
74
|
extra_args: list[str] | None = None,
|
|
75
|
+
stream_output: bool = True,
|
|
73
76
|
) -> BuildResult:
|
|
74
77
|
"""Execute the build process.
|
|
75
|
-
|
|
78
|
+
|
|
76
79
|
Args:
|
|
77
80
|
source_dir: Source code directory
|
|
78
81
|
output_dir: Build output directory
|
|
79
82
|
environment: Additional environment variables
|
|
80
83
|
mirror_enabled: Whether to use mirror acceleration
|
|
81
84
|
extra_args: Additional arguments to pass to the build command
|
|
82
|
-
|
|
85
|
+
stream_output: Whether to stream output in real-time (default: True)
|
|
86
|
+
|
|
83
87
|
Returns:
|
|
84
88
|
BuildResult containing success status and output information.
|
|
85
89
|
"""
|
|
86
90
|
...
|
|
87
|
-
|
|
91
|
+
|
|
88
92
|
@abstractmethod
|
|
89
93
|
def clean(self, directory: Path) -> bool:
|
|
90
94
|
"""Clean build artifacts in the specified directory.
|
|
91
|
-
|
|
95
|
+
|
|
92
96
|
Args:
|
|
93
97
|
directory: Directory to clean
|
|
94
|
-
|
|
98
|
+
|
|
95
99
|
Returns:
|
|
96
100
|
True if successful, False otherwise.
|
|
97
101
|
"""
|
|
98
102
|
...
|
|
99
|
-
|
|
103
|
+
|
|
100
104
|
def _run_build(
|
|
101
105
|
self,
|
|
102
106
|
command: list[str],
|
|
@@ -105,42 +109,151 @@ class CompilerBase(ABC):
|
|
|
105
109
|
*,
|
|
106
110
|
environment: dict[str, str] | None = None,
|
|
107
111
|
extra_args: list[str] | None = None,
|
|
112
|
+
stream_output: bool = True,
|
|
108
113
|
) -> BuildResult:
|
|
109
114
|
"""Execute a build command with timing and error handling.
|
|
110
|
-
|
|
115
|
+
|
|
111
116
|
Args:
|
|
112
117
|
command: Build command to execute
|
|
113
118
|
source_dir: Source directory for the build
|
|
114
119
|
output_dir: Output directory for build artifacts
|
|
115
120
|
environment: Additional environment variables
|
|
116
121
|
extra_args: Additional arguments to append to command
|
|
117
|
-
|
|
122
|
+
stream_output: Whether to stream output in real-time (default: True)
|
|
123
|
+
|
|
118
124
|
Returns:
|
|
119
125
|
BuildResult with success status and output information.
|
|
120
126
|
"""
|
|
121
|
-
import subprocess
|
|
122
|
-
|
|
123
127
|
full_command = command.copy()
|
|
124
128
|
if extra_args:
|
|
125
129
|
full_command.extend(extra_args)
|
|
126
|
-
|
|
130
|
+
|
|
127
131
|
env = environment.copy() if environment else {}
|
|
128
132
|
env.setdefault("PATH", "")
|
|
129
|
-
|
|
133
|
+
|
|
130
134
|
start_time = time.perf_counter()
|
|
131
|
-
|
|
135
|
+
|
|
136
|
+
if stream_output:
|
|
137
|
+
return self._run_build_stream(
|
|
138
|
+
full_command, source_dir, output_dir, env, start_time
|
|
139
|
+
)
|
|
140
|
+
else:
|
|
141
|
+
return self._run_build_capture(
|
|
142
|
+
full_command, source_dir, output_dir, env, start_time
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
def _run_build_stream(
|
|
146
|
+
self,
|
|
147
|
+
command: list[str],
|
|
148
|
+
source_dir: Path,
|
|
149
|
+
output_dir: Path,
|
|
150
|
+
env: dict[str, str],
|
|
151
|
+
start_time: float,
|
|
152
|
+
) -> BuildResult:
|
|
153
|
+
"""Execute build command with real-time output streaming.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
command: Build command to execute
|
|
157
|
+
source_dir: Source directory for the build
|
|
158
|
+
output_dir: Output directory for build artifacts
|
|
159
|
+
env: Environment variables
|
|
160
|
+
start_time: Start time for duration calculation
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
BuildResult with success status and output information.
|
|
164
|
+
"""
|
|
165
|
+
stdout_buffer = []
|
|
166
|
+
stderr_buffer = []
|
|
167
|
+
|
|
168
|
+
try:
|
|
169
|
+
process = subprocess.Popen(
|
|
170
|
+
command,
|
|
171
|
+
cwd=source_dir,
|
|
172
|
+
stdout=subprocess.PIPE,
|
|
173
|
+
stderr=subprocess.PIPE,
|
|
174
|
+
text=True,
|
|
175
|
+
env=env,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
# Read stdout in real-time
|
|
179
|
+
for line in process.stdout:
|
|
180
|
+
line = line.rstrip('\n\r')
|
|
181
|
+
stdout_buffer.append(line)
|
|
182
|
+
print(line)
|
|
183
|
+
sys.stdout.flush()
|
|
184
|
+
|
|
185
|
+
# Read stderr in real-time
|
|
186
|
+
for line in process.stderr:
|
|
187
|
+
line = line.rstrip('\n\r')
|
|
188
|
+
stderr_buffer.append(line)
|
|
189
|
+
print(line, file=sys.stderr)
|
|
190
|
+
sys.stderr.flush()
|
|
191
|
+
|
|
192
|
+
return_code = process.wait()
|
|
193
|
+
duration = time.perf_counter() - start_time
|
|
194
|
+
|
|
195
|
+
return BuildResult(
|
|
196
|
+
success=return_code == 0,
|
|
197
|
+
return_code=return_code,
|
|
198
|
+
stdout='\n'.join(stdout_buffer),
|
|
199
|
+
stderr='\n'.join(stderr_buffer),
|
|
200
|
+
output_path=output_dir if return_code == 0 else None,
|
|
201
|
+
duration_seconds=duration,
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
except subprocess.TimeoutExpired:
|
|
205
|
+
duration = time.perf_counter() - start_time
|
|
206
|
+
return BuildResult(
|
|
207
|
+
success=False,
|
|
208
|
+
return_code=-1,
|
|
209
|
+
stdout='\n'.join(stdout_buffer),
|
|
210
|
+
stderr="Build timed out after 1 hour",
|
|
211
|
+
output_path=None,
|
|
212
|
+
duration_seconds=duration,
|
|
213
|
+
)
|
|
214
|
+
except Exception as e:
|
|
215
|
+
duration = time.perf_counter() - start_time
|
|
216
|
+
return BuildResult(
|
|
217
|
+
success=False,
|
|
218
|
+
return_code=-2,
|
|
219
|
+
stdout='\n'.join(stdout_buffer),
|
|
220
|
+
stderr=f"Build error: {str(e)}",
|
|
221
|
+
output_path=None,
|
|
222
|
+
duration_seconds=duration,
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
def _run_build_capture(
|
|
226
|
+
self,
|
|
227
|
+
command: list[str],
|
|
228
|
+
source_dir: Path,
|
|
229
|
+
output_dir: Path,
|
|
230
|
+
env: dict[str, str],
|
|
231
|
+
start_time: float,
|
|
232
|
+
) -> BuildResult:
|
|
233
|
+
"""Execute build command with captured output (no real-time display).
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
command: Build command to execute
|
|
237
|
+
source_dir: Source directory for the build
|
|
238
|
+
output_dir: Output directory for build artifacts
|
|
239
|
+
env: Environment variables
|
|
240
|
+
start_time: Start time for duration calculation
|
|
241
|
+
|
|
242
|
+
Returns:
|
|
243
|
+
BuildResult with success status and output information.
|
|
244
|
+
"""
|
|
132
245
|
try:
|
|
133
246
|
result = subprocess.run(
|
|
134
|
-
|
|
247
|
+
command,
|
|
135
248
|
cwd=source_dir,
|
|
136
249
|
capture_output=True,
|
|
137
250
|
text=True,
|
|
138
251
|
env=env,
|
|
139
252
|
timeout=3600, # 1 hour timeout
|
|
140
253
|
)
|
|
141
|
-
|
|
254
|
+
|
|
142
255
|
duration = time.perf_counter() - start_time
|
|
143
|
-
|
|
256
|
+
|
|
144
257
|
return BuildResult(
|
|
145
258
|
success=result.returncode == 0,
|
|
146
259
|
return_code=result.returncode,
|
|
@@ -149,7 +262,7 @@ class CompilerBase(ABC):
|
|
|
149
262
|
output_path=output_dir if result.returncode == 0 else None,
|
|
150
263
|
duration_seconds=duration,
|
|
151
264
|
)
|
|
152
|
-
|
|
265
|
+
|
|
153
266
|
except subprocess.TimeoutExpired:
|
|
154
267
|
duration = time.perf_counter() - start_time
|
|
155
268
|
return BuildResult(
|
|
@@ -110,16 +110,18 @@ class GoCompiler(CompilerBase):
|
|
|
110
110
|
environment: dict[str, str] | None = None,
|
|
111
111
|
mirror_enabled: bool = True,
|
|
112
112
|
extra_args: list[str] | None = None,
|
|
113
|
+
stream_output: bool = True,
|
|
113
114
|
) -> BuildResult:
|
|
114
115
|
"""Execute the Go build process.
|
|
115
|
-
|
|
116
|
+
|
|
116
117
|
Args:
|
|
117
118
|
source_dir: Source code directory
|
|
118
119
|
output_dir: Build output directory (for binary)
|
|
119
120
|
environment: Additional environment variables
|
|
120
121
|
mirror_enabled: Whether to use Go proxy mirror
|
|
121
122
|
extra_args: Additional arguments to pass to go build
|
|
122
|
-
|
|
123
|
+
stream_output: Whether to stream output in real-time (default: True)
|
|
124
|
+
|
|
123
125
|
Returns:
|
|
124
126
|
BuildResult containing success status and output information.
|
|
125
127
|
"""
|
|
@@ -147,22 +149,24 @@ class GoCompiler(CompilerBase):
|
|
|
147
149
|
source_dir,
|
|
148
150
|
output_dir,
|
|
149
151
|
environment=env,
|
|
152
|
+
stream_output=stream_output,
|
|
150
153
|
)
|
|
151
|
-
|
|
154
|
+
|
|
152
155
|
if not deps_result["success"]:
|
|
153
156
|
return deps_result
|
|
154
|
-
|
|
157
|
+
|
|
155
158
|
# Build the project
|
|
156
159
|
build_args = [go_executable, "build", "-o", str(output_dir)]
|
|
157
|
-
|
|
160
|
+
|
|
158
161
|
if extra_args:
|
|
159
162
|
build_args.extend(extra_args)
|
|
160
|
-
|
|
163
|
+
|
|
161
164
|
return self._run_build(
|
|
162
165
|
build_args,
|
|
163
166
|
source_dir,
|
|
164
167
|
output_dir,
|
|
165
168
|
environment=env,
|
|
169
|
+
stream_output=stream_output,
|
|
166
170
|
)
|
|
167
171
|
|
|
168
172
|
def build_binary(
|
|
@@ -175,9 +179,10 @@ class GoCompiler(CompilerBase):
|
|
|
175
179
|
mirror_enabled: bool = True,
|
|
176
180
|
ldflags: str | None = None,
|
|
177
181
|
tags: list[str] | None = None,
|
|
182
|
+
stream_output: bool = True,
|
|
178
183
|
) -> BuildResult:
|
|
179
184
|
"""Build a specific Go binary.
|
|
180
|
-
|
|
185
|
+
|
|
181
186
|
Args:
|
|
182
187
|
source_dir: Source code directory (working directory for build)
|
|
183
188
|
output_path: Output path for the binary
|
|
@@ -187,40 +192,42 @@ class GoCompiler(CompilerBase):
|
|
|
187
192
|
mirror_enabled: Whether to use Go proxy mirror
|
|
188
193
|
ldflags: Linker flags to pass to the compiler
|
|
189
194
|
tags: Build tags to pass to the compiler
|
|
190
|
-
|
|
195
|
+
stream_output: Whether to stream output in real-time (default: True)
|
|
196
|
+
|
|
191
197
|
Returns:
|
|
192
198
|
BuildResult containing success status and output information.
|
|
193
199
|
"""
|
|
194
200
|
go_executable = self._get_executable_path()
|
|
195
|
-
|
|
201
|
+
|
|
196
202
|
source_dir = self._validate_directory(source_dir, create_if_not_exists=False)
|
|
197
|
-
|
|
203
|
+
|
|
198
204
|
# Ensure output directory exists
|
|
199
205
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
200
|
-
|
|
206
|
+
|
|
201
207
|
env = environment.copy() if environment else {}
|
|
202
|
-
|
|
208
|
+
|
|
203
209
|
if mirror_enabled:
|
|
204
210
|
mirror_key = self._mirror or "go"
|
|
205
211
|
env = apply_mirror_environment(mirror_key, env)
|
|
206
|
-
|
|
212
|
+
|
|
207
213
|
build_args = [go_executable, "build", "-o", str(output_path)]
|
|
208
|
-
|
|
214
|
+
|
|
209
215
|
if ldflags:
|
|
210
216
|
build_args.extend(["-ldflags", ldflags])
|
|
211
|
-
|
|
217
|
+
|
|
212
218
|
if tags:
|
|
213
219
|
build_args.extend(["-tags", ",".join(tags)])
|
|
214
|
-
|
|
220
|
+
|
|
215
221
|
# Add target if specified (target is relative to source_dir)
|
|
216
222
|
if target:
|
|
217
223
|
build_args.append(str(target))
|
|
218
|
-
|
|
224
|
+
|
|
219
225
|
return self._run_build(
|
|
220
226
|
build_args,
|
|
221
227
|
source_dir,
|
|
222
228
|
output_path.parent,
|
|
223
229
|
environment=env,
|
|
230
|
+
stream_output=stream_output,
|
|
224
231
|
)
|
|
225
232
|
|
|
226
233
|
def build_all(
|
|
@@ -231,42 +238,45 @@ class GoCompiler(CompilerBase):
|
|
|
231
238
|
environment: dict[str, str] | None = None,
|
|
232
239
|
mirror_enabled: bool = True,
|
|
233
240
|
platform: str | None = None,
|
|
241
|
+
stream_output: bool = True,
|
|
234
242
|
) -> BuildResult:
|
|
235
243
|
"""Build all binaries defined in a Makefile or build script.
|
|
236
|
-
|
|
244
|
+
|
|
237
245
|
Args:
|
|
238
246
|
source_dir: Source code directory
|
|
239
247
|
output_dir: Output directory for all binaries
|
|
240
248
|
environment: Additional environment variables
|
|
241
249
|
mirror_enabled: Whether to use Go proxy mirror
|
|
242
250
|
platform: Target platform (e.g., "linux/amd64", "windows/amd64")
|
|
243
|
-
|
|
251
|
+
stream_output: Whether to stream output in real-time (default: True)
|
|
252
|
+
|
|
244
253
|
Returns:
|
|
245
254
|
BuildResult containing success status and output information.
|
|
246
255
|
"""
|
|
247
256
|
go_executable = self._get_executable_path()
|
|
248
|
-
|
|
257
|
+
|
|
249
258
|
source_dir = self._validate_directory(source_dir, create_if_not_exists=False)
|
|
250
259
|
output_dir = self._validate_directory(output_dir, create_if_not_exists=True)
|
|
251
|
-
|
|
260
|
+
|
|
252
261
|
env = environment.copy() if environment else {}
|
|
253
|
-
|
|
262
|
+
|
|
254
263
|
if mirror_enabled:
|
|
255
264
|
mirror_key = self._mirror or "go"
|
|
256
265
|
env = apply_mirror_environment(mirror_key, env)
|
|
257
|
-
|
|
266
|
+
|
|
258
267
|
build_args = [go_executable, "build", "-o", str(output_dir), "./..."]
|
|
259
|
-
|
|
268
|
+
|
|
260
269
|
if platform:
|
|
261
270
|
env["GOOS"], env["GOARCH"] = platform.split("/")
|
|
262
|
-
|
|
271
|
+
|
|
263
272
|
return self._run_build(
|
|
264
273
|
build_args,
|
|
265
274
|
source_dir,
|
|
266
275
|
output_dir,
|
|
267
276
|
environment=env,
|
|
277
|
+
stream_output=stream_output,
|
|
268
278
|
)
|
|
269
|
-
|
|
279
|
+
|
|
270
280
|
def run_tests(
|
|
271
281
|
self,
|
|
272
282
|
source_dir: Path,
|
|
@@ -275,16 +285,18 @@ class GoCompiler(CompilerBase):
|
|
|
275
285
|
mirror_enabled: bool = True,
|
|
276
286
|
verbose: bool = True,
|
|
277
287
|
race: bool = False,
|
|
288
|
+
stream_output: bool = True,
|
|
278
289
|
) -> BuildResult:
|
|
279
290
|
"""Run Go tests.
|
|
280
|
-
|
|
291
|
+
|
|
281
292
|
Args:
|
|
282
293
|
source_dir: Source code directory
|
|
283
294
|
environment: Additional environment variables
|
|
284
295
|
mirror_enabled: Whether to use Go proxy mirror
|
|
285
296
|
verbose: Enable verbose test output
|
|
286
297
|
race: Enable race detector
|
|
287
|
-
|
|
298
|
+
stream_output: Whether to stream output in real-time (default: True)
|
|
299
|
+
|
|
288
300
|
Returns:
|
|
289
301
|
BuildResult containing success status and output information.
|
|
290
302
|
"""
|
|
@@ -299,52 +311,56 @@ class GoCompiler(CompilerBase):
|
|
|
299
311
|
env = apply_mirror_environment(mirror_key, env)
|
|
300
312
|
|
|
301
313
|
test_args = [go_executable, "test"]
|
|
302
|
-
|
|
314
|
+
|
|
303
315
|
if verbose:
|
|
304
316
|
test_args.append("-v")
|
|
305
|
-
|
|
317
|
+
|
|
306
318
|
if race:
|
|
307
319
|
test_args.append("-race")
|
|
308
|
-
|
|
320
|
+
|
|
309
321
|
return self._run_build(
|
|
310
322
|
test_args,
|
|
311
323
|
source_dir,
|
|
312
324
|
source_dir,
|
|
313
325
|
environment=env,
|
|
326
|
+
stream_output=stream_output,
|
|
314
327
|
)
|
|
315
|
-
|
|
328
|
+
|
|
316
329
|
def tidy_modules(
|
|
317
330
|
self,
|
|
318
331
|
source_dir: Path,
|
|
319
332
|
*,
|
|
320
333
|
environment: dict[str, str] | None = None,
|
|
321
334
|
mirror_enabled: bool = True,
|
|
335
|
+
stream_output: bool = True,
|
|
322
336
|
) -> BuildResult:
|
|
323
337
|
"""Run go mod tidy to clean up dependencies.
|
|
324
|
-
|
|
338
|
+
|
|
325
339
|
Args:
|
|
326
340
|
source_dir: Source code directory
|
|
327
341
|
environment: Additional environment variables
|
|
328
342
|
mirror_enabled: Whether to use Go proxy mirror
|
|
329
|
-
|
|
343
|
+
stream_output: Whether to stream output in real-time (default: True)
|
|
344
|
+
|
|
330
345
|
Returns:
|
|
331
346
|
BuildResult containing success status and output information.
|
|
332
347
|
"""
|
|
333
348
|
go_executable = self._get_executable_path()
|
|
334
|
-
|
|
349
|
+
|
|
335
350
|
source_dir = self._validate_directory(source_dir, create_if_not_exists=False)
|
|
336
|
-
|
|
351
|
+
|
|
337
352
|
env = environment.copy() if environment else {}
|
|
338
|
-
|
|
353
|
+
|
|
339
354
|
if mirror_enabled:
|
|
340
355
|
mirror_key = self._mirror or "go"
|
|
341
356
|
env = apply_mirror_environment(mirror_key, env)
|
|
342
|
-
|
|
357
|
+
|
|
343
358
|
return self._run_build(
|
|
344
359
|
[go_executable, "mod", "tidy"],
|
|
345
360
|
source_dir,
|
|
346
361
|
source_dir,
|
|
347
362
|
environment=env,
|
|
363
|
+
stream_output=stream_output,
|
|
348
364
|
)
|
|
349
365
|
|
|
350
366
|
def clean(self, directory: Path) -> bool:
|
|
@@ -108,48 +108,94 @@ class PnpmCompiler(CompilerBase):
|
|
|
108
108
|
command: list[str],
|
|
109
109
|
working_dir: Path,
|
|
110
110
|
environment: dict[str, str],
|
|
111
|
+
stream_output: bool = True,
|
|
111
112
|
) -> BuildResult:
|
|
112
113
|
"""Execute a command in the specified directory, returning to original cwd afterwards.
|
|
113
|
-
|
|
114
|
+
|
|
114
115
|
Args:
|
|
115
116
|
command: Command to execute
|
|
116
117
|
working_dir: Working directory for the command
|
|
117
118
|
environment: Environment variables
|
|
118
|
-
|
|
119
|
+
stream_output: Whether to stream output in real-time (default: True)
|
|
120
|
+
|
|
119
121
|
Returns:
|
|
120
122
|
BuildResult containing success status and output information
|
|
121
123
|
"""
|
|
122
124
|
import subprocess
|
|
123
|
-
|
|
125
|
+
import sys
|
|
126
|
+
|
|
124
127
|
original_cwd = Path.cwd()
|
|
125
128
|
full_command = command.copy()
|
|
126
|
-
|
|
129
|
+
|
|
127
130
|
start_time: float = 0.0
|
|
128
|
-
|
|
131
|
+
|
|
129
132
|
try:
|
|
130
133
|
os.chdir(working_dir)
|
|
131
|
-
|
|
134
|
+
|
|
132
135
|
start_time = time.perf_counter()
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
136
|
+
|
|
137
|
+
if stream_output:
|
|
138
|
+
stdout_buffer = []
|
|
139
|
+
stderr_buffer = []
|
|
140
|
+
|
|
141
|
+
process = subprocess.Popen(
|
|
142
|
+
full_command,
|
|
143
|
+
stdout=subprocess.PIPE,
|
|
144
|
+
stderr=subprocess.PIPE,
|
|
145
|
+
text=True,
|
|
146
|
+
env={**os.environ, **environment},
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
stdout_buffer = []
|
|
150
|
+
stderr_buffer = []
|
|
151
|
+
|
|
152
|
+
# Read stdout in real-time
|
|
153
|
+
if process.stdout:
|
|
154
|
+
for line in process.stdout:
|
|
155
|
+
line = line.rstrip('\n\r')
|
|
156
|
+
stdout_buffer.append(line)
|
|
157
|
+
print(line)
|
|
158
|
+
sys.stdout.flush()
|
|
159
|
+
|
|
160
|
+
# Read stderr in real-time
|
|
161
|
+
if process.stderr:
|
|
162
|
+
for line in process.stderr:
|
|
163
|
+
line = line.rstrip('\n\r')
|
|
164
|
+
stderr_buffer.append(line)
|
|
165
|
+
print(line, file=sys.stderr)
|
|
166
|
+
sys.stderr.flush()
|
|
167
|
+
|
|
168
|
+
return_code = process.wait()
|
|
169
|
+
duration = time.perf_counter() - start_time
|
|
170
|
+
|
|
171
|
+
return BuildResult(
|
|
172
|
+
success=return_code == 0,
|
|
173
|
+
return_code=return_code,
|
|
174
|
+
stdout='\n'.join(stdout_buffer),
|
|
175
|
+
stderr='\n'.join(stderr_buffer),
|
|
176
|
+
output_path=working_dir,
|
|
177
|
+
duration_seconds=duration,
|
|
178
|
+
)
|
|
179
|
+
else:
|
|
180
|
+
result = subprocess.run(
|
|
181
|
+
full_command,
|
|
182
|
+
capture_output=True,
|
|
183
|
+
text=True,
|
|
184
|
+
timeout=3600,
|
|
185
|
+
env={**os.environ, **environment},
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
duration = time.perf_counter() - start_time
|
|
189
|
+
|
|
190
|
+
return BuildResult(
|
|
191
|
+
success=result.returncode == 0,
|
|
192
|
+
return_code=result.returncode,
|
|
193
|
+
stdout=result.stdout,
|
|
194
|
+
stderr=result.stderr,
|
|
195
|
+
output_path=working_dir,
|
|
196
|
+
duration_seconds=duration,
|
|
197
|
+
)
|
|
198
|
+
|
|
153
199
|
except subprocess.TimeoutExpired:
|
|
154
200
|
duration = time.perf_counter() - start_time
|
|
155
201
|
return BuildResult(
|
|
@@ -171,7 +217,6 @@ class PnpmCompiler(CompilerBase):
|
|
|
171
217
|
duration_seconds=duration,
|
|
172
218
|
)
|
|
173
219
|
finally:
|
|
174
|
-
# Always return to original working directory
|
|
175
220
|
os.chdir(original_cwd)
|
|
176
221
|
|
|
177
222
|
def build(
|
|
@@ -182,16 +227,18 @@ class PnpmCompiler(CompilerBase):
|
|
|
182
227
|
environment: dict[str, str] | None = None,
|
|
183
228
|
mirror_enabled: bool = True,
|
|
184
229
|
extra_args: list[str] | None = None,
|
|
230
|
+
stream_output: bool = True,
|
|
185
231
|
) -> BuildResult:
|
|
186
232
|
"""Execute the pnpm build process with auto-detection of project root.
|
|
187
|
-
|
|
233
|
+
|
|
188
234
|
Args:
|
|
189
235
|
source_dir: Source code directory or subdirectory
|
|
190
236
|
output_dir: Build output directory
|
|
191
237
|
environment: Additional environment variables
|
|
192
238
|
mirror_enabled: Whether to use mirror acceleration
|
|
193
239
|
extra_args: Additional arguments to pass to pnpm build
|
|
194
|
-
|
|
240
|
+
stream_output: Whether to stream output in real-time (default: True)
|
|
241
|
+
|
|
195
242
|
Returns:
|
|
196
243
|
BuildResult containing success status and output information.
|
|
197
244
|
"""
|
|
@@ -225,20 +272,22 @@ class PnpmCompiler(CompilerBase):
|
|
|
225
272
|
[pnpm_executable, "install"],
|
|
226
273
|
project_root,
|
|
227
274
|
env,
|
|
275
|
+
stream_output=stream_output,
|
|
228
276
|
)
|
|
229
|
-
|
|
277
|
+
|
|
230
278
|
if not install_result["success"]:
|
|
231
279
|
return install_result
|
|
232
|
-
|
|
280
|
+
|
|
233
281
|
# Run build
|
|
234
282
|
build_args = [pnpm_executable, "build"]
|
|
235
283
|
if extra_args:
|
|
236
284
|
build_args.extend(extra_args)
|
|
237
|
-
|
|
285
|
+
|
|
238
286
|
return self._execute_in_directory(
|
|
239
287
|
build_args,
|
|
240
288
|
project_root,
|
|
241
289
|
env,
|
|
290
|
+
stream_output=stream_output,
|
|
242
291
|
)
|
|
243
292
|
|
|
244
293
|
def install_dependencies(
|
|
@@ -282,11 +331,12 @@ class PnpmCompiler(CompilerBase):
|
|
|
282
331
|
command = [pnpm_executable, "install"]
|
|
283
332
|
if production:
|
|
284
333
|
command.append("--prod")
|
|
285
|
-
|
|
334
|
+
|
|
286
335
|
return self._execute_in_directory(
|
|
287
336
|
command,
|
|
288
337
|
project_root,
|
|
289
338
|
env,
|
|
339
|
+
stream_output=True,
|
|
290
340
|
)
|
|
291
341
|
|
|
292
342
|
def run_script(
|
|
@@ -106,16 +106,18 @@ class PythonCompiler(CompilerBase):
|
|
|
106
106
|
environment: dict[str, str] | None = None,
|
|
107
107
|
mirror_enabled: bool = True,
|
|
108
108
|
extra_args: list[str] | None = None,
|
|
109
|
+
stream_output: bool = True,
|
|
109
110
|
) -> BuildResult:
|
|
110
111
|
"""Execute the Python build process.
|
|
111
|
-
|
|
112
|
+
|
|
112
113
|
Args:
|
|
113
114
|
source_dir: Source code directory
|
|
114
115
|
output_dir: Build output directory
|
|
115
116
|
environment: Additional environment variables
|
|
116
117
|
mirror_enabled: Whether to use PyPI mirror
|
|
117
118
|
extra_args: Additional arguments to pass to build command
|
|
118
|
-
|
|
119
|
+
stream_output: Whether to stream output in real-time (default: True)
|
|
120
|
+
|
|
119
121
|
Returns:
|
|
120
122
|
BuildResult containing success status and output information.
|
|
121
123
|
"""
|
|
@@ -134,18 +136,18 @@ class PythonCompiler(CompilerBase):
|
|
|
134
136
|
|
|
135
137
|
# Determine build system
|
|
136
138
|
build_system = self._detect_build_system(source_dir)
|
|
137
|
-
|
|
139
|
+
|
|
138
140
|
if build_system == "poetry":
|
|
139
141
|
return self._build_with_poetry(
|
|
140
|
-
python_executable, source_dir, output_dir, env, extra_args
|
|
142
|
+
python_executable, source_dir, output_dir, env, extra_args, stream_output
|
|
141
143
|
)
|
|
142
144
|
elif build_system == "setuptools":
|
|
143
145
|
return self._build_with_setuptools(
|
|
144
|
-
python_executable, source_dir, output_dir, env, extra_args
|
|
146
|
+
python_executable, source_dir, output_dir, env, extra_args, stream_output
|
|
145
147
|
)
|
|
146
148
|
elif build_system == "pdm":
|
|
147
149
|
return self._build_with_pdm(
|
|
148
|
-
python_executable, source_dir, output_dir, env, extra_args
|
|
150
|
+
python_executable, source_dir, output_dir, env, extra_args, stream_output
|
|
149
151
|
)
|
|
150
152
|
else:
|
|
151
153
|
return BuildResult(
|
|
@@ -200,34 +202,37 @@ class PythonCompiler(CompilerBase):
|
|
|
200
202
|
output_dir: Path,
|
|
201
203
|
env: dict[str, str],
|
|
202
204
|
extra_args: list[str] | None = None,
|
|
205
|
+
stream_output: bool = True,
|
|
203
206
|
) -> BuildResult:
|
|
204
207
|
"""Build using Poetry."""
|
|
205
208
|
# Install dependencies
|
|
206
209
|
install_cmd = [python_executable, "-m", "poetry", "install"]
|
|
207
|
-
|
|
210
|
+
|
|
208
211
|
install_result = self._run_build(
|
|
209
212
|
install_cmd,
|
|
210
213
|
source_dir,
|
|
211
214
|
output_dir,
|
|
212
215
|
environment=env,
|
|
216
|
+
stream_output=stream_output,
|
|
213
217
|
)
|
|
214
|
-
|
|
218
|
+
|
|
215
219
|
if not install_result["success"]:
|
|
216
220
|
return install_result
|
|
217
|
-
|
|
221
|
+
|
|
218
222
|
# Build package
|
|
219
223
|
build_cmd = [python_executable, "-m", "poetry", "build"]
|
|
220
|
-
|
|
224
|
+
|
|
221
225
|
if extra_args:
|
|
222
226
|
build_cmd.extend(extra_args)
|
|
223
|
-
|
|
227
|
+
|
|
224
228
|
return self._run_build(
|
|
225
229
|
build_cmd,
|
|
226
230
|
source_dir,
|
|
227
231
|
output_dir,
|
|
228
232
|
environment=env,
|
|
233
|
+
stream_output=stream_output,
|
|
229
234
|
)
|
|
230
|
-
|
|
235
|
+
|
|
231
236
|
def _build_with_setuptools(
|
|
232
237
|
self,
|
|
233
238
|
python_executable: str,
|
|
@@ -235,6 +240,7 @@ class PythonCompiler(CompilerBase):
|
|
|
235
240
|
output_dir: Path,
|
|
236
241
|
env: dict[str, str],
|
|
237
242
|
extra_args: list[str] | None = None,
|
|
243
|
+
stream_output: bool = True,
|
|
238
244
|
) -> BuildResult:
|
|
239
245
|
"""Build using setuptools."""
|
|
240
246
|
# Install build dependencies first
|
|
@@ -253,8 +259,9 @@ class PythonCompiler(CompilerBase):
|
|
|
253
259
|
source_dir,
|
|
254
260
|
output_dir,
|
|
255
261
|
environment=env,
|
|
262
|
+
stream_output=stream_output,
|
|
256
263
|
)
|
|
257
|
-
|
|
264
|
+
|
|
258
265
|
def _build_with_pdm(
|
|
259
266
|
self,
|
|
260
267
|
python_executable: str,
|
|
@@ -262,19 +269,21 @@ class PythonCompiler(CompilerBase):
|
|
|
262
269
|
output_dir: Path,
|
|
263
270
|
env: dict[str, str],
|
|
264
271
|
extra_args: list[str] | None = None,
|
|
272
|
+
stream_output: bool = True,
|
|
265
273
|
) -> BuildResult:
|
|
266
274
|
"""Build using PDM."""
|
|
267
275
|
# Build with PDM
|
|
268
276
|
build_cmd = [python_executable, "-m", "pdm", "build"]
|
|
269
|
-
|
|
277
|
+
|
|
270
278
|
if extra_args:
|
|
271
279
|
build_cmd.extend(extra_args)
|
|
272
|
-
|
|
280
|
+
|
|
273
281
|
return self._run_build(
|
|
274
282
|
build_cmd,
|
|
275
283
|
source_dir,
|
|
276
284
|
output_dir,
|
|
277
285
|
environment=env,
|
|
286
|
+
stream_output=stream_output,
|
|
278
287
|
)
|
|
279
288
|
|
|
280
289
|
def install_dependencies(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|