@iobroker/js-controller-cli 6.0.9 → 6.0.10-alpha.0-20240803-d90cc8849
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 +4 -4
- package/build/cjs/lib/setup/setupInstall.js +4 -4
- package/build/cjs/lib/setup/setupInstall.js.map +2 -2
- package/build/cjs/lib/setup/setupUpgrade.d.ts +2 -2
- package/build/cjs/lib/setup/setupUpgrade.js.map +1 -1
- package/build/cjs/lib/setup/utils.d.ts +1 -1
- package/build/cjs/lib/setup/utils.js.map +1 -1
- package/build/esm/lib/setup/setupInstall.d.ts +4 -4
- package/build/esm/lib/setup/setupInstall.js +28 -28
- package/build/esm/lib/setup/setupInstall.js.map +1 -1
- package/build/esm/lib/setup/setupUpgrade.d.ts +2 -2
- package/build/esm/lib/setup/setupUpgrade.js +12 -12
- package/build/esm/lib/setup/setupUpgrade.js.map +1 -1
- package/build/esm/lib/setup/utils.d.ts +1 -1
- package/build/esm/lib/setup/utils.js +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/setup/setupUpgrade.ts"],
|
|
4
|
-
"sourcesContent": ["import Debug from 'debug';\nimport fs from 'fs-extra';\nimport { tools, EXIT_CODES } from '@iobroker/js-controller-common';\nimport semver from 'semver';\nimport { Upload } from '@/lib/setup/setupUpload.js';\nimport { Install } from '@/lib/setup/setupInstall.js';\nimport rl from 'readline-sync';\nimport tty from 'node:tty';\nimport path from 'node:path';\nimport { getRepository, isVersionIgnored } from '@/lib/setup/utils.js';\nimport type { Client as ObjectsInRedisClient } from '@iobroker/db-objects-redis';\nimport type { Client as StatesInRedisClient } from '@iobroker/db-states-redis';\nimport type { ProcessExitCallback } from '@/lib/_Types.js';\nimport { IoBrokerError } from '@/lib/setup/customError.js';\n\nconst debug = Debug('iobroker:cli');\n\ntype IoPackDependencies = string[] | Record<string, any>[] | Record<string, any>;\n\ninterface CLIUpgradeOptions {\n processExit: ProcessExitCallback;\n objects: ObjectsInRedisClient;\n states: StatesInRedisClient;\n params: Record<string, any>;\n}\n\nexport class Upgrade {\n private readonly hostname = tools.getHostName();\n private readonly upload: Upload;\n private readonly install: Install;\n private readonly objects: ObjectsInRedisClient;\n private readonly processExit: ProcessExitCallback;\n\n constructor(options: CLIUpgradeOptions) {\n options = options || {};\n\n if (!options.processExit) {\n throw new Error('Invalid arguments: processExit is missing');\n }\n\n this.processExit = options.processExit;\n this.objects = options.objects;\n\n this.upload = new Upload(options);\n this.install = new Install(options);\n }\n\n /**\n * Sorts the adapters by their dependencies and then upgrades multiple adapters from the given repository url\n *\n * @param repo the repository content\n * @param list list of adapters to upgrade\n * @param forceDowngrade flag to force downgrade\n * @param autoConfirm automatically confirm the tty questions (bypass)\n */\n async upgradeAdapterHelper(\n repo: Record<string, any>,\n list: string[],\n forceDowngrade: boolean,\n autoConfirm: boolean\n ): Promise<void> {\n const relevantAdapters = [];\n // check which adapters are upgradeable and sort them according to their dependencies\n for (const adapter of list) {\n if (repo[adapter].controller) {\n // skip controller\n continue;\n }\n const adapterDir = tools.getAdapterDir(adapter);\n if (adapterDir && fs.existsSync(path.join(adapterDir, 'io-package.json'))) {\n const ioInstalled = fs.readJsonSync(path.join(adapterDir, 'io-package.json'));\n if (!tools.upToDate(repo[adapter].version, ioInstalled.common.version)) {\n // not up to date, we need to put it into account for our dependency check\n relevantAdapters.push(adapter);\n }\n }\n }\n\n if (relevantAdapters.length) {\n const sortedAdapters = [];\n\n while (relevantAdapters.length) {\n let oneAdapterAdded = false;\n // create ordered list for upgrades\n for (let i = relevantAdapters.length - 1; i >= 0; i--) {\n const relAdapter = relevantAdapters[i];\n // if new version has no dependencies we can upgrade\n if (!repo[relAdapter].dependencies && !repo[relAdapter].globalDependencies) {\n // no deps, simply add it\n sortedAdapters.push(relAdapter);\n relevantAdapters.splice(relevantAdapters.indexOf(relAdapter), 1);\n oneAdapterAdded = true;\n } else {\n const allDeps: Record<string, string> = {\n ...tools.parseDependencies(repo[relAdapter].dependencies),\n ...tools.parseDependencies(repo[relAdapter].globalDependencies)\n };\n\n // we have to check if the deps are there\n let conflict = false;\n for (const [depName, version] of Object.entries(allDeps)) {\n debug(`adapter \"${relAdapter}\" has dependency \"${depName}\": \"${version}\"`);\n if (version !== '*') {\n // dependency is important, because it affects version range\n if (relevantAdapters.includes(depName)) {\n // the dependency is also in the upgrade list and not previously added, we should add the dependency first\n debug(`conflict for dependency \"${depName}\" at adapter \"${relAdapter}\"`);\n conflict = true;\n break;\n }\n }\n }\n // we reached here and no conflict so every dep is satisfied\n if (!conflict) {\n sortedAdapters.push(relAdapter);\n relevantAdapters.splice(relevantAdapters.indexOf(relAdapter), 1);\n oneAdapterAdded = true;\n }\n }\n }\n\n if (!oneAdapterAdded) {\n // no adapter during this loop -> circular dependency\n console.warn(`Circular dependency detected between adapters \"${relevantAdapters.join(', ')}\"`);\n sortedAdapters.concat(relevantAdapters);\n break; // however, break and try to update\n }\n }\n\n debug(`upgrade order is \"${sortedAdapters.join(', ')}\"`);\n\n for (const sortedAdapter of sortedAdapters) {\n if (repo[sortedAdapter]?.controller) {\n continue;\n }\n await this.upgradeAdapter(repo, sortedAdapter, forceDowngrade, autoConfirm, true);\n }\n } else {\n console.log('All adapters are up to date');\n }\n }\n\n /**\n * Checks that local and global deps are fulfilled else rejects promise\n *\n * @param deps local dependencies - required on this host\n * @param globalDeps global dependencies - required on one of the hosts\n */\n private async _checkDependencies(deps: IoPackDependencies, globalDeps: IoPackDependencies): Promise<void> {\n if (!deps && !globalDeps) {\n return Promise.resolve();\n }\n\n deps = tools.parseDependencies(deps);\n globalDeps = tools.parseDependencies(globalDeps);\n // combine both dependencies\n const allDeps = { ...deps, ...globalDeps };\n\n // Get all installed adapters\n let objs;\n try {\n objs = await this.objects.getObjectViewAsync(\n 'system',\n 'instance',\n {\n startkey: 'system.adapter.',\n endkey: 'system.adapter.\\u9999'\n },\n undefined\n );\n } catch (e) {\n return Promise.reject(e);\n }\n\n if (objs?.rows?.length) {\n for (const dName in allDeps) {\n if (dName === 'js-controller') {\n const version = allDeps[dName];\n // Check only if version not *, else we don't have to read io-pack unnecessarily\n if (version !== '*') {\n const iopkg_ = fs.readJSONSync(`${tools.getControllerDir()}/package.json`);\n try {\n if (!semver.satisfies(iopkg_.version, version, { includePrerelease: true })) {\n return Promise.reject(\n new Error(\n `Invalid version of \"${dName}\". Installed \"${iopkg_.version}\", required \"${version}`\n )\n );\n }\n } catch (e) {\n console.log(`Can not check js-controller dependency requirement: ${e.message}`);\n return Promise.reject(\n new Error(\n `Invalid version of \"${dName}\". Installed \"${iopkg_.version}\", required \"${version}`\n )\n );\n }\n }\n } else {\n let gInstances: ioBroker.GetObjectViewItem<ioBroker.InstanceObject>[] = [];\n let locInstances: ioBroker.GetObjectViewItem<ioBroker.InstanceObject>[] = [];\n // if global dep get all instances of adapter\n if (globalDeps[dName] !== undefined) {\n gInstances = objs.rows.filter(obj => obj.value.common && obj.value.common.name === dName);\n }\n if (deps[dName] !== undefined) {\n // local dep get all instances on same host\n locInstances = objs.rows.filter(\n obj =>\n obj.value.common &&\n obj.value.common.name === dName &&\n obj.value.common.host === this.hostname\n );\n if (locInstances.length === 0) {\n return Promise.reject(new Error(`Required dependency \"${dName}\" not found on this host.`));\n }\n }\n\n let isFound = false;\n // we check, that all instances match - respect different local and global dep versions\n for (const instance of locInstances) {\n const instanceVersion = instance.value.common.version;\n try {\n if (\n !semver.satisfies(instanceVersion, deps[dName], {\n includePrerelease: true\n })\n ) {\n return Promise.reject(\n new Error(\n `Invalid version of \"${dName}\". Installed \"${instanceVersion}\", required \"${deps[dName]}`\n )\n );\n }\n } catch (e) {\n console.log(`Can not check dependency requirement: ${e.message}`);\n return Promise.reject(\n new Error(\n `Invalid version of \"${dName}\". Installed \"${instanceVersion}\", required \"${deps[dName]}`\n )\n );\n }\n isFound = true;\n }\n\n for (const instance of gInstances) {\n const instanceVersion = instance.value.common.version;\n try {\n if (\n !semver.satisfies(instanceVersion, globalDeps[dName], {\n includePrerelease: true\n })\n ) {\n return Promise.reject(\n new Error(\n `Invalid version of \"${dName}\". Installed \"${instanceVersion}\", required \"${globalDeps[dName]}`\n )\n );\n }\n } catch (e) {\n console.log(`Can not check dependency requirement: ${e.message}`);\n return Promise.reject(\n new Error(\n `Invalid version of \"${dName}\". Installed \"${instanceVersion}\", required \"${globalDeps[dName]}`\n )\n );\n }\n isFound = true;\n }\n\n if (isFound === false) {\n return Promise.reject(new Error(`Required dependency \"${dName}\" not found.`));\n }\n }\n }\n }\n }\n\n /**\n * Try to async upgrade adapter from given source with some checks\n *\n * @param repoUrlOrObject url of the selected repository or parsed repo, if undefined use current active repository\n * @param adapter name of the adapter (can also include version like web@3.0.0)\n * @param forceDowngrade flag to force downgrade\n * @param autoConfirm automatically confirm the tty questions (bypass)\n * @param upgradeAll if true, this is an upgrade all call, we don't do major upgrades if no tty\n */\n async upgradeAdapter(\n repoUrlOrObject: string | Record<string, any> | undefined,\n adapter: string,\n forceDowngrade: boolean,\n autoConfirm: boolean,\n upgradeAll: boolean\n ): Promise<void> {\n let sources: Record<string, any>;\n if (!repoUrlOrObject || !tools.isObject(repoUrlOrObject)) {\n try {\n sources = await getRepository({ repoName: repoUrlOrObject, objects: this.objects });\n } catch (e) {\n console.error(e.message);\n return this.processExit(e instanceof IoBrokerError ? e.code : e);\n }\n } else {\n sources = repoUrlOrObject;\n }\n\n let version: string;\n if (adapter.includes('@')) {\n const parts = adapter.split('@');\n adapter = parts[0];\n version = parts[1];\n } else {\n version = '';\n }\n if (version) {\n forceDowngrade = true;\n }\n\n /** Repository entry of this adapter */\n const repoAdapter: Record<string, any> = sources[adapter];\n\n // TODO: not really adapter object but close enough\n const finishUpgrade = async (name: string, ioPack?: ioBroker.AdapterObject): Promise<void> => {\n if (!ioPack) {\n const adapterDir = tools.getAdapterDir(name);\n\n if (!adapterDir) {\n console.error(`Cannot find io-package.json in ${adapterDir}`);\n return this.processExit(EXIT_CODES.MISSING_ADAPTER_FILES);\n }\n\n try {\n // close enough to an AdapterObject\n ioPack = fs.readJSONSync(path.join(adapterDir, 'io-package.json')) as ioBroker.AdapterObject;\n } catch {\n console.error(`Cannot find io-package.json in ${adapterDir}`);\n return this.processExit(EXIT_CODES.MISSING_ADAPTER_FILES);\n }\n }\n\n if (ioPack.common.osDependencies) {\n // install linux/osx libraries\n await this.install.installOSPackages(ioPack.common.osDependencies);\n }\n\n // Upload www and admin files of adapter\n await this.upload.uploadAdapter(name, false, true);\n // extend all adapter instance default configs with current config\n // (introduce potentially new attributes while keeping current settings)\n await this.upload.upgradeAdapterObjects(name, ioPack);\n await this.upload.uploadAdapter(name, true, true);\n };\n\n const adapterDir = tools.getAdapterDir(adapter);\n\n // Read actual description of installed adapter with version\n if (!adapterDir || (!version && !fs.existsSync(path.join(adapterDir, 'io-package.json')))) {\n return console.log(\n `Adapter \"${adapter}\"${\n adapter.length < 15 ? new Array(15 - adapter.length).join(' ') : ''\n } is not installed.`\n );\n }\n // Get the url of io-package.json or direct the version\n if (!repoAdapter) {\n console.log(`Adapter \"${adapter}\" is not in the repository and cannot be updated.`);\n return this.processExit(EXIT_CODES.ADAPTER_NOT_FOUND);\n }\n if (repoAdapter.controller) {\n return console.log(\n `Cannot update ${adapter} using this command. Please use \"iobroker upgrade self\" instead!`\n );\n }\n\n // TODO: not 100 % true but should be correct enough\n let ioInstalled: Pick<ioBroker.AdapterObject, 'common'>;\n if (adapterDir && fs.existsSync(path.join(adapterDir, 'io-package.json'))) {\n ioInstalled = fs.readJsonSync(`${adapterDir}/io-package.json`);\n } else {\n // @ts-expect-error https://github.com/ioBroker/adapter-core/issues/455\n ioInstalled = { common: { version: '0.0.0' } };\n }\n\n const installedVersion = ioInstalled.common.version;\n\n /**\n * We show changelog (news) and ask user if he really wants to upgrade but only if fd is associated with a tty, returns true if upgrade desired\n *\n * @param installedVersion - installed version of adapter\n * @param targetVersion - target version of adapter\n * @param adapterName - name of the adapter\n */\n const showUpgradeDialog = (installedVersion: string, targetVersion: string, adapterName: string): boolean => {\n // major upgrade or downgrade\n const isMajor = semver.major(installedVersion) !== semver.major(targetVersion);\n\n if (autoConfirm || (!tty.isatty(process.stdout.fd) && (!isMajor || !upgradeAll))) {\n // force flag or script on non major or single adapter upgrade -> always upgrade\n return true;\n }\n\n if (!tty.isatty(process.stdout.fd) && isMajor && upgradeAll) {\n // no tty and not forced and multiple adapters, do not upgrade\n console.log(`Skip major upgrade of ${adapterName} from ${installedVersion} to ${targetVersion}`);\n return false;\n }\n\n const isUpgrade = semver.gt(targetVersion, installedVersion);\n const isDowngrade = semver.lt(targetVersion, installedVersion);\n\n // if information in repo files -> show news\n if (repoAdapter?.news) {\n const news = repoAdapter.news;\n\n let first = true;\n // check if upgrade or downgrade\n if (isUpgrade) {\n for (const version in news) {\n try {\n if (semver.lte(version, targetVersion) && semver.gt(version, installedVersion)) {\n if (first === true) {\n const noMissingNews = news[targetVersion] && news[installedVersion];\n console.log(\n `\\nThis upgrade of \"${adapter}\" will ${\n noMissingNews ? '' : 'at least '\n }introduce the following changes:`\n );\n console.log(\n '=========================================================================='\n );\n first = false;\n } else if (first === false) {\n console.log();\n }\n console.log(`-> ${version}:`);\n console.log(news[version].en);\n }\n } catch {\n // ignore\n }\n }\n } else if (isDowngrade) {\n for (const version in news) {\n try {\n if (semver.gt(version, targetVersion) && semver.lte(version, installedVersion)) {\n if (first === true) {\n const noMissingNews = news[targetVersion] && news[installedVersion];\n console.log(\n `\\nThis downgrade of \"${adapter}\" will ${\n noMissingNews ? '' : 'at least '\n }remove the following changes:`\n );\n console.log(\n '=========================================================================='\n );\n first = false;\n } else if (first === false) {\n console.log();\n }\n console.log(`-> ${version}`);\n console.log(news[version].en);\n }\n } catch {\n // ignore\n }\n }\n }\n if (first === false) {\n console.log('==========================================================================\\n');\n }\n }\n\n let answer;\n\n // ask user if he really wants to upgrade/downgrade/reinstall - repeat until (y)es or (n)o given\n do {\n if (isUpgrade || isDowngrade) {\n if (isMajor) {\n console.log(\n `BE CAREFUL: THIS IS A MAJOR ${\n isUpgrade ? 'UPGRADE' : 'DOWNGRADE'\n }, WHICH WILL MOST LIKELY INTRODUCE BREAKING CHANGES!`\n );\n }\n answer = rl.question(\n `Would you like to ${\n isUpgrade ? 'upgrade' : 'downgrade'\n } ${adapter} from @${installedVersion} to @${\n version || repoAdapter.version\n } now? [(y)es, (n)o]: `,\n {\n defaultInput: 'n'\n }\n );\n } else {\n answer = rl.question(\n `Would you like to reinstall version ${\n version || repoAdapter.version\n } of ${adapter} now? [(y)es, (n)o]: `,\n {\n defaultInput: 'n'\n }\n );\n }\n\n answer = answer.toLowerCase();\n\n if (answer === 'n' || answer === 'no') {\n return false;\n }\n } while (answer !== 'y' && answer !== 'yes');\n return true;\n };\n\n // If version is included in repository\n if (repoAdapter.version) {\n if (!forceDowngrade) {\n try {\n await this._checkDependencies(repoAdapter.dependencies, repoAdapter.globalDependencies);\n } catch (e) {\n return console.error(`Cannot check dependencies: ${e.message}`);\n }\n }\n\n if (\n !forceDowngrade &&\n (repoAdapter.version === installedVersion || tools.upToDate(repoAdapter.version, installedVersion))\n ) {\n return console.log(\n `Adapter \"${adapter}\"${\n adapter.length < 15 ? new Array(15 - adapter.length).join(' ') : ''\n } is up to date.`\n );\n } else {\n const targetVersion = version || repoAdapter.version;\n\n const isIgnored = await isVersionIgnored({\n adapterName: adapter,\n version: targetVersion,\n objects: this.objects\n });\n\n if (isIgnored) {\n console.log(\n `No upgrade of \"${adapter}\" desired, because version \"${targetVersion}\" is configured to be ignored by the user. Run \"${tools.appNameLowerCase} version ${adapter} --recognize\" to allow this upgrade!`\n );\n return;\n }\n\n try {\n if (!showUpgradeDialog(installedVersion, targetVersion, adapter)) {\n console.log(`No upgrade of \"${adapter}\" desired.`);\n return;\n }\n } catch (e) {\n console.log(`Can not check version information to display upgrade infos: ${e.message}`);\n }\n console.log(`Update ${adapter} from @${installedVersion} to @${targetVersion}`);\n const npmPacketName = `${tools.appNameLowerCase}.${adapter}`;\n\n try {\n if (!semver.diff(installedVersion, targetVersion)) {\n console.log(`Uninstall npm packet \"${npmPacketName}\" for a clean re-installation`);\n await tools.uninstallNodeModule(npmPacketName, { debug: process.argv.includes('--debug') });\n }\n } catch (e) {\n console.warn(`Could not uninstall npm packet \"${npmPacketName}\": ${e.message}`);\n }\n\n // Get the adapter from website\n const { packetName, stoppedList } = await this.install.downloadPacket(\n sources,\n `${adapter}@${targetVersion}`\n );\n await finishUpgrade(packetName);\n await this.install.enableInstances(stoppedList, true);\n }\n } else if (repoAdapter.meta) {\n // Read repository from url or file\n const ioPack = (await tools.getJsonAsync(repoAdapter.meta)) as ioBroker.AdapterObject;\n if (!ioPack) {\n console.error(`Cannot parse file${repoAdapter.meta}`);\n return;\n }\n\n if (!forceDowngrade) {\n try {\n // @ts-expect-error https://github.com/ioBroker/adapter-core/issues/455\n await this._checkDependencies(ioPack.common.dependencies, ioPack.common.globalDependencies);\n } catch (e) {\n console.error(`Cannot check dependencies: ${e.message}`);\n return;\n }\n }\n\n if (\n !version &&\n (ioPack.common.version === installedVersion ||\n (!forceDowngrade && tools.upToDate(ioPack.common.version, installedVersion)))\n ) {\n console.log(\n `Adapter \"${adapter}\"${\n adapter.length < 15 ? new Array(15 - adapter.length).join(' ') : ''\n } is up to date.`\n );\n } else {\n // Get the adapter from web site\n const targetVersion = version || ioPack.common.version;\n\n const isIgnored = await isVersionIgnored({\n adapterName: adapter,\n version: targetVersion,\n objects: this.objects\n });\n\n if (isIgnored) {\n console.log(\n `No upgrade of \"${adapter}\" desired, because version \"${targetVersion}\" is configured to be ignored by the user. Run \"${tools.appNameLowerCase} version ${adapter} --recognize\" to allow this upgrade!`\n );\n return;\n }\n\n try {\n if (!showUpgradeDialog(installedVersion, targetVersion, adapter)) {\n console.log(`No upgrade of \"${adapter}\" desired.`);\n return;\n }\n } catch (e) {\n console.log(`Can not check version information to display upgrade infos: ${e.message}`);\n }\n console.log(`Update ${adapter} from @${installedVersion} to @${targetVersion}`);\n const { packetName, stoppedList } = await this.install.downloadPacket(\n sources,\n `${adapter}@${targetVersion}`\n );\n await finishUpgrade(packetName, ioPack);\n await this.install.enableInstances(stoppedList, true);\n }\n } else if (forceDowngrade) {\n try {\n if (!showUpgradeDialog(installedVersion, version, adapter)) {\n return console.log(`No upgrade of \"${adapter}\" desired.`);\n }\n } catch (e) {\n console.log(`Can not check version information to display upgrade infos: ${e.message}`);\n }\n console.warn(`Unable to get version for \"${adapter}\". Update anyway.`);\n console.log(`Update ${adapter} from @${installedVersion} to @${version}`);\n // Get the adapter from website\n const { packetName, stoppedList } = await this.install.downloadPacket(sources, `${adapter}@${version}`);\n await finishUpgrade(packetName);\n await this.install.enableInstances(stoppedList, true);\n } else {\n return console.error(`Unable to get version for \"${adapter}\".`);\n }\n }\n\n /**\n * Upgrade the js-controller\n *\n * @param repoUrl the repo or url\n * @param forceDowngrade if downgrades are allowed\n * @param controllerRunning if controller is currently running\n */\n async upgradeController(repoUrl: string, forceDowngrade: boolean, controllerRunning: boolean): Promise<void> {\n let sources: Record<string, any>;\n\n try {\n const result = await getRepository({ repoName: repoUrl, objects: this.objects });\n if (!result) {\n return console.warn(`Cannot get repository under \"${repoUrl}\"`);\n }\n sources = result;\n } catch (e) {\n console.error(e.message);\n return this.processExit(e instanceof IoBrokerError ? e.code : e);\n }\n\n const installed = fs.readJSONSync(`${tools.getControllerDir()}/io-package.json`);\n if (!installed || !installed.common || !installed.common.version) {\n return console.error(\n `Host \"${this.hostname}\"${\n this.hostname.length < 15 ? ''.padStart(15 - this.hostname.length) : ''\n } is not installed.`\n );\n }\n\n const controllerName = installed.common.name;\n /** Repository entry of the controller */\n const repoController = sources[controllerName];\n\n if (!repoController) {\n // no info for controller\n return console.error(`Cannot find this controller \"${controllerName}\" in repository.`);\n }\n\n if (repoController.version) {\n if (\n !forceDowngrade &&\n (repoController.version === installed.common.version ||\n tools.upToDate(repoController.version, installed.common.version))\n ) {\n console.log(\n `Host \"${this.hostname}\"${\n this.hostname.length < 15 ? new Array(15 - this.hostname.length).join(' ') : ''\n } is up to date.`\n );\n } else if (controllerRunning) {\n console.warn(`Controller is running. Please stop ioBroker first.`);\n } else {\n console.log(`Update ${controllerName} from @${installed.common.version} to @${repoController.version}`);\n // Get the controller from website\n await this.install.downloadPacket(sources, `${controllerName}@${repoController.version}`, {\n stopDb: true\n });\n }\n } else {\n const ioPack = await tools.getJsonAsync(repoController.meta);\n if ((!ioPack || !ioPack.common) && !forceDowngrade) {\n return console.warn(\n `Cannot read version. Write \"${tools.appName} upgrade self --force\" to upgrade controller anyway.`\n );\n }\n let version = ioPack?.common ? ioPack.common.version : '';\n if (version) {\n version = `@${version}`;\n }\n\n if (\n (ioPack?.common && ioPack.common.version === installed.common.version) ||\n (!forceDowngrade && ioPack?.common && tools.upToDate(ioPack.common.version, installed.common.version))\n ) {\n console.log(\n `Host \"${this.hostname}\"${\n this.hostname.length < 15 ? new Array(15 - this.hostname.length).join(' ') : ''\n } is up to date.`\n );\n } else if (controllerRunning) {\n console.warn(`Controller is running. Please stop ioBroker first.`);\n } else {\n const name = ioPack?.common?.name || controllerName;\n console.log(`Update ${name} from @${installed.common.version} to ${version}`);\n // Get the controller from website\n await this.install.downloadPacket(sources, name + version, { stopDb: true });\n }\n }\n }\n}\n"],
|
|
4
|
+
"sourcesContent": ["import Debug from 'debug';\nimport fs from 'fs-extra';\nimport { tools, EXIT_CODES } from '@iobroker/js-controller-common';\nimport semver from 'semver';\nimport { Upload } from '@/lib/setup/setupUpload.js';\nimport { Install } from '@/lib/setup/setupInstall.js';\nimport rl from 'readline-sync';\nimport tty from 'node:tty';\nimport path from 'node:path';\nimport { getRepository, isVersionIgnored } from '@/lib/setup/utils.js';\nimport type { Client as ObjectsInRedisClient } from '@iobroker/db-objects-redis';\nimport type { Client as StatesInRedisClient } from '@iobroker/db-states-redis';\nimport type { ProcessExitCallback } from '@/lib/_Types.js';\nimport { IoBrokerError } from '@/lib/setup/customError.js';\n\nconst debug = Debug('iobroker:cli');\n\ntype IoPackDependencies = string[] | Record<string, any>[] | Record<string, any>;\n\ninterface CLIUpgradeOptions {\n processExit: ProcessExitCallback;\n objects: ObjectsInRedisClient;\n states: StatesInRedisClient;\n params: Record<string, any>;\n}\n\nexport class Upgrade {\n private readonly hostname = tools.getHostName();\n private readonly upload: Upload;\n private readonly install: Install;\n private readonly objects: ObjectsInRedisClient;\n private readonly processExit: ProcessExitCallback;\n\n constructor(options: CLIUpgradeOptions) {\n options = options || {};\n\n if (!options.processExit) {\n throw new Error('Invalid arguments: processExit is missing');\n }\n\n this.processExit = options.processExit;\n this.objects = options.objects;\n\n this.upload = new Upload(options);\n this.install = new Install(options);\n }\n\n /**\n * Sorts the adapters by their dependencies and then upgrades multiple adapters from the given repository url\n *\n * @param repo the repository content\n * @param list list of adapters to upgrade\n * @param forceDowngrade flag to force downgrade\n * @param autoConfirm automatically confirm the tty questions (bypass)\n */\n async upgradeAdapterHelper(\n repo: Record<string, any>,\n list: string[],\n forceDowngrade: boolean,\n autoConfirm: boolean\n ): Promise<void> {\n const relevantAdapters = [];\n // check which adapters are upgradeable and sort them according to their dependencies\n for (const adapter of list) {\n if (repo[adapter].controller) {\n // skip controller\n continue;\n }\n const adapterDir = tools.getAdapterDir(adapter);\n if (adapterDir && fs.existsSync(path.join(adapterDir, 'io-package.json'))) {\n const ioInstalled = fs.readJsonSync(path.join(adapterDir, 'io-package.json'));\n if (!tools.upToDate(repo[adapter].version, ioInstalled.common.version)) {\n // not up to date, we need to put it into account for our dependency check\n relevantAdapters.push(adapter);\n }\n }\n }\n\n if (relevantAdapters.length) {\n const sortedAdapters = [];\n\n while (relevantAdapters.length) {\n let oneAdapterAdded = false;\n // create an ordered list for upgrades\n for (let i = relevantAdapters.length - 1; i >= 0; i--) {\n const relAdapter = relevantAdapters[i];\n // if a new version has no dependencies, we can upgrade\n if (!repo[relAdapter].dependencies && !repo[relAdapter].globalDependencies) {\n // no deps, simply add it\n sortedAdapters.push(relAdapter);\n relevantAdapters.splice(relevantAdapters.indexOf(relAdapter), 1);\n oneAdapterAdded = true;\n } else {\n const allDeps: Record<string, string> = {\n ...tools.parseDependencies(repo[relAdapter].dependencies),\n ...tools.parseDependencies(repo[relAdapter].globalDependencies)\n };\n\n // we have to check if the deps are there\n let conflict = false;\n for (const [depName, version] of Object.entries(allDeps)) {\n debug(`adapter \"${relAdapter}\" has dependency \"${depName}\": \"${version}\"`);\n if (version !== '*') {\n // dependency is important because it affects the version range\n if (relevantAdapters.includes(depName)) {\n // the dependency is also in the upgrade list and not previously added, we should add the dependency first\n debug(`conflict for dependency \"${depName}\" at adapter \"${relAdapter}\"`);\n conflict = true;\n break;\n }\n }\n }\n // we reached here and no conflict, so every dep is satisfied\n if (!conflict) {\n sortedAdapters.push(relAdapter);\n relevantAdapters.splice(relevantAdapters.indexOf(relAdapter), 1);\n oneAdapterAdded = true;\n }\n }\n }\n\n if (!oneAdapterAdded) {\n // no adapter during this loop -> circular dependency\n console.warn(`Circular dependency detected between adapters \"${relevantAdapters.join(', ')}\"`);\n sortedAdapters.concat(relevantAdapters);\n break; // however, break and try to update\n }\n }\n\n debug(`upgrade order is \"${sortedAdapters.join(', ')}\"`);\n\n for (const sortedAdapter of sortedAdapters) {\n if (repo[sortedAdapter]?.controller) {\n continue;\n }\n await this.upgradeAdapter(repo, sortedAdapter, forceDowngrade, autoConfirm, true);\n }\n } else {\n console.log('All adapters are up to date');\n }\n }\n\n /**\n * Checks that local and global deps are fulfilled else rejects promise\n *\n * @param deps local dependencies - required on this host\n * @param globalDeps global dependencies - required on one of the hosts\n */\n private async _checkDependencies(deps: IoPackDependencies, globalDeps: IoPackDependencies): Promise<void> {\n if (!deps && !globalDeps) {\n return Promise.resolve();\n }\n\n deps = tools.parseDependencies(deps);\n globalDeps = tools.parseDependencies(globalDeps);\n // combine both dependencies\n const allDeps = { ...deps, ...globalDeps };\n\n // Get all installed adapters\n let objs;\n try {\n objs = await this.objects.getObjectViewAsync(\n 'system',\n 'instance',\n {\n startkey: 'system.adapter.',\n endkey: 'system.adapter.\\u9999'\n },\n undefined\n );\n } catch (e) {\n return Promise.reject(e);\n }\n\n if (objs?.rows?.length) {\n for (const dName in allDeps) {\n if (dName === 'js-controller') {\n const version = allDeps[dName];\n // Check only if version not *, else we don't have to read io-pack unnecessarily\n if (version !== '*') {\n const iopkg_ = fs.readJSONSync(`${tools.getControllerDir()}/package.json`);\n try {\n if (!semver.satisfies(iopkg_.version, version, { includePrerelease: true })) {\n return Promise.reject(\n new Error(\n `Invalid version of \"${dName}\". Installed \"${iopkg_.version}\", required \"${version}`\n )\n );\n }\n } catch (e) {\n console.log(`Can not check js-controller dependency requirement: ${e.message}`);\n return Promise.reject(\n new Error(\n `Invalid version of \"${dName}\". Installed \"${iopkg_.version}\", required \"${version}`\n )\n );\n }\n }\n } else {\n let gInstances: ioBroker.GetObjectViewItem<ioBroker.InstanceObject>[] = [];\n let locInstances: ioBroker.GetObjectViewItem<ioBroker.InstanceObject>[] = [];\n // if global dep get all instances of adapter\n if (globalDeps[dName] !== undefined) {\n gInstances = objs.rows.filter(obj => obj.value.common && obj.value.common.name === dName);\n }\n if (deps[dName] !== undefined) {\n // local dependencies: get all instances on the same host\n locInstances = objs.rows.filter(\n obj =>\n obj.value.common &&\n obj.value.common.name === dName &&\n obj.value.common.host === this.hostname\n );\n if (locInstances.length === 0) {\n return Promise.reject(new Error(`Required dependency \"${dName}\" not found on this host.`));\n }\n }\n\n let isFound = false;\n // we check that all instances match - respect different local and global dep versions\n for (const instance of locInstances) {\n const instanceVersion = instance.value.common.version;\n try {\n if (\n !semver.satisfies(instanceVersion, deps[dName], {\n includePrerelease: true\n })\n ) {\n return Promise.reject(\n new Error(\n `Invalid version of \"${dName}\". Installed \"${instanceVersion}\", required \"${deps[dName]}`\n )\n );\n }\n } catch (e) {\n console.log(`Can not check dependency requirement: ${e.message}`);\n return Promise.reject(\n new Error(\n `Invalid version of \"${dName}\". Installed \"${instanceVersion}\", required \"${deps[dName]}`\n )\n );\n }\n isFound = true;\n }\n\n for (const instance of gInstances) {\n const instanceVersion = instance.value.common.version;\n try {\n if (\n !semver.satisfies(instanceVersion, globalDeps[dName], {\n includePrerelease: true\n })\n ) {\n return Promise.reject(\n new Error(\n `Invalid version of \"${dName}\". Installed \"${instanceVersion}\", required \"${globalDeps[dName]}`\n )\n );\n }\n } catch (e) {\n console.log(`Can not check dependency requirement: ${e.message}`);\n return Promise.reject(\n new Error(\n `Invalid version of \"${dName}\". Installed \"${instanceVersion}\", required \"${globalDeps[dName]}`\n )\n );\n }\n isFound = true;\n }\n\n if (isFound === false) {\n return Promise.reject(new Error(`Required dependency \"${dName}\" not found.`));\n }\n }\n }\n }\n }\n\n /**\n * Try to async upgrade adapter from a given source with some checks\n *\n * @param repoUrlOrObject url of the selected repository or parsed repo, if undefined, use current active repository\n * @param adapter name of the adapter (can also include version like web@3.0.0)\n * @param forceDowngrade flag to force downgrade\n * @param autoConfirm automatically confirm the tty questions (bypass)\n * @param upgradeAll if true, this is an upgrade all call, we don't do major upgrades if no tty\n */\n async upgradeAdapter(\n repoUrlOrObject: string | Record<string, any> | undefined,\n adapter: string,\n forceDowngrade: boolean,\n autoConfirm: boolean,\n upgradeAll: boolean\n ): Promise<void> {\n let sources: Record<string, any>;\n if (!repoUrlOrObject || !tools.isObject(repoUrlOrObject)) {\n try {\n sources = await getRepository({ repoName: repoUrlOrObject, objects: this.objects });\n } catch (e) {\n console.error(e.message);\n return this.processExit(e instanceof IoBrokerError ? e.code : e);\n }\n } else {\n sources = repoUrlOrObject;\n }\n\n let version: string;\n if (adapter.includes('@')) {\n const parts = adapter.split('@');\n adapter = parts[0];\n version = parts[1];\n } else {\n version = '';\n }\n if (version) {\n forceDowngrade = true;\n }\n\n /** Repository entry of this adapter */\n const repoAdapter: Record<string, any> = sources[adapter];\n\n // TODO: not really adapter object but close enough\n const finishUpgrade = async (name: string, ioPack?: ioBroker.AdapterObject): Promise<void> => {\n if (!ioPack) {\n const adapterDir = tools.getAdapterDir(name);\n\n if (!adapterDir) {\n console.error(`Cannot find io-package.json in ${adapterDir}`);\n return this.processExit(EXIT_CODES.MISSING_ADAPTER_FILES);\n }\n\n try {\n // close enough to an AdapterObject\n ioPack = fs.readJSONSync(path.join(adapterDir, 'io-package.json')) as ioBroker.AdapterObject;\n } catch {\n console.error(`Cannot find io-package.json in ${adapterDir}`);\n return this.processExit(EXIT_CODES.MISSING_ADAPTER_FILES);\n }\n }\n\n if (ioPack.common.osDependencies) {\n // install linux/osx libraries\n await this.install.installOSPackages(ioPack.common.osDependencies);\n }\n\n // Upload www and admin files of adapter\n await this.upload.uploadAdapter(name, false, true);\n // extend all adapter instance default configs with current config\n // (introduce potentially new attributes while keeping current settings)\n await this.upload.upgradeAdapterObjects(name, ioPack);\n await this.upload.uploadAdapter(name, true, true);\n };\n\n const adapterDir = tools.getAdapterDir(adapter);\n\n // Read the actual description of installed adapter with a version\n if (!adapterDir || (!version && !fs.existsSync(path.join(adapterDir, 'io-package.json')))) {\n return console.log(\n `Adapter \"${adapter}\"${\n adapter.length < 15 ? new Array(15 - adapter.length).join(' ') : ''\n } is not installed.`\n );\n }\n // Get the url of io-package.json or direct the version\n if (!repoAdapter) {\n console.log(`Adapter \"${adapter}\" is not in the repository and cannot be updated.`);\n return this.processExit(EXIT_CODES.ADAPTER_NOT_FOUND);\n }\n if (repoAdapter.controller) {\n return console.log(\n `Cannot update ${adapter} using this command. Please use \"iobroker upgrade self\" instead!`\n );\n }\n\n // TODO: not 100 % true but should be correct enough\n let ioInstalled: Pick<ioBroker.AdapterObject, 'common'>;\n if (adapterDir && fs.existsSync(path.join(adapterDir, 'io-package.json'))) {\n ioInstalled = fs.readJsonSync(`${adapterDir}/io-package.json`);\n } else {\n // @ts-expect-error https://github.com/ioBroker/adapter-core/issues/455\n ioInstalled = { common: { version: '0.0.0' } };\n }\n\n const installedVersion = ioInstalled.common.version;\n\n /**\n * We show changelog (news) and ask user if he really wants to upgrade but only if fd is associated with a tty, returns true if upgrade desired\n *\n * @param installedVersion - installed version of adapter\n * @param targetVersion - target version of adapter\n * @param adapterName - name of the adapter\n */\n const showUpgradeDialog = (installedVersion: string, targetVersion: string, adapterName: string): boolean => {\n // major upgrade or downgrade\n const isMajor = semver.major(installedVersion) !== semver.major(targetVersion);\n\n if (autoConfirm || (!tty.isatty(process.stdout.fd) && (!isMajor || !upgradeAll))) {\n // force flag or script on non-major or single adapter upgrade -> always upgrade\n return true;\n }\n\n if (!tty.isatty(process.stdout.fd) && isMajor && upgradeAll) {\n // no tty and not forced and multiple adapters, do not upgrade\n console.log(`Skip major upgrade of ${adapterName} from ${installedVersion} to ${targetVersion}`);\n return false;\n }\n\n const isUpgrade = semver.gt(targetVersion, installedVersion);\n const isDowngrade = semver.lt(targetVersion, installedVersion);\n\n // if information in repo files -> show news\n if (repoAdapter?.news) {\n const news = repoAdapter.news;\n\n let first = true;\n // check if upgrade or downgrade\n if (isUpgrade) {\n for (const version in news) {\n try {\n if (semver.lte(version, targetVersion) && semver.gt(version, installedVersion)) {\n if (first === true) {\n const noMissingNews = news[targetVersion] && news[installedVersion];\n console.log(\n `\\nThis upgrade of \"${adapter}\" will ${\n noMissingNews ? '' : 'at least '\n }introduce the following changes:`\n );\n console.log(\n '=========================================================================='\n );\n first = false;\n } else if (first === false) {\n console.log();\n }\n console.log(`-> ${version}:`);\n console.log(news[version].en);\n }\n } catch {\n // ignore\n }\n }\n } else if (isDowngrade) {\n for (const version in news) {\n try {\n if (semver.gt(version, targetVersion) && semver.lte(version, installedVersion)) {\n if (first === true) {\n const noMissingNews = news[targetVersion] && news[installedVersion];\n console.log(\n `\\nThis downgrade of \"${adapter}\" will ${\n noMissingNews ? '' : 'at least '\n }remove the following changes:`\n );\n console.log(\n '=========================================================================='\n );\n first = false;\n } else if (first === false) {\n console.log();\n }\n console.log(`-> ${version}`);\n console.log(news[version].en);\n }\n } catch {\n // ignore\n }\n }\n }\n if (first === false) {\n console.log('==========================================================================\\n');\n }\n }\n\n let answer;\n\n // ask user if he really wants to upgrade/downgrade/reinstall - repeat until (y)es or (n)o given\n do {\n if (isUpgrade || isDowngrade) {\n if (isMajor) {\n console.log(\n `BE CAREFUL: THIS IS A MAJOR ${\n isUpgrade ? 'UPGRADE' : 'DOWNGRADE'\n }, WHICH WILL MOST LIKELY INTRODUCE BREAKING CHANGES!`\n );\n }\n answer = rl.question(\n `Would you like to ${\n isUpgrade ? 'upgrade' : 'downgrade'\n } ${adapter} from @${installedVersion} to @${\n version || repoAdapter.version\n } now? [(y)es, (n)o]: `,\n {\n defaultInput: 'n'\n }\n );\n } else {\n answer = rl.question(\n `Would you like to reinstall version ${\n version || repoAdapter.version\n } of ${adapter} now? [(y)es, (n)o]: `,\n {\n defaultInput: 'n'\n }\n );\n }\n\n answer = answer.toLowerCase();\n\n if (answer === 'n' || answer === 'no') {\n return false;\n }\n } while (answer !== 'y' && answer !== 'yes');\n return true;\n };\n\n // If a version is included in the repository\n if (repoAdapter.version) {\n if (!forceDowngrade) {\n try {\n await this._checkDependencies(repoAdapter.dependencies, repoAdapter.globalDependencies);\n } catch (e) {\n return console.error(`Cannot check dependencies: ${e.message}`);\n }\n }\n\n if (\n !forceDowngrade &&\n (repoAdapter.version === installedVersion || tools.upToDate(repoAdapter.version, installedVersion))\n ) {\n return console.log(\n `Adapter \"${adapter}\"${\n adapter.length < 15 ? new Array(15 - adapter.length).join(' ') : ''\n } is up to date.`\n );\n } else {\n const targetVersion = version || repoAdapter.version;\n\n const isIgnored = await isVersionIgnored({\n adapterName: adapter,\n version: targetVersion,\n objects: this.objects\n });\n\n if (isIgnored) {\n console.log(\n `No upgrade of \"${adapter}\" desired, because version \"${targetVersion}\" is configured to be ignored by the user. Run \"${tools.appNameLowerCase} version ${adapter} --recognize\" to allow this upgrade!`\n );\n return;\n }\n\n try {\n if (!showUpgradeDialog(installedVersion, targetVersion, adapter)) {\n console.log(`No upgrade of \"${adapter}\" desired.`);\n return;\n }\n } catch (e) {\n console.log(`Can not check version information to display upgrade infos: ${e.message}`);\n }\n console.log(`Update ${adapter} from @${installedVersion} to @${targetVersion}`);\n const npmPacketName = `${tools.appNameLowerCase}.${adapter}`;\n\n try {\n if (!semver.diff(installedVersion, targetVersion)) {\n console.log(`Uninstall npm packet \"${npmPacketName}\" for a clean re-installation`);\n await tools.uninstallNodeModule(npmPacketName, { debug: process.argv.includes('--debug') });\n }\n } catch (e) {\n console.warn(`Could not uninstall npm packet \"${npmPacketName}\": ${e.message}`);\n }\n\n // Get the adapter from website\n const { packetName, stoppedList } = await this.install.downloadPacket(\n sources,\n `${adapter}@${targetVersion}`\n );\n await finishUpgrade(packetName);\n await this.install.enableInstances(stoppedList, true);\n }\n } else if (repoAdapter.meta) {\n // Read repository from url or file\n const ioPack = (await tools.getJsonAsync(repoAdapter.meta)) as ioBroker.AdapterObject;\n if (!ioPack) {\n console.error(`Cannot parse file${repoAdapter.meta}`);\n return;\n }\n\n if (!forceDowngrade) {\n try {\n // @ts-expect-error https://github.com/ioBroker/adapter-core/issues/455\n await this._checkDependencies(ioPack.common.dependencies, ioPack.common.globalDependencies);\n } catch (e) {\n console.error(`Cannot check dependencies: ${e.message}`);\n return;\n }\n }\n\n if (\n !version &&\n (ioPack.common.version === installedVersion ||\n (!forceDowngrade && tools.upToDate(ioPack.common.version, installedVersion)))\n ) {\n console.log(\n `Adapter \"${adapter}\"${\n adapter.length < 15 ? new Array(15 - adapter.length).join(' ') : ''\n } is up to date.`\n );\n } else {\n // Get the adapter from website\n const targetVersion = version || ioPack.common.version;\n\n const isIgnored = await isVersionIgnored({\n adapterName: adapter,\n version: targetVersion,\n objects: this.objects\n });\n\n if (isIgnored) {\n console.log(\n `No upgrade of \"${adapter}\" desired, because version \"${targetVersion}\" is configured to be ignored by the user. Run \"${tools.appNameLowerCase} version ${adapter} --recognize\" to allow this upgrade!`\n );\n return;\n }\n\n try {\n if (!showUpgradeDialog(installedVersion, targetVersion, adapter)) {\n console.log(`No upgrade of \"${adapter}\" desired.`);\n return;\n }\n } catch (e) {\n console.log(`Can not check version information to display upgrade infos: ${e.message}`);\n }\n console.log(`Update ${adapter} from @${installedVersion} to @${targetVersion}`);\n const { packetName, stoppedList } = await this.install.downloadPacket(\n sources,\n `${adapter}@${targetVersion}`\n );\n await finishUpgrade(packetName, ioPack);\n await this.install.enableInstances(stoppedList, true);\n }\n } else if (forceDowngrade) {\n try {\n if (!showUpgradeDialog(installedVersion, version, adapter)) {\n return console.log(`No upgrade of \"${adapter}\" desired.`);\n }\n } catch (e) {\n console.log(`Can not check version information to display upgrade infos: ${e.message}`);\n }\n console.warn(`Unable to get version for \"${adapter}\". Update anyway.`);\n console.log(`Update ${adapter} from @${installedVersion} to @${version}`);\n // Get the adapter from website\n const { packetName, stoppedList } = await this.install.downloadPacket(sources, `${adapter}@${version}`);\n await finishUpgrade(packetName);\n await this.install.enableInstances(stoppedList, true);\n } else {\n return console.error(`Unable to get version for \"${adapter}\".`);\n }\n }\n\n /**\n * Upgrade the js-controller\n *\n * @param repoUrl the repo or url\n * @param forceDowngrade if downgrades are allowed\n * @param controllerRunning if controller is currently running\n */\n async upgradeController(repoUrl: string, forceDowngrade: boolean, controllerRunning: boolean): Promise<void> {\n let sources: Record<string, any>;\n\n try {\n const result = await getRepository({ repoName: repoUrl, objects: this.objects });\n if (!result) {\n return console.warn(`Cannot get repository under \"${repoUrl}\"`);\n }\n sources = result;\n } catch (e) {\n console.error(e.message);\n return this.processExit(e instanceof IoBrokerError ? e.code : e);\n }\n\n const installed = fs.readJSONSync(`${tools.getControllerDir()}/io-package.json`);\n if (!installed || !installed.common || !installed.common.version) {\n return console.error(\n `Host \"${this.hostname}\"${\n this.hostname.length < 15 ? ''.padStart(15 - this.hostname.length) : ''\n } is not installed.`\n );\n }\n\n const controllerName = installed.common.name;\n /** Repository entry of the controller */\n const repoController = sources[controllerName];\n\n if (!repoController) {\n // no info for controller\n return console.error(`Cannot find this controller \"${controllerName}\" in repository.`);\n }\n\n if (repoController.version) {\n if (\n !forceDowngrade &&\n (repoController.version === installed.common.version ||\n tools.upToDate(repoController.version, installed.common.version))\n ) {\n console.log(\n `Host \"${this.hostname}\"${\n this.hostname.length < 15 ? new Array(15 - this.hostname.length).join(' ') : ''\n } is up to date.`\n );\n } else if (controllerRunning) {\n console.warn(`Controller is running. Please stop ioBroker first.`);\n } else {\n console.log(`Update ${controllerName} from @${installed.common.version} to @${repoController.version}`);\n // Get the controller from website\n await this.install.downloadPacket(sources, `${controllerName}@${repoController.version}`, {\n stopDb: true\n });\n }\n } else {\n const ioPack = await tools.getJsonAsync(repoController.meta);\n if ((!ioPack || !ioPack.common) && !forceDowngrade) {\n return console.warn(\n `Cannot read version. Write \"${tools.appName} upgrade self --force\" to upgrade controller anyway.`\n );\n }\n let version = ioPack?.common ? ioPack.common.version : '';\n if (version) {\n version = `@${version}`;\n }\n\n if (\n (ioPack?.common && ioPack.common.version === installed.common.version) ||\n (!forceDowngrade && ioPack?.common && tools.upToDate(ioPack.common.version, installed.common.version))\n ) {\n console.log(\n `Host \"${this.hostname}\"${\n this.hostname.length < 15 ? new Array(15 - this.hostname.length).join(' ') : ''\n } is up to date.`\n );\n } else if (controllerRunning) {\n console.warn(`Controller is running. Please stop ioBroker first.`);\n } else {\n const name = ioPack?.common?.name || controllerName;\n console.log(`Update ${name} from @${installed.common.version} to ${version}`);\n // Get the controller from website\n await this.install.downloadPacket(sources, name + version, { stopDb: true });\n }\n }\n }\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["Debug", "fs", "path", "semver", "adapterDir", "installedVersion", "tty", "version", "rl"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/setup/utils.ts"],
|
|
4
|
-
"sourcesContent": ["import { EXIT_CODES } from '@iobroker/js-controller-common';\nimport { tools } from '@iobroker/js-controller-common';\nimport type { Client as ObjectsClient } from '@iobroker/db-objects-redis';\nimport semver from 'semver';\nimport { IoBrokerError } from '@/lib/setup/customError.js';\n\ninterface GetRepositoryOptions {\n /** The objects DB client */\n objects: ObjectsClient;\n /** Name of the repository */\n repoName?: string;\n}\n\n/**\n * Get
|
|
4
|
+
"sourcesContent": ["import { EXIT_CODES } from '@iobroker/js-controller-common';\nimport { tools } from '@iobroker/js-controller-common';\nimport type { Client as ObjectsClient } from '@iobroker/db-objects-redis';\nimport semver from 'semver';\nimport { IoBrokerError } from '@/lib/setup/customError.js';\n\ninterface GetRepositoryOptions {\n /** The objects DB client */\n objects: ObjectsClient;\n /** Name of the repository */\n repoName?: string;\n}\n\n/**\n * Get JSON of the given repository\n *\n * @param options Repository specific options\n */\nexport async function getRepository(options: GetRepositoryOptions): Promise<Record<string, any>> {\n const { objects } = options;\n const { repoName } = options;\n\n let repoNameOrArray: string | string[] | undefined = repoName;\n if (!repoName || repoName === 'auto') {\n const systemConfig = await objects!.getObjectAsync('system.config');\n repoNameOrArray = systemConfig!.common.activeRepo;\n }\n\n const repoArr = !Array.isArray(repoNameOrArray) ? [repoNameOrArray!] : repoNameOrArray;\n\n const systemRepos = (await objects!.getObjectAsync('system.repositories'))!;\n\n const allSources = {};\n let changed = false;\n let anyFound = false;\n for (const repoUrl of repoArr) {\n const repo = systemRepos.native.repositories[repoUrl];\n if (repo) {\n if (typeof repo === 'string') {\n systemRepos.native.repositories[repo] = {\n link: repo,\n json: null\n };\n changed = true;\n }\n\n // If repo is not yet loaded\n if (!systemRepos.native.repositories[repoUrl].json) {\n console.log(`Update repository \"${repoUrl}\" under \"${systemRepos.native.repositories[repoUrl].link}\"`);\n const data = await tools.getRepositoryFileAsync(systemRepos.native.repositories[repoUrl].link);\n systemRepos.native.repositories[repoUrl].json = data.json;\n systemRepos.native.repositories[repoUrl].hash = data.hash;\n systemRepos.from = `system.host.${tools.getHostName()}.cli`;\n systemRepos.ts = new Date().getTime();\n changed = true;\n }\n\n if (systemRepos.native.repositories[repoUrl].json) {\n Object.assign(allSources, systemRepos.native.repositories[repoUrl].json);\n anyFound = true;\n }\n }\n\n if (changed) {\n await objects.setObjectAsync('system.repositories', systemRepos);\n }\n }\n\n if (!anyFound) {\n let message: string;\n if (repoArr.length) {\n message = `ERROR: No repositories defined matching \"${repoArr.join(\n ' | '\n )}\". Please use one of ${Object.keys(systemRepos.native.repositories)\n .map(repo => `\"${repo}\"`)\n .join(', ')}.`;\n } else {\n message = `ERROR: No repositories defined. Please define one repository as active: \"iob repo set <${Object.keys(\n systemRepos.native.repositories\n ).join(' | ')}>\"`;\n }\n\n throw new IoBrokerError({ message, code: EXIT_CODES.INVALID_REPO });\n } else {\n return allSources;\n }\n}\n\ninterface VersionOptions {\n /** The adapter name to check the version for */\n adapterName: string;\n /** The objects DB instance */\n objects: ObjectsClient;\n}\n\ninterface IgnoreVersionOptions extends VersionOptions {\n /** The version which will be checked */\n version: string;\n}\n\n/**\n * Get info if a specific version should be ignored of this adapter\n *\n * @param options name and target version of the adapter\n */\nexport async function isVersionIgnored(options: IgnoreVersionOptions): Promise<boolean> {\n const { adapterName, version, objects } = options;\n const obj = await objects.getObject(`system.host.${tools.getHostName()}.adapter.${adapterName}`);\n\n if (obj?.common.ignoreVersion === undefined) {\n return false;\n }\n\n return semver.satisfies(version, obj?.common.ignoreVersion);\n}\n\n/**\n * Ignore a specific version of an adapter\n *\n * @param options name and target version of the adapter\n */\nexport async function ignoreVersion(options: IgnoreVersionOptions): Promise<void> {\n const { adapterName, version, objects } = options;\n const id = `system.host.${tools.getHostName()}.adapter.${adapterName}`;\n const obj = await objects.getObject(id);\n\n if (!obj) {\n throw new IoBrokerError({ code: EXIT_CODES.CANNOT_SET_OBJECT, message: `Object \"${id}\" does not exist` });\n }\n\n obj.common.ignoreVersion = version;\n\n await objects.setObject(id, obj);\n}\n\n/**\n * Recognize all updates of adapter again\n *\n * @param options name of the adapter\n */\nexport async function recognizeVersion(options: VersionOptions): Promise<void> {\n const { adapterName, objects } = options;\n const id = `system.host.${tools.getHostName()}.adapter.${adapterName}`;\n const obj = await objects.getObject(id);\n\n if (!obj) {\n throw new IoBrokerError({ code: EXIT_CODES.CANNOT_SET_OBJECT, message: `Object \"${id}\" does not exist` });\n }\n\n delete obj.common.ignoreVersion;\n\n await objects.setObject(id, obj);\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["import_js_controller_common", "semver"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Install adapter
|
|
3
3
|
*
|
|
4
|
-
* Copyright 2013-
|
|
4
|
+
* Copyright 2013-2024 bluefox <dogafox@gmail.com>
|
|
5
5
|
*
|
|
6
6
|
* MIT License
|
|
7
7
|
*
|
|
@@ -188,7 +188,7 @@ export declare class Install {
|
|
|
188
188
|
*/
|
|
189
189
|
deleteInstance(adapter: string, instance?: number): Promise<void | EXIT_CODES.CANNOT_DELETE_DEPENDENCY>;
|
|
190
190
|
/**
|
|
191
|
-
* Remove all node modules
|
|
191
|
+
* Remove all node modules that has been installed by this instance
|
|
192
192
|
*
|
|
193
193
|
* @param adapter adapter name like hm-rpc
|
|
194
194
|
* @param instance e.g. 1, if undefined deletes all instances
|
|
@@ -212,7 +212,7 @@ export declare class Install {
|
|
|
212
212
|
*
|
|
213
213
|
* @param adapter adapter name
|
|
214
214
|
* @param instance instance, like 1
|
|
215
|
-
* @returns if dependent exists returns adapter name
|
|
215
|
+
* @returns if dependent exists, returns adapter name
|
|
216
216
|
*/
|
|
217
217
|
private _hasDependentInstances;
|
|
218
218
|
/**
|
|
@@ -221,7 +221,7 @@ export declare class Install {
|
|
|
221
221
|
* @param adapter adapter name
|
|
222
222
|
* @param instancesRows all instances objects view rows
|
|
223
223
|
* @param scopedHostname hostname which should be assumed as local
|
|
224
|
-
* @returns true if an instance is present on
|
|
224
|
+
* @returns true if an instance is present on another host
|
|
225
225
|
*/
|
|
226
226
|
private _checkDependencyFulfilledForeignHosts;
|
|
227
227
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Install adapter
|
|
3
3
|
*
|
|
4
|
-
* Copyright 2013-
|
|
4
|
+
* Copyright 2013-2024 bluefox <dogafox@gmail.com>
|
|
5
5
|
*
|
|
6
6
|
* MIT License
|
|
7
7
|
*
|
|
@@ -110,7 +110,7 @@ export class Install {
|
|
|
110
110
|
version = parts[1];
|
|
111
111
|
}
|
|
112
112
|
else {
|
|
113
|
-
// always take version from repository
|
|
113
|
+
// always take a version from repository
|
|
114
114
|
if (sources[packetName]?.version) {
|
|
115
115
|
version = sources[packetName].version;
|
|
116
116
|
}
|
|
@@ -178,7 +178,7 @@ export class Install {
|
|
|
178
178
|
return { packetName, stoppedList };
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
|
-
console.error(`host.${hostname} Unknown
|
|
181
|
+
console.error(`host.${hostname} Unknown packet name ${packetName}. Please install packages from outside the repository using "${tools.appNameLowerCase} url <url-or-package>"!`);
|
|
182
182
|
throw new IoBrokerError({
|
|
183
183
|
code: EXIT_CODES.UNKNOWN_PACKET_NAME,
|
|
184
184
|
message: `Unknown packetName ${packetName}. Please install packages from outside the repository using npm!`
|
|
@@ -251,7 +251,7 @@ export class Install {
|
|
|
251
251
|
npmUrl = npmUrl.substring(0, npmUrl.indexOf('#'));
|
|
252
252
|
}
|
|
253
253
|
if (npmUrl.includes('/') && !npmUrl.startsWith('@')) {
|
|
254
|
-
// only scoped packages (e.g
|
|
254
|
+
// only scoped packages (e.g., @types/node) may have a slash in their path
|
|
255
255
|
npmUrl = npmUrl.substring(npmUrl.lastIndexOf('/') + 1);
|
|
256
256
|
}
|
|
257
257
|
if (!npmUrl.startsWith('@')) {
|
|
@@ -282,7 +282,7 @@ export class Install {
|
|
|
282
282
|
debug: !!debug,
|
|
283
283
|
unsafePerm: !!options.unsafePerm
|
|
284
284
|
});
|
|
285
|
-
// code 1 is sometimes a real error and sometimes a strange error, where everything is installed but error
|
|
285
|
+
// code 1 is sometimes a real error and sometimes a strange error, where everything is installed but still the error
|
|
286
286
|
const isSuccess = result.success || (result.exitCode === 1 && !result.stderr.startsWith('npm ERR!'));
|
|
287
287
|
if (isSuccess) {
|
|
288
288
|
// Determine where the packet would be installed if npm succeeds
|
|
@@ -397,7 +397,7 @@ export class Install {
|
|
|
397
397
|
let isFound = false;
|
|
398
398
|
if (dName === 'js-controller') {
|
|
399
399
|
const version = allDeps[dName];
|
|
400
|
-
// Check only if version not *, else we
|
|
400
|
+
// Check only if version not *, else we don't have to read io-pack unnecessarily
|
|
401
401
|
if (version !== '*') {
|
|
402
402
|
const packJson = fs.readJSONSync(`${tools.getControllerDir()}/package.json`);
|
|
403
403
|
if (!semver.satisfies(packJson.version, version, { includePrerelease: true })) {
|
|
@@ -420,7 +420,7 @@ export class Install {
|
|
|
420
420
|
gInstances = objs.rows.filter(obj => obj.value.common && obj.value.common.name === dName);
|
|
421
421
|
}
|
|
422
422
|
if (deps[dName] !== undefined) {
|
|
423
|
-
// local
|
|
423
|
+
// local dependencies: get all instances on the same host
|
|
424
424
|
locInstances = objs.rows.filter(obj => obj.value.common &&
|
|
425
425
|
obj.value.common.name === dName &&
|
|
426
426
|
obj.value.common.host === hostname);
|
|
@@ -428,7 +428,7 @@ export class Install {
|
|
|
428
428
|
console.error(`host.${hostname} Required dependency "${dName}" not found on this host.`);
|
|
429
429
|
}
|
|
430
430
|
}
|
|
431
|
-
// we check
|
|
431
|
+
// we check that all existing instances match - respect different versions for local and global deps
|
|
432
432
|
for (const instance of locInstances) {
|
|
433
433
|
const instanceVersion = instance.value.common.version;
|
|
434
434
|
if (!semver.satisfies(instanceVersion, deps[dName], {
|
|
@@ -540,7 +540,7 @@ export class Install {
|
|
|
540
540
|
_installCount++;
|
|
541
541
|
const { stoppedList } = await this.downloadPacket(repoUrl, fullName);
|
|
542
542
|
await this.installAdapter(adapter, repoUrl, _installCount);
|
|
543
|
-
await this.enableInstances(stoppedList, true); // even if unlikely make sure to
|
|
543
|
+
await this.enableInstances(stoppedList, true); // even if unlikely make sure to re-enable disabled instances
|
|
544
544
|
return adapter;
|
|
545
545
|
}
|
|
546
546
|
let adapterConf;
|
|
@@ -884,7 +884,7 @@ export class Install {
|
|
|
884
884
|
.filter(row => !!row.value._id)
|
|
885
885
|
// ... that matches the pattern
|
|
886
886
|
.filter(row => instanceRegex.test(row.value._id))
|
|
887
|
-
// if instance given also delete from foreign host else only instance on this host
|
|
887
|
+
// if instance given, also delete it from foreign host else only instance on this host
|
|
888
888
|
.filter(row => {
|
|
889
889
|
if (instance !== undefined || !row.value.common?.host || row.value.common?.host === hostname) {
|
|
890
890
|
return true;
|
|
@@ -1201,7 +1201,7 @@ export class Install {
|
|
|
1201
1201
|
}
|
|
1202
1202
|
while (stateIDs.length > 0) {
|
|
1203
1203
|
if (stateIDs.length % 200 === 0) {
|
|
1204
|
-
// write progress report
|
|
1204
|
+
// write a progress report
|
|
1205
1205
|
console.log(`host.${hostname}: Only ${stateIDs.length} states left to be deleted.`);
|
|
1206
1206
|
}
|
|
1207
1207
|
// try to delete the current state
|
|
@@ -1209,7 +1209,7 @@ export class Install {
|
|
|
1209
1209
|
await this.states.delState(stateIDs.pop());
|
|
1210
1210
|
}
|
|
1211
1211
|
catch (e) {
|
|
1212
|
-
// yep that works!
|
|
1212
|
+
// yep, that works!
|
|
1213
1213
|
e !== tools.ERRORS.ERROR_NOT_FOUND &&
|
|
1214
1214
|
e.message !== tools.ERRORS.ERROR_NOT_FOUND &&
|
|
1215
1215
|
console.error(`host.${hostname} Cannot delete states: ${e.message}`);
|
|
@@ -1235,7 +1235,7 @@ export class Install {
|
|
|
1235
1235
|
}
|
|
1236
1236
|
while (objIDs.length > 0) {
|
|
1237
1237
|
if (objIDs.length % 200 === 0) {
|
|
1238
|
-
// write progress report
|
|
1238
|
+
// write a progress report
|
|
1239
1239
|
console.log(`host.${hostname}: Only ${objIDs.length} objects left to be deleted.`);
|
|
1240
1240
|
}
|
|
1241
1241
|
// try to delete the current object
|
|
@@ -1270,7 +1270,7 @@ export class Install {
|
|
|
1270
1270
|
const ioPack = await fs.readJSON(ioPackPath);
|
|
1271
1271
|
if (!ioPack.common || !ioPack.common.nondeletable) {
|
|
1272
1272
|
await this._npmUninstall(adapterNpm, false);
|
|
1273
|
-
// after uninstalling we have to restart the defined adapters
|
|
1273
|
+
// after uninstalling, we have to restart the defined adapters
|
|
1274
1274
|
if (ioPack.common.restartAdapters) {
|
|
1275
1275
|
if (!Array.isArray(ioPack.common.restartAdapters)) {
|
|
1276
1276
|
// it's not an array, now it can only be a single adapter as string
|
|
@@ -1325,7 +1325,7 @@ export class Install {
|
|
|
1325
1325
|
await _uninstallNpm();
|
|
1326
1326
|
}
|
|
1327
1327
|
else {
|
|
1328
|
-
// we are not allowed to delete last instance if another instance depends on us
|
|
1328
|
+
// we are not allowed to delete the last instance if another instance depends on us
|
|
1329
1329
|
const dependentInstance = await this._hasDependentInstances(adapter);
|
|
1330
1330
|
if (dependentInstance) {
|
|
1331
1331
|
console.log(`Cannot remove adapter "${adapter}", because instance "${dependentInstance}" depends on it!`);
|
|
@@ -1363,7 +1363,7 @@ export class Install {
|
|
|
1363
1363
|
async deleteInstance(adapter, instance) {
|
|
1364
1364
|
const knownObjectIDs = [];
|
|
1365
1365
|
const knownStateIDs = [];
|
|
1366
|
-
// we are not allowed to delete last instance if another instance depends on us
|
|
1366
|
+
// we are not allowed to delete the last instance if another instance depends on us
|
|
1367
1367
|
const dependentInstance = await this._hasDependentInstances(adapter, instance);
|
|
1368
1368
|
if (dependentInstance) {
|
|
1369
1369
|
console.log(`Cannot remove instance "${adapter}.${instance}", because instance "${dependentInstance}" depends on it!`);
|
|
@@ -1384,7 +1384,7 @@ export class Install {
|
|
|
1384
1384
|
}
|
|
1385
1385
|
}
|
|
1386
1386
|
/**
|
|
1387
|
-
* Remove all node modules
|
|
1387
|
+
* Remove all node modules that has been installed by this instance
|
|
1388
1388
|
*
|
|
1389
1389
|
* @param adapter adapter name like hm-rpc
|
|
1390
1390
|
* @param instance e.g. 1, if undefined deletes all instances
|
|
@@ -1405,7 +1405,7 @@ export class Install {
|
|
|
1405
1405
|
* @param ids - id of the adapter/instance to check for
|
|
1406
1406
|
*/
|
|
1407
1407
|
async _removeCustomFromObjects(ids) {
|
|
1408
|
-
// get all objects
|
|
1408
|
+
// get all objects that have a custom attribute
|
|
1409
1409
|
const res = await this.objects.getObjectViewAsync('system', 'custom', {
|
|
1410
1410
|
startkey: '',
|
|
1411
1411
|
endkey: '\u9999'
|
|
@@ -1437,7 +1437,7 @@ export class Install {
|
|
|
1437
1437
|
* @param name package name
|
|
1438
1438
|
*/
|
|
1439
1439
|
async installAdapterFromUrl(url, name) {
|
|
1440
|
-
// If the user provided
|
|
1440
|
+
// If the user provided a URL, try to parse it into known ways to represent a GitHub URL
|
|
1441
1441
|
let parsedUrl;
|
|
1442
1442
|
try {
|
|
1443
1443
|
parsedUrl = new URL(url);
|
|
@@ -1459,7 +1459,7 @@ export class Install {
|
|
|
1459
1459
|
const result = await axios(`http://api.github.com/repos/${user}/${repo}/commits`, {
|
|
1460
1460
|
headers: {
|
|
1461
1461
|
'User-Agent': 'ioBroker Adapter install',
|
|
1462
|
-
// @ts-expect-error should be okay
|
|
1462
|
+
// @ts-expect-error should be okay...
|
|
1463
1463
|
validateStatus: status => status === 200
|
|
1464
1464
|
}
|
|
1465
1465
|
});
|
|
@@ -1485,7 +1485,7 @@ export class Install {
|
|
|
1485
1485
|
console.log(`install ${url}`);
|
|
1486
1486
|
// Try to extract name from URL
|
|
1487
1487
|
if (!name) {
|
|
1488
|
-
const reNpmPacket = new RegExp(
|
|
1488
|
+
const reNpmPacket = new RegExp(`^${tools.appName}\\.([-_\\w\\d]+)(@.*)?$`, 'i');
|
|
1489
1489
|
const match = reNpmPacket.exec(url); // we have iobroker.adaptername@1.2.3
|
|
1490
1490
|
if (match) {
|
|
1491
1491
|
name = match[1];
|
|
@@ -1493,7 +1493,7 @@ export class Install {
|
|
|
1493
1493
|
else if (url.match(/\.(tgz|gz|zip|tar\.gz)$/)) {
|
|
1494
1494
|
const parts = url.split('/');
|
|
1495
1495
|
const last = parts.pop();
|
|
1496
|
-
const mm = last.match(/\.([-_\w
|
|
1496
|
+
const mm = last.match(/\.([-_\w]+)-[.\d]+/);
|
|
1497
1497
|
if (mm) {
|
|
1498
1498
|
name = mm[1];
|
|
1499
1499
|
}
|
|
@@ -1509,7 +1509,7 @@ export class Install {
|
|
|
1509
1509
|
name = url;
|
|
1510
1510
|
}
|
|
1511
1511
|
// Remove the leading `iobroker.` from the name
|
|
1512
|
-
const reG = new RegExp(tools.appName
|
|
1512
|
+
const reG = new RegExp(`${tools.appName}\\.([-_\\w\\d]+)$`, 'i');
|
|
1513
1513
|
const match = reG.exec(name);
|
|
1514
1514
|
if (match) {
|
|
1515
1515
|
name = match[1];
|
|
@@ -1570,7 +1570,7 @@ export class Install {
|
|
|
1570
1570
|
*
|
|
1571
1571
|
* @param adapter adapter name
|
|
1572
1572
|
* @param instance instance, like 1
|
|
1573
|
-
* @returns if dependent exists returns adapter name
|
|
1573
|
+
* @returns if dependent exists, returns adapter name
|
|
1574
1574
|
*/
|
|
1575
1575
|
async _hasDependentInstances(adapter, instance) {
|
|
1576
1576
|
try {
|
|
@@ -1590,7 +1590,7 @@ export class Install {
|
|
|
1590
1590
|
scopedHostname = scopedHostname || hostname;
|
|
1591
1591
|
for (const row of doc.rows) {
|
|
1592
1592
|
if (!row.value?.common) {
|
|
1593
|
-
// this object seems to be corrupted so it will not need our adapter
|
|
1593
|
+
// this object seems to be corrupted, so it will not need our adapter
|
|
1594
1594
|
continue;
|
|
1595
1595
|
}
|
|
1596
1596
|
const localDeps = tools.parseDependencies(row.value.common.dependencies);
|
|
@@ -1601,7 +1601,7 @@ export class Install {
|
|
|
1601
1601
|
return `${row.value.common.name}.${row.id.split('.').pop()}`;
|
|
1602
1602
|
}
|
|
1603
1603
|
else {
|
|
1604
|
-
// check if
|
|
1604
|
+
// check if another instance of us exists on this host
|
|
1605
1605
|
if (this._checkDependencyFulfilledThisHost(adapter, instance, doc.rows, scopedHostname)) {
|
|
1606
1606
|
// there are other instances of our adapter - ok
|
|
1607
1607
|
break;
|
|
@@ -1616,7 +1616,7 @@ export class Install {
|
|
|
1616
1616
|
for (const globalDep of Object.keys(globalDeps)) {
|
|
1617
1617
|
if (globalDep === adapter) {
|
|
1618
1618
|
if (instance === undefined) {
|
|
1619
|
-
// all instances on this host should be removed so check if there are some on other hosts
|
|
1619
|
+
// all instances on this host should be removed, so check if there are some on other hosts
|
|
1620
1620
|
if (this._checkDependencyFulfilledForeignHosts(adapter, doc.rows, scopedHostname)) {
|
|
1621
1621
|
break;
|
|
1622
1622
|
}
|
|
@@ -1646,7 +1646,7 @@ export class Install {
|
|
|
1646
1646
|
* @param adapter adapter name
|
|
1647
1647
|
* @param instancesRows all instances objects view rows
|
|
1648
1648
|
* @param scopedHostname hostname which should be assumed as local
|
|
1649
|
-
* @returns true if an instance is present on
|
|
1649
|
+
* @returns true if an instance is present on another host
|
|
1650
1650
|
*/
|
|
1651
1651
|
_checkDependencyFulfilledForeignHosts(adapter, instancesRows, scopedHostname) {
|
|
1652
1652
|
for (const row of instancesRows) {
|