Skip to content

Adding Plugin System #628

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Nov 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ce8d9cb
Adding the Plugin System. Initial commit containing logic for 4/5 of …
joseph-flinn Aug 30, 2020
5ddde64
removing a rogue line
joseph-flinn Aug 30, 2020
b8b77cf
ran black over the changes
joseph-flinn Aug 30, 2020
a912b1a
added the logic for the method after re-reading Tony's issue stateme…
joseph-flinn Aug 30, 2020
03bf7e2
Adding in test plugins. Got these plugins to programmitcally install …
joseph-flinn Sep 10, 2020
53f672b
Redoing the plugin fixtures for testing
joseph-flinn Sep 12, 2020
0ef8e16
finished invididual plugin method testing. Moved the plugin loading i…
joseph-flinn Sep 13, 2020
28f7927
finished the tests
joseph-flinn Sep 13, 2020
c990e9b
moved the plugin interface into the tmuxp package instead of its own …
joseph-flinn Sep 13, 2020
072d3ab
Updating the versioning in relation to the plugin system
joseph-flinn Sep 13, 2020
96f8c2e
Switching the test plugins over to using poetry instead of wheel
joseph-flinn Sep 20, 2020
bdfbec1
fixing based on flake8 and black
joseph-flinn Sep 27, 2020
7987905
fixing mistype
joseph-flinn Sep 27, 2020
3a4bef3
fixed typo
joseph-flinn Oct 4, 2020
1228422
Updating the location of the before_script plugin method execution. U…
joseph-flinn Oct 4, 2020
c56c695
updating the plugin system docs
joseph-flinn Oct 11, 2020
bab350e
Updated the readme with the plugin docs link
joseph-flinn Oct 11, 2020
aa1ae98
fixed plugin system link in the readme
joseph-flinn Oct 11, 2020
cae94b9
updating test plugin required versions
joseph-flinn Oct 13, 2020
f61c0fd
Working on version contraints for the plugin system. Moved the load_p…
joseph-flinn Oct 19, 2020
2742381
Finishing up the version contraints of the plugin system as well as s…
joseph-flinn Oct 24, 2020
f63340a
running black over changes
joseph-flinn Oct 24, 2020
f779439
Typo fix
tony Oct 31, 2020
823245e
Plugin tests: Use pytest.raises and assert message contents
tony Oct 31, 2020
ceb7b6b
Rename PluginInterface -> Plugin
tony Oct 31, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ current
-------
- *Insert changes/features/fixes for next release here*

tmuxp 1.7.0a1 (2020-11-07)
--------------------------
- :issue:`530` Add plugin system for user customization of tmuxp
- :issue:`530` Add tests for the plugin system
- :issue:`530` Update existing tests for the plugin system
- :issue:`530` Add the plugin interface to the tmuxp package
- :issue:`530` Add in depth documentation for the plugin system

tmuxp 1.6.1 (2020-11-07)
------------------------
- :issue:`641` Improvements to ``shell``
Expand Down
7 changes: 6 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ Snapshot your tmux layout, pane paths, and window/session names.

See more about `freezing tmux`_ sessions.


Convert a session file
----------------------

Expand All @@ -176,6 +175,11 @@ You can auto confirm the prompt. In this case no preview will be shown.
$ tmuxp convert -y filename
$ tmuxp convert --yes filename

Plugin System
-------------

tmuxp has a plugin system to allow for custom behavior. See more about the
`Plugin System`_.

Docs / Reading material
-----------------------
Expand All @@ -200,6 +204,7 @@ Want to learn more about tmux itself? `Read The Tao of Tmux online`_.
.. _teamocil: https://github.com/remiprev/teamocil
.. _Examples: http://tmuxp.git-pull.com/examples.html
.. _freezing tmux: http://tmuxp.git-pull.com/cli.html#freeze-sessions
.. _Plugin System: http://tmuxp.git-pull.com/plugin_system.html
.. _bootstrap_env.py: https://github.com/tmux-python/tmuxp/blob/master/bootstrap_env.py
.. _testing: http://tmuxp.git-pull.com/developing.html#test-runner
.. _python objects: http://tmuxp.git-pull.com/api.html#api
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Table of Contents
quickstart
examples
cli
plugin_system
developing
api
history
Expand Down
130 changes: 130 additions & 0 deletions docs/plugin_system.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
.. _plugin_system:

=============
Plugin System
=============

The plugin system allows users to customize and extend different aspects of
tmuxp without the need to change tmuxp itself.


Using a Plugin
--------------

To use a plugin, install it in your local python environment and add it to
your tmuxp configuration file.

Example Configurations
^^^^^^^^^^^^^^^^^^^^^^
YAML
~~~~

.. literalinclude:: ../examples/plugin-system.yaml
:language: yaml

JSON
~~~~

.. literalinclude:: ../examples/plugin-system.json
:language: json

.. _poetry: https://python-poetry.org/


Developing a Plugin
-------------------

