def _run_tool(tool, extra_args):
  """Run external executable tool.

  Args:
    tool: string name of the tool to run.
    extra_args: additional arguments for tool.

  Returns:
    A tuple of the (stdout, stderr) from the process.

  Raises:
    BuildError: if tool fails.
  """
  args = [tool]
  if sys.platform.startswith('win'):
    args = [tool + '.exe']
  args.extend(extra_args)
  logging.debug('Calling: %s', ' '.join(args))
  try:
    process = safe_subprocess.start_process(args,
                                            stdout=subprocess.PIPE,
                                            stderr=subprocess.PIPE)
    stdout, stderr = process.communicate()
  except OSError as e:
    msg = '%s not found.' % args[0]
    raise go_errors.BuildError('%s\n%s' % (msg, e))
  if process.returncode:
    raise go_errors.BuildError(
        '(Executed command: %s)\n\n%s\n%s' % (' '.join(args), stdout, stderr))
  return stdout, stderr
    def maybe_build(self, maybe_modified_since_last_build):
        """Builds an executable for the application if necessary.

    Args:
      maybe_modified_since_last_build: True if any files in the application root
          or the GOPATH have changed since the last call to maybe_build, False
          otherwise. This argument is used to decide whether a build is Required
          or not.

    Returns:
      True if compilation was successfully performed (will raise
        an exception if compilation was attempted but failed).
      False if compilation was not attempted.

    Raises:
      BuildError: if building the executable fails for any reason.
    """
        if not self._work_dir:
            self._work_dir = tempfile.mkdtemp('appengine-go-bin')
            atexit.register(_rmtree, self._work_dir)

        if not os.path.exists(_GAB_PATH):
            # TODO: This message should be more useful i.e. point the
            # user to an SDK that does have the right components.
            raise go_errors.BuildError(
                'Required Go components are missing from the SDK.')

        if self._go_executable and not maybe_modified_since_last_build:
            return False

        (self._go_file_to_mtime,
         old_go_file_to_mtime) = (self._get_go_files_to_mtime(),
                                  self._go_file_to_mtime)

        if not self._go_file_to_mtime:
            raise go_errors.BuildError(
                'no .go files found in %s' %
                self._module_configuration.application_root)

        self._extras_hash, old_extras_hash = (self._get_extras_hash(),
                                              self._extras_hash)

        if (self._go_executable
                and self._go_file_to_mtime == old_go_file_to_mtime
                and self._extras_hash == old_extras_hash):
            return False

        if self._go_file_to_mtime != old_go_file_to_mtime:
            logging.debug(
                'Rebuilding Go application due to source modification')
        elif self._extras_hash != old_extras_hash:
            logging.debug(
                'Rebuilding Go application due to GOPATH modification')
        else:
            logging.debug('Building Go application')
        self._build()
        return True
Example #3
0
    def _run_gab(self, gab_extra_args, env):
        """Run go-app-builder.

    Args:
      gab_extra_args: additional arguments (i.e. other than the standard base
        arguments) for go-app-builder.
      env: A dict containing environment variables for the subprocess.

    Returns:
      A tuple of the (stdout, stderr) from the go-app-builder process.

    Raises:
      BuildError: if the go application builder fails.
    """
        gab_path = os.path.join(self._goroot, 'bin', 'go-app-builder')
        if sys.platform.startswith('win'):
            gab_path += '.exe'

        if not os.path.exists(gab_path):
            # TODO: This message should be more useful i.e. point the
            # user to an SDK that does have the right components.
            raise go_errors.BuildError(
                'Required Go components are missing from the SDK.')

        # Go's regexp package does not implicitly anchor to the start.
        gab_args = [
            gab_path,
            '-app_base',
            self._module_configuration.application_root,
            '-arch',
            self._arch,
            '-dynamic',
            '-goroot',
            self._goroot,
            '-gopath',
            os.environ.get('GOPATH', GOPATH),
            '-nobuild_files',
            '^' + str(self._module_configuration.nobuild_files),
            '-incremental_rebuild',
            '-unsafe',
        ]
        gab_args.extend(gab_extra_args)
        gab_process = safe_subprocess.start_process(gab_args,
                                                    stdout=subprocess.PIPE,
                                                    stderr=subprocess.PIPE,
                                                    env=env)
        gab_stdout, gab_stderr = gab_process.communicate()
        if gab_process.returncode:
            raise go_errors.BuildError(
                '(Executed command: %s)\n%s\n%s' %
                (' '.join(gab_args), gab_stdout, gab_stderr))
        return gab_stdout, gab_stderr
