Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SPL2 Notebooks #90

Merged
merged 44 commits into from
Jul 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
3d5cff7
Initial grammar and extension support for .spl2nb
fantavlik Jun 2, 2023
4330f76
Dispatch with SPL2 working
fantavlik Jun 3, 2023
659e67a
Add support for modules.json as SPL2 notebook extension.
fantavlik Jun 5, 2023
b77ec9d
Refactor for DRYness.
fantavlik Jun 5, 2023
4fbbe3c
Remove TODO
fantavlik Jun 5, 2023
700766e
Address review feedback
fantavlik Jun 7, 2023
bed1888
Merge pull request #85 from fantavlik/spl2-vscode
JasonConger Jun 8, 2023
855aff0
Skeleton code for language server installation and initialization.
fantavlik Jun 8, 2023
2725ac6
Autodetect Java version, download JDK with statusBar showing progress.
fantavlik Jun 9, 2023
13a6879
Extracting java tarball.
fantavlik Jun 9, 2023
6f523e9
Fix path and add tar-fs dependency
fantavlik Jun 9, 2023
621873b
Unzip support and progressBar updates.
fantavlik Jun 9, 2023
0aed310
Add dialogs for user to approve SPL2 / JDK downloads
fantavlik Jun 12, 2023
2e46d8a
Download maven metadata for determining latest LSP version
fantavlik Jun 15, 2023
e257ce4
Clean up lsp and jdk artifacts before downloading and extracting
fantavlik Jun 15, 2023
4618df6
Better surfacing of errors to the user
fantavlik Jun 16, 2023
f841834
Hardcode lsp version for now, add detection for latest later
fantavlik Jun 16, 2023
b69f9ad
Fix issue with download headers.
fantavlik Jun 16, 2023
04acbae
Add explanation for header overrides
fantavlik Jun 16, 2023
3f98c19
Fix settings mismatch.
fantavlik Jun 16, 2023
c716d35
Better error handling for storing/retrieving config and make updating…
fantavlik Jun 16, 2023
c525c70
Record acceptance of terms and remove lsp download url (hardcode)
fantavlik Jun 16, 2023
e055b64
Fix recording of acceptance of terms.
fantavlik Jun 16, 2023
c4a9de3
SPL2 client and server are checking for open ports and initializing
fantavlik Jun 20, 2023
66efeb9
Dear god it works
fantavlik Jun 20, 2023
31966a3
Hide certain viz options to focus on developer audience
fantavlik Jun 20, 2023
ad79fd8
Allow switching between documents
fantavlik Jun 21, 2023
978f6e1
Better support for multiple documents, show language server status on…
fantavlik Jun 21, 2023
868a061
Allow restart of language server
fantavlik Jun 22, 2023
b742bde
Cleanup
fantavlik Jun 22, 2023
9b7cadc
Address review feedback and fix bug with unzipped Java path.
fantavlik Jun 24, 2023
b2e24dd
Merge pull request #86 from fantavlik/spl2-install
fantavlik Jun 26, 2023
041f127
Merge pull request #87 from fantavlik/spl2-initialize
fantavlik Jun 26, 2023
4efbabf
Fix an issue with unzipping in Windows
fantavlik Jun 26, 2023
765849c
Merge pull request #88 from fantavlik/spl2-fix-unzip
fantavlik Jun 26, 2023
b0c733d
Fix issue with percentage progress getting stuck
fantavlik Jun 26, 2023
bd289c1
Provide better error handling and configuration of SPL2 language server.
fantavlik Jun 26, 2023
7e70389
Add earliest and latest time inputs for SPL2
fantavlik Jun 28, 2023
887f636
Serialize SPL2 notebooks to format closer to modules.json spec
fantavlik Jun 28, 2023
ba998e6
Fix regression with tar extraction.
fantavlik Jun 30, 2023
a1a7675
Fix LSP install issue.
fantavlik Jun 30, 2023
7db01d8
Fix issue with deserializing blank documents.
fantavlik Jun 30, 2023
22fbcca
Merge pull request #89 from fantavlik/spl2-fixes
fantavlik Jun 30, 2023
ff189a0
Fix syntax error and turn on tests for this branch
fantavlik Jun 30, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
- main
- master
- develop
- spl2

