fujin-cli 0.7.0__py3-none-any.whl → 0.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of fujin-cli might be problematic. Click here for more details.

@@ -1,2 +1 @@
1
1
  from ._base import BaseCommand # noqa
2
- from ._base import BaseCommand # noqa
fujin/commands/_base.py CHANGED
@@ -6,7 +6,8 @@ from functools import cached_property
6
6
  import cappa
7
7
 
8
8
  from fujin.config import Config
9
- from fujin.connection import host_connection, Connection
9
+ from fujin.connection import Connection
10
+ from fujin.connection import host_connection
10
11
  from fujin.errors import ImproperlyConfiguredError
11
12
  from fujin.hooks import HookManager
12
13
  from fujin.process_managers import ProcessManager
@@ -32,6 +33,14 @@ class BaseCommand:
32
33
  def app_dir(self) -> str:
33
34
  return self.config.host.get_app_dir(app_name=self.config.app_name)
34
35
 
36
+ @cached_property
37
+ def hook_manager(self) -> HookManager:
38
+ return HookManager(
39
+ hooks=self.config.hooks,
40
+ app_name=self.config.app_name,
41
+ local_config_dir=self.config.local_config_dir,
42
+ )
43
+
35
44
  @contextmanager
36
45
  def connection(self):
37
46
  with host_connection(host=self.config.host) as conn:
@@ -69,8 +78,3 @@ class BaseCommand:
69
78
 
70
79
  def create_process_manager(self, conn: Connection) -> ProcessManager:
71
80
  return self.process_manager_class.create(conn=conn, config=self.config)
72
-
73
- def create_hook_manager(self, conn: Connection) -> HookManager:
74
- return HookManager(
75
- conn=conn, hooks=self.config.hooks, app_name=self.config.app_name
76
- )
fujin/commands/deploy.py CHANGED
@@ -7,8 +7,8 @@ import cappa
7
7
 
8
8
  from fujin.commands import BaseCommand
9
9
  from fujin.config import InstallationMode
10
- from fujin.secrets import resolve_secrets
11
10
  from fujin.connection import Connection
11
+ from fujin.secrets import resolve_secrets
12
12
 
13
13
 
14
14
  @cappa.command(
@@ -16,15 +16,15 @@ from fujin.connection import Connection
16
16
  )
17
17
  class Deploy(BaseCommand):
18
18
  def __call__(self):
19
+ self.hook_manager.pre_build()
19
20
  parsed_env = self.parse_envfile()
20
21
  self.build_app()
21
-
22
+ self.hook_manager.pre_deploy()
22
23
  with self.connection() as conn:
23
24
  process_manager = self.create_process_manager(conn)
24
25
  conn.run(f"mkdir -p {self.app_dir}")
25
26
  conn.run(f"mkdir -p {self.versioned_assets_dir}")
26
27
  with conn.cd(self.app_dir):
27
- self.create_hook_manager(conn).pre_deploy()
28
28
  self.transfer_files(conn, env=parsed_env)
29
29
  self.install_project(conn)
30
30
  with self.app_environment() as app_conn:
@@ -35,7 +35,7 @@ class Deploy(BaseCommand):
35
35
  self.create_web_proxy(app_conn).setup()
36
36
  self.update_version_history(app_conn)
37
37
  self.prune_assets(app_conn)
38
- self.create_hook_manager(conn).post_deploy()
38
+ self.hook_manager.post_deploy()
39
39
  self.stdout.output("[green]Project deployment completed successfully![/green]")
40
40
  self.stdout.output(
41
41
  f"[blue]Access the deployed project at: https://{self.config.host.domain_name}[/blue]"
@@ -60,7 +60,7 @@ class Deploy(BaseCommand):
60
60
  return self.config.host.envfile.read_text()
61
61
 
62
62
  def transfer_files(
63
- self, conn: Connection, env: str, skip_requirements: bool = False
63
+ self, conn: Connection, env: str, skip_requirements: bool = False
64
64
  ):
65
65
  conn.run(f"echo '{env}' > {self.app_dir}/.env")
66
66
  distfile_path = self.config.get_distfile_path()
@@ -78,7 +78,7 @@ class Deploy(BaseCommand):
78
78
  )
79
79
 
