Skip to content

Commit 9931281

Browse files
feat: refactored CLI binary location to be more resilient (#172)
Following options added to the settings * dataformExecutablePath * gcloudExecutablePath
1 parent 12c41e8 commit 9931281

File tree

6 files changed

+594
-329
lines changed

6 files changed

+594
-329
lines changed

package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,18 @@
265265
"default": "global",
266266
"markdownDescription": "Dataform installation scope to use. Default to `global` which uses the dataform cli installed in global scope when running `dataform install -g @dataform/cli`. Selecting `local` scope would mean dataform cli installation in your workspace folder in `./node_modules/.bin/dataform` will be used. This is created when `npm install @dataform/cli` is ran from the root of the workspace folder."
267267
},
268+
"vscode-dataform-tools.dataformExecutablePath": {
269+
"type": "string",
270+
"default": null,
271+
"markdownDescription": "**Override path to dataform executable**\n\n⚠️ **Only use this if the extension cannot find dataform automatically**\n\nThe extension automatically searches:\n- System PATH\n- Common tool managers (mise, asdf, nvm, etc.)\n- Standard installation locations\n\nUse this setting for:\n- **Specific versions** for testing: `/path/to/dataform-v3.0.25`\n- **Company-approved versions**: `/opt/company-tools/dataform`\n- **Non-standard locations**: Custom installation paths\n\n**Example**: `/usr/local/bin/dataform` or `${HOME}/.local/share/mise/installs/npm-dataform-cli/3.0.26/bin/dataform`",
272+
"pattern": "^.*dataform(?:\\.cmd|\\.exe)?$"
273+
},
274+
"vscode-dataform-tools.gcloudExecutablePath": {
275+
"type": "string",
276+
"default": null,
277+
"markdownDescription": "**Override path to gcloud executable**\n\n⚠️ **Only use this if the extension cannot find gcloud automatically**\n\nThe extension automatically searches:\n- System PATH\n- Common tool managers (mise, asdf, etc.)\n- Standard gcloud installation locations\n\nUse this setting for:\n- **Specific versions** for testing: `/path/to/gcloud-v530.0.0`\n- **Company-approved versions**: `/opt/company-tools/gcloud`\n- **Non-standard locations**: Custom installation paths\n\n**Example**: `/usr/local/bin/gcloud` or `${HOME}/google-cloud-sdk/bin/gcloud`",
278+
"pattern": "^.*gcloud(?:\\.cmd|\\.exe)?$"
279+
},
268280
"vscode-dataform-tools.compileAndDryRunBeforeFormatting": {
269281
"type": "boolean",
270282
"default": true,

src/constants.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { getWorkspaceFolder } from './utils';
55

66
const tempDir = os.tmpdir();
77
export const sqlFileToFormatPath = path.join(tempDir, "format.sql");
8-
export const executablesToCheck = ['dataform', 'gcloud'];
8+
export const executablesToCheck: ('dataform' | 'gcloud')[] = ['dataform', 'gcloud'];
99
export const tableQueryOffset = 2;
1010
export const incrementalTableOffset = 1;
1111
export const assertionQueryOffset = 4;
@@ -105,15 +105,17 @@ export const sqlKeywordsToExcludeFromHoverDefinition = [
105105
"qualify"
106106
];
107107

108+
export const cacheDurationMs = 5 * 60 * 1000; // 5 minutes
108109

109-
export async function getFileNotFoundErrorMessageForWebView(relativeFilePath:string){
110110

111-
if(!workspaceFolder){
112-
workspaceFolder = await getWorkspaceFolder();
113-
}
114-
115-
// Create a single HTML string with the error message
116-
const errorMessage = `
111+
export async function getFileNotFoundErrorMessageForWebView(relativeFilePath: string) {
112+
113+
if (!workspaceFolder) {
114+
workspaceFolder = await getWorkspaceFolder();
115+
}
116+
117+
// Create a single HTML string with the error message
118+
const errorMessage = `
117119
<div>
118120
<p>File <b>"${relativeFilePath}"</b> not found in Dataform compiled json with workspace folder <b>"${workspaceFolder}"</b></p>
119121
<p>Ignore the error if the file you are in is not expected to produce a sql output</p>
@@ -134,6 +136,6 @@ export async function getFileNotFoundErrorMessageForWebView(relativeFilePath:str
134136
</ol>
135137
</div>
136138
`;
137-
138-
return errorMessage;
139+
140+
return errorMessage;
139141
}

src/extension.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export async function activate(context: vscode.ExtensionContext) {
3838
});
3939

4040
globalThis.CACHED_COMPILED_DATAFORM_JSON = undefined as DataformCompiledJson | undefined;
41-
logger.debug('Initialized global cache');
41+
logger.debug('Extension activated - initialized global cache (CACHED_COMPILED_DATAFORM_JSON = undefined)');
4242
globalThis.declarationsAndTargets = [] as string[];
4343
globalThis.dataformTags = [] as string[];
4444
globalThis.isRunningOnWindows = os.platform() === 'win32' ? true : false;
@@ -70,7 +70,8 @@ export async function activate(context: vscode.ExtensionContext) {
7070

7171
for (let i = 0; i < executablesToCheck.length; i++) {
7272
let executable = executablesToCheck[i];
73-
executableIsAvailable(executable);
73+
logger.debug(`Checking executable availability: ${executable}`);
74+
executableIsAvailable(executable, true); // Show error if not found
7475
}
7576

7677
// Clean up on deactivation

src/types.ts

Lines changed: 52 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ export interface Table {
1717
incrementalPreOps: string[];
1818
dependencyTargets: Target[];
1919
bigquery: TableBigQueryConfig;
20-
actionDescriptor:ActionDescription;
20+
actionDescriptor: ActionDescription;
2121
}
2222

23-
export interface ActionDescription{
23+
export interface ActionDescription {
2424
description: string;
2525
columns: Column[]
2626
}
@@ -31,7 +31,7 @@ export interface Column {
3131
}
3232

3333
export interface QueryMeta {
34-
type:string,
34+
type: string,
3535
tableOrViewQuery: string
3636
nonIncrementalQuery: string
3737
incrementalQuery: string
@@ -117,7 +117,7 @@ export interface Operation {
117117
bigquery?: TableBigQueryConfig;
118118
}
119119

120-
type GraphErrors = {
120+
type GraphErrors = {
121121
compilationErrors: {
122122
fileName: string,
123123
message: string,
@@ -150,7 +150,7 @@ export interface ConfigBlockMetadata {
150150
exists: boolean;
151151
}
152152

153-
interface BlockMeta{
153+
interface BlockMeta {
154154
startLine: number;
155155
endLine: number;
156156
exists: boolean;
@@ -189,20 +189,20 @@ export interface TableBigQueryConfig {
189189
}
190190

191191
export type GraphError = {
192-
error: string;
193-
fileName: string;
192+
error: string;
193+
fileName: string;
194194
};
195195

196196
export interface ColumnMetadata {
197197
name: string;
198198
type: string;
199199
mode?: string;
200-
description?:string;
200+
description?: string;
201201
};
202202

203203
export interface ErrorLocation {
204-
line: number;
205-
column: number;
204+
line: number;
205+
column: number;
206206
};
207207

208208
interface DryRunErorr {
@@ -216,7 +216,7 @@ export interface BigQueryDryRunResponse {
216216
location: string | undefined;
217217
statistics: {
218218
totalBytesProcessed: number;
219-
cost?:{
219+
cost?: {
220220
currency: string
221221
value: number
222222
};
@@ -227,11 +227,11 @@ export interface BigQueryDryRunResponse {
227227
}
228228

229229
export interface CompiledQuerySchema {
230-
fields: ColumnMetadata[];
230+
fields: ColumnMetadata[];
231231
}
232232

233233
export type Metadata = {
234-
type:string,
234+
type: string,
235235
description: string,
236236
fullTableId: string,
237237
};
@@ -241,32 +241,32 @@ export type SchemaMetadata = {
241241
};
242242

243243
export type CurrentFileMetadata = {
244-
isDataformWorkspace?: boolean;
245-
errors?: { errorGettingFileNameFromDocument?:string, dataformCompilationErrors?: GraphError[]; fileNotFoundError?: boolean; queryMetaError?: string | undefined}
246-
fileMetadata?: TablesWtFullQuery;
247-
possibleResolutions?: any[];
248-
dependents?: any;
249-
lineageMetadata?: {
250-
dependencies: undefined;
251-
error: undefined;
252-
};
253-
pathMeta?: {
254-
filename: string;
255-
extension: string;
256-
relativeFilePath: string;
257-
};
258-
document?: TextDocument;
244+
isDataformWorkspace?: boolean;
245+
errors?: { errorGettingFileNameFromDocument?: string, dataformCompilationErrors?: GraphError[]; fileNotFoundError?: boolean; queryMetaError?: string | undefined }
246+
fileMetadata?: TablesWtFullQuery;
247+
possibleResolutions?: any[];
248+
dependents?: any;
249+
lineageMetadata?: {
250+
dependencies: undefined;
251+
error: undefined;
252+
};
253+
pathMeta?: {
254+
filename: string;
255+
extension: string;
256+
relativeFilePath: string;
257+
};
258+
document?: TextDocument;
259259
};
260260

261261
export type TagDryRunStats = {
262-
type: string;
263-
targetName: string;
264-
costOfRunningModel: number;
265-
currency: SupportedCurrency;
266-
totalGBProcessed: string;
267-
totalBytesProcessedAccuracy: string | undefined;
268-
statementType: string | undefined;
269-
error: string
262+
type: string;
263+
targetName: string;
264+
costOfRunningModel: number;
265+
currency: SupportedCurrency;
266+
totalGBProcessed: string;
267+
totalBytesProcessedAccuracy: string | undefined;
268+
statementType: string | undefined;
269+
error: string
270270
};
271271

272272
export type TagDryRunStatsMeta = {
@@ -275,13 +275,13 @@ export type TagDryRunStatsMeta = {
275275
};
276276

277277
export const supportedCurrencies = {
278-
USD: "USD",
279-
EUR: "EUR",
280-
GBP: "GBP",
281-
JPY: "JPY",
282-
CAD: "CAD",
283-
AUD: "AUD",
284-
INR: "INR",
278+
USD: "USD",
279+
EUR: "EUR",
280+
GBP: "GBP",
281+
JPY: "JPY",
282+
CAD: "CAD",
283+
AUD: "AUD",
284+
INR: "INR",
285285
} as const;
286286

287287
export type SupportedCurrency = keyof typeof supportedCurrencies;
@@ -308,4 +308,12 @@ export type ErrorMeta = {
308308
nonIncrementalError?: DryRunError;
309309
incrementalError?: DryRunError;
310310
assertionError?: DryRunError;
311-
};
311+
};
312+
313+
export type ExecutablePathInfo = {
314+
path: string | null;
315+
timestamp: number;
316+
};
317+
318+
export type ExecutablePathCache = Map<string, ExecutablePathInfo>;
319+

0 commit comments

Comments
 (0)