Skip to content

Commit 7c00ed6

Browse files
committed
Re-named previous entities. Modified plugin resolver to pull from s3
1 parent 85d965c commit 7c00ed6

7 files changed

Lines changed: 73 additions & 31 deletions

File tree

codify-core/src/plugins/entities/plugin-data.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export class PluginData {
99
// Plugin names should be globally unique
1010
name!: string;
1111
directory!: string;
12-
resourceDefinitions!: Map<ResourceName, ResourceDefinition>;
12+
resourceDefinitions?: Map<ResourceName, ResourceDefinition>;
1313

1414
constructor(props: RemoveMethods<PluginData>) {
1515
Object.assign(this, props);

codify-core/src/plugins/entities/plugin.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,28 @@ import { PluginData } from './plugin-data.js';
44

55
export class Plugin {
66

7-
ipcBridge: PluginIpcBridge;
7+
ipcBridge?: PluginIpcBridge;
88

99
// Separate out data so that the validation logic is testable.
1010
data: PluginData;
1111

12-
constructor(data: PluginData, ipcBridge: PluginIpcBridge) {
13-
this.ipcBridge = ipcBridge;
12+
constructor(data: PluginData) {
1413
this.data = data;
1514
}
1615

17-
static async create(directory: string, name: string, ipcBridge?: PluginIpcBridge): Promise<Plugin> {
18-
ipcBridge = ipcBridge ?? await PluginIpcBridge.create(directory, name);
19-
const resourceDefinitions = await ipcBridge.sendMessageForResult({ cmd: 'getResourceDefinitions' });
16+
async initialize(ipcBridge?: PluginIpcBridge): Promise<unknown> {
17+
ipcBridge = ipcBridge ?? await PluginIpcBridge.create(this.data.directory);
18+
const resourceList = await ipcBridge.sendMessageForResult({ cmd: 'initialize' });
2019

21-
return new Plugin(PluginData.create(directory, name, resourceDefinitions), ipcBridge);
20+
this.data.resourceDefinitions = resourceList as any;
21+
return resourceList;
2222
}
2323

2424
async generateResourcePlan(applyable: Applyable): Promise<unknown> {
25-
return this.ipcBridge.sendMessageForResult({ cmd: 'generateResourcePlan', data: applyable.toJson() });
25+
return this.ipcBridge!.sendMessageForResult({ cmd: 'generateResourcePlan', data: applyable.toJson() });
2626
}
2727

2828
destroy() {
29-
this.ipcBridge.killPlugin();
29+
this.ipcBridge!.killPlugin();
3030
}
3131
}

codify-core/src/plugins/ipc-bridge.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import { ChildProcess, fork } from 'node:child_process';
2-
3-
import { config } from '../project-configs/index.js';
42
import { validateTypeRecordStringUnknown } from '../utils/validator.js';
53
import { PluginMessage } from './entities/message.js';
64

@@ -16,9 +14,9 @@ export class PluginIpcBridge {
1614
this.process = process;
1715
}
1816

19-
static async create(directory: string, name: string): Promise<PluginIpcBridge> {
20-
const process = await fork(
21-
directory + '/' + name + config.defaultPluginEntryPoint,
17+
static async create(jsFileDir: string): Promise<PluginIpcBridge> {
18+
const process = fork(
19+
jsFileDir,
2220
[],
2321
{ execArgv: ['-r', 'ts-node/register'], silent: true },
2422
);

codify-core/src/plugins/plugin-collection.ts renamed to codify-core/src/plugins/plugin-manager.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@ import { PluginResolver } from './resolver.js';
77
type PluginName = string;
88

99
const DEFAULT_PLUGINS = {
10-
'default:homebrew': 'latest',
10+
'default': 'latest',
1111
// 'default:node': 'latest',
1212
}
1313

14-
export class PluginCollection {
14+
export class PluginManager {
1515

1616
private plugins: Map<PluginName, Plugin>
1717

1818
constructor(plugins: Map<PluginName, Plugin>) {
1919
this.plugins = plugins;
2020
}
2121

22-
static async create(project: ParsedProject): Promise<PluginCollection> {
22+
static async initialize(project: ParsedProject): Promise<PluginManager> {
2323
const pluginDefinitions: Record<string, string> = {
2424
...DEFAULT_PLUGINS,
2525
...project.projectConfig.plugins,
@@ -29,7 +29,11 @@ export class PluginCollection {
2929
PluginResolver.resolve(name, version)
3030
));
3131

32-
return new PluginCollection(new Map(plugins.map((plugin) => [plugin.data.name, plugin])))
32+
const definitions = await Promise.all(
33+
plugins.map((p) => p.initialize())
34+
);
35+
36+
return new PluginManager(new Map(plugins.map((plugin) => [plugin.data.name, plugin])))
3337
}
3438

3539
getResourceDefinitions(): Map<string, ResourceDefinition> {
Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,50 @@
1+
import * as fsSync from 'node:fs';
12
import * as fs from 'node:fs/promises';
3+
import path from 'node:path';
4+
import { Readable } from 'node:stream';
5+
import { finished } from 'node:stream/promises';
26

37
import { Plugin } from './entities/plugin.js';
48

5-
const DEFAULT_PLUGIN_REGEX = /(?<=default:).*$/g
9+
const DEFAULT_PLUGIN_URL = 'https://codify-plugin-library.s3.amazonaws.com/codify-core/index.js';
10+
const DEFAULT_PLUGIN_REGEX = /(?<=default).*$/g
11+
const PLUGIN_CACHE_DIR = '/Library/Caches/codify/plugins'
612

713
export class PluginResolver {
814

9-
static async resolve(name: string, version: string): Promise<Plugin> {
15+
static async resolve(name: string, version?: string): Promise<Plugin> {
16+
await PluginResolver.checkAndCreateCacheDirIfNotExists()
1017

18+
// TODO: Add plugin versioning in the future
1119
if (DEFAULT_PLUGIN_REGEX.test(name)) {
12-
return this.resolveDefaultPlugin(name, version)
20+
return this.resolveDefaultPlugin()
1321
}
1422

1523
throw new Error(`Unable to resolve plugin of name: ${name} and version: ${version}`)
1624
}
1725

18-
// TODO: update this method to resolve default plugins from github in the future.
19-
private static async resolveDefaultPlugin(name: string, _version: string): Promise<Plugin> {
20-
const pluginName = name.match(DEFAULT_PLUGIN_REGEX)![0]
26+
private static async resolveDefaultPlugin(): Promise<Plugin> {
2127

22-
const defaultPluginDir = '/Users/kevinwang/Projects/codify/plugins';
23-
const pluginDirFiles = await fs.readdir(defaultPluginDir);
24-
if (!pluginDirFiles.includes(pluginName)) {
25-
throw new Error(`Unable to find default plugin: ${name}`)
28+
const { body } = await fetch(DEFAULT_PLUGIN_URL)
29+
if (!body) {
30+
throw new Error('Un-able to fetch default plugin. Body was null');
2631
}
2732

28-
return Plugin.create(defaultPluginDir, pluginName);
33+
const fileUrl = path.join(PLUGIN_CACHE_DIR, 'default.js');
34+
const ws = fsSync.createWriteStream(fileUrl)
35+
36+
// Different type definitions here for readable stream (NodeJS vs DOM). Small hack to fix that
37+
await finished(Readable.fromWeb(body as never).pipe(ws));
38+
39+
return new Plugin({
40+
directory: fileUrl,
41+
name: 'default',
42+
})
2943
}
3044

45+
private static async checkAndCreateCacheDirIfNotExists() {
46+
if (!(await fs.stat(PLUGIN_CACHE_DIR))) {
47+
await fs.mkdir(PLUGIN_CACHE_DIR);
48+
}
49+
}
3150
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { beforeEach, describe, expect, it } from 'vitest';
2+
3+
import { PluginResolver } from '../../src/plugins/resolver.js';
4+
import mock from 'mock-fs';
5+
import * as fs from 'fs';
6+
7+
describe('Plugin resolver integration test', () => {
8+
beforeEach(() => {
9+
mock({
10+
'/Library/Caches/codify/plugins': {}
11+
})
12+
13+
})
14+
15+
it('resolves the default plugin', async () => {
16+
const plugin = await PluginResolver.resolve('default')
17+
18+
expect(fs.existsSync('/Library/Caches/codify/plugins/default.js')).to.be.true;
19+
})
20+
})

codify-core/tsconfig.test.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
},
66
"include": [
77
"src/**/*.test.ts",
8-
"test/**/*.test.ts"
8+
"test/**/*.test.ts",
9+
"test/**/*.integration-test.ts"
910
]
1011
}

0 commit comments

Comments
 (0)