80
80
  def install_project(
81
- self, conn: Connection, version: str | None = None, *, skip_setup: bool = False
81
+ self, conn: Connection, version: str | None = None, *, skip_setup: bool = False
82
82
  ):
83
83
  version = version or self.config.version
84
84
  if self.config.installation_mode == InstallationMode.PY_PACKAGE:
@@ -87,7 +87,7 @@ class Deploy(BaseCommand):
87
87
  self._install_binary(conn, version)
88
88
 
89
89
  def _install_python_package(
90
- self, conn: Connection, version: str, skip_setup: bool = False
90
+ self, conn: Connection, version: str, skip_setup: bool = False
91
91
  ):
92
92
  appenv = f"""
93
93
  set -a # Automatically export all variables
@@ -100,6 +100,7 @@ export PATH=".venv/bin:$PATH"
100
100
  conn.run(f"echo '{appenv.strip()}' > {self.app_dir}/.appenv")
101
101
  versioned_assets_dir = f"{self.app_dir}/v{version}"
102
102
  if not skip_setup:
103
+ conn.run("rm -rf .venv")
103
104
  conn.run("uv venv")
104
105
  if self.config.requirements:
105
106
  conn.run(f"uv pip install -r {versioned_assets_dir}/requirements.txt")
fujin/commands/down.py CHANGED
@@ -33,8 +33,6 @@ class Down(BaseCommand):
33
33
  if not confirm:
34
34
  return
35
35
  with self.connection() as conn:
36
- hook_manager = self.create_hook_manager(conn)
37
- hook_manager.pre_teardown()
38
36
  process_manager = self.create_process_manager(conn)
39
37
  conn.run(f"rm -rf {self.app_dir}")
40
38
  self.create_web_proxy(conn).teardown()
@@ -42,7 +40,6 @@ class Down(BaseCommand):
42
40
  process_manager.reload_configuration()
43
41
  if self.full:
44
42
  self.create_web_proxy(conn).uninstall()
45
- hook_manager.post_teardown()
46
43
  self.stdout.output(
47
44
  "[green]Project teardown completed successfully![/green]"
48
45
  )
fujin/commands/init.py CHANGED
@@ -8,7 +8,8 @@ import cappa
8
8
  import tomli_w
9
9
 
10
10
  from fujin.commands import BaseCommand
11
- from fujin.config import tomllib, InstallationMode
11
+ from fujin.config import InstallationMode
12
+ from fujin.config import tomllib
12
13
 
13
14
 
14
15
  @cappa.command(help="Generate a sample configuration file")
@@ -5,12 +5,14 @@ from fujin.secrets import resolve_secrets
5
5
 
6
6
 
7
7
  @cappa.command(
8
- help="Print the content of the envfile with extracted secrets (for debugging)"
8
+ help="Display the contents of the envfile with resolved secrets (for debugging purposes)"
9
9
  )
10
10
  class Printenv(BaseCommand):
11
11
  def __call__(self):
12
12
  if self.config.secret_config:
13
- result = resolve_secrets(self.config.host.envfile, self.config.secret_config)
13
+ result = resolve_secrets(
14
+ self.config.host.envfile, self.config.secret_config
15
+ )
14
16
  else:
15
17
  result = self.config.host.envfile.read_text()
16
18
  self.stdout.output(result)
@@ -6,21 +6,20 @@ from pathlib import Path
6
6
  import cappa
7
7
 
8
8
  from fujin.commands import BaseCommand
9
- from .deploy import Deploy
10
9
  from fujin.config import InstallationMode
11
10
  from fujin.connection import Connection
11
+ from .deploy import Deploy
12
12
 
13
13
 
14
14
  @cappa.command(help="Redeploy the application to apply code and environment changes")
15
15
  class Redeploy(BaseCommand):
16
16
  def __call__(self):
17
17
  deploy = Deploy()
18
+ self.hook_manager.pre_build()
18
19
  parsed_env = deploy.parse_envfile()
19
20
  deploy.build_app()
20
-
21
+ self.hook_manager.pre_deploy()
21
22
  with self.app_environment() as conn:
22
- hook_manager = self.create_hook_manager(conn)
23
- hook_manager.pre_deploy()
24
23
  conn.run(f"mkdir -p {deploy.versioned_assets_dir}")
25
24
  requirements_copied = self._copy_requirements_if_needed(conn)
26
25
  deploy.transfer_files(
@@ -30,13 +29,13 @@ class Redeploy(BaseCommand):
30
29
  deploy.release(conn)
31
30
  self.create_process_manager(conn).restart_services()
32
31
  deploy.update_version_history(conn)
33
- hook_manager.post_deploy()
34
- self.stdout.output("[green]Redeployment completed successfully![/green]")
32
+ self.hook_manager.post_deploy()
33
+ self.stdout.output("[green]Redeployment completed successfully![/green]")
35
34
 
36
35
  def _copy_requirements_if_needed(self, conn: Connection) -> bool:
37
36
  if (
38
- not self.config.requirements
39
- or self.config.installation_mode == InstallationMode.BINARY
37
+ not self.config.requirements
38
+ or self.config.installation_mode == InstallationMode.BINARY
40
39
  ):
41
40
  return False
42
41
  local_requirements = hashlib.md5(
@@ -1,7 +1,8 @@
1
1
  from dataclasses import dataclass
2
2
 
3
3
  import cappa
4
- from rich.prompt import Prompt, Confirm
4
+ from rich.prompt import Confirm
5
+ from rich.prompt import Prompt
5
6
 
6
7
  from fujin.commands import BaseCommand
7
8
  from fujin.commands.deploy import Deploy
fujin/commands/server.py CHANGED
@@ -23,8 +23,6 @@ class Server(BaseCommand):
23
23
  @cappa.command(help="Setup uv, web proxy, and install necessary dependencies")
24
24
  def bootstrap(self):
25
25
  with self.connection() as conn:
26
- hook_manager = self.create_hook_manager(conn)
27
- hook_manager.pre_bootstrap()
28
26
  conn.run("sudo apt update && sudo apt upgrade -y", pty=True)
29
27
  conn.run("sudo apt install -y sqlite3 curl rsync", pty=True)
30
28
  result = conn.run("command -v uv", warn=True)
@@ -33,7 +31,6 @@ class Server(BaseCommand):
33
31
  conn.run("uv tool update-shell")
34
32
  conn.run("uv tool install fastfetch-bin-edge")
35
33
  self.create_web_proxy(conn).install()
36
- hook_manager.post_bootstrap()
37
34
  self.stdout.output(
38
35
  "[green]Server bootstrap completed successfully![/green]"
39
36
  )
fujin/commands/up.py CHANGED
@@ -1,8 +1,8 @@
1
1
  import cappa
2
- from fujin.commands import BaseCommand
3
2
 
4
3
  from .deploy import Deploy
5
4
  from .server import Server
5
+ from fujin.commands import BaseCommand
6
6
 
7
7
 
8
8
  @cappa.command(help="Run everything required to deploy an application to a fresh host.")
fujin/config.py CHANGED
@@ -176,6 +176,9 @@ Example:
176
176
  dbconsole = "app exec -i dbshell" # open an interactive django database shell
177
177
  shell = "server exec --appenv -i bash" # SSH into the project directory with environment variables loaded
178
178
 
179
+ hooks
180
+ -----
181
+ Run custom scripts at specific points with hooks. Check out the `secrets </hooks.html>`_ page for more information.
179
182
 
180
183
  """
