diff --git a/.devcontainer/.devrequirements/install-editable-requirements.sh b/.devcontainer/.devrequirements/install-editable-requirements.sh new file mode 100755 index 00000000..2fed61dc --- /dev/null +++ b/.devcontainer/.devrequirements/install-editable-requirements.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Defaults +GEONODE_BRANCH="master" +MAPSTORE_BRANCH="master" + +usage() { + echo "Usage: $0 [-g|--geonode-branch ] [-m|--mapstore-branch ]" + echo "" + echo " -g, --geonode-branch Branch/tag for geonode/geonode (default: master)" + echo " -m, --mapstore-branch Branch/tag for GeoNode/geonode-mapstore-client (default: master)" + echo " -h, --help Show this help message" + exit 1 +} + +# Parse options +while [[ $# -gt 0 ]]; do + case "$1" in + -g|--geonode-branch) + GEONODE_BRANCH="$2" + shift 2 + ;; + -m|--mapstore-branch) + MAPSTORE_BRANCH="$2" + shift 2 + ;; + -h|--help) + usage + ;; + *) + echo "Unknown option: $1" + usage + ;; + esac +done + +# Parent devrequirements directory +DEV_REQ_DIR="/usr/src/.devrequirements" + +# repo_name | folder_name | git_url | egg_name | branch +REPOS=( + "geonode|geonode|https://github.com/GeoNode/geonode.git|geonode|${GEONODE_BRANCH}" + "geonode-mapstore-client|django-geonode-mapstore-client|https://github.com/GeoNode/geonode-mapstore-client.git|django_geonode_mapstore_client|${MAPSTORE_BRANCH}" +) + +for entry in "${REPOS[@]}"; do + IFS='|' read -r name folder url egg branch <<< "$entry" + + echo ">>> Installing ${name} @ ${branch}" + + # Safely remove the specific subfolder if it exists + rm -rf "${DEV_REQ_DIR}/${folder}" + + # Install + yes w | pip install --src "$DEV_REQ_DIR" -e "git+${url}@${branch}#egg=${egg}" + + # Fix ownership + chown -R 1000:1000 "${DEV_REQ_DIR}/${folder}" +done \ No newline at end of file diff --git a/.devcontainer/.gitignore b/.devcontainer/.gitignore new file mode 100644 index 00000000..27eb1c54 --- /dev/null +++ b/.devcontainer/.gitignore @@ -0,0 +1,2 @@ +.devrequirements/django-geonode-mapstore-client +.devrequirements/geonode diff --git a/.devcontainer/.vscode/launch.json b/.devcontainer/.vscode/launch.json index 8aa448c3..26c54833 100644 --- a/.devcontainer/.vscode/launch.json +++ b/.devcontainer/.vscode/launch.json @@ -14,7 +14,7 @@ "0.0.0.0:8000" ], "env": { - "ASYNC_SIGNALS": "True", + "ASYNC_SIGNALS": "False", }, "django": true, "autoStartBrowser": false, @@ -95,6 +95,24 @@ "autoStartBrowser": false, "program": "${workspaceFolder}/venv/bin/celery", "justMyCode": false - } + }, + { + "name": "Example test", + "type": "debugpy", + "request": "launch", + "args": [ + "test", + "geonode.base.api.tests.BaseApiTests", + "--keepdb" + ], + "env": { + "ASYNC_SIGNALS": "False", + "SAFE_URL_CHECK_ENABLED": "False" + }, + "django": true, + "autoStartBrowser": false, + "program": "${workspaceFolder}/project/manage.py", + "justMyCode": false + }, ] } \ No newline at end of file diff --git a/.devcontainer/README.md b/.devcontainer/README.md new file mode 100644 index 00000000..fde66a43 --- /dev/null +++ b/.devcontainer/README.md @@ -0,0 +1,38 @@ +# Dev Container + +A development setup for working on GeoNode inside Docker, with VS Code debugging ready to go. + +## 1. Start the containers + +```bash +cd ./.devcontainer +./docker.sh build +./docker.sh up -d +``` + +`docker.sh` is a thin wrapper that loads `../.env` and runs `docker compose` with both the base `docker-compose.yml` and this folder's override. + +Then, in VS Code, open the Command Palette (`Ctrl+Shift+P`, or `Ctrl+P` and type `>`) and run **Dev Containers: Reopen in Container** to attach the editor to the running container. + +## 2. Services start idle + +The `django` and `celery` containers start **without** their services running (their command is `sleep infinity` in `docker-compose.yml`). This lets you exec into a container and start the services yourself, so you stay in control of when and how they run. + +## 3. Debugging from VS Code + +The container ships preconfigured with the Python extension and VS Code settings (`.vscode/launch.json`) ready to launch **Django** and **Celery** debug sessions. + +- The containers run **synchronously** (`ASYNC_SIGNALS` is `False`). +- You can also start Django the plain way instead of the debugger: + + ```bash + django-admin runserver 0.0.0.0:8000 + ``` + +## 4. Editable GeoNode / mapstore-client + +`geonode` and `geonode-mapstore-client` are installed in the venv like a standard GeoNode deployment. + +To work on them in **editable** mode, the `.devrequirements/` folder (mounted at `/usr/src/.devrequirements`) contains `install-editable-requirements.sh` (take care of making it executable with `chmod +x`), which installs both packages as editable git checkouts into that folder. + +The `docker-compose.yml` override also prepends `PYTHONPATH` with those paths. Because the editable packages live in the mounted folder, the installation is **retained across container restarts and rebuilds**. diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 4522b9e8..d784c630 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -4,6 +4,7 @@ services: volumes: - './src:/usr/src/project' - './.devcontainer/.vscode:/usr/src/.vscode' + - './.devcontainer/.devrequirements:/usr/src/.devrequirements' - statics:/mnt/volumes/statics - geoserver-data-dir:/geoserver_data/data - backup-restore:/backup_restore @@ -12,7 +13,12 @@ services: healthcheck: test: "echo 'Alive'" entrypoint: ["/usr/src/project/entrypoint.sh"] + environment: + - ASYNC_SIGNALS=False + - PYTHONPATH=/usr/src/.devrequirements/geonode:/usr/src/.devrequirements/geonode-mapstore-client command: sleep infinity celery: entrypoint: ["/usr/src/project/entrypoint.sh"] + environment: + - PYTHONPATH=/usr/src/.devrequirements/geonode:/usr/src/.devrequirements/geonode-mapstore-client command: sleep infinity