@iobroker/js-controller-cli 7.2.5 → 8.0.0-alpha.11-20261103-58da667b3

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 (225) hide show
  1. package/build/cjs/index.js +3 -3
  2. package/build/cjs/lib/_Types.d.ts +8 -1
  3. package/build/cjs/lib/cli/cliCert.d.ts +7 -4
  4. package/build/cjs/lib/cli/cliCert.js +10 -6
  5. package/build/cjs/lib/cli/cliCert.js.map +2 -2
  6. package/build/cjs/lib/cli/cliCommand.d.ts +63 -15
  7. package/build/cjs/lib/cli/cliCommand.js +8 -1
  8. package/build/cjs/lib/cli/cliCommand.js.map +2 -2
  9. package/build/cjs/lib/cli/cliCompact.d.ts +5 -2
  10. package/build/cjs/lib/cli/cliCompact.js +9 -2
  11. package/build/cjs/lib/cli/cliCompact.js.map +2 -2
  12. package/build/cjs/lib/cli/cliDebug.d.ts +5 -2
  13. package/build/cjs/lib/cli/cliDebug.js +8 -1
  14. package/build/cjs/lib/cli/cliDebug.js.map +2 -2
  15. package/build/cjs/lib/cli/cliHost.d.ts +13 -10
  16. package/build/cjs/lib/cli/cliHost.js +13 -5
  17. package/build/cjs/lib/cli/cliHost.js.map +2 -2
  18. package/build/cjs/lib/cli/cliLogs.d.ts +9 -3
  19. package/build/cjs/lib/cli/cliLogs.js +12 -1
  20. package/build/cjs/lib/cli/cliLogs.js.map +2 -2
  21. package/build/cjs/lib/cli/cliMessage.d.ts +2 -1
  22. package/build/cjs/lib/cli/cliMessage.js +5 -0
  23. package/build/cjs/lib/cli/cliMessage.js.map +2 -2
  24. package/build/cjs/lib/cli/cliObjects.d.ts +21 -18
  25. package/build/cjs/lib/cli/cliObjects.js +51 -33
  26. package/build/cjs/lib/cli/cliObjects.js.map +2 -2
  27. package/build/cjs/lib/cli/cliPlugin.d.ts +3 -3
  28. package/build/cjs/lib/cli/cliPlugin.js +6 -0
  29. package/build/cjs/lib/cli/cliPlugin.js.map +2 -2
  30. package/build/cjs/lib/cli/cliProcess.d.ts +17 -7
  31. package/build/cjs/lib/cli/cliProcess.js +77 -24
  32. package/build/cjs/lib/cli/cliProcess.js.map +3 -3
  33. package/build/cjs/lib/cli/cliStates.d.ts +7 -4
  34. package/build/cjs/lib/cli/cliStates.js +14 -6
  35. package/build/cjs/lib/cli/cliStates.js.map +2 -2
  36. package/build/cjs/lib/cli/cliTools.js +11 -0
  37. package/build/cjs/lib/cli/cliTools.js.map +1 -1
  38. package/build/cjs/lib/cli/messages.js +47 -46
  39. package/build/cjs/lib/cli/messages.js.map +1 -1
  40. package/build/cjs/lib/progressBar.d.ts +59 -0
  41. package/build/cjs/lib/progressBar.js +115 -0
  42. package/build/cjs/lib/progressBar.js.map +7 -0
  43. package/build/cjs/lib/setup/customError.d.ts +4 -0
  44. package/build/cjs/lib/setup/customError.js +7 -0
  45. package/build/cjs/lib/setup/customError.js.map +2 -2
  46. package/build/cjs/lib/setup/dbConnection.js +69 -64
  47. package/build/cjs/lib/setup/dbConnection.js.map +3 -3
  48. package/build/cjs/lib/setup/formatters.d.ts +4 -4
  49. package/build/cjs/lib/setup/formatters.js +5 -0
  50. package/build/cjs/lib/setup/formatters.js.map +2 -2
  51. package/build/cjs/lib/setup/multihostClient.js +6 -2
  52. package/build/cjs/lib/setup/multihostClient.js.map +1 -1
  53. package/build/cjs/lib/setup/pluginInfos.d.ts +5 -0
  54. package/build/cjs/lib/setup/pluginInfos.js +2 -0
  55. package/build/cjs/lib/setup/pluginInfos.js.map +2 -2
  56. package/build/cjs/lib/setup/setupBackup.d.ts +53 -0
  57. package/build/cjs/lib/setup/setupBackup.js +125 -14
  58. package/build/cjs/lib/setup/setupBackup.js.map +3 -3
  59. package/build/cjs/lib/setup/setupInstall.d.ts +81 -15
  60. package/build/cjs/lib/setup/setupInstall.js +307 -26
  61. package/build/cjs/lib/setup/setupInstall.js.map +2 -2
  62. package/build/cjs/lib/setup/setupLicense.d.ts +13 -0
  63. package/build/cjs/lib/setup/setupLicense.js +33 -2
  64. package/build/cjs/lib/setup/setupLicense.js.map +2 -2
  65. package/build/cjs/lib/setup/setupList.d.ts +55 -1
  66. package/build/cjs/lib/setup/setupList.js +78 -24
  67. package/build/cjs/lib/setup/setupList.js.map +3 -3
  68. package/build/cjs/lib/setup/setupMultihost.d.ts +7 -0
  69. package/build/cjs/lib/setup/setupMultihost.js +78 -11
  70. package/build/cjs/lib/setup/setupMultihost.js.map +3 -3
  71. package/build/cjs/lib/setup/setupPacketManager.d.ts +10 -0
  72. package/build/cjs/lib/setup/setupPacketManager.js +16 -6
  73. package/build/cjs/lib/setup/setupPacketManager.js.map +2 -2
  74. package/build/cjs/lib/setup/setupRepo.d.ts +19 -0
  75. package/build/cjs/lib/setup/setupRepo.js +141 -13
  76. package/build/cjs/lib/setup/setupRepo.js.map +2 -2
  77. package/build/cjs/lib/setup/setupSetup.d.ts +34 -0
  78. package/build/cjs/lib/setup/setupSetup.js +209 -35
  79. package/build/cjs/lib/setup/setupSetup.js.map +3 -3
  80. package/build/cjs/lib/setup/setupUpgrade.d.ts +13 -2
  81. package/build/cjs/lib/setup/setupUpgrade.js +72 -12
  82. package/build/cjs/lib/setup/setupUpgrade.js.map +2 -2
  83. package/build/cjs/lib/setup/setupUpload.d.ts +77 -1
  84. package/build/cjs/lib/setup/setupUpload.js +152 -9
  85. package/build/cjs/lib/setup/setupUpload.js.map +2 -2
  86. package/build/cjs/lib/setup/setupUsers.d.ts +44 -14
  87. package/build/cjs/lib/setup/setupUsers.js +330 -17
  88. package/build/cjs/lib/setup/setupUsers.js.map +2 -2
  89. package/build/cjs/lib/setup/setupVendor.d.ts +14 -1
  90. package/build/cjs/lib/setup/setupVendor.js +40 -8
  91. package/build/cjs/lib/setup/setupVendor.js.map +2 -2
  92. package/build/cjs/lib/setup/setupVisDebug.d.ts +16 -2
  93. package/build/cjs/lib/setup/setupVisDebug.js +41 -17
  94. package/build/cjs/lib/setup/setupVisDebug.js.map +3 -3
  95. package/build/cjs/lib/setup/utils.d.ts +1 -1
  96. package/build/cjs/lib/setup/utils.js +13 -9
  97. package/build/cjs/lib/setup/utils.js.map +3 -3
  98. package/build/cjs/lib/setup.d.ts +1 -1
  99. package/build/cjs/lib/setup.js +858 -1758
  100. package/build/cjs/lib/setup.js.map +3 -3
  101. package/build/esm/lib/_Types.d.ts +8 -1
  102. package/build/esm/lib/_Types.d.ts.map +1 -1
  103. package/build/esm/lib/cli/cliCert.d.ts +7 -4
  104. package/build/esm/lib/cli/cliCert.d.ts.map +1 -1
  105. package/build/esm/lib/cli/cliCert.js +6 -6
  106. package/build/esm/lib/cli/cliCert.js.map +1 -1
  107. package/build/esm/lib/cli/cliCommand.d.ts +63 -15
  108. package/build/esm/lib/cli/cliCommand.d.ts.map +1 -1
  109. package/build/esm/lib/cli/cliCommand.js +4 -1
  110. package/build/esm/lib/cli/cliCommand.js.map +1 -1
  111. package/build/esm/lib/cli/cliCompact.d.ts +5 -2
  112. package/build/esm/lib/cli/cliCompact.d.ts.map +1 -1
  113. package/build/esm/lib/cli/cliCompact.js +5 -2
  114. package/build/esm/lib/cli/cliCompact.js.map +1 -1
  115. package/build/esm/lib/cli/cliDebug.d.ts +5 -2
  116. package/build/esm/lib/cli/cliDebug.d.ts.map +1 -1
  117. package/build/esm/lib/cli/cliDebug.js +4 -1
  118. package/build/esm/lib/cli/cliDebug.js.map +1 -1
  119. package/build/esm/lib/cli/cliHost.d.ts +13 -10
  120. package/build/esm/lib/cli/cliHost.d.ts.map +1 -1
  121. package/build/esm/lib/cli/cliHost.js +8 -5
  122. package/build/esm/lib/cli/cliHost.js.map +1 -1
  123. package/build/esm/lib/cli/cliLogs.d.ts +9 -3
  124. package/build/esm/lib/cli/cliLogs.d.ts.map +1 -1
  125. package/build/esm/lib/cli/cliLogs.js +8 -1
  126. package/build/esm/lib/cli/cliLogs.js.map +1 -1
  127. package/build/esm/lib/cli/cliMessage.d.ts +2 -1
  128. package/build/esm/lib/cli/cliMessage.d.ts.map +1 -1
  129. package/build/esm/lib/cli/cliMessage.js +1 -0
  130. package/build/esm/lib/cli/cliMessage.js.map +1 -1
  131. package/build/esm/lib/cli/cliObjects.d.ts +21 -18
  132. package/build/esm/lib/cli/cliObjects.d.ts.map +1 -1
  133. package/build/esm/lib/cli/cliObjects.js +44 -38
  134. package/build/esm/lib/cli/cliObjects.js.map +1 -1
  135. package/build/esm/lib/cli/cliPlugin.d.ts +3 -3
  136. package/build/esm/lib/cli/cliPlugin.d.ts.map +1 -1
  137. package/build/esm/lib/cli/cliPlugin.js +1 -1
  138. package/build/esm/lib/cli/cliPlugin.js.map +1 -1
  139. package/build/esm/lib/cli/cliProcess.d.ts +17 -7
  140. package/build/esm/lib/cli/cliProcess.d.ts.map +1 -1
  141. package/build/esm/lib/cli/cliProcess.js +73 -12
  142. package/build/esm/lib/cli/cliProcess.js.map +1 -1
  143. package/build/esm/lib/cli/cliStates.d.ts +7 -4
  144. package/build/esm/lib/cli/cliStates.d.ts.map +1 -1
  145. package/build/esm/lib/cli/cliStates.js +6 -2
  146. package/build/esm/lib/cli/cliStates.js.map +1 -1
  147. package/build/esm/lib/progressBar.d.ts +59 -0
  148. package/build/esm/lib/progressBar.d.ts.map +1 -0
  149. package/build/esm/lib/progressBar.js +104 -0
  150. package/build/esm/lib/progressBar.js.map +1 -0
  151. package/build/esm/lib/setup/customError.d.ts +4 -0
  152. package/build/esm/lib/setup/customError.d.ts.map +1 -1
  153. package/build/esm/lib/setup/customError.js +3 -0
  154. package/build/esm/lib/setup/customError.js.map +1 -1
  155. package/build/esm/lib/setup/dbConnection.d.ts.map +1 -1
  156. package/build/esm/lib/setup/dbConnection.js +10 -13
  157. package/build/esm/lib/setup/dbConnection.js.map +1 -1
  158. package/build/esm/lib/setup/formatters.d.ts +4 -4
  159. package/build/esm/lib/setup/formatters.js +4 -4
  160. package/build/esm/lib/setup/pluginInfos.d.ts +5 -0
  161. package/build/esm/lib/setup/pluginInfos.d.ts.map +1 -1
  162. package/build/esm/lib/setup/pluginInfos.js +5 -0
  163. package/build/esm/lib/setup/pluginInfos.js.map +1 -1
  164. package/build/esm/lib/setup/setupBackup.d.ts +53 -0
  165. package/build/esm/lib/setup/setupBackup.d.ts.map +1 -1
  166. package/build/esm/lib/setup/setupBackup.js +132 -13
  167. package/build/esm/lib/setup/setupBackup.js.map +1 -1
  168. package/build/esm/lib/setup/setupInstall.d.ts +81 -15
  169. package/build/esm/lib/setup/setupInstall.d.ts.map +1 -1
  170. package/build/esm/lib/setup/setupInstall.js +334 -21
  171. package/build/esm/lib/setup/setupInstall.js.map +1 -1
  172. package/build/esm/lib/setup/setupLicense.d.ts +13 -0
  173. package/build/esm/lib/setup/setupLicense.d.ts.map +1 -1
  174. package/build/esm/lib/setup/setupLicense.js +31 -1
  175. package/build/esm/lib/setup/setupLicense.js.map +1 -1
  176. package/build/esm/lib/setup/setupList.d.ts +55 -1
  177. package/build/esm/lib/setup/setupList.d.ts.map +1 -1
  178. package/build/esm/lib/setup/setupList.js +61 -8
  179. package/build/esm/lib/setup/setupList.js.map +1 -1
  180. package/build/esm/lib/setup/setupMultihost.d.ts +7 -0
  181. package/build/esm/lib/setup/setupMultihost.d.ts.map +1 -1
  182. package/build/esm/lib/setup/setupMultihost.js +85 -6
  183. package/build/esm/lib/setup/setupMultihost.js.map +1 -1
  184. package/build/esm/lib/setup/setupPacketManager.d.ts +10 -0
  185. package/build/esm/lib/setup/setupPacketManager.d.ts.map +1 -1
  186. package/build/esm/lib/setup/setupPacketManager.js +9 -0
  187. package/build/esm/lib/setup/setupPacketManager.js.map +1 -1
  188. package/build/esm/lib/setup/setupRepo.d.ts +19 -0
  189. package/build/esm/lib/setup/setupRepo.d.ts.map +1 -1
  190. package/build/esm/lib/setup/setupRepo.js +164 -14
  191. package/build/esm/lib/setup/setupRepo.js.map +1 -1
  192. package/build/esm/lib/setup/setupSetup.d.ts +34 -0
  193. package/build/esm/lib/setup/setupSetup.d.ts.map +1 -1
  194. package/build/esm/lib/setup/setupSetup.js +218 -21
  195. package/build/esm/lib/setup/setupSetup.js.map +1 -1
  196. package/build/esm/lib/setup/setupUpgrade.d.ts +13 -2
  197. package/build/esm/lib/setup/setupUpgrade.d.ts.map +1 -1
  198. package/build/esm/lib/setup/setupUpgrade.js +70 -6
  199. package/build/esm/lib/setup/setupUpgrade.js.map +1 -1
  200. package/build/esm/lib/setup/setupUpload.d.ts +77 -1
  201. package/build/esm/lib/setup/setupUpload.d.ts.map +1 -1
  202. package/build/esm/lib/setup/setupUpload.js +164 -7
  203. package/build/esm/lib/setup/setupUpload.js.map +1 -1
  204. package/build/esm/lib/setup/setupUsers.d.ts +44 -14
  205. package/build/esm/lib/setup/setupUsers.d.ts.map +1 -1
  206. package/build/esm/lib/setup/setupUsers.js +346 -14
  207. package/build/esm/lib/setup/setupUsers.js.map +1 -1
  208. package/build/esm/lib/setup/setupVendor.d.ts +14 -1
  209. package/build/esm/lib/setup/setupVendor.d.ts.map +1 -1
  210. package/build/esm/lib/setup/setupVendor.js +33 -2
  211. package/build/esm/lib/setup/setupVendor.js.map +1 -1
  212. package/build/esm/lib/setup/setupVisDebug.d.ts +16 -2
  213. package/build/esm/lib/setup/setupVisDebug.d.ts.map +1 -1
  214. package/build/esm/lib/setup/setupVisDebug.js +39 -14
  215. package/build/esm/lib/setup/setupVisDebug.js.map +1 -1
  216. package/build/esm/lib/setup/utils.d.ts +1 -1
  217. package/build/esm/lib/setup/utils.d.ts.map +1 -1
  218. package/build/esm/lib/setup/utils.js +2 -4
  219. package/build/esm/lib/setup/utils.js.map +1 -1
  220. package/build/esm/lib/setup.d.ts +1 -1
  221. package/build/esm/lib/setup.d.ts.map +1 -1
  222. package/build/esm/lib/setup.js +959 -1910
  223. package/build/esm/lib/setup.js.map +1 -1
  224. package/build/tsconfig.build.tsbuildinfo +1 -1
  225. package/package.json +14 -14