def _run_gab(application_root, nobuild_files, arch, gab_extra_args, env):
    """Run go-app-builder.

  Args:
    application_root: string path to the root dir of the application.
    nobuild_files: regexp identifying which files to not build.
    arch: The one-character architecture designator (5, 6, or 8).
    gab_extra_args: additional arguments (i.e. other than the standard base
      arguments) for go-app-builder.
    env: A dict containing environment variables for the subprocess.

  Returns:
    A tuple of the (stdout, stderr) from the go-app-builder process.

  Raises:
    BuildError: if the go application builder fails.
  """
    gab_args = _get_base_gab_args(application_root, nobuild_files, arch)
    gab_args.extend(gab_extra_args)
    gab_process = safe_subprocess.start_process(gab_args,
                                                stdout=subprocess.PIPE,
                                                stderr=subprocess.PIPE,
                                                env=env)
    gab_stdout, gab_stderr = gab_process.communicate()
    if gab_process.returncode:
        raise go_errors.BuildError(
            '(Executed command: %s)\n%s\n%s' %
            (' '.join(gab_args), gab_stdout, gab_stderr))
    return gab_stdout, gab_stderr
 def _get_pkg_path():
     for n in os.listdir(os.path.join(GOROOT, 'pkg')):
         # Look for 'linux_amd64_appengine', 'windows_386_appengine', etc.
         if n.endswith('_appengine'):
             return os.path.join(GOROOT, 'pkg', n)
     raise go_errors.BuildError('No package path found in goroot (%s)' %
                                GOROOT)
Example #6
0
    def _get_architecture(goroot):
        """Get the architecture number for the go compiler.

    Args:
      goroot: The string path to goroot.

    Returns:
      The architecture number, as a string, for the go compiler.

    Raises:
      BuildError: If the arch for the goroot isn't one we support.
    """
        architecture_map = {
            'arm': '5',
            'amd64': '6',
            '386': '8',
        }
        for platform in os.listdir(os.path.join(goroot, 'pkg', 'tool')):
            # Look for 'linux_amd64', 'windows_386', etc.
            if '_' not in platform:
                continue
            architecture = platform.split('_', 1)[1]
            if architecture in architecture_map:
                return architecture_map[architecture]
        raise go_errors.BuildError('No known compiler found in goroot (%s)' %
                                   goroot)
Example #7
0
    def _build(self):
        """Builds the Managed VM app locally.

    Note that the go compiler must be called from within the app directory.
    Otherwise, it returns an error like:
    can't load package: package /a/b: import "/a/b": cannot import absolute path

    Raises:
      BuildError: if build fails.
    """
        logging.debug('Building Go application')

        app_root = self._module_configuration.application_root
        exe_name = os.path.join(self._work_dir, '_ah_exe')
        args = ['build', '-tags', 'appenginevm', '-o', exe_name]
        try:
            cwd = os.getcwd()
            os.chdir(app_root)
            stdout, stderr = _run_tool('go', args)
        finally:
            os.chdir(cwd)
        if not _file_is_executable(exe_name):
            raise go_errors.BuildError(
                'Your Go app must use "package main" and must provide'
                ' a "func main". See https://cloud.google.com/appengine'
                '/docs/go/managed-vms/ for more information.')
        logging.debug('Build succeeded:\n%s\n%s', stdout, stderr)
        self._go_executable = exe_name
 def _get_architecture():
     architecture_map = {
         'arm': '5',
         'amd64': '6',
         '386': '8',
     }
     for platform in os.listdir(os.path.join(GOROOT, 'pkg', 'tool')):
         # Look for 'linux_amd64', 'windows_386', etc.
         if '_' not in platform:
             continue
         architecture = platform.split('_', 1)[1]
         if architecture in architecture_map:
             return architecture_map[architecture]
     raise go_errors.BuildError('No known compiler found in goroot (%s)' %
                                GOROOT)
Example #9
0
  def _get_pkg_path(goroot):
    """The the path to the go pkg dir for appengine.

    Args:
      goroot: The path to goroot.

    Returns:
      The path to the go appengine pkg dir.

    Raises:
      BuildError: If the no package dir was found.
    """
    for n in os.listdir(os.path.join(goroot, 'pkg')):
      # Look for 'linux_amd64_appengine', 'windows_386_appengine', etc.
      if n.endswith('_appengine'):
        return os.path.join(goroot, 'pkg', n)
    raise go_errors.BuildError('No package path found in goroot (%s)' % goroot)
Example #10
0
  def maybe_build(self):
    """Builds an executable for the application if necessary.

    Returns:
      True if compilation was successfully performed (will raise
        an exception if compilation was attempted but failed).
      False if compilation was not attempted.

    Raises:
      BuildError: if building the executable fails for any reason.
    """
    if not self._work_dir:
      self._work_dir = tempfile.mkdtemp('appengine-go-bin')
      atexit.register(_rmtree, self._work_dir)

    if self._go_executable:
      return False

    (self._go_file_to_mtime,
     old_go_file_to_mtime) = (self._get_go_files_to_mtime(),
                              self._go_file_to_mtime)

    if not self._go_file_to_mtime:
      raise go_errors.BuildError('no .go files found in %s' %
                                 self._module_configuration.application_root)

    self._extras_hash, old_extras_hash = (self._get_extras_hash(),
                                          self._extras_hash)

    if (self._go_executable and
        self._go_file_to_mtime == old_go_file_to_mtime and
        self._extras_hash == old_extras_hash):
      return False

    if self._go_file_to_mtime != old_go_file_to_mtime:
      logging.debug('Rebuilding Go application due to source modification')
    elif self._extras_hash != old_extras_hash:
      logging.debug('Rebuilding Go application due to GOPATH modification')
    else:
      logging.debug('Building Go application')
    self._build()
    return True