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

IAC-805 Lazy Load of vRO Inventory Items #142

Merged
merged 10 commits into from
Feb 14, 2024
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"**/build/azure-pipelines/**/*.yml": "azure-pipelines"
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
"source.fixAll.eslint": "explicit"
},
"eslint.validate": ["javascript", "typescript"],

Expand Down
2 changes: 1 addition & 1 deletion extension/src/client/command/DeletePackage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: MIT
*/

import { AutoWire, Logger, VroRestClient } from "@vmware/vrdt-common"

Check warning on line 6 in extension/src/client/command/DeletePackage.ts

View workflow job for this annotation

GitHub Actions / Node.js v16.x on macOS-latest

Unable to resolve path to module '@vmware/vrdt-common'

Check warning on line 6 in extension/src/client/command/DeletePackage.ts

View workflow job for this annotation

GitHub Actions / Node.js v14.x on macOS-latest

Unable to resolve path to module '@vmware/vrdt-common'

Check warning on line 6 in extension/src/client/command/DeletePackage.ts

View workflow job for this annotation

GitHub Actions / Node.js v16.x on macOS-latest

Unable to resolve path to module '@vmware/vrdt-common'

Check warning on line 6 in extension/src/client/command/DeletePackage.ts

View workflow job for this annotation

GitHub Actions / Node.js v14.x on macOS-latest

Unable to resolve path to module '@vmware/vrdt-common'
import * as vscode from "vscode"

import { Command } from "./Command"
Expand All @@ -26,7 +26,7 @@

constructor(config: ConfigurationManager, environment: EnvironmentManager) {
super()
this.restClient = new VroRestClient(config, environment)
this.restClient = new VroRestClient(config)
}

