1- import { UsageError } from 'clipanion' ;
2- import fs from 'fs' ;
3- import path from 'path' ;
4- import semverSatisfies from 'semver/functions/satisfies' ;
5- import semverValid from 'semver/functions/valid' ;
6- import semverValidRange from 'semver/ranges/valid' ;
7-
8- import { PreparedPackageManagerInfo } from './Engine' ;
9- import * as debugUtils from './debugUtils' ;
10- import { NodeError } from './nodeUtils' ;
11- import * as nodeUtils from './nodeUtils' ;
12- import { Descriptor , isSupportedPackageManager } from './types' ;
1+ import { UsageError } from 'clipanion' ;
2+ import fs from 'fs' ;
3+ import path from 'path' ;
4+ import semverSatisfies from 'semver/functions/satisfies' ;
5+ import semverValid from 'semver/functions/valid' ;
6+ import semverValidRange from 'semver/ranges/valid' ;
7+ import { parseEnv } from 'util' ;
8+
9+ import type { PreparedPackageManagerInfo } from './Engine' ;
10+ import * as debugUtils from './debugUtils' ;
11+ import type { NodeError } from './nodeUtils' ;
12+ import * as nodeUtils from './nodeUtils' ;
13+ import { isSupportedPackageManager } from './types' ;
14+ import type { LocalEnvFile , Descriptor } from './types' ;
1315
1416const nodeModulesRegExp = / [ \\ / ] n o d e _ m o d u l e s [ \\ / ] ( @ [ ^ \\ / ] * [ \\ / ] ) ? ( [ ^ @ \\ / ] [ ^ \\ / ] * ) $ / ;
1517
@@ -138,10 +140,11 @@ export async function setLocalPackageManager(cwd: string, info: PreparedPackageM
138140 } ;
139141}
140142
143+ type FoundSpecResult = { type : `Found`, target : string , spec : Descriptor , range ?: Descriptor , envFilePath ?: string } ;
141144export type LoadSpecResult =
142145 | { type : `NoProject`, target : string }
143146 | { type : `NoSpec`, target : string }
144- | { type : `Found` , target : string , spec : Descriptor , range ?: Descriptor } ;
147+ | FoundSpecResult ;
145148
146149export async function loadSpec ( initialCwd : string ) : Promise < LoadSpecResult > {
147150 let nextCwd = initialCwd ;
@@ -150,6 +153,8 @@ export async function loadSpec(initialCwd: string): Promise<LoadSpecResult> {
150153 let selection : {
151154 data : any ;
152155 manifestPath : string ;
156+ envFilePath ?: string ;
157+ localEnv : LocalEnvFile ;
153158 } | null = null ;
154159
155160 while ( nextCwd !== currCwd && ( ! selection || ! selection . data . packageManager ) ) {
@@ -177,23 +182,55 @@ export async function loadSpec(initialCwd: string): Promise<LoadSpecResult> {
177182 if ( typeof data !== `object` || data === null )
178183 throw new UsageError ( `Invalid package.json in ${ path . relative ( initialCwd , manifestPath ) } ` ) ;
179184
180- selection = { data, manifestPath} ;
185+ let localEnv : LocalEnvFile ;
186+ const envFilePath = path . resolve ( currCwd , process . env . COREPACK_ENV_FILE ?? `.corepack.env` ) ;
187+ if ( process . env . COREPACK_ENV_FILE == `0` ) {
188+ debugUtils . log ( `Skipping env file as configured with COREPACK_ENV_FILE` ) ;
189+ localEnv = process . env ;
190+ } else if ( typeof parseEnv !== `function` ) {
191+ // TODO: remove this block when support for Node.js 18.x is dropped.
192+ debugUtils . log ( `Skipping env file as it is not supported by the current version of Node.js` ) ;
193+ localEnv = process . env ;
194+ } else {
195+ debugUtils . log ( `Checking ${ envFilePath } ` ) ;
196+ try {
197+ localEnv = {
198+ ...Object . fromEntries ( Object . entries ( parseEnv ( await fs . promises . readFile ( envFilePath , `utf8` ) ) ) . filter ( e => e [ 0 ] . startsWith ( `COREPACK_` ) ) ) ,
199+ ...process . env ,
200+ } ;
201+ debugUtils . log ( `Successfully loaded env file found at ${ envFilePath } ` ) ;
202+ } catch ( err ) {
203+ if ( ( err as NodeError ) ?. code !== `ENOENT` )
204+ throw err ;
205+
206+ debugUtils . log ( `No env file found at ${ envFilePath } ` ) ;
207+ localEnv = process . env ;
208+ }
209+ }
210+
211+ selection = { data, manifestPath, localEnv, envFilePath} ;
181212 }
182213
183214 if ( selection === null )
184215 return { type : `NoProject` , target : path . join ( initialCwd , `package.json` ) } ;
185216
217+ let envFilePath : string | undefined ;
218+ if ( selection . localEnv !== process . env ) {
219+ envFilePath = selection . envFilePath ;
220+ process . env = selection . localEnv ;
221+ }
222+
186223 const rawPmSpec = parsePackageJSON ( selection . data ) ;
187224 if ( typeof rawPmSpec === `undefined` )
188225 return { type : `NoSpec` , target : selection . manifestPath } ;
189226
190227 debugUtils . log ( `${ selection . manifestPath } defines ${ rawPmSpec } as local package manager` ) ;
191228
192- const spec = parseSpec ( rawPmSpec , path . relative ( initialCwd , selection . manifestPath ) ) ;
193229 return {
194230 type : `Found` ,
195231 target : selection . manifestPath ,
196- spec,
232+ envFilePath,
233+ spec : parseSpec ( rawPmSpec , path . relative ( initialCwd , selection . manifestPath ) ) ,
197234 range : selection . data . devEngines ?. packageManager ?. version && {
198235 name : selection . data . devEngines . packageManager . name ,
199236 range : selection . data . devEngines . packageManager . version ,
0 commit comments