jobs:
build:
Expand Down
114 changes: 92 additions & 22 deletions out/extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,25 @@ const splunkCustomRESTHandler = require('./customRESTHandler.js')
const splunkSpec = require("./spec.js");
const reload = require("./commands/reload.js");

const notebookSerializers = require('./notebooks/serializers');
const notebookControllers = require('./notebooks/controller');
const { SplunkNotebookSerializer } = require('./notebooks/serializers');
const { SplunkController } = require('./notebooks/controller');
const { Spl2NotebookSerializer } = require('./notebooks/spl2/serializer');
const { Spl2Controller } = require('./notebooks/spl2/controller');
const { installMissingSpl2Requirements, getLatestSpl2Release } = require('./notebooks/spl2/installer');
const { startSpl2ClientAndServer } = require('./notebooks/spl2/initializer');
const notebookCommands = require('./notebooks/commands');
const notebookProviders = require('./notebooks/provider');
const { CellResultCountStatusBarProvider } = require('./notebooks/provider');

//const { transpileModule } = require("typescript");
//const { AsyncLocalStorage } = require("async_hooks");
const PLACEHOLDER_REGEX = /\<([^\>]+)\>/g
let specConfigs = {};
let timeout = undefined;
let diagnosticCollection = undefined;
let specConfig = undefined;
let timeout;
let diagnosticCollection;
let specConfig;
let snippets = {};
let spl2Client;
let spl2PortToAttempt = 59143; // 59143 ~ SPLNK if you squint really hard :)

function getParentStanza(document, line) {
// Start at the passed in line and go backwards
Expand Down Expand Up @@ -63,7 +69,7 @@ function getDocumentItems(document, PATTERN) {
return items
}

function activate(context) {
async function activate(context) {

let splunkOutputChannel = vscode.window.createOutputChannel("Splunk");

Expand Down Expand Up @@ -196,8 +202,12 @@ function activate(context) {

}));

// Register Utility Commands
// Setup progress bar for install
const progressBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
context.subscriptions.push(progressBar);
progressBar.hide();

// Register Utility Commands
context.subscriptions.push(vscode.commands.registerCommand('splunk.fullDebugRefresh', async () => {reload.fullDebugRefresh(splunkOutputChannel)}))

// Set up stanza folding
Expand All @@ -206,8 +216,23 @@ function activate(context) {
], new splunkFoldingRangeProvider.confFoldingRangeProvider()));

// If vscode was opened with an active Splunk file, handle it.
if(vscode.window.activeTextEditor && isSplunkFile(vscode.window.activeTextEditor.document.fileName)) {
handleSplunkFile(context);
vscode.commands.registerCommand('splunk.restartSpl2LanguageServer', async () => {
try {
if (spl2Client) {
await spl2Client.deactivate();
}
spl2Client = undefined;
await handleSpl2Document(context, progressBar);
} catch (err) {
console.warn(`Error restarting SPL2 language server, err: ${err}`);
}
});
if(vscode.window.activeTextEditor) {
if (isSplunkDocument(vscode.window.activeTextEditor.document)) {
handleSplunkDocument(context);
} else if (isSpl2Document(vscode.window.activeTextEditor.document)) {
await handleSpl2Document(context, progressBar);
}
}

// Set up listener for text document changes
Expand All @@ -219,32 +244,41 @@ function activate(context) {
}));

