Skip to content

Commit

Permalink
Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
Hexagon committed Apr 12, 2024
1 parent b160fa3 commit d60b93c
Show file tree
Hide file tree
Showing 24 changed files with 90 additions and 146 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/deno.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:

steps:
- name: Git Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Use Deno Version ${{ matrix.deno-version }}
uses: denoland/setup-deno@v1
Expand Down
2 changes: 1 addition & 1 deletion application.meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

const Application = {
name: "pup",
version: "1.0.0-rc.14",
version: "1.0.0-rc.15",
url: "https://deno.land/x/pup@$VERSION/pup.ts",
canary_url: "https://raw.githubusercontent.com/Hexagon/pup/main/pup.ts",
deno: null, /* Minimum stable version of Deno required to run Pup (without --unstable-* flags) */
Expand Down
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@
"@std/assert": "jsr:@std/assert@^0.221.0",
"@std/async": "jsr:@std/async@^0.221.0",
"@std/io": "jsr:@std/io@^0.221.0",
"@std/jsonc": "jsr:@std/jsonc@^0.221.0",
"@std/path": "jsr:@std/path@^0.221.0",
"@std/semver": "jsr:@std/semver@^0.221.0",
"@std/testing": "jsr:@std/testing@^0.221.0",
"@std/uuid": "jsr:@std/uuid@^0.221.0",
"dax-sh": "npm:dax-sh@^0.40.0",
"json5": "npm:json5@^2.2.3",
"zod": "npm:zod@^3.22.4",
"zod-to-json-schema": "npm:zod-to-json-schema@^3.22.5"
}
Expand Down
7 changes: 4 additions & 3 deletions docs/src/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ All notable changes to this project will be documented in this section.
- [x] change(cli): Rename cli command `install` to `enable-service`
- [x] change(cli): Rename cli command `uninstall` to `disable-service`
- [ ] change(logging): Make logs streaming by default.
- [ ] change(config): Support JSON5.
- [ ] change(packaging): Use jsr.io instead of deno.land/x for distribution.
- [ ] change(packaging]: Specify installation command for next version in version metadata instead of code, allowing for new installation commands for new versions.
- [x] change(config): Support JSON5.

### Non-breaking

- [ ] fix(core): Foreground command does not keep an autostarted process running.
- [x] fix(cli): Controlled output of manual rests after installing/uninstalling as service.
- [x] fix(docs): Docs incorrectly stated that `**/_._` is default for watcher config. `**/*.*` is correct.
- [ ] chore(docs): Add a PM2 migration guide.

## Maintenance

