Describe and prepare your QGIS profiles#

QDT is designed to work with QGIS profiles that allow different configurations (plugins, connections, symbologies, expressions, templates, etc.) to be segmented for different uses on the same installation.

In order to avoid unnecessary duplication of code (typically that of the various plugins) or configuration files and to make deployment reproducible, QDT relies on a profile definition file: profile.json.

QDT expects to find this file in the folder of each profile stored in the source of synchronized profiles in the qprofiles-manager job.

Publish them#

3 options:

  • on a remote Git repository (github.com, gitlab.com, GitLab instance…)

  • on a local Git repository

  • on a web server through HTTP using a qdt-files.json

On an HTTP web server#

Generate the qdt-files.json index file#

Typically on Ubuntu

Install tree:

sudo apt install tree

Run it:

# move to your QDT profiles folder. Here we take the QDT repository as example:
cd examples/
# generate the qdt-files.json
tree --gitignore -D --timefmt="%Y-%m-%dT%H:%M:%S%Z" -s -J -o qdt-files.json .

Detailed explanation:

  • tree: command that displays the directory tree structure.

  • --gitignore: apply gitignore-style rules to exclude files and directories.

  • -D: print the modification time for each file or directory.

  • --timefmt="%Y-%m-%dT%H:%M:%S%Z": specify the time format as ISO8601 with UTC (Coordinated Universal Time).

  • -s: print the size of each file.

  • -J: output the directory tree in JSON format.

  • -o qdt-files.json: save the output to a file named ‘qdt-files.json’.

  • .: specify the current directory as the starting point for the tree.


Typical structure of a project with profiles#

Given 3 profiles to be deployed: avdanced, beginner and readonly. Here comes a typical organization of folders, subfolers and files into your repository:

qgis-profiles/
├── .git/
├── .gitignore
├── LICENSE
├── profiles
│   ├── .gitignore
│   ├── advanced
│      ├── images
│         ├── profile_advanced.ico
│         └── splash.png
│      ├── profile.json
│      └── QGIS
│          ├── QGIS3.ini
│   ├── beginner
│      ├── images
│         ├── profile_beginner.ico
│         └── splash.png
│      ├── profile.json
│      └── QGIS
│          ├── QGIS3.ini
│          └── QGISCUSTOMIZATION3.ini
│   └── readonly       ├── bookmarks.xml
│       ├── images
│          └── profile_readonly.ico
│       ├── profile.json
│       ├── project_default.qgs
│       └── QGIS
│           └── QGIS3.ini
│           └── QGISCUSTOMIZATION3.ini
├── qdt
│   └── scenario.qdt.yml
├── README.md

Good practices and recomendations#

  • if you use a Git repository, store profiles in a subfolder not at the project root and specify the relative path in scenario

  • do not store the entire profile folder, but only files that contans something specific to your profile (use a .gitignore file - see below)

  • keep only the lines of *.ini files which are custom to your profile:

    • QGIS will fill them automatically if needed

    • it reduces the surface of possible conflicts when dealing to upgrade a profile

Use a .gitignore file to exclude folders and files with patterns#

What and why#

A QGIS profile folder often contains a bunch of files. Some of these files might be temporary or generated automatically by your computer or QGIS, and you don’t really want to include them when you’re sharing your profile with others or storing it in a version control system like Git.

That’s where the .gitignore file comes in. It’s a special file that you can create in your profile folder, and it lists the names or patterns of files that you want Git (and compatible softwares) to ignore. When you tell Git to ignore certain files, it won’t track them or include them when you share or save your profile.

For example, if your profile involves plugins or automatically generated preview images (projects thumbnails), you might want to ignore most of theses files and the other ones like compiled binaries or scripts (typically *.pyc…), log files, or temporary build files. By adding these file names or patterns to your .gitignore file, you keep your profile clean and avoid cluttering it with files that aren’t essential for others to understand and work on your profile.

In summary, the .gitignore file helps you manage which files Git should ignore and not include when you’re tracking changes in your profile. It’s a helpful tool for keeping your version control system tidy and focused on the important parts of your work.

How#

  1. Create a .gitignore in your QDT folder

  2. Add a file or folder path or pattern to exclude by line

Typical .gitignore content:

# -- QDT usual patterns --

# Common
!.gitkeep
*.log

# QGIS Profiles
profiles/*/python/plugins/
profiles/*/previewImages/
*.db
*.*~
*.*~

Resources#


Model definition#

