Skip to content

Commit 55f6f52

Browse files
authored
SPL2 notebooks download/use the latest SPL2 language server by default (#115)
* Enable SPL2 notebooks to download/use the latest SPL2 language server by default. Also scope machine-specific installation settings (e.g. local paths) to only be tracked per-machine as opposed to across all users' machines. * Adding version to logs * Revert to latest LSP version as backup value
1 parent 37d2082 commit 55f6f52

File tree

4 files changed

+78
-35
lines changed

4 files changed

+78
-35
lines changed

out/extension.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const splunkCustomCommand = require('./customCommand.js');
1212
const globalConfigPreview = require('./globalConfigPreview')
1313
const splunkCustomRESTHandler = require('./customRESTHandler.js')
1414
const splunkSpec = require("./spec.js");
15-
const PLACEHOLDER_REGEX = /\<([^\>]+)\>/g
15+
const PLACEHOLDER_REGEX = /\<([^\>]+)\>/g;
1616
let specConfigs = {};
1717
let timeout;
1818
let diagnosticCollection;

out/notebooks/spl2/initializer.ts

+13-12
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,7 @@ export async function startSpl2ClientAndServer(globalStoragePath: string, progre
7777
return;
7878
}
7979
const lspPath = path.join(getLocalLspDir(globalStoragePath), getLspFilename(lspVersion));
80-
81-
const server = new Spl2ClientServer(progressBar, javaPath, lspPath, portToAttempt, onClose);
80+
const server = new Spl2ClientServer(progressBar, javaPath, lspVersion, lspPath, portToAttempt, onClose);
8281
await server.initialize();
8382
resolve(server);
8483
} catch (err) {
@@ -90,6 +89,7 @@ export async function startSpl2ClientAndServer(globalStoragePath: string, progre
9089
export class Spl2ClientServer {
9190
progressBar: StatusBarItem;
9291
javaPath: string;
92+
lspVersion: string;
9393
lspPath: string;
9494
retries: number;
9595
restarting: boolean;
@@ -101,9 +101,10 @@ export class Spl2ClientServer {
101101
serverProcess: child_process.ChildProcess;
102102
socket: Socket;
103103

104-
constructor(progressBar: StatusBarItem, javaPath: string, lspPath: string, portToAttempt: number, onClose: (nextPort: number) => void) {
104+
constructor(progressBar: StatusBarItem, javaPath: string, lspVersion: string, lspPath: string, portToAttempt: number, onClose: (nextPort: number) => void) {
105105
this.progressBar = progressBar;
106106
this.javaPath = javaPath;
107+
this.lspVersion = lspVersion;
107108
this.lspPath = lspPath;
108109
this.retries = 0;
109110
this.restarting = false;
@@ -116,15 +117,15 @@ export class Spl2ClientServer {
116117
}
117118

118119
async initialize(): Promise<void> {
119-
this.progressBar.text = 'Starting SPL2 Language Server';
120+
this.progressBar.text = `Starting SPL2 Language Server v${this.lspVersion}`;
120121
this.progressBar.show();
121122
return new Promise(async (resolve, reject) => {
122123
this.lspPort = await getNextAvailablePort(this.portToAttempt, 10)
123124
.catch((err) => {
124-
reject(`Unable to find available port for SPL2 language server, err: ${err}`);
125+
reject(`Unable to find available port for SPL2 language server v${this.lspVersion}, err: ${err}`);
125126
}) || -1;
126127
if (this.lspPort === -1) {
127-
reject(`Unable to find available port for SPL2 language server`);
128+
reject(`Unable to find available port for SPL2 language server v${this.lspVersion}`);
128129
return;
129130
}
130131

@@ -160,11 +161,11 @@ export class Spl2ClientServer {
160161
// TODO: implement module resolution
161162
return;
162163
});
163-
this.progressBar.text = 'SPL2 Language Server Running';
164+
this.progressBar.text = `SPL2 Language Server v${this.lspVersion} Running`;
164165
} else if (event.newState === State.Starting) {
165-
this.progressBar.text = 'SPL2 Language Server Starting';
166+
this.progressBar.text = `SPL2 Language Server v${this.lspVersion} Starting`;
166167
} else {
167-
this.progressBar.text = 'SPL2 Language Server Stopped';
168+
this.progressBar.text = `SPL2 Language Server v${this.lspVersion} Stopped`;
168169
}
169170
this.progressBar.show();
170171
});
@@ -192,10 +193,10 @@ export class Spl2ClientServer {
192193
];
193194
this.serverProcess = child_process.spawn(this.javaPath, javaArgs);
194195
if (!this.serverProcess || !this.serverProcess.pid) {
195-
reject(`Launching server with ${this.javaPath} ${javaArgs.join(' ')} failed.`);
196+
reject(`Launching language server v${this.lspVersion} with ${this.javaPath} ${javaArgs.join(' ')} failed.`);
196197
return;
197198
} else {
198-
console.log(`SPL2 Language Server launched with pid: ${this.serverProcess.pid} and listening on port: ${this.lspPort}`);
199+
console.log(`SPL2 Language Server v${this.lspVersion} launched with pid: ${this.serverProcess.pid} and listening on port: ${this.lspPort}`);
199200
}
200201
this.serverProcess.stderr.on('data', stderr => {
201202
console.warn(`[SPL2 Server]: ${stderr}`);
@@ -218,7 +219,7 @@ export class Spl2ClientServer {
218219
console.log(`[SPL2 Server]: ${stdout}`);
219220
const lspLog: LSPLog = JSON.parse(stdout);
220221
if (lspLog.message.includes('started listening on port')) {
221-
console.log('SPL2 Server is up, starting client...');
222+
console.log(`SPL2 Server v${this.lspVersion} is up, starting client...`);
222223
// Ready for client
223224
this.socket = new Socket();
224225

out/notebooks/spl2/installer.ts

+54-19
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ export const configKeyAcceptedTerms = 'splunk.spl2.acceptedTerms';
1515
export const configKeyJavaPath = 'splunk.spl2.javaPath';
1616
export const configKeyLspDirectory = 'splunk.spl2.languageServerDirectory';
1717
export const configKeyLspVersion = 'splunk.spl2.languageServerVersion';
18-
19-
export const stateKeyLatestLspVersion = 'splunk.spl2.latestLspVersion';
20-
export const stateKeyLastLspCheck = 'splunk.spl2.lastLspCheck';
18+
export const configKeyDownloadLatestSPL2 = 'splunk.spl2.downloadLatestSPL2';
2119

2220
// Minimum version of Java needed for SPL2 Language Server
2321
const minimumMajorJavaVersion = 17;
@@ -518,17 +516,28 @@ async function promptToDownloadLsp(alsoInstallJava: boolean): Promise<boolean> {
518516
}
519517

520518
/**
521-
* Checks if the installed SPL2 Language Server version is the latest and prompt for
522-
* upgrade if not, or automatically upgrade if user has that setting enabled.
519+
* Checks if the installed SPL2 Language Server version is the latest and
520+
* automatically upgrade if user has that setting enabled.
523521
*/
524522
export async function getLatestSpl2Release(globalStoragePath: string, progressBar: StatusBarItem): Promise<void> {
525523
return new Promise(async (resolve, reject) => {
526524
const lspArtifactPath = getLocalLspDir(globalStoragePath);
527-
// TODO: Remove this hardcoded version/update time and check for updates
528-
let latestLspVersion: string = '2.0.385';
529-
const lastUpdateMs: number = Date.now();
530-
// Don't check for new version of SPL2 Language Server if less than 24 hours since last check
531-
if (Date.now() - lastUpdateMs > 24 * 60 * 60 * 1000) {
525+
const shouldDownloadLatest = workspace.getConfiguration().get(configKeyDownloadLatestSPL2);
526+
// Used as backup if latest version can't be determined or current version is invalid
527+
let lspVersionToInstall = '2.0.402'
528+
// If user has unchecked the option to always download the latest LSP then
529+
// check if the current specified version is installed, if not then download it
530+
const currentLspVersion: string = workspace.getConfiguration().get(configKeyLspVersion);
531+
const parsedCurrentVersion = parseLspVersion(currentLspVersion);
532+
533+
if (!shouldDownloadLatest && (parsedCurrentVersion.length >= 3)) {
534+
// If the current version is valid and the user has elected not to download a new one
535+
// then we are done
536+
lspVersionToInstall = currentLspVersion;
537+
}
538+
// If not using current version, determine latest available
539+
if (lspVersionToInstall !== currentLspVersion) {
540+
// Determine the latest LSP version using maven metadata from jfrog
532541
const metaPath = path.join(lspArtifactPath, 'maven-metadata.xml');
533542
try {
534543
await downloadWithProgress(
@@ -540,27 +549,35 @@ export async function getLatestSpl2Release(globalStoragePath: string, progressBa
540549
const parser = new XMLParser();
541550
const metadata = fs.readFileSync(metaPath);
542551
const metaParsed = parser.parse(metadata);
543-
latestLspVersion = metaParsed?.metadata?.versioning?.release;
552+
let latestCandidate = metaParsed?.metadata?.versioning?.release;
553+
const parsedCandidate = parseLspVersion(latestCandidate);
554+
if (parsedCandidate.length >= 3) {
555+
// Valid latest version found, update to use this
556+
lspVersionToInstall = latestCandidate;
557+
}
544558
} catch (err) {
545559
console.warn(`Error retrieving latest SPL2 version, err: ${err}`);
546560
}
547561
}
548-
const currentLspVersion = workspace.getConfiguration().get(configKeyLspVersion);
549-
if (currentLspVersion === latestLspVersion) {
550-
resolve();
551-
return Promise.resolve();
552-
}
553562
// Check if latest version has already been downloaded
554-
const lspFilename = getLspFilename(latestLspVersion);
563+
const lspFilename = getLspFilename(lspVersionToInstall);
555564
const localLspPath = path.join(getLocalLspDir(globalStoragePath), lspFilename);
556565
// Check if local file exists before downloading
557566
if (fs.existsSync(localLspPath)) {
567+
if (lspVersionToInstall !== currentLspVersion) {
568+
try {
569+
await workspace.getConfiguration().update(configKeyLspVersion, lspVersionToInstall, true);
570+
} catch (err) {
571+
reject(`Error updating configuration '${configKeyLspVersion}', err: ${err}`);
572+
return Promise.resolve();
573+
}
574+
}
558575
resolve();
559576
return Promise.resolve();
560577
}
561578
try {
562579
await downloadWithProgress(
563-
`https://splunk.jfrog.io/splunk/maven-splunk/spl2/com/splunk/spl/spl-lang-server-sockets/${latestLspVersion}/${lspFilename}`,
580+
`https://splunk.jfrog.io/splunk/maven-splunk/spl2/com/splunk/spl/spl-lang-server-sockets/${lspVersionToInstall}/${lspFilename}`,
564581
localLspPath,
565582
progressBar,
566583
'Downloading SPL2 Language Server',
@@ -571,7 +588,7 @@ export async function getLatestSpl2Release(globalStoragePath: string, progressBa
571588
}
572589
// Update this setting to indicate that this version is ready-to-use
573590
try {
574-
await workspace.getConfiguration().update(configKeyLspVersion, latestLspVersion, true);
591+
await workspace.getConfiguration().update(configKeyLspVersion, lspVersionToInstall, true);
575592
} catch (err) {
576593
reject(`Error updating configuration '${configKeyLspVersion}', err: ${err}`);
577594
return Promise.resolve();
@@ -580,6 +597,24 @@ export async function getLatestSpl2Release(globalStoragePath: string, progressBa
580597
});
581598
}
582599

600+
/**
601+
* Helper function to parse language server version to array of nums.
602+
* Example: '2.0.401' -> [2, 0, 401]
603+
* @param ver Expected format: X.Y.Z[-*] which returns [X,Y,Z] and ignores [-*]
604+
*/
605+
function parseLspVersion(ver: string): Number[] {
606+
const regex = /^\s*([0-9]+)\.([0-9]+)\.([0-9]+)\.?([0-9]+)?(?:\-.*)?$/gm;
607+
const match = regex.exec(ver);
608+
if (match && match.length === 5) {
609+
if (match[4] !== undefined) {
610+
return [Number(match[1]), Number(match[2]), Number(match[3]), Number(match[4])];
611+
} else {
612+
return [Number(match[1]), Number(match[2]), Number(match[3])];
613+
}
614+
}
615+
return [];
616+
}
617+
583618
/**
584619
* Helper function to get all files nested under a given directory
585620
* and subdirectories.

package.json

+10-3
Original file line numberDiff line numberDiff line change
@@ -191,24 +191,31 @@
191191
},
192192
"splunk.spl2.javaPath": {
193193
"type": "string",
194-
"scope": "resource",
194+
"scope": "machine",
195195
"default": "",
196196
"order": 11,
197197
"description": "[SPL2] Java Path\nSpecify the full path to a Java executable (./java for Mac/Linux or java.exe for Windows). For example, the full path of $JAVA_HOME/bin/java."
198198
},
199199
"splunk.spl2.languageServerDirectory": {
200200
"type": "string",
201-
"scope": "resource",
201+
"scope": "machine",
202202
"default": "",
203203
"order": 12,
204204
"description": "[SPL2] Language Server Directory\nSpecify the full path of the directory containing SPL2 (Websockets) Langauge Server. Trailing slash not required. Example:\n/Users/<User>/Library/Application Support/Code/User/globalStorage/splunk.splunk/spl2/lsp"
205205
},
206206
"splunk.spl2.languageServerVersion": {
207207
"type": "string",
208-
"scope": "resource",
208+
"scope": "machine",
209209
"default": "",
210210
"order": 13,
211211
"description": "[SPL2] Language Server Version\nSpecify the version of the SPL2 language server which will be used to create the path to invoke the server. Example, a value of '2.0.362' will invoke spl-lang-server-sockets-2.0.362-all.jar"
212+
},
213+
"splunk.spl2.downloadLatestSPL2": {
214+
"type": "boolean",
215+
"scope": "machine",
216+
"default": true,
217+
"order": 14,
218+
"description": "[SPL2] Automatically update to the latest version of the SPL2 language server."
212219
}
213220
}
214221
},

0 commit comments

Comments
 (0)