lib/pip.js
function installRequirementsIfNeeded(
  servicePath,
  modulePath,
  options,
  funcOptions,
  serverless
) {
  // Our source requirements, under our service path, and our module path (if specified)
  const fileName = path.join(servicePath, modulePath, options.fileName);

  // Skip requirements generation, if requirements file doesn't exist
  if (!requirementsFileExists(servicePath, options, fileName)) {
    return false;
  }

  let requirementsTxtDirectory;
  // Copy our requirements to another path in .serverless (incase of individually packaged)
  if (modulePath && modulePath !== '.') {
    requirementsTxtDirectory = path.join(
      servicePath,
      '.serverless',
      modulePath
    );
  } else {
    requirementsTxtDirectory = path.join(servicePath, '.serverless');
  }
  fse.ensureDirSync(requirementsTxtDirectory);
  const slsReqsTxt = path.join(requirementsTxtDirectory, 'requirements.txt');

  generateRequirementsFile(
    fileName,
    slsReqsTxt,
    serverless,
    servicePath,
    options
  );

  // If no requirements file or an empty requirements file, then do nothing
  if (!fse.existsSync(slsReqsTxt) || fse.statSync(slsReqsTxt).size == 0) {
    serverless.cli.log(
      `Skipping empty output requirements.txt file from ${slsReqsTxt}`
    );
    return false;
  }

  // Then generate our MD5 Sum of this requirements file to determine where it should "go" to and/or pull cache from
  const reqChecksum = sha256Path(slsReqsTxt);

  // Then figure out where this cache should be, if we're caching, if we're in a module, etc
  const workingReqsFolder = getRequirementsWorkingPath(
    reqChecksum,
    requirementsTxtDirectory,
    options
  );

  // Check if our static cache is present and is valid
  if (fse.existsSync(workingReqsFolder)) {
    if (
      fse.existsSync(path.join(workingReqsFolder, '.completed_requirements')) &&
      workingReqsFolder.endsWith('_slspyc')
    ) {
      serverless.cli.log(
        `Using static cache of requirements found at ${workingReqsFolder} ...`
      );
      // We'll "touch" the folder, as to bring it to the start of the FIFO cache
      fse.utimesSync(workingReqsFolder, new Date(), new Date());
      return workingReqsFolder;
    }
    // Remove our old folder if it didn't complete properly, but _just incase_ only remove it if named properly...
    if (
      workingReqsFolder.endsWith('_slspyc') ||
      workingReqsFolder.endsWith('.requirements')
    ) {
      rimraf.sync(workingReqsFolder);
    }
  }

  // Ensuring the working reqs folder exists
  fse.ensureDirSync(workingReqsFolder);

  // Copy our requirements.txt into our working folder...
  fse.copySync(slsReqsTxt, path.join(workingReqsFolder, 'requirements.txt'));

  // Then install our requirements from this folder
  installRequirements(workingReqsFolder, serverless, options);

  // Copy vendor libraries to requirements folder
  if (options.vendor) {
    copyVendors(options.vendor, workingReqsFolder, serverless);
  }
  if (funcOptions.vendor) {
    copyVendors(funcOptions.vendor, workingReqsFolder, serverless);
  }

  // Then touch our ".completed_requirements" file so we know we can use this for static cache
  if (options.useStaticCache) {
    fse.closeSync(
      fse.openSync(path.join(workingReqsFolder, '.completed_requirements'), 'w')
    );
  }
  return workingReqsFolder;
}
function installRequirementsIfNeeded(
  servicePath,
  modulePath,
  options,
  funcOptions,
  serverless
) {
  // Our source requirements, under our service path, and our module path (if specified)
  const fileName = path.join(servicePath, modulePath, options.fileName);

  // Skip requirements generation, if requirements file doesn't exist
  if (!requirementsFileExists(servicePath, options, fileName)) {
    return false;
  }

  let requirementsTxtDirectory;
  // Copy our requirements to another path in .serverless (incase of individually packaged)
  if (modulePath && modulePath !== '.') {
    requirementsTxtDirectory = path.join(
      servicePath,
      '.serverless',
      modulePath
    );
  } else {
    requirementsTxtDirectory = path.join(servicePath, '.serverless');
  }
  fse.ensureDirSync(requirementsTxtDirectory);
  const slsReqsTxt = path.join(requirementsTxtDirectory, 'requirements.txt');

  generateRequirementsFile(
    fileName,
    slsReqsTxt,
    serverless,
    servicePath,
    options
  );

  // If no requirements file or an empty requirements file, then do nothing
  if (!fse.existsSync(slsReqsTxt) || fse.statSync(slsReqsTxt).size == 0) {
    serverless.cli.log(
      `Skipping empty output requirements.txt file from ${slsReqsTxt}`
    );
    return false;
  }

  // Then generate our MD5 Sum of this requirements file to determine where it should "go" to and/or pull cache from
  const reqChecksum = sha256Path(slsReqsTxt);

  // Then figure out where this cache should be, if we're caching, if we're in a module, etc
  const workingReqsFolder = getRequirementsWorkingPath(
    reqChecksum,
    requirementsTxtDirectory,
    options
  );

  // Check if our static cache is present and is valid
  if (fse.existsSync(workingReqsFolder)) {
    if (
      fse.existsSync(path.join(workingReqsFolder, '.completed_requirements')) &&
      workingReqsFolder.endsWith('_slspyc')
    ) {
      serverless.cli.log(
        `Using static cache of requirements found at ${workingReqsFolder} ...`
      );
      // We'll "touch" the folder, as to bring it to the start of the FIFO cache
      fse.utimesSync(workingReqsFolder, new Date(), new Date());
      return workingReqsFolder;
    }
    // Remove our old folder if it didn't complete properly, but _just incase_ only remove it if named properly...
    if (
      workingReqsFolder.endsWith('_slspyc') ||
      workingReqsFolder.endsWith('.requirements')
    ) {
      rimraf.sync(workingReqsFolder);
    }
  }

  // Ensuring the working reqs folder exists
  fse.ensureDirSync(workingReqsFolder);

  // Copy our requirements.txt into our working folder...
  fse.copySync(slsReqsTxt, path.join(workingReqsFolder, 'requirements.txt'));

  // Then install our requirements from this folder
  installRequirements(workingReqsFolder, serverless, options);

  // Copy vendor libraries to requirements folder
  if (options.vendor) {
    copyVendors(options.vendor, workingReqsFolder, serverless);
  }
  if (funcOptions.vendor) {
    copyVendors(funcOptions.vendor, workingReqsFolder, serverless);
  }

  // Then touch our ".completed_requirements" file so we know we can use this for static cache
  if (options.useStaticCache) {
    fse.closeSync(
      fse.openSync(path.join(workingReqsFolder, '.completed_requirements'), 'w')
    );
  }
  return workingReqsFolder;
}
function installRequirementsIfNeeded ( servicePath , modulePath , options , funcOptions , serverless ) { // Our source requirements, under our service path, and our module path (if specified) const fileName = path . join ( servicePath , modulePath , options . fileName ) ; // Skip requirements generation, if requirements file doesn't exist if ( ! requirementsFileExists ( servicePath , options , fileName ) ) { return false ; } let requirementsTxtDirectory ; // Copy our requirements to another path in .serverless (incase of individually packaged) if ( modulePath && modulePath !== '.' ) { requirementsTxtDirectory = path . join ( servicePath , '.serverless' , modulePath ) ; } else { requirementsTxtDirectory = path . join ( servicePath , '.serverless' ) ; } fse . ensureDirSync ( requirementsTxtDirectory ) ; const slsReqsTxt = path . join ( requirementsTxtDirectory , 'requirements.txt' ) ; generateRequirementsFile ( fileName , slsReqsTxt , serverless , servicePath , options ) ; // If no requirements file or an empty requirements file, then do nothing if ( ! fse . existsSync ( slsReqsTxt ) || fse . statSync ( slsReqsTxt ) . size == 0 ) { serverless . cli . log ( ` ${ slsReqsTxt } ` ) ; return false ; } // Then generate our MD5 Sum of this requirements file to determine where it should "go" to and/or pull cache from const reqChecksum = sha256Path ( slsReqsTxt ) ; // Then figure out where this cache should be, if we're caching, if we're in a module, etc const workingReqsFolder = getRequirementsWorkingPath ( reqChecksum , requirementsTxtDirectory , options ) ; // Check if our static cache is present and is valid if ( fse . existsSync ( workingReqsFolder ) ) { if ( fse . existsSync ( path . join ( workingReqsFolder , '.completed_requirements' ) ) && workingReqsFolder . endsWith ( '_slspyc' ) ) { serverless . cli . log ( ` ${ workingReqsFolder } ` ) ; // We'll "touch" the folder, as to bring it to the start of the FIFO cache fse . utimesSync ( workingReqsFolder , new Date ( ) , new Date ( ) ) ; return workingReqsFolder ; } // Remove our old folder if it didn't complete properly, but _just incase_ only remove it if named properly... if ( workingReqsFolder . endsWith ( '_slspyc' ) || workingReqsFolder . endsWith ( '.requirements' ) ) { rimraf . sync ( workingReqsFolder ) ; } } // Ensuring the working reqs folder exists fse . ensureDirSync ( workingReqsFolder ) ; // Copy our requirements.txt into our working folder... fse . copySync ( slsReqsTxt , path . join ( workingReqsFolder , 'requirements.txt' ) ) ; // Then install our requirements from this folder installRequirements ( workingReqsFolder , serverless , options ) ; // Copy vendor libraries to requirements folder if ( options . vendor ) { copyVendors ( options . vendor , workingReqsFolder , serverless ) ; } if ( funcOptions . vendor ) { copyVendors ( funcOptions . vendor , workingReqsFolder , serverless ) ; } // Then touch our ".completed_requirements" file so we know we can use this for static cache if ( options . useStaticCache ) { fse . closeSync ( fse . openSync ( path . join ( workingReqsFolder , '.completed_requirements' ) , 'w' ) ) ; } return workingReqsFolder ; }
This evaluates if requirements are actually needed to be installed, but fails
gracefully if no req file is found intentionally.  It also assists with code
re-use for this logic pertaining to individually packaged functions
@param {string} servicePath
@param {string} modulePath
@param {Object} options
@param {Object} funcOptions
@param {Object} serverless
@return {string}
This evaluates if requirements are actually needed to be installed but fails gracefully if no req file is found intentionally . It also assists with code re - use for this logic pertaining to individually packaged functions