How does the integrated terminal allow Linux/UNIX commands to be run on windows machines? Look through the codebase and think before returning an answer, cite code snippets
Use Tool: list_directory (call_gDj2Ar9YlXv9ttWQmGCGeEd3)
{
"path": "pros-vsc"
}Tool Results: call_gDj2Ar9YlXv9ttWQmGCGeEd3
pros-vsc/.github pros-vsc/.vscode pros-vsc/media pros-vsc/src
pros-vsc/.eslintignore pros-vsc/.eslintrc.json pros-vsc/.gitignore pros-vsc/.pre-commit-config.yaml pros-vsc/.vscodeignore pros-vsc/CHANGELOG.md pros-vsc/CONTRIBUTING.md pros-vsc/LICENSE.txt pros-vsc/README.md pros-vsc/azure-pipelines.yml pros-vsc/package-lock.json pros-vsc/package.json pros-vsc/tsconfig.json
Use Tool: grep (call_n2vGbgi8jJaFCkAkL3u6LolX)
{
"regex": "createTerminal",
"include_pattern": "pros-vsc/src"
}Tool Results: call_n2vGbgi8jJaFCkAkL3u6LolX
Found 1 matches:
// Create a new terminal with the correct path, return it.
return vscode.window.createTerminal({
name: "PROS Terminal",
env: process.env,
Use Tool: grep (call_1Z1uVU6qVZuy1CK4MRtUShRW)
{
"regex": "shell",
"include_pattern": "pros-vsc/src"
}Tool Results: call_1Z1uVU6qVZuy1CK4MRtUShRW
No matches found
Use Tool: grep (call_CIQWETvQRcQWtzMBPi5BHUmK)
{
"regex": "process\\.platform",
"include_pattern": "pros-vsc/src"
}Tool Results: call_CIQWETvQRcQWtzMBPi5BHUmK
Found 1 matches:
export const getOperatingSystem = () => {
if (process.platform === "win32") {
return "windows";
}
if (process.platform === "darwin") {
return "macos";
}
return "linux";
};
Use Tool: list_directory (call_TUo05GLsdO6o1VSlgvckWXuv)
{
"path": "pros-vsc/.vscode"
}Tool Results: call_TUo05GLsdO6o1VSlgvckWXuv
pros-vsc/.vscode/extensions.json pros-vsc/.vscode/launch.json pros-vsc/.vscode/prosDocs.json pros-vsc/.vscode/settings.json pros-vsc/.vscode/tasks.json
Use Tool: read_file (call_wiLngD2xzKO6LZL8ZXpeIiK1)
{
"path": "pros-vsc/.vscode/settings.json",
"start_line": 1,
"end_line": 200
}Tool Results: call_wiLngD2xzKO6LZL8ZXpeIiK1
// Place your settings in this file to overwrite default and user settings. { "files.exclude": { "out": false // set this to true to hide the "out" folder with the compiled JS files }, "search.exclude": { "out": true // set this to false to include "out" folder in search results }, // Turn off tsc task auto detection since we have the necessary tasks as npm scripts "typescript.tsc.autoDetect": "off", "cmake.configureOnOpen": false }
Use Tool: read_file (call_Pr3WBgMuDwAwsbGoPl2sp8n4)
{
"path": "pros-vsc/.vscode/tasks.json",
"start_line": 1,
"end_line": 200
}Tool Results: call_Pr3WBgMuDwAwsbGoPl2sp8n4
// See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format { "version": "2.0.0", "tasks": [ { "type": "npm", "script": "watch", "problemMatcher": "$tsc-watch", "isBackground": true, "presentation": { "reveal": "never" }, "group": { "kind": "build", "isDefault": true } } ] }
Use Tool: grep (call_1swNgIdL7LEjY5MkBLEkzd0j)
{
"regex": "shellPath",
"include_pattern": "pros-vsc/src"
}Tool Results: call_1swNgIdL7LEjY5MkBLEkzd0j
No matches found
Use Tool: read_file (call_00iZQs9mYzp9TYNkRMIc5Tqh)
{
"path": "pros-vsc/src/workspace_utils.ts",
"start_line": 1,
"end_line": 300
}Tool Results: call_00iZQs9mYzp9TYNkRMIc5Tqh
import * as vscode from "vscode"; import * as path from "path"; import * as fs from "fs"; import { promisify } from "util"; import { getOperatingSystem } from "./one-click/install"; import { getChildProcessProsToolchainPath } from "./one-click/path"; import { configurePaths } from "./one-click/install";
/**
- This function searches a directory of the workspace for a file with the given name
- @param filename This is the name of the file to search for (including extension)
- @param dir This is the directory to search in. Ex. "src" or "include" or "src/chassis". "root" causes the entire workspace to be searched.
- @param debug This is a boolean that determines whether or not to log all potential matches + other debug messages
- @returns The Uri of the first matching file if any are found, null if directory or file not found */ export const findFile = async ( filename: string, dir: string, debug: boolean = false ): Promise<vscode.Uri | null> => { const debugMsg = "While searching for " + filename + " in " + dir + ": ";
// Return null if either string or dir is undefined or null if ( filename === undefined || dir === undefined || filename === null || dir === null ) { if (debug) { // Log message if in debug mode console.log(debugMsg + "invalid input of some kind! "); } return null; }
// Perform search operation if (dir === "root") { // Search entire workspace if dir is "root" var searchResults = await vscode.workspace.findFiles(filename); } else { // Search specified directory if dir is not "root". This is done by using glob patterns. // Ex. "/src//main.cpp" searches for "main.cpp" in any folder named "src" in the workspace, including all folders inside of all folders labeled "src" in the workspace. // NOTE: The use of vscode's joinPath is not necesary here, since everything is a web uri so regardless of user OS, it will be a standard forward slash for filepaths. var searchResults = await vscode.workspace.findFiles( "/" + dir + "//" + filename ); }
// vscode's findFiles function returns a thenable which operates as an array of URIs. Thus, we can use array functions on it: if (searchResults.length === 0) { // Return null if no files found if (debug) { // Log message if in debug mode console.log(debugMsg + "no matching files found!"); } return null; } else if (debug) { // >= 1 matching file found, in debug mode searchResults.forEach((path) => { // Log all matching files found if in debug mode console.log(debugMsg + "matching file found: " + path); }); }
// Double check file exists (for some reason vscode's findFiles function returns files that don't exist for users of the web version of vscode sometimes) // (According to Benjamin Davis anyways) try { await vscode.workspace.fs.stat(searchResults[0]); } catch (err) { return null; }
// Return first matching file found if any are found return searchResults[0]; };
/**
- This function searches the workspace for all instances of a project.pros file. It then returns the folders containing those files.
- It is used to offer the user a choice of which pros project to work on in the event there are multiple in the current workspace.
- @returns An array of every folder which houses a project.pros file in the workspace. Returns an empty array if none found. */ export async function findProsProjectFolders(debug: boolean = false) { // Type is any for js reasons. Doesn't really matter, will end up being a string array. const debugMsg = "While searching for pros project folder names: "; var array: any = []; if ( vscode.workspace.workspaceFolders === undefined || vscode.workspace.workspaceFolders === null ) { // Return empty array if no workspace folders if (debug) { // Log message if in debug mode console.log(debugMsg + "no workspace folders found!"); } return array; }
if (debug) { // Log list of found folders in workspace if in debug mode console.log( debugMsg + " candidate folders found: " + vscode.workspace.workspaceFolders ); }
for (const workspace of vscode.workspace.workspaceFolders) { // Loop through each workspace folder and check if it contains a project.pros file in any of its subfolders (or at root level) const currentDir = workspace.uri; // uri to top workspace folder const folders = await vscode.workspace.fs.readDirectory(currentDir); // all subfolders, subfiles of top workspace folder for (const folder of folders) { // Loop through each subfolder and check if it contains a project.pros file var exists = true; // assume it exists until proven otherwise
try {
// By using VSCode's stat function (and the uri parsing functions), this code should work regardless
// of if the workspace is using a physical file system or not.
const workspaceUri = vscode.Uri.file(
path.join(currentDir.fsPath, folder[0])
); // uri to subfolder
const uriString = `${workspaceUri.scheme}:${
workspaceUri.path
}/${"project.pros"}`; // uri path to project.pros file in subfolder (candidate)
const uri = vscode.Uri.parse(uriString);
// Check if candidate path actually leads to a project.pros file
await vscode.workspace.fs.stat(uri);
} catch (e) {
// If not, set exists to false
console.error(e);
exists = false;
}
if (exists) {
// We have confirmed that the candidate path leads to a project.pros file. Add this folder to the array.
array.push(folder);
}
}
}
if (debug) { // Log list of found folders in workspace if in debug mode console.log(debugMsg + " final list of folders found: " + array); }
return array; // return array of folders }
/**
- This function is a convinient wrapper for findFile. It searches the entire workspace for a project.pros file.
- @returns A boolean indicating whether or not the current workspace contains a pros project */ export const workspaceContainsProsProject = async ( debug: boolean = false ): Promise => { return (await findFile("project.pros", "root", debug)) !== null; };
/**
- This function is a convinient wrapper for findFile. It searches the entire workspace for a project.pros file.
- @returns A vscode.Uri pointing to the directory containing the project.pros file, or null if no project.pros file found */ export const getProjectFileDir = async ( debug: boolean = false ): Promise<vscode.Uri | null> => { let fullUri = await findFile("project.pros", "root", debug); // get uri of project.pros file if (fullUri === null) { // return null if no project.pros file found return null; } return vscode.Uri.file(path.dirname(fullUri.fsPath)); // return uri of directory containing project.pros file };
/**
- This function creates or gets a reference to an existing vscode terminal named "PROS Terminal".
- It also configures the path of the terminal to include the pros-cli.
- It also cleans up any duplicate terminals named "PROS Terminal" that may exist.
- @param context The vscode extension context
- @returns A reference to the PROS terminal */ export const getProsTerminal = async ( context: vscode.ExtensionContext ): Promise<vscode.Terminal> => { // First, check if one or more terminals labeled "PROS Terminal" already exist. const prosTerminals = vscode.window.terminals.filter( (t) => t.name === "PROS Terminal" ); // Get all terminals named "PROS Terminal"
if (prosTerminals.length > 1) { // Clean up duplicate terminals prosTerminals.slice(1).forEach((t) => t.dispose()); }
// If there is already a terminal named "PROS Terminal" and it has the correct path, return it. if (prosTerminals.length) { const options: Readonly<vscode.TerminalOptions> = prosTerminals[0].creationOptions; if (options?.env?.PATH?.includes("pros-cli")) { // Only keep the existing terminal if it has the correct path return prosTerminals[0]; } }
// If there is not already a terminal named "PROS Terminal" or it does not have the correct path, create a new one. await configurePaths(context); // Configure the paths (see install.ts) so that everything runs properly when you click a button
// Create a new terminal with the correct path, return it. return vscode.window.createTerminal({ name: "PROS Terminal", env: process.env, }); };
/**
- This function allows the user to choose which pros project to work on in the event there are multiple in the current workspace.
- It also warns the user if there is no pros project in the current workspace.
- @returns Nothing */ export async function chooseProject() { // First, check if the current workspace exists correctly if ( vscode.workspace.workspaceFolders === undefined || vscode.workspace.workspaceFolders === null ) { return; // return if no workspace folders }
// Second, check if the current workspace contains a pros project var array = await findProsProjectFolders(); // get list of folders which contain pros projects // If no pros projects found, warn user and return if (array.length === 0) { vscode.window.showInformationMessage( "No PROS Projects found in current directory!" ); return; }
// Third, prompt user to choose which pros project to work on const targetOptions: vscode.QuickPickOptions = { placeHolder: array[0].name, title: "Select the PROS project to work on", ignoreFocusOut: true, }; var folderNames: Array<vscode.QuickPickItem> = []; for (const f of array) { folderNames.push({ label: f[0], description: "" }); } folderNames.push({ label: "PROS: Cancel Selection", description: "Do not open a PROS project", }); // Display the options to users const target = await vscode.window.showQuickPick(folderNames, targetOptions); if (target === undefined) { throw new Error(); } if (target.label === "PROS: Cancel Selection") { return; } //This will open the folder the user selects await vscode.commands.executeCommand( "vscode.openFolder", vscode.Uri.file( path.join(vscode.workspace.workspaceFolders[0].uri.fsPath, target.label) ) ); }
/**
- This function modifies the c_cpp_properties.json file which is used by the C/C++ extension to provide intellisense.
- This allows it to "understand" pros.
- @param dirpath the path to the c_cpp_properties.json file
- @param json json object
- @param os user's OS (for pathing) */ const modifyCCppJson = async ( dirpath: vscode.Uri, json: any, os: string, debug: boolean = false ) => { // First, check if json configurations setting contains include section, if not, add it let include = path.join(dirpath.fsPath, "include"); if (!json.configurations[0].includePath.includes(include)) { json.configurations[0].includePath.push(include); }
// Third, setup cStandard, cppStandard, and intelliSenseMode json.configurations[0].cStandard = "gnu11"; json.configurations[0].cppStandard = "gnu++20"; json.configurations[0].intelliSenseMode = "gcc-arm";
// Fourth, account for mac users with different framework filepath
Use Tool: read_file (call_xbg2HGSXM6Sr6RNaTP4VQh2P)
{
"path": "pros-vsc/src/one-click/install.ts",
"start_line": 1,
"end_line": 300
}Tool Results: call_xbg2HGSXM6Sr6RNaTP4VQh2P
import * as vscode from "vscode";
import * as path from "path"; import * as os from "os"; import { downloadextract, chmod } from "./download"; import { getCurrentVersion, getCurrentReleaseVersion, getToolchainVersion, } from "./installed"; import * as fs from "fs"; import { promisify } from "util"; import * as child_process from "child_process"; import * as semver from "semver"; import { getChildProcessPath, getIntegratedTerminalPaths, getChildProcessProsToolchainPath, } from "./path"; import { prosLogger } from "../extension"; import { BackgroundProgress } from "../logger"; import * as device from "../device"; //TOOLCHAIN and CLI_EXEC_PATH are exported and used for running commands. export var TOOLCHAIN: string; export var CLI_EXEC_PATH: string; export var PATH_SEP: string;
export const getOperatingSystem = () => { if (process.platform === "win32") { return "windows"; } if (process.platform === "darwin") { return "macos"; } return "linux"; };
export async function removeDirAsync(directory: string, begin: boolean) { // get all files in directory if (begin) { await vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, title: "Cleaning Directory", cancellable: false, }, async (progress, token) => { await removeDirAsync(directory, false); } ); } const files = await fs.promises.readdir(directory); if (files.length > 0) { // iterate through found files and directory for (const file of files) { if ((await fs.promises.lstat(path.join(directory, file))).isDirectory()) { // if the file is found to be a directory, // recursively call this function to remove subdirectory await removeDirAsync(path.join(directory, file), false); } else { //delete the file await fs.promises.unlink(path.join(directory, file)); } } } // delete the directory now that it is empty. await fs.promises.rmdir(directory, { recursive: true, maxRetries: 20 }); return true; }
export async function uninstall(context: vscode.ExtensionContext) {
const globalPath = context.globalStorageUri;
const title = "Are you sure you want to uninstall PROS?";
const labelResponse = await vscode.window.showInformationMessage(
title,
"Uninstall Now!",
"Uninstall CLI Only",
"No Thanks."
);
if (labelResponse === "Uninstall Now!") {
await vscode.window.withProgress(
{
location: vscode.ProgressLocation.Notification,
title: "Uninstalling PROS",
cancellable: false,
},
async () => {
try {
await vscode.workspace.fs.delete(
vscode.Uri.joinPath(globalPath, "install"),
{ recursive: true }
);
} catch (err) {
console.error(err);
}
try {
await vscode.workspace.fs.delete(
vscode.Uri.joinPath(globalPath, "download"),
{ recursive: true }
);
} catch (err) {
console.error(err);
}
}
);
vscode.window.showInformationMessage("PROS Uninstalled!");
} else if (labelResponse === "Uninstall CLI Only") {
const cliName = pros-cli-${getOperatingSystem()};
await vscode.window.withProgress(
{
location: vscode.ProgressLocation.Notification,
title: "Uninstalling PROS CLI",
cancellable: false,
},
async () => {
await vscode.workspace.fs.delete(
vscode.Uri.joinPath(context.globalStorageUri, "install", cliName),
{ recursive: true }
);
}
);
}
}
async function getUrls( cliVersion: number, toolchainVersion: string, vexcomVersion: string ) { var cliArch = "lin-64bit"; var toolchainArch = "x86_64"; var vexcomArch = "linux-x64";
await prosLogger.log(
"OneClick",
Selecting proper download URLS for CLI and Toolchain
);
var operatingSystem = getOperatingSystem();
if (operatingSystem === "windows") {
await prosLogger.log("OneClick", Windows detected, using Windows URLS);
// Set system, path seperator, and downloads to windows version
cliArch = "win-64bit";
vexcomArch = "win32";
} else if (operatingSystem === "macos") {
await prosLogger.log("OneClick", MacOS detected, using MacOS URLS);
// Set system, path seperator, and downloads to windows version
cliArch = "macos-64bit";
toolchainArch = os.arch() === "x64" ? "darwin-x86_64" : "darwin-arm64";
vexcomArch = "osx";
} else {
await prosLogger.log("OneClick", Linux detected, using Linux URLS);
}
var downloadCli = https://github.com/purduesigbots/pros-cli/releases/download/${cliVersion}/pros_cli-${cliVersion}-${cliArch}.zip;
var downloadVexcom = https://pros.cs.purdue.edu/v5/_static/releases/vexcom_${vexcomVersion}-${vexcomArch}.zip;
if (operatingSystem === "windows") {
var downloadToolchain = https://github.com/purduesigbots/toolchain/releases/download/${toolchainVersion}/pros-toolchain-windows-formatted.zip;
} else {
let toolchainSemver = semver.parse(toolchainVersion, { loose: true });
toolchainVersion = ${toolchainSemver?.major}.${toolchainSemver?.minor}.rel${toolchainSemver?.patch};
var downloadToolchain = https://developer.arm.com/-/media/Files/downloads/gnu/${toolchainVersion}/binrel/arm-gnu-toolchain-${toolchainVersion}-${toolchainArch}-arm-none-eabi.tar.xz;
}
const customCli =
vscode.workspace
.getConfiguration("pros")
.get("OneClick: CLI Download URL") ?? "default";
const customToolchain =
vscode.workspace
.getConfiguration("pros")
.get("OneClick: Toolchain Download URL") ?? "default";
await prosLogger.log("OneClick", Checking for custom installation URLs);
console.log(Custom URLS: ${customCli} | ${customToolchain});
if (customCli !== "default") {
try {
downloadCli = customCli === "default" ? downloadCli : customCli;
await prosLogger.log(
"OneClick",
Using custom CLI download URL: ${downloadCli}
);
} catch (e: any) {
await prosLogger.log("OneClick", Invalid custom CLI URL: ${customCli});
console.log(
"CLI Url specified in PROS extension settings was invalid. Using default instead"
);
}
}
if (customToolchain !== "default") {
try {
downloadToolchain =
customToolchain === "default" ? downloadToolchain : customToolchain;
await prosLogger.log(
"OneClick",
Using custom Toolchain download URL: ${downloadToolchain}
);
} catch (e: any) {
await prosLogger.log(
"OneClick",
Invalid custom Toolchain URL: ${customToolchain}
);
console.log(
"Toolchain Url specified in PROS extension settings was invalid. Using default instead"
);
}
}
return [downloadCli, downloadToolchain, downloadVexcom]; }
export async function install(context: vscode.ExtensionContext) { const preparingInstall = new BackgroundProgress( "Verifying Current PROS Installation", false, true );
await prosLogger.log( "OneClick", "Configuring Environment Variables for PROS" ); await configurePaths(context); await prosLogger.log("OneClick", "Fetching Operating System...."); const system = getOperatingSystem();
await prosLogger.log("OneClick", Operating System Detected: ${system});
await prosLogger.log("OneClick", "Fetching Latest CLI Version....");
let cliVersion, toolchainVersion;
try {
cliVersion = await getCurrentReleaseVersion(
"https://api.github.com/repos/purduesigbots/pros-cli/releases/latest"
);
toolchainVersion = await getCurrentReleaseVersion(
"https://api.github.com/repos/purduesigbots/toolchain/releases/latest"
);
await prosLogger.log("OneClick", CLI Version: ${cliVersion});
} catch (e: any) {
await prosLogger.log("OneClick", "Failed to access version number");
console.log("Hit the rate limit, please try again after some time.");
cliVersion = undefined;
}
let vexcomVersion = "1_0_0_23";
if (cliVersion === undefined || toolchainVersion === undefined) { preparingInstall.stop(); throw new Error("Failed to access version number"); }
// Get system type, path string separator, CLI download url, and toolchain download url.
// Default variables are based on linux.
await prosLogger.log(
"OneClick",
"Fetching CLI and Toolchain Download URLs...."
);
let [downloadCli, downloadToolchain, downloadVexcom] = await getUrls(
cliVersion,
toolchainVersion,
vexcomVersion
);
await prosLogger.log("OneClick", CLI Download URL: ${downloadCli});
await prosLogger.log(
"OneClick",
Toolchain Download URL: ${downloadToolchain}
);
await prosLogger.log("OneClick", Vexcom Download URL: ${downloadVexcom});
// Set the installed file names
var cliName = pros-cli-${system}.zip;
var vexcomName = vex-vexcom-${system}.zip;
var toolchainName = pros-toolchain-${ system === "windows" ? ${system}.zip:${system}.tar.xz };
// Verify that the CLI and toolchain are working before prompting user to install.
await prosLogger.log("OneClick", "Checking Status of CLI and Toolchain....");
// Check if CLI is working, up to date and installed with OneClick
let [cliExecPath, toolchainExecPath] = getIntegratedTerminalPaths(context);
const addQuotes =
system === "macos" && !os.cpus()[0].model.includes("Apple M");
let [currentCliVersion, isOneClickInstall] = await getCurrentVersion(
path.join(
${addQuotes ? ": ""}${cliExecPath}${addQuotes ?" : ""},
"pros"
)
);
let [currentToolchainVersion, isToolchainOneClickInstall] =
await getToolchainVersion(
path.join(
${addQuotes ? ": ""}${toolchainExecPath}${addQuotes ?" : ""},
"bin",
"arm-none-eabi-g++"
)
);
const cliWorking = currentCliVersion !== "0.0.0";
const toolchainWorking = currentToolchainVersion !== "0.0.0";
const vexcomWorking = await verifyVexcom();
//log the result of cli and toolchain working await prosLogger.log(
Use Tool: grep (call_jWCRoNjqT7KZLzZqJDx03Km8)
{
"regex": "bash",
"include_pattern": "pros-vsc/src"
}Tool Results: call_jWCRoNjqT7KZLzZqJDx03Km8
No matches found
Use Tool: read_file (call_txIeXRcr1XJgdUFoxI1N8dBk)
{
"path": "pros-vsc/src/one-click/path.ts",
"start_line": 1,
"end_line": 300
}Tool Results: call_txIeXRcr1XJgdUFoxI1N8dBk
import * as path from "path"; import * as os from "os"; import * as vscode from "vscode"; import { getOperatingSystem } from "./install";
// Returns the path to the PROS CLI and PROS toolchain. // These paths should only be used in the integrated terminal, for some unknown // reason the spaces in the paths need to be escaped differently when running // outside the integrated terminal. export const getIntegratedTerminalPaths = ( context: vscode.ExtensionContext ): [string, string, string] => { const globalPath = context.globalStorageUri.fsPath; const system = getOperatingSystem();
// path to cli
let cliExecPath = ${path.join(globalPath, "install", pros-cli-${system})};
// path to toolchain
let toolchainPath = path.join(
globalPath,
"install",
pros-toolchain-${ system === "windows" ? path.join("windows", "usr") : system }
);
let vexcomPath = path.join(globalPath, "install", vex-vexcom-${system});
if (system === "macos" && !os.cpus()[0].model.includes("Apple M")) { // Escape spaces in paths on Intel Mac cliExecPath = cliExecPath.replace(/(\s+)/g, "\$1"); toolchainPath = toolchainPath.replace(/(\s+)/g, "\$1"); vexcomPath = vexcomPath.replace(/(\s+)/g, "\$1"); }
return [cliExecPath, toolchainPath, vexcomPath]; };
// Returns the path to the PROS CLI.
// This path should only be used in child_process.exec calls, not the
// integrated terminal.
export const getChildProcessPath = (): string | undefined => {
let path = process.env["PATH"];
if (getOperatingSystem() === "macos") {
path = "${path?.replace(/\\/g, "")}";
}
return path;
};
// Returns the path to the PROS Toolchain.
// This path should only be used in child_process.exec calls, not the
// integrated terminal.
export const getChildProcessProsToolchainPath = (): string | undefined => {
let toolchainPath = process.env["PROS_TOOLCHAIN"];
if (getOperatingSystem() === "macos") {
toolchainPath = ${toolchainPath?.replace(/\\/g, "")};
}
return toolchainPath;
};
Use Tool: read_file (call_p58YoBdmqkRGH614HgZPck9M)
{
"path": "pros-vsc/package.json",
"start_line": 1,
"end_line": 200
}Tool Results: call_p58YoBdmqkRGH614HgZPck9M
{ "name": "pros", "displayName": "PROS", "publisher": "sigbots", "description": "PROS Extension that allows for C/C++ Development for VEX V5 and VEX Cortex", "author": { "name": "Purdue ACM SIGBOTS" }, "license": "SEE LICENSE IN LICENSE.txt", "bugs": { "url": "https://github.com/purduesigbots/pros-vsc/issues", "email": "pros_development@cs.purdue.edu" }, "repository": { "type": "git", "url": "https://github.com/purduesigbots/pros-vsc.git" }, "homepage": "http://pros.cs.purdue.edu", "keywords": [ "vex", "v5", "pros", "education", "outreach", "robotics", "vrc", "cortex", "code", "autonomous", "opcontrol" ], "icon": "media/pros-tux-white.png", "galleryBanner": { "color": "#D6B872", "theme": "dark" }, "version": "0.8.2", "engines": { "vscode": "^1.82.0" }, "categories": [ "Other" ], "activationEvents": [ "workspaceContains:**/project.pros", "onCommand:pros.new", "onCommand:pros.welcome", "onCommand:pros.build&upload", "onView:prosTreeview", "onCommand:pros.selectProject" ], "main": "./out/extension.js", "contributes": { "viewsContainers": { "activitybar": [ { "id": "pros-view-container", "title": "PROS", "icon": "media/pros-tux-white.png" } ] }, "views": { "pros-view-container": [ { "id": "prosTreeview", "name": "PROS", "icon": "media/pros-tux-white.png", "contextualTitle": "PROS" }, { "when": "pros.betaFeaturesEnabled", "id": "pros.brainView", "name": "Brain View", "type": "webview", "contextualTitle": "Brain View" } ] }, "icons": { "pros-v5-brain": { "description": "V5 Brain", "default": { "fontPath": "media/vexicon.woff", "fontCharacter": "\E00C" } }, "pros-v5-controller": { "description": "V5 Controller", "default": { "fontPath": "media/vexicon.woff", "fontCharacter": "\E00D" } }, "pros-v5-unknown": { "description": "Unknown V5 Device", "default": { "fontPath": "media/vexicon.woff", "fontCharacter": "\E00A" } } }, "commands": [ { "command": "pros.build&upload", "title": "Build & Upload", "icon": { "light": "media/pros-tux-black.png", "dark": "media/pros-tux-white.png" } }, { "command": "pros.upload", "title": "PROS: Upload" }, { "command": "pros.build", "title": "PROS: Build" }, { "command": "pros.run", "title": "PROS: Run", "icon": { "light": "media/run-tux-black.png", "dark": "media/run-tux-white.png" } }, { "command": "pros.stop", "title": "PROS: Stop", "icon": { "light": "media/stop-tux-black.png", "dark": "media/stop-tux-white.png" } }, { "command": "pros.clean", "title": "PROS: Clean" }, { "command": "pros.terminal", "title": "PROS: Brain Terminal" }, { "command": "pros.showterminal", "title": "PROS: Integrated Terminal" }, { "command": "pros.batterymedic", "title": "PROS: Run Battery Medic" }, { "command": "pros.capture", "title": "PROS: Screenshot V5 Brain" }, { "command": "pros.upgrade", "title": "PROS: Upgrade Project" }, { "command": "pros.new", "title": "PROS: Create New PROS Project" }, { "command": "pros.infoProject", "title": "PROS: Project Information" }, { "command": "pros.resetConductor", "title": "PROS: Reset Conductor" }, { "command": "pros.welcome", "title": "PROS: Welcome" }, { "command": "pros.install", "title": "PROS: Install PROS" }, { "command": "pros.uninstall", "title": "PROS: Uninstall PROS" }, { "command": "pros.verify", "title": "PROS: Verify PROS Installation" }, { "command": "pros.selectProject", "title": "PROS: Select PROS Project" }, { "command": "pros.installVision", "title": "PROS: Install PROS Vision" }, { "command": "pros.uninstallVision", "title": "PROS: Uninstall PROS Vision" }, {
Use Tool: grep (call_OTGYeZ4a0BhRfApkxSMdFL2P)
{
"regex": "configurePaths",
"include_pattern": "pros-vsc/src"
}Tool Results: call_OTGYeZ4a0BhRfApkxSMdFL2P
Found 8 matches:
import {
install,
configurePaths,
uninstall,
cleanup,
installVision,
uninstallVision,
getOperatingSystem,
} from "./one-click/install";
// Sets up paths for integrated terminal (context is the vscode extension context)
await configurePaths(context);
// If we are in a pros project, set the variable which tracks that to true and set everything up
"Configuring Environment Variables for PROS"
);
await configurePaths(context);
await prosLogger.log("OneClick", "Fetching Operating System....");
const system = getOperatingSystem();
await chmod(globalPath.fsPath, system);
await prosLogger.log("OneClick", `Configuring environment variables`);
await configurePaths(context).catch((e) => {
prosLogger.log("OneClick", e, "ERROR");
});
export async function configurePaths(
context: vscode.ExtensionContext,
repeat: boolean = true
) {
await prosLogger.log("OneClick", "Getting paths for integrated terminal");
let [cliExecPath, toolchainPath, vexcomPath] =
getIntegratedTerminalPaths(context);
// return if the path is already configured
const addQuotes =
getOperatingSystem() === "macos" && !os.cpus()[0].model.includes("Apple M");
99 lines remaining in ancestor node. Read the file to see all.
if (repeat) {
configurePaths(context, false); // recursive call to ensure that the path is configured. This is necessary because Macs are stupid and need the PATH updated twice for some reason.
}
import * as vscode from "vscode";
import * as path from "path";
import * as fs from "fs";
import { promisify } from "util";
import { getOperatingSystem } from "./one-click/install";
import { getChildProcessProsToolchainPath } from "./one-click/path";
import { configurePaths } from "./one-click/install";
/**
* This function searches a directory of the workspace for a file with the given name
*
420 lines remaining in ancestor node. Read the file to see all.
// If there is not already a terminal named "PROS Terminal" or it does not have the correct path, create a new one.
await configurePaths(context); // Configure the paths (see install.ts) so that everything runs properly when you click a button
// Create a new terminal with the correct path, return it.
Use Tool: read_file (call_fE1P1F6vMdLOjmeejUlBA6UG)
{
"path": "pros-vsc/src/one-click/install.ts",
"start_line": 600,
"end_line": 800
}Tool Results: call_fE1P1F6vMdLOjmeejUlBA6UG
}
await prosLogger.log(
"OneClick",
`Verifying that CLI and Toolchain are working`
);
await chmod(globalPath.fsPath, system);
await prosLogger.log("OneClick", `Configuring environment variables`);
await configurePaths(context).catch((e) => {
prosLogger.log("OneClick", e, "ERROR");
});
// Ensure that toolchain and cli are working
let cliSuccess = await verifyCli();
let toolchainSuccess = await verifyToolchain();
let vexcomSuccess = await verifyVexcom();
if (cliSuccess && toolchainSuccess && vexcomSuccess) {
vscode.window.showInformationMessage(
"CLI and Toolchain are working!"
);
} else {
vscode.window.showErrorMessage(
`${cliSuccess && vexcomSuccess ? "" : "CLI"}
${!cliSuccess && !toolchainSuccess && !vexcomSuccess ? " and " : ""}
${toolchainSuccess ? "" : "Toolchain"}
Installation Failed!`
);
vscode.window.showInformationMessage(
`Please try installing again! If this problem persists, consider trying an alternative install method: https://pros.cs.purdue.edu/v5/getting-started/${system}.html`
);
}
} catch (err: any) {
vscode.window.showInformationMessage("FATAL ERROR DURING VERIFICATION");
prosLogger.log("OneClick", err, "ERROR");
}
}
); }
export async function configurePaths( context: vscode.ExtensionContext, repeat: boolean = true ) { await prosLogger.log("OneClick", "Getting paths for integrated terminal"); let [cliExecPath, toolchainPath, vexcomPath] = getIntegratedTerminalPaths(context);
// return if the path is already configured
const addQuotes =
getOperatingSystem() === "macos" && !os.cpus()[0].model.includes("Apple M");
// Check if user has CLI installed through one-click or other means.
await prosLogger.log("OneClick", "Checking How CLI is installed");
let [version, isOneClickInstall] = await getCurrentVersion(
path.join(
${addQuotes ? ": ""}${cliExecPath}${addQuotes ?" : ""},
"pros"
)
);
let [currentToolchainVersion, isToolchainOneClickInstall] =
await getToolchainVersion(
path.join(
${addQuotes ? ": ""}${toolchainPath}${addQuotes ?" : ""},
"bin",
"arm-none-eabi-g++"
)
);
process.env["PROS_VSCODE_FLAGS"] = semver.gte(
semver.coerce(version) ?? "0.0.0",
"3.2.4"
)
? "--no-sentry --no-analytics"
: "";
await prosLogger.log(
"OneClick",
CLI is installed through ${ isOneClickInstall ? "one-click" : "other means" } with version ${version}
);
await prosLogger.log(
"OneClick",
Toolchain is installed through ${ isToolchainOneClickInstall ? "one-click" : "other means" } with version ${currentToolchainVersion}
);
console.log(${isOneClickInstall} | ${version});
PATH_SEP = getOperatingSystem() === "windows" ? ";" : ":";
if (PATH_SEP === ":") { cliExecPath = cliExecPath.replace(/\/g, ""); toolchainPath = toolchainPath.replace(/\/g, ""); vexcomPath = vexcomPath.replace(/\/g, ""); } TOOLCHAIN = process.env["PROS_TOOLCHAIN"] ?? toolchainPath; // Set CLI environmental variable file location CLI_EXEC_PATH = cliExecPath;
let pathCliCount: number = process.env["PATH"]?.split(PATH_SEP).filter((x) => x.includes(cliExecPath)) .length ?? 0; let pathToolchainCount: number = process.env["PATH"] ?.split(PATH_SEP) .filter((x) => x.includes(toolchainPath)).length ?? 0; let pathVexcomCount: number = process.env["PATH"]?.split(PATH_SEP).filter((x) => x.includes(vexcomPath)) .length ?? 0;
prosLogger.log("OneClick", CLI path count: ${pathCliCount});
prosLogger.log("OneClick", Toolchain path count: ${pathToolchainCount});
prosLogger.log("OneClick", Vexcom path count: ${pathVexcomCount});
console.log(CLI path count: ${pathCliCount});
console.log(Toolchain path count: ${pathToolchainCount});
console.log(Vexcom path count: ${pathVexcomCount});
if (
pathCliCount > 2 &&
pathToolchainCount > 2 &&
pathVexcomCount > 2 &&
process.env["PROS_TOOLCHAIN"]?.includes(TOOLCHAIN)
) {
console.log("path already configured");
await prosLogger.log("OneClick", "PATH is already configured");
return;
}
// Prepend CLI and TOOLCHAIN to path
await prosLogger.log("OneClick", "Appending CLI and TOOLCHAIN to PATH");
await prosLogger.log("OneClick", CLI Executable Path: ${cliExecPath});
process.env.PATH = ${process.env.PATH}; // bypass compile errors
await prosLogger.log("OneClick", process.env.PATH ?? "no PATH", "INFO");
process.env.PATH =
${cliExecPath}${PATH_SEP} +
${path.join(toolchainPath, "bin")}${PATH_SEP} +
${vexcomPath}${PATH_SEP} +
${process.env.PATH.replace(/\"/g, "")};
await prosLogger.log("OneClick", process.env.PATH ?? "no PATH", "INFO");
// Make PROS_TOOLCHAIN variable
await prosLogger.log("OneClick", "Setting PROS_TOOLCHAIN");
process.env.PROS_TOOLCHAIN = TOOLCHAIN;
await prosLogger.log(
"OneClick",
"PROS_TOOLCHAIN: " + process.env.PROS_TOOLCHAIN,
"INFO"
);
process.env.LC_ALL = "en_US.utf-8"; if (repeat) { configurePaths(context, false); // recursive call to ensure that the path is configured. This is necessary because Macs are stupid and need the PATH updated twice for some reason. } }
async function verifyCli() {
var command = pros --version ${process.env["PROS_VSCODE_FLAGS"]};
await prosLogger.log("OneClick", Verifying CLI with command ${command});
try {
const { stdout, stderr } = await promisify(child_process.exec)(command, {
timeout: 30000,
env: {
...process.env,
// eslint-disable-next-line @typescript-eslint/naming-convention
PATH: getChildProcessPath(),
},
});
if (stderr) {
await prosLogger.log(
"OneClick",
CLI verification failed with error ${stderr},
"ERROR"
);
console.error(stderr);
}
return stdout.startsWith("pros, version");
} catch (err) {
prosLogger.log(
"OneClick",
CLI verification failed with error ${err},
"ERROR"
);
console.error(err);
return false;
}
}
async function verifyToolchain() { await prosLogger.log("OneClick", "Verifying TOOLCHAIN");
let toolchainPath = getChildProcessProsToolchainPath() ?? ""; if (!toolchainPath) { await prosLogger.log("OneClick", "No valid toolchain path found", "error"); return false; }
await prosLogger.log("OneClick", Using toolchain path ${toolchainPath});
let command = "${path.join( toolchainPath, "bin", "arm-none-eabi-g++" )}" --version;
console.log(command);
await prosLogger.log(
"OneClick",
The magic really boils down to how we cheat the Windows shell into “seeing” a whole folder‐full of Linux-flavored executables, by prepending our PROS toolchain and CLI directories onto the user’s PATH and then spinning up the integrated terminal with that augmented environment.
-
We calculate three install paths (CLI, toolchain, vexcom) in
export const getIntegratedTerminalPaths = ( context: vscode.ExtensionContext ): [string, string, string] => { const globalPath = context.globalStorageUri.fsPath; const system = getOperatingSystem(); // On Windows this ends up pointing at: // <storage>/install/pros-cli-windows let cliExecPath = path.join(globalPath, "install", `pros-cli-${system}`); // and // <storage>/install/pros-toolchain-windows-formatted/usr let toolchainPath = path.join( globalPath, "install", `pros-toolchain-windows-formatted`, "usr" ); // … return [cliExecPath, toolchainPath, vexcomPath]; }; -
During activation (and again every time you open the “PROS Terminal”), we call
// Prepend our CLI & toolchain into the PATH so that all their GNU‐style // binaries (sh, ls, grep, make, arm-none-eabi-g++, pros, …) are first in line. process.env.PATH = `${cliExecPath}${PATH_SEP}` + `${path.join(toolchainPath, "bin")}${PATH_SEP}` + `${vexcomPath}${PATH_SEP}` + `${process.env.PATH.replace(/\"/g, "")}`; // Export PROS_TOOLCHAIN for child processes process.env.PROS_TOOLCHAIN = TOOLCHAIN; -
Finally we hand that patched
process.envoff to VS Code when creating the terminal:// Ensure our PROS CLI + GNU toolchain are on the PATH await configurePaths(context); // Launch the terminal with our modified env return vscode.window.createTerminal({ name: "PROS Terminal", env: process.env, }); });
Because the “windows-formatted” toolchain bundle actually contains Windows binaries of the familiar GNU/UNIX tools (e.g. sh.exe, ls.exe, grep.exe, make.exe, arm-none-eabi-g++.exe, etc.) and we stick its bin folder at the front of the PATH, you can open “PROS Terminal” on Windows and use essentially the same Linux/UNIX commands you’d have on macOS or Linux.