multi-lang-build 0.2.8__py3-none-any.whl → 0.2.10__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.
- multi_lang_build/__init__.py +4 -4
- multi_lang_build/cli.py +3 -2
- multi_lang_build/compiler/__init__.py +1 -1
- multi_lang_build/compiler/go_compiler.py +388 -0
- multi_lang_build/compiler/go_support/__init__.py +19 -0
- multi_lang_build/compiler/go_support/binary.py +117 -0
- multi_lang_build/compiler/go_support/builder.py +228 -0
- multi_lang_build/compiler/go_support/cleaner.py +40 -0
- multi_lang_build/compiler/go_support/env.py +41 -0
- multi_lang_build/compiler/go_support/mirror.py +111 -0
- multi_lang_build/compiler/go_support/module.py +77 -0
- multi_lang_build/compiler/go_support/tester.py +199 -0
- multi_lang_build/compiler/pnpm.py +61 -209
- multi_lang_build/compiler/pnpm_support/__init__.py +6 -0
- multi_lang_build/compiler/pnpm_support/executor.py +148 -0
- multi_lang_build/compiler/pnpm_support/project.py +53 -0
- multi_lang_build/compiler/python.py +65 -222
- multi_lang_build/compiler/python_support/__init__.py +13 -0
- multi_lang_build/compiler/python_support/cleaner.py +56 -0
- multi_lang_build/compiler/python_support/cli.py +46 -0
- multi_lang_build/compiler/python_support/detector.py +64 -0
- multi_lang_build/compiler/python_support/installer.py +162 -0
- multi_lang_build/compiler/python_support/venv.py +63 -0
- multi_lang_build/ide_register.py +97 -0
- multi_lang_build/mirror/config.py +19 -0
- multi_lang_build/register/support/__init__.py +13 -0
- multi_lang_build/register/support/claude.py +94 -0
- multi_lang_build/register/support/codebuddy.py +100 -0
- multi_lang_build/register/support/opencode.py +62 -0
- multi_lang_build/register/support/trae.py +72 -0
- {multi_lang_build-0.2.8.dist-info → multi_lang_build-0.2.10.dist-info}/METADATA +1 -1
- multi_lang_build-0.2.10.dist-info/RECORD +40 -0
- multi_lang_build/compiler/go.py +0 -564
- multi_lang_build/register.py +0 -412
- multi_lang_build-0.2.8.dist-info/RECORD +0 -18
- {multi_lang_build-0.2.8.dist-info → multi_lang_build-0.2.10.dist-info}/WHEEL +0 -0
- {multi_lang_build-0.2.8.dist-info → multi_lang_build-0.2.10.dist-info}/entry_points.txt +0 -0
- {multi_lang_build-0.2.8.dist-info → multi_lang_build-0.2.10.dist-info}/licenses/LICENSE +0 -0
multi_lang_build/__init__.py
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
from multi_lang_build.compiler.base import BuildConfig, BuildResult, CompilerBase
|
|
4
4
|
from multi_lang_build.compiler.pnpm import PnpmCompiler
|
|
5
|
-
from multi_lang_build.compiler.
|
|
5
|
+
from multi_lang_build.compiler.go_compiler import GoCompiler
|
|
6
6
|
from multi_lang_build.compiler.python import PythonCompiler
|
|
7
7
|
from multi_lang_build.mirror.config import MirrorConfig, get_mirror_config
|
|
8
|
-
from multi_lang_build.
|
|
8
|
+
from multi_lang_build.ide_register import register_skill
|
|
9
9
|
|
|
10
|
-
__version__ = "0.2.
|
|
10
|
+
__version__ = "0.2.10"
|
|
11
11
|
__all__ = [
|
|
12
12
|
"BuildConfig",
|
|
13
13
|
"BuildResult",
|
|
@@ -33,7 +33,7 @@ def main_register() -> None:
|
|
|
33
33
|
"""Entry point for the register CLI tool."""
|
|
34
34
|
import sys
|
|
35
35
|
import argparse
|
|
36
|
-
from multi_lang_build.
|
|
36
|
+
from multi_lang_build.ide_register import register_skill
|
|
37
37
|
|
|
38
38
|
parser = argparse.ArgumentParser(
|
|
39
39
|
description="Register multi-lang-build as an IDE skill",
|
multi_lang_build/cli.py
CHANGED
|
@@ -70,7 +70,8 @@ Supported languages:
|
|
|
70
70
|
)
|
|
71
71
|
go_parser.add_argument("source_dir", type=Path, help="Source directory")
|
|
72
72
|
go_parser.add_argument("-o", "--output", type=Path, required=True, help="Output file or directory")
|
|
73
|
-
go_parser.add_argument("--mirror
|
|
73
|
+
go_parser.add_argument("--mirror", dest="mirror", action="store_true", default=True, help="Enable/disable Go proxy mirror")
|
|
74
|
+
go_parser.add_argument("--no-mirror", dest="mirror", action="store_false", help="Enable/disable Go proxy mirror")
|
|
74
75
|
go_parser.add_argument("--ldflags", type=str, help="Linker flags")
|
|
75
76
|
go_parser.add_argument("--tags", type=str, help="Build tags (comma-separated)")
|
|
76
77
|
go_parser.add_argument("--test", action="store_true", help="Run tests instead of building")
|
|
@@ -201,7 +202,7 @@ Examples:
|
|
|
201
202
|
)
|
|
202
203
|
|
|
203
204
|
elif parsed_args.language == "go":
|
|
204
|
-
from multi_lang_build.compiler.
|
|
205
|
+
from multi_lang_build.compiler.go_compiler import GoCompiler
|
|
205
206
|
|
|
206
207
|
compiler = GoCompiler()
|
|
207
208
|
|
|
@@ -8,7 +8,7 @@ from multi_lang_build.compiler.base import (
|
|
|
8
8
|
)
|
|
9
9
|
|
|
10
10
|
from multi_lang_build.compiler.pnpm import PnpmCompiler
|
|
11
|
-
from multi_lang_build.compiler.
|
|
11
|
+
from multi_lang_build.compiler.go_compiler import GoCompiler
|
|
12
12
|
from multi_lang_build.compiler.python import PythonCompiler
|
|
13
13
|
|
|
14
14
|
__all__ = [
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
"""Go compiler with mirror acceleration support and failover."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Final
|
|
5
|
+
import shutil
|
|
6
|
+
import subprocess
|
|
7
|
+
|
|
8
|
+
from loguru import logger
|
|
9
|
+
|
|
10
|
+
from multi_lang_build.compiler.base import CompilerBase, BuildResult, CompilerInfo
|
|
11
|
+
from multi_lang_build.mirror.config import (
|
|
12
|
+
apply_mirror_environment,
|
|
13
|
+
DEFAULT_GO_MIRROR,
|
|
14
|
+
)
|
|
15
|
+
from multi_lang_build.compiler.go_support import (
|
|
16
|
+
GoMirrorFailover,
|
|
17
|
+
GoBinaryBuilder,
|
|
18
|
+
GoModuleBuilder,
|
|
19
|
+
GoTester,
|
|
20
|
+
GoEnvironment,
|
|
21
|
+
GoCleaner,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class GoCompiler(CompilerBase):
|
|
26
|
+
"""Compiler for Go projects with module support and mirror failover."""
|
|
27
|
+
|
|
28
|
+
NAME: Final[str] = "go"
|
|
29
|
+
DEFAULT_MIRROR: Final[str] = DEFAULT_GO_MIRROR
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
go_path: str | None = None,
|
|
34
|
+
mirror: str | None = None,
|
|
35
|
+
):
|
|
36
|
+
"""Initialize Go compiler.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
go_path: Optional path to Go executable
|
|
40
|
+
mirror: Mirror configuration name (e.g., "go", "go_qiniu", "go_vip")
|
|
41
|
+
"""
|
|
42
|
+
self._go_path = go_path
|
|
43
|
+
self._mirror = mirror
|
|
44
|
+
self._version_cache: str | None = None
|
|
45
|
+
self._mirror_failover = GoMirrorFailover(mirror)
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def name(self) -> str:
|
|
49
|
+
"""Get the compiler name."""
|
|
50
|
+
return self.NAME
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def version(self) -> str:
|
|
54
|
+
"""Get the Go version."""
|
|
55
|
+
if self._version_cache:
|
|
56
|
+
return self._version_cache
|
|
57
|
+
|
|
58
|
+
go_executable = self._get_executable_path()
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
result = subprocess.run(
|
|
62
|
+
[go_executable, "version"],
|
|
63
|
+
capture_output=True,
|
|
64
|
+
text=True,
|
|
65
|
+
timeout=10,
|
|
66
|
+
)
|
|
67
|
+
version_output = result.stdout.strip()
|
|
68
|
+
if "version go" in version_output:
|
|
69
|
+
self._version_cache = version_output.split("version go")[1].split()[0]
|
|
70
|
+
else:
|
|
71
|
+
self._version_cache = "unknown"
|
|
72
|
+
except Exception:
|
|
73
|
+
self._version_cache = "unknown"
|
|
74
|
+
|
|
75
|
+
return self._version_cache
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def supported_mirrors(self) -> list[str]:
|
|
79
|
+
"""Get list of supported mirror configurations."""
|
|
80
|
+
return ["go", "go_qiniu", "go_vip"]
|
|
81
|
+
|
|
82
|
+
def get_info(self) -> CompilerInfo:
|
|
83
|
+
"""Get compiler information."""
|
|
84
|
+
return {
|
|
85
|
+
"name": self.name,
|
|
86
|
+
"version": self.version,
|
|
87
|
+
"supported_mirrors": self.supported_mirrors,
|
|
88
|
+
"default_mirror": self.DEFAULT_MIRROR,
|
|
89
|
+
"executable": self._get_executable_path(),
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
def _get_executable_path(self) -> str:
|
|
93
|
+
"""Get the path to the Go executable."""
|
|
94
|
+
if self._go_path:
|
|
95
|
+
return shutil.which(self._go_path) or self._go_path
|
|
96
|
+
|
|
97
|
+
go_executable = shutil.which("go")
|
|
98
|
+
if not go_executable:
|
|
99
|
+
raise RuntimeError("Go executable not found in PATH")
|
|
100
|
+
|
|
101
|
+
return go_executable
|
|
102
|
+
|
|
103
|
+
def _prepare_environment(self, environment: dict[str, str] | None = None) -> dict[str, str]:
|
|
104
|
+
"""Prepare environment with GOMODCACHE and GOCACHE set."""
|
|
105
|
+
return GoEnvironment.prepare(environment)
|
|
106
|
+
|
|
107
|
+
def _execute_with_mirror_failover(
|
|
108
|
+
self,
|
|
109
|
+
command: list[str],
|
|
110
|
+
source_dir: Path,
|
|
111
|
+
output_dir: Path,
|
|
112
|
+
environment: dict[str, str],
|
|
113
|
+
stream_output: bool,
|
|
114
|
+
) -> BuildResult:
|
|
115
|
+
"""Execute build command with mirror failover."""
|
|
116
|
+
def run_build(cmd, src, out, env, stream):
|
|
117
|
+
return self._run_build(cmd, src, out, environment=env, stream_output=stream)
|
|
118
|
+
|
|
119
|
+
return self._mirror_failover.try_build_with_fallback(
|
|
120
|
+
command, source_dir, output_dir, environment, stream_output, run_build
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
def build(
|
|
124
|
+
self,
|
|
125
|
+
source_dir: Path,
|
|
126
|
+
output_dir: Path,
|
|
127
|
+
*,
|
|
128
|
+
environment: dict[str, str] | None = None,
|
|
129
|
+
mirror_enabled: bool = True,
|
|
130
|
+
extra_args: list[str] | None = None,
|
|
131
|
+
stream_output: bool = True,
|
|
132
|
+
) -> BuildResult:
|
|
133
|
+
"""Execute the Go build process.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
source_dir: Source code directory
|
|
137
|
+
output_dir: Build output directory
|
|
138
|
+
environment: Additional environment variables
|
|
139
|
+
mirror_enabled: Whether to use Go proxy mirror
|
|
140
|
+
extra_args: Additional arguments to pass to go build
|
|
141
|
+
stream_output: Whether to stream output in real-time (default: True)
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
BuildResult containing success status and output information.
|
|
145
|
+
"""
|
|
146
|
+
go_executable = self._get_executable_path()
|
|
147
|
+
|
|
148
|
+
source_dir = self._validate_directory(source_dir, create_if_not_exists=False)
|
|
149
|
+
output_dir = self._validate_directory(output_dir, create_if_not_exists=True)
|
|
150
|
+
|
|
151
|
+
cwd = Path.cwd().resolve()
|
|
152
|
+
logger.info(f"当前工作目录: {cwd}")
|
|
153
|
+
|
|
154
|
+
env = self._prepare_environment(environment)
|
|
155
|
+
|
|
156
|
+
# Download dependencies if go.mod exists
|
|
157
|
+
go_mod = source_dir / "go.mod"
|
|
158
|
+
if go_mod.exists():
|
|
159
|
+
logger.info("⬇️ 下载Go依赖...")
|
|
160
|
+
deps_result = self._execute_with_mirror_failover(
|
|
161
|
+
[go_executable, "mod", "download"],
|
|
162
|
+
source_dir, output_dir, env, stream_output,
|
|
163
|
+
)
|
|
164
|
+
logger.info("✅ 依赖下载完成")
|
|
165
|
+
|
|
166
|
+
if not deps_result["success"]:
|
|
167
|
+
return deps_result
|
|
168
|
+
|
|
169
|
+
# Build the project
|
|
170
|
+
logger.info("🔨 开始构建...")
|
|
171
|
+
build_args = [go_executable, "build", "-o", str(output_dir)]
|
|
172
|
+
|
|
173
|
+
if extra_args:
|
|
174
|
+
build_args.extend(extra_args)
|
|
175
|
+
|
|
176
|
+
if mirror_enabled and self._mirror is None:
|
|
177
|
+
build_result = self._execute_with_mirror_failover(
|
|
178
|
+
build_args, source_dir, output_dir, env, stream_output
|
|
179
|
+
)
|
|
180
|
+
else:
|
|
181
|
+
if mirror_enabled:
|
|
182
|
+
env = apply_mirror_environment(self._mirror or "go", env)
|
|
183
|
+
build_result = self._run_build(
|
|
184
|
+
build_args, source_dir, output_dir, environment=env, stream_output=stream_output
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
if build_result["success"]:
|
|
188
|
+
logger.info("✅ 构建成功")
|
|
189
|
+
|
|
190
|
+
return build_result
|
|
191
|
+
|
|
192
|
+
def build_binary(
|
|
193
|
+
self,
|
|
194
|
+
source_dir: Path,
|
|
195
|
+
output_path: Path,
|
|
196
|
+
*,
|
|
197
|
+
target: str | Path | None = None,
|
|
198
|
+
environment: dict[str, str] | None = None,
|
|
199
|
+
mirror_enabled: bool = True,
|
|
200
|
+
ldflags: str | None = None,
|
|
201
|
+
tags: list[str] | None = None,
|
|
202
|
+
stream_output: bool = True,
|
|
203
|
+
) -> BuildResult:
|
|
204
|
+
"""Build a specific Go binary.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
source_dir: Source code directory
|
|
208
|
+
output_path: Output path for the binary
|
|
209
|
+
target: Build target file or directory
|
|
210
|
+
environment: Additional environment variables
|
|
211
|
+
mirror_enabled: Whether to use Go proxy mirror
|
|
212
|
+
ldflags: Linker flags
|
|
213
|
+
tags: Build tags
|
|
214
|
+
stream_output: Whether to stream output in real-time
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
BuildResult containing success status and output information.
|
|
218
|
+
"""
|
|
219
|
+
go_executable = self._get_executable_path()
|
|
220
|
+
|
|
221
|
+
source_dir = self._validate_directory(source_dir, create_if_not_exists=False)
|
|
222
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
223
|
+
|
|
224
|
+
cwd = Path.cwd().resolve()
|
|
225
|
+
logger.info(f"当前工作目录: {cwd}")
|
|
226
|
+
|
|
227
|
+
env = self._prepare_environment(environment)
|
|
228
|
+
|
|
229
|
+
def run_build(cmd, src, out, env_copy):
|
|
230
|
+
return self._run_build(cmd, src, out, environment=env_copy, stream_output=stream_output)
|
|
231
|
+
|
|
232
|
+
if mirror_enabled and self._mirror is None:
|
|
233
|
+
return GoBinaryBuilder.build_with_failover(
|
|
234
|
+
go_executable, source_dir, output_path, env,
|
|
235
|
+
ldflags, tags, target, run_build, stream_output
|
|
236
|
+
)
|
|
237
|
+
else:
|
|
238
|
+
if mirror_enabled:
|
|
239
|
+
env = apply_mirror_environment(self._mirror or "go", env)
|
|
240
|
+
return GoBinaryBuilder.build_single(
|
|
241
|
+
go_executable, source_dir, output_path, env,
|
|
242
|
+
ldflags, tags, target, run_build, stream_output
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
def build_all(
|
|
246
|
+
self,
|
|
247
|
+
source_dir: Path,
|
|
248
|
+
output_dir: Path,
|
|
249
|
+
*,
|
|
250
|
+
environment: dict[str, str] | None = None,
|
|
251
|
+
mirror_enabled: bool = True,
|
|
252
|
+
platform: str | None = None,
|
|
253
|
+
stream_output: bool = True,
|
|
254
|
+
) -> BuildResult:
|
|
255
|
+
"""Build all binaries in the project.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
source_dir: Source code directory
|
|
259
|
+
output_dir: Output directory for all binaries
|
|
260
|
+
environment: Additional environment variables
|
|
261
|
+
mirror_enabled: Whether to use Go proxy mirror
|
|
262
|
+
platform: Target platform (e.g., "linux/amd64")
|
|
263
|
+
stream_output: Whether to stream output in real-time
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
BuildResult containing success status and output information.
|
|
267
|
+
"""
|
|
268
|
+
go_executable = self._get_executable_path()
|
|
269
|
+
|
|
270
|
+
source_dir = self._validate_directory(source_dir, create_if_not_exists=False)
|
|
271
|
+
output_dir = self._validate_directory(output_dir, create_if_not_exists=True)
|
|
272
|
+
|
|
273
|
+
cwd = Path.cwd().resolve()
|
|
274
|
+
logger.info(f"当前工作目录: {cwd}")
|
|
275
|
+
|
|
276
|
+
env = self._prepare_environment(environment)
|
|
277
|
+
|
|
278
|
+
def run_build(cmd, src, out, env_copy):
|
|
279
|
+
return self._run_build(cmd, src, out, environment=env_copy, stream_output=stream_output)
|
|
280
|
+
|
|
281
|
+
if mirror_enabled and self._mirror is None:
|
|
282
|
+
build_result = self._execute_with_mirror_failover(
|
|
283
|
+
[go_executable, "build", "-o", str(output_dir), "./..."],
|
|
284
|
+
source_dir, output_dir, env, stream_output
|
|
285
|
+
)
|
|
286
|
+
else:
|
|
287
|
+
if mirror_enabled:
|
|
288
|
+
env = apply_mirror_environment(self._mirror or "go", env)
|
|
289
|
+
build_result = GoModuleBuilder.build_all(
|
|
290
|
+
go_executable, source_dir, output_dir, env, platform, run_build, stream_output
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
return build_result
|
|
294
|
+
|
|
295
|
+
def run_tests(
|
|
296
|
+
self,
|
|
297
|
+
source_dir: Path,
|
|
298
|
+
*,
|
|
299
|
+
environment: dict[str, str] | None = None,
|
|
300
|
+
mirror_enabled: bool = True,
|
|
301
|
+
verbose: bool = True,
|
|
302
|
+
race: bool = False,
|
|
303
|
+
stream_output: bool = True,
|
|
304
|
+
) -> BuildResult:
|
|
305
|
+
"""Run Go tests.
|
|
306
|
+
|
|
307
|
+
Args:
|
|
308
|
+
source_dir: Source code directory
|
|
309
|
+
environment: Additional environment variables
|
|
310
|
+
mirror_enabled: Whether to use Go proxy mirror
|
|
311
|
+
verbose: Enable verbose test output
|
|
312
|
+
race: Enable race detector
|
|
313
|
+
stream_output: Whether to stream output in real-time
|
|
314
|
+
|
|
315
|
+
Returns:
|
|
316
|
+
BuildResult containing success status and output information.
|
|
317
|
+
"""
|
|
318
|
+
go_executable = self._get_executable_path()
|
|
319
|
+
|
|
320
|
+
source_dir = self._validate_directory(source_dir, create_if_not_exists=False)
|
|
321
|
+
|
|
322
|
+
cwd = Path.cwd().resolve()
|
|
323
|
+
logger.info(f"当前工作目录: {cwd}")
|
|
324
|
+
|
|
325
|
+
env = self._prepare_environment(environment)
|
|
326
|
+
|
|
327
|
+
if mirror_enabled:
|
|
328
|
+
env = apply_mirror_environment(self._mirror or "go", env)
|
|
329
|
+
|
|
330
|
+
def run_test(cmd, src, out, env_copy):
|
|
331
|
+
return self._run_build(cmd, src, out, environment=env_copy, stream_output=stream_output)
|
|
332
|
+
|
|
333
|
+
return GoTester.run(
|
|
334
|
+
go_executable, source_dir, env, verbose, race, stream_output, run_test
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
def tidy_modules(
|
|
338
|
+
self,
|
|
339
|
+
source_dir: Path,
|
|
340
|
+
*,
|
|
341
|
+
environment: dict[str, str] | None = None,
|
|
342
|
+
mirror_enabled: bool = True,
|
|
343
|
+
stream_output: bool = True,
|
|
344
|
+
) -> BuildResult:
|
|
345
|
+
"""Run go mod tidy to clean up dependencies.
|
|
346
|
+
|
|
347
|
+
Args:
|
|
348
|
+
source_dir: Source code directory
|
|
349
|
+
environment: Additional environment variables
|
|
350
|
+
mirror_enabled: Whether to use Go proxy mirror
|
|
351
|
+
stream_output: Whether to stream output in real-time
|
|
352
|
+
|
|
353
|
+
Returns:
|
|
354
|
+
BuildResult containing success status and output information.
|
|
355
|
+
"""
|
|
356
|
+
go_executable = self._get_executable_path()
|
|
357
|
+
|
|
358
|
+
source_dir = self._validate_directory(source_dir, create_if_not_exists=False)
|
|
359
|
+
|
|
360
|
+
cwd = Path.cwd().resolve()
|
|
361
|
+
logger.info(f"当前工作目录: {cwd}")
|
|
362
|
+
|
|
363
|
+
env = self._prepare_environment(environment)
|
|
364
|
+
|
|
365
|
+
def run_build(cmd, src, out, env_copy):
|
|
366
|
+
return self._run_build(cmd, src, out, environment=env_copy, stream_output=stream_output)
|
|
367
|
+
|
|
368
|
+
if mirror_enabled and self._mirror is None:
|
|
369
|
+
return self._execute_with_mirror_failover(
|
|
370
|
+
[go_executable, "mod", "tidy"],
|
|
371
|
+
source_dir, source_dir, env, stream_output
|
|
372
|
+
)
|
|
373
|
+
else:
|
|
374
|
+
if mirror_enabled:
|
|
375
|
+
env = apply_mirror_environment(self._mirror or "go", env)
|
|
376
|
+
return GoModuleBuilder.tidy(go_executable, source_dir, env, run_build, stream_output)
|
|
377
|
+
|
|
378
|
+
def clean(self, directory: Path) -> bool:
|
|
379
|
+
"""Clean Go build artifacts in the specified directory.
|
|
380
|
+
|
|
381
|
+
Args:
|
|
382
|
+
directory: Directory to clean
|
|
383
|
+
|
|
384
|
+
Returns:
|
|
385
|
+
True if successful, False otherwise.
|
|
386
|
+
"""
|
|
387
|
+
directory = self._validate_directory(directory, create_if_not_exists=False)
|
|
388
|
+
return GoCleaner.clean(directory)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Go compiler support modules."""
|
|
2
|
+
|
|
3
|
+
from multi_lang_build.compiler.go_support.mirror import GoMirrorFailover
|
|
4
|
+
from multi_lang_build.compiler.go_support.builder import GoBuilder
|
|
5
|
+
from multi_lang_build.compiler.go_support.binary import GoBinaryBuilder
|
|
6
|
+
from multi_lang_build.compiler.go_support.module import GoModuleBuilder
|
|
7
|
+
from multi_lang_build.compiler.go_support.tester import GoTester
|
|
8
|
+
from multi_lang_build.compiler.go_support.env import GoEnvironment
|
|
9
|
+
from multi_lang_build.compiler.go_support.cleaner import GoCleaner
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"GoMirrorFailover",
|
|
13
|
+
"GoBuilder",
|
|
14
|
+
"GoBinaryBuilder",
|
|
15
|
+
"GoModuleBuilder",
|
|
16
|
+
"GoTester",
|
|
17
|
+
"GoEnvironment",
|
|
18
|
+
"GoCleaner",
|
|
19
|
+
]
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""Go binary building with mirror failover support."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from loguru import logger
|
|
6
|
+
|
|
7
|
+
from multi_lang_build.compiler.base import BuildResult
|
|
8
|
+
from multi_lang_build.mirror.config import apply_mirror_environment, MIRROR_CONFIGS
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class GoBinaryBuilder:
|
|
12
|
+
"""Build Go binaries with optional mirror failover."""
|
|
13
|
+
|
|
14
|
+
MIRROR_KEYS = ["go_qiniu", "go", "go_vip"]
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def build_with_failover(
|
|
18
|
+
go_executable: str,
|
|
19
|
+
source_dir: Path,
|
|
20
|
+
output_path: Path,
|
|
21
|
+
env: dict[str, str],
|
|
22
|
+
ldflags: str | None,
|
|
23
|
+
tags: list[str] | None,
|
|
24
|
+
target: str | Path | None,
|
|
25
|
+
run_build,
|
|
26
|
+
stream_output: bool = True,
|
|
27
|
+
) -> BuildResult:
|
|
28
|
+
"""Build binary with automatic mirror failover.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
go_executable: Path to Go executable
|
|
32
|
+
source_dir: Source directory
|
|
33
|
+
output_path: Output path for binary
|
|
34
|
+
env: Environment variables
|
|
35
|
+
ldflags: Linker flags
|
|
36
|
+
tags: Build tags
|
|
37
|
+
target: Build target
|
|
38
|
+
run_build: Callback to execute build
|
|
39
|
+
stream_output: Whether to stream output
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
BuildResult with success status
|
|
43
|
+
"""
|
|
44
|
+
last_result: BuildResult | None = None
|
|
45
|
+
|
|
46
|
+
for i, mirror_key in enumerate(GoBinaryBuilder.MIRROR_KEYS):
|
|
47
|
+
env_copy = env.copy()
|
|
48
|
+
mirror_name = MIRROR_CONFIGS.get(mirror_key, {}).get("name", mirror_key)
|
|
49
|
+
logger.info(f"🔗 使用代理: {mirror_name}")
|
|
50
|
+
env_copy = apply_mirror_environment(mirror_key, env_copy)
|
|
51
|
+
|
|
52
|
+
build_args = [go_executable, "build", "-o", str(output_path)]
|
|
53
|
+
|
|
54
|
+
if ldflags:
|
|
55
|
+
build_args.extend(["-ldflags", ldflags])
|
|
56
|
+
if tags:
|
|
57
|
+
build_args.extend(["-tags", ",".join(tags)])
|
|
58
|
+
if target:
|
|
59
|
+
build_args.append(str(target))
|
|
60
|
+
|
|
61
|
+
result = run_build(build_args, source_dir, output_path.parent, env_copy)
|
|
62
|
+
last_result = result
|
|
63
|
+
|
|
64
|
+
if result["success"]:
|
|
65
|
+
logger.info("✅ 构建成功")
|
|
66
|
+
return result
|
|
67
|
+
|
|
68
|
+
if i < len(GoBinaryBuilder.MIRROR_KEYS) - 1:
|
|
69
|
+
logger.warning(f"❌ {mirror_name} 失败,切换到备用镜像...")
|
|
70
|
+
|
|
71
|
+
assert last_result is not None
|
|
72
|
+
return last_result
|
|
73
|
+
|
|
74
|
+
@staticmethod
|
|
75
|
+
def build_single(
|
|
76
|
+
go_executable: str,
|
|
77
|
+
source_dir: Path,
|
|
78
|
+
output_path: Path,
|
|
79
|
+
env: dict[str, str],
|
|
80
|
+
ldflags: str | None,
|
|
81
|
+
tags: list[str] | None,
|
|
82
|
+
target: str | Path | None,
|
|
83
|
+
run_build,
|
|
84
|
+
stream_output: bool = True,
|
|
85
|
+
) -> BuildResult:
|
|
86
|
+
"""Build binary with single mirror.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
go_executable: Path to Go executable
|
|
90
|
+
source_dir: Source directory
|
|
91
|
+
output_path: Output path for binary
|
|
92
|
+
env: Environment variables
|
|
93
|
+
ldflags: Linker flags
|
|
94
|
+
tags: Build tags
|
|
95
|
+
target: Build target
|
|
96
|
+
run_build: Callback to execute build
|
|
97
|
+
stream_output: Whether to stream output
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
BuildResult with success status
|
|
101
|
+
"""
|
|
102
|
+
build_args = [go_executable, "build", "-o", str(output_path)]
|
|
103
|
+
|
|
104
|
+
if ldflags:
|
|
105
|
+
build_args.extend(["-ldflags", ldflags])
|
|
106
|
+
if tags:
|
|
107
|
+
build_args.extend(["-tags", ",".join(tags)])
|
|
108
|
+
if target:
|
|
109
|
+
build_args.append(str(target))
|
|
110
|
+
|
|
111
|
+
logger.info("🔨 开始构建...")
|
|
112
|
+
build_result = run_build(build_args, source_dir, output_path.parent, env)
|
|
113
|
+
|
|
114
|
+
if build_result["success"]:
|
|
115
|
+
logger.info("✅ 构建成功")
|
|
116
|
+
|
|
117
|
+
return build_result
|