dbt-selly/dbt-env/lib/python3.8/site-packages/dbt/task/rpc/cli.py

126 lines
4.2 KiB
Python

import abc
import shlex
from dbt.clients.yaml_helper import Dumper, yaml # noqa: F401
from typing import Type, Optional
from dbt.config.utils import parse_cli_vars
from dbt.contracts.rpc import RPCCliParameters
from dbt.rpc.method import (
RemoteMethod,
RemoteManifestMethod,
Parameters,
Result,
)
from dbt.exceptions import InternalException
from dbt.parser.manifest import ManifestLoader
from .base import RPCTask
class HasCLI(RemoteMethod[Parameters, Result]):
@classmethod
def has_cli_parameters(cls):
return True
@abc.abstractmethod
def handle_request(self) -> Result:
pass
class RemoteRPCCli(RPCTask[RPCCliParameters]):
METHOD_NAME = 'cli_args'
def __init__(self, args, config, manifest):
super().__init__(args, config, manifest)
self.task_type: Optional[Type[RemoteMethod]] = None
self.real_task: Optional[RemoteMethod] = None
def set_config(self, config):
super().set_config(config)
if self.task_type is None:
raise InternalException('task type not set for set_config')
if issubclass(self.task_type, RemoteManifestMethod):
task_type: Type[RemoteManifestMethod] = self.task_type
self.real_task = task_type(
self.args, self.config, self.manifest
)
else:
self.real_task = self.task_type(
self.args, self.config
)
def set_args(self, params: RPCCliParameters) -> None:
# more import cycles :(
from dbt.main import parse_args, RPCArgumentParser
split = shlex.split(params.cli)
self.args = parse_args(split, RPCArgumentParser)
self.task_type = self.get_rpc_task_cls()
def get_flags(self):
if self.task_type is None:
raise InternalException('task type not set for get_flags')
# this is a kind of egregious hack from a type perspective...
return self.task_type.get_flags(self) # type: ignore
def get_rpc_task_cls(self) -> Type[HasCLI]:
# This is obnoxious, but we don't have actual access to the TaskManager
# so instead we get to dig through all the subclasses of RPCTask
# (recursively!) looking for a matching METHOD_NAME
candidate: Type[HasCLI]
for candidate in HasCLI.recursive_subclasses():
if candidate.METHOD_NAME == self.args.rpc_method:
return candidate
# this shouldn't happen
raise InternalException(
'No matching handler found for rpc method {} (which={})'
.format(self.args.rpc_method, self.args.which)
)
def load_manifest(self):
# we started out with a manifest!
pass
def handle_request(self) -> Result:
if self.real_task is None:
raise InternalException(
'CLI task is in a bad state: handle_request called with no '
'real_task set!'
)
# It's important to update cli_vars here, because set_config()'s
# `self.config` is before the fork(), so it would alter the behavior of
# future calls.
# read any cli vars we got and use it to update cli_vars
self.config.cli_vars.update(
parse_cli_vars(getattr(self.args, 'vars', '{}'))
)
# If this changed the vars, rewrite args.vars to reflect our merged
# vars and reload the manifest.
dumped = yaml.safe_dump(self.config.cli_vars)
if dumped != self.args.vars:
self.real_task.args.vars = dumped
if isinstance(self.real_task, RemoteManifestMethod):
self.real_task.manifest = ManifestLoader.get_full_manifest(
self.config, reset=True
)
# we parsed args from the cli, so we're set on that front
return self.real_task.handle_request()
def get_selection_spec(self):
return self.real_task.get_selection_spec()
def get_node_selector(self):
return self.real_task.get_node_selector()
def interpret_results(self, results):
if self.real_task is None:
# I don't know what happened, but it was surely some flavor of
# failure
return False
return self.real_task.interpret_results(results)