Skip to content

Commit 4069a3d

Browse files
partoufclaude
andcommitted
Add Go library support with module resolution and import path detection
Add full Go language support to the wizard, including: - GoHandler for adding Go modules to libraries.yaml and go.amazon.properties - Module path resolution via Go proxy (handles subpackage paths) - Auto-detection of import_path for modules with non-importable roots - Go build testing support with compiler auto-detection - Interactive and CLI modes with --import-path flag Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 596eabd commit 4069a3d

7 files changed

Lines changed: 1166 additions & 13 deletions

File tree

cli/main.py

Lines changed: 223 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from core.fortran_handler import FortranHandler
1414
from core.git_operations import GitManager
1515
from core.github_auth import get_github_token_via_gh_cli, get_github_token_via_oauth
16+
from core.go_handler import GoHandler, detect_import_path, resolve_go_module
1617
from core.models import Language, LibraryConfig, LibraryType
1718
from core.rust_handler import RustLibraryHandler
1819
from core.subprocess_utils import run_ce_install_command
@@ -896,6 +897,196 @@ def process_fortran_library(
896897
raise
897898

898899

900+
def process_go_library(
901+
config: LibraryConfig,
902+
github_token: str | None = None,
903+
verify: bool = False,
904+
dry_run: bool = False,
905+
debug: bool = False,
906+
build_test: str = "auto",
907+
keep_temp: bool = False,
908+
yes: bool = False,
909+
):
910+
"""Process a Go library addition"""
911+
click.echo(
912+
f"\nProcessing Go module: {config.module} ({config.library_id or 'auto'}) {config.version}"
913+
)
914+
915+
with GitManager(github_token, debug=debug, keep_temp=keep_temp) as git_mgr:
916+
click.echo("Cloning repositories...")
917+
main_repo_path, infra_repo_path = git_mgr.clone_repositories()
918+
919+
library_name = config.library_id or GoHandler.suggest_library_id_static(config.module)
920+
branch_name = f"add-go-{library_name}-{config.version}".replace(".", "-")
921+
infra_branch = f"{branch_name}-infra"
922+
main_branch = f"{branch_name}-main"
923+
git_mgr.create_branch(infra_repo_path, infra_branch)
924+
git_mgr.create_branch(main_repo_path, main_branch)
925+
926+
click.echo("Adding Go library...")
927+
go_handler = GoHandler(infra_repo_path, main_repo_path, debug=debug)
928+
929+
try:
930+
if config.module:
931+
click.echo("Resolving module path...")
932+
resolved_module, resolved_import = resolve_go_module(
933+
config.module, config.get_primary_version()
934+
)
935+
if resolved_module != config.module:
936+
click.echo(f"Resolved subpackage path to module: {resolved_module}")
937+
config.import_path = config.import_path or resolved_import
938+
config.module = resolved_module
939+
config.library_id = GoHandler.suggest_library_id_static(resolved_module)
940+
941+
if not config.import_path:
942+
click.echo("Checking module structure...")
943+
detected = detect_import_path(config.module, config.get_primary_version())
944+
if detected:
945+
click.echo(f"Root package not importable, using: {detected}")
946+
config.import_path = detected
947+
else:
948+
click.echo("Root package is importable")
949+
950+
library_id = go_handler.add_library(config)
951+
if not library_id:
952+
click.echo("Failed to add library to libraries.yaml", err=True)
953+
return
954+
955+
click.echo("Updating go.amazon.properties...")
956+
config.library_id = library_id
957+
if not go_handler.update_go_properties(library_id, config):
958+
click.echo("Failed to update Go properties", err=True)
959+
return
960+
961+
click.echo(SUCCESS_MODIFIED_FILES)
962+
963+
# Run build test based on mode
964+
should_build_test = build_test.lower()
965+
is_auto_mode = should_build_test == "auto"
966+
967+
if should_build_test != "no":
968+
if platform.system() == "Windows":
969+
if should_build_test == "yes":
970+
click.echo("\nBuild test is not supported on Windows")
971+
else:
972+
available, msg = go_handler.is_build_test_available()
973+
if not available:
974+
if should_build_test == "yes":
975+
click.echo(f"\n{msg}", err=True)
976+
return
977+
# Auto mode: silently skip if no compiler
978+
else:
979+
click.echo(f"\nRunning Go build test... ({msg})")
980+
build_result = go_handler.run_build_test(library_id, config.version)
981+
if not build_result.success:
982+
click.echo("Build test failed.", err=True)
983+
if is_auto_mode:
984+
click.echo(
985+
" Hint: Use --build-test=no to skip build testing "
986+
"if this failure is expected.",
987+
err=True,
988+
)
989+
click.echo("Aborting.", err=True)
990+
return
991+
click.echo("Build test passed")
992+
if build_result.artifacts:
993+
click.echo(" Artifacts produced:")
994+
click.echo(f" {build_result.get_artifact_summary()}")
995+
996+
# Show diffs if verify or dry_run flag is set
997+
if verify or dry_run:
998+
click.echo("\n" + "=" * 60)
999+
click.echo("CHANGES TO BE COMMITTED:")
1000+
click.echo("=" * 60)
1001+
1002+
click.echo(f"\nRepository: {GitManager.CE_INFRA_REPO}")
1003+
click.echo("-" * 60)
1004+
infra_diff = git_mgr.get_diff(infra_repo_path)
1005+
if infra_diff:
1006+
click.echo(infra_diff)
1007+
else:
1008+
click.echo("No changes detected")
1009+
1010+
click.echo(f"\nRepository: {GitManager.CE_MAIN_REPO}")
1011+
click.echo("-" * 60)
1012+
main_diff = git_mgr.get_diff(main_repo_path)
1013+
if main_diff:
1014+
click.echo(main_diff)
1015+
else:
1016+
click.echo("No changes detected")
1017+
1018+
click.echo("\n" + "=" * 60)
1019+
1020+
# Exit early if dry-run mode
1021+
if dry_run:
1022+
click.echo("\nDry run complete - no changes committed.")
1023+
return
1024+
1025+
if not yes and not click.confirm("\nDo you want to proceed with these changes?"):
1026+
click.echo("Changes cancelled.")
1027+
return
1028+
1029+
commit_msg = f"Add Go library {library_id} {config.version}"
1030+
1031+
infra_committed = git_mgr.commit_changes(infra_repo_path, commit_msg)
1032+
main_committed = git_mgr.commit_changes(main_repo_path, commit_msg)
1033+
1034+
if not infra_committed and not main_committed:
1035+
click.echo("Library version already exists - no changes to commit.")
1036+
return
1037+
1038+
if github_token:
1039+
# Only proceed with pushing and PRs if we have commits
1040+
if infra_committed or main_committed:
1041+
# Push branches and create PRs
1042+
click.echo("\nPushing branches...")
1043+
if infra_committed:
1044+
git_mgr.push_branch(infra_repo_path, infra_branch)
1045+
if main_committed:
1046+
git_mgr.push_branch(main_repo_path, main_branch)
1047+
1048+
click.echo("\nCreating pull requests...")
1049+
pr_body = (
1050+
f"This PR adds the Go library **{library_id}** "
1051+
f"(module: `{config.module}`) "
1052+
f"version {config.version} to Compiler Explorer.\n\n"
1053+
)
1054+
pr_body += f"- Go module: {config.module}\n"
1055+
pr_body += "- Build type: gomod"
1056+
1057+
if infra_committed:
1058+
infra_pr_body = pr_body + PR_FOOTER
1059+
infra_pr_url = git_mgr.create_pull_request(
1060+
GitManager.CE_INFRA_REPO, infra_branch, commit_msg, infra_pr_body
1061+
)
1062+
click.echo("\nCreated PR:")
1063+
click.echo(f" - Infra: {infra_pr_url}")
1064+
1065+
if main_committed:
1066+
main_pr_body = pr_body
1067+
if infra_committed:
1068+
main_pr_body += f"\n\nRelated PR: {infra_pr_url}"
1069+
main_pr_body += PR_FOOTER
1070+
1071+
main_pr_url = git_mgr.create_pull_request(
1072+
GitManager.CE_MAIN_REPO,
1073+
main_branch,
1074+
commit_msg,
1075+
main_pr_body,
1076+
)
1077+
if not infra_committed:
1078+
click.echo("\nCreated PR:")
1079+
click.echo(f" - Main: {main_pr_url}")
1080+
else:
1081+
click.echo("\nNo changes to push - skipping PR creation.")
1082+
else:
1083+
display_authentication_warning()
1084+
1085+
except Exception as e:
1086+
click.echo(f"\nError processing Go library: {e}", err=True)
1087+
raise
1088+
1089+
8991090
@click.command()
9001091
@click.option("--debug", is_flag=True, help="Enable debug mode")
9011092
@click.option("--github-token", envvar="GITHUB_TOKEN", help="GitHub token for creating PRs")
@@ -914,7 +1105,7 @@ def process_fortran_library(
9141105
@click.option("--top-rust-crates", is_flag=True, help="Add the top 100 Rust crates")
9151106
@click.option(
9161107
"--lang",
917-
type=click.Choice(["c", "c++", "rust", "fortran"], case_sensitive=False),
1108+
type=click.Choice(["c", "c++", "rust", "fortran", "go"], case_sensitive=False),
9181109
help="Language for the library",
9191110
)
9201111
@click.option("--lib", help="Library name (for Rust) or GitHub URL (for other languages)")
@@ -934,6 +1125,10 @@ def process_fortran_library(
9341125
"(automatic for packaged-headers, optional for others)"
9351126
),
9361127
)
1128+
@click.option(
1129+
"--import-path",
1130+
help="Go import path override (for modules where root package isn't importable)",
1131+
)
9371132
def main(
9381133
debug: bool,
9391134
github_token: str | None,
@@ -950,6 +1145,7 @@ def main(
9501145
ver: str | None,
9511146
type: str | None,
9521147
package_install: bool,
1148+
import_path: str | None,
9531149
):
9541150
"""CLI tool to add libraries to Compiler Explorer"""
9551151
if debug:
@@ -985,14 +1181,23 @@ def main(
9851181
"c++": Language.CPP,
9861182
"rust": Language.RUST,
9871183
"fortran": Language.FORTRAN,
1184+
"go": Language.GO,
9881185
}
9891186

9901187
language = lang_map[lang.lower()]
9911188

9921189
if language == Language.RUST:
9931190
config = LibraryConfig(language=language, name=lib, version=ver)
1191+
elif language == Language.GO:
1192+
config = LibraryConfig(
1193+
language=language,
1194+
module=lib,
1195+
version=ver,
1196+
import_path=import_path,
1197+
)
1198+
config.library_id = GoHandler.suggest_library_id_static(lib)
9941199
else:
995-
# For non-Rust, lib should be a GitHub URL
1200+
# For non-Rust/Go, lib should be a GitHub URL
9961201
config = LibraryConfig(language=language, github_url=lib, version=ver)
9971202

9981203
# For C, C++, and Fortran, we need to set library_id
@@ -1089,6 +1294,17 @@ def main(
10891294
keep_temp,
10901295
yes,
10911296
)
1297+
elif config.is_go():
1298+
process_go_library(
1299+
single_config,
1300+
github_token,
1301+
verify,
1302+
dry_run,
1303+
debug,
1304+
build_test,
1305+
keep_temp,
1306+
yes,
1307+
)
10921308
else:
10931309
click.echo(f"\n⚠️ Language {config.language} is not yet implemented.")
10941310
break
@@ -1126,10 +1342,14 @@ def main(
11261342
process_fortran_library(
11271343
config, github_token, verify, dry_run, debug, build_test, keep_temp, yes
11281344
)
1345+
elif config.is_go():
1346+
process_go_library(
1347+
config, github_token, verify, dry_run, debug, build_test, keep_temp, yes
1348+
)
11291349
else:
11301350
click.echo("\n⚠️ This language is not yet implemented.")
11311351
click.echo(
1132-
"Currently only Rust, C, C++, and Fortran library additions are supported."
1352+
"Currently only Rust, C, C++, Fortran, and Go library additions are supported."
11331353
)
11341354

11351355
except KeyboardInterrupt:

0 commit comments

Comments
 (0)