def watcher(task, *args, **kwargs): while True: run("clear") kwargs["warn"] = True task(*args, **kwargs) try: run("inotifywait -q -e create -e modify -e delete " '--exclude ".*\.(pyc|sw.)" -r docs/ mopidy/ tests/') except KeyboardInterrupt: sys.exit()
def watcher(task, *args, **kwargs): while True: run('clear') kwargs['warn'] = True task(*args, **kwargs) try: run('inotifywait -q -e create -e modify -e delete ' '--exclude ".*\.(pyc|sw.)" -r docs/ mopidy/ tests/') except KeyboardInterrupt: sys.exit()
def main() -> None: # This says importlib.util.find_spec() can test if a module is currently importable: # https://docs.python.org/3/library/importlib.html#importlib.util.find_spec if not importlib.util.find_spec("invoke"): ensure_invoke() from invoke import task, Program, Config, Collection from invoke.config import merge_dicts from invoke.watchers import Responder namespace = Collection() globs = dict(globals()) namespace.add_task(task(atask_default, post=[ atask_install_scoop, atask_install_keepass, atask_setup_keepass, atask_schedule_updates, ]), default=True) for i,name in enumerate(namespace.tasks["atask-default"].post): namespace.tasks["atask-default"].post[i] = task(name) namespace.add_task(task(name)) class SetupConfig(Config): prefix: str = PROG_NAME @staticmethod def global_defaults(): base_defaults = Config.global_defaults() overrides = { "tasks": {"collection_name": PROG_NAME}, "run": { "shell": "C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", "echo": True, "debug": True, }, } return merge_dicts(base=base_defaults, updates=overrides) program = Program( name=PROG_NAME, namespace=namespace, config_class=SetupConfig, version="0.0.1" ) # NOTE: Debug # This uses the Python auditing framework in Python 3.8+ if sys.version_info>=(3,8): print("auditing enabled") def print_popen(*args, **kwargs) -> None: if args[0] == "subprocess.Popen": # sys.audit("subprocess.Popen", executable, args, cwd, env) # ("subprocess.Popen", (executable, args, cwd, env)) print(f"{args[1][0]} -> {args[1][1]}") sys.addaudithook(print_popen) program.run()
def generate_spectask(taskname): def spectask(ctx, files="", options="", untranslated=False): runner = Rubyspecs(files, options, untranslated=untranslated) getattr(runner, taskname)() spectask.__name__ = taskname return invoke.task(spectask)
def _empty_task(*args, name, doc=None, **kwargs): """Create a task that just calls other tasks""" f = lambda c: None # noqa: E731 f.__name__ = name if doc: f.__doc__ = doc return task(pre=list(args), **kwargs)(f)
def task(_function=None, *args, use_context=True, **kwargs): # pylint: disable=W1113 """ Replacement Invoke task decorator that enables the decorating of task functions that don't have an initial context parameter. In all other ways this decorator is identical to Invoke's own `task` decorator. The Invoke execution tool requires that all task functions include an initial context parameter, even if that parameter is not referenced anywhere in the function body. If, on the other hand, the `use_context` parameter is set to False in this decorator, then the decorated function does not need (and should not have) a context parameter. The new context parameter is (unsurprisingly) named 'context'. Args: _function (function, optional): The task function to decorate. This parameter need not be set explicitly. Defaults to None. use_context (bool): Whether the function has an initial Invoke context parameter. Defaults to True. If not set to False then this decorator behaves identically to the Invoke equivalent. *args: Argument list passed directly to the Invoke task decorator. **kwargs: Keyword argument list passed directly to the Invoke task decorator. Returns: function, Task: A decorator to apply to a task function if the function was not yet supplied. Otherwise, returns the Invoke Task object resulting from the decorator having been already applied to the task function. """ task_decorator = invoke.task(*args, **kwargs) # Add a dummy context parameter to the function if it doesn't have one already if not use_context: task_decorator = compose(task_decorator, create_task_function) # Enable usage of the decorator both with and without parentheses return task_decorator if _function is None else task_decorator(_function)
def make_env_task(name): def func(ctx, user=None, host=None, project_name=None): env(ctx, name, user, host, project_name) func.__name__ = name func.__doc__ = 'Configure for {name} environment'.format(name=name) return task(func)
def load(self, root, component_name): task_module = importlib.import_module(f'{root}.{component_name}') endpoint = getattr(task_module, 'ENDPOINT') methods = getattr(task_module, 'METHODS') arg_help = getattr(task_module, 'ARGUMENT_HELP', {}) for method, spec in methods.items(): invoke_task_name = f'{component_name}-{method}' origin_fn_name = f'_origin_{component_name}_{method}' proxy_fn_name = f'_proxy_{component_name}_{method}' self._namespace[origin_fn_name] = ApiCallTask( kong_admin_url=self._config.kong_admin_url, name=invoke_task_name, requests_method=spec.method, doc=spec.doc_url, endpoint=endpoint, endpoint_params=spec.endpoint_params) proxy_fn = ProxyDefinition( store_name=CTX_NS_PROXY_STORE_NAME, origin_fn_name=origin_fn_name, fn_name=proxy_fn_name, fn_args=[INVOKE_CTX_ARG_NAME, *spec.endpoint_params], fn_kwargs=spec.request_data_params) # execute define proxy function and bind to invoke task's body. exec(proxy_fn.as_string, self._namespace) invoke_task = task(self._namespace[origin_fn_name], help=arg_help) # set proxy function signature as task.body. invoke_task.body = self._namespace[proxy_fn_name] self.tasks.append(invoke_task)
def task(*args, name=None, aliases=(), positional=None, optional=(), iterable=None, incrementable=None, default=False, auto_shortflags=True, help={}, pre=[], post=[], autoprint=False, klass=invoke.Task): if len(args) > 0 and callable(args[0]) and not isinstance(args[0], invoke.Task): if hasattr(args[0], "__annotations__"): del (args[0].__annotations__) return klass( args[0], name=name, aliases=aliases, positional=positional, optional=optional, iterable=iterable, incrementable=incrementable, default=default, auto_shortflags=auto_shortflags, help=help, pre=pre, post=post, autoprint=autoprint, ) if len(args) > 0 and isinstance(args[0], invoke.Task): pre += list(args) wrap = invoke.task( name=name, aliases=aliases, positional=positional, optional=optional, iterable=iterable, incrementable=incrementable, default=default, auto_shortflags=auto_shortflags, help=help, pre=pre, post=post, autoprint=autoprint) def inner(obj): if hasattr(obj, "__annotations__"): del (obj.__annotations__) return wrap(obj) return inner
def task(*args, **kwargs): """Behaves the same way as invoke.task. Adds the task to the root namespace. """ if len(args) == 1 and callable(args[0]): new_task = invoke.task(args[0]) ns.add_task(new_task) return new_task def decorator(f): new_task = invoke.task(f, *args, **kwargs) ns.add_task(new_task) return new_task return decorator
def _ns_task(self, *args, **kwargs): # @task -- no options were (probably) given. if len(args) == 1 and callable(args[0]) and not isinstance(args[0], Task): t = task(args[0]) self.add_task(t) return t # All other invocations are just task arguments, without the function to wrap: def inner(f): t = task(f, *args, **kwargs) self.add_task(t) return t return inner
def task(*args, **kwargs): """ Wraps/extends Invoke's `@task <invoke.tasks.task>` with extra kwargs. See `the Invoke-level API docs <invoke.tasks.task>` for most details; this Fabric-specific implementation adds the following additional keyword arguments: :param hosts: An iterable of host-connection specifiers appropriate for eventually instantiating a `.Connection`. The existence of this argument will trigger automatic parameterization of the task when invoked from the CLI, similar to the behavior of :option:`--hosts`. .. note:: This parameterization is "lower-level" than that driven by :option:`--hosts`: if a task decorated with this parameter is executed in a session where :option:`--hosts` was given, the CLI-driven value will win out. List members may be one of: - A string appropriate for being the first positional argument to `.Connection` - see its docs for details, but these are typically shorthand-only convenience strings like ``hostname.example.com`` or ``user@host:port``. - A dictionary appropriate for use as keyword arguments when instantiating a `.Connection`. Useful for values that don't mesh well with simple strings (e.g. statically defined IPv6 addresses) or to bake in more complex info (eg ``connect_timeout``, ``connect_kwargs`` params like auth info, etc). These two value types *may* be mixed together in the same list, though we recommend that you keep things homogenous when possible, to avoid confusion when debugging. .. note:: No automatic deduplication of values is performed; if you pass in multiple references to the same effective target host, the wrapped task will execute on that host multiple times (including making separate connections). .. versionadded:: 2.1 """ # Override klass to be our own Task, not Invoke's, unless somebody gave it # explicitly. kwargs.setdefault("klass", Task) return invoke.task(*args, **kwargs)
def partial(t1: Task, **new_defaults): @functools.wraps(t1.body) def partial_task(c, **original_params) -> FunctionType: partially_applied_params = {} partially_applied_params.update(original_params) partially_applied_params.update(new_defaults) return t1.body(c, **partially_applied_params) # Had to ignore mypy due to https://github.com/python/typing/issues/598 # And https://github.com/python/mypy/issues/5958 partial_task.__signature__ = inspect.signature(t1.body) # type: ignore t2 = task( partial_task, help={k: v for k, v in t1.help.items() if k not in new_defaults}, ) t2.__doc__ = t1.__doc__ return t2
def uses_MyTask(*args, **kwargs): kwargs.setdefault("klass", MyTask) return task(*args, **kwargs)
""" context.run("failprint -t 'Combining coverage data' -- coverage combine --rcfile=config/coverage.ini") @invoke.task def coverage(context): """Report coverage as text and HTML. Arguments: context: The context of the Invoke task. """ context.run("coverage report --rcfile=config/coverage.ini") context.run("coverage html --rcfile=config/coverage.ini") @invoke.task(pre=[invoke.task(lambda c: c.run("rm -f .coverage"))]) @invoke.python(PYTHON_VERSIONS) def test(context, match=""): """Run the test suite. Arguments: context: The context of the Invoke task. match: A pytest expression to filter selected tests. """ title = f"Running tests ({context.python_version})" command = f"pytest -c config/pytest.ini -n auto -k '{match}' {PY_SRC}" if context.skip: title += " (missing interpreter)" command = "true" context.run(f"failprint -t '{title}' -- {command}", pty=PTY)
def allows_access_to_wrapped_object(self): def lolcats(c): pass assert task(lolcats).body == lolcats
site_prefix, base_url=''): ''' Runs the npm "federalist" script if it is defined ''' if PACKAGE_JSON_PATH.is_file() and has_federalist_script(): with node_context(ctx, ctx.cd(CLONE_DIR_PATH)): LOGGER.info('Running federalist build script in package.json') ctx.run( 'npm run federalist', env=build_env(branch, owner, repository, site_prefix, base_url) ) # 'Exported' run_federalist_script task run_federalist_script = task( pre=[setup_node], name='run-federalist-script')(_run_federalist_script) @task def setup_ruby(ctx): ''' Sets up RVM and installs ruby Uses the ruby version specified in .ruby-version if present ''' with ctx.prefix(f'source {RVM_PATH}'): if RUBY_VERSION_PATH.is_file(): ruby_version = '' with open(RUBY_VERSION_PATH, 'r') as ruby_vers_file: ruby_version = ruby_vers_file.readline().strip() if ruby_version: LOGGER.info('Using ruby version in .ruby-version')
def decorator(f): new_task = invoke.task(f, *args, **kwargs) ns.add_task(new_task) return new_task
def fn(*args, **kwargs): t = task(*args, **kwargs) assert isinstance(t, Task) collection.add_task(t) return t
from invoke import task import os @task(skip_ifs=[task(lambda ctx: os.getenv("SKIP_MYTASK", False))]) def mytask(ctx): print("Didn't skip!")
# escape-quote the value in case there's anything weird branch = shlex.quote(branch) ctx.run(f'git clone -b {branch} --single-branch {depth} ' f'{clone_url(owner, repository, github_token)} ' f'{CLONE_DIR_PATH}') # 'Exported' clone-repo task clone_repo = task( pre=[call(clean, which=CLONE_DIR_PATH)], post=[ # Remove _site if it exists call(clean, which=SITE_BUILD_DIR_PATH), ], help={ "owner": "Owner of the repository to clone", "repository": "Name of the repository to clone", }, name='clone-repo')(_clone_repo) @task def push_repo_remote(ctx, owner, repository, branch, remote_name='destination'): ''' Pushes the git repo in CLONE_DIR_PATH to a new remote destination.
# write out the main shell profile script files with configs in # them write_profile(profile_dir, name) # link the appropriate config files # TODO: currently we just link all of them since we don't have a # way to select them in the config yet, but we want to make the # right API for env variables in scripts cx.run( f'ln -f -s -r -T "{CONFIG_DIR}/{LIB_DIRNAME}" "{profile_dir}/{name}/lib"' ) profile_ns.add_task(task(profile_gen), name='gen') @task(default=True) def profile_load(cx, name='bimhaw'): # generate the profile profile_gen(cx, name=name) if name not in config.PROFILES: raise ValueError(f"Profile {name} not found") cx.run( f'ln -s -r -f -T "{CONFIG_DIR}/profiles/{name}" "{CONFIG_DIR}/active"')
def simple_task(name: str, commands: str) -> task: def caller(c): # noqa c.run(f"echo running {name}") c.run(commands) return task(caller, name=name)
def ns_task(function, *args, **kwargs): return ns.add_task(task(*args, **kwargs)(function))
def inner(f): t = task(f, *args, **kwargs) self.add_task(t) return t
def allows_access_to_wrapped_object(self): def lolcats(ctx): pass eq_(task(lolcats).body, lolcats)
def task_decorator(function, **kwargs): name = kwargs.pop("name", None) default = kwargs.pop("default", None) created_task = task(function, **kwargs) ns.add_task(created_task, name=name, default=default) return created_task
import IPython from . import copy from . import db as db_collection from okcupyd import user, db, util from okcupyd.db import model log = logging.getLogger(__name__) ns = Collection() ns.add_collection(copy) ns.add_collection(db_collection) login = task(util.get_credentials) ns.add_task(login, 'login') @ns.add_task @task(login, default=True) def interactive(): u = user.User() IPython.embed() @ns.add_task @task(aliases='s') def session(): with db.txn() as session: IPython.embed()
from invoke import task from tests.integration import harness start_mb = task(harness.start_mb) stop_mb = task(harness.stop_mb)
Arguments: context: The context of the Invoke task. """ context.run( "failprint -t 'Combining coverage data' -- coverage combine --rcfile=config/coverage.ini" ) @invoke.task def coverage(context): """Report coverage as text and HTML. Arguments: context: The context of the Invoke task. """ context.run("coverage report --rcfile=config/coverage.ini") context.run("coverage html --rcfile=config/coverage.ini") @invoke.task(pre=[invoke.task(lambda context: context.run("rm -f .coverage"))]) def test(context, match=""): """Run the test suite. Arguments: context: The context of the Invoke task. match: A pytest expression to filter selected tests. """ context.run( f"failprint -t 'Running tests' -- pytest -c config/pytest.ini -n auto -k '{match}' {PY_SRC}", pty=PTY)
from invoke import Context, task import devops.settings import devops.tasks from devops.lib.log import logger from devops.lib.utils import big_label, label, list_envs, load_env_settings, run ALL_COMPONENTS = ["service/pipeline-agent"] ENVS = list_envs() LOCAL_ENV = "minikube" # Determines some special rules # Maximum number of Docker tags to keep after cleanup MAX_TAGS = 50 validate_release_configs = task(devops.tasks.validate_release_configs) @task( iterable=["component", "docker_arg"], help={ "component": "The components to build - if none given defaults to: " + ", ".join(ALL_COMPONENTS), "dry-run": "Do not perform any changes, just generate configs and log what would be done", "docker-arg": "Arguments to pass to docker build, e.g. --docker-arg foo=bar " + "--docker-arg bar=baz", }, )
def register_task(self, task_func, name=None): self.add_task(task(task_func), name=name)