@kapeta/local-cluster-service 0.16.0 → 0.16.1

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/cjs/src/RepositoryWatcher.d.ts +4 -3
  3. package/dist/cjs/src/RepositoryWatcher.js +15 -19
  4. package/dist/cjs/src/assetManager.d.ts +4 -6
  5. package/dist/cjs/src/assetManager.js +29 -52
  6. package/dist/cjs/src/assets/routes.js +2 -2
  7. package/dist/cjs/src/cacheManager.d.ts +16 -0
  8. package/dist/cjs/src/cacheManager.js +38 -0
  9. package/dist/cjs/src/definitionsManager.d.ts +2 -4
  10. package/dist/cjs/src/definitionsManager.js +7 -21
  11. package/dist/cjs/src/repositoryManager.d.ts +7 -2
  12. package/dist/cjs/src/repositoryManager.js +10 -10
  13. package/dist/cjs/src/types.d.ts +2 -0
  14. package/dist/cjs/src/utils/utils.js +1 -1
  15. package/dist/esm/src/RepositoryWatcher.d.ts +4 -3
  16. package/dist/esm/src/RepositoryWatcher.js +15 -19
  17. package/dist/esm/src/assetManager.d.ts +4 -6
  18. package/dist/esm/src/assetManager.js +29 -52
  19. package/dist/esm/src/assets/routes.js +2 -2
  20. package/dist/esm/src/cacheManager.d.ts +16 -0
  21. package/dist/esm/src/cacheManager.js +31 -0
  22. package/dist/esm/src/definitionsManager.d.ts +2 -4
  23. package/dist/esm/src/definitionsManager.js +7 -21
  24. package/dist/esm/src/repositoryManager.d.ts +7 -2
  25. package/dist/esm/src/repositoryManager.js +10 -10
  26. package/dist/esm/src/types.d.ts +2 -0
  27. package/dist/esm/src/utils/utils.js +1 -1
  28. package/package.json +1 -1
  29. package/src/RepositoryWatcher.ts +18 -20
  30. package/src/assetManager.ts +40 -58
  31. package/src/assets/routes.ts +2 -2
  32. package/src/cacheManager.ts +45 -0
  33. package/src/definitionsManager.ts +9 -33
  34. package/src/repositoryManager.ts +11 -12
  35. package/src/types.ts +2 -2
  36. package/src/utils/utils.ts +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [0.16.1](https://github.com/kapetacom/local-cluster-service/compare/v0.16.0...v0.16.1) (2023-08-11)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * Instead of ignoring we set source-of-change ([ecd23c4](https://github.com/kapetacom/local-cluster-service/commit/ecd23c4c3316a189038a1f2f2f2c8794f6153261))
7
+
1
8
  # [0.16.0](https://github.com/kapetacom/local-cluster-service/compare/v0.15.3...v0.16.0) (2023-08-11)
2
9
 
3
10
 
@@ -1,15 +1,16 @@
1
+ import { SourceOfChange } from './types';
1
2
  export declare class RepositoryWatcher {
2
3
  private watcher?;
3
4
  private disabled;
4
5
  private readonly baseDir;
5
6
  private allDefinitions;
6
7
  private symbolicLinks;
7
- private ignoredFiles;
8
+ private sourceOfChange;
8
9
  constructor();
9
10
  setDisabled(disabled: boolean): void;
10
11
  watch(): void;
11
- ignoreChangesFor(file: string): Promise<void>;
12
- resumeChangedFor(file: string): Promise<void>;
12
+ setSourceOfChangeFor(file: string, source: SourceOfChange): Promise<void>;
13
+ clearSourceOfChangeFor(file: string): Promise<void>;
13
14
  unwatch(): Promise<void>;
14
15
  private getAssetIdentity;
15
16
  private handleFileChange;
@@ -12,12 +12,7 @@ const yaml_1 = __importDefault(require("yaml"));
12
12
  const nodejs_utils_1 = require("@kapeta/nodejs-utils");
13
13
  const lodash_1 = __importDefault(require("lodash"));
14
14
  const socketManager_1 = require("./socketManager");
15
- const definitionsManager_1 = require("./definitionsManager");
16
- const assetManager_1 = require("./assetManager");
17
- function clearAllCaches() {
18
- definitionsManager_1.definitionsManager.clearCache();
19
- assetManager_1.assetManager.clearCache();
20
- }
15
+ const cacheManager_1 = require("./cacheManager");
21
16
  const KAPETA_YML_RX = /^kapeta.ya?ml$/;
22
17
  class RepositoryWatcher {
23
18
  watcher;
@@ -25,7 +20,7 @@ class RepositoryWatcher {
25
20
  baseDir;
26
21
  allDefinitions = [];
27
22
  symbolicLinks = {};
28
- ignoredFiles = new Set();
23
+ sourceOfChange = new Map();
29
24
  constructor() {
30
25
  this.baseDir = local_cluster_config_1.default.getRepositoryBasedir();
31
26
  }
@@ -61,18 +56,18 @@ class RepositoryWatcher {
61
56
  return;
62
57
  }
63
58
  }
64
- async ignoreChangesFor(file) {
65
- this.ignoredFiles.add(file);
59
+ async setSourceOfChangeFor(file, source) {
60
+ this.sourceOfChange.set(file, source);
66
61
  const realPath = await fs_extra_1.default.realpath(file);
67
62
  if (realPath !== file) {
68
- this.ignoredFiles.add(realPath);
63
+ this.sourceOfChange.set(realPath, source);
69
64
  }
70
65
  }
71
- async resumeChangedFor(file) {
72
- this.ignoredFiles.delete(file);
66
+ async clearSourceOfChangeFor(file) {
67
+ this.sourceOfChange.delete(file);
73
68
  const realPath = await fs_extra_1.default.realpath(file);
74
69
  if (realPath !== file) {
75
- this.ignoredFiles.delete(realPath);
70
+ this.sourceOfChange.delete(realPath);
76
71
  }
77
72
  }
78
73
  async unwatch() {
@@ -127,9 +122,6 @@ class RepositoryWatcher {
127
122
  if (!path) {
128
123
  return;
129
124
  }
130
- if (this.ignoredFiles.has(path)) {
131
- return;
132
- }
133
125
  //console.log('File changed', eventName, path);
134
126
  const assetIdentity = await this.getAssetIdentity(path);
135
127
  if (!assetIdentity) {
@@ -153,9 +145,12 @@ class RepositoryWatcher {
153
145
  await this.updateSymlinkTarget(path);
154
146
  }
155
147
  }
156
- await this.checkForChange(assetIdentity);
148
+ const sourceOfChange = this.sourceOfChange.get(path) ?? 'filesystem';
149
+ await this.checkForChange(assetIdentity, sourceOfChange);
150
+ // We consume the sourceOfChange when the file is changed
151
+ this.sourceOfChange.delete(path);
157
152
  }
158
- async checkForChange(assetIdentity) {
153
+ async checkForChange(assetIdentity, sourceOfChange) {
159
154
  const ymlPath = node_path_1.default.join(this.baseDir, assetIdentity.handle, assetIdentity.name, assetIdentity.version, 'kapeta.yml');
160
155
  const newDefinitions = local_cluster_config_1.default.getDefinitions();
161
156
  const newDefinition = newDefinitions.find((d) => d.ymlPath === ymlPath);
@@ -194,11 +189,12 @@ class RepositoryWatcher {
194
189
  type,
195
190
  definition: newDefinition?.definition ?? currentDefinition?.definition,
196
191
  asset: assetIdentity,
192
+ sourceOfChange,
197
193
  };
198
194
  this.allDefinitions = newDefinitions;
199
195
  //console.log('Asset changed', payload);
200
196
  socketManager_1.socketManager.emitGlobal('asset-change', payload);
201
- clearAllCaches();
197
+ cacheManager_1.cacheManager.flush();
202
198
  }
203
199
  async exists(path) {
204
200
  try {
@@ -1,5 +1,6 @@
1
1
  import { Definition } from '@kapeta/local-cluster-config';
2
2
  import { BlockDefinition } from '@kapeta/schemas';
3
+ import { SourceOfChange } from './types';
3
4
  export interface EnrichedAsset {
4
5
  ref: string;
5
6
  editable: boolean;
@@ -11,9 +12,6 @@ export interface EnrichedAsset {
11
12
  ymlPath: string;
12
13
  }
13
14
  declare class AssetManager {
14
- private cache;
15
- constructor();
16
- clearCache(): void;
17
15
  /**
18
16
  *
19
17
  * @param {string[]} [assetKinds]
@@ -23,12 +21,12 @@ declare class AssetManager {
23
21
  getPlans(): EnrichedAsset[];
24
22
  getPlan(ref: string, noCache?: boolean): Promise<Definition>;
25
23
  getAsset(ref: string, noCache?: boolean, autoFetch?: boolean): Promise<EnrichedAsset | undefined>;
26
- createAsset(path: string, yaml: BlockDefinition): Promise<EnrichedAsset[]>;
27
- updateAsset(ref: string, yaml: BlockDefinition): Promise<void>;
28
- private maybeGenerateCode;
24
+ createAsset(path: string, yaml: BlockDefinition, sourceOfChange?: SourceOfChange): Promise<EnrichedAsset[]>;
25
+ updateAsset(ref: string, yaml: BlockDefinition, sourceOfChange?: SourceOfChange): Promise<void>;
29
26
  importFile(filePath: string): Promise<EnrichedAsset[]>;
30
27
  unregisterAsset(ref: string): Promise<void>;
31
28
  installAsset(ref: string): Promise<import("./taskManager").Task<void>[] | undefined>;
29
+ private maybeGenerateCode;
32
30
  }
33
31
  export declare const assetManager: AssetManager;
34
32
  export {};
@@ -7,7 +7,6 @@ exports.assetManager = void 0;
7
7
  const node_path_1 = __importDefault(require("node:path"));
8
8
  const fs_extra_1 = __importDefault(require("fs-extra"));
9
9
  const yaml_1 = __importDefault(require("yaml"));
10
- const node_cache_1 = __importDefault(require("node-cache"));
11
10
  const codeGeneratorManager_1 = require("./codeGeneratorManager");
12
11
  const progressListener_1 = require("./progressListener");
13
12
  const nodejs_utils_1 = require("@kapeta/nodejs-utils");
@@ -16,10 +15,8 @@ const nodejs_registry_utils_1 = require("@kapeta/nodejs-registry-utils");
16
15
  const definitionsManager_1 = require("./definitionsManager");
17
16
  const utils_1 = require("./utils/utils");
18
17
  const taskManager_1 = require("./taskManager");
19
- function clearAllCaches() {
20
- definitionsManager_1.definitionsManager.clearCache();
21
- exports.assetManager.clearCache();
22
- }
18
+ const cacheManager_1 = require("./cacheManager");
19
+ const CACHE_TTL = 60 * 60 * 1000; // 1 hour
23
20
  function enrichAsset(asset) {
24
21
  return {
25
22
  ref: `kapeta://${asset.definition.metadata.name}:${asset.version}`,
@@ -45,15 +42,6 @@ function parseRef(ref) {
45
42
  return [out[0].toLowerCase(), out[1].toLowerCase()];
46
43
  }
47
44
  class AssetManager {
48
- cache;
49
- constructor() {
50
- this.cache = new node_cache_1.default({
51
- stdTTL: 60 * 60, // 1 hour
52
- });
53
- }
54
- clearCache() {
55
- this.cache.flushAll();
56
- }
57
45
  /**
58
46
  *
59
47
  * @param {string[]} [assetKinds]
@@ -86,8 +74,8 @@ class AssetManager {
86
74
  async getAsset(ref, noCache = false, autoFetch = true) {
87
75
  ref = (0, utils_1.normalizeKapetaUri)(ref);
88
76
  const cacheKey = `getAsset:${ref}`;
89
- if (!noCache && this.cache.has(cacheKey)) {
90
- return this.cache.get(cacheKey);
77
+ if (!noCache && cacheManager_1.cacheManager.has(cacheKey)) {
78
+ return cacheManager_1.cacheManager.get(cacheKey);
91
79
  }
92
80
  const uri = (0, nodejs_utils_1.parseKapetaUri)(ref);
93
81
  if (autoFetch) {
@@ -101,11 +89,11 @@ class AssetManager {
101
89
  throw new Error('Asset not found: ' + ref);
102
90
  }
103
91
  if (asset) {
104
- this.cache.set(cacheKey, asset);
92
+ cacheManager_1.cacheManager.set(cacheKey, asset, CACHE_TTL);
105
93
  }
106
94
  return asset;
107
95
  }
108
- async createAsset(path, yaml) {
96
+ async createAsset(path, yaml, sourceOfChange = 'filesystem') {
109
97
  if (await fs_extra_1.default.pathExists(path)) {
110
98
  throw new Error('File already exists: ' + path);
111
99
  }
@@ -113,14 +101,15 @@ class AssetManager {
113
101
  if (!(await fs_extra_1.default.pathExists(dirName))) {
114
102
  await fs_extra_1.default.mkdirp(dirName);
115
103
  }
104
+ await repositoryManager_1.repositoryManager.setSourceOfChangeFor(path, sourceOfChange);
116
105
  await fs_extra_1.default.writeFile(path, yaml_1.default.stringify(yaml));
117
106
  const asset = await this.importFile(path);
118
- clearAllCaches();
107
+ cacheManager_1.cacheManager.flush();
119
108
  const ref = `kapeta://${yaml.metadata.name}:local`;
120
109
  this.maybeGenerateCode(ref, path, yaml);
121
110
  return asset;
122
111
  }
123
- async updateAsset(ref, yaml) {
112
+ async updateAsset(ref, yaml, sourceOfChange = 'filesystem') {
124
113
  const asset = await this.getAsset(ref, true, false);
125
114
  if (!asset) {
126
115
  throw new Error('Attempted to update unknown asset: ' + ref);
@@ -131,36 +120,11 @@ class AssetManager {
131
120
  if (!asset.ymlPath) {
132
121
  throw new Error('Attempted to update corrupted asset: ' + ref);
133
122
  }
134
- const path = asset.ymlPath;
135
- try {
136
- await repositoryManager_1.repositoryManager.ignoreChangesFor(path);
137
- await fs_extra_1.default.writeFile(asset.ymlPath, yaml_1.default.stringify(yaml));
138
- console.log('Wrote to ' + asset.ymlPath);
139
- clearAllCaches();
140
- this.maybeGenerateCode(asset.ref, asset.ymlPath, yaml);
141
- }
142
- finally {
143
- //We need to wait a bit for the disk to settle before we can resume watching
144
- setTimeout(async () => {
145
- try {
146
- await repositoryManager_1.repositoryManager.resumeChangedFor(path);
147
- }
148
- catch (e) { }
149
- }, 500);
150
- }
151
- }
152
- maybeGenerateCode(ref, ymlPath, block) {
153
- ref = (0, utils_1.normalizeKapetaUri)(ref);
154
- if (codeGeneratorManager_1.codeGeneratorManager.canGenerateCode(block)) {
155
- const assetTitle = block.metadata.title ? block.metadata.title : (0, nodejs_utils_1.parseKapetaUri)(block.metadata.name).name;
156
- taskManager_1.taskManager.add(`codegen:${ref}`, async () => {
157
- await codeGeneratorManager_1.codeGeneratorManager.generate(ymlPath, block);
158
- }, {
159
- name: `Generating code for ${assetTitle}`,
160
- });
161
- return true;
162
- }
163
- return false;
123
+ await repositoryManager_1.repositoryManager.setSourceOfChangeFor(asset.ymlPath, sourceOfChange);
124
+ await fs_extra_1.default.writeFile(asset.ymlPath, yaml_1.default.stringify(yaml));
125
+ console.log('Wrote to ' + asset.ymlPath);
126
+ cacheManager_1.cacheManager.flush();
127
+ this.maybeGenerateCode(asset.ref, asset.ymlPath, yaml);
164
128
  }
165
129
  async importFile(filePath) {
166
130
  if (filePath.startsWith('file://')) {
@@ -174,7 +138,7 @@ class AssetManager {
174
138
  await nodejs_registry_utils_1.Actions.link(new progressListener_1.ProgressListener(), node_path_1.default.dirname(filePath));
175
139
  const version = 'local';
176
140
  const refs = assetInfos.map((assetInfo) => `kapeta://${assetInfo.metadata.name}:${version}`);
177
- clearAllCaches();
141
+ cacheManager_1.cacheManager.flush();
178
142
  return this.getAssets().filter((a) => refs.some((ref) => compareRefs(ref, a.ref)));
179
143
  }
180
144
  async unregisterAsset(ref) {
@@ -182,7 +146,7 @@ class AssetManager {
182
146
  if (!asset) {
183
147
  throw new Error('Asset does not exists: ' + ref);
184
148
  }
185
- clearAllCaches();
149
+ cacheManager_1.cacheManager.flush();
186
150
  await nodejs_registry_utils_1.Actions.uninstall(new progressListener_1.ProgressListener(), [asset.ref]);
187
151
  }
188
152
  async installAsset(ref) {
@@ -194,5 +158,18 @@ class AssetManager {
194
158
  console.log('Installing %s', ref);
195
159
  return await repositoryManager_1.repositoryManager.ensureAsset(uri.handle, uri.name, uri.version, false);
196
160
  }
161
+ maybeGenerateCode(ref, ymlPath, block) {
162
+ ref = (0, utils_1.normalizeKapetaUri)(ref);
163
+ if (codeGeneratorManager_1.codeGeneratorManager.canGenerateCode(block)) {
164
+ const assetTitle = block.metadata.title ? block.metadata.title : (0, nodejs_utils_1.parseKapetaUri)(block.metadata.name).name;
165
+ taskManager_1.taskManager.add(`codegen:${ref}`, async () => {
166
+ await codeGeneratorManager_1.codeGeneratorManager.generate(ymlPath, block);
167
+ }, {
168
+ name: `Generating code for ${assetTitle}`,
169
+ });
170
+ return true;
171
+ }
172
+ return false;
173
+ }
197
174
  }
198
175
  exports.assetManager = new AssetManager();
@@ -63,7 +63,7 @@ router.post('/create', async (req, res) => {
63
63
  }
64
64
  const content = parseBody(req);
65
65
  try {
66
- const assets = await assetManager_1.assetManager.createAsset(req.query.path, content);
66
+ const assets = await assetManager_1.assetManager.createAsset(req.query.path, content, 'user');
67
67
  res.status(200).send(assets);
68
68
  }
69
69
  catch (err) {
@@ -81,7 +81,7 @@ router.put('/update', async (req, res) => {
81
81
  }
82
82
  const content = parseBody(req);
83
83
  try {
84
- await assetManager_1.assetManager.updateAsset(req.query.ref, content);
84
+ await assetManager_1.assetManager.updateAsset(req.query.ref, content, 'user');
85
85
  res.sendStatus(204);
86
86
  }
87
87
  catch (err) {
@@ -0,0 +1,16 @@
1
+ export interface CacheEntry<T = any> {
2
+ expires: number;
3
+ data: T;
4
+ }
5
+ declare class CacheManager {
6
+ private cache;
7
+ flush(): void;
8
+ doCached<T>(key: string, getter: () => T, ttl?: number): T;
9
+ get<T>(key: string): T | undefined;
10
+ set<T>(key: string, data: T, ttl?: number): void;
11
+ has(key: string): boolean;
12
+ remove(key: string): number;
13
+ }
14
+ export declare const cacheManager: CacheManager;
15
+ export declare const doCached: <T>(key: string, getter: () => T, ttl?: number) => T;
16
+ export {};
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.doCached = exports.cacheManager = void 0;
7
+ const node_cache_1 = __importDefault(require("node-cache"));
8
+ const DEFAULT_CACHE_TTL = 60 * 1000; // 1 min
9
+ class CacheManager {
10
+ cache = new node_cache_1.default();
11
+ flush() {
12
+ this.cache.flushAll();
13
+ }
14
+ doCached(key, getter, ttl = DEFAULT_CACHE_TTL) {
15
+ const data = this.cache.get(key);
16
+ if (data !== undefined) {
17
+ return data;
18
+ }
19
+ const result = getter();
20
+ this.cache.set(key, result, ttl);
21
+ return result;
22
+ }
23
+ get(key) {
24
+ return this.cache.get(key);
25
+ }
26
+ set(key, data, ttl = DEFAULT_CACHE_TTL) {
27
+ this.cache.set(key, data, ttl);
28
+ }
29
+ has(key) {
30
+ return this.cache.has(key);
31
+ }
32
+ remove(key) {
33
+ return this.cache.del(key);
34
+ }
35
+ }
36
+ exports.cacheManager = new CacheManager();
37
+ const doCached = (key, getter, ttl = DEFAULT_CACHE_TTL) => exports.cacheManager.doCached(key, getter, ttl);
38
+ exports.doCached = doCached;
@@ -1,9 +1,7 @@
1
1
  import { DefinitionInfo } from '@kapeta/local-cluster-config';
2
2
  declare class DefinitionsManager {
3
- private cache;
4
- private getKey;
5
- clearCache(): void;
6
- private doCached;
3
+ private getHash;
4
+ private getFullKey;
7
5
  getDefinitions(kindFilter?: string | string[]): DefinitionInfo[];
8
6
  exists(ref: string): boolean;
9
7
  getProviderDefinitions(): DefinitionInfo[];
@@ -6,10 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.definitionsManager = void 0;
7
7
  const local_cluster_config_1 = __importDefault(require("@kapeta/local-cluster-config"));
8
8
  const nodejs_utils_1 = require("@kapeta/nodejs-utils");
9
- const CACHE_TTL = 60 * 1000; // 1 min
9
+ const cacheManager_1 = require("./cacheManager");
10
10
  class DefinitionsManager {
11
- cache = {};
12
- getKey(kindFilter) {
11
+ getHash(kindFilter) {
13
12
  if (kindFilter) {
14
13
  if (Array.isArray(kindFilter)) {
15
14
  return kindFilter.join(',');
@@ -18,31 +17,18 @@ class DefinitionsManager {
18
17
  }
19
18
  return 'none';
20
19
  }
21
- clearCache() {
22
- this.cache = {};
23
- }
24
- doCached(key, getter) {
25
- if (this.cache[key]) {
26
- if (this.cache[key].expires > Date.now()) {
27
- return this.cache[key].definitions;
28
- }
29
- delete this.cache[key];
30
- }
31
- this.cache[key] = {
32
- expires: Date.now() + CACHE_TTL,
33
- definitions: getter(),
34
- };
35
- return this.cache[key].definitions;
20
+ getFullKey(kindFilter) {
21
+ return `DefinitionsManager:${this.getHash(kindFilter)}`;
36
22
  }
37
23
  getDefinitions(kindFilter) {
38
- const key = this.getKey(kindFilter);
39
- return this.doCached(key, () => local_cluster_config_1.default.getDefinitions(kindFilter));
24
+ const key = this.getFullKey(kindFilter);
25
+ return (0, cacheManager_1.doCached)(key, () => local_cluster_config_1.default.getDefinitions(kindFilter));
40
26
  }
41
27
  exists(ref) {
42
28
  return !!this.getDefinition(ref);
43
29
  }
44
30
  getProviderDefinitions() {
45
- return this.doCached('providers', () => local_cluster_config_1.default.getProviderDefinitions());
31
+ return (0, cacheManager_1.doCached)('providers', () => local_cluster_config_1.default.getProviderDefinitions());
46
32
  }
47
33
  getDefinition(ref) {
48
34
  const uri = (0, nodejs_utils_1.parseKapetaUri)(ref);
@@ -1,4 +1,5 @@
1
1
  import { Task } from './taskManager';
2
+ import { SourceOfChange } from './types';
2
3
  declare class RepositoryManager {
3
4
  private _registryService;
4
5
  private _cache;
@@ -6,8 +7,12 @@ declare class RepositoryManager {
6
7
  constructor();
7
8
  listenForChanges(): void;
8
9
  stopListening(): Promise<void>;
9
- ignoreChangesFor(file: string): Promise<void>;
10
- resumeChangedFor(file: string): Promise<void>;
10
+ /**
11
+ * Setting the source of change helps us know
12
+ * how to react to changes in the UI.
13
+ */
14
+ setSourceOfChangeFor(file: string, source: SourceOfChange): Promise<void>;
15
+ clearSourceOfChangeFor(file: string): Promise<void>;
11
16
  ensureDefaultProviders(): void;
12
17
  private _install;
13
18
  ensureAsset(handle: string, name: string, version: string, wait?: boolean): Promise<undefined | Task[]>;
@@ -12,11 +12,7 @@ const taskManager_1 = require("./taskManager");
12
12
  const utils_1 = require("./utils/utils");
13
13
  const progressListener_1 = require("./progressListener");
14
14
  const RepositoryWatcher_1 = require("./RepositoryWatcher");
15
- const assetManager_1 = require("./assetManager");
16
- function clearAllCaches() {
17
- definitionsManager_1.definitionsManager.clearCache();
18
- assetManager_1.assetManager.clearCache();
19
- }
15
+ const cacheManager_1 = require("./cacheManager");
20
16
  const EVENT_DEFAULT_PROVIDERS_START = 'default-providers-start';
21
17
  const EVENT_DEFAULT_PROVIDERS_END = 'default-providers-end';
22
18
  const DEFAULT_PROVIDERS = [
@@ -50,11 +46,15 @@ class RepositoryManager {
50
46
  async stopListening() {
51
47
  return this.watcher.unwatch();
52
48
  }
53
- ignoreChangesFor(file) {
54
- return this.watcher.ignoreChangesFor(file);
49
+ /**
50
+ * Setting the source of change helps us know
51
+ * how to react to changes in the UI.
52
+ */
53
+ setSourceOfChangeFor(file, source) {
54
+ return this.watcher.setSourceOfChangeFor(file, source);
55
55
  }
56
- resumeChangedFor(file) {
57
- return this.watcher.resumeChangedFor(file);
56
+ clearSourceOfChangeFor(file) {
57
+ return this.watcher.clearSourceOfChangeFor(file);
58
58
  }
59
59
  ensureDefaultProviders() {
60
60
  socketManager_1.socketManager.emitGlobal(EVENT_DEFAULT_PROVIDERS_START, { providers: DEFAULT_PROVIDERS });
@@ -85,7 +85,7 @@ class RepositoryManager {
85
85
  console.error(`Failed to install asset: ${ref}`, e);
86
86
  throw e;
87
87
  }
88
- clearAllCaches();
88
+ cacheManager_1.cacheManager.flush();
89
89
  //console.log(`Asset installed: ${ref}`);
90
90
  };
91
91
  };
@@ -8,6 +8,8 @@ export type StringMap = {
8
8
  export type AnyMap = {
9
9
  [key: string]: any;
10
10
  };
11
+ export type SourceOfChange = 'user' | 'filesystem';
12
+ export type WatchEventName = 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir';
11
13
  export type LogLevel = 'ERROR' | 'WARN' | 'INFO' | 'DEBUG' | 'TRACE' | 'FATAL';
12
14
  export type LogSource = 'stdout' | 'stderr';
13
15
  export type EnvironmentType = 'docker' | 'process';
@@ -29,7 +29,7 @@ function readYML(path) {
29
29
  return yaml_1.default.parse(rawYaml.toString());
30
30
  }
31
31
  catch (err) {
32
- throw new Error('Failed to parse plan YAML: ' + err);
32
+ throw new Error(`Failed to parse plan YAML: ${err}`);
33
33
  }
34
34
  }
35
35
  exports.readYML = readYML;
@@ -1,15 +1,16 @@
1
+ import { SourceOfChange } from './types';
1
2
  export declare class RepositoryWatcher {
2
3
  private watcher?;
3
4
  private disabled;
4
5
  private readonly baseDir;
5
6
  private allDefinitions;
6
7
  private symbolicLinks;
7
- private ignoredFiles;
8
+ private sourceOfChange;
8
9
  constructor();
9
10
  setDisabled(disabled: boolean): void;
10
11
  watch(): void;
11
- ignoreChangesFor(file: string): Promise<void>;
12
- resumeChangedFor(file: string): Promise<void>;
12
+ setSourceOfChangeFor(file: string, source: SourceOfChange): Promise<void>;
13
+ clearSourceOfChangeFor(file: string): Promise<void>;
13
14
  unwatch(): Promise<void>;
14
15
  private getAssetIdentity;
15
16
  private handleFileChange;
@@ -6,12 +6,7 @@ import YAML from 'yaml';
6
6
  import { parseKapetaUri } from '@kapeta/nodejs-utils';
7
7
  import _ from 'lodash';
8
8
  import { socketManager } from './socketManager';
9
- import { definitionsManager } from './definitionsManager';
10
- import { assetManager } from './assetManager';
11
- function clearAllCaches() {
12
- definitionsManager.clearCache();
13
- assetManager.clearCache();
14
- }
9
+ import { cacheManager } from './cacheManager';
15
10
  const KAPETA_YML_RX = /^kapeta.ya?ml$/;
16
11
  export class RepositoryWatcher {
17
12
  watcher;
@@ -19,7 +14,7 @@ export class RepositoryWatcher {
19
14
  baseDir;
20
15
  allDefinitions = [];
21
16
  symbolicLinks = {};
22
- ignoredFiles = new Set();
17
+ sourceOfChange = new Map();
23
18
  constructor() {
24
19
  this.baseDir = ClusterConfiguration.getRepositoryBasedir();
25
20
  }
@@ -55,18 +50,18 @@ export class RepositoryWatcher {
55
50
  return;
56
51
  }
57
52
  }
58
- async ignoreChangesFor(file) {
59
- this.ignoredFiles.add(file);
53
+ async setSourceOfChangeFor(file, source) {
54
+ this.sourceOfChange.set(file, source);
60
55
  const realPath = await FS.realpath(file);
61
56
  if (realPath !== file) {
62
- this.ignoredFiles.add(realPath);
57
+ this.sourceOfChange.set(realPath, source);
63
58
  }
64
59
  }
65
- async resumeChangedFor(file) {
66
- this.ignoredFiles.delete(file);
60
+ async clearSourceOfChangeFor(file) {
61
+ this.sourceOfChange.delete(file);
67
62
  const realPath = await FS.realpath(file);
68
63
  if (realPath !== file) {
69
- this.ignoredFiles.delete(realPath);
64
+ this.sourceOfChange.delete(realPath);
70
65
  }
71
66
  }
72
67
  async unwatch() {
@@ -121,9 +116,6 @@ export class RepositoryWatcher {
121
116
  if (!path) {
122
117
  return;
123
118
  }
124
- if (this.ignoredFiles.has(path)) {
125
- return;
126
- }
127
119
  //console.log('File changed', eventName, path);
128
120
  const assetIdentity = await this.getAssetIdentity(path);
129
121
  if (!assetIdentity) {
@@ -147,9 +139,12 @@ export class RepositoryWatcher {
147
139
  await this.updateSymlinkTarget(path);
148
140
  }
149
141
  }
150
- await this.checkForChange(assetIdentity);
142
+ const sourceOfChange = this.sourceOfChange.get(path) ?? 'filesystem';
143
+ await this.checkForChange(assetIdentity, sourceOfChange);
144
+ // We consume the sourceOfChange when the file is changed
145
+ this.sourceOfChange.delete(path);
151
146
  }
152
- async checkForChange(assetIdentity) {
147
+ async checkForChange(assetIdentity, sourceOfChange) {
153
148
  const ymlPath = Path.join(this.baseDir, assetIdentity.handle, assetIdentity.name, assetIdentity.version, 'kapeta.yml');
154
149
  const newDefinitions = ClusterConfiguration.getDefinitions();
155
150
  const newDefinition = newDefinitions.find((d) => d.ymlPath === ymlPath);
@@ -188,11 +183,12 @@ export class RepositoryWatcher {
188
183
  type,
189
184
  definition: newDefinition?.definition ?? currentDefinition?.definition,
190
185
  asset: assetIdentity,
186
+ sourceOfChange,
191
187
  };
192
188
  this.allDefinitions = newDefinitions;
193
189
  //console.log('Asset changed', payload);
194
190
  socketManager.emitGlobal('asset-change', payload);
195
- clearAllCaches();
191
+ cacheManager.flush();
196
192
  }
197
193
  async exists(path) {
198
194
  try {