text: # Copyright 2019 Google Inc.
  #
  # 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.
  """
  `cli.py`
  Command-Line interface of `slo-generator`.
  """
  
  import logging
  import os
  import sys
  import time
  from pathlib import Path
  from pkg_resources import get_distribution
  
  import click
  from slo_generator import utils
  from slo_generator.compute import compute as _compute
  from slo_generator.migrations import migrator
  from slo_generator.constants import LATEST_MAJOR_VERSION
  
  sys.path.append(os.getcwd())  # dynamic backend loading
  
  LOGGER = logging.getLogger(__name__)
  
  
  @click.group(invoke_without_command=True)
  @click.option('--version',
                '-v',
                is_flag=True,
                help='Show slo-generator version.')
  @click.pass_context
  def main(ctx, version):
      """CLI entrypoint."""
      utils.setup_logging()
      if ctx.invoked_subcommand is None or version:
          ver = get_distribution('slo-generator').version
          print(f'slo-generator v{ver}')
          sys.exit(0)
  
  
  @main.command()
  @click.option('--slo-config',
                '-f',
                type=click.Path(),
                required=True,
                help='SLO config path')
  @click.option('--config',
                '-c',
                type=click.Path(exists=True),
                default='config.yaml',
                show_default=True,
                help='slo-generator config path')
  @click.option('--export',
                '-e',
                is_flag=True,
                help='Export SLO report to exporters')
  @click.option('--delete',
                '-d',
                is_flag=True,
                help='Delete mode (used for backends with SLO APIs)')
  @click.option('--timestamp',
                '-t',
                type=float,
                default=time.time(),
                help='End timestamp for query.')
  def compute(slo_config, config, export, delete, timestamp):
      """Compute SLO report."""
      start = time.time()
  
      # Load slo-generator config
      LOGGER.debug(f"Loading slo-generator config from {config}")
      config_dict = utils.load_config(config)
  
      # Load SLO config(s)
      if Path(slo_config).is_dir():
          slo_configs = utils.load_configs(slo_config,
                                           kind='ServiceLevelObjective')
      else:
          slo_configs = [
              utils.load_config(slo_config, kind='ServiceLevelObjective')
          ]
  
      if not slo_configs:
          LOGGER.error(f'No SLO configs found in {slo_config}.')
          sys.exit(1)
  
      # Load SLO configs and compute SLO reports
      all_reports = {}
      for slo_config_dict in slo_configs:
          reports = _compute(slo_config_dict,
                             config_dict,
                             timestamp=timestamp,
                             do_export=export,
                             delete=delete)
          if reports:
              name = slo_config_dict['metadata']['name']
              all_reports[name] = reports
      end = time.time()
      duration = round(end - start, 1)
      LOGGER.info(f'Run summary | SLO Configs: {len(slo_configs)} | '
                  f'Duration: {duration}s')
      LOGGER.debug(all_reports)
      return all_reports
  
  
  # pylint: disable=import-error,import-outside-toplevel
  @main.command()
  @click.pass_context
  @click.option('--config',
                envvar='CONFIG_PATH',
                required=True,
                help='slo-generator configuration file path.')
  @click.option('--signature-type',
                envvar='GOOGLE_FUNCTION_SIGNATURE_TYPE',
                default='http',
                type=click.Choice(['http', 'cloudevent']),
                help='Signature type')
  @click.option('--target',
                envvar='GOOGLE_FUNCTION_SIGNATURE_TYPE',
                default='run_compute',
                help='Target function name')
  def api(ctx, config, signature_type, target):
      """Run an API that can receive requests (supports both 'http' and
      'cloudevents' signature types)."""
      from functions_framework._cli import _cli
      os.environ['CONFIG_PATH'] = config
      os.environ['GOOGLE_FUNCTION_SIGNATURE_TYPE'] = signature_type
      os.environ['GOOGLE_FUNCTION_TARGET'] = target
      ctx.invoke(_cli,
                 target=target,
                 source=Path(__file__).parent / 'api' / 'main.py',
                 signature_type=signature_type)
  
  
  @main.command()
  @click.option('--source',
                '-s',
                type=click.Path(exists=True, resolve_path=True, readable=True),
                required=True,
                default=Path.cwd(),
                help='Source SLO configs folder')
  @click.option('--target',
                '-t',
                type=click.Path(resolve_path=True),
                default=Path.cwd(),
                required=True,
                help='Target SLO configs folder')
  @click.option('--error-budget-policy-path',
                '-b',
                type=click.Path(exists=True, resolve_path=True, readable=True),
                required=False,
                default='error_budget_policy.yaml',
                help='Error budget policy path')
  @click.option('--glob',
                type=str,
                required=False,
                default='**/*.yaml',
                help='Glob expression to seek SLO configs in subpaths')
  @click.option('--version',
                type=str,
                required=False,
                default=LATEST_MAJOR_VERSION,
                show_default=True,
                help='SLO generate major version to migrate towards')
  @click.option('--quiet',
                '-q',
                is_flag=True,
                default=False,
                help='Do not ask for user input and auto-generate config keys')
  def migrate(**kwargs):
      """Migrate SLO configs from v1 to v2."""
      migrator.do_migrate(**kwargs)
  