diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 14b78b0..8036bea 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -7,7 +7,7 @@
"features": {
"ghcr.io/devcontainers/features/python:1": {
"installTools": true,
- "version": "3.13.0"
+ "version": "3.13.2"
}
},
"customizations": {
diff --git a/.github/actions/python/action.yml b/.github/actions/python/action.yml
index e101b14..774aa44 100644
--- a/.github/actions/python/action.yml
+++ b/.github/actions/python/action.yml
@@ -23,7 +23,7 @@ runs:
- name: Set up Python
uses: actions/setup-python@v3
with:
- python-version: '3.13.0'
+ python-version: '3.13.2'
- name: Install Dependencies
shell: bash
run: |
diff --git a/.github/actions/tests/action.yml b/.github/actions/tests/action.yml
index 97805a3..d267fca 100644
--- a/.github/actions/tests/action.yml
+++ b/.github/actions/tests/action.yml
@@ -8,7 +8,7 @@ runs:
- name: Set up Python
uses: actions/setup-python@v3
with:
- python-version: '3.13.0'
+ python-version: '3.13.2'
- name: Install dependencies
shell: bash
run: |
diff --git a/Dockerfile b/Dockerfile
index fd258fa..695426b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
ARG BASE_IMAGE=python
-ARG BASE_IMAGE_TAG=3.13.0-slim-bookworm
+ARG BASE_IMAGE_TAG=3.13.2-slim-bookworm
FROM ${BASE_IMAGE}:${BASE_IMAGE_TAG}
diff --git a/Makefile b/Makefile
index 3eef2ba..0ea5a7a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
## DOCKER BUILD VARS
BASE_IMAGE=python
-BASE_IMAGE_TAG=3.13.0-slim-bookworm
+BASE_IMAGE_TAG=3.13.2-slim-bookworm
IMAGE_NAME=homeylab/bookstack-file-exporter
# keep this start sequence unique (IMAGE_TAG=)
# github actions will use this to create a tag
diff --git a/README.md b/README.md
index a7487cf..710424a 100644
--- a/README.md
+++ b/README.md
@@ -87,7 +87,7 @@ assets:
The exporter can be installed via pip and run directly.
#### Python Version
-_Note: This application is tested and developed on Python version `3.13.X`. The min required version is >= `3.8` but is recommended to install (or set up a venv) a `3.13.X` version._
+_Note: This application is tested and developed on Python version `3.13.2`. The min required version is >= `3.8` but is recommended to install (or set up a venv) a `3.13.2` version._
#### Examples
```bash
@@ -150,6 +150,11 @@ docker run \
homeylab/bookstack-file-exporter:latest
```
+#### Docker Compose
+When using the configuration option: `run_interval`, a docker compose set up could be used to run the exporter as an always running application. The exporter will sleep and wait until `{run_interval}` seconds has elapsed before subsequent runs.
+
+An example is shown in `examples/docker-compose.yaml`
+
#### Environment Variables
See [Valid Environment Variables](#valid-environment-variables) for more options.
@@ -256,6 +261,7 @@ More descriptions can be found for each section below:
| `assets.export_meta` | `bool` | `false` | Optional (default: `false`), export of metadata about the page in a json file |
| `assets.verify_ssl` | `bool` | `false` | Optional (default: `true`), whether or not to check ssl certificates when requesting content from Bookstack host |
| `keep_last` | `int` | `false` | Optional (default: `None`), if exporter can delete older archives. valid values are:
- set to `-1` if you want to delete all archives after each run (useful if you only want to upload to object storage)
- set to `1+` if you want to retain a certain number of archives
- `0` will result in no action done |
+| `run_interval` | `int` | `false` | Optional (default: `0`). If specified, exporter will run in a loop and pause for `{run_interval}` seconds before subsequent runs. Example: `86400` seconds = `24` hours or run once a day. Setting this property to `0` will disable looping |
| `minio` | `object` | `false` | Optional [Minio](#minio-backups) configuration options. |
#### Valid Environment Variables
diff --git a/bookstack_file_exporter/__main__.py b/bookstack_file_exporter/__main__.py
index d91a0df..38fd292 100644
--- a/bookstack_file_exporter/__main__.py
+++ b/bookstack_file_exporter/__main__.py
@@ -9,7 +9,7 @@ def main():
args: argparse.Namespace = run_args.get_args()
logging.basicConfig(format='%(asctime)s [%(levelname)s] %(message)s',
level=run_args.get_log_level(args.log_level), datefmt='%Y-%m-%d %H:%M:%S')
- run.exporter(args)
+ run.entrypoint(args)
if __name__ == '__main__':
diff --git a/bookstack_file_exporter/config_helper/config_helper.py b/bookstack_file_exporter/config_helper/config_helper.py
index 80b822f..e89a861 100644
--- a/bookstack_file_exporter/config_helper/config_helper.py
+++ b/bookstack_file_exporter/config_helper/config_helper.py
@@ -57,8 +57,6 @@ def __init__(self, args: argparse.Namespace):
self._token_id, self._token_secret = self._generate_credentials()
self._headers = self._generate_headers()
self._urls = self._generate_urls()
- self._minio_access_key = ""
- self._minio_secret_key = ""
self._object_storage_config = self._generate_remote_config()
def _generate_config(self, config_file: str) -> models.UserInput:
diff --git a/bookstack_file_exporter/config_helper/models.py b/bookstack_file_exporter/config_helper/models.py
index e82e5da..153296e 100644
--- a/bookstack_file_exporter/config_helper/models.py
+++ b/bookstack_file_exporter/config_helper/models.py
@@ -36,7 +36,7 @@ class UserInput(BaseModel):
credentials: Optional[BookstackAccess] = None
formats: List[Literal["markdown", "html", "pdf", "plaintext"]]
output_path: Optional[str] = None
- # export_meta: Optional[bool] = None
assets: Optional[Assets] = Assets()
minio: Optional[ObjectStorageConfig] = None
keep_last: Optional[int] = None
+ run_interval: Optional[int] = 0
\ No newline at end of file
diff --git a/bookstack_file_exporter/run.py b/bookstack_file_exporter/run.py
index b69a35b..547760f 100644
--- a/bookstack_file_exporter/run.py
+++ b/bookstack_file_exporter/run.py
@@ -1,6 +1,7 @@
import argparse
import sys
import logging
+import time
from typing import Dict
from bookstack_file_exporter.config_helper.config_helper import ConfigNode
@@ -10,10 +11,20 @@
log = logging.getLogger(__name__)
-def exporter(args: argparse.Namespace):
- """export bookstack nodes and archive locally and/or remotely"""
- ## get configuration from helper
+def entrypoint(args: argparse.Namespace):
+ """entrypoint for export process"""
+ # get configuration from helper
config = ConfigNode(args)
+ if config.user_inputs.run_interval:
+ while True:
+ exporter(config)
+ log.info(f"Waiting {config.user_inputs.run_interval} seconds for next run")
+ # sleep process state
+ time.sleep(config.user_inputs.run_interval)
+ exporter(config)
+
+def exporter(config: ConfigNode):
+ """export bookstack nodes and archive locally and/or remotely"""
## convenience vars
bookstack_headers = config.headers
diff --git a/examples/config.yml b/examples/config.yml
index cca6602..07df0bb 100644
--- a/examples/config.yml
+++ b/examples/config.yml
@@ -52,3 +52,8 @@ output_path: "bkps/"
# set to 1+ if you want to retain a certain number of archives
# set to 0 or comment out section if you want no action done
keep_last: 5
+## optional - if specified exporter will run in a loop
+# it will run and then pause for {run_interval} seconds before running again
+# specify in seconds, example: 86400 seconds = 24 hours or run once a day
+# omit/commit out or set to 0 if you just want a single run and exit
+run_interval: 0
\ No newline at end of file
diff --git a/examples/docker-compose.yaml b/examples/docker-compose.yaml
new file mode 100644
index 0000000..23fd82a
--- /dev/null
+++ b/examples/docker-compose.yaml
@@ -0,0 +1,18 @@
+name: bookstack-file-exporter
+services:
+ bookstack-file-exporter:
+ image: homeylab/bookstack-file-exporter:latest
+ # use a uid/gid that has permissions to write to local dump directory
+ user: 1000:1000
+ container_name: bookstack-file-exporter
+ environment:
+ - LOG_LEVEL=info
+ # example volumes shown
+ # change the left side of the ':' to your preferred files/dir
+ volumes:
+ - /opt/bookstack/bkps/config.yml:/export/config/config.yml:ro
+ - /opt/bookstack/bkps/archives:/export/dump
+ # can also pass env variables as a file
+ env_file:
+ - bkp.env
+ restart: always
\ No newline at end of file
diff --git a/examples/minio_config.yml b/examples/minio_config.yml
index 3b36a08..56efe9d 100644
--- a/examples/minio_config.yml
+++ b/examples/minio_config.yml
@@ -82,4 +82,9 @@ clean_up: true
# - this is useful if you only want to upload to object storage
# set to 1+ if you want to retain a certain number of archives
# set to 0 or comment out section if you want no action done
-keep_last: -1
\ No newline at end of file
+keep_last: -1
+## optional - if specified exporter will run in a loop
+# it will run and then pause for {run_interval} seconds before running again
+# specify in seconds, example: 86400 seconds = 24 hours or run once a day
+# omit/commit out or set to 0 if you just want a single run and exit
+run_interval: 0
\ No newline at end of file
diff --git a/setup.cfg b/setup.cfg
index 2cc3992..4c25490 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -18,9 +18,9 @@ classifiers =
python_requires = >=3.8
install_requires =
Pyyaml >= 6.0.2 # https://pypi.org/project/PyYAML/
- Pydantic >= 2.9.2 # https://docs.pydantic.dev/latest/
+ Pydantic >= 2.10.6 # https://docs.pydantic.dev/latest/
requests >= 2.32.3 # https://pypi.org/project/requests/
- minio >= 7.2.10 # https://pypi.org/project/minio/
+ minio >= 7.2.15 # https://pypi.org/project/minio/
packages = find:
[options.entry_points]