181
184
 
fujin/connection.py CHANGED
@@ -8,11 +8,9 @@ import cappa
8
8
  from fabric import Connection
9
9
  from invoke import Responder
10
10
  from invoke.exceptions import UnexpectedExit
11
- from paramiko.ssh_exception import (
12
- AuthenticationException,
13
- NoValidConnectionsError,
14
- SSHException,
15
- )
11
+ from paramiko.ssh_exception import AuthenticationException
12
+ from paramiko.ssh_exception import NoValidConnectionsError
13
+ from paramiko.ssh_exception import SSHException
16
14
 
17
15
  if TYPE_CHECKING:
18
16
  from fujin.config import HostConfig
fujin/hooks.py CHANGED
@@ -1,6 +1,8 @@
1
+ import subprocess
1
2
  from dataclasses import dataclass
3
+ from pathlib import Path
2
4
 
3
- from fujin.connection import Connection
5
+ import cappa
4
6
  from rich import print as rich_print
5
7
 
6
8
  try:
@@ -13,43 +15,45 @@ except ImportError:
13
15
 
14
16
 
15
17
  class Hook(StrEnum):
18
+ PRE_BUILD = "pre_build"
16
19
  PRE_DEPLOY = "pre_deploy"
17
20
  POST_DEPLOY = "post_deploy"
