text: from docutils.parsers.rst import directives
  
  from sphinx.directives.code import CodeBlock
  from sphinx.errors import ExtensionError
  
  import os
  import subprocess
  
  
  class ValidatingCodeBlock(CodeBlock):
      """A directive that provides protobuf yaml formatting and validation.
  
      'type-name' option is required and expected to conain full Envoy API type.
      An ExtensionError is raised on validation failure.
      Validation will be skipped if SPHINX_SKIP_CONFIG_VALIDATION environment variable is set.
      """
      has_content = True
      required_arguments = CodeBlock.required_arguments
      optional_arguments = CodeBlock.optional_arguments
      final_argument_whitespace = CodeBlock.final_argument_whitespace
      option_spec = {
          'type-name': directives.unchanged,
      }
      option_spec.update(CodeBlock.option_spec)
      skip_validation = (os.getenv('SPHINX_SKIP_CONFIG_VALIDATION') or 'false').lower() == 'true'
  
      def run(self):
          source, line = self.state_machine.get_source_and_line(self.lineno)
          # built-in directives.unchanged_required option validator produces a confusing error message
          if self.options.get('type-name') == None:
              raise ExtensionError("Expected type name in: {0} line: {1}".format(source, line))
  
          if not ValidatingCodeBlock.skip_validation:
              args = [
                  'bazel-bin/tools/config_validation/validate_fragment',
                  self.options.get('type-name'), '-s', '\n'.join(self.content)
              ]
              completed = subprocess.run(
                  args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8')
              if completed.returncode != 0:
                  raise ExtensionError(
                      "Failed config validation for type: '{0}' in: {1} line: {2}:\n {3}".format(
                          self.options.get('type-name'), source, line, completed.stderr))
  
          self.options.pop('type-name', None)
          return list(CodeBlock.run(self))
  
  
  def setup(app):
      app.add_directive("validated-code-block", ValidatingCodeBlock)
  
      return {
          'version': '0.1',
          'parallel_read_safe': True,
          'parallel_write_safe': True,
      }
  