The project comes with a JSON schema describing the model of a profile:

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$id": "https://github.com/Guts/qgis-deployment-cli/raw/main/docs/schemas/profile/qgis_profile.json",
    "$comment": "A QGIS profile described in a JSON file.",
    "type": "object",
    "properties": {
        "alias": {
            "description": "Profile's name in an human readable form, allowing special characters.",
            "type": "string"
        },
        "author": {
            "description": "Name of profile auhor and maintener.",
            "type": "string"
        },
        "description": {
            "description": "Profile description.",
            "type": "string"
        },
        "email": {
            "description": "Email of profile's auhor and maintener.",
            "format": "email",
            "maxLength": 127,
            "minLength": 6,
            "type": "string"
        },
        "folder_name": {
            "description": "Name of the profile's directory in QGIS.",
            "pattern": "^([a-zA-Z]:)?(\\\\[^<>:\"/\\\\|?*]+)+\\\\?$",
            "type": "string"
        },
        "icon": {
            "description": "Relative path to the icon used for shortcuts.",
            "type": "string"
        },
        "name": {
            "description": "Profile name without any special characters.",
            "pattern": "^[_a-zA-Z][a-zA-Z0-9_-]*$"
        },
        "plugins": {
            "description": "Plugins installed with the profile.",
            "title": "QGIS Plugins",
            "type": "array",
            "items": {
                "$ref": "qgis_plugin.json"
            }
        },
        "qgisMaximumVersion": {
            "description": "Maximum QGIS version where the profile can be deployed.",
            "maxLength": 14,
            "minLength": 5,
            "pattern": "^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)$",
            "type": "string"
        },
        "qgisMinimumVersion": {
            "description": "Minimum QGIS version where the profile can be deployed.",
            "maxLength": 14,
            "minLength": 5,
            "pattern": "^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)$",
            "type": "string"
        },
        "splash": {
            "description": "Relative path to the splash image.",
            "type": "string"
        },
        "version": {
            "description": "Profile version. Must complies with SemVer.",
            "maxLength": 14,
            "minLength": 5,
            "pattern": "^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)$",
            "type": "string"
        }
    },
    "required": [
        "author",
        "email",
        "name",
        "version"
    ]
}

With a submodel for plugin object:

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$id": "https://raw.githubusercontent.com/Guts/qgis-deployment-cli/main/docs/schemas/profile/qgis_plugin.json",
    "$comment": "A QGIS plugin described in a JSON file.",
    "type": "object",
    "properties": {
        "folder_name": {
            "description": "Name of the plugins's directory once installed in QGIS. Useful when name does not complies with filename conventions.",
            "pattern": "^([a-zA-Z]:)?(\\\\[^<>:\"/\\\\|?*]+)+\\\\?$",
            "type": "string"
        },
        "location": {
            "description": "Indicates if the plugin is located on a remote server or on local drive/network.",
            "enum": [
                "local",
                "remote"
            ],
            "type": "string"
        },
        "name": {
            "description": "Plugin name, as referenced in the source plugins repository.",
            "type": "string"
        },
        "official_repository": {
            "description": "Indicates if the plugin is referenced on plugins.qgis.org",
            "type": "boolean"
        },
        "plugin_id": {
            "description": "Plugin ID as referenced into the repository (XML version). Typically for official repository: https://plugins.qgis.org/plugins/plugins.xml?qgis=3.22",
            "type": "number"
        },
        "qgisMaximumVersion": {
            "description": "Maximum QGIS version where the plugin can be installed.",
            "maxLength": 14,
            "minLength": 5,
            "pattern": "^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)$",
            "type": "string"
        },
        "qgisMinimumVersion": {
            "description": "Minimum QGIS version where the plugin can be installed.",
            "maxLength": 14,
            "minLength": 5,
            "pattern": "^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)$",
            "type": "string"
        },
        "repository_url_xml": {
            "description": "URL to the plugin repository file (XML).",
            "type": "string"
        },
        "type": {
            "enum": [
                "local",
                "remote"
            ],
            "deprecated": true,
            "type": "string"
        },
        "url": {
            "description": "Direct URI (URL or local path) to download the plugin archive (.zip).",
            "type": "string",
            "format": "uri",
            "examples": [
                "https: //plugins.qgis.org/plugins/QuickOSM/version/2.2.2/download/",
                "/home/jmo/Git/Oslandia/QGIS/stsi-plugin-qgis-geocoder-locator-filter/stsi_locator_filter.1.0.0.zip"
            ]
        },
        "version": {
            "description": "Plugin version to install.",
            "maxLength": 14,
            "minLength": 5,
            "pattern": "^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)$",
            "type": "string"
        }
    }
}

Tip

To retrieve the ID of a plugin see this page.


Sample profile.json#

{
    "$schema": "https://raw.githubusercontent.com/Guts/qgis-deployment-cli/main/docs/schemas/profile/qgis_profile.json",
    "name": "demo_qdt",
    "folder_name": "demo_qdt",
    "description": "QGIS profile made to demonstrate how QGIS Deployement Toolbelt works.",
    "author": "Julien Moura",
    "email": "qgis@oslandia.com",
    "icon": "images/qgis_icon_oslandia.ico",
    "qgisMinimumVersion": "3.24",
    "qgisMaximumVersion": "3.99",
    "version": "1.1.0",
    "plugins": [
        {
            "name": "Layers menu from project",
            "folder_name": "menu_from_project",
            "official_repository": true,
            "plugin_id": 43,
            "version": "2.1.0"
        },
        {
            "name": "QuickOSM",
            "folder_name": "QuickOSM",
            "location": "remote",
            "official_repository": true,
            "plugin_id": 2733,
            "version": "2.1.1"
        },
        {
            "name": "QTribu",
            "folder_name": "qtribu",
            "official_repository": true,
            "plugin_id": 2733,
            "version": "0.14.2"
        }
    ]
}