UNPKG

@foxpage/foxpage-manager

Version:

foxpage resource manager

391 lines (390 loc) 13.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PackageManagerImpl = void 0; const foxpage_shared_1 = require("@foxpage/foxpage-shared"); const common_1 = require("../common"); const data_service_1 = require("../data-service"); const package_1 = require("./package"); /** * package manager * component * * @export * @class PackageManager */ class PackageManagerImpl extends common_1.ManagerBaseImpl { constructor(app) { super(app, { type: 'component', diskCache: { enable: true }, lruCache: { cloned: false } }); /** * cache package name & versions * key: package name, value: version list * @private */ this.packageVersionsMap = new Map(); /** * package id map * key: package id, value: package name * * @private */ this.packageIdMap = new Map(); this.generateKey = (name, version) => { return foxpage_shared_1.packager.generateKey(name, version); }; this.splitKey = (key) => { return foxpage_shared_1.packager.splitKey(key); }; this.resourceConfig = app.resourceMap; this.config = app.configs.package || {}; } /** * add package to manager * * @param {Package} pkg */ addPackage(pkg) { const { id, name, version } = pkg; this.logger.info(`add component ${name}@${version}`); if (!version) { this.logger.warn('component version is invalid'); return null; } const newPkg = this.newPackage(pkg); this.addOne(newPkg.key, pkg, newPkg); this.updatePackageVersionsMap(pkg); this.updatePackageLiveVersion(pkg); this.packageIdMap.set(id, name); return newPkg; } /** * remove package from manager via package names * * @param {string[]} names package names */ removePackages(names) { const versionInfo = this.getPackageVersionsByNames(names); Object.keys(versionInfo).forEach(name => { var _a; const versions = versionInfo[name]; if (versions) { this.remove(versions.map(item => this.generateKey(name, item))); } const packageId = (_a = this.packageVersionsMap.get(name)) === null || _a === void 0 ? void 0 : _a.id; if (packageId) { this.packageIdMap.delete(packageId); } this.packageVersionsMap.delete(name); }); } /** * get package by package name * will return the live versions * @param {string} type * @return {*} {Package | undefined} */ async getPackage(name) { return (await this.getPackages([name]))[0]; } /** * get package count * @returns count */ getPackageCount() { return this.packageIdMap.size; } /** * get all packages by package names * will return the live versions * @param {string[]} names * @return {*} {Promise<Package[]>} */ async getPackages(names) { const keys = names.map(name => { const liveVersion = this.getPackageLiveVersion(name); return this.generateKey(name, liveVersion || ''); }); return await this.find(keys); } /** * select one version * * @param {string} name package name * @return {*} */ getPackageLiveVersion(name) { var _a; return (_a = this.packageVersionsMap.get(name)) === null || _a === void 0 ? void 0 : _a.liveVersion; } /** * update package live version * * @param {string} pkg package content */ updatePackageLiveVersion(pkg) { if (pkg.isLive) { const pkgInfo = this.packageVersionsMap.get(pkg.name); if (pkgInfo) { pkgInfo.liveVersion = pkg.version; } } } /** * get package sync from hot * @param name package name * @param version package version * @returns pkg */ getPackageSync(name, version) { const versions = this.getPackageVersionsByNames([name])[name]; if (!versions) { return null; } if (version && versions.indexOf(version) === -1) { this.logger.warn(`get local component: ${name}@${version} is empty.`); return null; } // !version use live version, or use appoint version let curVersion = this.getPackageLiveVersion(name); if (version && version !== curVersion) { this.logger.info(`component ${name} local live version is: ${curVersion}, appoint version is: ${version}`); curVersion = version; } if (!curVersion) { this.logger.warn(`component ${name} version is invalid`); return null; } const key = this.generateKey(name, curVersion); const pkg = this.findOne(key); if (!pkg || pkg.version !== curVersion) { this.logger.warn(`get local component: ${key} is empty.`); return null; } // this.logger.info(`get local package: ${key} succeed.`); return pkg; } /** * get local package * * @param {string} name package name * @param {string} version package version * @return {*} {(Package | null)} */ async getLocalPackage(name, version) { const versions = this.getPackageVersionsByNames([name])[name]; if (!versions) { return null; } if (version && versions.indexOf(version) === -1) { this.logger.warn(`get local package: ${name}@${version} is empty.`); return null; } // !version use live version, or use appoint version let curVersion = this.getPackageLiveVersion(name); if (version && version !== curVersion) { this.logger.info(`component ${name} local live version is: ${curVersion}, appoint version is: ${version}`); curVersion = version; } if (!curVersion) { this.logger.warn(`component ${name} version is invalid`); return null; } const key = this.generateKey(name, curVersion); const pkg = await this.findOneFromLocal(key); if (!pkg || pkg.version !== curVersion) { this.logger.warn(`get local component: ${key} is empty.`); return null; } // this.logger.info(`get local package: ${key} succeed.`); return pkg; } /** * fetch packages, instance packages and install packages then add to local * note: return contains package dependencies contents * @param {PackageFreshOption} [params] * @return {*} */ async freshPackages(params) { const packages = (params === null || params === void 0 ? void 0 : params.namedVersions) ? this.resolvePackage(await this.fetchPackagesByNamedVersions(params.namedVersions)) : await this.fetchPackages(params === null || params === void 0 ? void 0 : params.packageIds, { strategy: params === null || params === void 0 ? void 0 : params.strategy }); return await this.install(packages, { cache: true }); } /** * install packages * * @param {FPPackage[]} packages * @param {{ cache: boolean; ignoreLocal:boolean }} [opt] {cache: will add package instance to manager} * @return {*} */ async install(packages, opt) { const installs = await this.initInstalls(packages, opt); const tasks = installs.map(async (item) => { await item.install(); return item; }); const result = await Promise.all(tasks); return result; } /** * fetch packages from server * * @param {string[]} [packageIds] * @return {*} */ async fetchPackages(packageIds, opt = {}) { var _a; return await data_service_1.foxpageDataService.fetchPackages(this.appId, Object.assign(Object.assign({ packageIds }, opt), { semver: (_a = this.config) === null || _a === void 0 ? void 0 : _a.version })); } /** * fetch packages with name and version from server * * @param {PackageNamedVersion[]} nameVersions * @param {PackageFreshOption} opt {isCanary,...} * @return {Promise<FPPackageResponse[]>} */ async fetchPackagesByNamedVersions(nameVersions, opt) { var _a; const { isCanary = false, isSemver = true } = opt || {}; return await data_service_1.foxpageDataService.fetchPackagesByNamedVersions(this.appId, { nameVersions, isCanary: isCanary, semver: isSemver ? (_a = this.config) === null || _a === void 0 ? void 0 : _a.version : '', }); } /** * listen the "ON_PULL" event * updates & removes is the package content id list * @protected * @param {ResourceUpdateInfo} data * @return {*} {Promise<void>} */ async onPull(data) { const { updates, removes } = data.component || {}; if (updates && updates.length > 0) { // this.markNeedUpdates(updates); await this.freshPackages({ packageIds: updates }); } if (removes && removes.length > 0) { this.removePackages(removes.map(item => this.packageIdMap.get(item)).filter(foxpage_shared_1.isNotNill)); } } /** * on fetch * list: the manager keys * @protected * @param {string[]} list * @return {*} {Promise<PackageImpl[]>} */ async onFetch(list) { return await this.freshPackages({ namedVersions: list.map(item => { const [name, version] = this.splitKey(item); return { name, version }; }), }); } async createInstance(data) { const instance = this.newPackage(data); await instance.install(); return instance; } newPackage(data) { return new package_1.PackageInstance(data, { appId: this.appId, appSlug: this.appSlug, resource: this.resourceConfig, logger: this.logger, }); } resolvePackage(packageInfos) { return packageInfos.map(item => item.package); } /** * init need install package instances * * @private * @param {FPPackage[]} packages * @param {{ cache: boolean, ignoreLocal:boolean }} [opt] * @return {*} */ async initInstalls(packages, opt) { var _a; const installMap = new Map(); const { cache = false, ignoreLocal = false, reInstall = false } = opt || {}; const create = async (list, { initDependencies } = { initDependencies: false }) => { for (const pkg of list) { const { name, version, components } = pkg; const key = this.generateKey(name, version); const localPkg = !ignoreLocal ? await this.getLocalPackage(name, version) : null; // will install it if (((!localPkg || !localPkg.available) && !installMap.has(key)) || reInstall) { let newPkg; if (cache) { newPkg = await this.addPackage(pkg); } else { newPkg = this.newPackage(pkg); } if (newPkg) { installMap.set(key, newPkg); } } else { if (cache) { this.updatePackageLiveVersion(pkg); } } // init components // components: the dependencies contents if (initDependencies && (components === null || components === void 0 ? void 0 : components.length)) { await create(components); } } }; try { await create(packages, { initDependencies: true }); } catch (e) { (_a = this.logger) === null || _a === void 0 ? void 0 : _a.error(`install packages failed: `, e); } return Array.from(installMap.values()); } /** * get package versions * * @private * @param {string[]} names package names * @return {*} {[key]: package name, [value]: versions} */ getPackageVersionsByNames(names) { const versionInfo = {}; names.forEach(name => { const { versions } = this.packageVersionsMap.get(name) || {}; if (!versions) { // this.logger.warn(`not exist the package@${name} in packageMap`); versionInfo[name] = null; } else { versionInfo[name] = versions; } }); return versionInfo; } updatePackageVersionsMap(pkg) { const { id, name, version } = pkg; const { versions } = this.packageVersionsMap.get(name) || {}; if (versions) { versions.push(version); } else { this.packageVersionsMap.set(name, { id, liveVersion: '', versions: [version] }); this.updatePackageLiveVersion(pkg); } } destroy() { super.destroy(); this.packageIdMap.clear(); this.packageVersionsMap.clear(); } } exports.PackageManagerImpl = PackageManagerImpl;