// Set up listener for active editor changing
context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor( () => {
if (vscode.window.activeTextEditor && isSplunkFile(vscode.window.activeTextEditor.document.fileName)) {
handleSplunkFile(context);
context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor( async () => {
if (!vscode.window.activeTextEditor) {
return;
}
if (isSplunkDocument(vscode.window.activeTextEditor.document)) {
handleSplunkDocument(context);
} else if (isSpl2Document(vscode.window.activeTextEditor.document)) {
await handleSpl2Document(context, progressBar);
}
}));

// Notebook
context.subscriptions.push(vscode.workspace.registerNotebookSerializer('splunk-notebook', new notebookSerializers.SplunkNotebookSerializer(), {transientCellMetadata: {inputCollapsed: true, outputCollapsed: true}, transientOutputs: false}));
let controller = new notebookControllers.SplunkController()
context.subscriptions.push(controller)
context.subscriptions.push(vscode.notebooks.registerNotebookCellStatusBarItemProvider('splunk-notebook', new notebookProviders.CellResultCountStatusBarProvider(splunkOutputChannel)));
notebookCommands.registerNotebookCommands(controller, splunkOutputChannel, context)
context.subscriptions.push(vscode.workspace.registerNotebookSerializer('splunk-notebook', new SplunkNotebookSerializer(), {transientCellMetadata: {inputCollapsed: true, outputCollapsed: true}, transientOutputs: false}));
context.subscriptions.push(vscode.workspace.registerNotebookSerializer('spl2-notebook', new Spl2NotebookSerializer(), {transientCellMetadata: {inputCollapsed: true, outputCollapsed: true}, transientOutputs: false}));
const controller = new SplunkController();
context.subscriptions.push(controller);
const spl2Controller = new Spl2Controller();
context.subscriptions.push(spl2Controller);
context.subscriptions.push(vscode.notebooks.registerNotebookCellStatusBarItemProvider('splunk-notebook', new CellResultCountStatusBarProvider(splunkOutputChannel)));
context.subscriptions.push(vscode.notebooks.registerNotebookCellStatusBarItemProvider('spl2-notebook', new CellResultCountStatusBarProvider(splunkOutputChannel)));
notebookCommands.registerNotebookCommands([controller, spl2Controller], splunkOutputChannel, context);
}
exports.activate = activate;

function isSplunkFile(fileName) {
function isSplunkDocument(document) {
let splunkFileExtensions = [".conf", "default.meta", "local.meta", "globalconfig.json"];
for (let i=0; i < splunkFileExtensions.length; i++) {
if(fileName.toLowerCase().endsWith(splunkFileExtensions[i])) {
if(document.fileName.toLowerCase().endsWith(splunkFileExtensions[i])) {
return true;
}
}
return false;
}

function handleSplunkFile(context) {
function handleSplunkDocument(context) {

if(diagnosticCollection === undefined) {
diagnosticCollection = vscode.languages.createDiagnosticCollection('splunk');
Expand Down Expand Up @@ -286,6 +320,37 @@ function handleSplunkFile(context) {
specConfigs[currentDocument] = specConfig
}

function isSpl2Document(document) {
return document.languageId == 'splunk_spl2';
}

async function handleSpl2Document(context, progressBar) {
if (spl2Client) {
// Client and server are already running, try refreshing for case of new document
const range = new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 1));
const text = vscode.window.activeTextEditor.document.getText(range) || " ";
vscode.window.activeTextEditor.edit((editBuilder) => {
// To refresh language server make a harmless edit by replacing the first character
editBuilder.replace(range, text);
});
return;
}
try {
const installedLatestLsp = await installMissingSpl2Requirements(context, progressBar);
if (!installedLatestLsp) {
await getLatestSpl2Release(context, progressBar);
}
const onSpl2Restart = async (nextPort) => {
await spl2Client.deactivate();
spl2PortToAttempt = nextPort;
spl2Client = await startSpl2ClientAndServer(context, progressBar, spl2PortToAttempt, onSpl2Restart);
};
spl2Client = await startSpl2ClientAndServer(context, progressBar, spl2PortToAttempt, onSpl2Restart);
} catch (err) {
vscode.window.showErrorMessage(`Issue setting up SPL2 environment: ${err}`);
}
}

function getSpecFilePath(basePath, filename) {

// Get the custom configuration options
Expand Down Expand Up @@ -509,5 +574,10 @@ function getDiagnostics(specConfig, document) {
return diagnostics;
}

function deactivate() { }
async function deactivate() {
if (spl2Client) {
return await spl2Client.deactivate();
}
}

exports.deactivate = deactivate;
85 changes: 77 additions & 8 deletions out/notebooks/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,37 @@ import { SplunkController } from './controller';
import { VIZ_TYPES } from './visualizations';
import { getClient, getJobSearchLog, getSearchJobBySid } from './splunk';

export async function registerNotebookCommands(controller: SplunkController, outputChannel: vscode.OutputChannel, context: vscode.ExtensionContext) {
context.subscriptions.push(vscode.commands.registerCommand('splunk.notebooks.addVisualizationPreference', (cell) => {
addVisualizationPreference(controller, cell)
}))
export async function registerNotebookCommands(controllers: SplunkController[], outputChannel: vscode.OutputChannel, context: vscode.ExtensionContext) {
context.subscriptions.push(vscode.commands.registerCommand('splunk.notebooks.addVisualizationPreference', (cell) => {
controllers.filter((controller) => (cell.notebook.notebookType === controller.notebookType))
.forEach((controller) => addVisualizationPreference(controller, cell));
}));

context.subscriptions.push(vscode.commands.registerCommand('splunk.notebooks.enterEarliestTime', (cell) => {
controllers.filter((controller) => (cell.notebook.notebookType === controller.notebookType))
.forEach((controller) => enterEarliestTime(controller, cell));
}));

context.subscriptions.push(vscode.commands.registerCommand('splunk.notebooks.enterLatestTime', (cell) => {
controllers.filter((controller) => (cell.notebook.notebookType === controller.notebookType))
.forEach((controller) => enterLatestTime(controller, cell));
}));

context.subscriptions.push(vscode.commands.registerCommand('splunk.notebooks.openJobInspector', (sid) => {
openJobInspector(sid)
}))
}));

context.subscriptions.push(vscode.commands.registerCommand('splunk.notebooks.openSearchLog', (cell) => {
openSearchLog(cell, outputChannel)
}))
}));

context.subscriptions.push(vscode.commands.registerCommand('splunk.notebooks.copyJobIdToClipboard', (cell) => {
copyJobIdToClipboard(cell)
}))
}));