18
- PRE_BOOTSTRAP = "pre_bootstrap"
19
- POST_BOOTSTRAP = "post_bootstrap"
20
- PRE_TEARDOWN = "pre_teardown"
21
- POST_TEARDOWN = "post_teardown"
22
21
 
23
22
 
24
- HooksDict = dict[Hook, dict]
23
+ HooksDict = dict[Hook, str]
25
24
 
26
25
 
27
- @dataclass(frozen=True, slots=True)
26
+ @dataclass(slots=True)
28
27
  class HookManager:
29
28
  app_name: str
30
29
  hooks: HooksDict
31
- conn: Connection
30
+ local_config_dir: Path
31
+
32
+ def __post_init__(self):
33
+ if self.hooks:
34
+ return
35
+ hooks_folder = self.local_config_dir / "hooks"
36
+ if not hooks_folder.exists():
37
+ return
38
+ self.hooks = {
39
+ h.value: f"./{hooks_folder / h.value}" # noqa
40
+ for h in Hook
41
+ if (hooks_folder / h.value).exists() # noqa
42
+ }
32
43
 
33
44
  def _run_hook(self, type_: Hook) -> None:
34
- if hooks := self.hooks.get(type_):
35
- for name, command in hooks.items():
36
- rich_print(f"[blue]Running {type_} hook {name} [/blue]")
37
- self.conn.run(command, pty=True)
45
+ if cmd := self.hooks.get(type_):
46
+ rich_print(f"[blue]Running {type_} hook[/blue]")
47
+ result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
48
+ if result.returncode != 0:
49
+ raise cappa.Exit(result.stderr)
50
+ rich_print(result.stdout)
51
+
52
+ def pre_build(self) -> None:
53
+ self._run_hook(Hook.PRE_BUILD)
38
54
 
39
55
  def pre_deploy(self) -> None:
40
56
  self._run_hook(Hook.PRE_DEPLOY)
41
57
 
42
58
  def post_deploy(self) -> None:
43
59
  self._run_hook(Hook.POST_DEPLOY)
44
-
45
- def pre_bootstrap(self) -> None:
46
- self._run_hook(Hook.PRE_BOOTSTRAP)
47
-
48
- def post_bootstrap(self) -> None:
49
- self._run_hook(Hook.POST_BOOTSTRAP)
50
-
51
- def pre_teardown(self) -> None:
52
- self._run_hook(Hook.PRE_TEARDOWN)
53
-
54
- def post_teardown(self) -> None:
55
- self._run_hook(Hook.POST_TEARDOWN)
fujin/secrets/__init__.py CHANGED
@@ -1,13 +1,15 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from pathlib import Path
4
+ from typing import Callable
5
+
4
6
  import gevent
5
7
  from dotenv import dotenv_values
6
- from typing import Callable
7
8
 
8
- from fujin.config import SecretConfig, SecretAdapter
9
9
  from .bitwarden import bitwarden
10
10
  from .onepassword import one_password
11
+ from fujin.config import SecretAdapter
12
+ from fujin.config import SecretConfig
11
13
 
12
14
 
13
15
  secret_reader = Callable[[str], str]
@@ -1,12 +1,14 @@
1
1
  from __future__ import annotations
2
- import cappa
2
+
3
3
  import os
4
+ import subprocess
5
+ from contextlib import contextmanager
6
+ from typing import Generator
7
+ from typing import TYPE_CHECKING
4
8
 
9
+ import cappa
5
10
 
6
11
  from fujin.config import SecretConfig
7
- import subprocess
8
- from contextlib import contextmanager
9
- from typing import Generator, TYPE_CHECKING
10
12
 
11
13
  if TYPE_CHECKING:
12
14
  from . import secret_reader
