gocommand.js 4.8 KB
Newer Older
B
bryk 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Helper function that spawns a go binary process.
 */
import child from 'child_process';
import lodash from 'lodash';
20
import q from 'q';
U
urcan 已提交
21
import semver from 'semver';
B
bryk 已提交
22

23 24
import conf from './conf';

25 26 27 28 29
// Add base directory to the gopath so that local imports work.
const sourceGopath = `${conf.paths.backendTmp}`;
// Add the project's required go tools to the PATH.
const devPath = `${process.env.PATH}:${conf.paths.goTools}/bin`;

B
bryk 已提交
30
/**
31 32 33 34
 * The environment needed for the execution of any go command.
 */
const env = lodash.merge(process.env, {GOPATH: sourceGopath, PATH: devPath});

U
urcan 已提交
35 36 37 38 39
/**
 * Minimum required Go Version
 */
const minGoVersion = '1.5.0';

40 41 42 43
/**
 * Spawns a Go process wrapped with the Godep command after making sure all GO prerequisites are
 * present. Backend source files must be packaged with 'package-backend-source' task before running
 * this command.
B
bryk 已提交
44
 *
45 46
 * @param {!Array<string>} args - Arguments of the go command.
 * @param {function(?Error=)} doneFn - Callback.
B
bryk 已提交
47
 */
48
export default function spawnGoProcess(args, doneFn) {
49 50 51 52 53 54 55 56
  checkPrerequisites().then(() => spawnProcess(args)).then(doneFn).fail((error) => doneFn(error));
}

/**
 * Checks if all prerequisites for a go-command execution are present.
 * @return {Q.Promise} A promise object.
 */
function checkPrerequisites() {
U
urcan 已提交
57
  return checkGo().then(checkGoVersion).then(checkGodep);
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
}

/**
 * Checks if go is on the PATH prior to a go command execution, promises an error otherwise.
 * @return {Q.Promise} A promise object.
 */
function checkGo() {
  let deferred = q.defer();
  child.exec(
      'which go',
      {
        env: env,
      },
      function(error, stdout, stderror) {
        if (error || stderror || !stdout) {
          deferred.reject(
              new Error(
                  'Go is not on the path. Please pass the PATH variable when you run ' +
                  'the gulp task with "PATH=$PATH" or install go if you have not yet.'));
          return;
        }
        deferred.resolve();
      });
  return deferred.promise;
}
83

U
urcan 已提交
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
/**
 * Checks if go version fulfills the minimum version prerequisite, promises an error otherwise.
 * @return {Q.Promise} A promise object.
 */
function checkGoVersion() {
  let deferred = q.defer();
  child.exec(
      'go version',
      {
        env: env,
      },
      function(error, stdout) {
        let match = /[\d\.]+/.exec(stdout.toString());  // matches version number
        if (match.length < 1) {
          deferred.reject(new Error('Go version not found.'));
          return;
        }
        if (semver.lt(match[0], minGoVersion)) {
          deferred.reject(
              new Error(
                  `The current go version "${match[0]}" is older than ` +
                  `the minimum required version "${minGoVersion}". ` +
                  `Please upgrade your go version!`));
          return;
        }
        deferred.resolve();
      });

  return deferred.promise;
}

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
/**
 * Checks if godep is on the PATH prior to a go command execution, promises an error otherwise.
 * @return {Q.Promise} A promise object.
 */
function checkGodep() {
  let deferred = q.defer();
  child.exec(
      'which godep',
      {
        env: env,
      },
      function(error, stdout, stderror) {
        if (error || stderror || !stdout) {
          deferred.reject(
              new Error(
                  'Godep is not on the path. ' +
                  'Please run "npm install" in the base directory of the project.'));
          return;
        }
        deferred.resolve();
      });
  return deferred.promise;
}
138

139 140 141 142 143 144 145 146 147
/**
 * Spawns Go process wrapped with the Godep command.
 * Promises an error if the go command process fails.
 *
 * @param {!Array<string>} args - Arguments of the go command.
 * @return {Q.Promise} A promise object.
 */
function spawnProcess(args) {
  let deferred = q.defer();
B
bryk 已提交
148
  let goTask = child.spawn('godep', ['go'].concat(args), {
149
    env: env,
150 151
    stdio: 'inherit',
  });
B
bryk 已提交
152 153 154
  // Call Gulp callback on task exit. This has to be done to make Gulp dependency management
  // work.
  goTask.on('exit', function(code) {
155 156 157
    if (code !== 0) {
      deferred.reject(Error(`Go command error, code: ${code}`));
      return;
B
bryk 已提交
158
    }
159
    deferred.resolve();
B
bryk 已提交
160
  });
161
  return deferred.promise;
B
bryk 已提交
162
}