That’s a fantastic question. There’s definitely no straightforward way to make this happen automatically (unfortunately).
But I can think of a few viable workarounds …
Option 1: During ‘bench get-app’ and ‘bench install-app’
When these 2 commands are run, whatever Bench and Frappe Framework are doing? That’s largely out of our control.
But there -is- something thing we can control: our App’s 'pyproject.toml'
configuration file.
- We can add additional Python dependencies (perhaps your custom daemon)
- We can teach our App’s package to run custom code/scripts during installation. For example:
[project.scripts]
my-install-script = "my_package.my_module:post_install_function"
Then write a 'post_install_function()'
to accomplish whatever you need. Downloading files from the internet, create directories, running Bash scripts, building system unit files, etc.
Here’s a good guide on ‘pyproject.toml’
Configuring setuptools using pyproject.toml files - setuptools 74.1.2.post20240906 documentation
Option 2: During module import.
Whenever the Python runtime loads our App’s Python module, the code in __init__.py
is executed. Normally in '__init__.py'
we’d add things like global variables, functions, or classes. But we could also just run code whenever that file is loaded. Code that does “installation stuff”.
""" __init__.py """
import frappe
__version__ = '0.1.0'
def do_post_installation_things():
print("I'm going to examine directories, and make sure things are installed and configured."
print("If they are not, I'm going to automatically fix them.")
do_post_installation_things() # this calls the function whenever __init__.py is loaded
Granted, this solution is a bit clunky and will be surprising to other developers. Also, your function do_post_installation_things()
is going to be called many times, often somewhat out of your control. So you’ll need to be careful. Make sure it’s safe for the function to be repeatedly called, but only actually install stuff when it’s truly missing (so it doesn’t slow down the system). But this would work.
Option 3: By altering your App’s ‘hooks.py’
The ‘hooks.py’ code is being imported and run all the time (possibly too-often, but that’s a topic for another day). Because you can count on it being run, you could add your post-installation steps in there. Either by just calling a function like I did in Option 2. Or by configuring a scheduler, to check for things automatically:
# Every 5 minutes, make sure everything is installed the way it's supposed to be.
scheduler_events = {
"cron": {
"0/5 * * * *": [
"my_app.my_module.check_for_installed_things",
]
}
}