@iobroker/js-controller-cli 8.0.0-alpha.1-20260921-e5941ca8a → 8.0.0-alpha.3-20260924-a3df0c4fe
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/build/cjs/lib/setup/setupInstall.d.ts +30 -0
- package/build/cjs/lib/setup/setupInstall.js +97 -0
- package/build/cjs/lib/setup/setupInstall.js.map +2 -2
- package/build/esm/lib/setup/setupInstall.d.ts +30 -0
- package/build/esm/lib/setup/setupInstall.d.ts.map +1 -1
- package/build/esm/lib/setup/setupInstall.js +109 -0
- package/build/esm/lib/setup/setupInstall.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -4
|
@@ -204,6 +204,21 @@ export declare class Install {
|
|
|
204
204
|
* @param adapter adapter name
|
|
205
205
|
*/
|
|
206
206
|
deleteAdapter(adapter: string): Promise<EXIT_CODES>;
|
|
207
|
+
/**
|
|
208
|
+
* Remove the virtual environment a Python adapter leaves behind in the data directory
|
|
209
|
+
*
|
|
210
|
+
* Host-local state like `node_modules` - rebuildable, but easily a few hundred megabytes - so it goes when
|
|
211
|
+
* the adapter goes. Deliberately not part of the npm uninstall: that one starts by resolving the adapter's
|
|
212
|
+
* `io-package.json`, so for a half-removed installation, where the package directory is already gone, it
|
|
213
|
+
* throws before ever getting here - and that is precisely the case which leaves the environment behind with
|
|
214
|
+
* nothing pointing at it.
|
|
215
|
+
*
|
|
216
|
+
* Removed without looking at `common.platform` for the same reason: the directory only exists for Python
|
|
217
|
+
* adapters, and the `io-package.json` that would say so may no longer be there.
|
|
218
|
+
*
|
|
219
|
+
* @param adapter adapter name, e.g. "pyexample"
|
|
220
|
+
*/
|
|
221
|
+
private _removePythonEnvironment;
|
|
207
222
|
/**
|
|
208
223
|
* Deletes given instance of an adapter
|
|
209
224
|
*
|
|
@@ -211,6 +226,21 @@ export declare class Install {
|
|
|
211
226
|
* @param instance e.g. 1, if undefined deletes all instances
|
|
212
227
|
*/
|
|
213
228
|
deleteInstance(adapter: string, instance?: number): Promise<void | EXIT_CODES.CANNOT_DELETE_DEPENDENCY>;
|
|
229
|
+
/**
|
|
230
|
+
* Free all exclusive resources (serial ports, TCP/UDP ports, ...) the given instance(s) had registered.
|
|
231
|
+
*
|
|
232
|
+
* This is needed because an instance can be deleted via the CLI while a js-controller is not running: it
|
|
233
|
+
* cannot notice that the instance object disappeared, so its `system.host.<host>.usedResources.<type>`
|
|
234
|
+
* states would keep listing the resources of an instance that no longer exists.
|
|
235
|
+
*
|
|
236
|
+
* Hosts that are running are deliberately skipped. Such a host cleans its own registry up when it sees the
|
|
237
|
+
* instance object being deleted, and it holds the registry in memory: it rewrites the state from that copy
|
|
238
|
+
* on its next change, which would silently undo a write made here.
|
|
239
|
+
*
|
|
240
|
+
* @param adapter adapter name, e.g. "mqtt"
|
|
241
|
+
* @param instance instance number; if undefined, all instances of the adapter are freed
|
|
242
|
+
*/
|
|
243
|
+
private _freeUsedResources;
|
|
214
244
|
/**
|
|
215
245
|
* Remove all node modules that has been installed by this instance
|
|
216
246
|
*
|
|
@@ -1126,6 +1126,7 @@ class Install {
|
|
|
1126
1126
|
}
|
|
1127
1127
|
await this._removeCustomFromObjects([adapter]);
|
|
1128
1128
|
await _uninstallNpm();
|
|
1129
|
+
await this._removePythonEnvironment(adapter);
|
|
1129
1130
|
} else {
|
|
1130
1131
|
const dependentInstance = await this._hasDependentInstances(adapter);
|
|
1131
1132
|
if (dependentInstance) {
|
|
@@ -1143,16 +1144,43 @@ class Install {
|
|
|
1143
1144
|
await this._deleteAdapterFiles(adapter, metaFilesToDelete);
|
|
1144
1145
|
await this._deleteAdapterObjects(knownObjectIDs);
|
|
1145
1146
|
await this._deleteAdapterStates(knownStateIDs);
|
|
1147
|
+
await this._freeUsedResources(adapter);
|
|
1146
1148
|
if (this.params.custom) {
|
|
1147
1149
|
await this._removeCustomFromObjects([...instances, adapter]);
|
|
1148
1150
|
}
|
|
1149
1151
|
await _uninstallNpm();
|
|
1152
|
+
await this._removePythonEnvironment(adapter);
|
|
1150
1153
|
}
|
|
1151
1154
|
} catch (e) {
|
|
1152
1155
|
console.error(`There was an error uninstalling ${adapter} on ${hostname}: ${e.message}`);
|
|
1153
1156
|
}
|
|
1154
1157
|
return resultCode;
|
|
1155
1158
|
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Remove the virtual environment a Python adapter leaves behind in the data directory
|
|
1161
|
+
*
|
|
1162
|
+
* Host-local state like `node_modules` - rebuildable, but easily a few hundred megabytes - so it goes when
|
|
1163
|
+
* the adapter goes. Deliberately not part of the npm uninstall: that one starts by resolving the adapter's
|
|
1164
|
+
* `io-package.json`, so for a half-removed installation, where the package directory is already gone, it
|
|
1165
|
+
* throws before ever getting here - and that is precisely the case which leaves the environment behind with
|
|
1166
|
+
* nothing pointing at it.
|
|
1167
|
+
*
|
|
1168
|
+
* Removed without looking at `common.platform` for the same reason: the directory only exists for Python
|
|
1169
|
+
* adapters, and the `io-package.json` that would say so may no longer be there.
|
|
1170
|
+
*
|
|
1171
|
+
* @param adapter adapter name, e.g. "pyexample"
|
|
1172
|
+
*/
|
|
1173
|
+
async _removePythonEnvironment(adapter) {
|
|
1174
|
+
try {
|
|
1175
|
+
const pythonEnvDir = import_js_controller_common.tools.getPythonEnvDir(adapter);
|
|
1176
|
+
if (await import_fs_extra.default.pathExists(pythonEnvDir)) {
|
|
1177
|
+
await import_fs_extra.default.remove(pythonEnvDir);
|
|
1178
|
+
console.log(`host.${hostname} Python environment "${pythonEnvDir}" deleted`);
|
|
1179
|
+
}
|
|
1180
|
+
} catch (e) {
|
|
1181
|
+
console.error(`Cannot delete the Python environment of ${adapter}: ${e.message}`);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1156
1184
|
/**
|
|
1157
1185
|
* Deletes given instance of an adapter
|
|
1158
1186
|
*
|
|
@@ -1176,10 +1204,79 @@ class Install {
|
|
|
1176
1204
|
await this._enumerateAdapterDocs(knownObjectIDs, adapter, instance);
|
|
1177
1205
|
await this._deleteAdapterObjects(knownObjectIDs);
|
|
1178
1206
|
await this._deleteAdapterStates(knownStateIDs);
|
|
1207
|
+
await this._freeUsedResources(adapter, instance);
|
|
1179
1208
|
if (this.params.custom) {
|
|
1180
1209
|
await this._removeCustomFromObjects([`${adapter}.${instance}`]);
|
|
1181
1210
|
}
|
|
1182
1211
|
}
|
|
1212
|
+
/**
|
|
1213
|
+
* Free all exclusive resources (serial ports, TCP/UDP ports, ...) the given instance(s) had registered.
|
|
1214
|
+
*
|
|
1215
|
+
* This is needed because an instance can be deleted via the CLI while a js-controller is not running: it
|
|
1216
|
+
* cannot notice that the instance object disappeared, so its `system.host.<host>.usedResources.<type>`
|
|
1217
|
+
* states would keep listing the resources of an instance that no longer exists.
|
|
1218
|
+
*
|
|
1219
|
+
* Hosts that are running are deliberately skipped. Such a host cleans its own registry up when it sees the
|
|
1220
|
+
* instance object being deleted, and it holds the registry in memory: it rewrites the state from that copy
|
|
1221
|
+
* on its next change, which would silently undo a write made here.
|
|
1222
|
+
*
|
|
1223
|
+
* @param adapter adapter name, e.g. "mqtt"
|
|
1224
|
+
* @param instance instance number; if undefined, all instances of the adapter are freed
|
|
1225
|
+
*/
|
|
1226
|
+
async _freeUsedResources(adapter, instance) {
|
|
1227
|
+
const matches = /* @__PURE__ */ __name((namespace) => instance !== void 0 ? namespace === `${adapter}.${instance}` : namespace.startsWith(`${adapter}.`), "matches");
|
|
1228
|
+
let keys;
|
|
1229
|
+
try {
|
|
1230
|
+
keys = await this.states.getKeys("system.host.*.usedResources.*");
|
|
1231
|
+
} catch (e) {
|
|
1232
|
+
console.warn(`Cannot read the used resources registry: ${e.message}`);
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
if (!keys?.length) {
|
|
1236
|
+
return;
|
|
1237
|
+
}
|
|
1238
|
+
const hostPrefix = "system.host.";
|
|
1239
|
+
const registryMarker = ".usedResources.";
|
|
1240
|
+
const hostIsRunning = /* @__PURE__ */ new Map();
|
|
1241
|
+
for (const id of keys) {
|
|
1242
|
+
const markerIndex = id.lastIndexOf(registryMarker);
|
|
1243
|
+
if (!id.startsWith(hostPrefix) || markerIndex <= hostPrefix.length) {
|
|
1244
|
+
continue;
|
|
1245
|
+
}
|
|
1246
|
+
const host = id.substring(hostPrefix.length, markerIndex);
|
|
1247
|
+
let isRunning = hostIsRunning.get(host);
|
|
1248
|
+
if (isRunning === void 0) {
|
|
1249
|
+
try {
|
|
1250
|
+
const aliveState = await this.states.getState(`${hostPrefix}${host}.alive`);
|
|
1251
|
+
isRunning = aliveState?.val === true;
|
|
1252
|
+
} catch (e) {
|
|
1253
|
+
console.warn(`Cannot check whether host "${host}" is running: ${e.message}`);
|
|
1254
|
+
isRunning = true;
|
|
1255
|
+
}
|
|
1256
|
+
hostIsRunning.set(host, isRunning);
|
|
1257
|
+
}
|
|
1258
|
+
if (isRunning) {
|
|
1259
|
+
continue;
|
|
1260
|
+
}
|
|
1261
|
+
try {
|
|
1262
|
+
const state = await this.states.getState(id);
|
|
1263
|
+
if (!state || typeof state.val !== "string" || !state.val) {
|
|
1264
|
+
continue;
|
|
1265
|
+
}
|
|
1266
|
+
const parsed = JSON.parse(state.val);
|
|
1267
|
+
if (!Array.isArray(parsed)) {
|
|
1268
|
+
continue;
|
|
1269
|
+
}
|
|
1270
|
+
const original = parsed;
|
|
1271
|
+
const filtered = original.filter((entry) => typeof entry?.instance !== "string" || !matches(entry.instance));
|
|
1272
|
+
if (filtered.length !== original.length) {
|
|
1273
|
+
await this.states.setStateAsync(id, { val: JSON.stringify(filtered), ack: true });
|
|
1274
|
+
}
|
|
1275
|
+
} catch (e) {
|
|
1276
|
+
console.warn(`Cannot free the used resources in "${id}": ${e.message}`);
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1183
1280
|
/**
|
|
1184
1281
|
* Remove all node modules that has been installed by this instance
|
|
1185
1282
|
*
|