@@ -6,25 +6,30 @@
6
6
  * MIT License
7
7
  *
8
8
  */
9
- import { tools, EXIT_CODES } from '@iobroker/js-controller-common';
10
- import fs from 'fs-extra';
11
9
  import path from 'node:path';
12
- import semver from 'semver';
13
10
  import child_process from 'node:child_process';
14
- import axios from 'axios';
15
11
  import { URL } from 'node:url';
12
+ import { createRequire } from 'node:module';
13
+ import axios from 'axios';
14
+ import fs from 'fs-extra';
15
+ import semver from 'semver';
16
+ import { tools, EXIT_CODES } from '@iobroker/js-controller-common';
16
17
  import { Upload } from '../../lib/setup/setupUpload.js';
17
18
  import { PacketManager } from '../../lib/setup/setupPacketManager.js';
18
19
  import { getRepository } from '../../lib/setup/utils.js';
19
20
  import { IoBrokerError } from '../../lib/setup/customError.js';
21
+ import { dbConnect } from '../../lib/setup/dbConnection.js';
22
+ import * as CLITools from '../../lib/cli/cliTools.js';
20
23
  import { SYSTEM_ADAPTER_PREFIX } from '@iobroker/js-controller-common-db/constants';
21
- import { createRequire } from 'node:module';
22
24
  // eslint-disable-next-line unicorn/prefer-module
