fujin-cli 0.10.0__tar.gz → 0.11.5__tar.gz
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.
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/CHANGELOG.md +42 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/PKG-INFO +3 -2
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/secrets.rst +30 -9
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/tutorial.rst +48 -37
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/pyproject.toml +8 -5
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/__main__.py +2 -2
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/commands/init.py +1 -1
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/config.py +46 -41
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/secrets/__init__.py +7 -1
- fujin_cli-0.11.5/src/fujin/secrets/system.py +19 -0
- fujin_cli-0.11.5/src/fujin/templates/granian/web.service +22 -0
- {fujin_cli-0.10.0/src/fujin/templates → fujin_cli-0.11.5/src/fujin/templates/gunicorn}/web.service +2 -2
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/templates/simple.service +2 -1
- fujin_cli-0.11.5/src/fujin/templates/web.service +22 -0
- fujin_cli-0.11.5/src/fujin/templates/web.socket +11 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/uv.lock +4 -3
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/.github/workflows/publish.yml +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/.gitignore +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/.pre-commit-config.yaml +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/.readthedocs.yaml +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/LICENSE.txt +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/README.md +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/Vagrantfile +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/changelog.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/commands/app.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/commands/config.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/commands/deploy.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/commands/docs.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/commands/down.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/commands/index.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/commands/init.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/commands/printenv.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/commands/proxy.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/commands/prune.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/commands/redeploy.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/commands/rollback.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/commands/server.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/commands/up.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/conf.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/configuration.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/hooks.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/index.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/installation.rst +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/docs/requirements.txt +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/examples/django/bookstore/README.md +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/examples/django/bookstore/bookstore/__init__.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/examples/django/bookstore/bookstore/__main__.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/examples/django/bookstore/bookstore/asgi.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/examples/django/bookstore/bookstore/settings.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/examples/django/bookstore/bookstore/urls.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/examples/django/bookstore/bookstore/wsgi.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/examples/django/bookstore/fujin.toml +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/examples/django/bookstore/manage.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/examples/django/bookstore/pyproject.toml +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/examples/django/bookstore/requirements.txt +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/examples/golang/pocketbase/.env.prod +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/examples/golang/pocketbase/fujin.toml +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/justfile +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/__init__.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/commands/__init__.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/commands/_base.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/commands/app.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/commands/config.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/commands/deploy.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/commands/docs.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/commands/down.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/commands/printenv.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/commands/proxy.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/commands/prune.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/commands/redeploy.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/commands/rollback.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/commands/server.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/commands/up.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/connection.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/errors.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/hooks.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/proxies/__init__.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/proxies/caddy.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/proxies/dummy.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/proxies/nginx.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/secrets/bitwarden.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/secrets/dopppler.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/secrets/onepassword.py +0 -0
- {fujin_cli-0.10.0 → fujin_cli-0.11.5}/src/fujin/systemd.py +0 -0
- {fujin_cli-0.10.0/src/fujin/templates → fujin_cli-0.11.5/src/fujin/templates/gunicorn}/web.socket +0 -0
|
@@ -4,6 +4,48 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.11.4] - 2025-03-08
|
|
8
|
+
|
|
9
|
+
### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- No mutable default
|
|
12
|
+
|
|
13
|
+
## [0.11.3] - 2025-03-08
|
|
14
|
+
|
|
15
|
+
### Cfeat
|
|
16
|
+
|
|
17
|
+
- Add fujin version info
|
|
18
|
+
|
|
19
|
+
## [0.11.2] - 2025-03-08
|
|
20
|
+
|
|
21
|
+
### 🚀 Features
|
|
22
|
+
|
|
23
|
+
- Set system as the default secrets adapter
|
|
24
|
+
|
|
25
|
+
## [0.11.1] - 2025-03-08
|
|
26
|
+
|
|
27
|
+
### 🐛 Bug Fixes
|
|
28
|
+
|
|
29
|
+
- Env content parse logic
|
|
30
|
+
|
|
31
|
+
## [0.11.0] - 2025-03-08
|
|
32
|
+
|
|
33
|
+
### 🚀 Features
|
|
34
|
+
|
|
35
|
+
- Add system secret reader
|
|
36
|
+
|
|
37
|
+
### 🚜 Refactor
|
|
38
|
+
|
|
39
|
+
- Rename env_content to env
|
|
40
|
+
|
|
41
|
+
### 📚 Documentation
|
|
42
|
+
|
|
43
|
+
- Apply a more consitent writing style
|
|
44
|
+
|
|
45
|
+
### ⚙️ Miscellaneous Tasks
|
|
46
|
+
|
|
47
|
+
- Specify source package to avoid failing build backend
|
|
48
|
+
|
|
7
49
|
## [0.10.0] - 2024-11-24
|
|
8
50
|
|
|
9
51
|
### 🚀 Features
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: fujin-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.5
|
|
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
|
|
7
7
|
Project-URL: Source, https://github.com/falcopackages/fujin
|
|
8
8
|
Author-email: Tobi DEGNON <tobidegnon@proton.me>
|
|
9
|
+
License-File: LICENSE.txt
|
|
9
10
|
Keywords: caddy,deployment,django,fastapi,litestar,python,systemd
|
|
10
11
|
Classifier: Development Status :: 3 - Alpha
|
|
11
12
|
Classifier: Intended Audience :: Developers
|
|
@@ -1,24 +1,43 @@
|
|
|
1
1
|
Secrets
|
|
2
2
|
=======
|
|
3
3
|
|
|
4
|
+
System
|
|
5
|
+
------
|
|
6
|
+
|
|
7
|
+
The system adapter uses environment variables directly from your system. This is the simplest adapter and requires no additional setup.
|
|
8
|
+
Update your fujin.toml file with the following configuration:
|
|
9
|
+
|
|
10
|
+
[secrets]
|
|
11
|
+
adapter = "system"
|
|
12
|
+
|
|
13
|
+
.. code-block:: text
|
|
14
|
+
:caption: Example of an environment file with system environment variables
|
|
15
|
+
|
|
16
|
+
DEBUG=False
|
|
17
|
+
AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID
|
|
18
|
+
AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY
|
|
19
|
+
|
|
20
|
+
The system adapter will look for environment variables with the same name as the value after the $ sign.
|
|
21
|
+
|
|
4
22
|
Bitwarden
|
|
5
23
|
---------
|
|
6
24
|
|
|
7
25
|
First, download and install the `Bitwarden CLI <https://bitwarden.com/help/cli/#download-and-install>`_. Make sure to log in to your account.
|
|
8
26
|
You should be able to run ``bw get password <name_of_secret>`` and get the value for the secret. This is the command that will be executed when pulling your secrets.
|
|
9
27
|
|
|
10
|
-
Add the following to your
|
|
28
|
+
Add the following to your **fujin.toml** file:
|
|
11
29
|
|
|
12
|
-
.. code-block:: toml
|
|
30
|
+
.. code-block:: toml
|
|
31
|
+
:caption: fujin.toml
|
|
13
32
|
|
|
14
33
|
[secrets]
|
|
15
34
|
adapter = "bitwarden"
|
|
16
35
|
password_env = "BW_PASSWORD"
|
|
17
36
|
|
|
18
|
-
To unlock the Bitwarden vault, the password is required.
|
|
19
|
-
When
|
|
37
|
+
To unlock the Bitwarden vault, the password is required. Set the *BW_PASSWORD* environment variable in your shell.
|
|
38
|
+
When ``fujin`` signs in, it will always sync the vault first.
|
|
20
39
|
|
|
21
|
-
Alternatively, you can set the
|
|
40
|
+
Alternatively, you can set the *BW_SESSION* environment variable. If *BW_SESSION* is present, ``fujin`` will use it directly without signing in or syncing the vault. In this case, the *password_env* configuration is not required.
|
|
22
41
|
|
|
23
42
|
.. code-block:: text
|
|
24
43
|
:caption: Example of an environment file with Bitwarden secrets
|
|
@@ -27,7 +46,7 @@ Alternatively, you can set the ``BW_SESSION`` environment variable. If ``BW_SESS
|
|
|
27
46
|
AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID
|
|
28
47
|
AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY
|
|
29
48
|
|
|
30
|
-
Note the
|
|
49
|
+
Note the *$* sign, which indicates to ``fujin`` that it is a secret.
|
|
31
50
|
|
|
32
51
|
1Password
|
|
33
52
|
---------
|
|
@@ -35,9 +54,10 @@ Note the ``$`` sign, which indicates to ``fujin`` that it is a secret.
|
|
|
35
54
|
Download and install the `1Password CLI <https://developer.1password.com/docs/cli>`_, and sign in to your account.
|
|
36
55
|
You need to be actively signed in for Fujin to work with 1Password.
|
|
37
56
|
|
|
38
|
-
Update your
|
|
57
|
+
Update your **fujin.toml** file with the following configuration:
|
|
39
58
|
|
|
40
|
-
.. code-block:: toml
|
|
59
|
+
.. code-block:: toml
|
|
60
|
+
:caption: fujin.toml
|
|
41
61
|
|
|
42
62
|
[secrets]
|
|
43
63
|
adapter = "1password"
|
|
@@ -55,9 +75,10 @@ Doppler
|
|
|
55
75
|
Download and install the `Doppler CLI <https://docs.doppler.com/docs/cli>`_, and sign in to your account.
|
|
56
76
|
Move to your project root directory and run ``doppler setup`` to configure your project.
|
|
57
77
|
|
|
58
|
-
Update your
|
|
78
|
+
Update your **fujin.toml** file with the following configuration:
|
|
59
79
|
|
|
60
80
|
.. code-block:: toml
|
|
81
|
+
:caption: fujin.toml
|
|
61
82
|
|
|
62
83
|
[secrets]
|
|
63
84
|
adapter = "doppler"
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
Tutorial
|
|
2
2
|
========
|
|
3
3
|
|
|
4
|
+
In this tutorial, you will deploy a Django project or a PocketBase binary (in binary mode) to a Linux server running Ubuntu using the ``fujin`` CLI.
|
|
5
|
+
|
|
4
6
|
First, make sure you follow the `installation </installation.html>`_ instructions and have the ``fujin`` command available globally in your shell.
|
|
5
|
-
``fujin`` allows you to interact with your remote server and your deployed apps from your local shell.
|
|
6
7
|
|
|
7
8
|
Prerequisites
|
|
8
9
|
-------------
|
|
@@ -48,9 +49,10 @@ Let's start by installing and initializing a simple Django project.
|
|
|
48
49
|
The ``uv init --package`` command makes your project mostly ready to be used with ``fujin``. It initializes a `packaged application <https://docs.astral.sh/uv/concepts/projects/#packaged-applications>`_ using uv,
|
|
49
50
|
meaning the app can be packaged and distributed (e.g: via PyPI) and defines an entry point, which are the two requirements of ``fujin``.
|
|
50
51
|
|
|
51
|
-
This is the content you'll get in the
|
|
52
|
+
This is the content you'll get in the **pyproject.toml** file, with the relevant parts highlighted.
|
|
52
53
|
|
|
53
54
|
.. code-block:: toml
|
|
55
|
+
:caption: fujin.toml
|
|
54
56
|
:linenos:
|
|
55
57
|
:emphasize-lines: 15-16,18-20
|
|
56
58
|
|
|
@@ -75,38 +77,39 @@ This is the content you'll get in the ``pyproject.toml`` file, with the relevant
|
|
|
75
77
|
requires = ["hatchling"]
|
|
76
78
|
build-backend = "hatchling.build"
|
|
77
79
|
|
|
78
|
-
The
|
|
80
|
+
The *build-system* section is what allows us to build our project into a wheel file (Python package format), and the *project.scripts* defines a CLI entry point for our app.
|
|
79
81
|
This means that if our app is installed (either with ``pip install`` or ``uv tool install``, for example), there will be a ``bookstore`` command available globally on our system to run the project.
|
|
80
82
|
|
|
81
83
|
.. note::
|
|
82
84
|
|
|
83
|
-
If you are installing it in a virtual environment, then there will be a file
|
|
84
|
-
When it deploys your Python project, it sets up and installs a virtual environment in the app directory in a
|
|
85
|
+
If you are installing it in a virtual environment, then there will be a file **.venv/bin/bookstore** that will run this CLI entry point. This is what ``fujin`` expects internally.
|
|
86
|
+
When it deploys your Python project, it sets up and installs a virtual environment in the app directory in a **.venv** folder and expects this entry point to be able to run
|
|
85
87
|
commands with the ``fujin app exec <command>`` command.
|
|
86
88
|
|
|
87
|
-
Currently, our entry point will run the main function in the
|
|
89
|
+
Currently, our entry point will run the main function in the **src/bookstore/__init__.py** file. Let's change that.
|
|
88
90
|
|
|
89
91
|
.. code-block:: shell
|
|
90
92
|
|
|
91
93
|
rm -r src
|
|
92
94
|
mv manage.py bookstore/__main__.py
|
|
93
95
|
|
|
94
|
-
We first remove the
|
|
96
|
+
We first remove the **src** folder, as we won't use that since our Django project will reside in the top-level **bookstore** folder. I also recommend keeping all
|
|
95
97
|
your Django code in that folder, including new apps, as this makes things easier for packaging purposes.
|
|
96
|
-
Then we move the
|
|
98
|
+
Then we move the **manage.py** file to the **bookstore** folder and rename it to **__main__.py**. This enables us to do this:
|
|
97
99
|
|
|
98
100
|
.. code-block:: shell
|
|
99
101
|
|
|
100
102
|
uv run bookstore migrate # equivalent to python manage.py migrate if we kept the manage.py file
|
|
101
103
|
|
|
102
|
-
Now to finish, update the
|
|
104
|
+
Now to finish, update the *scripts* section in your **pyproject.toml** file.
|
|
103
105
|
|
|
104
106
|
.. code-block:: toml
|
|
107
|
+
:caption: fujin.toml
|
|
105
108
|
|
|
106
109
|
[project.scripts]
|
|
107
110
|
bookstore = "bookstore.__main__:main"
|
|
108
111
|
|
|
109
|
-
Now the CLI that will be installed with your project will do the job of the
|
|
112
|
+
Now the CLI that will be installed with your project will do the job of the **manage.py** file. To test this out, run the following commands:
|
|
110
113
|
|
|
111
114
|
.. code-block:: shell
|
|
112
115
|
|
|
@@ -134,6 +137,7 @@ Now that our project is ready, run ``fujin init`` at the root of it.
|
|
|
134
137
|
Here's what you'll get:
|
|
135
138
|
|
|
136
139
|
.. code-block:: toml
|
|
140
|
+
:caption: fujin.toml
|
|
137
141
|
|
|
138
142
|
app = "bookstore"
|
|
139
143
|
build_command = "uv build && uv pip compile pyproject.toml -o requirements.txt"
|
|
@@ -160,6 +164,7 @@ Here's what you'll get:
|
|
|
160
164
|
Update the host section; it should look something like this, but with your server IP:
|
|
161
165
|
|
|
162
166
|
.. code-block:: toml
|
|
167
|
+
:caption: fujin.toml
|
|
163
168
|
|
|
164
169
|
[host]
|
|
165
170
|
domain_name = "SERVER_IP.sslip.io"
|
|
@@ -170,10 +175,11 @@ Update the host section; it should look something like this, but with your serve
|
|
|
170
175
|
|
|
171
176
|
Make sure to replace ``SERVER_IP`` with the actual IP address of your server.
|
|
172
177
|
|
|
173
|
-
Create a
|
|
174
|
-
Update your
|
|
178
|
+
Create a **.env.prod** file at the root of your project; it can be an empty file for now. The only requirement is that the file should exist.
|
|
179
|
+
Update your **bookstore/settings.py** with the changes below:
|
|
175
180
|
|
|
176
181
|
.. code-block:: python
|
|
182
|
+
:caption: settings.py
|
|
177
183
|
|
|
178
184
|
# SECURITY WARNING: don't run with debug turned on in production!
|
|
179
185
|
DEBUG = False
|
|
@@ -182,9 +188,10 @@ Update your ``bookstore/settings.py`` with the changes below:
|
|
|
182
188
|
|
|
183
189
|
With the current setup, we should already be able to deploy our app with the ``fujin up`` command, but static files won't work. Let's make some changes.
|
|
184
190
|
|
|
185
|
-
Update
|
|
191
|
+
Update **bookstore/settings.py** with the changes below:
|
|
186
192
|
|
|
187
193
|
.. code-block:: python
|
|
194
|
+
:caption: settings.py
|
|
188
195
|
:linenos:
|
|
189
196
|
:lineno-start: 118
|
|
190
197
|
:emphasize-lines: 119
|
|
@@ -194,7 +201,7 @@ Update ``bookstore/settings.py`` with the changes below:
|
|
|
194
201
|
|
|
195
202
|
The last line means that when the ``collectstatic`` command is run, the files will be placed in a **staticfiles** directory in the current directory.
|
|
196
203
|
|
|
197
|
-
Now let's update the
|
|
204
|
+
Now let's update the **fujin.toml** file to run ``collectstatic`` before the app is started and move these files to the folder where our web server
|
|
198
205
|
can read them:
|
|
199
206
|
|
|
200
207
|
.. code-block:: toml
|
|
@@ -232,10 +239,11 @@ For this tutorial, we will use `pocketbase <https://github.com/pocketbase/pocket
|
|
|
232
239
|
curl -LO https://github.com/pocketbase/pocketbase/releases/download/v0.22.26/pocketbase_0.22.26_linux_amd64.zip
|
|
233
240
|
fujin init --profile binary
|
|
234
241
|
|
|
235
|
-
With the instructions above, we will download a version of Pocketbase to run on Linux from their GitHub release and initialize a new fujin configuration in
|
|
236
|
-
Now update the
|
|
242
|
+
With the instructions above, we will download a version of Pocketbase to run on Linux from their GitHub release and initialize a new fujin configuration in *binary* mode.
|
|
243
|
+
Now update the **fujin.toml** file with the changes below:
|
|
237
244
|
|
|
238
245
|
.. code-block:: toml
|
|
246
|
+
:caption: fujin.toml
|
|
239
247
|
:linenos:
|
|
240
248
|
:emphasize-lines: 2-5,9,13,19-21
|
|
241
249
|
|
|
@@ -263,25 +271,26 @@ Now update the ``fujin.toml`` file with the changes below:
|
|
|
263
271
|
|
|
264
272
|
.. caution::
|
|
265
273
|
|
|
266
|
-
Make sure to replace
|
|
274
|
+
Make sure to replace *SERVER_IP* with the actual IP address of your server.
|
|
267
275
|
|
|
268
276
|
Create User
|
|
269
277
|
-----------
|
|
270
278
|
|
|
271
|
-
Currently, we have the user set to **root** in our
|
|
279
|
+
Currently, we have the user set to **root** in our **fujin.toml** file and ``fujin`` might work with the root user, but I've noticed some issues with it, so I highly recommend creating a custom user.
|
|
272
280
|
For that, you'll need the root user with SSH access set up on the server.
|
|
273
|
-
Then you'll run the command ``fujin server create-user`` with the username you want to use. You can, for example, use
|
|
274
|
-
For example:
|
|
281
|
+
Then you'll run the command ``fujin server create-user`` with the username you want to use. You can, for example, use *fujin* as the username.
|
|
275
282
|
|
|
276
283
|
.. code-block:: shell
|
|
284
|
+
:caption: create-user example
|
|
277
285
|
|
|
278
286
|
fujin server create-user fujin
|
|
279
287
|
|
|
280
288
|
This will create a new **fujin** user on your server, add it to the ``sudo`` group with the option to run all commands without having to type a password, and will
|
|
281
289
|
copy the authorized key from the **root** to your new user so that the SSH setup you made for the root user still works with this new one.
|
|
282
|
-
Now update the
|
|
290
|
+
Now update the **fujin.toml** file with the new user:
|
|
283
291
|
|
|
284
292
|
.. code-block:: toml
|
|
293
|
+
:caption: fujin.toml
|
|
285
294
|
|
|
286
295
|
[host]
|
|
287
296
|
domain_name = "SERVER_IP.sslip.io"
|
|
@@ -298,31 +307,33 @@ Now that your project is ready, run the commands below to deploy for the first t
|
|
|
298
307
|
fujin up
|
|
299
308
|
|
|
300
309
|
The first time, the process can take a few minutes. At the end of it, you should have a link to your deployed app.
|
|
301
|
-
A few notable commands:
|
|
302
310
|
|
|
303
|
-
..
|
|
304
|
-
:
|
|
311
|
+
.. admonition:: A few notable commands
|
|
312
|
+
:class: note dropdown
|
|
305
313
|
|
|
306
|
-
|
|
314
|
+
.. code-block:: shell
|
|
315
|
+
:caption: Deploy an app on a host where ``fujin`` has already been set up
|
|
307
316
|
|
|
308
|
-
|
|
317
|
+
fujin deploy
|
|
309
318
|
|
|
310
|
-
|
|
311
|
-
:caption: Export the systemd config being used so that you can edit them
|
|
319
|
+
You also use the ``deploy`` command when you have changed the ``fujin`` config or exported configs:
|
|
312
320
|
|
|
313
|
-
|
|
321
|
+
.. code-block:: shell
|
|
322
|
+
:caption: Export the systemd config being used so that you can edit them
|
|
314
323
|
|
|
315
|
-
|
|
316
|
-
:caption: Export the webserver config, in this case, caddy
|
|
324
|
+
fujin app export-config
|
|
317
325
|
|
|
318
|
-
|
|
326
|
+
.. code-block:: shell
|
|
327
|
+
:caption: Export the webserver config, in this case, caddy
|
|
319
328
|
|
|
320
|
-
|
|
329
|
+
fujin proxy export-config
|
|
321
330
|
|
|
322
|
-
|
|
323
|
-
|
|
331
|
+
and the command you'll probably be running the most:
|
|
332
|
+
|
|
333
|
+
.. code-block:: shell
|
|
334
|
+
:caption: When you've only made code and envfile related changes
|
|
324
335
|
|
|
325
|
-
|
|
336
|
+
fujin redeploy
|
|
326
337
|
|
|
327
338
|
FAQ
|
|
328
339
|
---
|
|
@@ -333,5 +344,5 @@ What about my database?
|
|
|
333
344
|
I'm currently using SQLite for my side projects, so this isn't an issue for me at the moment. That's why ``fujin`` does not currently assist with databases.
|
|
334
345
|
However, you can still SSH into your server and manually install PostgreSQL or any other database or services you need.
|
|
335
346
|
|
|
336
|
-
I plan to add support for managing additional tools like Redis or databases by declaring containers via the
|
|
347
|
+
I plan to add support for managing additional tools like Redis or databases by declaring containers via the **fujin.toml** file. These containers will be managed with ``podman``,
|
|
337
348
|
To follow the development of this feature, subscribe to this `issue <https://github.com/falcopackages/fujin/issues/17>`_.
|
|
@@ -7,7 +7,7 @@ requires = [
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "fujin-cli"
|
|
10
|
-
version = "0.
|
|
10
|
+
version = "0.11.5"
|
|
11
11
|
description = "Get your project up and running in a few minutes on your own vps."
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
keywords = [
|
|
@@ -72,9 +72,7 @@ docs = [
|
|
|
72
72
|
]
|
|
73
73
|
|
|
74
74
|
[tool.hatch.build.targets.wheel]
|
|
75
|
-
packages = [
|
|
76
|
-
"src/fujin",
|
|
77
|
-
]
|
|
75
|
+
packages = [ "src/fujin" ]
|
|
78
76
|
|
|
79
77
|
[tool.ruff]
|
|
80
78
|
# Assume Python {{ python_version }}
|
|
@@ -154,7 +152,7 @@ lint.isort.required-imports = [
|
|
|
154
152
|
lint.pyupgrade.keep-runtime-typing = true
|
|
155
153
|
|
|
156
154
|
[tool.bumpversion]
|
|
157
|
-
current_version = "0.
|
|
155
|
+
current_version = "0.11.5"
|
|
158
156
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
|
159
157
|
serialize = [
|
|
160
158
|
"{major}.{minor}.{patch}",
|
|
@@ -178,6 +176,11 @@ filename = "pyproject.toml"
|
|
|
178
176
|
search = 'version = "{current_version}"'
|
|
179
177
|
replace = 'version = "{new_version}"'
|
|
180
178
|
|
|
179
|
+
[[tool.bumpversion.files]]
|
|
180
|
+
filename = "src/fujin/__main__.py"
|
|
181
|
+
replace = 'version="{new_version}"'
|
|
182
|
+
search = 'version="{current_version}"'
|
|
183
|
+
|
|
181
184
|
[tool.mypy]
|
|
182
185
|
check_untyped_defs = true
|
|
183
186
|
exclude = [
|
|
@@ -50,9 +50,9 @@ class Fujin:
|
|
|
50
50
|
def main():
|
|
51
51
|
alias_cmd = _parse_aliases()
|
|
52
52
|
if alias_cmd:
|
|
53
|
-
cappa.invoke(Fujin, argv=alias_cmd)
|
|
53
|
+
cappa.invoke(Fujin, argv=alias_cmd, version="0.11.5")
|
|
54
54
|
else:
|
|
55
|
-
cappa.invoke(Fujin)
|
|
55
|
+
cappa.invoke(Fujin, version="0.11.5")
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
def _parse_aliases() -> list[str] | None:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Fujin uses a
|
|
2
|
+
Fujin uses a **fujin.toml** file at the root of your project for configuration. Below are all available configuration options.
|
|
3
3
|
|
|
4
4
|
app
|
|
5
5
|
---
|
|
@@ -7,16 +7,16 @@ The name of your project or application. Must be a valid Python package name.
|
|
|
7
7
|
|
|
8
8
|
version
|
|
9
9
|
--------
|
|
10
|
-
The version of your project to build and deploy. If not specified, automatically parsed from
|
|
10
|
+
The version of your project to build and deploy. If not specified, automatically parsed from **pyproject.toml** under *project.version*.
|
|
11
11
|
|
|
12
12
|
python_version
|
|
13
13
|
--------------
|
|
14
|
-
The Python version for your virtualenv. If not specified, automatically parsed from
|
|
15
|
-
required if the installation mode is set to
|
|
14
|
+
The Python version for your virtualenv. If not specified, automatically parsed from **.python-version** file. This is only
|
|
15
|
+
required if the installation mode is set to **python-package**
|
|
16
16
|
|
|
17
17
|
requirements
|
|
18
18
|
------------
|
|
19
|
-
Optional path to your requirements file. This will only be used when the installation mode is set to
|
|
19
|
+
Optional path to your requirements file. This will only be used when the installation mode is set to *python-package*
|
|
20
20
|
|
|
21
21
|
versions_to_keep
|
|
22
22
|
----------------
|
|
@@ -30,32 +30,28 @@ The command to use to build your project's distribution file.
|
|
|
30
30
|
distfile
|
|
31
31
|
--------
|
|
32
32
|
Path to your project's distribution file. This should be the main artifact containing everything needed to run your project on the server.
|
|
33
|
-
Supports version placeholder, e.g.,
|
|
33
|
+
Supports version placeholder, e.g., **dist/app_name-{version}-py3-none-any.whl**
|
|
34
34
|
|
|
35
35
|
installation_mode
|
|
36
36
|
-----------------
|
|
37
37
|
|
|
38
|
-
Indicates whether the
|
|
39
|
-
The
|
|
40
|
-
|
|
38
|
+
Indicates whether the *distfile* is a Python package or a self-contained executable. The possible values are *python-package* and *binary*.
|
|
39
|
+
The *binary* option disables specific Python-related features, such as virtual environment creation and requirements installation. ``fujin`` will assume the provided
|
|
40
|
+
*distfile* already contains all the necessary dependencies to run your program.
|
|
41
41
|
|
|
42
42
|
release_command
|
|
43
43
|
---------------
|
|
44
|
-
Optional command to run at the end of deployment (e.g., database migrations).
|
|
44
|
+
Optional command to run at the end of deployment (e.g., database migrations) before your application is started.
|
|
45
45
|
|
|
46
46
|
secrets
|
|
47
47
|
-------
|
|
48
48
|
|
|
49
|
-
Optional secrets configuration. If set,
|
|
49
|
+
Optional secrets configuration. If set, ``fujin`` will load secrets from the specified secret management service.
|
|
50
50
|
Check out the `secrets </secrets.html>`_ page for more information.
|
|
51
51
|
|
|
52
52
|
adapter
|
|
53
53
|
~~~~~~~
|
|
54
|
-
The secret management service to use.
|
|
55
|
-
|
|
56
|
-
- ``bitwarden``
|
|
57
|
-
- ``1password``
|
|
58
|
-
- ``doppler``
|
|
54
|
+
The secret management service to use. The currently available options are *bitwarden*, *1password*, *doppler*
|
|
59
55
|
|
|
60
56
|
password_env
|
|
61
57
|
~~~~~~~~~~~~
|
|
@@ -64,35 +60,39 @@ Environment variable containing the password for the service account. This is on
|
|
|
64
60
|
Webserver
|
|
65
61
|
---------
|
|
66
62
|
|
|
63
|
+
Web server configurations.
|
|
64
|
+
|
|
67
65
|
type
|
|
68
66
|
~~~~
|
|
69
67
|
The reverse proxy implementation to use. Available options:
|
|
70
68
|
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
69
|
+
- *fujin.proxies.caddy* (default)
|
|
70
|
+
- *fujin.proxies.nginx*
|
|
71
|
+
- *fujin.proxies.dummy* (disables proxy)
|
|
74
72
|
|
|
75
73
|
upstream
|
|
76
74
|
~~~~~~~~
|
|
77
75
|
The address where your web application listens for requests. Supports any value compatible with your chosen web proxy:
|
|
78
76
|
|
|
79
|
-
- HTTP address (e.g.,
|
|
80
|
-
- Unix socket (e.g.,
|
|
77
|
+
- HTTP address (e.g., *localhost:8000* )
|
|
78
|
+
- Unix socket caddy (e.g., *unix//run/project.sock* )
|
|
79
|
+
- Unix socket nginx (e.g., *http://unix:/run/project.sock* )
|
|
81
80
|
|
|
82
81
|
certbot_email
|
|
83
82
|
~~~~~~~~~~~~~
|
|
84
|
-
Required when Nginx is used as a proxy
|
|
83
|
+
Required when Nginx is used as a proxy to obtain SSL certificates.
|
|
85
84
|
|
|
86
85
|
statics
|
|
87
86
|
~~~~~~~
|
|
88
87
|
|
|
89
88
|
Defines the mapping of URL paths to local directories for serving static files. The syntax and support for static
|
|
90
89
|
file serving depend on the selected reverse proxy. The directories you map should be accessible by the web server, meaning
|
|
91
|
-
with read permissions for the
|
|
90
|
+
with read permissions for the *www-data* group; a reliable choice is **/var/www**.
|
|
92
91
|
|
|
93
92
|
Example:
|
|
94
93
|
|
|
95
94
|
.. code-block:: toml
|
|
95
|
+
:caption: fujin.toml
|
|
96
96
|
|
|
97
97
|
[webserver]
|
|
98
98
|
upstream = "unix//run/project.sock"
|
|
@@ -103,12 +103,12 @@ processes
|
|
|
103
103
|
---------
|
|
104
104
|
|
|
105
105
|
A mapping of process names to commands that will be managed by the process manager. Define as many processes as needed, but
|
|
106
|
-
when using any proxy other than
|
|
107
|
-
setting on the host to understand how ``app_dir`` is determined.
|
|
106
|
+
when using any proxy other than *fujin.proxies.dummy*, a *web* process must be declared.
|
|
108
107
|
|
|
109
108
|
Example:
|
|
110
109
|
|
|
111
110
|
.. code-block:: toml
|
|
111
|
+
:caption: fujin.toml
|
|
112
112
|
|
|
113
113
|
[processes]
|
|
114
114
|
web = ".venv/bin/gunicorn myproject.wsgi:application"
|
|
@@ -116,7 +116,8 @@ Example:
|
|
|
116
116
|
|
|
117
117
|
.. note::
|
|
118
118
|
|
|
119
|
-
Commands are relative to your
|
|
119
|
+
Commands are relative to your *app_dir*. When generating systemd service files, the full path is automatically constructed.
|
|
120
|
+
Refer to the *apps_dir* setting on the host to understand how *app_dir* is determined.
|
|
120
121
|
Here are the templates for the service files:
|
|
121
122
|
|
|
122
123
|
- `web.service <https://github.com/falcopackages/fujin/blob/main/src/fujin/templates/web.service>`_
|
|
@@ -128,7 +129,7 @@ Host Configuration
|
|
|
128
129
|
|
|
129
130
|
ip
|
|
130
131
|
~~
|
|
131
|
-
The IP address or anything that resolves to the remote host IP's. This is use to communicate via ssh with the server, if omitted it's value will default to the one of the
|
|
132
|
+
The IP address or anything that resolves to the remote host IP's. This is use to communicate via ssh with the server, if omitted it's value will default to the one of the *domain_name*.
|
|
132
133
|
|
|
133
134
|
domain_name
|
|
134
135
|
~~~~~~~~~~~
|
|
@@ -142,23 +143,23 @@ The login user for running remote tasks. Should have passwordless sudo access fo
|
|
|
142
143
|
|
|
143
144
|
You can create a user with these requirements using the ``fujin server create-user`` command.
|
|
144
145
|
|
|
145
|
-
|
|
146
|
-
|
|
146
|
+
envfile
|
|
147
|
+
~~~~~~~
|
|
147
148
|
Path to the production environment file that will be copied to the host.
|
|
148
149
|
|
|
149
|
-
|
|
150
|
-
|
|
150
|
+
env
|
|
151
|
+
~~~
|
|
151
152
|
A string containing the production environment variables, ideal for scenarios where most variables are retrieved from secrets and you prefer not to use a separate file.
|
|
152
153
|
|
|
153
154
|
.. important::
|
|
154
155
|
|
|
155
|
-
|
|
156
|
+
*envfile* and *env* are mutually exclusive—you can define only one.
|
|
156
157
|
|
|
157
158
|
apps_dir
|
|
158
159
|
~~~~~~~~
|
|
159
160
|
|
|
160
161
|
Base directory for project storage on the host. Path is relative to user's home directory.
|
|
161
|
-
Default:
|
|
162
|
+
Default: **.local/share/fujin**. This value determines your project's **app_dir**, which is **{apps_dir}/{app}**.
|
|
162
163
|
|
|
163
164
|
password_env
|
|
164
165
|
~~~~~~~~~~~~
|
|
@@ -168,8 +169,7 @@ Environment variable containing the user's password. Only needed if the user can
|
|
|
168
169
|
ssh_port
|
|
169
170
|
~~~~~~~~
|
|
170
171
|
|
|
171
|
-
SSH port for connecting to the host.
|
|
172
|
-
Default: ``22``
|
|
172
|
+
SSH port for connecting to the host. Default to **22**.
|
|
173
173
|
|
|
174
174
|
key_filename
|
|
175
175
|
~~~~~~~~~~~~
|
|
@@ -184,6 +184,7 @@ A mapping of shortcut names to Fujin commands. Allows you to create convenient s
|
|
|
184
184
|
Example:
|
|
185
185
|
|
|
186
186
|
.. code-block:: toml
|
|
187
|
+
:caption: fujin.toml
|
|
187
188
|
|
|
188
189
|
[aliases]
|
|
189
190
|
console = "app exec -i shell_plus" # open an interactive django shell
|
|
@@ -223,6 +224,7 @@ class SecretAdapter(StrEnum):
|
|
|
223
224
|
BITWARDEN = "bitwarden"
|
|
224
225
|
ONE_PASSWORD = "1password"
|
|
225
226
|
DOPPLER = "doppler"
|
|
227
|
+
SYSTEM = "system"
|
|
226
228
|
|
|
227
229
|
|
|
228
230
|
class SecretConfig(msgspec.Struct):
|
|
@@ -246,7 +248,10 @@ class Config(msgspec.Struct, kw_only=True):
|
|
|
246
248
|
requirements: str | None = None
|
|
247
249
|
hooks: HooksDict = msgspec.field(default_factory=dict)
|
|
248
250
|
local_config_dir: Path = Path(".fujin")
|
|
249
|
-
secret_config: SecretConfig | None = msgspec.field(
|
|
251
|
+
secret_config: SecretConfig | None = msgspec.field(
|
|
252
|
+
name="secrets",
|
|
253
|
+
default_factory=lambda: SecretConfig(adapter=SecretAdapter.SYSTEM),
|
|
254
|
+
)
|
|
250
255
|
|
|
251
256
|
def __post_init__(self):
|
|
252
257
|
if self.installation_mode == InstallationMode.PY_PACKAGE:
|
|
@@ -285,8 +290,8 @@ class HostConfig(msgspec.Struct, kw_only=True):
|
|
|
285
290
|
ip: str | None = None
|
|
286
291
|
domain_name: str
|
|
287
292
|
user: str
|
|
288
|
-
_env_file: str = msgspec.field(name="envfile", default=
|
|
289
|
-
env_content: str = ""
|
|
293
|
+
_env_file: str | None = msgspec.field(name="envfile", default=None)
|
|
294
|
+
env_content: str | None = msgspec.field(name="env", default=None)
|
|
290
295
|
apps_dir: str = ".local/share/fujin"
|
|
291
296
|
password_env: str | None = None
|
|
292
297
|
ssh_port: int = 22
|
|
@@ -295,14 +300,14 @@ class HostConfig(msgspec.Struct, kw_only=True):
|
|
|
295
300
|
def __post_init__(self):
|
|
296
301
|
if self._env_file and self.env_content:
|
|
297
302
|
raise ImproperlyConfiguredError(
|
|
298
|
-
"Cannot set both '
|
|
303
|
+
"Cannot set both 'env' and 'envfile' properties."
|
|
299
304
|
)
|
|
300
|
-
if
|
|
305
|
+
if self._env_file:
|
|
301
306
|
envfile = Path(self._env_file)
|
|
302
307
|
if not envfile.exists():
|
|
303
308
|
raise ImproperlyConfiguredError(f"{self._env_file} not found")
|
|
304
309
|
self.env_content = envfile.read_text()
|
|
305
|
-
self.env_content = self.env_content.strip()
|
|
310
|
+
self.env_content = self.env_content.strip() if self.env_content else ""
|
|
306
311
|
self.apps_dir = f"/home/{self.user}/{self.apps_dir}"
|
|
307
312
|
self.ip = self.ip or self.domain_name
|
|
308
313
|
|
|
@@ -12,11 +12,13 @@ from fujin.config import SecretConfig
|
|
|
12
12
|
from .bitwarden import bitwarden
|
|
13
13
|
from .dopppler import doppler
|
|
14
14
|
from .onepassword import one_password
|
|
15
|
+
from .system import system
|
|
15
16
|
|
|
16
17
|
secret_reader = Callable[[str], str]
|
|
17
18
|
secret_adapter_context = Callable[[SecretConfig], ContextManager[secret_reader]]
|
|
18
19
|
|
|
19
20
|
adapter_to_context: dict[SecretAdapter, secret_adapter_context] = {
|
|
21
|
+
SecretAdapter.SYSTEM: system,
|
|
20
22
|
SecretAdapter.BITWARDEN: bitwarden,
|
|
21
23
|
SecretAdapter.ONE_PASSWORD: one_password,
|
|
22
24
|
SecretAdapter.DOPPLER: doppler,
|
|
@@ -24,6 +26,8 @@ adapter_to_context: dict[SecretAdapter, secret_adapter_context] = {
|
|
|
24
26
|
|
|
25
27
|
|
|
26
28
|
def resolve_secrets(env_content: str, secret_config: SecretConfig) -> str:
|
|
29
|
+
if not env_content: # this is really for empty string
|
|
30
|
+
return ""
|
|
27
31
|
with closing(StringIO(env_content)) as buffer:
|
|
28
32
|
env_dict = dotenv_values(stream=buffer)
|
|
29
33
|
secrets = {key: value for key, value in env_dict.items() if value.startswith("$")}
|
|
@@ -33,7 +37,9 @@ def resolve_secrets(env_content: str, secret_config: SecretConfig) -> str:
|
|
|
33
37
|
parsed_secrets = {}
|
|
34
38
|
with adapter_context(secret_config) as reader:
|
|
35
39
|
for key, secret in secrets.items():
|
|
36
|
-
parsed_secrets[key] = gevent.spawn(
|
|
40
|
+
parsed_secrets[key] = gevent.spawn(
|
|
41
|
+
reader, secret[1:]
|
|
42
|
+
) # remove the leading $
|
|
37
43
|
gevent.joinall(parsed_secrets.values())
|
|
38
44
|
env_dict.update({key: thread.value for key, thread in parsed_secrets.items()})
|
|
39
45
|
return "\n".join(f'{key}="{value}"' for key, value in env_dict.items())
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from contextlib import contextmanager
|
|
5
|
+
from typing import Generator
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from fujin.config import SecretConfig
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from . import secret_reader
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@contextmanager
|
|
15
|
+
def system(_: SecretConfig) -> Generator[secret_reader, None, None]:
|
|
16
|
+
try:
|
|
17
|
+
yield os.getenv
|
|
18
|
+
finally:
|
|
19
|
+
pass
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# All options are documented here https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html
|
|
2
|
+
# Inspiration was taken from here https://docs.gunicorn.org/en/stable/deploy.html#systemd
|
|
3
|
+
[Unit]
|
|
4
|
+
Description={app_name} daemon
|
|
5
|
+
After=network.target
|
|
6
|
+
|
|
7
|
+
[Service]
|
|
8
|
+
User={user}
|
|
9
|
+
Group={user}
|
|
10
|
+
RuntimeDirectory={app_name}
|
|
11
|
+
WorkingDirectory={app_dir}
|
|
12
|
+
ExecStart={app_dir}/{command}
|
|
13
|
+
EnvironmentFile={app_dir}/.env
|
|
14
|
+
ExecReload=/bin/kill -s HUP $MAINPID
|
|
15
|
+
KillMode=mixed
|
|
16
|
+
TimeoutStopSec=5
|
|
17
|
+
PrivateTmp=true
|
|
18
|
+
# if your app does not need administrative capabilities, let systemd know
|
|
19
|
+
ProtectSystem=strict
|
|
20
|
+
|
|
21
|
+
[Install]
|
|
22
|
+
WantedBy=multi-user.target
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# All options are documented here https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html
|
|
2
|
+
# Inspiration was taken from here https://docs.gunicorn.org/en/stable/deploy.html#systemd
|
|
3
|
+
[Unit]
|
|
4
|
+
Description={app_name} daemon
|
|
5
|
+
After=network.target
|
|
6
|
+
|
|
7
|
+
[Service]
|
|
8
|
+
User={user}
|
|
9
|
+
Group={user}
|
|
10
|
+
RuntimeDirectory={app_name}
|
|
11
|
+
WorkingDirectory={app_dir}
|
|
12
|
+
ExecStart={app_dir}/{command}
|
|
13
|
+
EnvironmentFile={app_dir}/.env
|
|
14
|
+
ExecReload=/bin/kill -s HUP $MAINPID
|
|
15
|
+
KillMode=mixed
|
|
16
|
+
TimeoutStopSec=5
|
|
17
|
+
PrivateTmp=true
|
|
18
|
+
# if your app does not need administrative capabilities, let systemd know
|
|
19
|
+
ProtectSystem=strict
|
|
20
|
+
|
|
21
|
+
[Install]
|
|
22
|
+
WantedBy=multi-user.target
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
version = 1
|
|
2
|
+
revision = 1
|
|
2
3
|
requires-python = ">=3.10"
|
|
3
4
|
|
|
4
5
|
[manifest]
|
|
@@ -304,7 +305,7 @@ name = "click"
|
|
|
304
305
|
version = "8.1.7"
|
|
305
306
|
source = { registry = "https://pypi.org/simple" }
|
|
306
307
|
dependencies = [
|
|
307
|
-
{ name = "colorama", marker = "
|
|
308
|
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
308
309
|
]
|
|
309
310
|
sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 }
|
|
310
311
|
wheels = [
|
|
@@ -477,7 +478,7 @@ wheels = [
|
|
|
477
478
|
|
|
478
479
|
[[package]]
|
|
479
480
|
name = "fujin-cli"
|
|
480
|
-
version = "0.
|
|
481
|
+
version = "0.11.4"
|
|
481
482
|
source = { editable = "." }
|
|
482
483
|
dependencies = [
|
|
483
484
|
{ name = "cappa" },
|
|
@@ -586,7 +587,7 @@ wheels = [
|
|
|
586
587
|
[package.optional-dependencies]
|
|
587
588
|
recommended = [
|
|
588
589
|
{ name = "cffi", marker = "platform_python_implementation == 'CPython'" },
|
|
589
|
-
{ name = "psutil", marker = "
|
|
590
|
+
{ name = "psutil", marker = "platform_python_implementation == 'CPython' or sys_platform != 'win32'" },
|
|
590
591
|
]
|
|
591
592
|
|
|
592
593
|
[[package]]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fujin_cli-0.10.0/src/fujin/templates → fujin_cli-0.11.5/src/fujin/templates/gunicorn}/web.socket
RENAMED
|
File without changes
|