Skip to content

Commit

Permalink
Make cross runtime
Browse files Browse the repository at this point in the history
  • Loading branch information
Hexagon committed Mar 17, 2024
1 parent 0cb4824 commit 82cd12e
Show file tree
Hide file tree
Showing 17 changed files with 231 additions and 274 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/bun.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: Bun CI

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: antongolub/action-setup-bun@v1.12.8
with:
bun-version: v1.x # Uses latest bun 1
- run: bun x jsr add @cross/test @std/assert @cross/runtime # Installs dependencies
- run: bun test # Runs the tests
32 changes: 32 additions & 0 deletions .github/workflows/deno.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Deno CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Setup repo
uses: actions/checkout@v4

- name: Setup Deno
uses: denoland/setup-deno@v1
with:
deno-version: v1.x

- name: Verify formatting
run: deno fmt --check

- name: Run linter
run: deno lint

- name: Check types
run: deno check mod.ts

- name: Run tests
run: deno test
20 changes: 20 additions & 0 deletions .github/workflows/jsr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Publish to jsr
on:
release:
types: [released]

workflow_dispatch:

jobs:
publish:
runs-on: ubuntu-latest

permissions:
contents: read
id-token: write

steps:
- uses: actions/checkout@v4

- name: Publish package
run: npx jsr publish
22 changes: 22 additions & 0 deletions .github/workflows/node.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Node.js CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [18.x, 21.x]

steps:
- uses: actions/checkout@v3
- run: npx jsr add @cross/test @std/assert @cross/runtime
- run: "echo '{ \"type\": \"module\" }' > package.json" # Needed for tsx to work
- run: npx --yes tsx --test utils/*.test.ts
14 changes: 7 additions & 7 deletions lib/cli/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* @license MIT
*/

import { ArgsParser } from "@cross/utils/args";
import { ArgsParser } from "@cross/utils/args"

/**
* Parses command line arguments and returns a parsed object.
Expand All @@ -14,7 +14,7 @@ import { ArgsParser } from "@cross/utils/args";
* @returns - A parsed object containing the command line arguments.
*/
function parseArguments(args: string[]): ArgsParser {
return new ArgsParser(args);
return new ArgsParser(args)
}

/**
Expand All @@ -25,7 +25,7 @@ function parseArguments(args: string[]): ArgsParser {
*/
function checkArguments(args: ArgsParser): ArgsParser {
// Check if the base argument is undefined or valid
const baseArgument = args.countLoose() > 0 ? args.getLoose()[0] : undefined;
const baseArgument = args.countLoose() > 0 ? args.getLoose()[0] : undefined
const validBaseArguments = ["install", "uninstall", "generate"]
if (baseArgument !== undefined && (typeof baseArgument !== "string" || !validBaseArguments.includes(baseArgument))) {
throw new Error(`Invalid base argument: ${baseArgument}`)
Expand All @@ -46,10 +46,10 @@ function checkArguments(args: ArgsParser): ArgsParser {
}
}

// Check that name is set
if (!args.count("name")) {
throw new Error("Service name must be specified.")
}
// Check that name is set
if (!args.count("name")) {
throw new Error("Service name must be specified.")
}

return args
}
Expand Down
11 changes: 6 additions & 5 deletions lib/cli/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import { printFlags, printUsage } from "./output.ts"
import { checkArguments, parseArguments } from "./args.ts"
import { installService, uninstallService } from "../service.ts"
import { exit } from "@cross/utils";
import { exit } from "@cross/utils"

/**
* Define the main entry point of the CLI application
Expand All @@ -24,7 +24,8 @@ async function main(inputArgs: string[]) {
args = checkArguments(parseArguments(inputArgs))
} catch (e) {
console.error(e.message)
Deno.exit(1)
exit(1)
return
}

// Extract base argument
Expand All @@ -34,7 +35,7 @@ async function main(inputArgs: string[]) {
printUsage()
console.log("")
printFlags()
Deno.exit(0)
exit(0)
}

// Handle arguments
Expand All @@ -54,10 +55,10 @@ async function main(inputArgs: string[]) {
if (baseArgument === "install" || baseArgument === "generate") {
try {
await installService({ system, name, cmd, cwd, user, home, path, env }, baseArgument === "generate", force)
Deno.exit(0)
exit(0)
} catch (e) {
console.error(`Could not install service, error: ${e.message}`)
Deno.exit(1)
exit(1)
}
/**
* Handle the uninstall argument
Expand Down
2 changes: 1 addition & 1 deletion lib/cli/output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* @license MIT
*/

import metadata from "../../deno.json" with { type: "json" };
import metadata from "../../deno.json" with { type: "json" }

