import execa from 'execa' ; import { Meta , debug } from '@vercel/build-utils' ; const makeDependencyCheckCode = ( dependency ) => `
from importlib import util
dep = '${ dependency }'.replace('-', '_')
spec = util.find_spec(dep)
print(spec.origin)
` ; async function isInstalled ( pythonPath , dependency , cwd ) { try { const { stdout } = await execa ( pythonPath , [ '-c' , makeDependencyCheckCode ( dependency ) ] , { stdio : 'pipe' , cwd , } ) ; return stdout . startsWith ( cwd ) ; } catch ( err ) { return false ; } } const makeRequirementsCheckCode = ( requirementsPath ) => `
import distutils.text_file
import pkg_resources
from pkg_resources import DistributionNotFound, VersionConflict
dependencies = distutils.text_file.TextFile(filename='${ requirementsPath }').readlines()
pkg_resources.require(dependencies)
` ; async function areRequirementsInstalled ( pythonPath , requirementsPath , cwd ) { try { await execa ( pythonPath , [ '-c' , makeRequirementsCheckCode ( requirementsPath ) ] , { stdio : 'pipe' , cwd , } ) ; return true ; } catch ( err ) { return false ; } } async function pipInstall ( pipPath , workPath , args ) { const target = '.' ; process . env . PIP_USER = '0' ; const cmdArgs = [ 'install' , '--disable-pip-version-check' , '--target' , target , ... args , ] ; const pretty = `${ pipPath } ${ cmdArgs . join ( ' ' ) }` ; debug ( `Running "${ pretty }"...` ) ; try { await execa ( pipPath , cmdArgs , { cwd : workPath , } ) ; } catch ( err ) { console . log ( `Failed to run "${ pretty }"` ) ; throw err ; } } interface InstallRequirementArg { pythonPath : string ; pipPath : string ; dependency : string ; version : string ; workPath : string ; meta : Meta ; args ? : string [ ] ; } export async function installRequirement ( { pythonPath , pipPath , dependency , version , workPath , meta , args = [ ] , } ) { if ( meta . isDev && ( await isInstalled ( pythonPath , dependency , workPath ) ) ) { debug ( `Skipping ${ dependency } dependency installation, already installed in ${ workPath }` ) ; return ; } const exact = `${ dependency }==${ version }` ; await pipInstall ( pipPath , workPath , [ exact , ... args ] ) ; } interface InstallRequirementsFileArg { pythonPath : string ; pipPath : string ; filePath : string ; workPath : string ; meta : Meta ; args ? : string [ ] ; } export async function installRequirementsFile ( { pythonPath , pipPath , filePath , workPath , meta , args = [ ] , } ) { if ( meta . isDev && ( await areRequirementsInstalled ( pythonPath , filePath , workPath ) ) ) { debug ( `Skipping requirements file installation, already installed` ) ; return ; } await pipInstall ( pipPath , workPath , [ '--upgrade' , '-r' , filePath , ... args ] ) ; }