Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codify-plugin-lib",
"version": "1.0.166",
"version": "1.0.173",
"description": "Library plugin library",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
Expand All @@ -16,7 +16,7 @@
"dependencies": {
"ajv": "^8.12.0",
"ajv-formats": "^2.1.1",
"codify-schemas": "1.0.73",
"codify-schemas": "1.0.76",
"@npmcli/promise-spawn": "^7.0.1",
"@homebridge/node-pty-prebuilt-multiarch": "^0.12.0-beta.5",
"uuid": "^10.0.0",
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { MessageHandler } from './messages/handlers.js';
import { Plugin } from './plugin/plugin.js';

export * from './errors.js'
export * from './messages/sender.js'
export * from './plan/change-set.js'
export * from './plan/plan.js'
export * from './plan/plan-types.js'
Expand Down
2 changes: 1 addition & 1 deletion src/messages/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { Plugin } from '../plugin/plugin.js';

const SupportedRequests: Record<string, { handler: (plugin: Plugin, data: any) => Promise<unknown>; requestValidator: SchemaObject; responseValidator: SchemaObject }> = {
'initialize': {
handler: async (plugin: Plugin) => plugin.initialize(),
handler: async (plugin: Plugin, data: any) => plugin.initialize(data),
requestValidator: InitializeRequestDataSchema,
responseValidator: InitializeResponseDataSchema
},
Expand Down
56 changes: 56 additions & 0 deletions src/messages/sender.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Ajv } from 'ajv';
import { IpcMessageV2, IpcMessageV2Schema, MessageCmd, PressKeyToContinueRequestData } from 'codify-schemas';
import { nanoid } from 'nanoid';

const ajv = new Ajv({
strict: true,
});

/**
* Send requests to the Codify CLI
*/
class CodifyCliSenderImpl {
private readonly validateIpcMessageV2 = ajv.compile(IpcMessageV2Schema);

async requestPressKeyToContinuePrompt(message?: string): Promise<void> {
await this.sendAndWaitForResponse(<IpcMessageV2>{
cmd: MessageCmd.PRESS_KEY_TO_CONTINUE_REQUEST,
data: <PressKeyToContinueRequestData>{
promptMessage: message,
}
})
}

private async sendAndWaitForResponse(message: IpcMessageV2): Promise<IpcMessageV2> {
return new Promise((resolve) => {
const requestId = nanoid(8);
const listener = (data: IpcMessageV2) => {
if (data.requestId === requestId) {
process.removeListener('message', listener);

if (!this.validateIpcMessageV2(data)) {
throw new Error(`Invalid response for request.
Request:
${JSON.stringify(message, null, 2)}
Response:
${JSON.stringify(data, null, 2)}
Error:
${JSON.stringify(this.validateIpcMessageV2.errors, null, 2)}`);
}

resolve(data);
}
}

process.on('message', listener);

const ipcMessage = {
...message,
requestId,
}
process.send!(ipcMessage)
})
}
}

export const CodifyCliSender = new CodifyCliSenderImpl();
12 changes: 9 additions & 3 deletions src/plugin/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
GetResourceInfoResponseData,
ImportRequestData,
ImportResponseData,
InitializeRequestData,
InitializeResponseData,
MatchRequestData,
MatchResponseData,
Expand All @@ -23,6 +24,7 @@ import { getPty } from '../pty/index.js';
import { Resource } from '../resource/resource.js';
import { ResourceController } from '../resource/resource-controller.js';
import { ptyLocalStorage } from '../utils/pty-local-storage.js';
import { VerbosityLevel } from '../utils/utils.js';

export class Plugin {
planStorage: Map<string, Plan<any>>;
Expand All @@ -46,7 +48,11 @@ export class Plugin {
return new Plugin(name, controllersMap);
}

async initialize(): Promise<InitializeResponseData> {
async initialize(data: InitializeRequestData): Promise<InitializeResponseData> {
if (data.verbosityLevel) {
VerbosityLevel.set(data.verbosityLevel);
}

for (const controller of this.resourceControllers.values()) {
await controller.initialize();
}
Expand Down Expand Up @@ -107,7 +113,7 @@ export class Plugin {
}

async import(data: ImportRequestData): Promise<ImportResponseData> {
const { core, parameters } = data;
const { core, parameters, autoSearchAll } = data;

if (!this.resourceControllers.has(core.type)) {
throw new Error(`Cannot get info for resource ${core.type}, resource doesn't exist`);
Expand All @@ -116,7 +122,7 @@ export class Plugin {
const result = await ptyLocalStorage.run(this.planPty, () =>
this.resourceControllers
.get(core.type!)
?.import(core, parameters)
?.import(core, parameters, autoSearchAll)
)

return {
Expand Down
18 changes: 11 additions & 7 deletions src/pty/background-pty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as fs from 'node:fs/promises';
import stripAnsi from 'strip-ansi';

import { debugLog } from '../utils/debug.js';
import { VerbosityLevel } from '../utils/utils.js';
import { IPty, SpawnError, SpawnOptions, SpawnResult } from './index.js';
import { PromiseQueue } from './promise-queue.js';

Expand Down Expand Up @@ -76,7 +77,10 @@ export class BackgroundPty implements IPty {
data: strippedData,
});
} else {
process.stdout.write(data);
// Print to stdout if the verbosity level is above 0
if (VerbosityLevel.get() > 0) {
process.stdout.write(data);
}
}
})

Expand All @@ -85,7 +89,7 @@ export class BackgroundPty implements IPty {
// Redirecting everything to the pipe and running in theb background avoids most if not all back-pressure problems
// Done is used to denote the end of the command
// Use the \\" at the end differentiate between command and response. \\" will evaluate to " in the terminal
const command = `((${cdCommand}${cmd}; echo %%%$?%%%done%%%\\") > "/tmp/${cid}" 2>&1 &); echo %%%done%%%${cid}\\";`
const command = ` ((${cdCommand}${cmd}; echo %%%$?%%%done%%%\\") > "/tmp/${cid}" 2>&1 &); echo %%%done%%%${cid}\\";`

let output = '';
const listener = this.basePty.onData((data: any) => {
Expand All @@ -97,7 +101,7 @@ export class BackgroundPty implements IPty {
}
});

console.log(`Running command ${cmd}`)
console.log(`Running command ${cmd}${options?.cwd ? ` (cwd: ${options.cwd})` : ''}`)
this.basePty.write(`${command}\r`);

}));
Expand All @@ -123,10 +127,10 @@ export class BackgroundPty implements IPty {
let outputBuffer = '';

return new Promise(resolve => {
this.basePty.write('set +o history;\n');
this.basePty.write('unset PS1;\n');
this.basePty.write('unset PS0;\n')
this.basePty.write('echo setup complete\\"\n')
this.basePty.write('setopt hist_ignore_space;\n');
this.basePty.write(' unset PS1;\n');
this.basePty.write(' unset PS0;\n')
this.basePty.write(' echo setup complete\\"\n')

const listener = this.basePty.onData((data: string) => {
outputBuffer += data;
Expand Down
17 changes: 16 additions & 1 deletion src/resource/resource-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,8 @@ export class ResourceController<T extends StringIndexedObject> {

async import(
core: ResourceConfig,
parameters: Partial<T>
parameters: Partial<T>,
autoSearchAll = false,
): Promise<Array<ResourceJson> | null> {
if (this.settings.importAndDestroy?.preventImport) {
throw new Error(`Type: ${this.typeId} cannot be imported`);
Expand All @@ -270,6 +271,20 @@ export class ResourceController<T extends StringIndexedObject> {
originalDesiredConfig: structuredClone(parameters),
};

// Auto search means that no required parameters will be provided. We will try to generate it ourselves or return an
// empty array if they can't be.
if (autoSearchAll && this.settings.allowMultiple) {
if (this.settings.allowMultiple === true || !this.settings.allowMultiple.findAllParameters?.()) {
return [];
}

const parametersToImport = await this.settings.allowMultiple.findAllParameters?.();
const results = await Promise.all(parametersToImport.map((p) =>
this.import(core, p).catch(() => null))
);
return results.filter(Boolean).flat() as ResourceJson[];
}

this.addDefaultValues(parameters);
await this.applyTransformParameters(parameters);

Expand Down
13 changes: 10 additions & 3 deletions src/resource/resource-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export interface ResourceSettings<T extends StringIndexedObject> {
* If paramA is required, then if resource1.paramA === resource2.paramA then are the same resource.
* If resource1.paramA !== resource1.paramA, then they are different.
*/
identifyingParameters?: string[]
identifyingParameters?: string[];

/**
* If multiple copies are allowed then a matcher must be defined to match the desired
Expand All @@ -54,7 +54,14 @@ export interface ResourceSettings<T extends StringIndexedObject> {
*
* @return The matched resource.
*/
matcher?: (desired: Partial<T>, current: Partial<T>) => boolean
matcher?: (desired: Partial<T>, current: Partial<T>) => boolean;

/**
* This method if supported by the resource returns an array of parameters that represent all of the possible
* instances of a resource on the system. An example of this is for the git-repository resource, this method returns
* a list of directories which are git repositories.
*/
findAllParameters?: () => Promise<Array<Partial<T>>>
} | boolean

/**
Expand Down Expand Up @@ -391,7 +398,7 @@ export function resolveFnFromEqualsFnOrString(

const ParameterTransformationDefaults: Partial<Record<ParameterSettingType, InputTransformation>> = {
'directory': {
to: (a: unknown) => path.resolve(resolvePathWithVariables((untildify(String(a))))),
to: (a: unknown) => resolvePathWithVariables((untildify(String(a)))),
from: (a: unknown, original) => {
if (ParameterEqualsDefaults.directory!(a, original)) {
return original;
Expand Down
12 changes: 12 additions & 0 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@ import { ResourceConfig, StringIndexedObject } from 'codify-schemas';
import os from 'node:os';
import path from 'node:path';

export const VerbosityLevel = new class {
level = 0;

get() {
return this.level;
}

set(level: number) {
this.level = level;
}
}

export function isDebug(): boolean {
return process.env.DEBUG != null && process.env.DEBUG.includes('codify'); // TODO: replace with debug library
}
Expand Down