├── LICENCE ├── on-add-pirate ├── on-modify-pirate └── README.md /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright 2015-2017 Tomas Babej 2 | https://github.com/tbabej/taskpirate 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /on-add-pirate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import glob 4 | from types import ModuleType 5 | from importlib.machinery import SourceFileLoader, ModuleSpec 6 | from importlib.util import module_from_spec 7 | import os 8 | 9 | from tasklib import TaskWarrior, Task 10 | 11 | 12 | def find_hooks(file_prefix): 13 | # Find all files in subdirectories whose names start with 14 | file_pattern = os.path.dirname(__file__) + '/*/' + file_prefix + "*.py" 15 | module_paths = [f for f in glob.glob(file_pattern) if os.path.isfile(f)] 16 | module_paths.sort() 17 | 18 | # Gather all hooks in these files 19 | hooks = [] 20 | 21 | for module_path in module_paths: 22 | # Load the module 23 | module_dir = os.path.dirname(module_path) 24 | module_filename = os.path.basename(module_path) 25 | module_name = 'pirate_{0}_{1}'.format(module_dir, module_filename) 26 | module_name = module_name.replace('.', '_') 27 | loader = SourceFileLoader(module_name, module_path) 28 | spec = ModuleSpec(module_name, loader, origin=module_path) 29 | module = module_from_spec(spec) 30 | loader.exec_module(module) 31 | 32 | # Find all hook methods available 33 | module_hooks = [ 34 | getattr(module, hook_name) 35 | for hook_name in dir(module) 36 | if hook_name.startswith('hook_') 37 | ] 38 | 39 | hooks += module_hooks 40 | 41 | return hooks 42 | 43 | task = Task.from_input() 44 | 45 | for hook in find_hooks('pirate_add'): 46 | hook(task) 47 | 48 | print(task.export_data()) 49 | -------------------------------------------------------------------------------- /on-modify-pirate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import glob 4 | from types import ModuleType 5 | from importlib.machinery import SourceFileLoader, ModuleSpec 6 | from importlib.util import module_from_spec 7 | import os 8 | 9 | from tasklib import TaskWarrior, Task 10 | 11 | 12 | def find_hooks(file_prefix): 13 | # Find all files in subdirectories whose names start with 14 | file_pattern = os.path.dirname(__file__) + '/*/' + file_prefix + "*.py" 15 | module_paths = [f for f in glob.glob(file_pattern) if os.path.isfile(f)] 16 | module_paths.sort() 17 | 18 | # Gather all hooks in these files 19 | hooks = [] 20 | 21 | for module_path in module_paths: 22 | # Load the module 23 | module_dir = os.path.dirname(module_path) 24 | module_filename = os.path.basename(module_path) 25 | module_name = 'pirate_{0}_{1}'.format(module_dir, module_filename) 26 | module_name = module_name.replace('.', '_') 27 | loader = SourceFileLoader(module_name, module_path) 28 | spec = ModuleSpec(module_name, loader, origin=module_path) 29 | module = module_from_spec(spec) 30 | loader.exec_module(module) 31 | 32 | # Find all hook methods available 33 | module_hooks = [ 34 | getattr(module, hook_name) 35 | for hook_name in dir(module) 36 | if hook_name.startswith('hook_') 37 | ] 38 | 39 | hooks += module_hooks 40 | 41 | return hooks 42 | 43 | task = Task.from_input() 44 | 45 | for hook in find_hooks('pirate_mod'): 46 | hook(task) 47 | 48 | print(task.export_data()) 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Taskpirate 2 | ---------- 3 | 4 | Taskpirate is a pluggable system for TaskWarrior python hooks. 5 | 6 | Why? 7 | ---- 8 | 9 | Simpler hooks: 10 | 11 | def hook_example(task): 12 | task['description'] += "changed by a hook" 13 | 14 | The above is fully working example, no more boilerplate needed. 15 | 16 | Much faster execution time in case of multiple hooks (see [more details](#more-details)). 17 | 18 | Install 19 | ------- 20 | 21 | You'll need tasklib as a dependency: 22 | 23 | pip install tasklib 24 | 25 | Then you need to save `on-add-pirate` and `on-modify-pirate` from this repository into ~/.task/hooks/. 26 | 27 | After that, you can just clone any taskpirate-enabled hook as a subfolder into ~/.task/hooks/: 28 | 29 | git clone https://github.com/tbabej/task.default-date-time ~/.task/hooks/default-date-time/ 30 | 31 | How to write a taskpirate hook 32 | ------------------------------ 33 | 34 | In your hook's repository, any file matching `pirate_add*.py` will be searched for hooks in on-add event. In the same sense, any file matching `pirate_mod*.py` will be searched for hooks in on-modify event. 35 | 36 | Now, the pirate_add_example.py might look as follows: 37 | 38 | def hook_example(task): 39 | task['description'] += "changed by a hook" 40 | 41 | Any function in pirate_add_example that is called `hook_*` will be considered as a hook in on-add event. It will be passed the `Task` object corresponding to the current state of the task being added (as modified by the previous hooks). 42 | 43 | For examples, look into my [task.default-date-time](https://github.com/tbabej/task.default-date-time) or [task.shift-recurrence](https://github.com/tbabej/task.shift-recurrence) hooks. 44 | 45 | More details 46 | ------------ 47 | 48 | TaskWarrior hooks are intended to be simple, but they involve writing some boilerplate code (parsing/formatting json). To allow users to write dead simple code, they can leverage tasklib. 49 | 50 | Using tasklib simplifies things a lot, however, it's not a super-lightweight - usage of tasklib can slow down the hook by as much as 30-50ms (usual python hook can probably run in under 40ms), since it imports multiple libraries. 51 | 52 | This becomes a problem when user has multiple tasklib-based hooks, since the import time adds up. 53 | 54 | Also, note that taskpirate with arbitrary number of hooks will be most likely faster than 2-3 regular python hooks. 55 | --------------------------------------------------------------------------------