@foxpage/foxpage-manager
Version:
foxpage resource manager
391 lines (390 loc) • 13.6 kB
JavaScript
"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;