Skip to content

Commit

Permalink
SPL2 notebooks download/use the latest SPL2 language server by default (
Browse files Browse the repository at this point in the history
#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
  • Loading branch information
fantavlik authored Mar 25, 2024
1 parent 37d2082 commit 55f6f52
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 35 deletions.
2 changes: 1 addition & 1 deletion out/extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const splunkCustomCommand = require('./customCommand.js');
const globalConfigPreview = require('./globalConfigPreview')
const splunkCustomRESTHandler = require('./customRESTHandler.js')
const splunkSpec = require("./spec.js");
const PLACEHOLDER_REGEX = /\<([^\>]+)\>/g
const PLACEHOLDER_REGEX = /\<([^\>]+)\>/g;
let specConfigs = {};
let timeout;
let diagnosticCollection;
Expand Down
25 changes: 13 additions & 12 deletions out/notebooks/spl2/initializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@ export async function startSpl2ClientAndServer(globalStoragePath: string, progre
return;
}
const lspPath = path.join(getLocalLspDir(globalStoragePath), getLspFilename(lspVersion));

const server = new Spl2ClientServer(progressBar, javaPath, lspPath, portToAttempt, onClose);
const server = new Spl2ClientServer(progressBar, javaPath, lspVersion, lspPath, portToAttempt, onClose);
await server.initialize();
resolve(server);
} catch (err) {
Expand All @@ -90,6 +89,7 @@ export async function startSpl2ClientAndServer(globalStoragePath: string, progre
export class Spl2ClientServer {
progressBar: StatusBarItem;
javaPath: string;
lspVersion: string;
lspPath: string;
retries: number;
restarting: boolean;
Expand All @@ -101,9 +101,10 @@ export class Spl2ClientServer {
serverProcess: child_process.ChildProcess;
socket: Socket;

constructor(progressBar: StatusBarItem, javaPath: string, lspPath: string, portToAttempt: number, onClose: (nextPort: number) => void) {
constructor(progressBar: StatusBarItem, javaPath: string, lspVersion: string, lspPath: string, portToAttempt: number, onClose: (nextPort: number) => void) {
this.progressBar = progressBar;
this.javaPath = javaPath;
this.lspVersion = lspVersion;
this.lspPath = lspPath;
this.retries = 0;
this.restarting = false;
Expand All @@ -116,15 +117,15 @@ export class Spl2ClientServer {
}

async initialize(): Promise<void> {
this.progressBar.text = 'Starting SPL2 Language Server';
this.progressBar.text = `Starting SPL2 Language Server v${this.lspVersion}`;
this.progressBar.show();
return new Promise(async (resolve, reject) => {
this.lspPort = await getNextAvailablePort(this.portToAttempt, 10)
.catch((err) => {
reject(`Unable to find available port for SPL2 language server, err: ${err}`);
reject(`Unable to find available port for SPL2 language server v${this.lspVersion}, err: ${err}`);
}) || -1;
if (this.lspPort === -1) {
reject(`Unable to find available port for SPL2 language server`);
reject(`Unable to find available port for SPL2 language server v${this.lspVersion}`);
return;
}

Expand Down Expand Up @@ -160,11 +161,11 @@ export class Spl2ClientServer {
// TODO: implement module resolution
return;
});
this.progressBar.text = 'SPL2 Language Server Running';
this.progressBar.text = `SPL2 Language Server v${this.lspVersion} Running`;
} else if (event.newState === State.Starting) {
this.progressBar.text = 'SPL2 Language Server Starting';
this.progressBar.text = `SPL2 Language Server v${this.lspVersion} Starting`;
} else {
this.progressBar.text = 'SPL2 Language Server Stopped';
this.progressBar.text = `SPL2 Language Server v${this.lspVersion} Stopped`;
}
this.progressBar.show();
});
Expand Down Expand Up @@ -192,10 +193,10 @@ export class Spl2ClientServer {
];
this.serverProcess = child_process.spawn(this.javaPath, javaArgs);
if (!this.serverProcess || !this.serverProcess.pid) {
reject(`Launching server with ${this.javaPath} ${javaArgs.join(' ')} failed.`);
reject(`Launching language server v${this.lspVersion} with ${this.javaPath} ${javaArgs.join(' ')} failed.`);
return;
} else {
console.log(`SPL2 Language Server launched with pid: ${this.serverProcess.pid} and listening on port: ${this.lspPort}`);
console.log(`SPL2 Language Server v${this.lspVersion} launched with pid: ${this.serverProcess.pid} and listening on port: ${this.lspPort}`);
}
this.serverProcess.stderr.on('data', stderr => {
console.warn(`[SPL2 Server]: ${stderr}`);
Expand All @@ -218,7 +219,7 @@ export class Spl2ClientServer {
console.log(`[SPL2 Server]: ${stdout}`);
const lspLog: LSPLog = JSON.parse(stdout);
if (lspLog.message.includes('started listening on port')) {
console.log('SPL2 Server is up, starting client...');
console.log(`SPL2 Server v${this.lspVersion} is up, starting client...`);
// Ready for client
this.socket = new Socket();

Expand Down
73 changes: 54 additions & 19 deletions out/notebooks/spl2/installer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ export const configKeyAcceptedTerms = 'splunk.spl2.acceptedTerms';
export const configKeyJavaPath = 'splunk.spl2.javaPath';
export const configKeyLspDirectory = 'splunk.spl2.languageServerDirectory';
export const configKeyLspVersion = 'splunk.spl2.languageServerVersion';

export const stateKeyLatestLspVersion = 'splunk.spl2.latestLspVersion';
export const stateKeyLastLspCheck = 'splunk.spl2.lastLspCheck';
export const configKeyDownloadLatestSPL2 = 'splunk.spl2.downloadLatestSPL2';

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

/**
* Checks if the installed SPL2 Language Server version is the latest and prompt for
* upgrade if not, or automatically upgrade if user has that setting enabled.
* Checks if the installed SPL2 Language Server version is the latest and
* automatically upgrade if user has that setting enabled.
*/
export async function getLatestSpl2Release(globalStoragePath: string, progressBar: StatusBarItem): Promise<void> {
return new Promise(async (resolve, reject) => {
const lspArtifactPath = getLocalLspDir(globalStoragePath);
// TODO: Remove this hardcoded version/update time and check for updates
let latestLspVersion: string = '2.0.385';
const lastUpdateMs: number = Date.now();
// Don't check for new version of SPL2 Language Server if less than 24 hours since last check
if (Date.now() - lastUpdateMs > 24 * 60 * 60 * 1000) {
const shouldDownloadLatest = workspace.getConfiguration().get(configKeyDownloadLatestSPL2);
// Used as backup if latest version can't be determined or current version is invalid
let lspVersionToInstall = '2.0.402'
// If user has unchecked the option to always download the latest LSP then
// check if the current specified version is installed, if not then download it
const currentLspVersion: string = workspace.getConfiguration().get(configKeyLspVersion);
const parsedCurrentVersion = parseLspVersion(currentLspVersion);

if (!shouldDownloadLatest && (parsedCurrentVersion.length >= 3)) {
// If the current version is valid and the user has elected not to download a new one
// then we are done
lspVersionToInstall = currentLspVersion;
}
// If not using current version, determine latest available
if (lspVersionToInstall !== currentLspVersion) {
// Determine the latest LSP version using maven metadata from jfrog
const metaPath = path.join(lspArtifactPath, 'maven-metadata.xml');
try {
await downloadWithProgress(
Expand All @@ -540,27 +549,35 @@ export async function getLatestSpl2Release(globalStoragePath: string, progressBa
const parser = new XMLParser();
const metadata = fs.readFileSync(metaPath);
const metaParsed = parser.parse(metadata);
latestLspVersion = metaParsed?.metadata?.versioning?.release;
let latestCandidate = metaParsed?.metadata?.versioning?.release;
const parsedCandidate = parseLspVersion(latestCandidate);
if (parsedCandidate.length >= 3) {
// Valid latest version found, update to use this
lspVersionToInstall = latestCandidate;
}
} catch (err) {
console.warn(`Error retrieving latest SPL2 version, err: ${err}`);
}
}
const currentLspVersion = workspace.getConfiguration().get(configKeyLspVersion);
if (currentLspVersion === latestLspVersion) {
resolve();
return Promise.resolve();
}
// Check if latest version has already been downloaded
const lspFilename = getLspFilename(latestLspVersion);
const lspFilename = getLspFilename(lspVersionToInstall);
const localLspPath = path.join(getLocalLspDir(globalStoragePath), lspFilename);
// Check if local file exists before downloading
if (fs.existsSync(localLspPath)) {
if (lspVersionToInstall !== currentLspVersion) {
try {
await workspace.getConfiguration().update(configKeyLspVersion, lspVersionToInstall, true);
} catch (err) {
reject(`Error updating configuration '${configKeyLspVersion}', err: ${err}`);
return Promise.resolve();
}
}
resolve();
return Promise.resolve();
}
try {
await downloadWithProgress(
`https://splunk.jfrog.io/splunk/maven-splunk/spl2/com/splunk/spl/spl-lang-server-sockets/${latestLspVersion}/${lspFilename}`,
`https://splunk.jfrog.io/splunk/maven-splunk/spl2/com/splunk/spl/spl-lang-server-sockets/${lspVersionToInstall}/${lspFilename}`,
localLspPath,
progressBar,
'Downloading SPL2 Language Server',
Expand All @@ -571,7 +588,7 @@ export async function getLatestSpl2Release(globalStoragePath: string, progressBa
}
// Update this setting to indicate that this version is ready-to-use
try {
await workspace.getConfiguration().update(configKeyLspVersion, latestLspVersion, true);
await workspace.getConfiguration().update(configKeyLspVersion, lspVersionToInstall, true);
} catch (err) {
reject(`Error updating configuration '${configKeyLspVersion}', err: ${err}`);
return Promise.resolve();
Expand All @@ -580,6 +597,24 @@ export async function getLatestSpl2Release(globalStoragePath: string, progressBa
});
}

/**
* Helper function to parse language server version to array of nums.
* Example: '2.0.401' -> [2, 0, 401]
* @param ver Expected format: X.Y.Z[-*] which returns [X,Y,Z] and ignores [-*]
*/
function parseLspVersion(ver: string): Number[] {
const regex = /^\s*([0-9]+)\.([0-9]+)\.([0-9]+)\.?([0-9]+)?(?:\-.*)?$/gm;
const match = regex.exec(ver);
if (match && match.length === 5) {
if (match[4] !== undefined) {
return [Number(match[1]), Number(match[2]), Number(match[3]), Number(match[4])];
} else {
return [Number(match[1]), Number(match[2]), Number(match[3])];
}
}
return [];
}

/**
* Helper function to get all files nested under a given directory
* and subdirectories.
Expand Down
13 changes: 10 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -191,24 +191,31 @@
},
"splunk.spl2.javaPath": {
"type": "string",
"scope": "resource",
"scope": "machine",
"default": "",
"order": 11,
"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."
},
"splunk.spl2.languageServerDirectory": {
"type": "string",
"scope": "resource",
"scope": "machine",
"default": "",
"order": 12,
"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"
},
"splunk.spl2.languageServerVersion": {
"type": "string",
"scope": "resource",
"scope": "machine",
"default": "",
"order": 13,
"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"
},
"splunk.spl2.downloadLatestSPL2": {
"type": "boolean",
"scope": "machine",
"default": true,
"order": 14,
"description": "[SPL2] Automatically update to the latest version of the SPL2 language server."
}
}
},
Expand Down

0 comments on commit 55f6f52

Please sign in to comment.