multi-lang-build 0.2.8__tar.gz → 0.2.10__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.
Files changed (46) hide show
  1. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/PKG-INFO +1 -1
  2. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/pyproject.toml +1 -1
  3. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/src/multi_lang_build/__init__.py +4 -4
  4. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/src/multi_lang_build/cli.py +3 -2
  5. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/src/multi_lang_build/compiler/__init__.py +1 -1
  6. multi_lang_build-0.2.10/src/multi_lang_build/compiler/go_compiler.py +388 -0
  7. multi_lang_build-0.2.10/src/multi_lang_build/compiler/go_support/__init__.py +19 -0
  8. multi_lang_build-0.2.10/src/multi_lang_build/compiler/go_support/binary.py +117 -0
  9. multi_lang_build-0.2.10/src/multi_lang_build/compiler/go_support/builder.py +228 -0
  10. multi_lang_build-0.2.10/src/multi_lang_build/compiler/go_support/cleaner.py +40 -0
  11. multi_lang_build-0.2.10/src/multi_lang_build/compiler/go_support/env.py +41 -0
  12. multi_lang_build-0.2.10/src/multi_lang_build/compiler/go_support/mirror.py +111 -0
  13. multi_lang_build-0.2.10/src/multi_lang_build/compiler/go_support/module.py +77 -0
  14. multi_lang_build-0.2.10/src/multi_lang_build/compiler/go_support/tester.py +199 -0
  15. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/src/multi_lang_build/compiler/pnpm.py +61 -209
  16. multi_lang_build-0.2.10/src/multi_lang_build/compiler/pnpm_support/__init__.py +6 -0
  17. multi_lang_build-0.2.10/src/multi_lang_build/compiler/pnpm_support/executor.py +148 -0
  18. multi_lang_build-0.2.10/src/multi_lang_build/compiler/pnpm_support/project.py +53 -0
  19. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/src/multi_lang_build/compiler/python.py +65 -222
  20. multi_lang_build-0.2.10/src/multi_lang_build/compiler/python_support/__init__.py +13 -0
  21. multi_lang_build-0.2.10/src/multi_lang_build/compiler/python_support/cleaner.py +56 -0
  22. multi_lang_build-0.2.10/src/multi_lang_build/compiler/python_support/cli.py +46 -0
  23. multi_lang_build-0.2.10/src/multi_lang_build/compiler/python_support/detector.py +64 -0
  24. multi_lang_build-0.2.10/src/multi_lang_build/compiler/python_support/installer.py +162 -0
  25. multi_lang_build-0.2.10/src/multi_lang_build/compiler/python_support/venv.py +63 -0
  26. multi_lang_build-0.2.10/src/multi_lang_build/ide_register.py +97 -0
  27. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/src/multi_lang_build/mirror/config.py +19 -0
  28. multi_lang_build-0.2.10/src/multi_lang_build/register/support/__init__.py +13 -0
  29. multi_lang_build-0.2.10/src/multi_lang_build/register/support/claude.py +94 -0
  30. multi_lang_build-0.2.10/src/multi_lang_build/register/support/codebuddy.py +100 -0
  31. multi_lang_build-0.2.10/src/multi_lang_build/register/support/opencode.py +62 -0
  32. multi_lang_build-0.2.10/src/multi_lang_build/register/support/trae.py +72 -0
  33. multi_lang_build-0.2.8/src/multi_lang_build/compiler/go.py +0 -564
  34. multi_lang_build-0.2.8/src/multi_lang_build/register.py +0 -412
  35. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/.gitignore +0 -0
  36. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/LICENSE +0 -0
  37. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/README.md +0 -0
  38. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/src/multi_lang_build/compiler/base.py +0 -0
  39. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/src/multi_lang_build/mirror/__init__.py +0 -0
  40. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/src/multi_lang_build/mirror/cli.py +0 -0
  41. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/src/multi_lang_build/py.typed +0 -0
  42. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/src/multi_lang_build/types.py +0 -0
  43. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/tests/__init__.py +0 -0
  44. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/tests/conftest.py +0 -0
  45. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/tests/test_compiler.py +0 -0
  46. {multi_lang_build-0.2.8 → multi_lang_build-0.2.10}/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.8
3
+ Version: 0.2.10
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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "multi-lang-build"
7
- version = "0.2.8"
7
+ version = "0.2.10"
8
8
  description = "Multi-language automated build tool with domestic mirror acceleration support"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -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.go import GoCompiler
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.register import register_skill
8
+ from multi_lang_build.ide_register import register_skill
9
9
 
10
- __version__ = "0.2.8"
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.register import register_skill
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",
@@ -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/--no-mirror", default=True, help="Enable/disable Go proxy 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.go import GoCompiler
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.go import GoCompiler
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