@kapeta/local-cluster-service 0.19.1 → 0.19.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/src/RepositoryWatcher.d.ts +3 -1
- package/dist/cjs/src/RepositoryWatcher.js +11 -3
- package/dist/cjs/src/assetManager.js +6 -1
- package/dist/cjs/src/codeGeneratorManager.d.ts +2 -0
- package/dist/cjs/src/codeGeneratorManager.js +46 -11
- package/dist/cjs/src/repositoryManager.d.ts +3 -1
- package/dist/cjs/src/repositoryManager.js +6 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/src/RepositoryWatcher.d.ts +3 -1
- package/dist/esm/src/RepositoryWatcher.js +11 -3
- package/dist/esm/src/assetManager.js +6 -1
- package/dist/esm/src/codeGeneratorManager.d.ts +2 -0
- package/dist/esm/src/codeGeneratorManager.js +46 -11
- package/dist/esm/src/repositoryManager.d.ts +3 -1
- package/dist/esm/src/repositoryManager.js +6 -1
- package/index.ts +2 -0
- package/package.json +1 -1
- package/src/RepositoryWatcher.ts +11 -3
- package/src/assetManager.ts +6 -1
- package/src/codeGeneratorManager.ts +55 -11
- package/src/repositoryManager.ts +7 -1
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## [0.19.3](https://github.com/kapetacom/local-cluster-service/compare/v0.19.2...v0.19.3) (2023-09-05)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* if codegen is already started for block - run after ([#69](https://github.com/kapetacom/local-cluster-service/issues/69)) ([a1b13ee](https://github.com/kapetacom/local-cluster-service/commit/a1b13eeab8413be8c165419ee36c26e3509338b4))
|
7
|
+
|
8
|
+
## [0.19.2](https://github.com/kapetacom/local-cluster-service/compare/v0.19.1...v0.19.2) (2023-09-05)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* Control boot order and reload code gen targets when repo changes ([#68](https://github.com/kapetacom/local-cluster-service/issues/68)) ([5557259](https://github.com/kapetacom/local-cluster-service/commit/5557259dda10f509a2b8cc45c0b4a4631e1d975a))
|
14
|
+
|
1
15
|
## [0.19.1](https://github.com/kapetacom/local-cluster-service/compare/v0.19.0...v0.19.1) (2023-09-03)
|
2
16
|
|
3
17
|
|
package/dist/cjs/index.js
CHANGED
@@ -28,6 +28,7 @@ const repositoryManager_1 = require("./src/repositoryManager");
|
|
28
28
|
const commandLineUtils_1 = require("./src/utils/commandLineUtils");
|
29
29
|
const DefaultProviderInstaller_1 = require("./src/utils/DefaultProviderInstaller");
|
30
30
|
const authManager_1 = require("./src/authManager");
|
31
|
+
const codeGeneratorManager_1 = require("./src/codeGeneratorManager");
|
31
32
|
let currentServer = null;
|
32
33
|
function createServer() {
|
33
34
|
const app = (0, express_1.default)();
|
@@ -109,6 +110,7 @@ exports.default = {
|
|
109
110
|
console.error('Could not ping docker runtime: ' + e.toString() + '. Make sure docker is running and working.');
|
110
111
|
}
|
111
112
|
await DefaultProviderInstaller_1.defaultProviderInstaller.checkForDefault();
|
113
|
+
await codeGeneratorManager_1.codeGeneratorManager.initialize();
|
112
114
|
const clusterPort = storageService_1.storageService.get('cluster', 'port');
|
113
115
|
if (clusterPort) {
|
114
116
|
clusterService_1.clusterService.setClusterServicePort(clusterPort);
|
@@ -1,5 +1,7 @@
|
|
1
|
+
/// <reference types="node" />
|
1
2
|
import { SourceOfChange } from './types';
|
2
|
-
|
3
|
+
import { EventEmitter } from 'node:events';
|
4
|
+
export declare class RepositoryWatcher extends EventEmitter {
|
3
5
|
private watcher?;
|
4
6
|
private disabled;
|
5
7
|
private readonly baseDir;
|
@@ -13,8 +13,9 @@ const nodejs_utils_1 = require("@kapeta/nodejs-utils");
|
|
13
13
|
const lodash_1 = __importDefault(require("lodash"));
|
14
14
|
const socketManager_1 = require("./socketManager");
|
15
15
|
const cacheManager_1 = require("./cacheManager");
|
16
|
+
const node_events_1 = require("node:events");
|
16
17
|
const KAPETA_YML_RX = /^kapeta.ya?ml$/;
|
17
|
-
class RepositoryWatcher {
|
18
|
+
class RepositoryWatcher extends node_events_1.EventEmitter {
|
18
19
|
watcher;
|
19
20
|
disabled = false;
|
20
21
|
baseDir;
|
@@ -22,6 +23,7 @@ class RepositoryWatcher {
|
|
22
23
|
symbolicLinks = {};
|
23
24
|
sourceOfChange = new Map();
|
24
25
|
constructor() {
|
26
|
+
super();
|
25
27
|
this.baseDir = local_cluster_config_1.default.getRepositoryBasedir();
|
26
28
|
}
|
27
29
|
setDisabled(disabled) {
|
@@ -204,6 +206,7 @@ class RepositoryWatcher {
|
|
204
206
|
this.allDefinitions = newDefinitions;
|
205
207
|
//console.log('Asset changed', payload);
|
206
208
|
socketManager_1.socketManager.emitGlobal('asset-change', payload);
|
209
|
+
this.emit('change', payload);
|
207
210
|
cacheManager_1.cacheManager.flush();
|
208
211
|
}
|
209
212
|
async exists(path) {
|
@@ -234,8 +237,13 @@ class RepositoryWatcher {
|
|
234
237
|
try {
|
235
238
|
// Make sure we're not watching the symlink target
|
236
239
|
await this.removeSymlinkTarget(path);
|
237
|
-
|
238
|
-
|
240
|
+
let symbolicLink = false;
|
241
|
+
try {
|
242
|
+
const stat = await fs_extra_1.default.lstat(path);
|
243
|
+
symbolicLink = stat.isSymbolicLink();
|
244
|
+
}
|
245
|
+
catch (e) { }
|
246
|
+
if (symbolicLink) {
|
239
247
|
const realPath = `${await fs_extra_1.default.realpath(path)}/kapeta.yml`;
|
240
248
|
if (await this.exists(realPath)) {
|
241
249
|
//console.log('Watching symlink target %s => %s', path, realPath);
|
@@ -16,6 +16,7 @@ const definitionsManager_1 = require("./definitionsManager");
|
|
16
16
|
const utils_1 = require("./utils/utils");
|
17
17
|
const taskManager_1 = require("./taskManager");
|
18
18
|
const cacheManager_1 = require("./cacheManager");
|
19
|
+
const node_uuid_1 = __importDefault(require("node-uuid"));
|
19
20
|
const CACHE_TTL = 60 * 60 * 1000; // 1 hour
|
20
21
|
const toKey = (ref) => `assetManager:asset:${ref}`;
|
21
22
|
function enrichAsset(asset) {
|
@@ -180,10 +181,14 @@ class AssetManager {
|
|
180
181
|
ref = (0, utils_1.normalizeKapetaUri)(ref);
|
181
182
|
if (await codeGeneratorManager_1.codeGeneratorManager.canGenerateCode(block)) {
|
182
183
|
const assetTitle = block.metadata.title ? block.metadata.title : (0, nodejs_utils_1.parseKapetaUri)(block.metadata.name).name;
|
183
|
-
|
184
|
+
const taskId = `codegen:${node_uuid_1.default.v4()}`;
|
185
|
+
const group = `codegen:${ref}`;
|
186
|
+
// We group the codegen tasks since we want to run them all but only 1 at a time per block
|
187
|
+
taskManager_1.taskManager.add(taskId, async () => {
|
184
188
|
await codeGeneratorManager_1.codeGeneratorManager.generate(ymlPath, block);
|
185
189
|
}, {
|
186
190
|
name: `Generating code for ${assetTitle}`,
|
191
|
+
group, //Group prevents multiple tasks from running at the same time
|
187
192
|
});
|
188
193
|
return true;
|
189
194
|
}
|
@@ -1,6 +1,8 @@
|
|
1
1
|
import { BlockDefinition } from '@kapeta/schemas';
|
2
2
|
declare class CodeGeneratorManager {
|
3
|
+
private ensureLanguageTargetInRegistry;
|
3
4
|
reload(): Promise<void>;
|
5
|
+
initialize(): Promise<void>;
|
4
6
|
canGenerateCode(yamlContent: BlockDefinition): Promise<boolean>;
|
5
7
|
generate(yamlFile: string, yamlContent: BlockDefinition): Promise<void>;
|
6
8
|
}
|
@@ -7,27 +7,51 @@ exports.codeGeneratorManager = void 0;
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
8
8
|
const codegen_1 = require("@kapeta/codegen");
|
9
9
|
const definitionsManager_1 = require("./definitionsManager");
|
10
|
+
const assetManager_1 = require("./assetManager");
|
11
|
+
const utils_1 = require("./utils/utils");
|
12
|
+
const repositoryManager_1 = require("./repositoryManager");
|
10
13
|
const TARGET_KIND = 'core/language-target';
|
11
14
|
const BLOCK_TYPE_KIND = 'core/block-type';
|
12
15
|
class CodeGeneratorManager {
|
16
|
+
async ensureLanguageTargetInRegistry(path, version, definition) {
|
17
|
+
const key = `${definition.metadata.name}:${version}`;
|
18
|
+
try {
|
19
|
+
if (await codegen_1.registry.get(key)) {
|
20
|
+
return;
|
21
|
+
}
|
22
|
+
}
|
23
|
+
catch (e) { }
|
24
|
+
try {
|
25
|
+
const target = require(path);
|
26
|
+
if (target.default) {
|
27
|
+
codegen_1.registry.register(key, target.default);
|
28
|
+
}
|
29
|
+
else {
|
30
|
+
codegen_1.registry.register(key, target);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
catch (e) {
|
34
|
+
console.error('Failed to load target: %s', key, e);
|
35
|
+
}
|
36
|
+
}
|
13
37
|
async reload() {
|
14
38
|
codegen_1.registry.reset();
|
15
39
|
const languageTargets = await definitionsManager_1.definitionsManager.getDefinitions(TARGET_KIND);
|
16
40
|
for (const languageTarget of languageTargets) {
|
17
|
-
|
41
|
+
await this.ensureLanguageTargetInRegistry(languageTarget.path, languageTarget.version, languageTarget.definition);
|
42
|
+
}
|
43
|
+
}
|
44
|
+
async initialize() {
|
45
|
+
await this.reload();
|
46
|
+
repositoryManager_1.repositoryManager.on('change', async () => {
|
47
|
+
// Reload code generators when the repository changes
|
18
48
|
try {
|
19
|
-
|
20
|
-
if (target.default) {
|
21
|
-
codegen_1.registry.register(key, target.default);
|
22
|
-
}
|
23
|
-
else {
|
24
|
-
codegen_1.registry.register(key, target);
|
25
|
-
}
|
49
|
+
await this.reload();
|
26
50
|
}
|
27
51
|
catch (e) {
|
28
|
-
console.error('Failed to
|
52
|
+
console.error('Failed to reload code generators', e);
|
29
53
|
}
|
30
|
-
}
|
54
|
+
});
|
31
55
|
}
|
32
56
|
async canGenerateCode(yamlContent) {
|
33
57
|
if (!yamlContent.spec.target?.kind) {
|
@@ -39,6 +63,18 @@ class CodeGeneratorManager {
|
|
39
63
|
return !!(yamlContent && yamlContent.kind && blockTypeKinds.indexOf(yamlContent.kind.toLowerCase()) > -1);
|
40
64
|
}
|
41
65
|
async generate(yamlFile, yamlContent) {
|
66
|
+
if (!yamlContent.spec.target?.kind) {
|
67
|
+
//Not all block types have targets
|
68
|
+
return;
|
69
|
+
}
|
70
|
+
const targetRef = (0, utils_1.normalizeKapetaUri)(yamlContent.spec.target?.kind);
|
71
|
+
// Automatically downloads target if not available
|
72
|
+
const targetAsset = await assetManager_1.assetManager.getAsset(targetRef);
|
73
|
+
if (!targetAsset) {
|
74
|
+
console.error('Language target not found: %s', yamlContent.spec.target?.kind);
|
75
|
+
return;
|
76
|
+
}
|
77
|
+
await this.ensureLanguageTargetInRegistry(targetAsset?.path, targetAsset?.version, targetAsset?.data);
|
42
78
|
const baseDir = path_1.default.dirname(yamlFile);
|
43
79
|
console.log('Generating code for path: %s', baseDir);
|
44
80
|
const codeGenerator = new codegen_1.BlockCodeGenerator(yamlContent);
|
@@ -50,4 +86,3 @@ class CodeGeneratorManager {
|
|
50
86
|
}
|
51
87
|
}
|
52
88
|
exports.codeGeneratorManager = new CodeGeneratorManager();
|
53
|
-
exports.codeGeneratorManager.reload();
|
@@ -1,6 +1,8 @@
|
|
1
|
+
/// <reference types="node" />
|
1
2
|
import { Task } from './taskManager';
|
2
3
|
import { SourceOfChange } from './types';
|
3
|
-
|
4
|
+
import { EventEmitter } from 'node:events';
|
5
|
+
declare class RepositoryManager extends EventEmitter {
|
4
6
|
private _registryService;
|
5
7
|
private watcher;
|
6
8
|
constructor();
|
@@ -13,6 +13,7 @@ const utils_1 = require("./utils/utils");
|
|
13
13
|
const progressListener_1 = require("./progressListener");
|
14
14
|
const RepositoryWatcher_1 = require("./RepositoryWatcher");
|
15
15
|
const cacheManager_1 = require("./cacheManager");
|
16
|
+
const node_events_1 = require("node:events");
|
16
17
|
const EVENT_DEFAULT_PROVIDERS_START = 'default-providers-start';
|
17
18
|
const EVENT_DEFAULT_PROVIDERS_END = 'default-providers-end';
|
18
19
|
const DEFAULT_PROVIDERS = [
|
@@ -29,13 +30,17 @@ const DEFAULT_PROVIDERS = [
|
|
29
30
|
'kapeta/language-target-nodejs',
|
30
31
|
'kapeta/language-target-java-spring-boot',
|
31
32
|
];
|
32
|
-
class RepositoryManager {
|
33
|
+
class RepositoryManager extends node_events_1.EventEmitter {
|
33
34
|
_registryService;
|
34
35
|
watcher;
|
35
36
|
constructor() {
|
37
|
+
super();
|
36
38
|
this._registryService = new nodejs_registry_utils_1.RegistryService(nodejs_registry_utils_1.Config.data.registry.url);
|
37
39
|
this.watcher = new RepositoryWatcher_1.RepositoryWatcher();
|
38
40
|
this.listenForChanges();
|
41
|
+
this.watcher.on('change', (file, source) => {
|
42
|
+
this.emit('change', file, source);
|
43
|
+
});
|
39
44
|
}
|
40
45
|
listenForChanges() {
|
41
46
|
this.watcher.watch();
|
package/dist/esm/index.js
CHANGED
@@ -28,6 +28,7 @@ const repositoryManager_1 = require("./src/repositoryManager");
|
|
28
28
|
const commandLineUtils_1 = require("./src/utils/commandLineUtils");
|
29
29
|
const DefaultProviderInstaller_1 = require("./src/utils/DefaultProviderInstaller");
|
30
30
|
const authManager_1 = require("./src/authManager");
|
31
|
+
const codeGeneratorManager_1 = require("./src/codeGeneratorManager");
|
31
32
|
let currentServer = null;
|
32
33
|
function createServer() {
|
33
34
|
const app = (0, express_1.default)();
|
@@ -109,6 +110,7 @@ exports.default = {
|
|
109
110
|
console.error('Could not ping docker runtime: ' + e.toString() + '. Make sure docker is running and working.');
|
110
111
|
}
|
111
112
|
await DefaultProviderInstaller_1.defaultProviderInstaller.checkForDefault();
|
113
|
+
await codeGeneratorManager_1.codeGeneratorManager.initialize();
|
112
114
|
const clusterPort = storageService_1.storageService.get('cluster', 'port');
|
113
115
|
if (clusterPort) {
|
114
116
|
clusterService_1.clusterService.setClusterServicePort(clusterPort);
|
@@ -1,5 +1,7 @@
|
|
1
|
+
/// <reference types="node" />
|
1
2
|
import { SourceOfChange } from './types';
|
2
|
-
|
3
|
+
import { EventEmitter } from 'node:events';
|
4
|
+
export declare class RepositoryWatcher extends EventEmitter {
|
3
5
|
private watcher?;
|
4
6
|
private disabled;
|
5
7
|
private readonly baseDir;
|
@@ -13,8 +13,9 @@ const nodejs_utils_1 = require("@kapeta/nodejs-utils");
|
|
13
13
|
const lodash_1 = __importDefault(require("lodash"));
|
14
14
|
const socketManager_1 = require("./socketManager");
|
15
15
|
const cacheManager_1 = require("./cacheManager");
|
16
|
+
const node_events_1 = require("node:events");
|
16
17
|
const KAPETA_YML_RX = /^kapeta.ya?ml$/;
|
17
|
-
class RepositoryWatcher {
|
18
|
+
class RepositoryWatcher extends node_events_1.EventEmitter {
|
18
19
|
watcher;
|
19
20
|
disabled = false;
|
20
21
|
baseDir;
|
@@ -22,6 +23,7 @@ class RepositoryWatcher {
|
|
22
23
|
symbolicLinks = {};
|
23
24
|
sourceOfChange = new Map();
|
24
25
|
constructor() {
|
26
|
+
super();
|
25
27
|
this.baseDir = local_cluster_config_1.default.getRepositoryBasedir();
|
26
28
|
}
|
27
29
|
setDisabled(disabled) {
|
@@ -204,6 +206,7 @@ class RepositoryWatcher {
|
|
204
206
|
this.allDefinitions = newDefinitions;
|
205
207
|
//console.log('Asset changed', payload);
|
206
208
|
socketManager_1.socketManager.emitGlobal('asset-change', payload);
|
209
|
+
this.emit('change', payload);
|
207
210
|
cacheManager_1.cacheManager.flush();
|
208
211
|
}
|
209
212
|
async exists(path) {
|
@@ -234,8 +237,13 @@ class RepositoryWatcher {
|
|
234
237
|
try {
|
235
238
|
// Make sure we're not watching the symlink target
|
236
239
|
await this.removeSymlinkTarget(path);
|
237
|
-
|
238
|
-
|
240
|
+
let symbolicLink = false;
|
241
|
+
try {
|
242
|
+
const stat = await fs_extra_1.default.lstat(path);
|
243
|
+
symbolicLink = stat.isSymbolicLink();
|
244
|
+
}
|
245
|
+
catch (e) { }
|
246
|
+
if (symbolicLink) {
|
239
247
|
const realPath = `${await fs_extra_1.default.realpath(path)}/kapeta.yml`;
|
240
248
|
if (await this.exists(realPath)) {
|
241
249
|
//console.log('Watching symlink target %s => %s', path, realPath);
|
@@ -16,6 +16,7 @@ const definitionsManager_1 = require("./definitionsManager");
|
|
16
16
|
const utils_1 = require("./utils/utils");
|
17
17
|
const taskManager_1 = require("./taskManager");
|
18
18
|
const cacheManager_1 = require("./cacheManager");
|
19
|
+
const node_uuid_1 = __importDefault(require("node-uuid"));
|
19
20
|
const CACHE_TTL = 60 * 60 * 1000; // 1 hour
|
20
21
|
const toKey = (ref) => `assetManager:asset:${ref}`;
|
21
22
|
function enrichAsset(asset) {
|
@@ -180,10 +181,14 @@ class AssetManager {
|
|
180
181
|
ref = (0, utils_1.normalizeKapetaUri)(ref);
|
181
182
|
if (await codeGeneratorManager_1.codeGeneratorManager.canGenerateCode(block)) {
|
182
183
|
const assetTitle = block.metadata.title ? block.metadata.title : (0, nodejs_utils_1.parseKapetaUri)(block.metadata.name).name;
|
183
|
-
|
184
|
+
const taskId = `codegen:${node_uuid_1.default.v4()}`;
|
185
|
+
const group = `codegen:${ref}`;
|
186
|
+
// We group the codegen tasks since we want to run them all but only 1 at a time per block
|
187
|
+
taskManager_1.taskManager.add(taskId, async () => {
|
184
188
|
await codeGeneratorManager_1.codeGeneratorManager.generate(ymlPath, block);
|
185
189
|
}, {
|
186
190
|
name: `Generating code for ${assetTitle}`,
|
191
|
+
group, //Group prevents multiple tasks from running at the same time
|
187
192
|
});
|
188
193
|
return true;
|
189
194
|
}
|
@@ -1,6 +1,8 @@
|
|
1
1
|
import { BlockDefinition } from '@kapeta/schemas';
|
2
2
|
declare class CodeGeneratorManager {
|
3
|
+
private ensureLanguageTargetInRegistry;
|
3
4
|
reload(): Promise<void>;
|
5
|
+
initialize(): Promise<void>;
|
4
6
|
canGenerateCode(yamlContent: BlockDefinition): Promise<boolean>;
|
5
7
|
generate(yamlFile: string, yamlContent: BlockDefinition): Promise<void>;
|
6
8
|
}
|
@@ -7,27 +7,51 @@ exports.codeGeneratorManager = void 0;
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
8
8
|
const codegen_1 = require("@kapeta/codegen");
|
9
9
|
const definitionsManager_1 = require("./definitionsManager");
|
10
|
+
const assetManager_1 = require("./assetManager");
|
11
|
+
const utils_1 = require("./utils/utils");
|
12
|
+
const repositoryManager_1 = require("./repositoryManager");
|
10
13
|
const TARGET_KIND = 'core/language-target';
|
11
14
|
const BLOCK_TYPE_KIND = 'core/block-type';
|
12
15
|
class CodeGeneratorManager {
|
16
|
+
async ensureLanguageTargetInRegistry(path, version, definition) {
|
17
|
+
const key = `${definition.metadata.name}:${version}`;
|
18
|
+
try {
|
19
|
+
if (await codegen_1.registry.get(key)) {
|
20
|
+
return;
|
21
|
+
}
|
22
|
+
}
|
23
|
+
catch (e) { }
|
24
|
+
try {
|
25
|
+
const target = require(path);
|
26
|
+
if (target.default) {
|
27
|
+
codegen_1.registry.register(key, target.default);
|
28
|
+
}
|
29
|
+
else {
|
30
|
+
codegen_1.registry.register(key, target);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
catch (e) {
|
34
|
+
console.error('Failed to load target: %s', key, e);
|
35
|
+
}
|
36
|
+
}
|
13
37
|
async reload() {
|
14
38
|
codegen_1.registry.reset();
|
15
39
|
const languageTargets = await definitionsManager_1.definitionsManager.getDefinitions(TARGET_KIND);
|
16
40
|
for (const languageTarget of languageTargets) {
|
17
|
-
|
41
|
+
await this.ensureLanguageTargetInRegistry(languageTarget.path, languageTarget.version, languageTarget.definition);
|
42
|
+
}
|
43
|
+
}
|
44
|
+
async initialize() {
|
45
|
+
await this.reload();
|
46
|
+
repositoryManager_1.repositoryManager.on('change', async () => {
|
47
|
+
// Reload code generators when the repository changes
|
18
48
|
try {
|
19
|
-
|
20
|
-
if (target.default) {
|
21
|
-
codegen_1.registry.register(key, target.default);
|
22
|
-
}
|
23
|
-
else {
|
24
|
-
codegen_1.registry.register(key, target);
|
25
|
-
}
|
49
|
+
await this.reload();
|
26
50
|
}
|
27
51
|
catch (e) {
|
28
|
-
console.error('Failed to
|
52
|
+
console.error('Failed to reload code generators', e);
|
29
53
|
}
|
30
|
-
}
|
54
|
+
});
|
31
55
|
}
|
32
56
|
async canGenerateCode(yamlContent) {
|
33
57
|
if (!yamlContent.spec.target?.kind) {
|
@@ -39,6 +63,18 @@ class CodeGeneratorManager {
|
|
39
63
|
return !!(yamlContent && yamlContent.kind && blockTypeKinds.indexOf(yamlContent.kind.toLowerCase()) > -1);
|
40
64
|
}
|
41
65
|
async generate(yamlFile, yamlContent) {
|
66
|
+
if (!yamlContent.spec.target?.kind) {
|
67
|
+
//Not all block types have targets
|
68
|
+
return;
|
69
|
+
}
|
70
|
+
const targetRef = (0, utils_1.normalizeKapetaUri)(yamlContent.spec.target?.kind);
|
71
|
+
// Automatically downloads target if not available
|
72
|
+
const targetAsset = await assetManager_1.assetManager.getAsset(targetRef);
|
73
|
+
if (!targetAsset) {
|
74
|
+
console.error('Language target not found: %s', yamlContent.spec.target?.kind);
|
75
|
+
return;
|
76
|
+
}
|
77
|
+
await this.ensureLanguageTargetInRegistry(targetAsset?.path, targetAsset?.version, targetAsset?.data);
|
42
78
|
const baseDir = path_1.default.dirname(yamlFile);
|
43
79
|
console.log('Generating code for path: %s', baseDir);
|
44
80
|
const codeGenerator = new codegen_1.BlockCodeGenerator(yamlContent);
|
@@ -50,4 +86,3 @@ class CodeGeneratorManager {
|
|
50
86
|
}
|
51
87
|
}
|
52
88
|
exports.codeGeneratorManager = new CodeGeneratorManager();
|
53
|
-
exports.codeGeneratorManager.reload();
|
@@ -1,6 +1,8 @@
|
|
1
|
+
/// <reference types="node" />
|
1
2
|
import { Task } from './taskManager';
|
2
3
|
import { SourceOfChange } from './types';
|
3
|
-
|
4
|
+
import { EventEmitter } from 'node:events';
|
5
|
+
declare class RepositoryManager extends EventEmitter {
|
4
6
|
private _registryService;
|
5
7
|
private watcher;
|
6
8
|
constructor();
|
@@ -13,6 +13,7 @@ const utils_1 = require("./utils/utils");
|
|
13
13
|
const progressListener_1 = require("./progressListener");
|
14
14
|
const RepositoryWatcher_1 = require("./RepositoryWatcher");
|
15
15
|
const cacheManager_1 = require("./cacheManager");
|
16
|
+
const node_events_1 = require("node:events");
|
16
17
|
const EVENT_DEFAULT_PROVIDERS_START = 'default-providers-start';
|
17
18
|
const EVENT_DEFAULT_PROVIDERS_END = 'default-providers-end';
|
18
19
|
const DEFAULT_PROVIDERS = [
|
@@ -29,13 +30,17 @@ const DEFAULT_PROVIDERS = [
|
|
29
30
|
'kapeta/language-target-nodejs',
|
30
31
|
'kapeta/language-target-java-spring-boot',
|
31
32
|
];
|
32
|
-
class RepositoryManager {
|
33
|
+
class RepositoryManager extends node_events_1.EventEmitter {
|
33
34
|
_registryService;
|
34
35
|
watcher;
|
35
36
|
constructor() {
|
37
|
+
super();
|
36
38
|
this._registryService = new nodejs_registry_utils_1.RegistryService(nodejs_registry_utils_1.Config.data.registry.url);
|
37
39
|
this.watcher = new RepositoryWatcher_1.RepositoryWatcher();
|
38
40
|
this.listenForChanges();
|
41
|
+
this.watcher.on('change', (file, source) => {
|
42
|
+
this.emit('change', file, source);
|
43
|
+
});
|
39
44
|
}
|
40
45
|
listenForChanges() {
|
41
46
|
this.watcher.watch();
|
package/index.ts
CHANGED
@@ -24,6 +24,7 @@ import { repositoryManager } from './src/repositoryManager';
|
|
24
24
|
import { ensureCLI } from './src/utils/commandLineUtils';
|
25
25
|
import { defaultProviderInstaller } from './src/utils/DefaultProviderInstaller';
|
26
26
|
import { authManager } from './src/authManager';
|
27
|
+
import { codeGeneratorManager } from './src/codeGeneratorManager';
|
27
28
|
|
28
29
|
export type LocalClusterService = HTTP.Server & { host?: string; port?: number };
|
29
30
|
|
@@ -125,6 +126,7 @@ export default {
|
|
125
126
|
}
|
126
127
|
|
127
128
|
await defaultProviderInstaller.checkForDefault();
|
129
|
+
await codeGeneratorManager.initialize();
|
128
130
|
|
129
131
|
const clusterPort = storageService.get('cluster', 'port');
|
130
132
|
if (clusterPort) {
|
package/package.json
CHANGED
package/src/RepositoryWatcher.ts
CHANGED
@@ -8,6 +8,7 @@ import _ from 'lodash';
|
|
8
8
|
import { socketManager } from './socketManager';
|
9
9
|
import { SourceOfChange, WatchEventName } from './types';
|
10
10
|
import { cacheManager } from './cacheManager';
|
11
|
+
import { EventEmitter } from 'node:events';
|
11
12
|
|
12
13
|
interface AssetIdentity {
|
13
14
|
handle: string;
|
@@ -15,7 +16,7 @@ interface AssetIdentity {
|
|
15
16
|
version: string;
|
16
17
|
}
|
17
18
|
const KAPETA_YML_RX = /^kapeta.ya?ml$/;
|
18
|
-
export class RepositoryWatcher {
|
19
|
+
export class RepositoryWatcher extends EventEmitter {
|
19
20
|
private watcher?: FSWatcher;
|
20
21
|
private disabled: boolean = false;
|
21
22
|
private readonly baseDir: string;
|
@@ -23,6 +24,7 @@ export class RepositoryWatcher {
|
|
23
24
|
private symbolicLinks: { [link: string]: string } = {};
|
24
25
|
private sourceOfChange: Map<string, SourceOfChange> = new Map();
|
25
26
|
constructor() {
|
27
|
+
super();
|
26
28
|
this.baseDir = ClusterConfiguration.getRepositoryBasedir();
|
27
29
|
}
|
28
30
|
|
@@ -228,6 +230,7 @@ export class RepositoryWatcher {
|
|
228
230
|
|
229
231
|
//console.log('Asset changed', payload);
|
230
232
|
socketManager.emitGlobal('asset-change', payload);
|
233
|
+
this.emit('change', payload);
|
231
234
|
|
232
235
|
cacheManager.flush();
|
233
236
|
}
|
@@ -261,8 +264,13 @@ export class RepositoryWatcher {
|
|
261
264
|
try {
|
262
265
|
// Make sure we're not watching the symlink target
|
263
266
|
await this.removeSymlinkTarget(path);
|
264
|
-
|
265
|
-
|
267
|
+
let symbolicLink = false;
|
268
|
+
try {
|
269
|
+
const stat = await FS.lstat(path);
|
270
|
+
symbolicLink = stat.isSymbolicLink();
|
271
|
+
} catch (e) {}
|
272
|
+
|
273
|
+
if (symbolicLink) {
|
266
274
|
const realPath = `${await FS.realpath(path)}/kapeta.yml`;
|
267
275
|
if (await this.exists(realPath)) {
|
268
276
|
//console.log('Watching symlink target %s => %s', path, realPath);
|
package/src/assetManager.ts
CHANGED
@@ -13,6 +13,7 @@ import { normalizeKapetaUri } from './utils/utils';
|
|
13
13
|
import { taskManager } from './taskManager';
|
14
14
|
import { SourceOfChange } from './types';
|
15
15
|
import { cacheManager } from './cacheManager';
|
16
|
+
import uuid from 'node-uuid';
|
16
17
|
|
17
18
|
const CACHE_TTL = 60 * 60 * 1000; // 1 hour
|
18
19
|
|
@@ -242,13 +243,17 @@ class AssetManager {
|
|
242
243
|
ref = normalizeKapetaUri(ref);
|
243
244
|
if (await codeGeneratorManager.canGenerateCode(block)) {
|
244
245
|
const assetTitle = block.metadata.title ? block.metadata.title : parseKapetaUri(block.metadata.name).name;
|
246
|
+
const taskId = `codegen:${uuid.v4()}`;
|
247
|
+
const group = `codegen:${ref}`;
|
248
|
+
// We group the codegen tasks since we want to run them all but only 1 at a time per block
|
245
249
|
taskManager.add(
|
246
|
-
|
250
|
+
taskId,
|
247
251
|
async () => {
|
248
252
|
await codeGeneratorManager.generate(ymlPath, block);
|
249
253
|
},
|
250
254
|
{
|
251
255
|
name: `Generating code for ${assetTitle}`,
|
256
|
+
group, //Group prevents multiple tasks from running at the same time
|
252
257
|
}
|
253
258
|
);
|
254
259
|
return true;
|
@@ -1,29 +1,58 @@
|
|
1
1
|
import Path from 'path';
|
2
2
|
import { registry as Targets, BlockCodeGenerator, CodeWriter } from '@kapeta/codegen';
|
3
|
-
import ClusterConfiguration from '@kapeta/local-cluster-config';
|
4
3
|
import { BlockDefinition } from '@kapeta/schemas';
|
5
4
|
import { definitionsManager } from './definitionsManager';
|
5
|
+
import { Definition } from '@kapeta/local-cluster-config';
|
6
|
+
import { assetManager } from './assetManager';
|
7
|
+
import { normalizeKapetaUri } from './utils/utils';
|
8
|
+
import { repositoryManager } from './repositoryManager';
|
6
9
|
|
7
10
|
const TARGET_KIND = 'core/language-target';
|
8
11
|
const BLOCK_TYPE_KIND = 'core/block-type';
|
9
12
|
|
10
13
|
class CodeGeneratorManager {
|
14
|
+
private async ensureLanguageTargetInRegistry(path: string, version: string, definition: Definition) {
|
15
|
+
const key = `${definition.metadata.name}:${version}`;
|
16
|
+
|
17
|
+
try {
|
18
|
+
if (await Targets.get(key)) {
|
19
|
+
return;
|
20
|
+
}
|
21
|
+
} catch (e) {}
|
22
|
+
|
23
|
+
try {
|
24
|
+
const target = require(path);
|
25
|
+
if (target.default) {
|
26
|
+
Targets.register(key, target.default);
|
27
|
+
} else {
|
28
|
+
Targets.register(key, target);
|
29
|
+
}
|
30
|
+
} catch (e) {
|
31
|
+
console.error('Failed to load target: %s', key, e);
|
32
|
+
}
|
33
|
+
}
|
11
34
|
async reload() {
|
12
35
|
Targets.reset();
|
13
36
|
const languageTargets = await definitionsManager.getDefinitions(TARGET_KIND);
|
14
37
|
for (const languageTarget of languageTargets) {
|
15
|
-
|
38
|
+
await this.ensureLanguageTargetInRegistry(
|
39
|
+
languageTarget.path,
|
40
|
+
languageTarget.version,
|
41
|
+
languageTarget.definition
|
42
|
+
);
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
async initialize() {
|
47
|
+
await this.reload();
|
48
|
+
repositoryManager.on('change', async () => {
|
49
|
+
// Reload code generators when the repository changes
|
16
50
|
try {
|
17
|
-
|
18
|
-
if (target.default) {
|
19
|
-
Targets.register(key, target.default);
|
20
|
-
} else {
|
21
|
-
Targets.register(key, target);
|
22
|
-
}
|
51
|
+
await this.reload();
|
23
52
|
} catch (e) {
|
24
|
-
console.error('Failed to
|
53
|
+
console.error('Failed to reload code generators', e);
|
25
54
|
}
|
26
|
-
}
|
55
|
+
});
|
27
56
|
}
|
28
57
|
|
29
58
|
async canGenerateCode(yamlContent: BlockDefinition): Promise<boolean> {
|
@@ -40,6 +69,22 @@ class CodeGeneratorManager {
|
|
40
69
|
}
|
41
70
|
|
42
71
|
async generate(yamlFile: string, yamlContent: BlockDefinition) {
|
72
|
+
if (!yamlContent.spec.target?.kind) {
|
73
|
+
//Not all block types have targets
|
74
|
+
return;
|
75
|
+
}
|
76
|
+
|
77
|
+
const targetRef = normalizeKapetaUri(yamlContent.spec.target?.kind);
|
78
|
+
|
79
|
+
// Automatically downloads target if not available
|
80
|
+
const targetAsset = await assetManager.getAsset(targetRef);
|
81
|
+
|
82
|
+
if (!targetAsset) {
|
83
|
+
console.error('Language target not found: %s', yamlContent.spec.target?.kind);
|
84
|
+
return;
|
85
|
+
}
|
86
|
+
|
87
|
+
await this.ensureLanguageTargetInRegistry(targetAsset?.path, targetAsset?.version, targetAsset?.data);
|
43
88
|
const baseDir = Path.dirname(yamlFile);
|
44
89
|
console.log('Generating code for path: %s', baseDir);
|
45
90
|
const codeGenerator = new BlockCodeGenerator(yamlContent);
|
@@ -55,4 +100,3 @@ class CodeGeneratorManager {
|
|
55
100
|
}
|
56
101
|
|
57
102
|
export const codeGeneratorManager = new CodeGeneratorManager();
|
58
|
-
codeGeneratorManager.reload();
|
package/src/repositoryManager.ts
CHANGED
@@ -9,6 +9,7 @@ import { ProgressListener } from './progressListener';
|
|
9
9
|
import { RepositoryWatcher } from './RepositoryWatcher';
|
10
10
|
import { SourceOfChange } from './types';
|
11
11
|
import { cacheManager } from './cacheManager';
|
12
|
+
import { EventEmitter } from 'node:events';
|
12
13
|
|
13
14
|
const EVENT_DEFAULT_PROVIDERS_START = 'default-providers-start';
|
14
15
|
const EVENT_DEFAULT_PROVIDERS_END = 'default-providers-end';
|
@@ -28,14 +29,19 @@ const DEFAULT_PROVIDERS = [
|
|
28
29
|
'kapeta/language-target-java-spring-boot',
|
29
30
|
];
|
30
31
|
|
31
|
-
class RepositoryManager {
|
32
|
+
class RepositoryManager extends EventEmitter {
|
32
33
|
private _registryService: RegistryService;
|
33
34
|
private watcher: RepositoryWatcher;
|
34
35
|
|
35
36
|
constructor() {
|
37
|
+
super();
|
36
38
|
this._registryService = new RegistryService(Config.data.registry.url);
|
37
39
|
this.watcher = new RepositoryWatcher();
|
38
40
|
this.listenForChanges();
|
41
|
+
|
42
|
+
this.watcher.on('change', (file: string, source: SourceOfChange) => {
|
43
|
+
this.emit('change', file, source);
|
44
|
+
});
|
39
45
|
}
|
40
46
|
|
41
47
|
listenForChanges() {
|