Skip to content

Commit 16439e9

Browse files
committed
feat: add arbitrary container manager support
Signed-off-by: Tulip Blossom <[email protected]>
1 parent 3c8c4d7 commit 16439e9

File tree

6 files changed

+35
-24
lines changed

6 files changed

+35
-24
lines changed

src/renderer/lib/config.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export type WinboatConfigObj = {
1212
customApps: WinApp[]
1313
experimentalFeatures: boolean
1414
multiMonitor: number
15+
containerRuntime: string
1516
};
1617

1718
const defaultConfig: WinboatConfigObj = {
@@ -22,6 +23,7 @@ const defaultConfig: WinboatConfigObj = {
2223
customApps: [],
2324
experimentalFeatures: false,
2425
multiMonitor: 0,
26+
containerRuntime: "podman",
2527
};
2628

2729
export class WinboatConfig {
@@ -101,4 +103,4 @@ export class WinboatConfig {
101103
return { ...defaultConfig };
102104
}
103105
}
104-
}
106+
}

src/renderer/lib/install.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const path: typeof import('path') = require('path');
99
const { promisify }: typeof import('util') = require('util');
1010
const nodeFetch: typeof import('node-fetch').default = require('node-fetch');
1111
const remote: typeof import('@electron/remote') = require('@electron/remote');
12+
import { WinboatConfig } from './config';
1213

