Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,21 @@ if ($env:GO_MODERN_GUIDELINES_DEV) {
exit $LASTEXITCODE
}

function Assert-BinaryVersion([string] $path, [string] $label) {
$actualVersion = ""
$exitCode = 1
try {
$actualVersion = ((& $path --version 2>$null) -join "`n").Trim()
$exitCode = $LASTEXITCODE
} catch {
}
if ($exitCode -ne 0 -or $actualVersion -ne $cliVersion) {
$reportedVersion = if ($actualVersion) { $actualVersion } else { "unknown version" }
Write-Error "go-modern-guidelines: $label binary reports $reportedVersion, want $cliVersion"
exit 1
}
}

$installDir = Join-Path $cacheRoot $cliVersion
$binaryPath = Join-Path $installDir $binaryName

Expand All @@ -31,8 +46,8 @@ if (-not (Test-Path -LiteralPath $binaryPath -PathType Leaf)) {
exit 1
}

$tmpDir = "$installDir.tmp.$PID"
Remove-Item -LiteralPath $tmpDir -Recurse -Force -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Path $cacheRoot -Force | Out-Null
$tmpDir = Join-Path $cacheRoot "$cliVersion.tmp.$([System.IO.Path]::GetRandomFileName())"
New-Item -ItemType Directory -Path $tmpDir -Force | Out-Null

Write-Host "go-modern-guidelines: installing $modulePath@$cliVersion into $installDir" -ForegroundColor DarkGray
Expand Down Expand Up @@ -63,22 +78,10 @@ if (-not (Test-Path -LiteralPath $binaryPath -PathType Leaf)) {
exit 1
}

$actualVersion = ""
try {
$actualVersion = (& $tmpBinary --version 2>$null)
} catch {
$actualVersion = ""
}
if ($actualVersion -ne $cliVersion) {
if (-not $actualVersion) {
$actualVersion = "unknown version"
}
Write-Error "go-modern-guidelines: installed $actualVersion, want $cliVersion"
exit 1
}
Assert-BinaryVersion $tmpBinary "installed"

New-Item -ItemType Directory -Path $installDir -Force | Out-Null
$stagedBinary = "$binaryPath.tmp.$PID"
$stagedBinary = "$binaryPath.tmp.$([System.IO.Path]::GetRandomFileName())"
Move-Item -LiteralPath $tmpBinary -Destination $stagedBinary -Force
Move-Item -LiteralPath $stagedBinary -Destination $binaryPath -Force
Remove-Item -LiteralPath $tmpDir -Recurse -Force -ErrorAction SilentlyContinue
Expand All @@ -87,5 +90,6 @@ if (-not (Test-Path -LiteralPath $binaryPath -PathType Leaf)) {
}
}

Assert-BinaryVersion $binaryPath "cached"
& $binaryPath @args
exit $LASTEXITCODE
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env sh
set -eu
umask 077

script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)"

Expand Down Expand Up @@ -35,9 +36,8 @@ if [ ! -x "${binary_path}" ]; then
exit 1
fi

tmp_dir="${install_dir}.tmp.$$"
rm -rf "${tmp_dir}"
mkdir -p "${tmp_dir}"
mkdir -p "${cache_root}"
tmp_dir="$(mktemp -d "${install_dir}.tmp.XXXXXX")"
trap 'rm -rf "${tmp_dir}"' EXIT HUP INT TERM

echo "go-modern-guidelines: installing ${module_path}@${cli_version} into ${install_dir}" >&2
Expand All @@ -60,9 +60,16 @@ if [ ! -x "${binary_path}" ]; then
fi

mkdir -p "${install_dir}"
mv "${tmp_binary}" "${binary_path}.tmp.$$"
mv "${binary_path}.tmp.$$" "${binary_path}"
staged_binary="$(mktemp "${binary_path}.tmp.XXXXXX")"
mv "${tmp_binary}" "${staged_binary}"
mv "${staged_binary}" "${binary_path}"
rm -rf "${tmp_dir}"
fi

actual_version="$("${binary_path}" --version 2>/dev/null || true)"
if [ "${actual_version}" != "${cli_version}" ]; then
echo "go-modern-guidelines: cached binary reports ${actual_version:-unknown version}, want ${cli_version}" >&2
exit 1
fi

exec "${binary_path}" "$@"
8 changes: 6 additions & 2 deletions packages/mtmharness/src/features/coding/modern-go.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const MODERN_GO_RESOURCE_BASE = resolve(
"../resources/go-modern-guidelines",
);

