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

feat: add launch action to bootable images #83

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
"command": "bootc.image.build",
"title": "Build Disk Image",
"when": "ostree.bootable in imageLabelKeys"
},
{
"command": "bootc.vfkit",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"title": "Launch as VM",
"when": "ostree.bootable in imageLabelKeys"
}
],
"dashboard/container": [
Expand Down
2 changes: 1 addition & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export async function activate(extensionContext: ExtensionContext): Promise<void

extensionContext.subscriptions.push(
extensionApi.commands.registerCommand('bootc.vfkit', async container => {
await launchVFKit(container);
await launchVFKit(container, history);
}),

extensionApi.commands.registerCommand('bootc.image.build', async image => {
Expand Down
24 changes: 24 additions & 0 deletions src/history.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,27 @@ test('check get returns latest after multiple adds', async () => {

expect(history.getLastLocation()).toEqual('c2');
});

test('check lastBuild get updated', async () => {
vi.mock('node:fs', async () => {
return {
readFile: vi.fn().mockImplementation(() => '[]'),
writeFile: vi.fn().mockImplementation(() => Promise.resolve()),
existsSync: vi.fn().mockImplementation(() => true),
};
});

const history: History = new History('test');

await history.addImageBuild('a0', 'b0', 'c0');
await history.addImageBuild('a1', 'b1', 'c1');

expect(history.getLastBuildFor('a0').type).toEqual('b0');
expect(history.getLastBuildFor('a0').location).toEqual('c0');

await history.addImageBuild('a0', 'b0b', 'c0b');
await history.addImageBuild('a2', 'b2', 'c2');

expect(history.getLastBuildFor('a0').type).toEqual('b0b');
expect(history.getLastBuildFor('a0').location).toEqual('c0b');
});
12 changes: 10 additions & 2 deletions src/history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,17 @@ export class History {
public getLastLocation(): string | undefined {
if (this.infos.length === 0) {
return undefined;
} else {
return this.infos[0].location;
}
return this.infos[0].location;
}

public getLastBuildFor(image: string): { type: string; location: string } | undefined {
if (this.infos.length === 0) {
return undefined;
}

// returns the details of the last build for this image
return this.infos.find((_value, index, info) => info[index].image === image);
}

public async addImageBuild(image: string, type: string, location: string) {
Expand Down
36 changes: 29 additions & 7 deletions src/launch-vfkit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,39 @@

import * as extensionApi from '@podman-desktop/api';
import * as fs from 'node:fs';
import type { History } from './history';

const telemetryLogger = extensionApi.env.createTelemetryLogger();

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export async function launchVFKit(container: any): Promise<void> {
const imageLocation = container.labels['bootc.build.image.location'];

// Check that vfkit is installed and error if it isn't before executing
export async function launchVFKit(target: any, history: History): Promise<void> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const telemetryData: Record<string, any> = {};
telemetryData.imageType = container.labels['bootc.build.type'];

let imageType: string;
let imageLocation: string;
if ('tag' in target) {
// launched on an image
const image = target as { name: string };
const lastBuild = history.getLastBuildFor(image.name);

if (!lastBuild) {
await extensionApi.window.showErrorMessage(`Unable to launch ${image.name} because there was no previous build`);
telemetryData.error = 'no-prior-build';
telemetryLogger.logUsage('launchVfkit', telemetryData);
return;
}
imageType = lastBuild.type;
imageLocation = lastBuild.location;
} else {
// launched on the builder container
const container = target as { labels: string[] };
imageType = container.labels['bootc.build.type'];
imageLocation = container.labels['bootc.build.image.location'];
}

// Check that vfkit is installed and error if it isn't before executing
telemetryData.imageType = imageType;
try {
await extensionApi.process.exec('vfkit', ['--version']);
} catch (error) {
Expand All @@ -50,9 +72,9 @@ export async function launchVFKit(container: any): Promise<void> {

// Check container.labels['bootc.build.type'] to see if it is ami or raw
// if it is not raw or ami, we cannot launch with vfkit
if (container.labels['bootc.build.type'] !== 'ami' && container.labels['bootc.build.type'] !== 'raw') {
if (imageType !== 'ami' && imageType !== 'raw') {
await extensionApi.window.showErrorMessage(
`Unable to launch ${imageLocation} with vfkit: ${container.labels['bootc.build.type']} is not supported`,
`Unable to launch ${imageLocation} with vfkit: ${imageType} is not supported`,
);
telemetryData.error = 'unsupported-type';
telemetryLogger.logUsage('launchVfkit', telemetryData);
Expand Down