All files YarnCli.js

0% Statements 0/25
0% Branches 0/16
0% Functions 0/8
0% Lines 0/25
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93                                                                                                                                                                                         
// @flow
 
import tmp from 'tmp'
import shell from './shell'
import path from 'path'
import fs from 'fs'
import DependencyPath from './DependencyPath'
import { execp } from './childProcess'
 
export default class YarnCli {
  _binaryPath: ?string
 
  constructor (binaryPath?: string) {
    this._binaryPath = binaryPath
  }
 
  get binaryPath () : string {
    return this._binaryPath ? this._binaryPath : `yarn`
  }
 
  async add (dependencyPath: DependencyPath,
  {
    dev,
    peer
  } : {
    dev?: boolean,
    peer?: boolean
  } = {}) {
    // Special handling with yarn add when the dependency is a local file path
    // In that case, for some reason it copies the node_modules directory of this path, which
    // is not a wanted behavior, especially for react-native bundling as it will create
    // haste module naming collisions
    // As a temporaray work-around, we copy the whole package directory to a temporary one
    // and remove node_modules from there and use this new path instead when yarn adding
    // Issue has been opened here https://github.com/yarnpkg/yarn/issues/1334
    // (still open as of this comment writing)
    // [Note: We tried another lighter workaround being to just remove the node_modules
    // directory contained within this package after yarn add is executed. Howver subsequent
    // yarn add of a different dependency just reintroduce the error on previous package
    // this is really weird]
    if (dependencyPath.isAFileSystemPath) {
      const tmpDirPath = tmp.dirSync({unsafeCleanup: true}).name
      shell.cp('-R', `${/file:(.+)/.exec(dependencyPath.toString())[1]}/*`, tmpDirPath)
      shell.rm('-rf', path.join(tmpDirPath, 'node_modules'))
      dependencyPath = DependencyPath.fromFileSystemPath(tmpDirPath)
    }
 
    const cmd = `add ${dependencyPath.toString()} --ignore-engines --exact ${dev ? '--dev' : ''} ${peer ? '--peer' : ''}`
    return this.runYarnCommand(cmd)
  }
 
  async install () {
    const cmd = `install --ignore-engines`
    return this.runYarnCommand(cmd)
  }
 
  async upgrade (dependencyPath: DependencyPath) {
    const cmd = `upgrade ${dependencyPath.toString()} --ignore-engines --exact`
    return this.runYarnCommand(cmd)
  }
 
  async init () {
    const cmd = `init --yes`
    return this.runYarnCommand(cmd)
  }
 
  async info (dependencyPath: DependencyPath, {
    field,
    json
  }: {
    field?: string,
    json?: boolean
  } = {}) {
    if (dependencyPath.isAFileSystemPath) {
      const packageJsonPath = path.join(dependencyPath.toString().substr(5), `package.json`)
      log.debug(`[runYarnCommand] Running info: returning ${packageJsonPath} `)
      return JSON.parse(fs.readFileSync(packageJsonPath, `utf-8`))
    } else {
      const cmd = `info ${dependencyPath.toString()} ${field || ''} ${json ? '--json' : ''}`
      const output = await this.runYarnCommand(cmd)
 
      // Assume single line of yarn JSON output in stdout for yarn info
      return JSON.parse(output.toString())
    }
  }
 
  async runYarnCommand (command: string) : Promise<string | Buffer> {
    const cmd = `${this.binaryPath} ${command}`
    log.debug(`[runYarnCommand] Running ${cmd}`)
    return execp(cmd)
  }
}