23
25
  const require = createRequire(import.meta.url || `file://${__filename}`);
24
26
  const hostname = tools.getHostName();
25
27
  const osPlatform = process.platform;
26
28
  /** Note: this is duplicated in preinstallCheck */
27
29
  const RECOMMENDED_NPM_VERSION = 8;
30
+ /**
31
+ * CLI command to install and download adapters and create their instances
32
+ */
28
33
  export class Install {
29
34
  isRootOnUnix;
30
35
  objects;
@@ -34,6 +39,9 @@ export class Install {
34
39
  tarballRegex;
35
40
  upload;
36
41
  packetManager;
42
+ /**
43
+ * @param options The states/objects clients, CLI parameters and the process-exit callback
44
+ */
37
45
  constructor(options) {
38
46
  this.isRootOnUnix = typeof process.getuid === 'function' && process.getuid() === 0;
39
47
  options = options || {};
@@ -88,7 +96,7 @@ export class Install {
88
96
  if (!options || typeof options !== 'object') {
89
97
  options = {};
90
98
  }
91
- stoppedList = stoppedList || [];
99
+ stoppedList ||= [];
92
100
  let sources;
93
101
  if (!repoUrlOrRepo || !tools.isObject(repoUrlOrRepo)) {
94
102
  sources = await getRepository({ repoName: repoUrlOrRepo, objects: this.objects });
@@ -465,7 +473,7 @@ export class Install {
465
473
  obj.from = `system.host.${hostname}.cli`;
466
474
  obj.ts = Date.now();
467
475
  try {
468
- await this.objects.extendObjectAsync(obj._id, obj);
476
+ await this.objects.extendObject(obj._id, obj);
469
477
  }
470
478
  catch (err) {
471
479
  console.error(`host.${hostname} error setObject ${obj._id} ${err.message}`);
@@ -479,8 +487,8 @@ export class Install {
479
487
  * Installs given adapter
480
488
  *
481
489
  * @param adapter The adapter name
482
- * @param repoUrl
483
- * @param _installCount
490
+ * @param repoUrl Optional repository URL to install the adapter from
491
+ * @param _installCount Internal recursion counter limiting the number of dependency installs
484
492
  */
485
493
  async installAdapter(adapter, repoUrl, _installCount) {
486
494
  _installCount = _installCount || 0;
@@ -547,6 +555,11 @@ export class Install {
547
555
  await this.upload.upgradeAdapterObjects(adapter);
548
556
  return adapter;
549
557
  }
558
+ /**
559
+ * Install the OS packages required by an adapter
560
+ *
561
+ * @param osDependencies The OS dependencies declared by the adapter, keyed by platform
562
+ */
550
563
  async installOSPackages(osDependencies) {
551
564
  if (osPlatform in osDependencies) {
552
565
  try {
@@ -560,6 +573,12 @@ export class Install {
560
573
  }
561
574
  }
562
575
  }
576
+ /**
577
+ * Run the custom install script of an adapter if it defines one
578
+ *
579
+ * @param adapter The adapter name
580
+ * @param config The adapter object containing the install configuration
581
+ */
563
582
  async callInstallOfAdapter(adapter, config) {
564
583
  if (config.common.install) {
565
584
  // Install node modules
@@ -815,10 +834,10 @@ export class Install {
815
834
  /**
816
835
  * Enumerate all instances of an adapter
817
836
  *
818
- * @param knownObjIDs
819
- * @param notDeleted
820
- * @param adapter
821
- * @param instance
837
+ * @param knownObjIDs Accumulator of object IDs found so far
838
+ * @param notDeleted Accumulator of object IDs that must not be deleted
839
+ * @param adapter The adapter name
840
+ * @param instance Optional instance number to restrict the search to
822
841
  */
823
842
  async _enumerateAdapterInstances(knownObjIDs, notDeleted, adapter, instance) {
824
843
  if (!notDeleted) {
@@ -868,9 +887,9 @@ export class Install {
868
887
  /**
869
888
  * Enumerate all meta objects of an adapter
870
889
  *
871
- * @param knownObjIDs
872
- * @param adapter
873
- * @param metaFilesToDelete
890
+ * @param knownObjIDs Accumulator of object IDs found so far
891
+ * @param adapter The adapter name
892
+ * @param metaFilesToDelete Accumulator of meta files that should be deleted
874
893
  */
875
894
  async _enumerateAdapterMeta(knownObjIDs, adapter, metaFilesToDelete) {
876
895
  try {
@@ -1077,9 +1096,9 @@ export class Install {
1077
1096
  /**
1078
1097
  * Enumerate all state IDs of an adapter (or instance)
1079
1098
  *
1080
- * @param knownStateIDs
1081
- * @param adapter
1082
- * @param instance
1099
+ * @param knownStateIDs Accumulator of state IDs found so far
1100
+ * @param adapter The adapter name
1101
+ * @param instance Optional instance number to restrict the search to
1083
1102
  */
1084
1103
  async _enumerateAdapterStates(knownStateIDs, adapter, instance) {
1085
1104
  for (const pattern of [
@@ -1108,8 +1127,8 @@ export class Install {
1108
1127
  /**
1109
1128
  * delete WWW pages, objects and meta files
1110
1129
  *
1111
- * @param adapter
1112
- * @param metaFilesToDelete
1130
+ * @param adapter The adapter name
1131
+ * @param metaFilesToDelete The meta files that should be deleted
1113
1132
  */
1114
1133
  async _deleteAdapterFiles(adapter, metaFilesToDelete) {
1115
1134
  // special files, which are not meta (vis widgets), combined with meta object ids
@@ -1277,6 +1296,7 @@ export class Install {
1277
1296
  // remove adapter from custom
1278
1297
  await this._removeCustomFromObjects([adapter]);
1279
1298
  await _uninstallNpm();
1299
+ await this._removePythonEnvironment(adapter);
1280
1300
  }
1281
1301
  else {
1282
1302
  // we are not allowed to delete the last instance if another instance depends on us
@@ -1296,11 +1316,15 @@ export class Install {
1296
1316
  await this._deleteAdapterFiles(adapter, metaFilesToDelete);
1297
1317
  await this._deleteAdapterObjects(knownObjectIDs);
1298
1318
  await this._deleteAdapterStates(knownStateIDs);
1319
+ // this path removes the instance objects itself instead of going through deleteInstance,
1320
+ // so the registry entries of every instance of the adapter have to be freed here as well
1321
+ await this._freeUsedResources(adapter);
1299
1322
  if (this.params.custom) {
1300
1323
  // remove adapter from custom
1301
1324
  await this._removeCustomFromObjects([...instances, adapter]);
1302
1325
  }
1303
1326
  await _uninstallNpm();
1327
+ await this._removePythonEnvironment(adapter);
1304
1328
  }
1305
1329
  }
1306
1330
  catch (e) {
@@ -1308,6 +1332,32 @@ export class Install {
1308
1332
  }
1309
1333
  return resultCode;
1310
1334
  }
1335
+ /**
1336
+ * Remove the virtual environment a Python adapter leaves behind in the data directory
1337
+ *
1338
+ * Host-local state like `node_modules` - rebuildable, but easily a few hundred megabytes - so it goes when
1339
+ * the adapter goes. Deliberately not part of the npm uninstall: that one starts by resolving the adapter's
1340
+ * `io-package.json`, so for a half-removed installation, where the package directory is already gone, it
1341
+ * throws before ever getting here - and that is precisely the case which leaves the environment behind with
1342
+ * nothing pointing at it.
1343
+ *
1344
+ * Removed without looking at `common.platform` for the same reason: the directory only exists for Python
1345
+ * adapters, and the `io-package.json` that would say so may no longer be there.
1346
+ *
1347
+ * @param adapter adapter name, e.g. "pyexample"
1348
+ */
1349
+ async _removePythonEnvironment(adapter) {
1350
+ try {
1351
+ const pythonEnvDir = tools.getPythonEnvDir(adapter);
1352
+ if (await fs.pathExists(pythonEnvDir)) {
1353
+ await fs.remove(pythonEnvDir);
1354
+ console.log(`host.${hostname} Python environment "${pythonEnvDir}" deleted`);
1355
+ }
1356
+ }
1357
+ catch (e) {
1358
+ console.error(`Cannot delete the Python environment of ${adapter}: ${e.message}`);
1359
+ }
1360
+ }
1311
1361
  /**
1312
1362
  * Deletes given instance of an adapter
1313
1363
  *
@@ -1332,11 +1382,89 @@ export class Install {
1332
1382
  await this._enumerateAdapterDocs(knownObjectIDs, adapter, instance);
1333
1383
  await this._deleteAdapterObjects(knownObjectIDs);
1334
1384
  await this._deleteAdapterStates(knownStateIDs);
1385
+ await this._freeUsedResources(adapter, instance);
1335
1386
  if (this.params.custom) {
1336
1387
  // delete instance from custom
1337
1388
  await this._removeCustomFromObjects([`${adapter}.${instance}`]);
1338
1389
  }
1339
1390
  }
1391
+ /**
1392
+ * Free all exclusive resources (serial ports, TCP/UDP ports, ...) the given instance(s) had registered.
1393
+ *
1394
+ * This is needed because an instance can be deleted via the CLI while a js-controller is not running: it
1395
+ * cannot notice that the instance object disappeared, so its `system.host.<host>.usedResources.<type>`
1396
+ * states would keep listing the resources of an instance that no longer exists.
1397
+ *
1398
+ * Hosts that are running are deliberately skipped. Such a host cleans its own registry up when it sees the
1399
+ * instance object being deleted, and it holds the registry in memory: it rewrites the state from that copy
1400
+ * on its next change, which would silently undo a write made here.
1401
+ *
1402
+ * @param adapter adapter name, e.g. "mqtt"
1403
+ * @param instance instance number; if undefined, all instances of the adapter are freed
1404
+ */
1405
+ async _freeUsedResources(adapter, instance) {
1406
+ const matches = (namespace) => instance !== undefined ? namespace === `${adapter}.${instance}` : namespace.startsWith(`${adapter}.`);
1407
+ let keys;
1408
+ try {
1409
+ keys = await this.states.getKeys('system.host.*.usedResources.*');
1410
+ }
1411
+ catch (e) {
1412
+ console.warn(`Cannot read the used resources registry: ${e.message}`);
1413
+ return;
1414
+ }
1415
+ if (!keys?.length) {
1416
+ return;
1417
+ }
1418
+ const hostPrefix = 'system.host.';
1419
+ const registryMarker = '.usedResources.';
1420
+ /** whether a host is currently running, queried once per host */
1421
+ const hostIsRunning = new Map();
1422
+ for (const id of keys) {
1423
+ const markerIndex = id.lastIndexOf(registryMarker);
1424
+ if (!id.startsWith(hostPrefix) || markerIndex <= hostPrefix.length) {
1425
+ continue;
1426
+ }
1427
+ const host = id.substring(hostPrefix.length, markerIndex);
1428
+ let isRunning = hostIsRunning.get(host);
1429
+ if (isRunning === undefined) {
1430
+ try {
1431
+ const aliveState = await this.states.getState(`${hostPrefix}${host}.alive`);
1432
+ isRunning = aliveState?.val === true;
1433
+ }
1434
+ catch (e) {
1435
+ // if it cannot be determined, assume the host is running: leaving an entry behind is
1436
+ // harmless (its controller drops it on the next start) while fighting a live controller
1437
+ // over the same state is not
1438
+ console.warn(`Cannot check whether host "${host}" is running: ${e.message}`);
1439
+ isRunning = true;
1440
+ }
1441
+ hostIsRunning.set(host, isRunning);
1442
+ }
1443
+ if (isRunning) {
1444
+ continue;
1445
+ }
1446
+ try {
1447
+ const state = await this.states.getState(id);
1448
+ if (!state || typeof state.val !== 'string' || !state.val) {
1449
+ continue;
1450
+ }
1451
+ const parsed = JSON.parse(state.val);
1452
+ if (!Array.isArray(parsed)) {
1453
+ continue;
1454
+ }
1455
+ const original = parsed;
1456
+ // keep anything that is malformed: it cannot be attributed to the deleted instance, and one
1457
+ // broken entry must not stop the cleanup of the sound ones in the same state
1458
+ const filtered = original.filter(entry => typeof entry?.instance !== 'string' || !matches(entry.instance));
1459
+ if (filtered.length !== original.length) {
1460
+ await this.states.setStateAsync(id, { val: JSON.stringify(filtered), ack: true });
1461
+ }
1462
+ }
1463
+ catch (e) {
1464
+ console.warn(`Cannot free the used resources in "${id}": ${e.message}`);
1465
+ }
1466
+ }
1467
+ }
1340
1468
  /**
1341
1469
  * Remove all node modules that has been installed by this instance
1342
1470
  *
@@ -1625,4 +1753,189 @@ export class Install {
1625
1753
  return instances;
1626
1754
  }
1627
1755
  }
1756
+ /**
1757
+ * @param options options provided by the processCommand dispatcher
1758
+ */
1759
+ export function processCommandUrl(options) {
1760
+ const { args, params, callback } = options;
1761
+ let url = args[0];
1762
+ const name = args[1];
1763
+ if (!url) {
1764
+ console.log('Please provide a URL to install from and optionally a name of the adapter to install');
1765
+ return void callback(EXIT_CODES.INVALID_ARGUMENTS);
1766
+ }
1767
+ if (url[0] === '"' && url[url.length - 1] === '"') {
1768
+ url = url.substring(1, url.length - 1);
1769
+ }
1770
+ url = url.trim();
1771
+ dbConnect(params, async ({ objects, states }) => {
1772
+ const install = new Install({
1773
+ objects,
1774
+ states,
1775
+ processExit: callback,
1776
+ params,
1777
+ });
1778
+ try {
1779
+ await install.installAdapterFromUrl(url, name);
1780
+ return void callback(EXIT_CODES.NO_ERROR);
1781
+ }
1782
+ catch (e) {
1783
+ console.error(`Could not install adapter from url: ${e.message}`);
1784
+ return void callback(EXIT_CODES.CANNOT_INSTALL_NPM_PACKET);
1785
+ }
1786
+ });
1787
+ }
1788
+ /**
1789
+ * @param options options provided by the processCommand dispatcher
1790
+ */
1791
+ export function processCommandInstall(options) {
1792
+ const { command, args, params, callback } = options;
1793
+ const { showHelp } = options.commandOptions;
1794
+ let name = args[0];
1795
+ let instance = args[1];
1796
+ let repoUrl = args[2];
1797
+ if (parseInt(instance, 10).toString() !== (instance || '').toString()) {
1798
+ repoUrl = instance;
1799
+ instance = undefined;
1800
+ }
1801
+ if (parseInt(repoUrl, 10).toString() === (repoUrl || '').toString()) {
1802
+ const temp = instance;
1803
+ instance = repoUrl;
1804
+ repoUrl = temp;
1805
+ }
1806
+ if (instance && parseInt(instance, 10).toString() === (instance || '').toString()) {
1807
+ params.instance = parseInt(instance, 10);
1808
+ }
1809
+ // If user accidentally wrote tools.appName.adapter => remove adapter
1810
+ name = CLITools.normalizeAdapterName(name);
1811
+ const parsedName = CLITools.splitAdapterOrInstanceIdentifierWithVersion(name);
1812
+ if (!parsedName) {
1813
+ console.log('Invalid adapter name for install');
1814
+ showHelp();
1815
+ return void callback(EXIT_CODES.INVALID_ADAPTER_ID);
1816
+ }
1817
+ // split the adapter into its parts if necessary
1818
+ if (parsedName.instance !== null) {
1819
+ params.instance = parsedName.instance;
1820
+ }
1821
+ name = parsedName.name;
1822
+ const installName = parsedName.nameWithVersion;
1823
+ const adapterDir = tools.getAdapterDir(name);
1824
+ dbConnect(params, async ({ objects, states }) => {
1825
+ const install = new Install({
1826
+ objects,
1827
+ states,
1828
+ processExit: callback,
1829
+ params,
1830
+ });
1831
+ if (params.host && params.host !== tools.getHostName()) {
1832
+ // if host argument provided we should check, that host actually exists in mh environment
1833
+ let obj;
1834
+ try {
1835
+ obj = await objects.getObjectAsync(`system.host.${params.host}`);
1836
+ }
1837
+ catch (err) {
1838
+ console.warn(`Could not check existence of host "${params.host}": ${err.message}`);
1839
+ }
1840
+ if (!obj) {
1841
+ console.error(`Cannot add instance to non-existing host "${params.host}"`);
1842
+ return void callback(EXIT_CODES.NON_EXISTING_HOST);
1843
+ }
1844
+ }
1845
+ if (!adapterDir || !fs.existsSync(adapterDir)) {
1846
+ try {
1847
+ const { stoppedList } = await install.downloadPacket(repoUrl, installName);
1848
+ await install.installAdapter(installName, repoUrl);
1849
+ await install.enableInstances(stoppedList, true); // even if unlikely make sure to re-enable disabled instances
1850
+ if (command !== 'install' && command !== 'i') {
1851
+ await install.createInstance(name, params);
1852
+ }
1853
+ return void callback();
1854
+ }
1855
+ catch (e) {
1856
+ console.error(`adapter "${name}" cannot be installed: ${e.message}`);
1857
+ return void callback(e instanceof IoBrokerError ? e.code : EXIT_CODES.UNKNOWN_ERROR);
1858
+ }
1859
+ }
1860
+ else if (command !== 'install' && command !== 'i') {
1861
+ try {
1862
+ await install.createInstance(name, params);
1863
+ return void callback();
1864
+ }
1865
+ catch (err) {
1866
+ console.error(`adapter "${name}" cannot be installed: ${err.message}`);
1867
+ return void callback(EXIT_CODES.UNKNOWN_ERROR);
1868
+ }
1869
+ }
1870
+ else {
1871
+ console.log(`adapter "${name}" already installed. Use "upgrade" to upgrade to a newer version.`);
1872
+ return void callback(EXIT_CODES.ADAPTER_ALREADY_INSTALLED);
1873
+ }
1874
+ });
1875
+ }
1876
+ /**
1877
+ * @param options options provided by the processCommand dispatcher
1878
+ */
1879
+ export function processCommandDelete(options) {
1880
+ const { args, params, callback } = options;
1881
+ const { showHelp } = options.commandOptions;
1882
+ let adapter = args[0];
1883
+ let instance = args[1];
1884
+ // The adapter argument is required
1885
+ if (!adapter) {
1886
+ showHelp();
1887
+ return void callback(EXIT_CODES.INVALID_ADAPTER_ID);
1888
+ }
1889
+ // If the user accidentally wrote <tools.appName>.adapter,
1890
+ // remove <tools.appName> from the adapter name
1891
+ adapter = CLITools.normalizeAdapterName(adapter);
1892
+ // Avoid deleting stuff we don't want to delete
1893
+ // e.g. `system.adapter.*`
1894
+ if (!instance) {
1895
+ // Ensure that adapter contains a valid adapter (without instance nr)
1896
+ // or instance (with instance nr) identifier
1897
+ if (!CLITools.validateAdapterOrInstanceIdentifier(adapter)) {
1898
+ showHelp();
1899
+ return void callback(EXIT_CODES.INVALID_ADAPTER_ID);
1900
+ }
1901
+ // split the adapter into adapter + instance if necessary
1902
+ if (adapter.indexOf('.') > -1) {
1903
+ [adapter, instance] = adapter.split('.', 2);
1904
+ }
1905
+ }
1906
+ else {
1907
+ // ensure that adapter contains a valid adapter identifier
1908
+ // and the instance is a number
1909
+ if (!CLITools.validateAdapterIdentifier(adapter) || !/^\d+$/.test(instance)) {
1910
+ showHelp();
1911
+ return void callback(EXIT_CODES.INVALID_ADAPTER_ID);
1912
+ }
1913
+ }
1914
+ if (instance) {
1915
+ dbConnect(params, async ({ objects, states }) => {
1916
+ const install = new Install({
1917
+ objects,
1918
+ states,
1919
+ processExit: callback,
1920
+ params,
1921
+ });
1922
+ console.log(`Delete instance "${adapter}.${instance}"`);
1923
+ await install.deleteInstance(adapter, parseInt(instance));
1924
+ callback();
1925
+ });
1926
+ }
1927
+ else {
1928
+ dbConnect(params, async ({ objects, states }) => {
1929
+ const install = new Install({
1930
+ objects,
1931
+ states,
1932
+ processExit: callback,
1933
+ params,
1934
+ });
1935
+ console.log(`Delete adapter "${adapter}"`);
1936
+ const resultCode = await install.deleteAdapter(adapter);
1937
+ callback(resultCode);
1938
+ });
1939
+ }
1940
+ }
1628
1941
  //# sourceMappingURL=setupInstall.js.map