Expand Down
4 changes: 2 additions & 2 deletions docs/src/examples/basic-webinterface/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ nav_order: 3
The example at [/docs/src/examples/basic-webinterface](https://github.com/Hexagon/pup/tree/main/docs/src/examples/basic-webinterface) borrows the server.ts and task.ts from the basic example. Both
processes have logging configurations, with the second process having custom logger settings which enable the periodic process to write its logs to separate files.

The web interface plugin is enabled by `pup.jsonc` and available at <http://localhost:5000/>
The web interface plugin is enabled by `pup.json` and available at <http://localhost:5000/>

## Example Files

Expand Down Expand Up @@ -43,7 +43,7 @@ intallation, you **can not** use the `$VERSION` variable, and should give an abs

`cd` to `/docs/src/examples/basic-webinterface` directory.

Start example by running `pup run` if pup is installed, or something like `deno run -A ../../../pup.ts run` if not.
Start example by running `pup foreground` if pup is installed, or something like `deno run -A ../../../pup.ts foreground` if not.

Browse to <http://localhost:5000/>

Expand Down
2 changes: 1 addition & 1 deletion docs/src/examples/basic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ its logs to separate files.

`cd` to `/docs/src/examples/basic` directory.

Start example by running `pup run` if pup is installed, or something like `deno run -A ../../../pup.ts run` if not.
Start example by running `pup foreground` if pup is installed, or something like `deno run -A ../../../pup.ts foreground` if not.

Success!
2 changes: 1 addition & 1 deletion docs/src/examples/cluster/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Detailed documentation available at [5. Scaling applications](https://hexagon.gi

`cd` to `/docs/src/examples/cluster` directory.

Run using command `pup run`
Run using command `pup foreground`

Browse to `http://localhost:3456`

Expand Down
4 changes: 2 additions & 2 deletions docs/src/examples/splunk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The example at [/docs/src/examples/splunk](https://github.com/Hexagon/pup/tree/m
output to Splunk using the splunk-hec plugin.

> **Note:** If you're connecting to a Splunk HEC server with a bad certificate, such as during testing, you'll need to start pup manually with the `--unsafely-ignore-certificate-errors` flag. The full
> command for this would be `deno run -Ar --unsafely-ignore-certificate-errors https://deno.land/x/pup/pup.ts run` { .note }
> command for this would be `deno run -Ar --unsafely-ignore-certificate-errors https://deno.land/x/pup/pup.ts foreground` { .note }
## Files

Expand All @@ -29,6 +29,6 @@ The HEC token can be configured in the `pup.jsonc` configuration file as shown i

`cd` to `/docs/src/examples/splunk` directory.

Start the example by running `pup run` if pup is installed, or something like `deno run -A ../../../pup.ts run` if not.
Start the example by running `pup foreground` if pup is installed, or something like `deno run -A ../../../pup.ts foreground` if not.

Success!
2 changes: 1 addition & 1 deletion docs/src/examples/telemetry/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ telemetry.emit("another-process-id", "my-event", { data: { to: "send" } })

`cd` to `docs/examples/telemetry` directory.

Start example by running `pup run` if pup is installed, or something like `deno run -A ../../../pup.ts run` if not.
Start example by running `pup foreground` if pup is installed, or something like `deno run -A ../../../pup.ts foreground` if not.

Now open another terminal and issue `pup status`, a brief overview of current status is shown, including memory usage.

Expand Down
4 changes: 2 additions & 2 deletions docs/src/examples/watcher/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ current directory (configuration `watch: ["."]`).

`cd` to `/docs/src/examples/watcher` directory.

Start example by running `pup run` if pup is installed, pup will automatically pick up the configuration in`pup.jsonc`.
Start example by running `pup foreground` if pup is installed, pup will automatically pick up the configuration in`pup.jsonc`.

Run something like `deno run -A ../../../pup.ts run` if pup is not installed globally.
Run something like `deno run -A ../../../pup.ts foreground` if pup is not installed globally.

Success!
2 changes: 1 addition & 1 deletion docs/src/examples/worker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ process using a worker. The process has logging configurations to write logs to

`cd` to `/docs/src/examples/worker` directory.

Start example by running `pup run` if pup is installed, or something like `deno run -A ../../../pup.ts run` if not.
Start example by running `pup foreground` if pup is installed, or something like `deno run -A ../../../pup.ts foreground` if not.

Success!

Expand Down
4 changes: 2 additions & 2 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ Pup is a powerful process manager for Deno, designed to simplify the management

> **Note** Programmatic usage, process telemetry, and IPC are currently available only when running Deno client processes. { .note }
Pup is centered on a single configuration file, ideally named `pup.json` or `pup.jsonc`, which manages all aspects of the processes to be executed, including their execution methods and logging
handling.
Pup is centered on a single configuration file, `pup.json`, which manages all aspects of the processes to be executed, including their execution methods and logging handling.
[JSON5](https://github.com/json5/json5) syntax is supported.

## Quick Start

Expand Down
4 changes: 2 additions & 2 deletions docs/src/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ This section will guide you through the installation process of Pup.

Before proceeding with the installation, ensure that you have the following installed on your system:

- Deno (version `1.30.x` or higher): You can install Deno by following the official Deno [instructions](https://deno.com/manual/getting_started/installation).
- Deno (version `1.38.x` or higher): You can install Deno by following the official Deno [instructions](https://deno.com/manual/getting_started/installation).

## Installing or upgrading Pup

Expand All @@ -35,7 +35,7 @@ If you already have Pup installed and want to upgrade to the latest version, you
pup upgrade --channel prerelease
```

Both the `setup` and `upgrade` commands support the following parameters:
The `upgrade` command support the following parameters:

- `--version`: Install, upgrade, or downgrade to a specific version.
- `--channel <channel>`: Defaults to stable, but you can also install the `prerelease` or `canary` channel.
Expand Down
10 changes: 5 additions & 5 deletions docs/src/usage/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ configuration file:

- `console` (boolean): Set to true to enable logging to the console. Default is false.
- `stdout` (string): The file path to write standard output logs.
- `stderr` (string): The file path to write standard error logs.
- `stderr` (string): The file path to write standard error logs. If omitted, stderr is redirected to stdout.
- `decorateFiles` (boolean): Set to true to enable decoration in the output files. Default is false.
- `decorate` (boolean): **Only available in global scope.** Set to true to enable decoration in the logs. Default is false.
- `colors` (boolean): **Only available in global scope.** Set to true to enable colored output. Default is false.
Expand Down Expand Up @@ -139,7 +139,7 @@ To change default behavior of the global watcher, use the following properties w

- `interval` (number): The interval (in milliseconds) at which the watcher checks for file changes. Default is `1000`.
- `exts` (array of strings): The file extensions to watch. Default is `["ts", "tsx", "js", "jsx", "json"]`.
- `match` (array of strings): The patterns to match for watched files. Default is `["**/_._"]`.
- `match` (array of strings): The patterns to match for watched files. Default is `["**/*.*"]`.
- `skip` (array of strings): The patterns to exclude from watching. Default is `["**/.git/**"]`.

```json
Expand All @@ -148,7 +148,7 @@ To change default behavior of the global watcher, use the following properties w
"watcher": {
"interval": 100, // default
"exts": ["ts", "tsx", "js", "jsx", "json"], // default
"match": ["**/_._"], // default
"match": ["**/*.*"], // default
"skip": ["**/.git/**"] // default
},

Expand Down Expand Up @@ -194,8 +194,8 @@ To activate plugins, add your plugins to the configuration using this pattern:

## Validating the Configuration

To ensure your configuration is valid, just run `pup run` (or `pup run --config custom/path/to/config.json`). If using pup as a library, you can use the `validateConfiguration()` function provided by
the `/lib/core/configuration.ts` file. This function checks if the configuration adheres to the schema and will throw an error if it doesn't.
To ensure your configuration is valid, just run `pup foreground` (or `pup run --config custom/path/to/config.json`). If using pup as a library, you can use the `validateConfiguration()` function
provided by the `/lib/core/configuration.ts` file. This function checks if the configuration adheres to the schema and will throw an error if it doesn't.

With a valid configuration in place, you're ready to use Pup to manage your processes.

Expand Down
16 changes: 8 additions & 8 deletions docs/src/usage/service.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Follow the guide below to install Pup as a system service and launch at boot. Th

### Prerequisites

Ensure that you have a working environment set up so that you can run `pup run` with a `pup.json` in the current directory, or that you can start Pup using `pup run --config path/to/pup.json`.
Ensure that you have a working environment set up so that you can run `pup foreground` with a `pup.json` in the current directory, or that you can start Pup using `pup run --config path/to/pup.json`.

Now there is two options, User Mode Installation, or System Installation. User Mode Installation is recommended as it rhymes best with Deno, which is installed for the current user. User mode is only
supported with launchd or systemd.
Expand All @@ -34,23 +34,23 @@ Replace `username` with your actual username.

2. Install Pup as a user mode service, named `pup`:

`pup install`
`pup enable-service`

To install multiple services, provide a unique name for each instance:

`pup install --name my-service`
`pup enable-service --name my-service`

### System Mode Installation

**Note**: This method works for all service managers, but may include some manual steps, and will require privileged access (e.g. sudo).

1. Install Pup as a system service, by default named `pup`:

`pup install --system`
`pup enable-service --system`

To install multiple services, provide a unique name for each instance:

`pup install --system --name my-service`
`pup enable-service --system --name my-service`

2. Follow the on-screen instructions to copy the generated configuration file to the correct location, and enable the service.

Expand All @@ -59,8 +59,8 @@ To install multiple services, provide a unique name for each instance:
Use the `pup <method> [...flags]` command with the following methods and flags:

- Methods:
- `install`: Installs the configured Pup instance as a system service, then verifies the installation by enabling and starting the service. Rolls back any changes on error.
- `uninstall`: Uninstall service
- `enable-service`: Installs the configured Pup instance as a system service, then verifies the installation by enabling and starting the service. Rolls back any changes on error.
- `disable-service`: Uninstall service

- Flags:
- `--config`: Specifies the configuration file for the instance to be installed, defaulting to `pup.json` or `pup.jsonc` in the current directory.
Expand Down Expand Up @@ -144,7 +144,7 @@ Description=Pup
After=network.target

[Service]
ExecStart=/home/user/.deno/bin/deno run -A https://deno.land/x/pup/pup.ts run --config /path/to/your/pup.json
ExecStart=/home/user/.deno/bin/deno run -A https://deno.land/x/pup/`pup.ts foreground` --config /path/to/your/pup.json
Restart=always

[Install]
Expand Down
16 changes: 8 additions & 8 deletions lib/cli/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import { Configuration, generateConfiguration, ProcessConfiguration } from "../core/configuration.ts"
import * as jsonc from "@std/jsonc"
import JSON5 from "npm:json5"
import { join } from "@std/path"
import { exists } from "@cross/fs"
import { ArgsParser } from "@cross/utils"
Expand Down Expand Up @@ -55,7 +55,7 @@ export async function appendConfigurationFile(configFile: string, checkedArgs: A
let existingConfigurationObject
try {
const existingConfiguration = await Deno.readTextFile(configFile)
existingConfigurationObject = jsonc.parse(existingConfiguration) as unknown as Configuration
existingConfigurationObject = JSON5.parse(existingConfiguration) as unknown as Configuration
} catch (e) {
throw new Error("Could not read configuration file: " + e.message)
}
Expand Down Expand Up @@ -109,7 +109,7 @@ export async function removeFromConfigurationFile(configFile: string, checkedArg
let existingConfigurationObject
try {
const existingConfiguration = await Deno.readTextFile(configFile)
existingConfigurationObject = jsonc.parse(existingConfiguration) as unknown as Configuration
existingConfigurationObject = JSON5.parse(existingConfiguration) as unknown as Configuration
} catch (e) {
throw new Error("Could not read configuration file.", e.message)
}
Expand Down Expand Up @@ -155,15 +155,15 @@ export async function findConfigFile(cwd: string, useConfigFile?: boolean, argum
}
}

// Try to find configuration file, jsonc first. Take cwd into account.
// Try to find configuration file, JSON5 first. Take cwd into account.
let jsonPath = "./pup.json"
let jsoncPath = "./pup.jsonc"
let JSON5Path = "./pup.JSON5"
if (cwd) {
jsonPath = join(toResolvedAbsolutePath(cwd), jsonPath)
jsoncPath = join(toResolvedAbsolutePath(cwd), jsoncPath)
JSON5Path = join(toResolvedAbsolutePath(cwd), JSON5Path)
}
if (await exists(jsoncPath)) {
return jsoncPath
if (await exists(JSON5Path)) {
return JSON5Path
} else {
return jsonPath
}
Expand Down
38 changes: 29 additions & 9 deletions lib/cli/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ import { toPersistentPath, toResolvedAbsolutePath, toTempPath } from "../common/
import { exists, readFile } from "@cross/fs"

// Import external dependencies
import * as jsonc from "@std/jsonc"
import JSON5 from "json5"
import * as path from "@std/path"
import { Logger } from "../core/logger.ts"

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

import { installService, uninstallService } from "@cross/service"
import { exit } from "@cross/utils"
import { Colors, exit } from "@cross/utils"
import { chdir, cwd } from "@cross/fs"

/**
Expand Down Expand Up @@ -144,7 +144,18 @@ async function main() {
const env = parsedArgs.getArray("env") || []

try {
await installService({ system, name, cmd, cwd, user, home, env }, parsedArgs.getBoolean("dry-run"))
const result = await installService({ system, name, cmd, cwd, user, home, env }, parsedArgs.getBoolean("dry-run"))
if (result.manualSteps && result.manualSteps.length) {
console.log(Colors.bold("To complete the installation, carry out these manual steps:"))
result.manualSteps.forEach((step, index) => {
console.log(Colors.cyan(`${index + 1}. ${step.text}`))
if (step.command) {
console.log(" " + Colors.yellow("Command: ") + step.command)
}
})
} else {
console.log(`Service ´${name}' successfully installed at '${result.servicePath}'.`)
}
exit(0)
} catch (e) {
console.error(`Could not install service, error: ${e.message}`)
Expand All @@ -154,10 +165,19 @@ async function main() {
const system = parsedArgs.getBoolean("system")
const name = parsedArgs.get("name") || "pup"
const home = parsedArgs.get("home")

try {
await uninstallService({ system, name, home })
console.log(`Service '${name}' uninstalled.`)
const result = await uninstallService({ system, name, home })
if (result.manualSteps && result.manualSteps.length) {
console.log(Colors.bold("To complete the uninstallation, carry out these manual steps:"))
result.manualSteps.forEach((step, index) => {
console.log(Colors.cyan(`${index + 1}. ${step.text}`))
if (step.command) {
console.log(" " + Colors.yellow("Command: ") + step.command)
}
})
} else {
console.log(`Service '${name}' at '${result.servicePath}' is now uninstalled.`)
}
exit(0)
} catch (e) {
console.error(`Could not uninstall service, error: ${e.message}`)
Expand All @@ -169,8 +189,8 @@ async function main() {
* Now, handle the argument to generate a new configuration file and exit
*/
if (baseArgument === "init") {
// Default new configuration file to pup.jsonc
const fallbackedConfigFile = configFile ?? "pup.jsonc"
// Default new configuration file to pup.json
const fallbackedConfigFile = configFile ?? "pup.json"
if (await exists(fallbackedConfigFile)) {
console.error(`Configuration file '${fallbackedConfigFile}' already exists, exiting.`)
exit(1)
Expand Down Expand Up @@ -234,7 +254,7 @@ async function main() {
try {
const rawConfig = await readFile(configFile)
const rawConfigText = new TextDecoder().decode(rawConfig)
configuration = validateConfiguration(jsonc.parse(rawConfigText))
configuration = validateConfiguration(JSON5.parse(rawConfigText))
} catch (e) {
console.error(`Could not start, error reading or parsing configuration file '${configFile}': ${e.message}`)
exit(1)
Expand Down
Loading

0 comments on commit d60b93c

Please sign in to comment.