summaryrefslogtreecommitdiff
path: root/u/process
diff options
context:
space:
mode:
Diffstat (limited to 'u/process')
-rw-r--r--u/process/argv.ts79
-rw-r--r--u/process/env.ts25
-rw-r--r--u/process/exec.ts86
-rw-r--r--u/process/index.ts5
-rw-r--r--u/process/signals.ts49
-rw-r--r--u/process/validate_identifier.ts18
6 files changed, 0 insertions, 262 deletions
diff --git a/u/process/argv.ts b/u/process/argv.ts
deleted file mode 100644
index 396fa96..0000000
--- a/u/process/argv.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-import { Either, type Mapper, type IEither, Optional } from '@emprespresso/pengueno';
-
-export const isArgKey = <K extends string>(k: string): k is K => k.startsWith('--');
-
-interface ArgHandler<V> {
- absent?: V;
- unspecified?: V;
- present: Mapper<string, V>;
-}
-
-export const getArg = <K extends string, V>(
- arg: K,
- argv: Array<string>,
- whenValue: ArgHandler<V>,
-): IEither<Error, V> => {
- const argIndex = Optional.from(argv.findIndex((_argv) => isArgKey(_argv) && _argv.split('=')[0] === arg)).filter(
- (index) => index >= 0 && index < argv.length,
- );
- if (!argIndex.present()) {
- return Optional.from(whenValue.absent)
- .map((v) => Either.right<Error, V>(v))
- .orSome(() =>
- Either.left(
- new Error(`arg ${arg} is not present in arguments list and does not have an 'absent' value`),
- ),
- )
- .get();
- }
-
- return argIndex
- .flatMap((idx) =>
- Optional.from(argv.at(idx)).map((_argv) => (_argv.includes('=') ? _argv.split('=')[1] : argv.at(idx + 1))),
- )
- .filter((next) => !isArgKey(next))
- .map((next) => whenValue.present(next))
- .orSome(() => whenValue.unspecified)
- .map((v) => Either.right<Error, V>(<V>v))
- .get();
-};
-
-type MappedArgs<
- Args extends ReadonlyArray<string>,
- Handlers extends Partial<Record<Args[number], ArgHandler<unknown>>>,
-> = {
- [K in Args[number]]: K extends keyof Handlers ? (Handlers[K] extends ArgHandler<infer T> ? T : string) : string;
-};
-
-export const argv = <
- const Args extends ReadonlyArray<string>,
- const Handlers extends Partial<Record<Args[number], ArgHandler<unknown>>>,
->(
- args: Args,
- handlers?: Handlers,
- argv = process.argv.slice(2),
-): IEither<Error, MappedArgs<Args, Handlers>> => {
- type Result = MappedArgs<Args, Handlers>;
-
- const defaultHandler: ArgHandler<string> = { present: (value: string) => value };
-
- const processArg = (arg: Args[number]): IEither<Error, [Args[number], unknown]> => {
- const handler = handlers?.[arg] ?? defaultHandler;
- return getArg(arg, argv, handler).mapRight((value) => [arg, value] as const);
- };
-
- const res = args
- .map(processArg)
- .reduce(
- (acc: IEither<Error, Partial<Result>>, current: IEither<Error, [Args[number], unknown]>) =>
- acc.flatMap((accValue) =>
- current.mapRight(([key, value]) => ({
- ...accValue,
- [key]: value,
- })),
- ),
- Either.right(<Partial<Result>>{}),
- )
- .mapRight((result) => <Result>result);
- return res;
-};
diff --git a/u/process/env.ts b/u/process/env.ts
deleted file mode 100644
index f59fadf..0000000
--- a/u/process/env.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { IOptional, Either, Optional, type IEither, type ObjectFromList } from '@emprespresso/pengueno';
-
-// type safe environment variables
-
-export const getEnv = (name: string): IOptional<string> => Optional.from(process.env[name]);
-
-export const getRequiredEnv = <V extends string>(name: V): IEither<Error, string> =>
- Either.fromFailable(() => getEnv(name).get()).mapLeft(
- () => new Error(`environment variable "${name}" is required D:`),
- );
-
-export const getRequiredEnvVars = <V extends string>(vars: Array<V>): IEither<Error, ObjectFromList<typeof vars>> => {
- type Environment = ObjectFromList<typeof vars>;
- const emptyEnvironment = Either.right<Error, Environment>(<Environment>{});
- const addTo = (env: Environment, key: V, val: string) =>
- <Environment>{
- ...env,
- [key]: val,
- };
- return vars.reduce(
- (environment, key) =>
- environment.joinRight(getRequiredEnv(key), (value, environment) => addTo(environment, key, value)),
- emptyEnvironment,
- );
-};
diff --git a/u/process/exec.ts b/u/process/exec.ts
deleted file mode 100644
index 46b31c4..0000000
--- a/u/process/exec.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-import {
- Either,
- IEither,
- type ITraceable,
- LogLevel,
- LogMetricTraceSupplier,
- Metric,
- TraceUtil,
-} from '@emprespresso/pengueno';
-import { exec } from 'node:child_process';
-
-export type Command = string[] | string;
-export type StdStreams = { stdout: string; stderr: string };
-
-export const CmdMetric = Metric.fromName('Exec').asResult();
-type Environment = Record<string, string>;
-type Options = { streamTraceable?: Array<'stdout' | 'stderr'>; env?: Environment; clearEnv?: boolean };
-export const getStdout = (
- cmd: ITraceable<Command, LogMetricTraceSupplier>,
- options: Options = { streamTraceable: [] },
-): Promise<IEither<Error, string>> =>
- cmd
- .flatMap(TraceUtil.withFunctionTrace(getStdout))
- .flatMap((tCmd) => tCmd.traceScope(() => `Command = ${tCmd.get()}`))
- .map((tCmd) => {
- const cmd = tCmd.get();
- const _exec = typeof cmd === 'string' ? cmd : cmd.join(' ');
- const env = options.clearEnv ? options.env : { ...process.env, ...options.env };
- return Either.fromFailableAsync<Error, StdStreams>(
- new Promise<StdStreams>((res, rej) => {
- const proc = exec(_exec, { env });
- let stdout = '';
- proc.stdout?.on('data', (d) => {
- const s = d.toString();
- stdout += s;
- if (options.streamTraceable?.includes('stdout')) {
- tCmd.trace.trace(s);
- }
- });
- let stderr = '';
- proc.stderr?.on('data', (d) => {
- const s = d.toString();
- stdout += s;
- if (options.streamTraceable?.includes('stderr')) {
- tCmd.trace.trace(s);
- }
- });
-
- proc.on('exit', (code) => {
- const streams = { stdout, stderr };
- if (code === 0) {
- res(streams);
- } else {
- rej(new Error(`exited with non-zero code: ${code}. ${stderr}`));
- }
- });
- }),
- );
- })
- .map(
- TraceUtil.promiseify((tEitherStdStreams) =>
- tEitherStdStreams.get().mapRight(({ stderr, stdout }) => {
- if (stderr) tEitherStdStreams.trace.traceScope(LogLevel.DEBUG).trace(`StdErr = ${stderr}`);
- return stdout;
- }),
- ),
- )
- .peek(TraceUtil.promiseify(TraceUtil.traceResultingEither(CmdMetric)))
- .get();
-
-export const getStdoutMany = (
- cmds: ITraceable<Array<Command>, LogMetricTraceSupplier>,
- options: Options = { streamTraceable: [] },
-): Promise<IEither<Error, Array<string>>> =>
- cmds
- .coExtend((t) => t.get())
- .reduce(
- async (_result, tCmd) => {
- const result = await _result;
- return result.joinRightAsync(
- () => tCmd.map((cmd) => getStdout(cmd, options)).get(),
- (stdout, pre) => pre.concat(stdout),
- );
- },
- Promise.resolve(Either.right<Error, Array<string>>([])),
- );
diff --git a/u/process/index.ts b/u/process/index.ts
deleted file mode 100644
index 2d74a5f..0000000
--- a/u/process/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export * from './exec.js';
-export * from './env.js';
-export * from './validate_identifier.js';
-export * from './argv.js';
-export * from './signals.js';
diff --git a/u/process/signals.ts b/u/process/signals.ts
deleted file mode 100644
index c4feb7a..0000000
--- a/u/process/signals.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import {
- Either,
- IEither,
- IMetric,
- ITraceable,
- LogMetricTrace,
- LogMetricTraceSupplier,
- Mapper,
- Metric,
- Optional,
- ResultMetric,
- SideEffect,
- TraceUtil,
-} from '@emprespresso/pengueno';
-
-export const SigIntMetric = Metric.fromName('SigInt').asResult();
-export const SigTermMetric = Metric.fromName('SigTerm').asResult();
-
-export interface Closeable<TFailure> {
- readonly close: SideEffect<SideEffect<TFailure | undefined>>;
-}
-
-export class Signals {
- public static async awaitClose<E extends Error>(
- t: ITraceable<Closeable<E>, LogMetricTraceSupplier>,
- ): Promise<IEither<Error, void>> {
- const success: IEither<Error, void> = Either.right(<void>undefined);
- return new Promise<IEither<Error, void>>((res) => {
- const metricizedInterruptHandler = (metric: ResultMetric) => (err: Error | undefined) =>
- t
- .flatMap(TraceUtil.withMetricTrace(metric))
- .peek((_t) => _t.trace.trace('closing'))
- .move(
- Optional.from(err)
- .map((e) => Either.left<Error, void>(e))
- .orSome(() => success)
- .get(),
- )
- .flatMap(TraceUtil.traceResultingEither(metric))
- .map((e) => res(e.get()))
- .peek((_t) => _t.trace.trace('finished'))
- .get();
- const sigintCloser = metricizedInterruptHandler(SigIntMetric);
- const sigtermCloser = metricizedInterruptHandler(SigTermMetric);
- process.on('SIGINT', () => t.flatMap(TraceUtil.withTrace('SIGINT')).get().close(sigintCloser));
- process.on('SIGTERM', () => t.flatMap(TraceUtil.withTrace('SIGTERM')).get().close(sigtermCloser));
- });
- }
-}
diff --git a/u/process/validate_identifier.ts b/u/process/validate_identifier.ts
deleted file mode 100644
index 1ff3791..0000000
--- a/u/process/validate_identifier.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { Either, type IEither } from '@emprespresso/pengueno';
-
-export const validateIdentifier = (token: string) => {
- return /^[a-zA-Z0-9_\-:. \/]+$/.test(token) && !token.includes('..');
-};
-
-// ensure {@param obj} is a Record<string, string> with stuff that won't
-// have the potential for shell injection, just to be super safe.
-type InvalidEntry<K, T> = [K, T];
-export const validateExecutionEntries = <T, K extends symbol | number | string = symbol | number | string>(
- obj: Record<K, T>,
-): IEither<Array<InvalidEntry<K, T>>, Record<string, string>> => {
- const invalidEntries = <Array<InvalidEntry<K, T>>>(
- Object.entries(obj).filter((e) => !e.every((x) => typeof x === 'string' && validateIdentifier(x)))
- );
- if (invalidEntries.length > 0) return Either.left(invalidEntries);
- return Either.right(<Record<string, string>>obj);
-};