tmuxp expects all plugins to be class within a python submodule named
``plugin`` that is within a python module that is installed in the local
python environment. A plugin interface is provided by tmuxp to inherit.

`poetry`_ is the chosen python package manager for tmuxp. It is highly
suggested to use it when developing plugins; however, ``pip`` will work
just as well. Only one of the configuration files is needed for the packaging
tool that the package developer desides to use.

.. code-block:: bash

python_module
├── tmuxp_plugin_my_plugin_module
│   ├── __init__.py
│   └── plugin.py
├── pyproject.toml # Poetry's module configuration file
└── setup.py # pip's module configuration file


When publishing plugins to pypi, tmuxp advocates for standardized naming:
``tmuxp-plugin-{your-plugin-name}`` to allow for easier searching. To create a
module configuration file with poetry, run ``poetry init`` in the module
directory. The resulting file looks something like this:

.. code-block:: toml

[tool.poetry]
name = "tmuxp-plugin-my-tmuxp-plugin"
version = "0.0.2"
description = "An example tmuxp plugin."
authors = ["Author Name <author.name@<domain>.com>"]

[tool.poetry.dependencies]
python = "~2.7 || ^3.5"
tmuxp = "^1.6.0"

[tool.poetry.dev-dependencies]

[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"


The `plugin.py` file could contain something like the following:

.. code-block:: python

from tmuxp.plugin import TmuxpPlugin
import datetime

class MyTmuxpPlugin(TmuxpPlugin):
def __init__(self):
"""
Initialize my custom plugin.
"""
# Optional version dependency configuration. See Plugin API docs
# for all supported config parameters
config = {
'tmuxp_min_version' = '1.6.2'
}

TmuxpPlugin.__init__(
self,
plugin_name='tmuxp-plugin-my-tmuxp-plugin',
**config
)

def before_workspace_builder(self, session):
session.rename_session('my-new-session-name')

def reattach(self, session):
now = datetime.datetime.now().strftime('%Y-%m-%d')
session.rename_session('session_{}'.format(now))


Once this plugin is installed in the local python environment, it can be used
in a configuration file like the following:

.. code-block:: yaml

session_name: plugin example
plugins:
- my_plugin_module.plugin.MyTmuxpPlugin
# ... the rest of your config


Plugin API
----------

.. automethod:: tmuxp.plugin.TmuxpPlugin.before_workspace_builder
.. automethod:: tmuxp.plugin.TmuxpPlugin.on_window_create
.. automethod:: tmuxp.plugin.TmuxpPlugin.after_window_finished
.. automethod:: tmuxp.plugin.TmuxpPlugin.before_script
.. automethod:: tmuxp.plugin.TmuxpPlugin.reattach
24 changes: 24 additions & 0 deletions examples/plugin-system.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"session_name": "plugin-system",
"plugins": [
"tmuxp_plugin_extended_build.plugin.PluginExtendedBuild"
],
"windows": [
{
"window_name": "editor",
"layout": "tiled",
"shell_command_before": [
"cd ~/"
],
"panes": [
{
"shell_command": [
"cd /var/log",
"ls -al | grep *.log"
]
},
"echo \"hello world\""
]
}
]
}
13 changes: 13 additions & 0 deletions examples/plugin-system.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
session_name: plugin-system
plugins:
- 'tmuxp_plugin_extended_build.plugin.PluginExtendedBuild'
windows:
- window_name: editor
layout: tiled
shell_command_before:
- cd ~/
panes:
- shell_command:
- cd /var/log
- ls -al | grep *.log
- echo "hello world"
8 changes: 7 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ skip-string-normalization = true

[tool.poetry]
name = "tmuxp"
version = "1.6.1"
version = "1.7.0a1"
description = "tmux session manager"
license = "MIT"
authors = ["Tony Narlock <tony@git-pull.com>"]
Expand Down Expand Up @@ -69,6 +69,12 @@ pytest-mock = [
{version="<3.0.0", python="<3"},
{version="*", python=">=3"}
]
tmuxp-test-plugin-bwb = { path = "tests/fixtures/pluginsystem/plugins/tmuxp_test_plugin_bwb/"}
tmuxp-test-plugin-bs = { path = "tests/fixtures/pluginsystem/plugins/tmuxp_test_plugin_bs/"}
tmuxp-test-plugin-r = { path = "tests/fixtures/pluginsystem/plugins/tmuxp_test_plugin_r/"}
tmuxp-test-plugin-owc = { path = "tests/fixtures/pluginsystem/plugins/tmuxp_test_plugin_owc/"}
tmuxp-test-plugin-awf = { path = "tests/fixtures/pluginsystem/plugins/tmuxp_test_plugin_awf/"}
tmuxp-test-plugin-fail = { path = "tests/fixtures/pluginsystem/plugins/tmuxp_test_plugin_fail/"}

### Coverage ###
codecov = "*"
Expand Down
Empty file.
Empty file.
20 changes: 20 additions & 0 deletions tests/fixtures/pluginsystem/partials/all_pass.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from .test_plugin_helpers import MyTestTmuxpPlugin


