Skip to content

Commit

Permalink
[vscode][8/n] Setup Env Variables: Use lowest common ancestor path fo…
Browse files Browse the repository at this point in the history
…r multiple workspaces (#1329)

[vscode][8/n] Setup Env Variables: Use lowest common ancestor path for
multiple workspaces

Somewhat slightly checked out in
https://gitlab.com/sebdeckers/lowest-common-ancestor/-/blob/master/src/index.js?ref_type=heads,
but didn't want to use this package since:

1. It doesn't have exact functionality I want (ex: if only 1 path
provided, it returns empty string)
2. Don't want something small to depend on a package when we can control
it ourselves

Some VS Code setups can have multiple workspaces, in which case we
should take the lowest common ancestor path that is shared across all of
them so that the same .env file can be used for multiple AIConfig files.
Initial comment from Sarmad in
#1291 (comment)

## Test Plan

Tested it with my vscode settings (only 1 workspace path) and no
functional changes


https://github.com/lastmile-ai/aiconfig/assets/151060367/a82eb30f-c951-4f27-aa8f-2b9353089c4e

To test, I also hardcoded some paths to ensure that this works with
multiple workspaces


https://github.com/lastmile-ai/aiconfig/assets/151060367/3110c87c-d3db-40bb-8dc2-6f0f15544d32

The nothing in common use case returns empty string, so no validation
will occur in that case



https://github.com/lastmile-ai/aiconfig/assets/151060367/e4b6fad8-feea-40b2-a339-973acf279520

I'd also love to test this in Windows just to 100% sanity check, though
the `path.sep` should ensure that it still works

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with
[ReviewStack](https://reviewstack.dev/lastmile-ai/aiconfig/pull/1329).
* #1346
* #1345
* #1343
* #1341
* #1340
* __->__ #1329
  • Loading branch information
rossdanlm authored Feb 25, 2024
2 parents cd4a256 + 5e03b0a commit 144d159
Showing 1 changed file with 42 additions and 9 deletions.
51 changes: 42 additions & 9 deletions vscode-extension/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,17 +310,12 @@ export async function setupEnvironmentVariables(
) {
const homedir = require("os").homedir(); // This is cross-platform: https://stackoverflow.com/a/9081436
const defaultEnvPath = path.join(homedir, ".env");

// TODO: If there are multiple workspace folders, use common lowest
// ancestor as workspacePath: https://github.com/lastmile-ai/aiconfig/issues/1299
const workspacePath = vscode.workspace.workspaceFolders
? vscode.workspace.workspaceFolders[0].uri.fsPath
: null;
const lowestCommonWorkspacePath = getLowestCommonAncestorAcrossWorkspaces();

const envPath = await vscode.window.showInputBox({
prompt: "Enter the path of your .env file",
value: defaultEnvPath,
validateInput: (input) => validateEnvPath(input, workspacePath),
validateInput: (input) => validateEnvPath(input, lowestCommonWorkspacePath),
});

if (!envPath) {
Expand Down Expand Up @@ -403,15 +398,53 @@ export function validateNewConfigName(name: string, mode: "json" | "yaml") {
return null;
}

/**
* Some VS Code setups can have multiple workspaces, in which
* case we should take the lowest common ancestor path that is shared
* across all of them so that the same .env file can be used for multiple
* AIConfig files
* @returns lowestCommonAncestorPath (string | undefined)
* -> string of path to lowest common ancestor: empty means no shared path
* -> undefined if no workspaces are defined in VS Code session
*/
function getLowestCommonAncestorAcrossWorkspaces(): string | undefined {
const workspaceFolders = vscode.workspace.workspaceFolders;
if (workspaceFolders === undefined || workspaceFolders.length === 0) {
return undefined;
}

const workspacePaths = workspaceFolders.map((folder) =>
path.normalize(folder.uri.fsPath)
);
let lowestCommonAncestorPath: string;
const separator = path.sep; // Handles Windows and Linux
lowestCommonAncestorPath = workspacePaths.reduce(
(currLowestCommonAncestorPath, currPath) => {
const ancestorFolders = currLowestCommonAncestorPath.split(separator);
const currPathFolders = currPath.split(separator);
const commonPathFolders: Array<string> = [];
for (var i = 0; i < ancestorFolders.length; i++) {
if (ancestorFolders[i] === currPathFolders[i]) {
commonPathFolders.push(ancestorFolders[i]);
} else {
break;
}
}
return commonPathFolders.join(separator);
}
);
return lowestCommonAncestorPath;
}

function validateEnvPath(
inputPath: string,
workspacePath: string | null
workspacePath: string | undefined
): string | null {
if (!inputPath) {
return "File path is required";
} else if (path.basename(inputPath) !== ".env") {
return 'Filename must be ".env"';
} else if (workspacePath !== null) {
} else if (workspacePath != null && workspacePath !== "") {
// loadenv() from Python checks each folder from the file/program where
// it's invoked for the presence of an `.env` file. Therefore, the `.env
// file must be saved either at the top-level directory of the workspace
Expand Down

0 comments on commit 144d159

Please sign in to comment.