def LoadCloudBuild(self, params):
        """Loads the Cloud Build configuration file for this builder reference.

    Args:
      params: dict, a dictionary of values to be substituted in to the
        Cloud Build configuration template corresponding to this runtime
        version.

    Returns:
      Build message, the parsed and parameterized Cloud Build configuration
        file.

    Raises:
      CloudBuildLoadError: If the Cloud Build configuration file is unknown.
      FileReadError: If reading the configuration file fails.
      InvalidRuntimeBuilderPath: If the path of the configuration file is
        invalid.
    """
        if not self.build_file_uri:
            raise CloudBuildLoadError(
                'There is no build file associated with runtime [{runtime}]'.
                format(runtime=self.runtime))
        messages = cloudbuild_util.GetMessagesModule()
        with _Read(self.build_file_uri) as data:
            return cloudbuild_config.LoadCloudbuildConfigFromStream(
                data, messages=messages, params=params)
    def testSubstitution_FromStream(self):
        data = io.StringIO("""
{
  "steps": [
    {"name": "gcr.io/cloud-builders/docker",
     "args": ["build", "-t", "gcr.io/my-project/simple"]
    }
   ],
  "substitutions": {"_MESSAGE": "hello world"}
}
        """)
        build = config.LoadCloudbuildConfigFromStream(data, self.messages,
                                                      None, 'mypath')
        self.assertEqual(
            build,
            self.messages.Build(
                steps=[
                    self.messages.BuildStep(
                        name='gcr.io/cloud-builders/docker',
                        args=['build', '-t', 'gcr.io/my-project/simple'],
                    ),
                ],
                substitutions=self.messages.Build.
                SubstitutionsValue(additionalProperties=[
                    self.messages.Build.SubstitutionsValue.AdditionalProperty(
                        key='_MESSAGE', value='hello world'),
                ]),
            ))
    def LoadCloudBuild(self, params):
        """Loads the Cloud Build configuration file for this runtime version.

    Pulls the file from the app/runtime_builders_root value. Supported protocols
    are Cloud Storage ('gs://') and local filesystem ('file://').

    Args:
      params: dict, a dictionary of values to be substituted in to the
        Cloud Build configuration template corresponding to this runtime
        version.

    Returns:
      Build message, the parsed and parameterized Cloud Build configuration
        file.

    Raises:
      CloudBuildLoadError: if the Cloud Build configuration file could not be
        loaded.
    """
        messages = cloudbuild_util.GetMessagesModule()
        build_file_path = os.path.join(self.source_dir, self.CLOUDBUILD_FILE)
        try:
            with open(build_file_path) as data:
                return cloudbuild_config.LoadCloudbuildConfigFromStream(
                    data, messages=messages, params=params)
        except (IOError, OSError, calliope_exceptions.BadFileException):
            raise self._CreateCloudBuildNotFoundException()
    def LoadCloudBuild(self, params):
        """Loads the Cloud Build configuration file for this runtime version.

    Pulls the file from the app/runtime_builders_root value. Supported protocols
    are Cloud Storage ('gs://') and local filesystem ('file://').

    If this RuntimeBuilderVersion has a version, this loads the file from
    '<runtime>-<version>.yaml' in the runtime builders root. Otherwise, it
    checks '<runtime>.version' to get the default version, and loads the
    configuration for that version.

    Args:
      params: dict, a dictionary of values to be substituted in to the
        Cloud Build configuration template corresponding to this runtime
        version.

    Returns:
      Build message, the parsed and parameterized Cloud Build configuration
        file.

    Raises:
      CloudBuildLoadError: if the Cloud Build configuration file could not be
        loaded.
    """
        build_file_root = properties.VALUES.app.runtime_builders_root.Get(
            required=True)
        log.debug('Using runtime builder root [%s]', build_file_root)

        if self.version is None:
            log.debug('Fetching version for runtime [%s]...', self.runtime)
            version_file_path = _Join(build_file_root,
                                      self.ToVersionFileName())
            try:
                with _Read(version_file_path) as f:
                    version = f.read().strip()
            except (IOError, OSError, calliope_exceptions.BadFileException):
                raise self._CreateCloudBuildNotFoundException(
                    version_file_path)
            log.info('Using version [%s] for runtime [%s].', version,
                     self.runtime)
            builder_version = CannedBuilderVersion(self.runtime, version)
            return builder_version.LoadCloudBuild(params)

        messages = cloudbuild_util.GetMessagesModule()
        build_file_name = self.ToYamlFileName()
        build_file_path = _Join(build_file_root, build_file_name)
        try:
            with _Read(build_file_path) as data:
                return cloudbuild_config.LoadCloudbuildConfigFromStream(
                    data, messages=messages, params=params)
        except (IOError, OSError, calliope_exceptions.BadFileException):
            raise self._CreateCloudBuildNotFoundException(build_file_path)
    def testSubstitutionError_FromStream(self):
        data = io.StringIO("""
{
  "steps": [
    {"name": "gcr.io/cloud-builders/docker",
     "args": ["build", "-t", "gcr.io/my-project/simple"]
    }
   ],
  "substitutions": {"COMMIT_SHA": "my-sha"}
}
        """)
        with self.assertRaisesRegex(
                config.InvalidBuildConfigException,
                'config cannot specify built-in substitutions'):
            config.LoadCloudbuildConfigFromStream(data, self.messages, None,
                                                  'mypath')
    def testJsonSyntaxError_FromStream(self):
        """Misplaced brace at the end of the document."""
        data = io.StringIO("""
{
  "steps": [
    {"name": "gcr.io/cloud-builders/docker",
     "args": ["build", "-t", "gcr.io/my-project/simple"]
    }
   ],
  "images": "gcr.io/my-project/simple"
}}
        """)
        with self.assertRaisesRegex(cloudbuild_util.ParserError,
                                    'parsing mypath'):
            config.LoadCloudbuildConfigFromStream(data, self.messages, None,
                                                  'mypath')
    def LoadCloudBuild(self, params):
        """Loads the Cloud Build configuration file for this builder reference.

    Args:
      params: dict, a dictionary of values to be substituted in to the
        Cloud Build configuration template corresponding to this runtime
        version.

    Returns:
      Build message, the parsed and parameterized Cloud Build configuration
        file.

    Raises:
      CloudBuildLoadError: If the Cloud Build configuration file is unknown.
      FileReadError: If reading the configuration file fails.
      InvalidRuntimeBuilderPath: If the path of the configuration file is
        invalid.
    """
        if not self.build_file_uri:
            raise CloudBuildLoadError(
                'There is no build file associated with runtime [{runtime}]'.
                format(runtime=self.runtime))
        messages = cloudbuild_util.GetMessagesModule()
        with _Read(self.build_file_uri) as data:
            build = cloudbuild_config.LoadCloudbuildConfigFromStream(
                data, messages=messages, params=params)
        if build.options is None:
            build.options = messages.BuildOptions()
        build.options.substitutionOption = (
            build.options.SubstitutionOptionValueValuesEnum.ALLOW_LOOSE)
        for step in build.steps:
            has_yaml_path = False
            has_runtime_version = False
            for env in step.env:
                parts = env.split('=')
                log.debug('Env var in build step: ' + str(parts))
                if 'GAE_APPLICATION_YAML_PATH' in parts:
                    has_yaml_path = True
                if 'GOOGLE_RUNTIME_VERSION' in parts:
                    has_runtime_version = True
            if not has_yaml_path:
                step.env.append(
                    'GAE_APPLICATION_YAML_PATH=${_GAE_APPLICATION_YAML_PATH}')
            if not has_runtime_version and '_GOOGLE_RUNTIME_VERSION' in params:
                step.env.append(
                    'GOOGLE_RUNTIME_VERSION=${_GOOGLE_RUNTIME_VERSION}')
        return build
    def testLoadJson_FromStream(self):
        data = io.StringIO("""
{
  "steps": [
    {"name": "gcr.io/cloud-builders/docker",
     "args": ["build", "-t", "gcr.io/my-project/simple"]
    }
   ],
  "images": "gcr.io/my-project/simple"
}
        """)
        build = config.LoadCloudbuildConfigFromStream(data, self.messages,
                                                      None, 'mypath')
        self.assertEqual(
            build,
            self.messages.Build(
                steps=[
                    self.messages.BuildStep(
                        name='gcr.io/cloud-builders/docker',
                        args=['build', '-t', 'gcr.io/my-project/simple'],
                    ),
                ],
                images=['gcr.io/my-project/simple'],
            ))