forked from github/copilot-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTestUtil.java
More file actions
138 lines (125 loc) · 5.68 KB
/
Copy pathTestUtil.java
File metadata and controls
138 lines (125 loc) · 5.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------------------------------------------*/
package com.github.copilot;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* Shared test utilities for locating the Copilot CLI binary and other
* cross-platform test helpers.
*/
public final class TestUtil {
private TestUtil() {
}
/**
* Returns a platform-independent path string for a file inside the system
* temporary directory. Uses {@code java.io.tmpdir} so tests run correctly on
* both POSIX and Windows.
*
* @param filename
* the file name (no directory separator required)
* @return absolute path string in the system temp directory
*/
public static String tempPath(String filename) {
return Path.of(System.getProperty("java.io.tmpdir"), filename).toString();
}
/**
* Locates a launchable Copilot CLI executable.
* <p>
* Resolution order:
* <ol>
* <li>Use the {@code COPILOT_CLI_PATH} environment variable when set.</li>
* <li>Otherwise search the system PATH using {@code where.exe} (Windows) or
* {@code which} (Linux/macOS).</li>
* <li>Walk parent directories looking for
* {@code nodejs/node_modules/@github/copilot/npm-loader.js}.</li>
* </ol>
*
* <p>
* <b>Why iterate all PATH results?</b> On Windows, {@code where.exe copilot}
* can return multiple candidates. The first hit is often a Linux ELF binary
* bundled inside the VS Code Insiders extension directory — it exists on disk
* but cannot be executed by {@link ProcessBuilder} (CreateProcess error 193).
* This method tries each candidate with {@code --version} and returns the first
* one that actually launches, skipping non-executable entries.
*
* @return the absolute path to a launchable {@code copilot} binary, or
* {@code null} if none was found
*/
static String findCliPath() {
String envPath = System.getenv("COPILOT_CLI_PATH");
if (envPath != null && !envPath.isEmpty()) {
return envPath;
}
String copilotInPath = findCopilotInPath();
if (copilotInPath != null) {
return copilotInPath;
}
// Walk parent directories looking for the CLI in the test harness or nodejs
// installation. Mirrors the resolution order in E2ETestContext.getCliPath().
String os = System.getProperty("os.name").toLowerCase();
String arch = System.getProperty("os.arch").toLowerCase();
String platform = os.contains("mac") ? "darwin" : os.contains("win") ? "win32" : "linux";
String cpuArch = arch.contains("aarch64") || arch.contains("arm64") ? "arm64" : "x64";
String binaryName = os.contains("win") ? "copilot.exe" : "copilot";
Path current = Paths.get(System.getProperty("user.dir"));
while (current != null) {
// Test harness platform-specific binary
Path platformBinary = current.resolve(
"test/harness/node_modules/@github/copilot-" + platform + "-" + cpuArch + "/" + binaryName);
if (platformBinary.toFile().exists()) {
return platformBinary.toString();
}
// Test harness npm-loader.js
Path npmLoader = current.resolve("test/harness/node_modules/@github/copilot/npm-loader.js");
if (npmLoader.toFile().exists()) {
return npmLoader.toString();
}
// nodejs installation (thin loader; resolves the platform-specific
// CLI package internally)
Path cliPath = current.resolve("nodejs/node_modules/@github/copilot/npm-loader.js");
if (cliPath.toFile().exists()) {
return cliPath.toString();
}
current = current.getParent();
}
return null;
}
/**
* Searches the system PATH for a launchable {@code copilot} executable.
* <p>
* Uses {@code where.exe} on Windows and {@code which} on Unix-like systems. On
* Windows, {@code where.exe} may return multiple results (e.g. a Linux ELF
* binary, a {@code .bat} wrapper, a {@code .cmd} wrapper). This method iterates
* all results and returns the first one that {@link ProcessBuilder} can
* actually start.
*/
private static String findCopilotInPath() {
try {
String command = System.getProperty("os.name").toLowerCase().contains("win") ? "where" : "which";
var pb = new ProcessBuilder(command, "copilot");
pb.redirectErrorStream(true);
Process process = pb.start();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
int exitCode = process.waitFor();
if (exitCode != 0) {
return null;
}
var lines = reader.lines().map(String::trim).filter(l -> !l.isEmpty()).toList();
for (String candidate : lines) {
try {
new ProcessBuilder(candidate, "--version").redirectErrorStream(true).start().destroyForcibly();
return candidate;
} catch (Exception launchFailed) {
// Not launchable on this platform — try next candidate
}
}
}
} catch (Exception e) {
// Ignore - copilot not found in PATH
}
return null;
}
}