async execute(context: vscode.ExtensionContext, node: PackageNode): Promise<void> {
Expand Down
2 changes: 1 addition & 1 deletion extension/src/client/command/FetchWorkflowSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class FetchWorkflowSchema extends Command<void> {

constructor(config: ConfigurationManager, environment: EnvironmentManager) {
super()
this.restClient = new VroRestClient(config, environment)
this.restClient = new VroRestClient(config)
}

async execute(context: vscode.ExtensionContext, node: WorkflowNode): Promise<void> {
Expand Down
105 changes: 58 additions & 47 deletions extension/src/client/command/RunAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,53 +147,17 @@ export class RunAction extends Command<void> {
}

private async getScriptContent(document: vscode.TextDocument): Promise<string> {
if (document.languageId === "javascript") {
return document.getText()
}

if (document.languageId === "typescript") {
let inputFilePath = document.uri.fsPath
let inputFileName = path.basename(inputFilePath)
let tsNamespace: string | undefined
let rootPath: string
let srcPath: string

if (!document.isUntitled) {
const workspacePath = vscode.workspace.getWorkspaceFolder(document.uri)
if (!workspacePath) {
throw new Error(`File ${inputFileName} is not part of the workspace`)
}

rootPath = workspacePath.uri.fsPath
srcPath = path.join(rootPath, "src")
const pomFilePath = path.join(workspacePath.uri.fsPath, "pom.xml")

if (!fs.existsSync(pomFilePath)) {
throw new Error(`Missing pom.xml in workspace ${workspacePath.name}`)
}

const pomFile = new PomFile(pomFilePath)
tsNamespace = `${pomFile.groupId}.${pomFile.artifactId}`
} else {
rootPath = tmp.dirSync({ prefix: "o11n-ts-" }).name
srcPath = path.join(rootPath, "src")
inputFileName = inputFileName.endsWith(".ts") ? inputFileName : `${inputFileName}.ts`
inputFilePath = path.join(srcPath, inputFileName)
fs.mkdirpSync(path.dirname(inputFilePath))
fs.writeFileSync(inputFilePath, document.getText(), { encoding: "utf8" })
switch (document.languageId) {
case "javascript": {
return document.getText()
}
case "typescript": {
return this.getTypescriptContent(document)
}
default: {
return Promise.reject(new Error(`Unsupported language ID: '${document.languageId}'`))
}

this.outputChannel.appendLine(`# Compiling ${inputFileName}`)
const tsFileRelativePath = path.relative(srcPath, inputFilePath)
this.logger.debug(`Input TS file: ${inputFilePath}`)
const outputFilePath = await this.compileFile(tsFileRelativePath, rootPath, tsNamespace)
this.logger.debug(`Output JS file: ${outputFilePath}`)
const scriptContent = fs.readFileSync(outputFilePath, { encoding: "utf8" })

return scriptContent
}

return Promise.reject(`Unsupported language ID: ${document.languageId}`)
}

/**
Expand All @@ -213,8 +177,55 @@ export class RunAction extends Command<void> {
command += ` -n ${namespace}`
}
await proc.exec(command, { cwd: projectDirPath }, this.logger)

return path.join(outputDir, inputFile.replace(/\.ts$/, ".js"))
}

/**
* Return the typescript content of a vscode text document.
* @param document - reference to the vscode document.
*
* @returns the compiled javascript from the typescript document.
*/
private async getTypescriptContent(document: vscode.TextDocument): Promise<string> {
let inputFilePath = document.uri.fsPath
let inputFileName = path.basename(inputFilePath)
let tsNamespace: string | undefined
let rootPath: string
let srcPath: string

if (!document.isUntitled) {
const workspacePath = vscode.workspace.getWorkspaceFolder(document.uri)
if (!workspacePath) {
throw new Error(`File ${inputFileName} is not part of the workspace`)
}
rootPath = workspacePath.uri.fsPath
srcPath = path.join(rootPath, "src")
const pomFilePath = path.join(workspacePath.uri.fsPath, "pom.xml")
if (!fs.existsSync(pomFilePath)) {
throw new Error(`Missing pom.xml in workspace ${workspacePath.name}`)
}

const pomFile = new PomFile(pomFilePath)
tsNamespace = `${pomFile.groupId}.${pomFile.artifactId}`
} else {
rootPath = tmp.dirSync({ prefix: "o11n-ts-" }).name
srcPath = path.join(rootPath, "src")
inputFileName = inputFileName.endsWith(".ts") ? inputFileName : `${inputFileName}.ts`
inputFilePath = path.join(srcPath, inputFileName)
fs.mkdirpSync(path.dirname(inputFilePath))
fs.writeFileSync(inputFilePath, document.getText(), { encoding: "utf8" })
}

this.outputChannel.appendLine(`# Compiling ${inputFileName}`)
const tsFileRelativePath = path.relative(srcPath, inputFilePath)
this.logger.debug(`Input TS file: ${inputFilePath}`)
const outputFilePath = await this.compileFile(tsFileRelativePath, rootPath, tsNamespace)
this.logger.debug(`Output JS file: ${outputFilePath}`)
const scriptContent = fs.readFileSync(outputFilePath, { encoding: "utf8" })

return scriptContent
}
}

class ActionRunner {
Expand All @@ -225,7 +236,7 @@ class ActionRunner {
private executionToken: string

constructor(config: ConfigurationManager, private environment: EnvironmentManager) {
this.restClient = new VroRestClient(config, environment)
this.restClient = new VroRestClient(config)
this.mavenProxy = new MavenCliProxy(environment, config.vrdev.maven, this.logger)
}

Expand Down Expand Up @@ -296,7 +307,7 @@ class ActionRunner {
if (!fs.existsSync(storagePath)) {
fs.mkdirSync(storagePath)
}

// exec
await this.mavenProxy.copyDependency(
"com.vmware.pscoe.o11n",
"exec",
Expand Down
2 changes: 1 addition & 1 deletion extension/src/client/command/ShowActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class ShowActions extends Command<void> {

constructor(environment: EnvironmentManager, private config: ConfigurationManager) {
super()
this.restClient = new VroRestClient(config, environment)
this.restClient = new VroRestClient(config)
}

async execute(context: vscode.ExtensionContext): Promise<void> {
Expand Down
2 changes: 1 addition & 1 deletion extension/src/client/command/ShowConfigurations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class ShowConfigurations extends Command<void> {

constructor(environment: EnvironmentManager, config: ConfigurationManager) {
super()
this.restClient = new VroRestClient(config, environment)
this.restClient = new VroRestClient(config)
}

async execute(context: vscode.ExtensionContext): Promise<void> {
Expand Down
2 changes: 1 addition & 1 deletion extension/src/client/command/ShowResources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class ShowResources extends Command<void> {

constructor(environment: EnvironmentManager, config: ConfigurationManager) {
super()
this.restClient = new VroRestClient(config, environment)
this.restClient = new VroRestClient(config)
}

async execute(context: vscode.ExtensionContext): Promise<void> {
Expand Down
2 changes: 1 addition & 1 deletion extension/src/client/command/ShowWorkflows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class ShowWorkflows extends Command<void> {

constructor(environment: EnvironmentManager, config: ConfigurationManager) {
super()
this.restClient = new VroRestClient(config, environment)
this.restClient = new VroRestClient(config)
}

async execute(context: vscode.ExtensionContext): Promise<void> {
Expand Down
54 changes: 28 additions & 26 deletions extension/src/client/command/TriggerCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
import { AutoWire, Logger, sleep } from "@vmware/vrdt-common"
import { remote } from "@vmware/vro-language-server"
import * as vscode from "vscode"
import { LanguageClient } from "vscode-languageclient"
import { CollectionStatus } from "packages/node/vro-language-server/src/server/request/collection/ServerCollection"

Check warning on line 10 in extension/src/client/command/TriggerCollection.ts

View workflow job for this annotation

GitHub Actions / Node.js v16.x on ubuntu-latest

Unable to resolve path to module 'packages/node/vro-language-server/src/server/request/collection/ServerCollection'

Check warning on line 10 in extension/src/client/command/TriggerCollection.ts

View workflow job for this annotation

GitHub Actions / Node.js v16.x on ubuntu-latest

Unable to resolve path to module 'packages/node/vro-language-server/src/server/request/collection/ServerCollection'

Check warning on line 10 in extension/src/client/command/TriggerCollection.ts

View workflow job for this annotation

GitHub Actions / Node.js v14.x on ubuntu-latest

Unable to resolve path to module 'packages/node/vro-language-server/src/server/request/collection/ServerCollection'

Check warning on line 10 in extension/src/client/command/TriggerCollection.ts

View workflow job for this annotation

GitHub Actions / Node.js v14.x on ubuntu-latest

Unable to resolve path to module 'packages/node/vro-language-server/src/server/request/collection/ServerCollection'

Check warning on line 10 in extension/src/client/command/TriggerCollection.ts

View workflow job for this annotation

GitHub Actions / Node.js v16.x on windows-latest

Unable to resolve path to module 'packages/node/vro-language-server/src/server/request/collection/ServerCollection'

Check warning on line 10 in extension/src/client/command/TriggerCollection.ts

View workflow job for this annotation

GitHub Actions / Node.js v14.x on windows-latest

Unable to resolve path to module 'packages/node/vro-language-server/src/server/request/collection/ServerCollection'

Check warning on line 10 in extension/src/client/command/TriggerCollection.ts

View workflow job for this annotation

GitHub Actions / Node.js v16.x on windows-latest

Unable to resolve path to module 'packages/node/vro-language-server/src/server/request/collection/ServerCollection'

Check warning on line 10 in extension/src/client/command/TriggerCollection.ts

View workflow job for this annotation

GitHub Actions / Node.js v14.x on windows-latest

Unable to resolve path to module 'packages/node/vro-language-server/src/server/request/collection/ServerCollection'

import { Commands } from "../constants"
import { Commands, LanguageServerConfig } from "../constants"
import { LanguageServices } from "../lang"
import { Command } from "./Command"

Expand All @@ -30,46 +32,46 @@
const languageClient = this.languageServices.client

if (!languageClient) {
this.logger.warn("The vRO language server is not running")
this.logger.warn(`The ${LanguageServerConfig.DisplayName} is not running`)
return
}

await vscode.commands.executeCommand(Commands.EventCollectionStart)

vscode.window.withProgress(
{
location: vscode.ProgressLocation.Window,
title: "vRO hint collection"
},
progress => {
async progress => {
return new Promise<void>(async (resolve, reject) => {
await languageClient.sendRequest(remote.server.triggerVroCollection, false)
let status = await languageClient.sendRequest(remote.server.giveVroCollectionStatus)

while (status && !status.finished) {
this.logger.info("Collection status:", status)
progress.report(status)
await sleep(1000)
status = await languageClient.sendRequest(remote.server.giveVroCollectionStatus)
}

this.logger.info("Collection finished:", status)

const status: CollectionStatus = await this.triggerVroDataCollection(languageClient, progress)
if (status.error !== undefined) {
await vscode.commands.executeCommand(Commands.EventCollectionError, status.error)

if (status.data.hintsPluginBuild === 0) {
vscode.window.showErrorMessage(
"The vRO Hint plug-in is not installed on the configured vRO server"
)
}
} else {
await vscode.commands.executeCommand(Commands.EventCollectionSuccess)
reject(new Error(`Failed to trigger data collection from vRO: ${status.error}`))
}

resolve()
})
}
)
}

private async triggerVroDataCollection(languageClient: LanguageClient, progress: any): Promise<CollectionStatus> {
await languageClient.sendRequest(remote.server.triggerVroCollection, false)
let status = await languageClient.sendRequest(remote.server.giveVroCollectionStatus)

// wait for status change
while (status && !status.finished) {
this.logger.info("Collection status:", status)
progress.report(status)
await sleep(LanguageServerConfig.SleepTime)
status = await languageClient.sendRequest(remote.server.giveVroCollectionStatus)
}
// check for error response
if (status.error !== undefined) {
await vscode.commands.executeCommand(Commands.EventCollectionError, status.error)
return status
}
await vscode.commands.executeCommand(Commands.EventCollectionSuccess)

return status
}
}
8 changes: 8 additions & 0 deletions extension/src/client/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,11 @@ export enum ProjectArchetypes {
VraNg = "com.vmware.pscoe.vra-ng:vra-ng-package",
Polyglot = "com.vmware.pscoe.polyglot:polyglot-project"
}

export enum LanguageServerConfig {
Port = 6014,
LoadType = "nolazy",
NodeType = "node-ipc",
DisplayName = "vRO Language Server",
SleepTime = 1000
}
15 changes: 9 additions & 6 deletions extension/src/client/lang/LanguageServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { remote } from "@vmware/vro-language-server"
import * as vscode from "vscode"
import * as client from "vscode-languageclient"

import { OutputChannels } from "../constants"
import { LanguageServerConfig, OutputChannels } from "../constants"
import { Registrable } from "../Registrable"
import { ConfigurationManager, EnvironmentManager } from "../system"

Expand Down Expand Up @@ -82,20 +82,23 @@ export class LanguageServices implements Registrable, vscode.Disposable {
? path.join(module, "dist", "langserver.js")
: path.join(module, "out", "server", "langserver.js")

this.logger.info(`Starting vRO language server on port 6014`)
this.logger.info(`Starting vRO language server on port '${LanguageServerConfig.Port}'`)

const serverOptions = {
run: {
module: executable,
transport: client.TransportKind.ipc,
args: ["--node-ipc"],
args: [`--${LanguageServerConfig.NodeType}`],
options: { cwd: module }
},
debug: {
module: executable,
transport: client.TransportKind.ipc,
args: ["--node-ipc"],
options: { cwd: module, execArgv: ["--nolazy", "--inspect=6014"] }
args: [`--${LanguageServerConfig.NodeType}`],
options: {
cwd: module,
execArgv: [`--${LanguageServerConfig.LoadType}`, `--inspect=${LanguageServerConfig.Port}`]
}
}
}

Expand All @@ -119,6 +122,6 @@ export class LanguageServices implements Registrable, vscode.Disposable {
]
}
}
return new client.LanguageClient("vRO LS", serverOptions, clientOptions)
return new client.LanguageClient(LanguageServerConfig.DisplayName, serverOptions, clientOptions)
}
}
2 changes: 1 addition & 1 deletion extension/src/client/provider/content/ContentProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class ContentProvider implements vscode.TextDocumentContentProvider, Regi
private readonly logger = Logger.get("ContentProvider")

constructor(environment: EnvironmentManager, config: ConfigurationManager) {
this.restClient = new VroRestClient(config, environment)
this.restClient = new VroRestClient(config)
}

dispose() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class ExplorerProvider implements vscode.TreeDataProvider<AbstractNode>,
readonly onDidChangeTreeData: vscode.Event<AbstractNode | undefined> = this.onDidChangeTreeDataEmitter.event

constructor(environment: EnvironmentManager, private config: ConfigurationManager) {
this.restClient = new VroRestClient(config, environment)
this.restClient = new VroRestClient(config)
}

register(context: vscode.ExtensionContext): void {
Expand Down
2 changes: 1 addition & 1 deletion extension/src/client/system/ConfigurationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { Registrable } from "../Registrable"

@AutoWire
export class ConfigurationManager extends BaseConfiguration implements Registrable {
private homeDir = process.env[process.platform === "win32" ? "USERPROFILE" : "HOME"] || "~"
private homeDir = process.env[process.platform === "win32" ? "USERPROFILE" : "HOME"] ?? "~"
private readonly logger = Logger.get("ConfigurationManager")

readonly settingsXmlPath: string = path.resolve(this.homeDir, ".m2", "settings.xml")
Expand Down
16 changes: 8 additions & 8 deletions extension/src/client/ui/StatusBarController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,6 @@ export class StatusBarController implements Registrable, vscode.Disposable {
this.collectionStatus.dispose()
}

private onConfigurationOrProfilesChanged() {
const currentProfileName = this.config.hasActiveProfile() ? this.config.activeProfile.get("id") : undefined

if (this.verifyConfiguration() && currentProfileName !== this.profileName && this.env.hasRelevantProject()) {
vscode.commands.executeCommand(Commands.TriggerServerCollection)
}
}

verifyConfiguration(): boolean {
this.profileName = this.config.hasActiveProfile() ? this.config.activeProfile.get("id") : undefined
this.logger.info(`Verifying configuration for active profile ${this.profileName}`)
Expand Down Expand Up @@ -96,6 +88,14 @@ export class StatusBarController implements Registrable, vscode.Disposable {
return false
}

private onConfigurationOrProfilesChanged() {
const currentProfileName = this.config.hasActiveProfile() ? this.config.activeProfile.get("id") : undefined

if (this.verifyConfiguration() && currentProfileName !== this.profileName && this.env.hasRelevantProject()) {
vscode.commands.executeCommand(Commands.TriggerServerCollection)
}
}

private onCollectionStart() {
this.collectionButton.text = "$(watch) "
this.collectionButton.command = Commands.TriggerServerCollection
Expand Down
Loading
Loading