@@ -25,7 +27,16 @@ def bitwarden(secret_config: SecretConfig) -> Generator[secret_reader, None, Non
25
27
 
26
28
  def read_secret(name: str) -> str:
27
29
  result = subprocess.run(
28
- ["bw", "get", "password", name, "--raw", "--session", session, "--nointeraction"],
30
+ [
31
+ "bw",
32
+ "get",
33
+ "password",
34
+ name,
35
+ "--raw",
36
+ "--session",
37
+ session,
38
+ "--nointeraction",
39
+ ],
29
40
  capture_output=True,
30
41
  text=True,
31
42
  )
@@ -1,12 +1,13 @@
1
1
  from __future__ import annotations
2
- import cappa
3
-
4
2
 
5
- from fujin.config import SecretConfig
6
3
  import subprocess
7
-
8
4
  from contextlib import contextmanager
9
- from typing import Generator, TYPE_CHECKING
5
+ from typing import Generator
6
+ from typing import TYPE_CHECKING
7
+
8
+ import cappa
9
+
10
+ from fujin.config import SecretConfig
10
11
 
11
12
  if TYPE_CHECKING:
12
13
  from . import secret_reader
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fujin-cli
3
- Version: 0.7.0
3
+ Version: 0.8.0
4
4
  Summary: Get your project up and running in a few minutes on your own vps.
5
5
  Project-URL: Documentation, https://github.com/falcopackages/fujin#readme
6
6
  Project-URL: Issues, https://github.com/falcopackages/fujin/issues
@@ -0,0 +1,38 @@
1
+ fujin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ fujin/__main__.py,sha256=VJMBzuQuxkQaAKNEySktGnms944bkRsrIAjj-XeaWR8,1813
3
+ fujin/config.py,sha256=FDHCkfAEt6sEjdK1szSCRqCvBfH7LMs_DQeAFHuR6wg,10540
4
+ fujin/connection.py,sha256=LL7LhX9p0X9FmiGdlSroD3Ht216QY0Kd51xkSrXmM3s,2479
5
+ fujin/errors.py,sha256=74Rh-Sgql1YspPdR_akQ2G3xZ48zecyafYCptpaFo1A,73
6
+ fujin/hooks.py,sha256=EDVYNozlDJ5kc1xHtZrXgtuKplUMEMPTp65TLMP02Ek,1449
7
+ fujin/commands/__init__.py,sha256=g0b13vzidPUbxne_Zo_Wv5jpEmwCiSK4AokCinH9uo4,39
8
+ fujin/commands/_base.py,sha256=Rtf7kcO_Pg2JxPNKsXEx0UdhqfzYU6g7IiezC8cqEPQ,2610
9
+ fujin/commands/app.py,sha256=mazb4dCTdR5juh79bL3a9b68Nd6O8u_nR9IgYqQlqWE,5279
10
+ fujin/commands/config.py,sha256=xdfd1OZLxw2YZldiAbW5rq5EBXEaXbUC-I7FKLRfzIQ,2387
11
+ fujin/commands/deploy.py,sha256=UFWraUDx2EmfD_riGq79fCWNGfytCJ9UR_eYKOfDYXY,5945
12
+ fujin/commands/docs.py,sha256=b5FZ8AgoAfn4q4BueEQvM2w5HCuh8-rwBqv_CRFVU8E,349
13
+ fujin/commands/down.py,sha256=aw_mxl_TMC66plKTXwlYP1W2XQBmHeROltQqOpQssyE,1577
14
+ fujin/commands/init.py,sha256=zREfkIQyC6etqqQ6hgvDqpNNWQT4bk_8IOPBBT5-YUE,3983
15
+ fujin/commands/printenv.py,sha256=bpGmOfc1t_dKWb8gy7EILYtwEyI9pIwhKg2XPKyJ9cQ,527
16
+ fujin/commands/proxy.py,sha256=ajXwboS0gDDiMWW7b9rtWU6WPF1h7JYYeycDyU-hQfg,3053
17
+ fujin/commands/prune.py,sha256=C2aAN6AUS84jgRg1eiCroyiuZyaZDmf5yvGAQY9xkcg,1517
18
+ fujin/commands/redeploy.py,sha256=PuXgrEc4fj_88WQXXBBvEtD46IeqzbPeMo-5pDlAuJQ,2363
19
+ fujin/commands/rollback.py,sha256=JsocJzQcdQelSnYD94klhjBh8UKkkdiRD9shfUfo4FI,2032
20
+ fujin/commands/server.py,sha256=-3-PyBNR0fGm-RYE3fz50kP-LSDYGU9BzUxrbGZEghc,3312
21
+ fujin/commands/up.py,sha256=OEK_n-6-mnnIUffFpR7QtVunr1V1F04pxlAAS1U62BY,419
22
+ fujin/process_managers/__init__.py,sha256=MhhfTBhm64zWRAKgjvsZRIToOUJus60vGScbAjqpQ6Y,994
23
+ fujin/process_managers/systemd.py,sha256=qG_4Ew8SEWtaTFOAW_XZXsMO2WjFWZ4dp5nBwAPBObk,5603
24
+ fujin/proxies/__init__.py,sha256=UuWYU175tkdaz1WWRCDDpQgGfFVYYNR9PBxA3lTCNr0,695
25
+ fujin/proxies/caddy.py,sha256=dzLD8s664_kIK-1hCE3y50JIwBd8kK9yS1LynUDRVSE,7908
26
+ fujin/proxies/dummy.py,sha256=qBKSn8XNEA9SVwB7GzRNX2l9Iw6tUjo2CFqZjWi0FjY,465
27
+ fujin/proxies/nginx.py,sha256=BNJNLxLLRVAmBIGVCk8pb16iiSJsOI9jXOZhdSQGtX8,4151
28
+ fujin/secrets/__init__.py,sha256=p4rY4J7yRoEEz6OXkomJ_Ov2AaaQ37-Zd_TJGpUDPgQ,1217
29
+ fujin/secrets/bitwarden.py,sha256=01GZL5hYwZzL6yXy5ab3L3kgBFBeOT8i3Yg9GC8YwFU,2008
30
+ fujin/secrets/onepassword.py,sha256=6Xj3XWttKfcjMbcoMZvXVpJW1KHxlD785DysmX_mqvk,654
31
+ fujin/templates/simple.service,sha256=-lyKjmSyfHGucP4O_vRQE1NNaHq0Qjsc0twdwoRLgI0,321
32
+ fujin/templates/web.service,sha256=NZ7ZeaFvV_MZTBn8QqRQeu8PIrWHf3aWYWNzjOQeqCw,685
33
+ fujin/templates/web.socket,sha256=2lJsiOHlMJL0YlN7YBLLnr5zqsytPEt81yP34nk0dmc,173
34
+ fujin_cli-0.8.0.dist-info/METADATA,sha256=S-SNZujrKy0Omj5KlcHlWSCPynXWrrm-HtLc9fo17BA,4576
35
+ fujin_cli-0.8.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
36
+ fujin_cli-0.8.0.dist-info/entry_points.txt,sha256=Y_TBtKt3j11qhwquMexZR5yqnDEqOBDACtresqQFE-s,46
37
+ fujin_cli-0.8.0.dist-info/licenses/LICENSE.txt,sha256=0QF8XfuH0zkIHhSet6teXfiCze6JSdr8inRkmLLTDyo,1099
38
+ fujin_cli-0.8.0.dist-info/RECORD,,
@@ -1,38 +0,0 @@
1
- fujin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- fujin/__main__.py,sha256=VJMBzuQuxkQaAKNEySktGnms944bkRsrIAjj-XeaWR8,1813
3
- fujin/config.py,sha256=pdWK4fM3BITpz0MAv_ydCXRcQbgC3eLz--APdOpehiQ,10412
4
- fujin/connection.py,sha256=ZkYaNykRFj9Yr-K-vOrZtVVGUDurDm6W7OQrgct71CA,2428
5
- fujin/errors.py,sha256=74Rh-Sgql1YspPdR_akQ2G3xZ48zecyafYCptpaFo1A,73
6
- fujin/hooks.py,sha256=QHIqxLxujG2U70UkN1BpUplE6tTqn7pFJP5oHde1tUQ,1350
7
- fujin/commands/__init__.py,sha256=uIGGXt8YofL5RZn8KIy153ioWGoCl32ffHtqOhB-6ZM,78
8
- fujin/commands/_base.py,sha256=o3R4-c3XeFWTIW3stiUdrcCPwdjzfjUVIpZy2L1-gZ4,2525
9
- fujin/commands/app.py,sha256=mazb4dCTdR5juh79bL3a9b68Nd6O8u_nR9IgYqQlqWE,5279
10
- fujin/commands/config.py,sha256=xdfd1OZLxw2YZldiAbW5rq5EBXEaXbUC-I7FKLRfzIQ,2387
11
- fujin/commands/deploy.py,sha256=SUI_aMqTmaWHVtyX03rjrbWMYESoysAykcvILsEtsWk,5897
12
- fujin/commands/docs.py,sha256=b5FZ8AgoAfn4q4BueEQvM2w5HCuh8-rwBqv_CRFVU8E,349
13
- fujin/commands/down.py,sha256=v1lAq70ApktjeHRB_1sCzjmKH8t6EXqyL4RTt7OE-f0,1716
14
- fujin/commands/init.py,sha256=t8uwwOi4SBqHjV8px_SkTHAeZIiIUJnFN-lf7DK6HhE,3959
15
- fujin/commands/printenv.py,sha256=1xz80UCKpz64wsR9rYStro0K6pkKndNoNQvusEMYRuQ,486
16
- fujin/commands/proxy.py,sha256=ajXwboS0gDDiMWW7b9rtWU6WPF1h7JYYeycDyU-hQfg,3053
17
- fujin/commands/prune.py,sha256=C2aAN6AUS84jgRg1eiCroyiuZyaZDmf5yvGAQY9xkcg,1517
18
- fujin/commands/redeploy.py,sha256=qYPM_Klj_2G1Up4ICu-8rklcqIbU-uohddmAzAA5sy0,2378
19
- fujin/commands/rollback.py,sha256=BN9vOTEBcSSpFIfck9nzWvMVO7asVC20lQbcNrxRchg,2009
20
- fujin/commands/server.py,sha256=0N_P_Luj31t56riZ8GfgRqW3vRHiw0cDrlp3PFoyWn8,3453
21
- fujin/commands/up.py,sha256=DgDN-1mc_mMHJRCIvcB947Cd5a7phunu9NpXloGK0UU,419
22
- fujin/process_managers/__init__.py,sha256=MhhfTBhm64zWRAKgjvsZRIToOUJus60vGScbAjqpQ6Y,994
23
- fujin/process_managers/systemd.py,sha256=qG_4Ew8SEWtaTFOAW_XZXsMO2WjFWZ4dp5nBwAPBObk,5603
24
- fujin/proxies/__init__.py,sha256=UuWYU175tkdaz1WWRCDDpQgGfFVYYNR9PBxA3lTCNr0,695
25
- fujin/proxies/caddy.py,sha256=dzLD8s664_kIK-1hCE3y50JIwBd8kK9yS1LynUDRVSE,7908
26
- fujin/proxies/dummy.py,sha256=qBKSn8XNEA9SVwB7GzRNX2l9Iw6tUjo2CFqZjWi0FjY,465
27
- fujin/proxies/nginx.py,sha256=BNJNLxLLRVAmBIGVCk8pb16iiSJsOI9jXOZhdSQGtX8,4151
28
- fujin/secrets/__init__.py,sha256=WFFe81fB6R3dzdvYsdPT9x-fE2LwpyrfF0nCuWrQNRw,1192
29
- fujin/secrets/bitwarden.py,sha256=rJ_n7CQT02TwwqN9lHQkh56g5BETKhZBtjWi3bOA8rQ,1846
30
- fujin/secrets/onepassword.py,sha256=2ySDY7fNW_sOqH-I89rfz3uMiBu0mJRHot4yKlTRbrE,636
31
- fujin/templates/simple.service,sha256=-lyKjmSyfHGucP4O_vRQE1NNaHq0Qjsc0twdwoRLgI0,321
32
- fujin/templates/web.service,sha256=NZ7ZeaFvV_MZTBn8QqRQeu8PIrWHf3aWYWNzjOQeqCw,685
33
- fujin/templates/web.socket,sha256=2lJsiOHlMJL0YlN7YBLLnr5zqsytPEt81yP34nk0dmc,173
34
- fujin_cli-0.7.0.dist-info/METADATA,sha256=0H7E8Re_jONc6BsoAdATLKM3r8QIrA_lT1oRgG3gWIw,4576
35
- fujin_cli-0.7.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
36
- fujin_cli-0.7.0.dist-info/entry_points.txt,sha256=Y_TBtKt3j11qhwquMexZR5yqnDEqOBDACtresqQFE-s,46
37
- fujin_cli-0.7.0.dist-info/licenses/LICENSE.txt,sha256=0QF8XfuH0zkIHhSet6teXfiCze6JSdr8inRkmLLTDyo,1099
38
- fujin_cli-0.7.0.dist-info/RECORD,,