@@ -4,12 +4,14 @@ import path from 'path';
44import semverSatisfies from 'semver/functions/satisfies' ;
55import semverValid from 'semver/functions/valid' ;
66import semverValidRange from 'semver/ranges/valid' ;
7+ import { parseEnv } from 'util' ;
78
89import { PreparedPackageManagerInfo } from './Engine' ;
910import * as debugUtils from './debugUtils' ;
1011import { NodeError } from './nodeUtils' ;
1112import * as nodeUtils from './nodeUtils' ;
1213import { Descriptor , isSupportedPackageManager } from './types' ;
14+ import type { LocalEnvFile } from './types' ;
1315
1416const nodeModulesRegExp = / [ \\ / ] n o d e _ m o d u l e s [ \\ / ] ( @ [ ^ \\ / ] * [ \\ / ] ) ? ( [ ^ @ \\ / ] [ ^ \\ / ] * ) $ / ;
1517
@@ -145,10 +147,17 @@ export async function setLocalPackageManager(cwd: string, info: PreparedPackageM
145147 } ;
146148}
147149
150+ interface FoundSpecResult {
151+ type : `Found`;
152+ target : string ;
153+ getSpec : ( ) => Descriptor ;
154+ range ?: Descriptor & { onFail ?: DevEngineDependency [ 'onFail' ] } ;
155+ envFilePath ?: string ;
156+ }
148157export type LoadSpecResult =
149158 | { type : `NoProject`, target : string }
150159 | { type : `NoSpec`, target : string }
151- | { type : `Found` , target : string , getSpec : ( ) => Descriptor , range ?: Descriptor & { onFail ?: DevEngineDependency [ 'onFail' ] } } ;
160+ | FoundSpecResult ;
152161
153162export async function loadSpec ( initialCwd : string ) : Promise < LoadSpecResult > {
154163 let nextCwd = initialCwd ;
@@ -157,6 +166,8 @@ export async function loadSpec(initialCwd: string): Promise<LoadSpecResult> {
157166 let selection : {
158167 data : any ;
159168 manifestPath : string ;
169+ envFilePath ?: string ;
170+ localEnv : LocalEnvFile ;
160171 } | null = null ;
161172
162173 while ( nextCwd !== currCwd && ( ! selection || ! selection . data . packageManager ) ) {
@@ -184,12 +195,44 @@ export async function loadSpec(initialCwd: string): Promise<LoadSpecResult> {
184195 if ( typeof data !== `object` || data === null )
185196 throw new UsageError ( `Invalid package.json in ${ path . relative ( initialCwd , manifestPath ) } ` ) ;
186197
187- selection = { data, manifestPath} ;
198+ let localEnv : LocalEnvFile ;
199+ const envFilePath = path . resolve ( currCwd , process . env . COREPACK_ENV_FILE ?? `.corepack.env` ) ;
200+ if ( process . env . COREPACK_ENV_FILE == `0` ) {
201+ debugUtils . log ( `Skipping env file as configured with COREPACK_ENV_FILE` ) ;
202+ localEnv = process . env ;
203+ } else if ( typeof parseEnv !== `function` ) {
204+ // TODO: remove this block when support for Node.js 18.x is dropped.
205+ debugUtils . log ( `Skipping env file as it is not supported by the current version of Node.js` ) ;
206+ localEnv = process . env ;
207+ } else {
208+ debugUtils . log ( `Checking ${ envFilePath } ` ) ;
209+ try {
210+ localEnv = {
211+ ...Object . fromEntries ( Object . entries ( parseEnv ( await fs . promises . readFile ( envFilePath , `utf8` ) ) ) . filter ( e => e [ 0 ] . startsWith ( `COREPACK_` ) ) ) ,
212+ ...process . env ,
213+ } ;
214+ debugUtils . log ( `Successfully loaded env file found at ${ envFilePath } ` ) ;
215+ } catch ( err ) {
216+ if ( ( err as NodeError ) ?. code !== `ENOENT` )
217+ throw err ;
218+
219+ debugUtils . log ( `No env file found at ${ envFilePath } ` ) ;
220+ localEnv = process . env ;
221+ }
222+ }
223+
224+ selection = { data, manifestPath, localEnv, envFilePath} ;
188225 }
189226
190227 if ( selection === null )
191228 return { type : `NoProject` , target : path . join ( initialCwd , `package.json` ) } ;
192229
230+ let envFilePath : string | undefined ;
231+ if ( selection . localEnv !== process . env ) {
232+ envFilePath = selection . envFilePath ;
233+ process . env = selection . localEnv ;
234+ }
235+
193236 const rawPmSpec = parsePackageJSON ( selection . data ) ;
194237 if ( typeof rawPmSpec === `undefined` )
195238 return { type : `NoSpec` , target : selection . manifestPath } ;
@@ -199,6 +242,7 @@ export async function loadSpec(initialCwd: string): Promise<LoadSpecResult> {
199242 return {
200243 type : `Found` ,
201244 target : selection . manifestPath ,
245+ envFilePath,
202246 range : selection . data . devEngines ?. packageManager ?. version && {
203247 name : selection . data . devEngines . packageManager . name ,
204248 range : selection . data . devEngines . packageManager . version ,
0 commit comments