Skip to content

Commit 4a04519

Browse files
committed
add --user-dir option for plugins
1 parent e3e636f commit 4a04519

File tree

5 files changed

+53
-19
lines changed

5 files changed

+53
-19
lines changed

resources/plugins/simln/simln.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
get_static_client,
1919
wait_for_pod,
2020
)
21-
from warnet.plugins import _get_plugins_directory as get_plugin_directory
21+
from warnet.plugins import get_plugins_directory_or as get_plugin_directory
2222
from warnet.process import run_command
2323
from warnet.status import _get_tank_status as network_status
2424

src/warnet/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
DEFAULTS_NAMESPACE_FILE = "namespace-defaults.yaml"
4343

4444
# Plugin architecture
45+
USER_DIR_TAG = "user_dir"
4546
PLUGINS_LABEL = "plugins"
4647
PLUGIN_YAML = "plugin.yaml"
4748
PLUGINS_DIR = RESOURCES_DIR.joinpath(PLUGINS_LABEL)

src/warnet/main.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
from pathlib import Path
2+
13
import click
24

5+
from warnet.constants import USER_DIR_TAG
6+
37
from .admin import admin
48
from .bitcoin import bitcoin
59
from .control import down, logs, run, snapshot, stop
@@ -8,14 +12,25 @@
812
from .graph import create, graph, import_network
913
from .image import image
1014
from .ln import ln
11-
from .plugins import load_plugins, plugins
15+
from .plugins import load_plugins, load_user_modules, plugins
1216
from .project import init, new, setup
1317
from .status import status
1418
from .users import auth
1519

1620

1721
@click.group()
18-
def cli():
22+
@click.option(
23+
"--user-dir",
24+
type=click.Path(exists=True, file_okay=False),
25+
help="Path to the user's Warnet project directory.",
26+
)
27+
@click.pass_context
28+
def cli(ctx, user_dir: str):
29+
ctx.ensure_object(dict) # initialize ctx object
30+
if user_dir:
31+
ctx.obj[USER_DIR_TAG] = Path(user_dir)
32+
if load_user_modules(ctx.obj.get(USER_DIR_TAG)):
33+
load_plugins()
1934
pass
2035

2136

@@ -41,10 +56,5 @@ def cli():
4156
cli.add_command(plugins)
4257

4358

44-
@load_plugins
45-
def load_early():
46-
pass
47-
48-
4959
if __name__ == "__main__":
5060
cli()

src/warnet/plugins.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
MISSION_TAG,
1919
PLUGIN_YAML,
2020
PLUGINS_LABEL,
21+
USER_DIR_TAG,
2122
WARNET_USER_DIR_ENV_VAR,
2223
)
2324

@@ -37,9 +38,10 @@ def plugins():
3738

3839

3940
@plugins.command()
40-
def ls():
41+
@click.pass_context
42+
def ls(ctx):
4143
"""List all available plugins and whether they are activated"""
42-
plugin_dir = _get_plugins_directory()
44+
plugin_dir = get_plugins_directory_or(ctx.obj.get(USER_DIR_TAG))
4345
if plugin_dir is None:
4446
direct_user_to_plugin_directory_and_exit()
4547

@@ -52,9 +54,10 @@ def ls():
5254

5355
@plugins.command()
5456
@click.argument("plugin", type=str, default="")
55-
def toggle(plugin: str):
57+
@click.pass_context
58+
def toggle(ctx, plugin: str):
5659
"""Toggle a plugin on or off"""
57-
plugin_dir = _get_plugins_directory()
60+
plugin_dir = get_plugins_directory_or(ctx.obj.get(USER_DIR_TAG))
5861
if plugin_dir is None:
5962
direct_user_to_plugin_directory_and_exit()
6063

@@ -85,10 +88,10 @@ def toggle(plugin: str):
8588
write_yaml(updated_settings, plugin_dir / Path(plugin) / Path(PLUGIN_YAML))
8689

8790

88-
def load_user_modules() -> bool:
91+
def load_user_modules(path: Optional[Path] = None) -> bool:
8992
was_successful_load = False
9093

91-
plugin_dir = _get_plugins_directory()
94+
plugin_dir = get_plugins_directory_or(path)
9295

9396
if not plugin_dir or not plugin_dir.is_dir():
9497
return was_successful_load
@@ -125,15 +128,23 @@ def register_command(command):
125128
register.add_command(command)
126129

127130

128-
def load_plugins(fn):
129-
load_user_modules()
131+
def load_plugins():
130132
for module in imported_modules.values():
131133
for name, func in inspect.getmembers(module, inspect.isfunction):
132134
if name == "warnet_register_plugin":
133135
func(register_command)
134136

135137

136-
def _get_plugins_directory() -> Optional[Path]:
138+
def get_plugins_directory_or(path: Optional[Path] = None) -> Optional[Path]:
139+
"""Get the plugins directory
140+
user-provided path > environment variable > relative path
141+
"""
142+
if path:
143+
if path.is_dir():
144+
return path / PLUGINS_LABEL
145+
else:
146+
click.secho(f"Not a directory: {path}", fg="red")
147+
137148
user_dir = os.getenv(WARNET_USER_DIR_ENV_VAR)
138149

139150
plugin_dir = Path(user_dir) / PLUGINS_LABEL if user_dir else Path.cwd() / PLUGINS_LABEL
@@ -147,7 +158,7 @@ def _get_plugins_directory() -> Optional[Path]:
147158
def direct_user_to_plugin_directory_and_exit():
148159
click.secho("Could not determine the plugin directory location.")
149160
click.secho(
150-
"Solution 1: try runing this command again, but this time from your initialized warnet directory."
161+
"Solution 1: try runing this command again, but this time from your initialized Warnet directory."
151162
)
152163
click.secho(
153164
"Solution 2: consider setting environment variable pointing to your Warnet project directory:"
@@ -190,7 +201,7 @@ def check_if_plugin_enabled(path: Path) -> bool:
190201

191202
def get_plugins_with_status(plugin_dir: Optional[Path] = None) -> list[tuple[Path, bool]]:
192203
if not plugin_dir:
193-
plugin_dir = _get_plugins_directory()
204+
plugin_dir = get_plugins_directory_or()
194205
candidates = [
195206
Path(os.path.join(plugin_dir, name))
196207
for name in os.listdir(plugin_dir)

test/simln_test.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def run_test(self):
3232
self.run_plugin()
3333
self.copy_results()
3434
self.run_activity()
35+
self.run_activity_with_user_dir()
3536
finally:
3637
self.cleanup()
3738

@@ -75,6 +76,17 @@ def run_activity(self):
7576
self.wait_for_predicate(partial_func)
7677
self.log.info("Successfully ran activity")
7778

79+
def run_activity_with_user_dir(self):
80+
cmd = "mkdir temp; cd temp; warnet --user-dir ../ plugins simln get-example-activity; cd ../; rm -rf temp"
81+
self.log.info(f"Activity: {cmd}")
82+
activity_result = run_command(cmd)
83+
activity = json.loads(activity_result)
84+
pod_result = run_command(f"warnet plugins simln launch-activity '{json.dumps(activity)}'")
85+
partial_func = partial(self.found_results_remotely, pod_result.strip())
86+
self.wait_for_predicate(partial_func)
87+
run_command("cd ../")
88+
self.log.info("Successfully ran activity using --user-dir")
89+
7890
def wait_for_gossip_sync(self, expected: int):
7991
self.log.info(f"Waiting for sync (expecting {expected})...")
8092
current = 0

0 commit comments

Comments
 (0)