import { quote } from 'shlex' ; import { TEMPORARY_ERROR } from '../../constants/error-messages' ; import { logger } from '../../logger' ; import { exec } from '../../util/exec' ; import type { ExecOptions } from '../../util/exec/types' ; import { deleteLocalFile , ensureCacheDir , readLocalFile , writeLocalFile , } from '../../util/fs' ; import { getRepoStatus } from '../../util/git' ; import type { UpdateArtifact , UpdateArtifactsConfig , UpdateArtifactsResult , } from '../types' ; function getPythonConstraint ( existingLockFileContent , config ) { const { constraints = { } } = config ; const { python } = constraints ; if ( python ) { logger . debug ( 'Using python constraint from config' ) ; return python ; } try { const pipfileLock = JSON . parse ( existingLockFileContent ) ; if ( pipfileLock ?. _meta ?. requires ?. python_version ) { const pythonVersion = pipfileLock . _meta . requires . python_version ; return `== ${ pythonVersion }.*` ; } if ( pipfileLock ?. _meta ?. requires ?. python_full_version ) { const pythonFullVersion = pipfileLock . _meta . requires . python_full_version ; return `== ${ pythonFullVersion }` ; } } catch ( err ) { } return undefined ; } function getPipenvConstraint ( existingLockFileContent , config ) { const { constraints = { } } = config ; const { pipenv } = constraints ; if ( pipenv ) { logger . debug ( 'Using pipenv constraint from config' ) ; return pipenv ; } try { const pipfileLock = JSON . parse ( existingLockFileContent ) ; if ( pipfileLock ?. default ?. pipenv ?. version ) { const pipenvVersion = pipfileLock . default . pipenv . version ; return pipenvVersion ; } if ( pipfileLock ?. develop ?. pipenv ?. version ) { const pipenvVersion = pipfileLock . develop . pipenv . version ; return pipenvVersion ; } } catch ( err ) { } return '' ; } export async function updateArtifacts ( { packageFileName : pipfileName , newPackageFileContent : newPipfileContent , config , } ) { logger . debug ( `pipenv.updateArtifacts(${ pipfileName })` ) ; const lockFileName = pipfileName + '.lock' ; const existingLockFileContent = await readLocalFile ( lockFileName , 'utf8' ) ; if ( ! existingLockFileContent ) { logger . debug ( 'No Pipfile.lock found' ) ; return null ; } try { await writeLocalFile ( pipfileName , newPipfileContent ) ; if ( config . isLockFileMaintenance ) { await deleteLocalFile ( lockFileName ) ; } const cmd = 'pipenv lock' ; const tagConstraint = getPythonConstraint ( existingLockFileContent , config ) ; const pipenvConstraint = getPipenvConstraint ( existingLockFileContent , config ) ; const execOptions = { cwdFile : pipfileName , extraEnv : { PIPENV_CACHE_DIR : await ensureCacheDir ( 'pipenv' ) , } , docker : { image : 'python' , tagConstraint , tagScheme : 'pep440' , } , preCommands : [ `pip install --user ${ quote ( `pipenv${ pipenvConstraint }` ) }` ] , } ; logger . debug ( { cmd } , 'pipenv lock command' ) ; await exec ( cmd , execOptions ) ; const status = await getRepoStatus ( ) ; if ( ! status ?. modified . includes ( lockFileName ) ) { return null ; } logger . debug ( 'Returning updated Pipfile.lock' ) ; return [ { file : { name : lockFileName , contents : await readLocalFile ( lockFileName , 'utf8' ) , } , } , ] ; } catch ( err ) { if ( err . message === TEMPORARY_ERROR ) { throw err ; } logger . debug ( { err } , 'Failed to update Pipfile.lock' ) ; return [ { artifactError : { lockFile : lockFileName , stderr : err . message , } , } , ] ; } }