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