From 6cde6b955d106057360d5eb60875e0da657e69d5 Mon Sep 17 00:00:00 2001 From: Gilad Shoham Date: Wed, 14 Jun 2023 16:51:21 +0300 Subject: [PATCH] feature(capsules) - support setting exact folder for scope aspects capsule base dir (#7531) --- .../isolator/isolator.main.runtime.ts | 14 +++++--- scopes/scope/scope/scope-aspects-loader.ts | 27 +++++++++++++-- scopes/scope/scope/scope.main.runtime.ts | 33 ++++++++++++++++--- scopes/workspace/workspace/capsule.cmd.ts | 6 +++- src/constants.ts | 10 ++++++ 5 files changed, 77 insertions(+), 13 deletions(-) diff --git a/scopes/component/isolator/isolator.main.runtime.ts b/scopes/component/isolator/isolator.main.runtime.ts index e839e1249ab9..e6c4568e096c 100644 --- a/scopes/component/isolator/isolator.main.runtime.ts +++ b/scopes/component/isolator/isolator.main.runtime.ts @@ -112,6 +112,11 @@ export type IsolateComponentsOptions = CreateGraphOptions & { */ baseDir?: string; + /** + * Whether to use hash function (of base dir) as capsules root dir name + */ + useHash?: boolean; + /** * create a new capsule with a random string attached to the path suffix */ @@ -247,7 +252,7 @@ export class IsolatorMain { }); opts.baseDir = opts.baseDir || host.path; const capsuleList = await this.createCapsules(componentsToIsolate, opts, legacyScope); - const capsuleDir = this.getCapsulesRootDir(opts.baseDir, opts.rootBaseDir); + const capsuleDir = this.getCapsulesRootDir(opts.baseDir, opts.rootBaseDir, opts.useHash); this.logger.debug( `creating network with base dir: ${opts.baseDir}, rootBaseDir: ${opts.rootBaseDir}. final capsule-dir: ${capsuleDir}. capsuleList: ${capsuleList.length}` ); @@ -305,7 +310,7 @@ export class IsolatorMain { legacyScope?: Scope ): Promise { this.logger.debug(`createCapsules, ${components.length} components`); - const capsulesDir = this.getCapsulesRootDir(opts.baseDir as string, opts.rootBaseDir); + const capsulesDir = this.getCapsulesRootDir(opts.baseDir as string, opts.rootBaseDir, opts.useHash); let longProcessLogger; if (opts.context?.aspects) { @@ -594,9 +599,10 @@ export class IsolatorMain { } } - getCapsulesRootDir(baseDir: string, rootBaseDir?: string): PathOsBasedAbsolute { + getCapsulesRootDir(baseDir: string, rootBaseDir?: string, useHash = true): PathOsBasedAbsolute { const capsulesRootBaseDir = rootBaseDir || this.getRootDirOfAllCapsules(); - return path.join(capsulesRootBaseDir, hash(baseDir)); + const dir = useHash ? hash(baseDir) : baseDir; + return path.join(capsulesRootBaseDir, dir); } async deleteCapsules(capsuleBaseDir: string | null): Promise { diff --git a/scopes/scope/scope/scope-aspects-loader.ts b/scopes/scope/scope/scope-aspects-loader.ts index 3f838ecb5b3f..a523b86b4267 100644 --- a/scopes/scope/scope/scope-aspects-loader.ts +++ b/scopes/scope/scope/scope-aspects-loader.ts @@ -1,8 +1,13 @@ +import { GlobalConfigMain } from '@teambit/global-config'; import mapSeries from 'p-map-series'; import { Lane } from '@teambit/legacy/dist/scope/models'; import { readdirSync, existsSync } from 'fs-extra'; import { resolve, join } from 'path'; -import { DEFAULT_DIST_DIRNAME } from '@teambit/legacy/dist/constants'; +import { + DEFAULT_DIST_DIRNAME, + CFG_CAPSULES_SCOPES_ASPECTS_BASE_DIR, + CFG_CAPSULES_GLOBAL_SCOPE_ASPECTS_BASE_DIR, +} from '@teambit/legacy/dist/constants'; import { Compiler } from '@teambit/compiler'; import { Capsule, IsolatorMain } from '@teambit/isolator'; import { AspectLoaderMain, AspectDefinition } from '@teambit/aspect-loader'; @@ -31,7 +36,8 @@ export class ScopeAspectsLoader { private aspectLoader: AspectLoaderMain, private envs: EnvsMain, private isolator: IsolatorMain, - private logger: Logger + private logger: Logger, + private globalConfig: GlobalConfigMain ) {} private parseLocalAspect(localAspects: string[]) { const dirPaths = localAspects.map((localAspect) => resolve(localAspect.replace('file://', ''))); @@ -234,11 +240,13 @@ needed-for: ${neededFor || ''}`); opts?: { skipIfExists?: boolean; packageManagerConfigRootDir?: string; workspaceName?: string } ): Promise { if (!components || !components.length) return []; + const useHash = this.shouldUseHashForCapsules(); const network = await this.isolator.isolateComponents( components.map((c) => c.id), // includeFromNestedHosts - to support case when you are in a workspace, trying to load aspect defined in the workspace.jsonc but not part of the workspace { baseDir: this.getAspectCapsulePath(), + useHash, skipIfExists: opts?.skipIfExists ?? true, seedersOnly: true, includeFromNestedHosts: true, @@ -384,7 +392,18 @@ needed-for: ${neededFor || ''}`); } getAspectCapsulePath() { - return `${this.scope.path}-aspects`; + const defaultPath = `${this.scope.path}-aspects`; + if (this.scope.isGlobalScope) { + return this.globalConfig.getSync(CFG_CAPSULES_GLOBAL_SCOPE_ASPECTS_BASE_DIR) || defaultPath; + } + return this.globalConfig.getSync(CFG_CAPSULES_SCOPES_ASPECTS_BASE_DIR) || defaultPath; + } + + shouldUseHashForCapsules(): boolean { + if (this.scope.isGlobalScope) { + return !this.globalConfig.getSync(CFG_CAPSULES_GLOBAL_SCOPE_ASPECTS_BASE_DIR); + } + return !this.globalConfig.getSync(CFG_CAPSULES_SCOPES_ASPECTS_BASE_DIR); } private async resolveUserAspects( @@ -394,10 +413,12 @@ needed-for: ${neededFor || ''}`); ): Promise { if (!userAspectsIds || !userAspectsIds.length) return []; const components = await this.scope.getMany(userAspectsIds); + const useHash = this.shouldUseHashForCapsules(); const network = await this.isolator.isolateComponents( userAspectsIds, { baseDir: this.getAspectCapsulePath(), + useHash, skipIfExists: true, // for some reason this needs to be false, otherwise tagging components in some workspaces // result in error during Preview task: diff --git a/scopes/scope/scope/scope.main.runtime.ts b/scopes/scope/scope/scope.main.runtime.ts index 6260f3eabefc..dbcb7f8d2976 100644 --- a/scopes/scope/scope/scope.main.runtime.ts +++ b/scopes/scope/scope/scope.main.runtime.ts @@ -1,3 +1,4 @@ +import GlobalConfigAspect, { GlobalConfigMain } from '@teambit/global-config'; import mapSeries from 'p-map-series'; import { Graph, Node, Edge } from '@teambit/graph.cleargraph'; import semver from 'semver'; @@ -49,6 +50,7 @@ import { remove } from '@teambit/legacy/dist/api/scope'; import { BitError } from '@teambit/bit-error'; import ConsumerComponent from '@teambit/legacy/dist/consumer/component'; import { resumeExport } from '@teambit/legacy/dist/scope/component-ops/export-scope-components'; +import { GLOBAL_SCOPE } from '@teambit/legacy/dist/constants'; import { ExtensionDataEntry, ExtensionDataList } from '@teambit/legacy/dist/consumer/config'; import EnvsAspect, { EnvsMain } from '@teambit/envs'; import { compact, slice, difference } from 'lodash'; @@ -129,7 +131,9 @@ export class ScopeMain implements ComponentFactory { private envs: EnvsMain, - private dependencyResolver: DependencyResolverMain + private dependencyResolver: DependencyResolverMain, + + private globalConfig: GlobalConfigMain ) { this.componentLoader = new ScopeComponentLoader(this, this.logger); } @@ -165,6 +169,10 @@ export class ScopeMain implements ComponentFactory { return this.legacyScope.isLegacy; } + get isGlobalScope(): boolean { + return this.path === GLOBAL_SCOPE; + } + // We need to reload the aspects with their new version since: // during get many by legacy, we go load component which in turn go to getEnv // get env validates that the env written on the component is really exist by checking the envs slot registry @@ -240,12 +248,24 @@ export class ScopeMain implements ComponentFactory { return scopeAspectsLoader.getAspectCapsulePath(); } + shouldUseHashForCapsules() { + const scopeAspectsLoader = this.getScopeAspectsLoader(); + return scopeAspectsLoader.shouldUseHashForCapsules(); + } + getManyByLegacy(components: ConsumerComponent[]): Promise { return mapSeries(components, async (component) => this.getFromConsumerComponent(component)); } getScopeAspectsLoader(): ScopeAspectsLoader { - const scopeAspectsLoader = new ScopeAspectsLoader(this, this.aspectLoader, this.envs, this.isolator, this.logger); + const scopeAspectsLoader = new ScopeAspectsLoader( + this, + this.aspectLoader, + this.envs, + this.isolator, + this.logger, + this.globalConfig + ); return scopeAspectsLoader; } @@ -898,6 +918,7 @@ export class ScopeMain implements ComponentFactory { LoggerAspect, EnvsAspect, DependencyResolverAspect, + GlobalConfigAspect, ]; static defaultConfig: ScopeConfig = { @@ -905,7 +926,7 @@ export class ScopeMain implements ComponentFactory { }; static async provider( - [componentExt, ui, graphql, cli, isolator, aspectLoader, express, loggerMain, envs, depsResolver]: [ + [componentExt, ui, graphql, cli, isolator, aspectLoader, express, loggerMain, envs, depsResolver, globalConfig]: [ ComponentMain, UiMain, GraphqlMain, @@ -915,7 +936,8 @@ export class ScopeMain implements ComponentFactory { ExpressMain, LoggerMain, EnvsMain, - DependencyResolverMain + DependencyResolverMain, + GlobalConfigMain ], config: ScopeConfig, [postPutSlot, postDeleteSlot, postExportSlot, postObjectsPersistSlot, preFetchObjectsSlot]: [ @@ -948,7 +970,8 @@ export class ScopeMain implements ComponentFactory { aspectLoader, logger, envs, - depsResolver + depsResolver, + globalConfig ); cli.registerOnStart(async (hasWorkspace: boolean) => { if (hasWorkspace) return; diff --git a/scopes/workspace/workspace/capsule.cmd.ts b/scopes/workspace/workspace/capsule.cmd.ts index c41e356cdb8b..4256f4a87c74 100644 --- a/scopes/workspace/workspace/capsule.cmd.ts +++ b/scopes/workspace/workspace/capsule.cmd.ts @@ -107,7 +107,11 @@ use --json to get the list of all workspace capsules`); private getCapsulesRootDirs() { const workspaceCapsulesRootDir = this.isolator.getCapsulesRootDir(this.workspace.path); - const scopeAspectsCapsulesRootDir = this.isolator.getCapsulesRootDir(this.workspace.scope.getAspectCapsulePath()); + const scopeAspectsCapsulesRootDir = this.isolator.getCapsulesRootDir( + this.workspace.scope.getAspectCapsulePath(), + undefined, + this.workspace.scope.shouldUseHashForCapsules() + ); return { workspaceCapsulesRootDir, scopeAspectsCapsulesRootDir }; } diff --git a/src/constants.ts b/src/constants.ts index 270bcbc42a88..4fca5e522f4d 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -336,6 +336,16 @@ export const CFG_FEATURE_TOGGLE = 'features'; export const CFG_PACKAGE_MANAGER_CACHE = 'package-manager.cache'; export const CFG_CAPSULES_ROOT_BASE_DIR = 'capsules_root_base_dir'; +/** + * Name of the directory where the capsules for aspects for regular scope are stored + * This directory is relative to the capsules root directory + */ +export const CFG_CAPSULES_SCOPES_ASPECTS_BASE_DIR = 'capsules_scopes_aspects_base_dir'; +/** + * Name of the directory where the capsules for aspects for the global scope are stored + * This directory is relative to the capsules root directory + */ +export const CFG_CAPSULES_GLOBAL_SCOPE_ASPECTS_BASE_DIR = 'capsules_global_scope_aspects_base_dir'; export const CFG_DEFAULT_RESOLVE_ENVS_FROM_ROOTS = 'default_resolve_envs_from_roots';