export function printHeader() {
console.log(metadata.name + " " + metadata.version)
Expand Down
23 changes: 14 additions & 9 deletions lib/managers/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
* @license MIT
*/

import { existsSync } from "../../deps.ts"
import { exists } from "../utils/exists.ts"
import { InstallServiceOptions, UninstallServiceOptions } from "../service.ts"
import { getEnv } from "@cross/env"
import { join } from "@std/path"
import { mkdtemp, writeFile } from "node:fs/promises"
import { exit } from "@cross/utils"

const initScriptTemplate = `#!/bin/sh
### BEGIN INIT INFO
Expand Down Expand Up @@ -67,7 +71,7 @@ class InitService {
generateConfig(config: InstallServiceOptions): string {
const denoPath = Deno.execPath()
const command = config.cmd
const servicePath = `${config.path?.join(":")}:${denoPath}:${Deno.env.get("HOME")}/.deno/bin`
const servicePath = `${config.path?.join(":")}:${denoPath}:${getEnv("HOME")}/.deno/bin`

let initScriptContent = initScriptTemplate.replace(/{{name}}/g, config.name)
initScriptContent = initScriptContent.replace("{{command}}", command)
Expand All @@ -90,9 +94,9 @@ class InitService {
async install(config: InstallServiceOptions, onlyGenerate: boolean) {
const initScriptPath = `/etc/init.d/${config.name}`

if (existsSync(initScriptPath)) {
if (await exists(initScriptPath)) {
console.error(`Service '${config.name}' already exists in '${initScriptPath}'. Exiting.`)
Deno.exit(1)
exit(1)
}

const initScriptContent = this.generateConfig(config)
Expand All @@ -104,8 +108,9 @@ class InitService {
console.log(initScriptContent)
} else {
// Store temporary file
const tempFilePath = await Deno.makeTempFile()
await Deno.writeTextFile(tempFilePath, initScriptContent)
const tempFilePathDir = await mkdtemp("svcinstall")
const tempFilePath = join(tempFilePathDir, "svc-init")
await writeFile(tempFilePath, initScriptContent)

console.log("\nThe service installer does not have (and should not have) root permissions, so the next steps have to be carried out manually.")
console.log(`\nStep 1: The init script has been saved to a temporary file, copy this file to the correct location using the following command:`)
Expand All @@ -119,12 +124,12 @@ class InitService {
}
}

uninstall(config: UninstallServiceOptions) {
async uninstall(config: UninstallServiceOptions) {
const initScriptPath = `/etc/init.d/${config.name}`

if (!existsSync(initScriptPath)) {
if (!await exists(initScriptPath)) {
console.error(`Service '${config.name}' does not exist in '${initScriptPath}'. Exiting.`)
Deno.exit(1)
exit(1)
}

console.log("The uninstaller does not have (and should not have) root permissions, so the next steps have to be carried out manually.")
Expand Down
26 changes: 14 additions & 12 deletions lib/managers/launchd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
* @file lib/managers/launchd.ts
* @license MIT
*/

import { existsSync, path } from "../../deps.ts"
import { exists } from "../utils/exists.ts"
import { InstallServiceOptions, UninstallServiceOptions } from "../service.ts"
import { dirname } from "@std/path"
import { cwd, exit } from "@cross/utils"
import { mkdir, unlink, writeFile } from "node:fs/promises"

const plistTemplate = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
Expand Down Expand Up @@ -41,7 +43,7 @@ class LaunchdService {
const denoPath = Deno.execPath()
const commandArgs = options.cmd.split(" ")
const servicePath = `${options.path?.join(":")}:${denoPath}:${options.home}/.deno/bin`
const workingDirectory = options.cwd ? options.cwd : Deno.cwd()
const workingDirectory = options.cwd ? options.cwd : cwd()

let plistContent = plistTemplate.replace(/{{name}}/g, options.name)
plistContent = plistContent.replace(/{{path}}/g, servicePath)
Expand Down Expand Up @@ -77,9 +79,9 @@ class LaunchdService {
const plistPath = config.system ? plistPathSystem : plistPathUser

// Do not allow to overwrite existing services, regardless of mode
if (existsSync(plistPathUser) || existsSync(plistPathSystem)) {
if (await exists(plistPathUser) || await exists(plistPathSystem)) {
console.error(`Service '${config.name}' already exists. Exiting.`)
Deno.exit(1)
exit(1)
}

const plistContent = this.generateConfig(config)
Expand All @@ -90,11 +92,11 @@ class LaunchdService {
console.log("\nConfiguration:\n")
console.log(plistContent)
} else {
const plistDir = path.dirname(plistPath)
await Deno.mkdir(plistDir, { recursive: true })
const plistDir = dirname(plistPath)
await mkdir(plistDir, { recursive: true })

// ToDo: Remember to rollback on failure
await Deno.writeTextFile(plistPath, plistContent)
await writeFile(plistPath, plistContent)

console.log(`Service '${config.name}' installed at '${plistPath}'.`)

Expand All @@ -117,7 +119,7 @@ class LaunchdService {
*/
async rollback(plistPath: string) {
try {
await Deno.remove(plistPath)
await unlink(plistPath)
console.log(`Changes rolled back: Removed '${plistPath}'.`)
} catch (error) {
console.error(`Failed to rollback changes: Could not remove '${plistPath}'. Error: ${error.message}`)
Expand All @@ -138,13 +140,13 @@ class LaunchdService {
const plistPath = config.system ? plistPathSystem : plistPathUser

// Check if the service exists
if (!existsSync(plistPath)) {
if (!await exists(plistPath)) {
console.error(`Service '${config.name}' does not exist. Exiting.`)
Deno.exit(1)
exit(1)
}

try {
await Deno.remove(plistPath)
await unlink(plistPath)
console.log(`Service '${config.name}' uninstalled successfully.`)

// Unload the service
Expand Down
Loading

0 comments on commit 82cd12e

Please sign in to comment.