class AllVersionPassPlugin(MyTestTmuxpPlugin):
def __init__(self):
config = {
'plugin_name': 'tmuxp-plugin-my-tmuxp-plugin',
'tmux_min_version': '1.8',
'tmux_max_version': '100.0',
'tmux_version_incompatible': ['2.3'],
'libtmux_min_version': '0.8.3',
'libtmux_max_version': '100.0',
'libtmux_version_incompatible': ['0.7.1'],
'tmuxp_min_version': '1.6.0',
'tmuxp_max_version': '100.0.0',
'tmuxp_version_incompatible': ['1.5.6'],
'tmux_version': '3.0',
'tmuxp_version': '1.6.0',
}
MyTestTmuxpPlugin.__init__(self, config)
31 changes: 31 additions & 0 deletions tests/fixtures/pluginsystem/partials/libtmux_version_fail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from .test_plugin_helpers import MyTestTmuxpPlugin


class LibtmuxVersionFailMinPlugin(MyTestTmuxpPlugin):
def __init__(self):
config = {
'plugin_name': 'libtmux-min-version-fail',
'libtmux_min_version': '0.8.3',
'libtmux_version': '0.7.0',
}
MyTestTmuxpPlugin.__init__(self, config)


class LibtmuxVersionFailMaxPlugin(MyTestTmuxpPlugin):
def __init__(self):
config = {
'plugin_name': 'libtmux-max-version-fail',
'libtmux_max_version': '3.0',
'libtmux_version': '3.5',
}
MyTestTmuxpPlugin.__init__(self, config)


class LibtmuxVersionFailIncompatiblePlugin(MyTestTmuxpPlugin):
def __init__(self):
config = {
'plugin_name': 'libtmux-incompatible-version-fail',
'libtmux_version_incompatible': ['0.7.1'],
'libtmux_version': '0.7.1',
}
MyTestTmuxpPlugin.__init__(self, config)
20 changes: 20 additions & 0 deletions tests/fixtures/pluginsystem/partials/test_plugin_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from tmuxp.plugin import TmuxpPlugin


class MyTestTmuxpPlugin(TmuxpPlugin):
def __init__(self, config):
tmux_version = config.pop('tmux_version', None)
libtmux_version = config.pop('libtmux_version', None)
tmuxp_version = config.pop('tmuxp_version', None)

TmuxpPlugin.__init__(self, **config)

# WARNING! This should not be done in anything but a test
if tmux_version:
self.version_constraints['tmux']['version'] = tmux_version
if libtmux_version:
self.version_constraints['libtmux']['version'] = libtmux_version
if tmuxp_version:
self.version_constraints['tmuxp']['version'] = tmuxp_version

self._version_check()
32 changes: 32 additions & 0 deletions tests/fixtures/pluginsystem/partials/tmux_version_fail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from .test_plugin_helpers import MyTestTmuxpPlugin


class TmuxVersionFailMinPlugin(MyTestTmuxpPlugin):
def __init__(self):
config = {
'plugin_name': 'tmux-min-version-fail',
'tmux_min_version': '1.8',
'tmux_version': '1.7',
}
MyTestTmuxpPlugin.__init__(self, config)


class TmuxVersionFailMaxPlugin(MyTestTmuxpPlugin):
def __init__(self):
config = {
'plugin_name': 'tmux-max-version-fail',
'tmux_max_version': '3.0',
'tmux_version': '3.5',
}
MyTestTmuxpPlugin.__init__(self, config)


class TmuxVersionFailIncompatiblePlugin(MyTestTmuxpPlugin):
def __init__(self):
config = {
'plugin_name': 'tmux-incompatible-version-fail',
'tmux_version_incompatible': ['2.3'],
'tmux_version': '2.3',
}

MyTestTmuxpPlugin.__init__(self, config)
31 changes: 31 additions & 0 deletions tests/fixtures/pluginsystem/partials/tmuxp_version_fail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from .test_plugin_helpers import MyTestTmuxpPlugin


class TmuxpVersionFailMinPlugin(MyTestTmuxpPlugin):
def __init__(self):
config = {
'plugin_name': 'tmuxp-min-version-fail',
'tmuxp_min_version': '1.6.0',
'tmuxp_version': '1.5.6',
}
MyTestTmuxpPlugin.__init__(self, config)


class TmuxpVersionFailMaxPlugin(MyTestTmuxpPlugin):
def __init__(self):
config = {
'plugin_name': 'tmuxp-max-version-fail',
'tmuxp_max_version': '2.0.0',
'tmuxp_version': '2.5',
}
MyTestTmuxpPlugin.__init__(self, config)


class TmuxpVersionFailIncompatiblePlugin(MyTestTmuxpPlugin):
def __init__(self):
config = {
'plugin_name': 'tmuxp-incompatible-version-fail',
'tmuxp_version_incompatible': ['1.5.0'],
'tmuxp_version': '1.5.0',
}
MyTestTmuxpPlugin.__init__(self, config)
Loading