1314
const execAsync = promisify(exec);
1415
const logger = createLogger(path.join(WINBOAT_DIR, 'install.log'));
@@ -83,12 +84,14 @@ export class InstallManager {
8384
emitter: Emitter<InstallEvents>;
8485
state: InstallState;
8586
preinstallMsg: string;
87+
wbConfig: WinboatConfig | null
8688

8789
constructor(conf: InstallConfiguration) {
8890
this.conf = conf;
8991
this.state = InstallStates.IDLE;
9092
this.preinstallMsg = ""
9193
this.emitter = createNanoEvents<InstallEvents>();
94+
this.wbConfig = new WinboatConfig();
9295
}
9396

9497
changeState(newState: InstallState) {
@@ -240,7 +243,7 @@ export class InstallManager {
240243
// Start the container
241244
try {
242245
// execSync(`docker compose -f ${composeFilePath} up -d`, { stdio: 'inherit' });
243-
const { stdout, stderr } = await execAsync(`docker compose -f ${composeFilePath} up -d`);
246+
const { stdout, stderr } = await execAsync(`${this.wbConfig!.config.containerRuntime} compose -f ${composeFilePath} up -d`);
244247
if (stderr) {
245248
logger.error(stderr);
246249
}
@@ -331,8 +334,9 @@ export class InstallManager {
331334

332335
export async function isInstalled() {
333336
// Check if a docker container named WinBoat exists
337+
const wbConfig: WinboatConfig | null = new WinboatConfig();
334338
try {
335-
const { stdout: res } = await execAsync('docker ps -a --filter "name=WinBoat" --format "{{.Names}}"');
339+
const { stdout: res } = await execAsync(`${wbConfig!.config.containerRuntime} ps -a --filter "name=WinBoat" --format "{{.Names}}"`);
336340
return res.includes('WinBoat');
337341
} catch(e) {
338342
logger.error("Failed to get WinBoat status, is Docker installed?");

src/renderer/lib/specs.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { getFreeRDP } from '../utils/getFreeRDP';
22
const fs: typeof import('fs') = require('fs');
33
const os: typeof import('os') = require('os');
4+
import { WinboatConfig } from './config';
45
const { exec }: typeof import('child_process') = require('child_process');
56
const { promisify }: typeof import('util') = require('util');
67
const execAsync = promisify(exec);
@@ -20,6 +21,7 @@ export const defaultSpecs: Specs = {
2021
cpuCores: 0,
2122
ramGB: 0,
2223
kvmEnabled: false,
24+
usingDocker: true,
2325
dockerInstalled: false,
2426
dockerComposeInstalled: false,
2527
dockerIsRunning: false,
@@ -30,6 +32,9 @@ export const defaultSpecs: Specs = {
3032
export async function getSpecs() {
3133
const specs: Specs = { ...defaultSpecs };
3234

35+
let wbConfig: WinboatConfig | null = new WinboatConfig(); // Instantiate singleton class
36+
specs.usingDocker = (wbConfig!.config.containerRuntime == "docker")
37+
3338
// Physical CPU cores check
3439
try {
3540
const res = (await execAsync('lscpu -p | egrep -v "^#" | sort -u -t, -k 2,4 | wc -l')).stdout;
@@ -59,15 +64,15 @@ export async function getSpecs() {
5964

6065
// Docker check
6166
try {
62-
const { stdout: dockerOutput } = await execAsync('docker --version');
63-
specs.dockerInstalled = !!dockerOutput;
67+
let { stdout: dockerOutput } = await execAsync(`${wbConfig!.config.containerRuntime} --version`);
68+
specs.dockerInstalled = (!!dockerOutput || !!podmanOutput);
6469
} catch (e) {
6570
console.error('Error checking for Docker installation:', e);
6671
}
6772

6873
// Docker Compose plugin check with version validation
6974
try {
70-
const { stdout: dockerComposeOutput } = await execAsync('docker compose version');
75+
const { stdout: dockerComposeOutput } = await execAsync(`${wbConfig!.config.containerRuntime} compose version`);
7176
if (dockerComposeOutput) {
7277
// Example output: "Docker Compose version v2.35.1"
7378
// Example output 2: "Docker Compose version 2.36.2"
@@ -87,16 +92,16 @@ export async function getSpecs() {
8792

8893
// Docker is running check
8994
try {
90-
const { stdout: dockerOutput } = await execAsync('docker ps');
95+
const { stdout: dockerOutput } = await execAsync(`${wbConfig!.config.containerRuntime} ps`);
9196
specs.dockerIsRunning = !!dockerOutput;
9297
} catch (e) {
93-
console.error('Error checking if Docker is running:', e);
98+
console.error('Error checking if Container Manager is running:', e);
9499
}
95100

96101
// Docker user group check
97102
try {
98103
const userGroups = (await execAsync('id -Gn')).stdout;
99-
specs.dockerIsInUserGroups = userGroups.split(/\s+/).includes('docker');
104+
specs.dockerIsInUserGroups = (wbConfig!.config.containerRuntime != "docker" || userGroups.split(/\s+/).includes('docker'));
100105
} catch (e) {
101106
console.error('Error checking user groups for docker:', e);
102107
}

src/renderer/lib/winboat.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -374,10 +374,10 @@ export class Winboat {
374374

375375
async getContainerStatus() {
376376
try {
377-
const { stdout: _containerStatus } = await execAsync(`docker inspect --format="{{.State.Status}}" WinBoat`);
377+
const { stdout: _containerStatus } = await execAsync(`${this.#wbConfig!.config.containerRuntime} inspect --format="{{.State.Status}}" WinBoat`);
378378
return _containerStatus.trim() as ContainerStatusValue;
379379
} catch(e) {
380-
console.error("Failed to get container status, most likely we are in the process of resetting");
380+
console.error(`Failed to get container status, most likely we are in the process of resetting ${this.#wbConfig!.config.containerRuntime}`);
381381
return ContainerStatus.Dead;
382382
}
383383
}
@@ -448,7 +448,7 @@ export class Winboat {
448448
logger.info("Starting WinBoat container...");
449449
this.containerActionLoading.value = true;
450450
try {
451-
const { stdout } = await execAsync("docker container start WinBoat");
451+
const { stdout } = await execAsync(`${this.#wbConfig!.config.containerRuntime} container start WinBoat`);
452452
logger.info(`Container response: ${stdout}`);
453453
} catch(e) {
454454
logger.error("There was an error performing the container action.");
@@ -463,7 +463,7 @@ export class Winboat {
463463
logger.info("Stopping WinBoat container...");
464464
this.containerActionLoading.value = true;
465465
try {
466-
const { stdout } = await execAsync("docker container stop WinBoat");
466+
const { stdout } = await execAsync(`${this.#wbConfig!.config.containerRuntime} container stop WinBoat`);
467467
logger.info(`Container response: ${stdout}`);
468468
} catch(e) {
469469
logger.error("There was an error performing the container action.");
@@ -478,7 +478,7 @@ export class Winboat {
478478
logger.info("Pausing WinBoat container...");
479479
this.containerActionLoading.value = true;
480480
try {
481-
const { stdout } = await execAsync("docker container pause WinBoat");
481+
const { stdout } = await execAsync(`${this.#wbConfig!.config.containerRuntime} container pause WinBoat`);
482482
logger.info(`Container response: ${stdout}`);
483483
// TODO: The heartbeat check should set this, but it doesn't because normal fetch timeout doesn't exist
484484
// Fix it once you change fetch to something else
@@ -496,7 +496,7 @@ export class Winboat {
496496
logger.info("Unpausing WinBoat container...");
497497
this.containerActionLoading.value = true;
498498
try {
499-
const { stdout } = await execAsync("docker container unpause WinBoat");
499+
const { stdout } = await execAsync(`${this.#wbConfig!.config.containerRuntime} container unpause WinBoat`);
500500
logger.info(`Container response: ${stdout}`);
501501
} catch(e) {
502502
logger.error("There was an error performing the container action.");
@@ -519,7 +519,7 @@ export class Winboat {
519519
}
520520

521521
// 1. Compose down the current container
522-
await execAsync(`docker compose -f ${composeFilePath} down`);
522+
await execAsync(`${this.#wbConfig!.config.containerRuntime} compose -f ${composeFilePath} down`);
523523

524524
// 2. Create a backup directory if it doesn't exist
525525
const backupDir = path.join(WINBOAT_DIR, 'backup');
@@ -539,7 +539,7 @@ export class Winboat {
539539
logger.info(`Wrote new compose file to: ${composeFilePath}`);
540540

541541
// 5. Deploy the container with the new compose file
542-
await execAsync(`docker compose -f ${composeFilePath} up -d`);
542+
await execAsync(`${this.#wbConfig!.config.containerRuntime} compose -f ${composeFilePath} up -d`);
543543

544544
logger.info("Replace compose config completed, successfully deployed new container");
545545

@@ -554,15 +554,15 @@ export class Winboat {
554554
console.info("Stopped container");
555555

556556
// 2. Remove the container
557-
await execAsync("docker rm WinBoat")
557+
await execAsync(`${this.#wbConfig!.config.containerRuntime} rm WinBoat`)
558558
console.info("Removed container")
559559

560560
// 3. Remove the container volume or folder
561561
const compose = this.parseCompose();
562562
const storage = compose.services.windows.volumes.find(vol => vol.includes('/storage'));
563563
if (storage?.startsWith("data:")) {
564564
// In this case we have a volume (legacy)
565-
await execAsync("docker volume rm winboat_data");
565+
await execAsync(`${this.#wbConfig!.config.containerRuntime} volume rm winboat_data`);
566566
console.info("Removed volume");
567567
} else {
568568
const storageFolder = storage?.split(":").at(0) ?? null;
@@ -716,4 +716,4 @@ export class Winboat {
716716
get hasQMPInterval() {
717717
return this.#qmpInterval !== null;
718718
}
719-
}
719+
}

src/renderer/utils/getFreeRDP.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ export async function getFreeRDP() {
1919
} catch {}
2020
}
2121
return null;
22-
}
22+
}

src/renderer/views/SetupUI.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
<li class="flex items-center gap-2">
8080
<span v-if="specs.dockerInstalled" class="text-green-500">✔</span>
8181
<span v-else class="text-red-500">✘</span>
82-
Docker installed
82+
Container manager installed
8383
<a href="https://docs.docker.com/engine/install/" @click="openAnchorLink" target="_blank" class="text-violet-400 hover:underline ml-1">How?</a>
8484
</li>
8585
<li class="flex items-center gap-2">
@@ -88,7 +88,7 @@
8888
Docker Compose v2 installed
8989
<a href="https://docs.docker.com/compose/install/#plugin-linux-only" @click="openAnchorLink" target="_blank" class="text-violet-400 hover:underline ml-1">How?</a>
9090
</li>
91-
<li class="flex items-center gap-2">
91+
<li class="flex items-center gap-2" v-if="specs.usingDocker">
9292
<span v-if="specs.dockerIsInUserGroups" class="text-green-500">✔</span>
9393
<span v-else class="text-red-500">✘</span>
9494
User added to the <span class="font-mono bg-neutral-700 rounded-md px-0.5">docker</span> group
@@ -97,7 +97,7 @@
9797
</span>
9898
<a href="https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user" @click="openAnchorLink" target="_blank" class="text-violet-400 hover:underline ml-1">How?</a>
9999
</li>
100-
<li class="flex items-center gap-2">
100+
<li class="flex items-center gap-2" v-if="specs.usingDocker">
101101
<span v-if="specs.dockerIsRunning" class="text-green-500">✔</span>
102102
<span v-else class="text-red-500">✘</span>
103103
Docker daemon is running

0 commit comments

Comments
 (0)