Esempio n. 1
0
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
Esempio n. 2
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,
            '-api_version',
            self._module_configuration.api_version,
            '-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)
        logging.debug('Calling go-app-builder: env: %s, args: %s', env,
                      gab_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:
            msg = (u'(Executed command: %s)\n%s\n%s' %
                   (u' '.join(gab_args), gab_stdout.decode('utf-8'),
                    gab_stderr.decode('utf-8')))
            raise go_errors.BuildError(msg.encode('utf-8'))
        return gab_stdout, gab_stderr
Esempio n. 3
0
    def _build(self):
        """Builds the 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', '-o', exe_name]
        if self._enable_debugging:
            args.extend(['-N', '-l'])
        try:
            cwd = os.getcwd()
            os.chdir(app_root)
            logging.debug('Working from dir %s', os.getcwd())
            stdout, stderr = _run_tool('go', args)
        finally:
            os.chdir(cwd)
        if not _file_is_executable(exe_name):
            # TODO: Fix this doc string
            raise go_errors.BuildError(
                'Your Go app must use "package main" and must provide a func main().'
                'See https://cloud.google.com/appengine/docs/standard/go/'
                'building-app/creating-your-application#creating_your_maingo_file '
                'for more information.')
        logging.debug('Build succeeded:\n%s\n%s', stdout, stderr)
        self._go_executable = exe_name
Esempio n. 4
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)
Esempio n. 5
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
Esempio n. 6
0
    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 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
Esempio n. 7
0
  def _get_pkg_path(goroot):
    """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)