context.subscriptions.push(vscode.commands.registerCommand('splunk.notebooks.copyDetection', (detection) => {
copyDetection(detection)
}))
}));
}


Expand Down Expand Up @@ -112,6 +123,64 @@ export async function addVisualizationPreference(
await controller.runCell(cell);
}

export async function enterEarliestTime(
controller: SplunkController,
cell: vscode.NotebookCell
) {
const cellMetadata = { ...cell.metadata };
if (!cellMetadata.splunk) {
cellMetadata.splunk = {};
}

let value = await vscode.window.showInputBox({
title: 'Earliest time',
value: cellMetadata.splunk.earliestTime || '-24h',
prompt: 'e.g. -24h, @d, -2d@d+2h, 1687909025',
});

if (value === undefined) { // canceled
return;
}

cellMetadata.splunk.earliestTime = value;

const edit = new vscode.WorkspaceEdit();
const nbEdit = vscode.NotebookEdit.updateCellMetadata(cell.index, cellMetadata);

edit.set(cell.notebook.uri, [nbEdit]);

await vscode.workspace.applyEdit(edit);
}

export async function enterLatestTime(
controller: SplunkController,
cell: vscode.NotebookCell
) {
const cellMetadata = { ...cell.metadata };
if (!cellMetadata.splunk) {
cellMetadata.splunk = {};
}

let value = await vscode.window.showInputBox({
title: 'Latest time',
value: cellMetadata.splunk.latestTime || 'now',
prompt: 'e.g. now, -24h, @d, -2d@d+2h, 1687909025',
});

if (value === undefined) { // canceled
return;
}

cellMetadata.splunk.latestTime = value;

const edit = new vscode.WorkspaceEdit();
const nbEdit = vscode.NotebookEdit.updateCellMetadata(cell.index, cellMetadata);

edit.set(cell.notebook.uri, [nbEdit]);

await vscode.workspace.applyEdit(edit);
}

export async function copyJobIdToClipboard(cell) {
if (!cell.outputs || cell.outputs[0].metadata == undefined) {
vscode.window.showErrorMessage("No job detected in cell. Please execute the cell and try again.")
Expand Down
Loading