// Adapted from JetBrains/go-modern-guidelines v1.1.1; command paths are resolved for mtmharness.
// Adapted from JetBrains/go-modern-guidelines CLI v0.1.1; command paths are resolved for mtmharness.
const SKILL_CONTENT_TEMPLATE = [
"# Modern Go Guidelines CLI",
"",
Expand Down Expand Up @@ -65,10 +65,14 @@ const SKILL_CONTENT_TEMPLATE = [
"Do not call `explain` without guideline IDs. Use `list` first to discover the short guideline list for the target Go version, then call `explain` for the specific returned IDs.",
].join("\n");

function powerShellLiteral(value: string): string {
return "'" + value.replaceAll("'", "''") + "'";
}

function content(command: string): string {
const configured = command.trim();
const unixCommand = configured || "sh \"" + join(MODERN_GO_RESOURCE_BASE, "scripts", "run-tool.sh") + "\"";
const windowsCommand = configured || "& '" + join(MODERN_GO_RESOURCE_BASE, "scripts", "run-tool.ps1") + "'";
const windowsCommand = configured || "& " + powerShellLiteral(join(MODERN_GO_RESOURCE_BASE, "scripts", "run-tool.ps1"));
return SKILL_CONTENT_TEMPLATE
.replaceAll("__UNIX_COMMAND__", unixCommand)
.replaceAll("__WINDOWS_COMMAND__", windowsCommand);
Expand Down
53 changes: 52 additions & 1 deletion packages/mtmharness/tests/coding-runtime.test.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import assert from "node:assert/strict";
import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { spawnSync } from "node:child_process";
import { tmpdir } from "node:os";
import { join, resolve } from "node:path";
import { deflateRawSync, gzipSync } from "node:zlib";
import { join } from "node:path";
import test from "node:test";
import {
ensureRuntime,
Expand Down Expand Up @@ -42,6 +45,54 @@ test("explicit command remains an opt-in override", () => {
});
});

test("lazily installs and validates the Modern Go wrapper cache", () => {
const root = mkdtempSync(join(tmpdir(), "mtmharness-modern-go-"));
try {
const binDir = join(root, "bin");
const cacheDir = join(root, "cache");
const installCount = join(root, "install-count");
const wrapper = resolve(import.meta.dirname, "../resources/go-modern-guidelines/scripts/run-tool.sh");
const version = readFileSync(resolve(import.meta.dirname, "../resources/go-modern-guidelines/scripts/VERSION"), "utf8").trim();
const fakeGo = join(binDir, "go");
mkdirSync(binDir, { recursive: true });
writeFileSync(fakeGo, `#!/bin/sh
set -eu
printf 'install\n' >> "$FAKE_GO_INSTALLS"
printf '%s\n' '#!/bin/sh' 'if [ "$1" = "--version" ]; then printf "%s\\n" "$FAKE_VERSION"; else printf "fake:%s\\n" "$*"; fi' > "$GOBIN/go-modern-guidelines"
chmod +x "$GOBIN/go-modern-guidelines"
`);
chmodSync(fakeGo, 0o755);
const env = {
...process.env,
FAKE_GO_INSTALLS: installCount,
FAKE_VERSION: version,
HOME: root,
PATH: binDir + ":" + (process.env.PATH ?? "/usr/bin:/bin"),
XDG_CACHE_HOME: cacheDir,
};
const run = (...args) => spawnSync("/bin/sh", [wrapper, ...args], { env, encoding: "utf8" });

let result = run("list", "--go-version", "1.27");
assert.equal(result.status, 0, result.stderr);
assert.equal(result.stdout.trim(), "fake:list --go-version 1.27");
assert.equal(readFileSync(installCount, "utf8"), "install\n");

result = run("list", "--go-version", "1.27");
assert.equal(result.status, 0, result.stderr);
assert.equal(result.stdout.trim(), "fake:list --go-version 1.27");
assert.equal(readFileSync(installCount, "utf8"), "install\n");

const cached = join(cacheDir, "go-modern-guidelines", version, "go-modern-guidelines");
writeFileSync(cached, "#!/bin/sh\nprintf 'wrong\\n'\n");
chmodSync(cached, 0o755);
result = run("list", "--go-version", "1.27");
assert.equal(result.status, 1);
assert.match(result.stderr, /cached binary reports wrong/);
} finally {
rmSync(root, { recursive: true, force: true });
}
});

test("resolves the native binary for the long-lived MCP connection", async () => {
const specs = [];
const fake = {
Expand Down
Loading