From e2bd09aa2e187fa2d63c4e41d3da661b7bad3703 Mon Sep 17 00:00:00 2001 From: Hexagon Date: Sat, 30 Mar 2024 21:46:47 +0100 Subject: [PATCH] WIP --- deno.json | 4 ++-- lib/managers/init.ts | 12 +++++++----- lib/managers/launchd.ts | 11 ++++++----- lib/managers/systemd.ts | 12 ++++++------ lib/managers/upstart.ts | 14 +++++++------- lib/managers/windows.ts | 5 +++-- lib/service.ts | 2 +- test/managers/systemd.test.ts | 8 ++++---- 8 files changed, 36 insertions(+), 32 deletions(-) diff --git a/deno.json b/deno.json index e13515e..329223d 100644 --- a/deno.json +++ b/deno.json @@ -9,10 +9,10 @@ }, "imports": { "@cross/env": "jsr:@cross/env@^1.0.0", - "@cross/fs": "jsr:@cross/fs@^0.0.7", + "@cross/fs": "jsr:@cross/fs@^0.0.8", "@cross/runtime": "jsr:@cross/runtime@^1.0.0", "@cross/test": "jsr:@cross/test@^0.0.9", - "@cross/utils": "jsr:@cross/utils@^0.8.2", + "@cross/utils": "jsr:@cross/utils@^0.9.1", "@std/assert": "jsr:@std/assert@^0.221.0", "@std/path": "jsr:@std/path@^0.221.0" }, diff --git a/lib/managers/init.ts b/lib/managers/init.ts index f80063b..d46ff76 100644 --- a/lib/managers/init.ts +++ b/lib/managers/init.ts @@ -6,6 +6,8 @@ */ import { exists, mktempdir, writeFile } from "@cross/fs"; +import { dirname } from "@std/path"; +import { resolvedExecPath } from "@cross/utils/execpath"; import { join } from "@std/path"; import type { InstallServiceOptions, UninstallServiceOptions } from "../service.ts"; import type { ServiceInstallResult, ServiceManualStep, ServiceUninstallResult } from "../result.ts"; @@ -66,11 +68,11 @@ class InitService { * @param {InstallServiceOptions} config - Options for the installService function. * @returns {string} - The configuration file content. */ - generateConfig(config: InstallServiceOptions): string { - const denoPath = Deno.execPath(); + async generateConfig(config: InstallServiceOptions): Promise { + const runtimePath = await resolvedExecPath(); + const runtimeDir = dirname(runtimePath); const command = config.cmd; - const servicePath = `${config.path?.join(":")}:${denoPath}:${config.home}/.deno/bin`; - + const servicePath = config.path?.length ? `${config.path?.join(":")}:${runtimeDir}` : runtimeDir; let initScriptContent = initScriptTemplate.replace(/{{name}}/g, config.name); initScriptContent = initScriptContent.replace("{{command}}", command); initScriptContent = initScriptContent.replace("{{path}}", servicePath); @@ -96,7 +98,7 @@ class InitService { throw new Error(`Service '${config.name}' already exists in '${initScriptPath}'.`); } - const initScriptContent = this.generateConfig(config); + const initScriptContent = await this.generateConfig(config); if (onlyGenerate) { return { diff --git a/lib/managers/launchd.ts b/lib/managers/launchd.ts index 5f91e89..d523319 100644 --- a/lib/managers/launchd.ts +++ b/lib/managers/launchd.ts @@ -6,7 +6,7 @@ */ import { exists, mkdir, unlink, writeFile } from "@cross/fs"; import { dirname } from "@std/path"; -import { cwd } from "@cross/utils"; +import { cwd, resolvedExecPath } from "@cross/utils"; import type { ServiceInstallResult, ServiceManualStep, ServiceUninstallResult } from "../result.ts"; import type { InstallServiceOptions, UninstallServiceOptions } from "../service.ts"; const plistTemplate = ` @@ -38,10 +38,11 @@ class LaunchdService { * @param {InstallServiceOptions} options - The options used to generate the Launchd plist configuration file. * @returns {string} The generated Launchd plist configuration file content as a string. */ - generateConfig(options: InstallServiceOptions): string { - const denoPath = Deno.execPath(); + async generateConfig(options: InstallServiceOptions): Promise { + const runtimePath = await resolvedExecPath(); + const runtimeDir = dirname(runtimePath); + const servicePath = options.path?.length ? `${options.path?.join(":")}:${runtimeDir}` : runtimeDir; const commandArgs = options.cmd.split(" "); - const servicePath = `${options.path?.join(":")}:${denoPath}:${options.home}/.deno/bin`; const workingDirectory = options.cwd ? options.cwd : cwd(); let plistContent = plistTemplate.replace(/{{name}}/g, options.name); @@ -82,7 +83,7 @@ class LaunchdService { throw new Error(`Service '${config.name}' already exists.`); } - const plistContent = this.generateConfig(config); + const plistContent = await this.generateConfig(config); if (onlyGenerate) { return { diff --git a/lib/managers/systemd.ts b/lib/managers/systemd.ts index 783c0a8..648f131 100644 --- a/lib/managers/systemd.ts +++ b/lib/managers/systemd.ts @@ -7,7 +7,7 @@ import { exists, mkdir, mktempdir, unlink, writeFile } from "@cross/fs"; import { dirname, join } from "@std/path"; -import { cwd, spawn } from "@cross/utils"; +import { cwd, resolvedExecPath, spawn } from "@cross/utils"; import type { ServiceInstallResult, ServiceManualStep, ServiceUninstallResult } from "../result.ts"; import type { InstallServiceOptions, UninstallServiceOptions } from "../service.ts"; @@ -63,7 +63,7 @@ class SystemdService { } } - const serviceFileContent = this.generateConfig(config); + const serviceFileContent = await this.generateConfig(config); if (onlyGenerate) { return { @@ -177,10 +177,10 @@ class SystemdService { * @param {InstallServiceOptions} options - The options used to generate the systemd service configuration file. * @returns {string} The generated systemd service configuration file content as a string. */ - generateConfig(options: InstallServiceOptions): string { - const denoPath = Deno.execPath(); - const defaultPath = `PATH=${denoPath}:${options.home}/.deno/bin`; - const envPath = options.path ? `${defaultPath}:${options.path.join(":")}` : defaultPath; + async generateConfig(options: InstallServiceOptions): Promise { + const runtimePath = await resolvedExecPath(); + const runtimeDir = dirname(runtimePath); + const envPath = "PATH=" + (options.path?.length ? `${options.path?.join(":")}:${runtimeDir}` : runtimeDir); const workingDirectory = options.cwd ? options.cwd : cwd(); let serviceFileContent = serviceFileTemplate.replace("{{name}}", options.name); diff --git a/lib/managers/upstart.ts b/lib/managers/upstart.ts index 0997693..700a79e 100644 --- a/lib/managers/upstart.ts +++ b/lib/managers/upstart.ts @@ -6,8 +6,8 @@ */ import { exists, mktempdir, unlink, writeFile } from "@cross/fs"; -import { join } from "@std/path"; -import { cwd } from "@cross/utils"; +import { dirname, join } from "@std/path"; +import { cwd, resolvedExecPath } from "@cross/utils"; import type { InstallServiceOptions, UninstallServiceOptions } from "../service.ts"; import type { ServiceInstallResult, ServiceManualStep, ServiceUninstallResult } from "../result.ts"; @@ -41,10 +41,10 @@ class UpstartService { * @param config - The configuration options for the service. * @returns The generated Upstart configuration file content. */ - generateConfig(config: InstallServiceOptions): string { - const denoPath = Deno.execPath(); - const defaultPath = `${denoPath}:${config.home}/.deno/bin`; - const envPath = config.path ? `${defaultPath}:${config.path.join(":")}` : defaultPath; + async generateConfig(config: InstallServiceOptions): Promise { + const runtimePath = await resolvedExecPath(); + const runtimeDir = dirname(runtimePath); + const envPath = config.path?.length ? `${config.path?.join(":")}:${runtimeDir}` : runtimeDir; const workingDirectory = config.cwd ? config.cwd : cwd(); let upstartFileContent = upstartFileTemplate.replace( @@ -88,7 +88,7 @@ class UpstartService { throw new Error(`Service '${config.name}' already exists in '${upstartFilePath}'.`); } - const upstartFileContent = this.generateConfig(config); + const upstartFileContent = await this.generateConfig(config); if (onlyGenerate) { return { diff --git a/lib/managers/windows.ts b/lib/managers/windows.ts index 10e24e7..ab7e7c2 100644 --- a/lib/managers/windows.ts +++ b/lib/managers/windows.ts @@ -28,7 +28,7 @@ class WindowsService { throw new Error(`Service '${config.name}' already exists in '${serviceBatchPath}'.`); } - const batchFileContent = this.generateConfig(config); + const batchFileContent = await this.generateConfig(config); if (onlyGenerate) { return { @@ -127,7 +127,7 @@ class WindowsService { * @param {InstallServiceOptions} options - The options used to generate the batch file. * @returns {string} The generated batch file content as a string. */ - generateConfig(options: InstallServiceOptions): string { + async generateConfig(options: InstallServiceOptions): Promise { const defaultPath = `%PATH%;`; const envPath = options.path ? `${defaultPath};${options.path.join(";")}` : defaultPath; const workingDirectory = options.cwd ? options.cwd : cwd(); @@ -144,6 +144,7 @@ class WindowsService { } batchFileContent += `"deno run -A --allow-ffi --unstable https://deno.land/x/windows_service@1.0.11/run.ts --serviceName ${options.name} -- ${options.cmd}\n`; + await true; return batchFileContent; } diff --git a/lib/service.ts b/lib/service.ts index b4d4ef9..e82263f 100644 --- a/lib/service.ts +++ b/lib/service.ts @@ -56,7 +56,7 @@ interface UninstallServiceOptions { interface ServiceManagerImplementation { install(options: InstallServiceOptions, onlyGenerate: boolean): Promise; uninstall(options: UninstallServiceOptions): Promise; - generateConfig(options: InstallServiceOptions): string; + generateConfig(options: InstallServiceOptions): Promise; } /** diff --git a/test/managers/systemd.test.ts b/test/managers/systemd.test.ts index 7ed5ab1..36d660d 100644 --- a/test/managers/systemd.test.ts +++ b/test/managers/systemd.test.ts @@ -4,7 +4,7 @@ import { assertEquals, assertStringIncludes } from "@std/assert"; import { test } from "@cross/test"; import type { ServiceInstallResult } from "../../lib/result.ts"; -test("generateConfig should create a valid service configuration", () => { +test("generateConfig should create a valid service configuration", async () => { const options: InstallServiceOptions = { name: "test-service", cmd: "deno run --allow-net server.ts", @@ -14,7 +14,7 @@ test("generateConfig should create a valid service configuration", () => { path: ["/usr/local/bin"], }; const systemdService = new SystemdService(); - const generatedConfig = systemdService.generateConfig(options); + const generatedConfig = await systemdService.generateConfig(options); assertStringIncludes(generatedConfig, "Description=test-service (Deno Service)"); assertStringIncludes(generatedConfig, 'ExecStart=/bin/sh -c "deno run --allow-net server.ts"'); @@ -48,7 +48,7 @@ test("install should create and display service configuration in user mode (dry- assertStringIncludes(installResult.serviceFileContent, 'ExecStart=/bin/sh -c "deno run --allow-net server.ts"'); }); -test("generateConfig should contain multi-user.target in system mode", () => { +test("generateConfig should contain multi-user.target in system mode", async () => { const options: InstallServiceOptions = { name: "test-service", cmd: "deno run --allow-net server.ts", @@ -58,7 +58,7 @@ test("generateConfig should contain multi-user.target in system mode", () => { path: ["/usr/local/bin"], }; const systemdService = new SystemdService(); - const generatedConfig = systemdService.generateConfig(options); + const generatedConfig = await systemdService.generateConfig(options); assertStringIncludes(generatedConfig, "WantedBy=multi-user.target"); });