From a38e70ce7c1e5679f653df0b7b6af71247f55086 Mon Sep 17 00:00:00 2001 From: Vitaliy Gulyy Date: Fri, 10 Feb 2023 02:33:51 +0200 Subject: [PATCH] Initial commit Signed-off-by: Vitaliy Gulyy --- README.md | 6 + media/generate-yaml.md | 3 + media/markdown.md | 9 - ...ontainer-component.md => new-component.md} | 0 media/screenshot-1.png | Bin 0 -> 82997 bytes package-lock.json | 4 +- package.json | 20 +- src/devfile-api.ts | 68 +++ src/devfile-extension.ts | 423 ++++++++++++------ src/devfile-writer.ts | 105 +++++ src/logger.ts | 12 + 11 files changed, 480 insertions(+), 170 deletions(-) create mode 100644 media/generate-yaml.md delete mode 100644 media/markdown.md rename media/{new-container-component.md => new-component.md} (100%) create mode 100644 media/screenshot-1.png create mode 100644 src/devfile-api.ts create mode 100644 src/devfile-writer.ts create mode 100644 src/logger.ts diff --git a/README.md b/README.md index a22eb8d..5910138 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ # @redhat.vscode-devfile With a wizard the extension provided you can easily create the Devfile. + +![Che-Theia](media/screenshot-1.png) + +--- + +To build the extension, use Node v16 and later. diff --git a/media/generate-yaml.md b/media/generate-yaml.md new file mode 100644 index 0000000..7313d17 --- /dev/null +++ b/media/generate-yaml.md @@ -0,0 +1,3 @@ +# Get Devfile yaml + +Click button to save Devfile to the root of your project. diff --git a/media/markdown.md b/media/markdown.md deleted file mode 100644 index 1628f1d..0000000 --- a/media/markdown.md +++ /dev/null @@ -1,9 +0,0 @@ -# Change Log - -All notable changes to the "redhat" extension will be documented in this file. - -Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. - -## [Unreleased] - -- Initial release \ No newline at end of file diff --git a/media/new-container-component.md b/media/new-component.md similarity index 100% rename from media/new-container-component.md rename to media/new-component.md diff --git a/media/screenshot-1.png b/media/screenshot-1.png new file mode 100644 index 0000000000000000000000000000000000000000..35fed2e9ce934990fba508f15e136b1e23412cd0 GIT binary patch literal 82997 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 literal 0 HcmV?d00001 diff --git a/package-lock.json b/package-lock.json index 05cb5d3..cc48795 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "redhat-devfiles", + "name": "vscode-devfile", "version": "0.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "redhat-devfiles", + "name": "vscode-devfile", "version": "0.0.1", "devDependencies": { "@types/glob": "^8.0.1", diff --git a/package.json b/package.json index 652a4ce..ef257b5 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "title": "Devfile :: New Devfile" }, { - "command": "vscode-devfile.new-container-component", + "command": "vscode-devfile.new-component", "title": "Devfile :: New Component" }, { @@ -62,8 +62,8 @@ "title": "Devfile :: New Command" }, { - "command": "vscode-devfile.generate-devfile", - "title": "Devfile :: Generate Devfile" + "command": "vscode-devfile.save-devfile", + "title": "Devfile :: Save Devfile" } ], @@ -77,15 +77,15 @@ { "id": "devfile-name", "title": "New Devfile", - "description": "Start with creating a Devfile\n[New Devfile](command:vscode-devfile.new-devfile)", + "description": "Start with creating a Devfile\n[Create](command:vscode-devfile.new-devfile)", "media": { "markdown": "media/new-devfile.md" }, "completionEvents": ["onCommand:vscode-devfile.new-devfile"] }, { - "id": "add-container-component", + "id": "add-component", "title": "Add Component", - "description": "Adding a container component\n[New Component](command:vscode-devfile.new-container-component)", - "media": { "markdown": "media/new-container-component.md" }, + "description": "Adding a container component\n[New Component](command:vscode-devfile.new-component)", + "media": { "markdown": "media/new-component.md" }, "completionEvents": [] }, { @@ -97,9 +97,9 @@ }, { "id": "generate-devfile", - "title": "Generate Devfile", - "description": "You are ready to get a new Devfile\n[Get Devfile](command:vscode-devfile.generate-devfile)", - "media": { "markdown": "media/markdown.md" }, + "title": "Save Devfile", + "description": "You are ready to get a new Devfile and save it to the root of your project\n[Save](command:vscode-devfile.save-devfile)", + "media": { "markdown": "media/generate-yaml.md" }, "completionEvents": [] } ] diff --git a/src/devfile-api.ts b/src/devfile-api.ts new file mode 100644 index 0000000..4549174 --- /dev/null +++ b/src/devfile-api.ts @@ -0,0 +1,68 @@ + +/** +``` +schemaVersion: 2.2.0 +metadata: + name: devfile-sample +``` +*/ +export interface Devfile { + + metadata: Metadata; + components: Component[]; + +} + +export interface Metadata { + name: string; +} + +/** +``` +components: + - name: dev + container: + image: quay.io/devfile/universal-developer-image:latest + memoryRequest: 256Mi + memoryLimit: 2048Mi + cpuRequest: 0.1 + cpuLimit: 0.5 + mountSources: true + endpoints: + - exposure: public + name: http-demo + protocol: http + targetPort: 8080 + env: + - name: WELCOME + value: "Hello World" + +``` + */ +export interface Component { + name: string; + container?: ComponentContainer; +} + +export interface ComponentContainer { + image: string; + memoryRequest?: string; + memoryLimit?: string; + cpuRequest?: string; + cpuLimit?: string; + mountSources?: boolean; + endpoints?: ExposedPort[]; + env?: EnvironmentVariable[]; +} + +export interface ExposedPort { + visibility: 'public' | 'internal'; + name: string; + protocol: string; + port: number; +} + +export interface EnvironmentVariable { + name: string; + value: string; +} diff --git a/src/devfile-extension.ts b/src/devfile-extension.ts index 9714634..73a0d15 100644 --- a/src/devfile-extension.ts +++ b/src/devfile-extension.ts @@ -1,191 +1,308 @@ import * as vscode from 'vscode'; import { posix } from 'path'; - -let output: vscode.OutputChannel | undefined; - -function log(msg: string) { - output?.appendLine(msg); -} +import { ComponentContainer, Devfile, EnvironmentVariable, ExposedPort } from './devfile-api'; +import { DevfileWriter } from './devfile-writer'; +import { log } from './logger'; export async function activate(context: vscode.ExtensionContext): Promise { - - output = vscode.window.createOutputChannel('devfile-extension'); - output.show(true); - // output.appendLine('> Initializing'); - // console.log('Congratulations, your extension "vscode-devfile" is now active!'); - - new DevfileGenerator(context); - - // output.appendLine('> Extension Initialized'); - // output.appendLine(''); + new DevfileExtension(context); } // This method is called when your extension is deactivated export function deactivate() { } -const DEF_DEVFILE_NAME = 'devfile-sample'; +// const DEF_DEVFILE_NAME = 'devfile-sample'; -const DEF_CONTAINER_COMPONENT_NAME = 'dev'; -const DEF_CONTAINER_COMPONENT_IMAGE = 'quay.io/devfile/universal-developer-image:latest'; -const DEF_CONTAINER_COMPONENT_MEMORY_LIMIT = '2048Mi'; -const DEF_CONTAINER_COMPONENT_CPU_LIMIT = '0.5'; +// const DEF_CONTAINER_COMPONENT_NAME = 'dev'; +// const DEF_CONTAINER_COMPONENT_IMAGE = 'quay.io/devfile/universal-developer-image:latest'; +// const DEF_CONTAINER_COMPONENT_MEMORY_LIMIT = '2048Mi'; +// const DEF_CONTAINER_COMPONENT_CPU_LIMIT = '0.5'; -export interface ExposedPort { - visibility: 'public' | 'private'; - name: string; - protocol: string; - port: number; -} +export class DevfileExtension { -export interface EnvironmentVariable { - name: string; - value: string; -} + private devfile: Devfile | undefined; -export class DevfileGenerator { + // private devfileName: string | undefined = DEF_DEVFILE_NAME; - private devfileName: string | undefined = DEF_DEVFILE_NAME; + // private containerComponentName: string | undefined = DEF_CONTAINER_COMPONENT_NAME; + // private containerComponentImage: string | undefined = DEF_CONTAINER_COMPONENT_IMAGE; + // private containerComponentMemoryLimit: string | undefined = DEF_CONTAINER_COMPONENT_MEMORY_LIMIT; + // private containerComponentCpuLimit: string | undefined = DEF_CONTAINER_COMPONENT_CPU_LIMIT; - private containerComponentName: string | undefined = DEF_CONTAINER_COMPONENT_NAME; - private containerComponentImage: string | undefined = DEF_CONTAINER_COMPONENT_IMAGE; - private containerComponentMemoryLimit: string | undefined = DEF_CONTAINER_COMPONENT_MEMORY_LIMIT; - private containerComponentCpuLimit: string | undefined = DEF_CONTAINER_COMPONENT_CPU_LIMIT; - - private containerExposedPorts: ExposedPort[] = []; - private containerEnvironmentVariables: EnvironmentVariable[] = []; + // private containerExposedPorts: ExposedPort[] = []; + // private containerEnvironmentVariables: EnvironmentVariable[] = []; constructor(context: vscode.ExtensionContext) { - context.subscriptions.push(vscode.commands.registerCommand('vscode-devfile.new-devfile', async () => this.nameTheDevfile())); - context.subscriptions.push(vscode.commands.registerCommand('vscode-devfile.new-container-component', async () => this.newContainerComponent())); + context.subscriptions.push(vscode.commands.registerCommand('vscode-devfile.new-devfile', async () => this.newDevfile())); + context.subscriptions.push(vscode.commands.registerCommand('vscode-devfile.new-component', async () => this.newComponent())); context.subscriptions.push(vscode.commands.registerCommand('vscode-devfile.new-command', async () => this.newCommand())); - context.subscriptions.push(vscode.commands.registerCommand('vscode-devfile.generate-devfile', async () => this.generateDevfile())); + context.subscriptions.push(vscode.commands.registerCommand('vscode-devfile.save-devfile', async () => this.saveDevfile())); } - public async nameTheDevfile(): Promise { - await new Promise(resolve => setTimeout(resolve, 500)); + public async newDevfile(): Promise { + this.devfile = undefined; - this.devfileName = await vscode.window.showInputBox({ - // prompt: 'Prompt', - // placeHolder: 'placeHolder', - value: DEF_DEVFILE_NAME, - title: 'Devfile Name' + const name = await vscode.window.showInputBox({ + value: 'devfile-sample', + title: 'New Devfile Name' }); - output?.appendLine(`.metadata.name: ${this.devfileName}`); - - if (!this.devfileName) { - // output?.appendLine('<< returning'); + if (!name) { + log('<< canceled'); return; } - try { - await vscode.workspace.getConfiguration('vscode-devfile').update('new-devfile-name', `${this.devfileName}`); - } catch (err) { - output?.appendLine(`>> ERROR ${err}`); - } - } + this.devfile = { + metadata: { + name + }, + components: [] + } as Devfile; - public async newContainerComponent(): Promise { - // cleanup - this.containerExposedPorts = []; - this.containerEnvironmentVariables = []; + log(new DevfileWriter(this.devfile).getMetadata()); - // component name - this.containerComponentName = await vscode.window.showInputBox({ - value: DEF_CONTAINER_COMPONENT_NAME, - title: 'Component Name' - }); + // try { + // await vscode.workspace.getConfiguration('vscode-devfile').update('new-devfile-name', `${this.devfileName}`); + // } catch (err) { + // output?.appendLine(`>> ERROR ${err}`); + // } + } - if (!this.containerComponentName) { - output?.appendLine(' << returning'); + public async newComponent(): Promise { + if (await this.missingDevfile()) { return; } - output?.appendLine(`.components[0].name: ${this.containerComponentName}`); + // component name + const componentName = await this.defineComponentName(); + if (!componentName) { + log('<< canceled'); + return; + } - // component container image - this.containerComponentImage = await vscode.window.showInputBox({ - value: DEF_CONTAINER_COMPONENT_IMAGE, - title: 'Component Image' - }); + log(`> component name: ${componentName}`); - if (!this.containerComponentImage) { - output?.appendLine(' << returning'); + // container component image + const containerImage = await this.defineComponentImage(); + if (!containerImage) { + log('<< canceled'); return; } - output?.appendLine(`.components[0].container.image: ${this.containerComponentImage}`); + log(`> container image: ${containerImage}`); - // memory limit, can be omitted - this.containerComponentMemoryLimit = await vscode.window.showInputBox({ - value: DEF_CONTAINER_COMPONENT_MEMORY_LIMIT, - title: 'Memory Limit' + const container: ComponentContainer = { + image: containerImage, + mountSources: true + }; + + // add new component + this.devfile?.components.push({ + name: componentName, + container }); - output?.appendLine(`.components[0].container.memoryLimit: ${this.containerComponentMemoryLimit}`); + // memory limit, can be omitted + const memoryLimit = await this.defineComponentMemoryLimit(); + if (memoryLimit) { + log(`> memory limit: ${memoryLimit}`); + container.memoryLimit = memoryLimit; + } else { + log('<< canceled'); + } // CPU limit, can be omitted - this.containerComponentCpuLimit = await vscode.window.showInputBox({ - value: DEF_CONTAINER_COMPONENT_CPU_LIMIT, - title: 'CPU Limit' - }); - - output?.appendLine(`.components[0].container.cpuLimit: ${this.containerComponentCpuLimit}`); + const cpuLimit = await this.defineComponentCpuLimit(); + if (cpuLimit) { + log(`> cpu limit: ${cpuLimit}`); + container.cpuLimit = cpuLimit; + } else { + log('<< canceled'); + } // define endpoints - while (await this.doExposePort()) { - output?.appendLine('> expose port...'); + while (await this.wantToExposePort(container.endpoints)) { + log('> expose port...'); - const port = await this.defineExposedPort(); - if (port) { - this.containerExposedPorts.push(port); + const exposedport = await this.defineExposedPort(); + if (exposedport) { + if (!container.endpoints) { + container.endpoints = []; + } + + container.endpoints.push(exposedport); } else { - output?.appendLine('<< got undefined.'); + log('<< canceled'); break; } } - output?.appendLine(`> Exposed ports: ${this.containerExposedPorts.length}`); - for (const port of this.containerExposedPorts) { - output?.appendLine(` [ Visibility: ${port.visibility}; Name: ${port.name}; Protocol: ${port.protocol}; Port: ${port.port}; ]`); + if (container.endpoints) { + log(`> Exposed ports: ${container.endpoints.length}`); + for (const port of container.endpoints) { + log(` [ Visibility: ${port.visibility}; Name: ${port.name}; Protocol: ${port.protocol}; Port: ${port.port}; ]`); + } } // define environment variables - while (await this.doDefineEnvironmentVariable()) { - output?.appendLine('> define environment variable...'); + while (await this.wantToDefineEnvironmentVariable(container.env)) { + log('> define environment variable...'); - const variable = await this.defineEnvironmentVariable(); + const variable = await this.defineEnvironmentVariable(container.env); if (variable) { - this.containerEnvironmentVariables.push(variable); + if (!container.env) { + container.env = []; + } + container.env.push(variable); } else { - output?.appendLine('<< got undefined.'); + log('<< canceled'); break; } } - output?.appendLine(`> Environment variables: ${this.containerEnvironmentVariables.length}`); - for (const variable of this.containerEnvironmentVariables) { - output?.appendLine(` [ Name: ${variable.name}; Value: ${variable.value}; ]`); + if (container.env) { + log(`> Environment variables: ${container.env.length}`); + for (const variable of container.env) { + log(` [ Name: ${variable.name}; Value: ${variable.value}; ]`); + } } + if (2 + 3 === 5) { + return; + } + + + + + } - private async doExposePort(): Promise { + private async defineComponentName(): Promise { + return await vscode.window.showInputBox({ + value: this.devfile?.components.length === 0 ? 'dev' : '', + title: 'Component Name', + + validateInput: (value): string | vscode.InputBoxValidationMessage | undefined | null | + Thenable => { + if (!this.devfile) { + return { + message: 'Devfile is not created', + severity: vscode.InputBoxValidationSeverity.Error + } as vscode.InputBoxValidationMessage; + } + + for (const c of this.devfile.components) { + if (c.name === value) { + return { + message: 'Component with this name already exists', + severity: vscode.InputBoxValidationSeverity.Error + } as vscode.InputBoxValidationMessage; + } else if (!value) { + return { + message: 'Component name cannot be empty', + severity: vscode.InputBoxValidationSeverity.Error + } as vscode.InputBoxValidationMessage; + } + } + } + }); + } + + private async defineComponentImage(): Promise { + return await vscode.window.showInputBox({ + value: this.devfile?.components.length === 0 ? 'quay.io/devfile/universal-developer-image:latest' : '', + title: 'Component Image', + + validateInput: (value): string | vscode.InputBoxValidationMessage | undefined | null | + Thenable => { + if (!this.devfile) { + return { + message: 'Devfile is not created', + severity: vscode.InputBoxValidationSeverity.Error + } as vscode.InputBoxValidationMessage; + } + + for (const c of this.devfile.components) { + if (c.container && c.container.image === value) { + return { + message: 'Component with this image already exists', + severity: vscode.InputBoxValidationSeverity.Error + } as vscode.InputBoxValidationMessage; + } else if (!value) { + return { + message: 'Component name cannot be empty', + severity: vscode.InputBoxValidationSeverity.Error + } as vscode.InputBoxValidationMessage; + } + } + } + }); + } + + private async defineComponentMemoryLimit(): Promise { + return await vscode.window.showInputBox({ + value: this.devfile?.components.length === 1 ? '2048Mi' : '512Mi', + title: 'Memory Limit', + + validateInput: (value): string | vscode.InputBoxValidationMessage | undefined | null | + Thenable => { + if (!this.devfile) { + return { + message: 'Devfile is not created', + severity: vscode.InputBoxValidationSeverity.Error + } as vscode.InputBoxValidationMessage; + } + + if (!value) { + return { + message: 'Memory limit cannot be empty', + severity: vscode.InputBoxValidationSeverity.Error + } as vscode.InputBoxValidationMessage; + } + } + }); + } + + private async defineComponentCpuLimit(): Promise { + return await vscode.window.showInputBox({ + value: '0.5', + title: 'CPU Limit', + + validateInput: (value): string | vscode.InputBoxValidationMessage | undefined | null | + Thenable => { + if (!this.devfile) { + return { + message: 'Devfile is not created', + severity: vscode.InputBoxValidationSeverity.Error + } as vscode.InputBoxValidationMessage; + } + + if (!value) { + return { + message: 'CPU limit cannot be empty', + severity: vscode.InputBoxValidationSeverity.Error + } as vscode.InputBoxValidationMessage; + } + } + }); + } + + private async wantToExposePort(endpoints: ExposedPort[] | undefined): Promise { const exposePort = await vscode.window.showQuickPick([ 'Yes', 'No' ], { - title: `Would you like to expose ${this.containerExposedPorts.length === 0 ? '' : 'one more '}port?`, + title: `Would you like to expose${endpoints && endpoints.length !== 0 ? ' one more ' : ' '}port?`, }); return 'Yes' === exposePort; } - private async doDefineEnvironmentVariable(): Promise { + private async wantToDefineEnvironmentVariable(env: EnvironmentVariable[] | undefined): Promise { const defineVariable = await vscode.window.showQuickPick([ 'Yes', 'No' ], { - title: `Would you like to define ${this.containerEnvironmentVariables.length === 0 ? '' : 'one more '}environment variable for the container?`, + title: `Would you like to define${env && env.length !== 0 ? ' one more ' : ' '}environment variable for the container?`, }); return 'Yes' === defineVariable; @@ -193,12 +310,12 @@ export class DevfileGenerator { private async defineExposedPort(): Promise { const visibility = await vscode.window.showQuickPick([ - 'public', 'private' + 'public', 'internal' ], { - title: 'Port Visibility' + title: 'Port Visibility' }); - output?.appendLine(`Visibility: ${visibility}`); + log(`Visibility: ${visibility}`); if (!visibility) { return undefined; @@ -224,8 +341,8 @@ export class DevfileGenerator { const portValue: number = Number.parseInt(port); - output?.appendLine(`Port value: ${portValue}`); - output?.appendLine(`Number.isInteger(portValue): ${Number.isInteger(portValue)}`); + log(`Port value: ${portValue}`); + log(`Number.isInteger(portValue): ${Number.isInteger(portValue)}`); const protocol = await vscode.window.showInputBox({ value: 'http', @@ -237,30 +354,33 @@ export class DevfileGenerator { } return { - visibility: visibility === 'public' ? 'public' : 'private', + visibility: visibility === 'public' ? 'public' : 'internal', name: name, port: portValue, protocol: protocol }; } - private async defineEnvironmentVariable(): Promise { + private async defineEnvironmentVariable(env: EnvironmentVariable[] | undefined): Promise { + const environment = env; const name = await vscode.window.showInputBox({ - value: this.containerEnvironmentVariables.length === 0 ? 'WELCOME' : '', + value: env && env.length !== 0 ? '' : 'WELCOME', title: 'Environment Variable Name', validateInput: (value): string | vscode.InputBoxValidationMessage | undefined | null | - Thenable => { - for (const v of this.containerEnvironmentVariables) { - if (v.name === value) { - return { - message: 'Enviroment variable with this name already exists', - severity: vscode.InputBoxValidationSeverity.Error - } as vscode.InputBoxValidationMessage; - } else if (!value) { - return { - message: 'Environment variable name cannot be empty', - severity: vscode.InputBoxValidationSeverity.Error - } as vscode.InputBoxValidationMessage; + Thenable => { + if (environment) { + for (const v of environment) { + if (v.name === value) { + return { + message: 'Enviroment variable with this name already exists', + severity: vscode.InputBoxValidationSeverity.Error + } as vscode.InputBoxValidationMessage; + } else if (!value) { + return { + message: 'Environment variable name cannot be empty', + severity: vscode.InputBoxValidationSeverity.Error + } as vscode.InputBoxValidationMessage; + } } } @@ -273,7 +393,7 @@ export class DevfileGenerator { } const value = await vscode.window.showInputBox({ - value: this.containerEnvironmentVariables.length === 0 ? 'Hello World' : '', + value: env && env.length !== 0 ? '' : 'Hello World', title: 'Environment Variable Value' }); @@ -287,19 +407,33 @@ export class DevfileGenerator { return { name, value - } + }; } public async newCommand(): Promise { vscode.window.showInformationMessage('New Command'); } - public async generateDevfile(): Promise { - if (await this.writeDevfile(this.getDevfileContent())) { + public async saveDevfile(): Promise { + if (await this.missingDevfile()) { + return; + } + + const content = new DevfileWriter(this.devfile!).toString(); + if (await this.writeDevfile(content)) { await this.openDevfile(); } } + private async missingDevfile(): Promise { + if (!this.devfile) { + await vscode.window.showErrorMessage('The first you need to create a Devfile'); + return true; + } + + return false; + } + private async writeDevfile(content: string): Promise { if (!vscode.workspace.workspaceFolders || vscode.workspace.workspaceFolders.length == 0) { @@ -317,16 +451,16 @@ export class DevfileGenerator { if (err instanceof vscode.FileSystemError) { devfileExist = false; } else { - output?.appendLine(`>> ERROR ${err}`); + log(`>> ERROR ${err}`); } } - output?.appendLine(''); - output?.appendLine(`> devfile exist ${devfileExist}`); + log(''); + log(`> devfile exist ${devfileExist}`); if (devfileExist) { const result = await vscode.window.showWarningMessage('Devfile already exists', 'Skip', 'Override'); - output?.appendLine(`> result ${result}`); + log(`> result ${result}`); if ('Override' === result) { await vscode.workspace.fs.writeFile(devfileUri, Buffer.from(content, 'utf8')); @@ -353,13 +487,4 @@ export class DevfileGenerator { vscode.window.showTextDocument(devfileUri); } - public getDevfileContent(): string { - let content = `schemaVersion: 2.2.0 -metadata: - name: ${this.devfileName} -`; - - return content; - } - } diff --git a/src/devfile-writer.ts b/src/devfile-writer.ts new file mode 100644 index 0000000..2e6b7ca --- /dev/null +++ b/src/devfile-writer.ts @@ -0,0 +1,105 @@ +import { Component, Devfile } from "./devfile-api"; + +const JOIN_STR = '\n'; + +export class DevfileWriter { + + constructor(private devfile: Devfile) { + } + + public toString(): string { + return [ + this.getHeader(), + this.getMetadata(), + this.getComponents() + ].join(JOIN_STR); + } + + public getHeader(): string { + return 'schemaVersion: 2.2.0'; + } + + public getMetadata(): string { + return [ + 'metadata:', + ` name: ${this.devfile?.metadata.name}` + ].join(JOIN_STR); + } + + public getComponents(): string { + if (this.devfile.components.length === 0) { + return ''; + } + + const arr: string[] = ['components:']; + + for (const c of this.devfile.components) { + if (c.container) { + arr.push(this.getContainerComponent(c)); + } + } + + return arr.join(JOIN_STR); + } + + public getContainerComponent(c: Component): string { + const arr: string[] = [ + ` - name: ${c.name}`, + ' container:' + ]; + + if (c.container?.image) { + arr.push(` image: ${c.container?.image}`); + } + + if (c.container?.memoryRequest) { + arr.push(` memoryRequest: '${c.container?.memoryRequest}'`); + } + + if (c.container?.memoryLimit) { + arr.push(` memoryLimit: '${c.container?.memoryLimit}'`); + } + + if (c.container?.cpuRequest) { + arr.push(` cpuRequest: '${c.container?.cpuRequest}'`); + } + + if (c.container?.cpuLimit) { + arr.push(` cpuLimit: '${c.container?.cpuLimit}'`); + } + + if (c.container?.mountSources) { + arr.push(` mountSources: ${c.container.mountSources}`); + } + + if (c.container?.endpoints) { + arr.push(' endpoints:'); + + for (const endpoint of c.container.endpoints) { + arr.push( + ` - exposure: ${endpoint.visibility}`, + ` name: ${endpoint.name}`, + ` protocol: ${endpoint.protocol}`, + ` targetPort: ${endpoint.port}` + ); + } + } + + if (c.container?.env) { + arr.push(' env:'); + for (const env of c.container.env) { + arr.push( + ` - name: ${env.name}`, + ` value: ${env.value}` + ); + } + } + + return arr.join(JOIN_STR); + } + + public getVolumeComponent(c: Component): string { + return ''; + } + +} diff --git a/src/logger.ts b/src/logger.ts new file mode 100644 index 0000000..83a74b1 --- /dev/null +++ b/src/logger.ts @@ -0,0 +1,12 @@ +import * as vscode from 'vscode'; + +let output: vscode.OutputChannel | undefined = undefined; + +export function log(msg: string) { + if (!output) { + output = vscode.window.createOutputChannel('devfile-extension'); + output.show(true); + } + + output?.appendLine(msg); +}