Skip to content

Commit b9c094f

Browse files
committed
initial windows support & bug fixes
Adding initial windows support and some bug fixes. https://github.com/bun-bm2/bm2/issues/19
1 parent 5535835 commit b9c094f

16 files changed

Lines changed: 605 additions & 379 deletions

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ BM2 replaces PM2's Node.js internals with Bun-native APIs. It uses `Bun.spawn` f
106106

107107
**Process Persistence** — Save the current process list and resurrect it after a daemon restart or system reboot. Combined with startup script generation, your applications survive server reboots.
108108

109-
**Startup Script Generation** — Automatically generate and install systemd (Linux) or launchd (macOS) service configurations so the BM2 daemon starts at boot.
109+
**Startup Script Generation** — Automatically generate and install systemd (Linux), launchd (macOS), or Task Scheduler (Windows) service configurations so the BM2 daemon starts at boot.
110110

111111
**Remote Deployment** — A built-in deploy system that handles SSH-based deployment with git pull, release directory management, symlink rotation, and pre/post-deploy hooks.
112112

@@ -885,7 +885,7 @@ Multi-host deployment is supported. Specify an array of hosts to deploy to all o
885885

886886
#### bm2 startup
887887

888-
Generate and display a startup script for your operating system. On Linux, this generates a systemd unit file. On macOS, this generates a launchd plist.
888+
Generate and display a startup script for your operating system. On Linux, this generates a systemd unit file. On macOS, this generates a launchd plist. On Windows, this generates a Task Scheduler configuration and PowerShell script.
889889

890890
```
891891
bm2 startup
@@ -931,7 +931,7 @@ bm2 save
931931
bm2 startup install
932932
```
933933

934-
On reboot, systemd or launchd starts the BM2 daemon, and the daemon automatically runs resurrect to restore your processes.
934+
On reboot, systemd, launchd, or Task Scheduler starts the BM2 daemon, and the daemon automatically runs resurrect to restore your processes.
935935

936936
---
937937

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@
6262
},
6363
"os": [
6464
"linux",
65-
"darwin"
65+
"darwin",
66+
"win32"
6667
],
6768
"dependencies": {
6869
"chalk": "^5.6.2",

src/cluster-manager.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ export class ClusterManager {
5757
const ext = config.script.split(".").pop()?.toLowerCase();
5858
if (ext === "ts" || ext === "tsx" || ext === "js" || ext === "jsx" || ext === "mjs") {
5959
cmd.push("bun", "run");
60-
} else if (ext === "py") {
61-
cmd.push("python3");
62-
} else {
60+
} else if (ext === "py") {
61+
cmd.push(process.platform === "win32" ? "python" : "python3");
62+
} else {
6363
cmd.push("bun", "run");
6464
}
6565
}

src/daemon-v1.ts

Lines changed: 0 additions & 244 deletions
This file was deleted.

src/daemon.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,14 @@ export default class Daemon {
302302
case "moduleList": {
303303
return { type: "moduleList", data: moduleManager.list(), success: true, id: msg.id };
304304
}
305+
case "daemonReload": {
306+
if (!this.server) {
307+
this.server = this.startServer();
308+
} else {
309+
this.server.reload(this.getServerOpts() as any);
310+
}
311+
return { type: "daemonReload", data: "Daemon reloaded", success: true, id: msg.id };
312+
}
305313
case "ping": {
306314
return {
307315
type: "pong",

src/deploy.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -166,11 +166,13 @@
166166
return stdout;
167167
}
168168

169-
private async localExec(command: string): Promise<string> {
170-
const proc = Bun.spawn(["sh", "-c", command], {
171-
stdout: "pipe",
172-
stderr: "pipe",
173-
});
169+
private async localExec(command: string): Promise<string> {
170+
const isWin = process.platform === "win32";
171+
const cmd = isWin ? ["cmd.exe", "/c", command] : ["sh", "-c", command];
172+
const proc = Bun.spawn(cmd, {
173+
stdout: "pipe",
174+
stderr: "pipe",
175+
});
174176

175177
const stdout = await new Response(proc.stdout).text();
176178
const stderr = await new Response(proc.stderr).text();

src/log-manager.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,12 @@
1414
* Author: Zak <zak@maxxpainn.com>
1515
*/
1616

17-
import { join, dirname } from "path";
17+
import { join, dirname, basename } from "path";
1818
import { appendFile, rename, unlink, readdir } from "fs/promises";
1919
import { LOG_DIR, DEFAULT_LOG_MAX_SIZE, DEFAULT_LOG_RETAIN } from "./constants";
2020
import type { LogEntry, LogRotateOptions } from "./types";
2121
import { watch } from "fs";
2222
import type { ReadableStreamController } from "bun";
23-
import { $ } from "bun"
2423
import { EOL } from 'node:os';
2524

2625
const isoRegex: RegExp = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?/;
@@ -152,11 +151,12 @@ export class LogManager {
152151

153152
const level = (fp == paths.errFile) ? "err" : "out";
154153

155-
const rawLog = await $`tail -n ${lines} ${fp}`.text();
154+
const rawLog = await f.text();
156155

157156
return rawLog
158157
.split("\n")
159158
.filter(Boolean)
159+
.slice(-lines)
160160
.map(l => this.parseLine(l, level));
161161

162162
}))).flat();
@@ -168,8 +168,6 @@ export class LogManager {
168168
if (sortedLogs.length > lines) {
169169
sortedLogs = sortedLogs.slice(-lines)
170170
}
171-
172-
console.log(sortedLogs)
173171

174172
return sortedLogs
175173
}
@@ -243,16 +241,25 @@ export class LogManager {
243241

244242
await rename(src, dst);
245243
if (options.compress) {
246-
// Fire-and-forget compression doesn't block the next rename
247-
bgTasks.push(Bun.spawn(["gzip", "-f", dst]).exited);
244+
bgTasks.push((async () => {
245+
try {
246+
const srcFile = Bun.file(dst);
247+
if (await srcFile.exists()) {
248+
const data = await srcFile.arrayBuffer();
249+
const compressed = Bun.gzipSync(new Uint8Array(data));
250+
await Bun.write(`${dst}.gz`, compressed);
251+
await unlink(dst);
252+
}
253+
} catch {}
254+
})());
248255
}
249256
}
250257
}
251258

252259
await Bun.write(filePath, ""); // Instantly truncate and reclaim space
253260

254261
const dir = dirname(filePath);
255-
const baseName = filePath.split("/").pop()!;
262+
const baseName = basename(filePath);
256263

257264
// Background cleanup
258265
bgTasks.push(

0 commit comments

Comments
 (0)