Compare commits

...

No commits in common. "pre_qt4_port" and "master" have entirely different histories.

34824 changed files with 12872677 additions and 744891 deletions

55
.ci/config.ctest Normal file
View File

@ -0,0 +1,55 @@
SET (CTEST_SOURCE_DIRECTORY $ENV{CTEST_SOURCE_DIR})
SET (CTEST_BINARY_DIRECTORY $ENV{CTEST_BUILD_DIR})
#SET (CTEST_SOURCE_DIRECTORY /usr/src/QGIS)
#SET (CTEST_BINARY_DIRECTORY /usr/src/qgis-build)
SET (CTEST_CMAKE_COMMAND "cmake")
SET (CTEST_BUILD_COMMAND $ENV{CTEST_BUILD_COMMAND})
SET (CTEST_SITE "github.com")
SET (CTEST_BUILD_NAME "$ENV{CTEST_BUILD_NAME}")
SET (CTEST_BUILD_CONFIGURATION "Release")
SET (CTEST_TEST_TIMEOUT 90) # 90 seconds
IF(DEFINED ENV{CTEST_PARALLEL_LEVEL})
SET(PARALLEL_LEVEL $ENV{CTEST_PARALLEL_LEVEL})
ELSE(DEFINED ENV{CTEST_PARALLEL_LEVEL})
SET(PARALLEL_LEVEL 2)
ENDIF(DEFINED ENV{CTEST_PARALLEL_LEVEL})
SET (INITIAL_CACHE "
BUILDNAME:STRING=${CTEST_BUILD_NAME}
SITE:STRING=${CTEST_SITE}
CTEST_USE_LAUNCHERS:BOOL=ON
")
SET (CTEST_NOTES_FILES
${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}
${CTEST_BINARY_DIRECTORY}/CMakeCache.txt
)
IF(NOT WIN32)
STRING(ASCII 27 Esc)
SET(ColorReset "${Esc}[m")
SET(ColorBold "${Esc}[1m")
SET(Red "${Esc}[31m")
SET(Green "${Esc}[32m")
SET(Yellow "${Esc}[33m")
SET(Blue "${Esc}[34m")
SET(Magenta "${Esc}[35m")
SET(Cyan "${Esc}[36m")
SET(White "${Esc}[37m")
SET(BoldRed "${Esc}[1;31m")
SET(BoldGreen "${Esc}[1;32m")
SET(BoldYellow "${Esc}[1;33m")
SET(BoldBlue "${Esc}[1;34m")
SET(BoldMagenta "${Esc}[1;35m")
SET(BoldCyan "${Esc}[1;36m")
SET(BoldWhite "${Esc}[1;37m")
ENDIF(NOT WIN32)
# Create link to test results
# CDash on OTB requires the date to be set for the search to work (used to be UTC-6, seems to be UTC now)
SET(ENV{TZ} "UTC")
EXECUTE_PROCESS(COMMAND date +%Y-%m-%d OUTPUT_VARIABLE CDASH_DATE)
SET(RESULT_LINK "http://cdash.orfeo-toolbox.org/index.php?project=QGIS&filtercount=1&showfilters=1&field1=buildname/string&compare1=63&value1=$ENV{CTEST_BUILD_NAME}&date=${CDASH_DATE}")
EXECUTE_PROCESS(COMMAND curl --data-urlencode "url=${RESULT_LINK}" -s http://tinyurl.com/api-create.php
OUTPUT_VARIABLE SHORTURL)

27
.ci/config_build.ctest Normal file
View File

@ -0,0 +1,27 @@
include(${CMAKE_CURRENT_LIST_DIR}/config.ctest)
# Requires a track on the CDash server
ctest_start(Experimental)
ctest_build (BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE BUILDRES NUMBER_WARNINGS NUMWARN NUMBER_ERRORS NUMERR)
SET(IGNORE_BUILD_FAILURES $ENV{IGNORE_BUILD_FAILURES})
IF(NOT IGNORE_BUILD_FAILURES)
IF(NOT ${BUILDRES} EQUAL 0 OR NOT ${NUMERR} EQUAL 0)
ctest_submit (RETRY_COUNT 3 RETRY_DELAY 30)
MESSAGE("")
MESSAGE(" ${Yellow}Test results submitted to:${ColorReset} ${SHORTURL}")
MESSAGE("")
MESSAGE( FATAL_ERROR " ${Red}Build failed. Not running tests.${ColorReset}" )
MESSAGE("")
ENDIF(NOT ${BUILDRES} EQUAL 0 OR NOT ${NUMERR} EQUAL 0)
ENDIF(NOT IGNORE_BUILD_FAILURES)
IF(${BUILDRES} EQUAL 0 OR ${NUMERR} EQUAL 0)
MESSAGE("")
MESSAGE(" ${BoldGreen}Success${ColorReset}")
MESSAGE(" ${Green}Build passed successfully.${ColorReset}")
MESSAGE("")
MESSAGE("")
ENDIF(${BUILDRES} EQUAL 0 OR ${NUMERR} EQUAL 0)

26
.ci/config_test.ctest Normal file
View File

@ -0,0 +1,26 @@
include(${CMAKE_CURRENT_LIST_DIR}/config.ctest)
# Requires a track on the CDash server
ctest_start(Experimental)
ctest_test (BUILD "${CTEST_BINARY_DIRECTORY}" PARALLEL_LEVEL ${PARALLEL_LEVEL} RETURN_VALUE TESTRES)
IF(NOT ${TESTRES} EQUAL 0)
ctest_submit (RETRY_COUNT 3 RETRY_DELAY 30)
MESSAGE("")
MESSAGE(" ${Yellow}Test results submitted to:${ColorReset} ${SHORTURL}" )
MESSAGE("")
SET(LEVEL "")
IF(NOT ${TESTRES} EQUAL 0)
SET(TESTRES_MESSAGE " Tests failed.")
SET(LEVEL FATAL_ERROR)
ENDIF(NOT ${TESTRES} EQUAL 0)
MESSAGE( ${LEVEL} " ${Red}${TESTRES_MESSAGE} ${ColorReset}" )
ENDIF(NOT ${TESTRES} EQUAL 0)
IF(NOT ${TESTRES} EQUAL 0)
MESSAGE("")
MESSAGE(" ${BoldGreen}Success${ColorReset}")
MESSAGE(" ${Green}All tests passed successfully.${ColorReset}")
MESSAGE("")
MESSAGE("")
ENDIF(NOT ${TESTRES} EQUAL 0)

139
.ci/ctest2ci.py Executable file
View File

@ -0,0 +1,139 @@
#!/usr/bin/env python3
"""
***************************************************************************
ctest2ci.py
---------------------
Date : March 2017
Copyright : (C) 2017 by Matthias Kuhn
Email : matthias@opengis.ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
__author__ = "Matthias Kuhn"
__date__ = "March 2017"
__copyright__ = "(C) 2017, Matthias Kuhn"
# This script parses output from ctest and injects
#
# - Colors for failing unit tests and test cases
# - Group control sequences to hide uninteresting output by default
import re
import string
import subprocess
import sys
from termcolor import colored
fold_stack = list()
printable = set(string.printable)
def start_fold(tag):
sys.stdout.write(f"::group::{tag}\n")
fold_stack.append(tag)
def end_fold():
try:
tag = fold_stack.pop()
sys.stdout.write("::endgroup::\n")
except IndexError:
updated_line = colored("======================", "magenta")
updated_line += colored(
"ctest2ci error when processing the following line:", "magenta"
)
updated_line += colored("----------------------", "magenta")
updated_line += colored(updated_line, "magenta")
updated_line += colored("----------------------", "magenta")
updated_line += colored(
"Tried to end fold, but fold was never started.", "magenta"
)
updated_line += colored("======================", "magenta")
test_count = 0
def start_test_fold():
global test_count
sys.stdout.write("Running tests\n")
start_fold(f"test.{test_count}")
test_count += 1
in_failing_test = False
in_failure = False
p = subprocess.Popen(sys.argv[1:], stdout=subprocess.PIPE)
for line in p.stdout:
updated_line = line.decode("utf-8")
# remove non printable characters https://stackoverflow.com/a/8689826/1548052
filter(lambda x: x in printable, updated_line)
if re.match("Run dashboard with model Experimental", updated_line):
start_fold("Run tests")
updated_line = "{title}\n{line}".format(
title=colored("Running tests...", "yellow", attrs=["bold"]),
line=updated_line,
)
elif re.match("Test project /home/runner/QGIS/QGIS/build", updated_line):
end_fold() # tag=Run tests
start_test_fold()
if re.search(r"\*\*\*Failed", updated_line) or re.search(
r"\*\*\*Timeout", updated_line
):
end_fold()
updated_line = colored(updated_line, "red")
in_failing_test = True
if in_failing_test:
if re.match(" Start", updated_line):
start_test_fold()
in_failing_test = False
elif in_failure:
if re.match("PASS", updated_line) or re.match("Ran", updated_line):
in_failure = False
else:
updated_line = colored(updated_line, "yellow")
elif re.search(r"\*\*\* Segmentation fault", updated_line):
start_fold("segfault")
updated_line = colored(updated_line, "magenta")
elif re.match(" Test failed: Segmentation fault", updated_line):
end_fold()
else:
if re.match(r"(FAIL|ERROR)[:\!].*", updated_line):
updated_line = colored(updated_line, "yellow")
in_failure = True
if not in_failing_test and re.search(
"[0-9]+% tests passed, [0-9]+ tests failed out of", updated_line
):
tests_failing = re.match(r".* ([0-9]+) tests failed", updated_line).group(1)
# updated_line += '\n::set-output name=TESTS_FAILING::{}'.format(tests_failing)
end_fold()
if re.search("100% tests passed", updated_line):
updated_line = colored(updated_line, "green")
if re.match("Submit files", updated_line):
start_fold("submit")
elif re.search("Test results submitted to", updated_line):
cdash_url = re.match(r".*(http.*)$", updated_line).group(1)
# updated_line += '\n::set-output name=CDASH_URL::{}'.format(cdash_url)
end_fold()
sys.stdout.write(updated_line)
exit(p.wait())

47
.ci/ogc/Dockerfile Normal file
View File

@ -0,0 +1,47 @@
FROM ubuntu:latest
RUN export DEBIAN_FRONTEND=noninteractive
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get upgrade -y \
&& apt-get install -y \
ccache \
cmake \
ninja-build \
clang \
flex \
bison \
libgeos-dev \
libgdal-dev \
libzip-dev \
libprotobuf-dev \
qtbase5-dev \
libdraco-dev \
libqt5svg5-dev \
libqt5serialport5-dev \
qttools5-dev \
protobuf-compiler \
qt5-qmake \
qtbase5-dev-tools \
qtchooser \
qtpositioning5-dev \
libqt5webkit5-dev \
libqca-qt5-2-dev \
libgsl-dev \
libspatialindex-dev \
qt5keychain-dev \
libexiv2-dev \
libfcgi-dev \
libqt5scintilla2-dev \
libqwt-qt5-dev \
pyqt5-dev \
python3-pyqt5 \
python3-pyqt5.qsci \
python3-all-dev \
python3-dev \
python3-sip-dev \
pyqt5-dev-tools \
spawn-fcgi
ADD qgis_mapserv.sh /root/qgis_mapserv.sh
CMD ["sh", "/root/qgis_mapserv.sh"]

53
.ci/ogc/build.sh Executable file
View File

@ -0,0 +1,53 @@
#!/bin/bash
set -e
mkdir -p /usr/src/qgis/build
cd /usr/src/qgis/build || exit 1
export CCACHE_TEMPDIR=/tmp
# Github workflow cache max size is 2.0, but ccache data get compressed (roughly 1/5?)
ccache -M 2.0G
# Temporarily uncomment to debug ccache issues
# export CCACHE_LOGFILE=/tmp/cache.debug
ccache -z
# To make ccache work properly with precompiled headers
ccache --set-config sloppiness=pch_defines,time_macros,include_file_mtime,include_file_ctime
cmake -GNinja \
-DUSE_CCACHE=ON \
-DWITH_QUICK=OFF \
-DWITH_3D=OFF \
-DWITH_STAGED_PLUGINS=OFF \
-DWITH_GRASS=OFF \
-DENABLE_MODELTEST=OFF \
-DENABLE_PGTEST=OFF \
-DENABLE_MSSQLTEST=OFF \
-DENABLE_TESTS=OFF \
-DWITH_QSPATIALITE=OFF \
-DWITH_QWTPOLAR=OFF \
-DWITH_APIDOC=OFF \
-DWITH_ASTYLE=OFF \
-DWITH_ANALYSIS=ON \
-DWITH_GSL=OFF \
-DWITH_DESKTOP=OFF \
-DWITH_GUI=OFF \
-DWITH_BINDINGS=ON \
-DWITH_SERVER=ON \
-DWITH_SERVER_PLUGINS=ON \
-DWITH_ORACLE=OFF \
-DWITH_PDAL=OFF \
-DWITH_QTPRINTER=OFF \
-DDISABLE_DEPRECATED=ON \
-DCXX_EXTRA_FLAGS="${CLANG_WARNINGS}" \
-DCMAKE_C_COMPILER=/bin/clang \
-DCMAKE_CXX_COMPILER=/bin/clang++ \
-DADD_CLAZY_CHECKS=OFF \
..
ninja
echo "ccache statistics"
ccache -s

View File

@ -0,0 +1,29 @@
version: '3'
services:
nginx:
image: nginx:1.13
container_name: qgis_server_nginx
ports:
- 8089:80
networks:
- qgis
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
- ./../../data/metadata:/var/www/html/wms13/metadata
depends_on:
- qgis-server
qgis-server:
image: ${DOCKER_IMAGE}
container_name: qgis_server_deps
volumes:
- ./../../:/usr/src/qgis/
- ./../../data:/data
networks:
- qgis
privileged: true
networks:
qgis:
driver: bridge

49
.ci/ogc/nginx.conf Normal file
View File

@ -0,0 +1,49 @@
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
server_name _;
location / {
try_files $uri $uri/ =404;
}
location /qgisserver_wms130 {
fastcgi_pass qgis-server:5555;
add_header Access-Control-Allow-Origin *;
add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept,Origin,X-Requested-With';
fastcgi_param PATH_INFO $fastcgi_script_name;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param HTTPS $https if_not_empty;
fastcgi_param SERVER_PORT 80;
fastcgi_param SERVER_NAME $server_addr;
fastcgi_param QGIS_PROJECT_FILE /data/teamengine_wms_130.qgs;
}
location /qgisserver_ogcapif {
fastcgi_pass qgis-server:5555;
add_header Access-Control-Allow-Origin *;
add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept,Origin,X-Requested-With';
fastcgi_param PATH_INFO $fastcgi_script_name;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param HTTPS $https if_not_empty;
fastcgi_param SERVER_PORT 80;
fastcgi_param SERVER_NAME $server_addr;
fastcgi_param QGIS_PROJECT_FILE /data/QGIS-Training-Data/exercise_data/qgis-server-tutorial-data/world.qgs;
}
}

7
.ci/ogc/qgis_mapserv.sh Normal file
View File

@ -0,0 +1,7 @@
#!/bin/bash
export QGIS_SERVER_LOG_STDERR=true
export QGIS_SERVER_LOG_LEVEL=0
export QGIS_PREFIX_PATH=/usr/src/qgis/build/output
exec /usr/bin/spawn-fcgi -n -p 5555 /usr/src/qgis/build/output/bin/qgis_mapserv.fcgi

40
.ci/pr_has_label.py Executable file
View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
import argparse
import json
import sys
from urllib.error import URLError
from urllib.request import ( # using urllib since it is a standard module (vs. requests)
urlopen,
)
parser = argparse.ArgumentParser(
description="Determines if a pull request has a defined label"
)
parser.add_argument("pull_request", type=str, help="pull request id")
parser.add_argument("label", type=int, help="label ID")
args = parser.parse_args()
if args.pull_request == "false":
print("false")
sys.exit(1)
url = f"https://api.github.com/repos/qgis/QGIS/pulls/{args.pull_request}"
try:
data = urlopen(url).read().decode("utf-8")
except URLError as err:
print(f"URLError: {err.reason}")
sys.exit(1)
obj = json.loads(data)
for label in obj["labels"]:
if label["id"] == args.label:
print("true")
sys.exit(0)
print("label not found")
sys.exit(1)

152
.ci/run_tests.sh Executable file
View File

@ -0,0 +1,152 @@
#!/bin/sh
set -e
DOCKER=$(command -v podman docker | head -1)
# check for docker availability
test -n "${DOCKER}" || {
echo "Please install podman or docker" >&2
exit 1
}
DOCKER_COMPOSE=$(command -v podman-compose docker-compose | head -1)
test -n "${DOCKER_COMPOSE}" || {
DOCKER_COMPOSE="${DOCKER} compose"
# check if supported
${DOCKER_COMPOSE} > /dev/null || {
echo "Cannot find podman-compose or docker-compose, and '${DOCKER_COMPOSE}' fails" >&2
echo "HINT: try installing podman-compose" >&2
exit 1
}
}
IMAGE_BUILD_DEPS=docker.io/qgis/qgis3-build-deps:latest
UPDATE_IMAGES=yes
INTERACTIVE=no
FORCE_REBUILD=no
export QT_VERSION=5 # TODO: ask user for this one
export DISTRO_VERSION=21.10 # TODO: ask user for this one
# can be: ALL, ALL_BUT_PROVIDERS, POSTGRES, HANA, ORACLE, SQLSERVER
TESTS_TO_RUN=ALL_BUT_PROVIDERS # TODO: ask user for this one
usage() {
echo "Usage: $(basename $0) [--skip-update-images] [--force-rebuild] [--interactive]"
}
while test -n "$1"; do
if test "$1" = '--help' || test "$1" = '-h'; then
usage
exit 0
elif test "$1" = '--skip-update-images'; then
UPDATE_IMAGES=no
shift
elif test "$1" = '--force-rebuild'; then
FORCE_REBUILD=yes
shift
elif test "$1" = '--interactive'; then
INTERACTIVE=yes
shift
else
echo "Unrecognized option $1" >&2
usage >&2
exit 1
fi
done
cd $(dirname $0)/.. || exit 1
#echo "--=[ PWD is $PWD"
export QGIS_BUILDDIR=build-ci
QGIS_WORKSPACE="$(pwd -P)"
export QGIS_WORKSPACE
echo "--=[ QGIS_WORKSPACE is $QGIS_WORKSPACE"
QGIS_WORKSPACE_MOUNTPOINT=${QGIS_WORKSPACE} # was /root/QGIS
export QGIS_WORKSPACE_MOUNTPOINT
echo "--=[ QGIS_WORKSPACE_MOUNTPOINT is $QGIS_WORKSPACE_MOUNTPOINT"
QGIS_GIT_DIR="$(git rev-parse --git-dir)"
if test -f ${QGIS_GIT_DIR}/commondir; then
QGIS_COMMON_GIT_DIR="$(cat ${QGIS_GIT_DIR}/commondir)"
else
QGIS_COMMON_GIT_DIR=${QGIS_WORKSPACE}
fi
QGIS_COMMON_GIT_DIR="$(cd ${QGIS_COMMON_GIT_DIR} && pwd -P)"
export QGIS_COMMON_GIT_DIR
echo "--=[ QGIS_COMMON_GIT_DIR is $QGIS_COMMON_GIT_DIR"
#
# Make qgis3-build-deps-binary-image available, building it if needed
#
if test "$(${DOCKER} images -q ${IMAGE_BUILD_DEPS})" = ""; then
echo "--=[ Fetching qgis build dependencies image"
${DOCKER} pull ${IMAGE_BUILD_DEPS}
elif test "${UPDATE_IMAGES}" = "yes"; then
echo "--=[ Updating qgis build dependencies image"
${DOCKER} pull ${IMAGE_BUILD_DEPS}
fi
if test -d ${QGIS_BUILDDIR} -a "${FORCE_REBUILD}" = "no"; then
echo "--=[ Testing against pre-existing build directory ${QGIS_BUILDDIR}. To rebuild use --force-rebuild or move it away"
else
echo "--=[ Building qgis inside the dependencies container"
VOLUMES="-v ${QGIS_WORKSPACE}:${QGIS_WORKSPACE}:z"
if test "${QGIS_WORKSPACE}" != "${QGIS_COMMON_GIT_DIR}"; then
VOLUMES="${VOLUMES} -v ${QGIS_COMMON_GIT_DIR}:${QGIS_COMMON_GIT_DIR}:z"
fi
${DOCKER} run -t --name qgis_container \
--rm \
${VOLUMES} \
--env-file .docker/docker-variables.env \
--env PUSH_TO_CDASH=false \
--env WITH_QT5=true \
--env BUILD_WITH_QT6=false \
--env WITH_QUICK=false \
--env WITH_3D=false \
--env PATCH_QT_3D=false \
--env CTEST_SOURCE_DIR=${QGIS_WORKSPACE} \
--env CTEST_BUILD_DIR=${QGIS_WORKSPACE}/${QGIS_BUILDDIR} \
${IMAGE_BUILD_DEPS} \
${QGIS_WORKSPACE_MOUNTPOINT}/.docker/docker-qgis-build.sh ||
exit 1
test -d ${QGIS_BUILDDIR} || {
echo "Building failed" >&2
exit 1
}
fi
if test "$(${DOCKER} images -q qgis3-build-deps-binary-image)" = ""; then
echo "--=[ Tagging qgis build dependencies image as required by .docker/docker-compose-testing.yml"
${DOCKER} tag ${IMAGE_BUILD_DEPS} qgis3-build-deps-binary-image
fi
if test "${INTERACTIVE}" = "no"; then
echo "--=[ Running tests via docker compose"
COMMAND=${QGIS_WORKSPACE_MOUNTPOINT}/.docker/docker-qgis-test.sh
COMMAND_ARGS="${TESTS_TO_RUN}"
else
echo "--=[ Starting interactive shell into test environment"
COMMAND=bash
fi
# Create an empty minio folder with appropriate permissions so www user can write inside it
mkdir -p /tmp/minio_tests/test-bucket && chmod -R 777 /tmp/minio_tests
# Create an empty webdav folder with appropriate permissions so www user can write inside it
mkdir -p /tmp/webdav_tests && chmod 777 /tmp/webdav_tests
${DOCKER_COMPOSE} \
-f .docker/docker-compose-testing.yml \
run \
-w "${QGIS_WORKSPACE_MOUNTPOINT}" \
-e PUSH_TO_CDASH=false \
-e CTEST_SOURCE_DIR="${QGIS_WORKSPACE}" \
-e CTEST_BUILD_DIR="${QGIS_WORKSPACE}/${QGIS_BUILDDIR}" \
qgis-deps \
${COMMAND} ${COMMAND_ARGS}

View File

@ -0,0 +1,19 @@
# block list
test_gui_queryresultwidget
# code layout tests are run on separate build
qgis_spelling
qgis_sipify
qgis_sip_include
qgis_sip_uptodate
# Need a local postgres installation
PyQgsAuthManagerOgrPostgresTest
PyQgsDbManagerPostgis
# Needs an OpenCL device, the library is not enough
test_core_openclutils
# Relies on a broken/unreliable 3rd party service
test_core_layerdefinition

View File

@ -0,0 +1,43 @@
# Qt6 blocklist
test_core_compositionconverter
test_core_labelingengine
test_core_layoutpicture
test_core_vectortilelayer
test_gui_processinggui
test_app_advanceddigitizing
test_app_vertextool
# Crashes -- also disabled on qt5 builds!
test_gui_queryresultwidget
# code layout tests are run on separate build
qgis_spelling
qgis_sipify
qgis_sip_include
qgis_sip_uptodate
# Need a local postgres installation
PyQgsAuthManagerOgrPostgresTest
PyQgsDbManagerPostgis
# Needs an OpenCL device, the library is not enough
test_core_openclutils
# Relies on a broken/unreliable 3rd party service
test_core_layerdefinition
# MSSQL requires the MSSQL docker
PyQgsProviderConnectionMssql
PyQgsStyleStorageMssql
# To be fixed
PyQgsAnnotation
PyQgsAuthenticationSystem
PyQgsEditWidgets
PyQgsElevationProfileCanvas
PyQgsLayoutHtml
PyQgsPalLabelingPlacement
PyQgsRasterLayerRenderer
PyQgsSettings
PyQgsSettingsEntry
ProcessingQgisAlgorithmsTestPt4

6
.ci/test_flaky.txt Normal file
View File

@ -0,0 +1,6 @@
# flaky
test_gui_filedownloader
test_provider_wcsprovider
PyQgsWFSProviderGUI
# See https://github.com/qgis/QGIS/issues/48927
test_core_tiledownloadmanager

219
.clang-format Normal file
View File

@ -0,0 +1,219 @@
---
Language: Cpp
AccessModifierOffset: -2
AlignAfterOpenBracket: BlockIndent
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: No
BinPackArguments: true
BinPackParameters: true
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterExternBlock: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakAfterAttributes: Never
BreakAfterJavaFieldAnnotations: false
BreakArrays: true
BreakBeforeBinaryOperators: All
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakStringLiterals: true
ColumnLimit: 0
CommentPragmas: "^ IWYU pragma:"
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
IncludeCategories:
- Regex: "^<Q.*"
Priority: 300
- Regex: "^<qgs.*"
Priority: 200
- Regex: "<.*"
Priority: 400
- Regex: '^".*'
Priority: 100
- Regex: ".*"
Priority: 1
IncludeIsMainRegex: false
#IncludeBlocks: Regroup
IncludeIsMainSourceRegex: ""
IndentAccessModifiers: true
IndentCaseBlocks: false
IndentCaseLabels: true
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 2
IndentWrappedFunctionNames: true
# should be:
# InsertBraces: true
# InsertNewlineAtEOF: true
InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
# Do not add QT_BEGIN_NAMESPACE/QT_END_NAMESPACE as this will indent lines in between.
MacroBlockBegin: ""
MacroBlockEnd: ""
MaxEmptyLinesToKeep: 2
NamespaceIndentation: All
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 4
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PackConstructorInitializers: BinPack
PenaltyBreakAssignment: 150
PenaltyBreakBeforeFirstCallParameter: 5000
PenaltyBreakComment: 500
PenaltyBreakFirstLessLess: 400
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 600
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 10
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 5000
PointerAlignment: Right
PPIndentWidth: -1
QualifierAlignment: Leave
ReferenceAlignment: Pointer
# should be:
# ReflowComments: true
ReflowComments: false
RemoveBracesLLVM: false
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes: false
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: true
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterOverloadedOperator: false
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Leave
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: true
SpacesInLineCommentPrefix:
# should be:
# Minimum: 1
Minimum: 0
Maximum: -1
SpacesInParentheses: true
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 2
UseTab: Never
Macros:
- SIP_ENUM_BASETYPE(x)=x
- SIP_MONKEYPATCH_SCOPEENUM_UNNEST(x,y)=x
AttributeMacros:
- SIP_SKIP
---
Language: ObjC
ObjCBlockIndentWidth: 4

2
.clang-tidy Normal file
View File

@ -0,0 +1,2 @@
Checks: 'bugprone-*,-bugprone-easily-swappable-parameters,-bugprone-virtual-near-miss,-bugprone-suspicious-include'
HeaderFilterRegex: ''

View File

@ -1,16 +0,0 @@
autogen.sh
Makefile
Makefile.in
aclocal.m4
compile
config.guess
config.log
config.status
config.sub
configure
libtool
ltmain.sh
qgis.spec
qgsconfig.h
qgsconfig.h.in
stamp-h1

258
.docker/README.md Normal file
View File

@ -0,0 +1,258 @@
QGIS Docker images
==================
The QGIS project provides a few official docker images that can be
used for testing purposes.
These dockers are currently used to run continuous integration
tests for the QGIS project itself and to run continuous integration
tests for several third party Python plugins.
The images are automatically built every day and pushed on docker hub
to the QGIS account: https://hub.docker.com/r/qgis/
# Available images
## Dependencies image
`qgis/qgis3-build-deps`
This is a simple base image that contains all the dependencies required to build
QGIS, it is used by the other images.
Multiple versions of this image may be available: the suffix in the image name indicates the Ubuntu version they are based on.
## Main QGIS image
`qgis/qgis`
This is the main image containing a build of QGIS.
The docker tags for this image are assigned for each point release (prefixed with `final-`), for the active development branches (prefixed with `release-`) while the `latest` tag refers to a build of the current master branch.
### Features
The docker file builds QGIS from the current directory and
sets up a testing environment suitable for running tests
inside QGIS.
You can use this docker image to test QGIS and/or to run unit tests inside
QGIS, `xvfb` (A fake X server) is available and running as a service inside
the container to allow for fully automated headless testing in CI pipelines
such as Travis or Circle-CI.
### Building
You can build the image from the main directory of the QGIS source tree with:
```
$ docker build -t qgis/qgis:latest \
--build-arg DOCKER_TAG=latest \
-f .docker/qgis.dockerfile \
.
```
The `DOCKER_TAG` argument, can be used to specify the tag of the dependencies image.
### Running QGIS
You can also use this image to run QGIS on your desktop.
To run a QGIS container, assuming that you want to use your current
display to use QGIS and the image is tagged `qgis/qgis:latest` you can use a script like the one here below:
```bash
# Allow connections from any host
$ xhost +
$ docker run --rm -it --name qgis \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e DISPLAY=unix$DISPLAY \
qgis/qgis:latest qgis
```
This code snippet will launch QGIS inside a container and display the
application on your screen.
### Running unit tests inside QGIS
Suppose that you have local directory containing the tests you want to execute into QGIS:
```
/my_tests/travis_tests/
├── __init__.py
└── test_TravisTest.py
```
To run the tests inside the container, you must mount the directory that
contains the tests (e.g. your local directory `/my_tests`) into a volume
that is accessible by the container, see `-v /my_tests/:/tests_directory`
in the example below:
```bash
$ docker run -d --name qgis -v /tmp/.X11-unix:/tmp/.X11-unix \
-v /my_tests/:/tests_directory \
-e DISPLAY=:99 \
qgis/qgis:latest
```
Here is an extract of `test_TravisTest.py`:
```python
# -*- coding: utf-8 -*-
import sys
from qgis.testing import unittest
class TestTest(unittest.TestCase):
def test_passes(self):
self.assertTrue(True)
def run_all():
"""Default function that is called by the runner if nothing else is specified"""
suite = unittest.TestSuite()
suite.addTests(unittest.makeSuite(TestTest, 'test'))
unittest.TextTestRunner(verbosity=3, stream=sys.stdout).run(suite)
```
When done, you can invoke the test runnner by specifying the test
that you want to run, for instance:
```
$ docker exec -it qgis sh -c "cd /tests_directory && qgis_testrunner.sh travis_tests.test_TravisTest.run_fail"
```
The test can be specified by using a dotted notation, similar to Python
import notation, by default the function named `run_all` will be executed
but you can pass another function name as the last item in the dotted syntax:
```bash
# Call the default function "run_all" inside test_TravisTest module
qgis_testrunner.sh travis_tests.test_TravisTest
# Call the function "run_fail" inside test_TravisTest module
qgis_testrunner.sh travis_tests.test_TravisTest.run_fail
```
Please note that in order to make the test script accessible to Python
the calling command must ensure that the tests are in Python path.
Common patterns are:
- change directory to the one containing the tests (like in the examples above)
- add to `PYTHONPATH` the directory containing the tests
#### Running tests for a Python plugin
All the above considerations applies to this case too, however in order
to simulate the installation of the plugin inside QGIS, you'll need to
make an additional step: call `qgis_setup.sh <YourPluginName>` in the
docker container before actually running the tests (see the paragraph
about Running on Travis for a complete example).
The `qgis_setup.sh` script prepares QGIS to run in headless mode and
simulate the plugin installation process:
- creates the QGIS profile folders
- "installs" the plugin by making a symbolic link from the profiles folder to the plugin folder
- installs `startup.py` monkey patches to prevent blocking dialogs
- enables the plugin
Please note that depending on your plugin repository internal directory structure
you may need to adjust (remove and create) the symbolic link created by `qgis_setup.sh`,
this is required in particular if the real plugin code in your repository is contained
in the main directory and not in a subdirectory with the same name of the plugin
internal name (the name in `metadata.txt`).
#### Options for the test runner
The env var `QGIS_EXTRA_OPTIONS` defaults to an empty string and can
contains extra parameters that are passed to QGIS by the test runner.
#### Running on Travis
Here is a simple example for running unit tests of a small QGIS plugin (named *QuickWKT*), assuming that the tests are in `tests/test_Plugin.py` under
the main directory of the QuickWKT plugin:
```yml
services:
- docker
install:
- docker run -d --name qgis-testing-environment -v ${TRAVIS_BUILD_DIR}:/tests_directory -e DISPLAY=:99 qgis/qgis:latest
- sleep 10 # This is required to allow xvfb to start
# Setup qgis and enables the plugin
- docker exec -it qgis-testing-environment sh -c "qgis_setup.sh QuickWKT"
# Additional steps (for example make or paver setup) here
# Fix the symlink created by qgis_setup.sh
- docker exec -it qgis-testing-environment sh -c "rm -f /root/.local/share/QGIS/QGIS3/profiles/default/python/plugins/QuickWKT"
- docker exec -it qgis-testing-environment sh -c "ln -s /tests_directory/ /root/.local/share/QGIS/QGIS3/profiles/default/python/plugins/QuickWKT"
script:
- docker exec -it qgis-testing-environment sh -c "cd /tests_directory && qgis_testrunner.sh tests.test_Plugin"
```
Please note that `cd /tests_directory && ` before the call to `qgis_testrunner.sh` could be avoided here, because QGIS automatically
adds the plugin main directory to Python path.
#### Running on Circle-CI
Here is an example for running unit tests of a small QGIS plugin (named *QuickWKT*), assuming
that the tests are in `tests/test_Plugin.py` under the main directory of the QuickWKT plugin:
```yml
version: 2
jobs:
build:
docker:
- image: qgis/qgis:latest
environment:
DISPLAY: ":99"
working_directory: /tests_directory
steps:
- checkout
- run:
name: Setup plugin
command: |
qgis_setup.sh QuickWKT
- run:
name: Fix installation path created by qgis_setup.s
command: |
rm -f /root/.local/share/QGIS/QGIS3/profiles/default/python/plugins/QuickWKT
ln -s /tests_directory/ /root/.local/share/QGIS/QGIS3/profiles/default/python/plugins/qgisce
- run:
name: run tests
command: |
sh -c "/usr/bin/Xvfb :99 -screen 0 1024x768x24 -ac +extension GLX +render -noreset -nolisten tcp &"
qgis_testrunner.sh tests.test_Plugin
```
#### Implementation notes
The main goal of the test runner in this image is to execute unit tests
inside a real instance of QGIS (not a mocked one).
The QGIS tests should be runnable from a Travis/Circle-CI CI job.
The implementation is:
- run the docker, mounting as volumes the unit tests folder in `/tests_directory`
(or the QGIS plugin folder if the unit tests belong to a plugin and the
plugin is needed to run the tests)
- execute `qgis_setup.sh MyPluginName` script in docker that sets up QGIS to
avoid blocking modal dialogs and installs the plugin into QGIS if needed
- create config and python plugin folders for QGIS
- enable the plugin in the QGIS configuration file
- install the `startup.py` script to disable python exception modal dialogs
- execute the tests by running `qgis_testrunner.sh MyPluginName.tests.tests_MyTestModule.run_my_tests_function`
- the output of the tests is captured by the `test_runner.sh` script and
searched for `FAILED` (that is in the standard unit tests output) and other
string that indicate a failure or success condition, if a failure condition
is identified, the script exits with `1` otherwise it exits with `0`.
`qgis_testrunner.sh` accepts a dotted notation path to the test module that
can end with the function that has to be called inside the module to run the
tests. The last part (`.run_my_tests_function`) can be omitted and defaults to
`run_all`.

View File

@ -0,0 +1,25 @@
version: '3'
services:
mssql:
image: mcr.microsoft.com/mssql/server:2022-latest
environment:
ACCEPT_EULA: Y
MSSQL_SA_PASSWORD: QGIStestSQLServer1234
ports:
- 1433:1433
qgis-deps:
tty: true
image: qgis3-build-deps-binary-image
volumes:
- ${QGIS_WORKSPACE}:/root/QGIS
links:
- mssql
env_file:
- docker-variables.env
environment:
- LANG=C.UTF-8
- LC_ALL=en_US.UTF-8
cap_add:
- NET_ADMIN

View File

@ -0,0 +1,24 @@
services:
oracle:
image: oslandia/oracle-slim-for-qgis:18.4.0-xe
environment:
- ORACLE_SID=XE
- ORACLE_PWD=adminpass
- ORACLE_PDB=ORCLPDBTEST
- ORACLE_CHARACTERSET=AL32UTF8
ports:
- 1521:1521
qgis-deps:
tty: true
image: qgis3-build-deps-binary-image
volumes:
- ${QGIS_WORKSPACE}:/root/QGIS
links:
- oracle
env_file:
- docker-variables.env
environment:
- LANG=C.UTF-8
- LC_ALL=en_US.UTF-8

View File

@ -0,0 +1,27 @@
version: '3'
services:
postgres:
build:
dockerfile: Dockerfile-postgis
context: ../tests/testdata
environment:
- ALLOW_IP_RANGE="172.18.0.0/16"
# The following files are added in Dockerfile-postgis
- SSL_CERT_FILE=/etc/ssl/certs/postgres.crt
- SSL_KEY_FILE=/etc/ssl/private/postgres.key
- SSL_CA_FILE=/etc/ssl/certs/qgis_ca.crt
qgis-deps:
tty: true
image: qgis3-build-deps-binary-image
volumes:
- ${QGIS_WORKSPACE}:/root/QGIS
links:
- postgres
env_file:
- docker-variables.env
environment:
- LANG=C.UTF-8
- LC_ALL=en_US.UTF-8
cap_add:
- NET_ADMIN

View File

@ -0,0 +1,39 @@
version: '3'
services:
httpbin:
image: kennethreitz/httpbin:latest
webdav:
image: nginx
volumes:
- ${QGIS_WORKSPACE}/.docker/webdav/nginx.conf:/etc/nginx/conf.d/default.conf
- ${QGIS_WORKSPACE}/.docker/webdav/passwords.list:/etc/nginx/.passwords.list
- /tmp/webdav_tests:/tmp/webdav_tests_root/webdav_tests
minio:
image: minio/minio
volumes:
- /tmp/minio_tests:/data
environment:
- MINIO_ROOT_USER=minioadmin
- MINIO_ROOT_PASSWORD=adminio€
command: server /data
qgis-deps:
tty: true
image: qgis3-build-deps-binary-image
volumes:
- ${QGIS_WORKSPACE}:/root/QGIS
- ${QGIS_COMMON_GIT_DIR}:${QGIS_COMMON_GIT_DIR}
links:
- webdav
- minio
- httpbin
env_file:
- docker-variables.env
environment:
- LANG=C.UTF-8
- LC_ALL=en_US.UTF-8
- QGIS_HTTPBIN_HOST=httpbin
- QGIS_TEST_ACCEPT_GITSTATUS_CHECK_FAILURE=1

149
.docker/docker-qgis-build.sh Executable file
View File

@ -0,0 +1,149 @@
#!/usr/bin/env bash
set -e
CTEST_SOURCE_DIR=${CTEST_SOURCE_DIR-/root/QGIS}
CTEST_BUILD_DIR=${CTEST_BUILD_DIR-/root/QGIS/build}
export LANG="C.UTF-8"
##############
# Setup ccache
##############
export CCACHE_TEMPDIR=/tmp
# Github workflow cache max size is 2.0, but ccache data get compressed (roughly 1/5?)
ccache -M 2.0G
# Temporarily uncomment to debug ccache issues
# export CCACHE_LOGFILE=/tmp/cache.debug
ccache -z
# To make ccache work properly with precompiled headers
ccache --set-config sloppiness=pch_defines,time_macros,include_file_mtime,include_file_ctime
##############################
# Variables for output styling
##############################
bold=$(tput bold)
endbold=$(tput sgr0)
###########
# Configure
###########
pushd ${CTEST_SOURCE_DIR} > /dev/null
mkdir -p ${CTEST_BUILD_DIR}
pushd ${CTEST_BUILD_DIR} > /dev/null
echo "${bold}Running cmake...${endbold}"
echo "::group::cmake"
BUILD_TYPE=Release
export CC=/usr/bin/clang
export CXX=/usr/bin/clang++
if [[ "${WITH_CLAZY}" = "ON" ]]; then
# In release mode, all variables in QgsDebugMsg would be considered unused
BUILD_TYPE=Debug
export CXX=clazy
# ignore sip and external libraries
export CLAZY_IGNORE_DIRS="(.*/external/.*)|(.*sip_.*part.*)"
fi
if [[ ${BUILD_WITH_QT6} = "ON" ]]; then
CLANG_WARNINGS="-Wrange-loop-construct"
fi
CMAKE_EXTRA_ARGS=()
if [[ "${WITH_COMPILE_COMMANDS}" == "ON" ]]; then
CMAKE_EXTRA_ARGS+=(
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
)
fi
if [[ ${WITH_GRASS7} == "ON" || ${WITH_GRASS8} == "ON" ]]; then
CMAKE_EXTRA_ARGS+=(
"-DGRASS_PREFIX$( grass --config version | cut -b 1 )=$( grass --config path )"
)
fi
if [[ ${BUILD_WITH_QT6} = "ON" ]]; then
CMAKE_EXTRA_ARGS+=(
"-DUSE_ALTERNATE_LINKER=mold"
)
fi
cmake \
-GNinja \
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-DUSE_CCACHE=ON \
-DBUILD_WITH_QT6=${BUILD_WITH_QT6} \
-DWITH_DESKTOP=ON \
-DWITH_ANALYSIS=ON \
-DWITH_GUI=ON \
-DWITH_QUICK=${WITH_QUICK} \
-DWITH_3D=${WITH_3D} \
-DWITH_STAGED_PLUGINS=ON \
-DWITH_GRASS7=${WITH_GRASS7} \
-DWITH_GRASS8=${WITH_GRASS8} \
-DWITH_GRASS_PLUGIN=${WITH_GRASS8} \
-DENABLE_TESTS=ON \
-DENABLE_MODELTEST=${WITH_QT5} \
-DENABLE_PGTEST=${WITH_QT5} \
-DENABLE_MSSQLTEST=${WITH_QT5} \
-DENABLE_MSSQLTEST_CPP=${WITH_QT5} \
-DENABLE_HANATEST=${WITH_QT5} \
-DENABLE_ORACLETEST=${WITH_QT5} \
-DENABLE_UNITY_BUILDS=${ENABLE_UNITY_BUILDS} \
-DPUSH_TO_CDASH=${PUSH_TO_CDASH} \
-DWITH_HANA=ON \
-DWITH_QGIS_PROCESS=ON \
-DWITH_QSPATIALITE=${WITH_QT5} \
-DWITH_QWTPOLAR=OFF \
-DWITH_APIDOC=OFF \
-DWITH_ASTYLE=OFF \
-DWITH_BINDINGS=ON \
-DWITH_SERVER=ON \
-DWITH_SERVER_LANDINGPAGE_WEBAPP=${WITH_QT5} \
-DWITH_ORACLE=ON \
-DWITH_PDAL=ON \
-DWITH_QTSERIALPORT=ON \
-DWITH_QTWEBKIT=${WITH_QT5} \
-DWITH_QTWEBENGINE=${WITH_QTWEBENGINE} \
-DWITH_PDF4QT=${WITH_PDF4QT} \
-DORACLE_INCLUDEDIR=/instantclient_21_16/sdk/include/ \
-DORACLE_LIBDIR=/instantclient_21_16/ \
-DDISABLE_DEPRECATED=ON \
-DPYTHON_TEST_WRAPPER="timeout -sSIGSEGV 55s" \
-DCXX_EXTRA_FLAGS="${CLANG_WARNINGS}" \
-DWERROR=TRUE \
-DAGGRESSIVE_SAFE_MODE=ON \
-DWITH_CLAZY=${WITH_CLAZY} \
"${CMAKE_EXTRA_ARGS[@]}" ..
echo "::endgroup::"
# Workaround https://github.com/actions/checkout/issues/760
git config --global --add safe.directory ${CTEST_SOURCE_DIR}
git config --global --add safe.directory ${CTEST_BUILD_DIR}
#######
# Build
#######
echo "${bold}Building QGIS...${endbold}"
echo "::group::build"
ctest -VV -S ${CTEST_SOURCE_DIR}/.ci/config_build.ctest
echo "::endgroup::"
########################
# Show ccache statistics
########################
echo "ccache statistics"
ccache -s
popd > /dev/null # ${CTEST_BUILD_DIR}
popd > /dev/null # ${CTEST_SOURCE_DIR}
[ -r /tmp/ctest-important.log ] && cat /tmp/ctest-important.log || true

View File

@ -0,0 +1,50 @@
#!/usr/bin/env bash
###########################################################################
# docker-qgis-clangtidy.sh
# ---------------------
# Date : September 2022
# Copyright : (C) 2022 by Julien Cabieces
# Email : julien dot cabieces at oslandia dot com
###########################################################################
# #
# This program is free software; you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation; either version 2 of the License, or #
# (at your option) any later version. #
# #
###########################################################################
set -e
SRCDIR=${CTEST_SOURCE_DIR-/root/QGIS}
cd ${SRCDIR}
# This is needed for `git status` to work, see
# https://github.com/qgis/QGIS/runs/6733585841?check_suite_focus=true#step:13:89
git config --global --add safe.directory ${SRCDIR}
# The clang-tidy version installed needs to match the one used to compile QGIS.
# Otherwise, it will not be able to inspect the modified files.
echo "::group::Install clang tidy"
apt install -y \
clang-tidy-15
echo "::endgroup::"
cd ${SRCDIR}
echo "${bold}Disable unity build...${endbold}"
cmake . -B build -DENABLE_UNITY_BUILDS=OFF
echo "${bold}Run clang-tidy on modifications...${endbold}"
# We need to add build/src/test dir as extra include directories because when clang-tidy tries to process qgstest.h
# it has no compile_commands.json instructions to know what are include directories
# It manages to figure out for other headers though, I don't get how...
git diff -U0 HEAD^ | python3 /usr/bin/clang-tidy-diff-15.py -p1 -path=${CTEST_BUILD_DIR} -use-color -extra-arg=-I${CTEST_BUILD_DIR}/src/test/ -clang-tidy-binary /usr/bin/clang-tidy-15 | tee clang-tidy.log
echo -e "\e[1;34mTo reproduce locally:"
echo -e "\e[1;34m - launch cmake with option -DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
echo -e "\e[1;34m - update build by calling Ninja"
echo -e "\e[1;34m - launch command ./scripts/clang-tidy.sh -p <your_build_dir> <source_file>"
exit $(grep -c "warning:" clang-tidy.log)

292
.docker/docker-qgis-test.sh Executable file
View File

@ -0,0 +1,292 @@
#!/usr/bin/env bash
set -e
SRCDIR=${CTEST_SOURCE_DIR-/root/QGIS}
cd ${SRCDIR}
# This is needed for `git status` to work, see
# https://github.com/qgis/QGIS/runs/6733585841?check_suite_focus=true#step:13:89
git config --global --add safe.directory ${SRCDIR}
usage() {
echo "Usage; $(basename $0) [<TEST_BATCHNAME>]"
echo "TEST_BATCHNAME can be any of:"
echo " HANA Test the HANA provider"
echo " POSTGRES Test the PostgreSQL provider"
echo " ORACLE Test the Oracle provider"
echo " SQLSERVER Test the SQL Server provider"
echo " ALL_BUT_PROVIDERS Skip all providers tests"
echo " ALL (default) Run all tests"
}
if [ $# -eq 1 ] && [ $1 = "HANA" ]; then
LABELS_TO_RUN="HANA"
RUN_HANA=YES
elif [ $# -eq 1 ] && [ $1 = "POSTGRES" ]; then
LABELS_TO_RUN="POSTGRES"
RUN_POSTGRES=YES
elif [ $# -eq 1 ] && [ $1 = "ORACLE" ]; then
LABELS_TO_RUN="ORACLE"
RUN_ORACLE=YES
elif [ $# -eq 1 ] && [ $1 = "SQLSERVER" ]; then
LABELS_TO_RUN="SQLSERVER"
RUN_SQLSERVER=YES
elif [ $# -eq 1 ] && [ $1 = "ALL_BUT_PROVIDERS" ]; then
LABELS_TO_EXCLUDE="HANA|POSTGRES|ORACLE|SQLSERVER"
elif [ $# -gt 0 ] && [ $1 != "ALL" ]; then
echo "Invalid argument"
usage >&2
exit 1
else
RUN_HANA=YES
RUN_POSTGRES=YES
RUN_ORACLE=YES
RUN_SQLSERVER=YES
fi
# Debug env
echo "::group::Print env"
env
echo "::endgroup::"
# Temporarily uncomment to debug ccache issues
# cat /tmp/cache.debug
if [ -n "$LABELS_TO_RUN" ]; then
echo "Only following test labels will be run: $LABELS_TO_RUN"
CTEST_OPTIONS="-L $LABELS_TO_RUN"
fi
if [ -n "$LABELS_TO_EXCLUDE" ]; then
echo "Following test labels will be excluded: $LABELS_TO_EXCLUDE"
CTEST_OPTIONS="$CTEST_OPTIONS -LE $LABELS_TO_EXCLUDE"
fi
if [ ${RUN_HANA:-"NO"} == "YES" ]; then
##################################
# Prepare HANA database connection
##################################
echo "::group::hana"
echo "${bold}Load HANA database...${endbold}"
export HANA_HOST=917df316-4e01-4a10-be54-eac1b6ab15fb.hana.prod-us10.hanacloud.ondemand.com
export HANA_PORT=443
export HANA_USER=QGISCI
export HANA_PASSWORD="tQ&7W3Klr9!p"
export QGIS_HANA_TEST_DB='driver='/usr/sap/hdbclient/libodbcHDB.so' host='${HANA_HOST}' port='${HANA_PORT}' user='${HANA_USER}' password='${HANA_PASSWORD}' sslEnabled=true sslValidateCertificate=False'
# wait for the DB to be available
echo "Wait a moment while trying to connect to a HANA database."
while ! echo exit | hdbsql -n '${HANA_HOST}:${HANA_PORT}' -u '${HANA_USER}' -p '${HANA_PASSWORD}' &> /dev/null
do
printf "⚘"
sleep 1
done
echo "🌊 done"
echo "::endgroup::"
fi
if [ ${RUN_POSTGRES:-"NO"} == "YES" ]; then
echo "::group::Setup PostgreSQL"
############################
# Restore postgres test data
############################
echo "${bold}Load Postgres database...🐘${endbold}"
printf "[qgis_test]\nhost=postgres\nport=5432\ndbname=qgis_test\nuser=docker\npassword=docker" > ~/.pg_service.conf
export PGUSER=docker
export PGHOST=postgres
export PGPASSWORD=docker
export PGDATABASE=qgis_test
# wait for the DB to be available
echo "Wait a moment while loading PostGreSQL database."
while ! PGPASSWORD='docker' psql -h postgres -U docker -p 5432 -l &> /dev/null
do
printf "🐘"
sleep 1
done
echo " done 🥩"
pushd ${SRCDIR} > /dev/null
echo "Restoring postgres test data ..."
${SRCDIR}/tests/testdata/provider/testdata_pg.sh
echo "Postgres test data restored ..."
popd > /dev/null # /root/QGIS
echo "::endgroup::"
fi
if [ ${RUN_ORACLE:-"NO"} == "YES" ]; then
echo "::group::Setup Oracle"
##############################
# Restore Oracle test data
##############################
echo "${bold}Load Oracle database...🙏${endbold}"
export ORACLE_HOST="oracle"
export ORACLE_PDB="XEPDB1"
export QGIS_ORACLETEST_DBNAME="${ORACLE_HOST}/${ORACLE_PDB}"
export QGIS_ORACLETEST_DB="host=${ORACLE_HOST} dbname=${ORACLE_PDB} port=1521 user='QGIS' password='qgis'"
echo "Wait a moment while loading Oracle database."
COUNT=0
while ! echo exit | sqlplus -L SYSTEM/adminpass@$QGIS_ORACLETEST_DBNAME &> /dev/null
do
printf "🙏"
sleep 5
if [[ $(( COUNT++ )) -eq 40 ]]; then
break
fi
done
if [[ ${COUNT} -eq 41 ]]; then
echo "timeout, no oracle, no 🙏"
else
echo " done 👀"
pushd ${SRCDIR} > /dev/null
${SRCDIR}/tests/testdata/provider/testdata_oracle.sh $ORACLE_HOST
popd > /dev/null # /root/QGIS
fi
echo "::endgroup::"
fi
if [ ${RUN_SQLSERVER:-"NO"} == "YES" ]; then
echo "::group::Setup SQL Server"
##############################
# Restore SQL Server test data
##############################
echo "Wait a moment before loading SQL Server database."
sleep 15
echo "Importing SQL Server test data..."
export SQLUSER=sa
export SQLHOST=mssql
export SQLPORT=1433
export SQLPASSWORD=QGIStestSQLServer1234
export SQLDATABASE=qgis_test
export PATH=$PATH:/opt/mssql-tools/bin
pushd ${SRCDIR} > /dev/null
${SRCDIR}/tests/testdata/provider/testdata_mssql.sh
popd > /dev/null # ${SRCDIR}
echo "Setting up DSN for test SQL Server"
cat <<EOT > /etc/odbc.ini
[ODBC Data Sources]
testsqlserver = ODBC Driver 18 for SQL Server
[testsqlserver]
Driver = ODBC Driver 18 for SQL Server
Description = Test SQL Server
Server = mssql
Encrypt = no
AllowSelfSignedServerCert=1
EOT
echo "::endgroup::"
fi
#######################################
# Wait for Minio container to be ready
#######################################
if [ $# -eq 0 ] || [ $1 = "ALL_BUT_PROVIDERS" ] || [ $1 = "ALL" ] ; then
echo "::group::Setup Minio"
echo "Wait for minio to be ready..."
COUNT=0
while ! curl http://$QGIS_MINIO_HOST:$QGIS_MINIO_PORT &> /dev/null;
do
printf "."
sleep 5
if [[ $(( COUNT++ )) -eq 40 ]]; then
break
fi
done
if [[ ${COUNT} -eq 41 ]]; then
echo "Error: Minio docker timeout!!!"
else
echo "done"
fi
echo "::endgroup::"
fi
#######################################
# Wait for WebDAV container to be ready
#######################################
if [ $# -eq 0 ] || [ $1 = "ALL_BUT_PROVIDERS" ] || [ $1 = "ALL" ] ; then
echo "::group::Setup WebDAV"
echo "Wait for webdav to be ready..."
COUNT=0
while ! curl -f -X GET -u qgis:myPasswd! http://$QGIS_WEBDAV_HOST:$QGIS_WEBDAV_PORT/webdav_tests/ &> /dev/null;
do
printf "."
sleep 5
if [[ $(( COUNT++ )) -eq 40 ]]; then
break
fi
done
if [[ ${COUNT} -eq 41 ]]; then
echo "Error: WebDAV docker timeout!!!"
else
echo "done"
fi
echo "::endgroup::"
fi
###########
# Run tests
###########
EXCLUDE_TESTS="^$(cat ${SRCDIR}/.ci/test_blocklist_qt${QT_VERSION}.txt | sed -r '/^(#.*?)?$/d' | paste -sd '~' | sed -r 's/~/\$|^/g' -)\$"
if ! [[ ${RUN_FLAKY_TESTS} == true ]]; then
echo "Flaky tests are skipped!"
EXCLUDE_TESTS=${EXCLUDE_TESTS}"|^"$(cat ${SRCDIR}/.ci/test_flaky.txt | sed -r '/^(#.*?)?$/d' | paste -sd '~' | sed -r 's/~/\$|^/g' -)"$"
else
echo "Flaky tests are run!"
fi
echo "List of skipped tests: $EXCLUDE_TESTS"
echo "::group::Print disk space before running tests"
df -h
echo "::endgroup::"
export QTWEBENGINE_DISABLE_SANDBOX=1
python3 ${SRCDIR}/.ci/ctest2ci.py xvfb-run ctest -V $CTEST_OPTIONS -E "${EXCLUDE_TESTS}" -S ${SRCDIR}/.ci/config_test.ctest --output-on-failure
echo "::group::Print disk space after running tests"
df -h
echo "::endgroup::"

View File

@ -0,0 +1,28 @@
# CTEST
SEGFAULT_SIGNALS="abrt segv"
CTEST_BUILD_COMMAND=/usr/bin/ninja
CTEST_PARALLEL_LEVEL=1
CTEST_SOURCE_DIR=/root/QGIS
CTEST_BUILD_DIR=/root/QGIS/build
# CTEST vars defined in workflow
CTEST_BUILD_NAME
RUN_FLAKY_TESTS
QT_VERSION
# Other vars
QGIS_NO_OVERRIDE_IMPORT=1
# This is used in some tests to be skipped
QGIS_CONTINUOUS_INTEGRATION_RUN=true
PUSH_TO_CDASH=false
XDG_RUNTIME_DIR=/tmp
QGIS_MINIO_HOST=minio
QGIS_MINIO_PORT=9000
QGIS_WEBDAV_HOST=webdav
QGIS_WEBDAV_PORT=80

79
.docker/qgis.dockerfile Normal file
View File

@ -0,0 +1,79 @@
# see https://docs.docker.com/docker-cloud/builds/advanced/
# using ARG in FROM requires min v17.05.0-ce
ARG DOCKER_DEPS_TAG=latest
FROM qgis/qgis3-build-deps:${DOCKER_DEPS_TAG} AS BUILDER
MAINTAINER Denis Rouzaud <denis@opengis.ch>
LABEL Description="Docker container with QGIS" Vendor="QGIS.org" Version="1.1"
# build timeout in seconds, so no timeout by default
ARG BUILD_TIMEOUT=360000
ARG CC=/usr/lib/ccache/gcc
ARG CXX=/usr/lib/ccache/g++
ENV LANG=C.UTF-8
COPY . /QGIS
# If this directory is changed, also adapt script.sh which copies the directory
# if ccache directory is not provided with the source
RUN mkdir -p /QGIS/.ccache_image_build
ENV CCACHE_DIR=/QGIS/.ccache_image_build
RUN ccache -M 1G
RUN ccache -s
RUN echo "ccache_dir: "$(du -h --max-depth=0 ${CCACHE_DIR})
WORKDIR /QGIS/build
RUN SUCCESS=OK \
&& cmake \
-GNinja \
-DUSE_CCACHE=OFF \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr \
-DWITH_DESKTOP=ON \
-DWITH_SERVER=ON \
-DWITH_3D=ON \
-DWITH_BINDINGS=ON \
-DWITH_CUSTOM_WIDGETS=ON \
-DBINDINGS_GLOBAL_INSTALL=ON \
-DWITH_STAGED_PLUGINS=ON \
-DWITH_GRASS=ON \
-DDISABLE_DEPRECATED=ON \
-DENABLE_TESTS=OFF \
-DWITH_QSPATIALITE=ON \
-DWITH_APIDOC=OFF \
-DWITH_ASTYLE=OFF \
.. \
&& ninja install || SUCCESS=FAILED \
&& echo "$SUCCESS" > /QGIS/build_exit_value
# Additional run-time dependencies
RUN pip3 install jinja2 pygments pexpect && apt install -y expect
################################################################################
# Python testing environment setup
# Add QGIS test runner
COPY .docker/qgis_resources/test_runner/qgis_* /usr/bin/
# Make all scripts executable
RUN chmod +x /usr/bin/qgis_*
# Add supervisor service configuration script
COPY .docker/qgis_resources/supervisor/ /etc/supervisor
# Python paths are for
# - kartoza images (compiled)
# - deb installed
# - built from git
# needed to find PyQt wrapper provided by QGIS
ENV PYTHONPATH=/usr/share/qgis/python/:/usr/share/qgis/python/plugins:/usr/lib/python3/dist-packages/qgis:/usr/share/qgis/python/qgis
WORKDIR /
# Run supervisor
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]

View File

@ -0,0 +1,249 @@
ARG DISTRO_VERSION=24.04
ARG PDAL_VERSION=2.8.4
# Oracle Docker image is too large, so we add as less dependencies as possible
# so there is enough space on GitHub runner
FROM ubuntu:${DISTRO_VERSION} AS binary-for-oracle
LABEL org.opencontainers.image.authors="Denis Rouzaud <denis@opengis.ch>"
LABEL Description="Docker container with QGIS dependencies" Vendor="QGIS.org" Version="1.0"
ARG PDAL_VERSION
# && echo "deb http://ppa.launchpad.net/ubuntugis/ubuntugis-unstable/ubuntu xenial main" >> /etc/apt/sources.list \
# && echo "deb-src http://ppa.launchpad.net/ubuntugis/ubuntugis-unstable/ubuntu xenial main" >> /etc/apt/sources.list \
# && apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 314DF160 \
RUN apt-get update \
&& apt-get install -y software-properties-common \
&& apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y \
apt-transport-https \
ca-certificates \
clazy \
cmake \
curl \
dh-python \
git \
gdal-bin \
gnupg \
gpsbabel \
graphviz \
'libaio1|libaio1t64' \
'libdraco4|libdraco8' \
libexiv2-27 \
'libfcgi0ldbl|libfcgi0t64' \
libgsl27 \
'libprotobuf-lite17|libprotobuf-lite23|libprotobuf-lite32t64' \
libqca-qt5-2-plugins \
libqt53dextras5 \
libqt53drender5 \
'libqt5concurrent5|libqt5concurrent5t64' \
libqt5keychain1 \
libqt5positioning5 \
libqt5multimedia5 \
libqt5multimediawidgets5 \
libqt5qml5 \
libqt5quick5 \
libqt5quickcontrols2-5 \
libqt5quickwidgets5 \
libqt5serialport5 \
libqt5sql5-odbc \
libqt5sql5-sqlite \
'libqt5xml5|libqt5xml5t64' \
libqt5webkit5 \
libqwt-qt5-6 \
libspatialindex6 \
libsqlite3-mod-spatialite \
'libzip4|libzip5|libzip4t64' \
lighttpd \
locales \
poppler-utils \
python3-future \
python3-gdal \
python3-mock \
python3-nose2 \
python3-numpy \
python3-owslib \
python3-pip \
python3-psycopg2 \
python3-pyproj \
python3-pyqt5 \
python3-pyqt5.qsci \
python3-pyqt5.qtsql \
python3-pyqt5.qtsvg \
python3-pyqt5.qtwebkit \
python3-pyqt5.qtpositioning \
python3-pyqt5.qtmultimedia \
python3-pyqt5.qtserialport \
python3-sip \
python3-termcolor \
python3-yaml \
qpdf \
qt3d-assimpsceneimport-plugin \
qt3d-defaultgeometryloader-plugin \
qt3d-gltfsceneio-plugin \
qt3d-scene2d-plugin \
qt5-image-formats-plugins \
saga \
supervisor \
unzip \
xauth \
xfonts-100dpi \
xfonts-75dpi \
xfonts-base \
xfonts-scalable \
xvfb \
ocl-icd-libopencl1 \
&& pip3 install --break-system-packages \
numpy \
nose2 \
pyyaml \
mock \
future \
termcolor \
oauthlib \
pyopenssl \
pep8 \
pexpect \
capturer \
sphinx \
requests \
six \
hdbcli \
shapely \
&& apt-get clean
# Node.js and Yarn for server landingpage webapp
RUN mkdir -p /etc/apt/keyrings
RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
RUN apt-get update
RUN apt-get install -y nodejs
RUN corepack enable
# Oracle : client side
RUN curl https://download.oracle.com/otn_software/linux/instantclient/2116000/instantclient-basic-linux.x64-21.16.0.0.0dbru.zip > instantclient-basic-linux.x64-21.16.0.0.0dbru.zip
RUN curl https://download.oracle.com/otn_software/linux/instantclient/2116000/instantclient-sdk-linux.x64-21.16.0.0.0dbru.zip > instantclient-sdk-linux.x64-21.16.0.0.0dbru.zip
RUN curl https://download.oracle.com/otn_software/linux/instantclient/2116000/instantclient-sqlplus-linux.x64-21.16.0.0.0dbru.zip > instantclient-sqlplus-linux.x64-21.16.0.0.0dbru.zip
RUN unzip -n instantclient-basic-linux.x64-21.16.0.0.0dbru.zip
RUN unzip -n instantclient-sdk-linux.x64-21.16.0.0.0dbru.zip
RUN unzip -n instantclient-sqlplus-linux.x64-21.16.0.0.0dbru.zip
ENV PATH="/instantclient_21_16:${PATH}"
ENV LD_LIBRARY_PATH="/instantclient_21_16"
# workaround noble libaio SONAME issue -- see https://bugs.launchpad.net/ubuntu/+source/libaio/+bug/2067501
RUN if [ -e /usr/lib/x86_64-linux-gnu/libaio.so.1t64 ] ; then ln -sf /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1 ; fi
# Avoid sqlcmd termination due to locale -- see https://github.com/Microsoft/mssql-docker/issues/163
RUN echo "nb_NO.UTF-8 UTF-8" > /etc/locale.gen
RUN echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
RUN locale-gen
RUN echo "alias python=python3" >> ~/.bash_aliases
# PDAL is not available in ubuntu 24.04
# Install it from source
# PDAL dependencies
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y \
ninja-build \
libgdal-dev \
libproj-dev
# download PDAL and compile it
RUN curl -L https://github.com/PDAL/PDAL/releases/download/${PDAL_VERSION}/PDAL-${PDAL_VERSION}-src.tar.gz --output PDAL-${PDAL_VERSION}-src.tar.gz \
&& mkdir pdal \
&& tar zxf PDAL-${PDAL_VERSION}-src.tar.gz -C pdal --strip-components=1 \
&& rm -f PDAL-${PDAL_VERSION}-src.tar.gz \
&& mkdir -p pdal/build \
&& cd pdal/build \
&& cmake -GNinja -DCMAKE_INSTALL_PREFIX=/usr/local -DWITH_TESTS=OFF .. \
&& ninja \
&& ninja install
FROM binary-for-oracle AS binary-only
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y \
grass \
iproute2 \
postgresql-client \
spawn-fcgi \
&& pip3 install --break-system-packages \
psycopg2 \
&& apt-get clean
# HANA: client side
# Install hdbsql tool
RUN curl -j -k -L -H "Cookie: eula_3_2_agreed=tools.hana.ondemand.com/developer-license-3_2.txt" https://tools.hana.ondemand.com/additional/hanaclient-latest-linux-x64.tar.gz --output hanaclient-latest-linux-x64.tar.gz \
&& tar -xvf hanaclient-latest-linux-x64.tar.gz \
&& mkdir /usr/sap \
&& ./client/hdbinst -a client --sapmnt=/usr/sap \
&& rm -rf client \
&& rm hanaclient*
ENV PATH="/usr/sap/hdbclient:${PATH}"
# MSSQL: client side
RUN curl -sSL -O https://packages.microsoft.com/config/ubuntu/$(grep VERSION_ID /etc/os-release | cut -d '"' -f 2)/packages-microsoft-prod.deb
RUN dpkg -i packages-microsoft-prod.deb
RUN rm packages-microsoft-prod.deb
RUN apt-get update
RUN ACCEPT_EULA=Y apt-get install -y --allow-unauthenticated msodbcsql18 mssql-tools18
ENV PATH="/opt/mssql-tools18/bin:${PATH}"
FROM binary-only
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y \
bison \
ccache \
clang \
cmake \
flex \
grass-dev \
libdraco-dev \
libexiv2-dev \
libexpat1-dev \
libfcgi-dev \
libgeos-dev \
libgsl-dev \
libpq-dev \
libprotobuf-dev \
libqca-qt5-2-dev \
libqt5opengl5-dev \
libqt5scintilla2-dev \
libqt5svg5-dev \
libqt5webkit5-dev \
libqt5serialport5-dev \
libqwt-qt5-dev \
libspatialindex-dev \
libspatialite-dev \
libsqlite3-dev \
libsqlite3-mod-spatialite \
libzip-dev \
libzstd-dev \
protobuf-compiler \
pyqt5-dev \
pyqt5-dev-tools \
pyqt5.qsci-dev \
python3-all-dev \
python3-dev \
python3-sip-dev \
qt3d5-dev \
qt5keychain-dev \
qtbase5-dev \
qtdeclarative5-dev-tools \
qtpositioning5-dev \
qtmultimedia5-dev \
qttools5-dev \
qttools5-dev-tools \
qtbase5-private-dev \
opencl-headers \
ocl-icd-opencl-dev \
&& apt-get clean
ENV PATH="/usr/local/bin:${PATH}"
# environment variables shall be located in .docker/docker-variables.env

View File

@ -0,0 +1,119 @@
ARG DISTRO_VERSION=39
FROM fedora:${DISTRO_VERSION} AS binary-for-oracle
LABEL org.opencontainers.image.authors="Matthias Kuhn <matthias@opengis.ch>"
RUN dnf -y --refresh install \
bison \
ccache \
clang \
clazy \
curl \
draco-devel \
exiv2-devel \
expat-devel \
fcgi-devel \
flex \
fontconfig-devel \
freetype-devel \
git \
gdal \
gdal-devel \
gdal-python-tools \
geos-devel \
gpsbabel \
grass \
grass-devel \
gsl-devel \
lcms2-devel \
libjpeg-turbo-devel \
libpq-devel \
libspatialite-devel \
libxml2-devel \
libzip-devel \
libzstd-devel \
libaio \
mold \
netcdf-devel \
ninja-build \
ocl-icd-devel \
openjpeg2-devel \
PDAL \
PDAL-libs \
PDAL-devel \
perl-YAML-Tiny \
poppler-utils \
proj-devel \
protobuf-devel \
protobuf-lite-devel \
python3-devel \
python3-mock \
python3-oauthlib \
python3-OWSLib \
python3-pyqt6 \
python3-pyqt6-devel \
python3-qscintilla-qt6 \
python3-qscintilla-qt6-devel \
python3-termcolor \
PyQt-builder \
qca-qt6-devel \
qpdf \
qt6-qt3d-devel \
qt6-qtbase-devel \
qt6-qtbase-private-devel \
qt6-qtdeclarative-devel \
qt6-qttools-static \
qt6-qtserialport-devel \
qt6-qtsvg-devel \
qt6-qtpositioning-devel \
qt6-qtdeclarative-devel \
qt6-qt5compat-devel \
qt6-qtmultimedia-devel \
qt6-qtwebengine-devel \
qtkeychain-qt6-devel \
qwt-qt6-devel \
qscintilla-qt6-devel \
sip6 \
spatialindex-devel \
sqlite-devel \
unzip \
unixODBC-devel \
xorg-x11-server-Xvfb \
util-linux \
wget \
openssl-devel \
libsecret-devel \
make \
automake \
gcc \
gcc-c++ \
kernel-devel \
ninja-build \
patch \
dos2unix
# Oracle : client side
RUN curl https://download.oracle.com/otn_software/linux/instantclient/2116000/instantclient-basic-linux.x64-21.16.0.0.0dbru.zip > instantclient-basic-linux.x64-21.16.0.0.0dbru.zip
RUN curl https://download.oracle.com/otn_software/linux/instantclient/2116000/instantclient-sdk-linux.x64-21.16.0.0.0dbru.zip > instantclient-sdk-linux.x64-21.16.0.0.0dbru.zip
RUN curl https://download.oracle.com/otn_software/linux/instantclient/2116000/instantclient-sqlplus-linux.x64-21.16.0.0.0dbru.zip > instantclient-sqlplus-linux.x64-21.16.0.0.0dbru.zip
RUN unzip -n instantclient-basic-linux.x64-21.16.0.0.0dbru.zip
RUN unzip -n instantclient-sdk-linux.x64-21.16.0.0.0dbru.zip
RUN unzip -n instantclient-sqlplus-linux.x64-21.16.0.0.0dbru.zip
ENV PATH="/instantclient_21_16:${PATH}"
ENV LD_LIBRARY_PATH="/instantclient_21_16"
ENV LANG=C.UTF-8
FROM binary-for-oracle AS binary-only
RUN dnf -y install \
python3-gdal \
python3-nose2 \
python3-psycopg2 \
python3-pyyaml \
python3-shapely
FROM binary-only

View File

@ -0,0 +1,7 @@
pep8
pexpect
capturer
sphinx
requests
future
six

View File

@ -0,0 +1,4 @@
; Supervisor config file for Xvfb
[program:Xvfb]
command=/usr/bin/Xvfb :99 -screen 0 1024x768x24 -ac +extension GLX +render -noreset -nolisten tcp

View File

@ -0,0 +1,13 @@
; Supervisor config file.
[supervisord]
nodaemon=true
logfile=/var/log/supervisor/supervisord.log
logfile_maxbytes=50MB
logfile_backups=10
loglevel=info
pidfile=/var/run/supervisord.pid
childlogdir=/var/log
[include]
files = /etc/supervisor/supervisor.d/*.conf

View File

@ -0,0 +1,63 @@
#!/bin/bash
# Setup QGIS for the automated tests
# This is normally called from Travis or rundockertests.sh
# before running the tests for a particular plugin
#
# Note: on QGIS3 assumes the default profile for root user
#
# - create the folders
# - install startup.py monkey patches
# - disable tips
# - enable the plugin (optionally)
PLUGIN_NAME=$1
CONF_MASTER_FOLDER="/root/.local/share/QGIS/QGIS3/profiles/default/QGIS/"
CONF_MASTER_FILE="${CONF_MASTER_FOLDER}/QGIS3.ini"
QGIS_MASTER_FOLDER="/root/.local/share/QGIS/QGIS3/profiles/default"
PLUGIN_MASTER_FOLDER="${QGIS_MASTER_FOLDER}/python/plugins"
STARTUP_MASTER_FOLDER="/root/.local/share/QGIS/QGIS3/"
# Creates the config file
mkdir -p $CONF_MASTER_FOLDER
if [ -e "$CONF_MASTER_FILE" ]; then
rm -f $CONF_MASTER_FILE
fi
touch $CONF_MASTER_FILE
# Creates plugin folder
mkdir -p $PLUGIN_MASTER_FOLDER
mkdir -p $STARTUP_MASTER_FOLDER
# Install the monkey patches to prevent modal stacktrace on python errors
cp /usr/bin/qgis_startup.py ${STARTUP_MASTER_FOLDER}/startup.py
# Disable tips
printf "[qgis]\n" >> $CONF_MASTER_FILE
SHOW_TIPS=$(qgis --help 2>&1 | head -2 | grep 'QGIS - ' | perl -npe 'chomp; s/QGIS - (\d+)\.(\d+).*/showTips\1\2=false/')
printf "%s\n\n" "$SHOW_TIPS" >> $CONF_MASTER_FILE
if [[ -n "$PLUGIN_NAME" ]]; then
# Enable plugin
printf '[PythonPlugins]\n' >> $CONF_MASTER_FILE
printf "%s=true\n\n" "$PLUGIN_NAME" >> $CONF_MASTER_FILE
# Install the plugin
if [ ! -d "${PLUGIN_MASTER_FOLDER}/${PLUGIN_NAME}" ]; then
plugin_dir="/tests_directory/${PLUGIN_NAME}"
if [ ! -d "${plugin_dir}" ]; then
echo "ERROR: ${plugin_dir} does not exist" >&2
exit 1
fi
ln -s "${plugin_dir}" "${PLUGIN_MASTER_FOLDER}"
echo "Plugin master folder linked in ${PLUGIN_MASTER_FOLDER}/${PLUGIN_NAME}"
fi
fi
# Disable firstRunVersionFlag for master
echo "
[migration]
fileVersion=2
firstRunVersionFlag=30500
settings=true
" >> $CONF_MASTER_FILE

View File

@ -0,0 +1,29 @@
"""
Disable QGIS modal error dialog.
This script is meant to be run automatically when QGIS starts.
Is should be renamed to `startup.py` and placed into
~/.qgis3/python/startup.py
"""
import traceback
from qgis import utils
from qgis.core import Qgis
def _showException(type, value, tb, msg, messagebar=False, level=Qgis.Warning):
print(msg)
logmessage = ""
for s in traceback.format_exception(type, value, tb):
logmessage += s.decode("utf-8", "replace") if hasattr(s, "decode") else s
print(logmessage)
def _open_stack_dialog(type, value, tb, msg, pop_error=True):
print(msg)
utils.showException = _showException
utils.open_stack_dialog = _open_stack_dialog

View File

@ -0,0 +1,185 @@
#!/usr/bin/env python
"""
***************************************************************************
Launches a unit test inside QGIS and exit the application.
Arguments:
accepts a single argument with the package name in python dotted notation,
the program tries first to load the module and launch the `run_all`
function of the module, if that fails it considers the last part of
the dotted path to be the function name and the previous part to be the
module.
Extra options for QGIS command line can be passed in the env var
QGIS_EXTRA_OPTIONS
Example run:
# Will load geoserverexplorer.test.catalogtests and run `run_all`
QGIS_EXTRA_OPTIONS='--optionspath .' \
GSHOSTNAME=localhost \
python qgis_testrunner.py geoserverexplorer.test.catalogtests
GSHOSTNAME=localhost \
python qgis_testrunner.py geoserverexplorer.test.catalogtests.run_my
---------------------
Date : May 2016
Copyright : (C) 2016 by Alessandro Pasotti
Email : apasotti at boundlessgeo dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
__author__ = "Alessandro Pasotti"
__date__ = "May 2016"
import importlib
import os
import re
import signal
import sys
import traceback
from shlex import quote
from pexpect import run
from qgis.utils import iface
def eprint(text):
sys.__stderr__.write(text + "\n")
def __get_test_function(test_module_name):
"""
Load the test module and return the test function
"""
print("QGIS Test Runner - Trying to import %s" % test_module_name)
try:
test_module = importlib.import_module(test_module_name)
function_name = "run_all"
except ImportError as e:
# traceback.print_exc(file=sys.stdout)
# Strip latest name
pos = test_module_name.rfind(".")
if pos <= 0:
raise e
test_module_name, function_name = (
test_module_name[:pos],
test_module_name[pos + 1 :],
)
print("QGIS Test Runner - Trying to import %s" % test_module_name)
sys.stdout.flush()
try:
test_module = importlib.import_module(test_module_name)
except ImportError as e:
# traceback.print_exc(file=sys.stdout)
raise e
return getattr(test_module, function_name, None)
if iface is None:
"""
Launch QGIS and passes itself as an init script
"""
sys.path.append(os.getcwd())
test_module_name = sys.argv[-1]
if __get_test_function(test_module_name) is None:
print(
"QGIS Test Runner - [ERROR] cannot load test function from %s"
% test_module_name
)
sys.exit(1)
try:
me = __file__
except NameError:
me = sys.argv[0]
os.environ["QGIS_DEBUG"] = "1"
args = [
"qgis",
os.environ.get("QGIS_EXTRA_OPTIONS", ""),
"--nologo",
"--noversioncheck",
"--code",
me,
test_module_name, # Must be the last one!
]
command_line = " ".join(args)
print("QGIS Test Runner - launching QGIS as %s ..." % command_line)
out, returncode = run("sh -c " + quote(command_line), withexitstatus=1)
if isinstance(out, bytes):
out = out.decode("utf-8")
assert returncode is not None
print("QGIS Test Runner - QGIS exited.")
ok = (
out.find("(failures=") < 0
and len(re.findall(r"Ran \d+ tests in\s", out, re.MULTILINE)) > 0
)
print("=" * 60)
if not ok:
print(out)
else:
eprint(out)
if len(out) == 0:
print("QGIS Test Runner - [WARNING] subprocess returned no output")
print("=" * 60)
print(
"QGIS Test Runner - {} bytes returned and finished with exit code: {}".format(
len(out), 0 if ok else 1
)
)
sys.exit(0 if ok else 1)
else: # We are inside QGIS!
# Start as soon as the initializationCompleted signal is fired
from qgis.core import QgsApplication, QgsProject, QgsProjectBadLayerHandler
from qgis.PyQt.QtCore import QDir
from qgis.utils import iface
class QgsProjectBadLayerDefaultHandler(QgsProjectBadLayerHandler):
def handleBadLayers(self, layers, dom):
pass
# Monkey patch QGIS Python console
from console.console_output import writeOut
def _write(self, m):
sys.__stdout__.write(m)
writeOut.write = _write
# Add current working dir to the python path
sys.path.append(QDir.current().path())
def __run_test():
"""
Run the test specified as last argument in the command line.
"""
# Disable modal handler for bad layers
QgsProject.instance().setBadLayerHandler(QgsProjectBadLayerDefaultHandler())
eprint("QGIS Test Runner Inside - starting the tests ...")
try:
test_module_name = QgsApplication.instance().arguments()[-1]
function_name = __get_test_function(test_module_name)
eprint("QGIS Test Runner Inside - executing function %s" % function_name)
function_name()
except Exception as e:
eprint("QGIS Test Runner Inside - [FAILED] Exception: %s" % e)
# Print tb
traceback.print_exc(file=sys.stdout)
app = QgsApplication.instance()
os.kill(app.applicationPid(), signal.SIGTERM)
iface.initializationCompleted.connect(__run_test)

View File

@ -0,0 +1,43 @@
#!/bin/bash
# Run a python test inside QGIS
# Note: the test module and function are specified in dotted notation
# for example, to run the test function run_all (which is the default anyway)
# $ qgis_testrunner.sh tests_folder.test_module.run_all
# tests_folder must be in PYTHONPATH (plugins main folders are automatically added to path)
### Turn on debug mode ###
#set -x
TEST_NAME=$1
TEST_RUNNER_PATH=${TEST_RUNNER_PATH:-/usr/bin/qgis_testrunner.py}
QGIS_BUILD_PATH=${QGIS_BUILD_PATH:-qgis}
LOGFILE=/tmp/qgis_testrunner_$$
echo "Running test $1 ..."
QGIS_TEST_MODULE=${TEST_NAME} unbuffer ${QGIS_BUILD_PATH} \
--version-migration --nologo --code \
${TEST_RUNNER_PATH} "$TEST_NAME" \
2>/dev/null | \
tee ${LOGFILE}
# NOTE: EXIT_CODE will always be 0 if "tee" works,
# we could `set -o pipefail` to change this
EXIT_CODE="$?"
OUTPUT=$(cat $LOGFILE) # quick hack to avoid changing too many lines
if [ -z "$OUTPUT" ]; then
echo "ERROR: no output from the test runner! (exit code: ${EXIT_CODE})"
exit 1
fi
echo "$OUTPUT" | grep -q 'FAILED'
IS_FAILED="$?"
echo "$OUTPUT" | grep -q 'OK' && echo "$OUTPUT" | grep -q 'Ran'
IS_PASSED="$?"
echo "$OUTPUT" | grep "QGIS died on signal"
IS_DEAD="$?"
echo "Finished running test $1 (codes: IS_DEAD=$IS_DEAD IS_FAILED=$IS_FAILED IS_PASSED=$IS_PASSED)."
if [ "$IS_PASSED" -eq "0" ] && [ "$IS_FAILED" -eq "1" ] && [ "$IS_DEAD" -eq "1" ]; then
exit 0;
fi
exit 1

21
.docker/webdav/nginx.conf Normal file
View File

@ -0,0 +1,21 @@
server {
listen 80;
listen [::]:80;
server_name localhost;
location /webdav_tests {
auth_basic realm_name;
auth_basic_user_file /etc/nginx/.passwords.list;
dav_methods PUT DELETE MKCOL COPY MOVE;
#dav_ext_methods PROPFIND OPTIONS;
dav_access user:rw group:rw all:r;
autoindex on;
client_max_body_size 0;
create_full_put_path on;
root /tmp/webdav_tests_root;
}
}

View File

@ -0,0 +1 @@
qgis:$apr1$cxID/nB1$3tG4J0FkYvEHyWAB.yqjo.

4
.dockerignore Normal file
View File

@ -0,0 +1,4 @@
/.ci
/.git
/.github
build*

17
.editorconfig Normal file
View File

@ -0,0 +1,17 @@
# See http://editorconfig.org
# top-most EditorConfig file
root = true
# every file needs these
[*]
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 2
# python scripts have 4 spaces indent
[*.py]
indent_size = 4

4
.git-blame-ignore-revs Normal file
View File

@ -0,0 +1,4 @@
0f032e5f2d78d0d0ba2edb4a20c4853e77ec0fc4 # python formatting after pre-commit introduction
33ea41a100e8eea891c1d9d95fe34e346c3e71d1 # clang-format on non sipified files
00fecc29bbe2e295d75c2dad4b9090f7afba739a # clang-format src/analysis
3a4f8bcdad4f843d7217116ac1cb94b6b6c3fb8b # clang-format src/3d + server

3
.gitattributes vendored Normal file
View File

@ -0,0 +1,3 @@
*.sip export-subst
*.py export-subst
tests/testdata/auth_system/certs_keys/donald_key_DSA_crlf.pem text eol=crlf

View File

@ -0,0 +1,72 @@
name: Bug/Crash report but not related to a third party plugin, read below for plugins
description: Create a bug report to help us improve QGIS.
labels:
- 'Bug'
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report correctly.
Please report only issues related to the QGIS application.
If the issue is related to a plugin, you should file the issue in the plugin code repository.
You can find the URL in the QGIS Plugin Manager.
- type: textarea
id: what
attributes:
label: What is the bug or the crash?
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to reproduce the issue
description: |
Steps, sample datasets and qgis project file to reproduce the behavior. Screencasts or screenshots are more than welcome, you can drag&drop them in the text box.
1. Go to '...'
2. Click on '...'
3. Scroll down to '...'
4. See error
validations:
required: true
- type: textarea
id: about-info
attributes:
label: Versions
description: |
In the QGIS Help menu -> About, click on the "Copy to Clipboard" button, then paste here.
validations:
required: true
- type: checkboxes
id: qgis-version
attributes:
label: Supported QGIS version
description: |
Each month, there is a new release of QGIS. According to the release schedule, you should at least be running a supported QGIS version.
You can check the release schedule https://www.qgis.org/en/site/getinvolved/development/roadmap.html#release-schedule
options:
- label: I'm running a supported QGIS version according to [the roadmap](https://www.qgis.org/en/site/getinvolved/development/roadmap.html#release-schedule).
- type: checkboxes
id: new-profile
attributes:
label: New profile
description: |
Did you try with a new QGIS profile? Some issues or crashes might be related to plugins or user configuration.
You must try with a new profile to check if the issue remains.
Read this link how to create a new profile
https://docs.qgis.org/latest/en/docs/user_manual/introduction/qgis_configuration.html#working-with-user-profiles
options:
- label: I tried with a new [QGIS profile](https://docs.qgis.org/latest/en/docs/user_manual/introduction/qgis_configuration.html#working-with-user-profiles)
- type: textarea
id: additional-context
attributes:
label: Additional context
description: |
Add any other context about the problem here.

View File

@ -0,0 +1,25 @@
name: Feature request
description: Suggest a feature idea for QGIS.
labels:
- 'Feature Request'
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this feature request correctly.
- type: textarea
id: what
attributes:
label: Feature description
description: A clear and concise description of what you want to happen. Ex. QGIS would rock even more if [...]
validations:
required: true
- type: textarea
id: Additional
attributes:
label: Additional context
description: |
Add any other context or screenshots about the feature request here. Open source is community driven, please consider a way to support this work either by hiring developers, supporting the QGIS project, find someone to submit a pull request.
If the change required is important, you should consider writing a [QGIS Enhancement Proposal](https://github.com/qgis/QGIS-Enhancement-Proposals/issues) (QEP) or hiring someone to, and announce your work on the lists.

View File

@ -0,0 +1,19 @@
name: API documentation (C++ or PyQGIS)
description: An issue about the C++ or PyQGIS documentation
labels:
- 'Documentation'
- 'API'
- 'PyQGIS'
body:
- type: markdown
attributes:
value: |
Report only an issue related to the C++ or PyQGIS documentation
- type: textarea
id: what
attributes:
label: What is the issue about the documentation?
validations:
required: true

21
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,21 @@
blank_issues_enabled: false
contact_links:
- name: Documentation (desktop and server)
url: https://github.com/qgis/QGIS-Documentation/issues
about: Suggest improvements or report errors regarding https://docs.qgis.org
- name: Question
url: https://gis.stackexchange.com/
about: >
Questions should go to the qgis-user mailing list at https://lists.osgeo.org/mailman/listinfo/qgis-user
or other support forums such as https://gis.stackexchange.com/.
GitHub issues are for bug reports and suggestions for new features.
- name: QGIS plugin issue
# There must be a link to make this option valid for GitHub
url: https://plugins.qgis.org
about: >
If the issue concerns a third party plugin (downloaded with the plugin manager) then it can't be fixed
by the QGIS core team. Please raise your issue in the dedicated bug tracker for that specific plugin
(as listed in the plugin's description)

33
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,33 @@
## Description
[Replace this with some text explaining the rationale and details about this pull request]
<!--
BEFORE HITTING SUBMIT -- Please BUILD AND TEST your changes thoroughly. This is YOUR responsibility! Do NOT rely on the QGIS code maintainers to do this for you!!
IMPORTANT NOTES FOR FIRST TIME CONTRIBUTORS
===========================================
Congratulations, you are about to make a pull request to QGIS! To make this as easy and pleasurable for everyone, please take the time to read these lines before opening the pull request.
Include a few sentences describing the overall goals for this pull request (PR). If applicable also add screenshots or - even better - screencasts.
Include both: *what* you changed and *why* you changed it.
If this is a pull request that adds new functionality which needs documentation, give an especially detailed explanation.
In this case, start with a short abstract and then write some text that can be copied 1:1 to the documentation in the best case.
Also mention if you think this PR needs to be backported. And list relevant or fixed issues.
------------------------
Reviewing is a process done by project maintainers, mostly on a volunteer basis. We try to keep the overhead as small as possible and appreciate if you help us to do so by checking the following list.
Feel free to ask in a comment if you have troubles with any of them.
- Commit messages are descriptive and explain the rationale for changes.
- Commits which fix bugs include `Fixes #11111` at the bottom of the commit message. If this is your first pull request and you forgot to do this, write the same statement into this text field with the pull request description.
- New unit tests have been added for relevant changes
- you have read the QGIS Developer Guide (https://docs.qgis.org/testing/en/docs/developers_guide/index.html) and your PR complies with its QGIS Coding Standards
-->

View File

@ -0,0 +1,34 @@
name: 'Get Workflow Artifact IDs'
description: 'Generates consistent artifact IDs and names based on workflow trigger'
outputs:
filename:
description: 'Filename to use for artifacts (e.g. pr123)'
value: ${{ steps.generate-ids.outputs.filename }}
display-name:
description: 'Human readable name (e.g. PR123)'
value: ${{ steps.generate-ids.outputs.display_name }}
runs:
using: "composite"
steps:
- id: generate-ids
shell: bash
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
ID="pr${{ github.event.pull_request.number }}"
DISPLAY_ID="PR${{ github.event.pull_request.number }}"
elif [[ "${{ github.ref }}" == refs/tags/* ]]; then
TAG=${GITHUB_REF#refs/tags/}
ID="$TAG"
DISPLAY_ID="$TAG"
else
SHORT_SHA=$(echo ${{ github.sha }} | cut -c1-7)
BRANCH_NAME=${GITHUB_REF#refs/heads/}
ID="$BRANCH_NAME-$SHORT_SHA"
DISPLAY_ID="$BRANCH_NAME-$SHORT_SHA"
fi
# Set outputs
echo "filename=$ID" >> $GITHUB_OUTPUT
echo "display_name=$DISPLAY_ID" >> $GITHUB_OUTPUT

View File

@ -0,0 +1,54 @@
name: Post Sticky Comment
description: Post a sticky comment
inputs:
marker:
description: Unique marker
required: true
type: string
body:
description: Body
required: true
type: string
pr:
description: Pull Request Number
required: true
type: string
runs:
using: composite
steps:
- name: Create metadata
uses: actions/github-script@v7
env:
BODY: ${{ inputs.body }}
with:
script: |
const fs = require('fs');
try {
// Get inputs from the GitHub Action
const marker = "${{ inputs.marker }}";
const body = process.env.BODY; // Transfer input via env variable as it's not possible to access it directly https://github.com/actions/github-script/issues/56#issuecomment-642188313
const pr = ${{ inputs.pr }};
// Create the content of the JSON file
const content = JSON.stringify({
marker: marker,
body: body,
pr_number: pr
}, null, 2);
console.debug(content)
fs.writeFileSync('comment-${{ github.job }}.json', content);
console.log('comment.json file has been written successfully.');
} catch (error) {
core.setFailed(`Action failed with error: ${error}`);
}
- name: 📤 Upload data
uses: actions/upload-artifact@v4
with:
name: comment_artifacts-${{ github.job }}
path: |
comment-${{ github.job }}.json

31
.github/actions/setup-vcpkg/action.yml vendored Normal file
View File

@ -0,0 +1,31 @@
name: Setup Vcpkg
description: Initialize vcpkg tool, does not checkout the registry
# TODO, set VCPKG_BASE_VERSION based on this
# inputs:
# vcpkg-version:
# description: Enter vcpkg version tag or stable or latest
# required: false
# default: latest
# type: string
runs:
using: composite
steps:
- name: Setup vcpkg
if: runner.os != 'Windows'
shell: bash
run: |
export VCPKG_ROOT=$HOME/.vcpkg
wget https://aka.ms/vcpkg-init.sh -O /tmp/vcpkg-init.sh
. /tmp/vcpkg-init.sh
echo "VCPKG_ROOT=$VCPKG_ROOT" >> $GITHUB_ENV
echo "$VCPKG_ROOT" >> $GITHUB_PATH
- name: Setup vcpkg
if: runner.os == 'Windows'
shell: powershell
run: |
$env:VCPKG_ROOT = "C:/.vcpkg"
iex (iwr -useb https://aka.ms/vcpkg-init.ps1)
echo "VCPKG_ROOT=$env:VCPKG_ROOT" >> $env:GITHUB_ENV
echo "$env:VCPKG_ROOT" >> $env:GITHUB_PATH

View File

@ -0,0 +1,54 @@
name: Compare vcpkg install changes
description: Compares vcpkg install outputs between the base and head refs on pull requests and generates a report.
inputs:
vcpkg-manifest-dir:
description: 'Directory containing the vcpkg.json manifest'
required: true
default: '.'
type: string
triplet:
description: 'Triplet to use for vcpkg installation'
required: true
default: 'x64-linux'
type: string
features:
description: 'Comma separated list of features'
required: false
default: ''
type: string
outputs:
report:
description: 'The report of added and removed packages after vcpkg installation comparison'
value: ${{ steps.compare.outputs.report }}
runs:
using: "composite"
steps:
# Run vcpkg install --dry-run on the head ref
- name: Run vcpkg install (HEAD)
shell: bash
run: |
vcpkg install --dry-run --triplet ${{ inputs.triplet }} --x-manifest-root=${{ inputs.vcpkg-manifest-dir }} $(awk -v FS=',' '{for(i=1; i<=NF; i++) printf "--x-feature=%s ", $i}' <<< "${{ inputs.features }}") --allow-unsupported > /tmp/vcpkg-head-output.txt
# Run vcpkg install --dry-run on the base ref
- name: Run vcpkg install (BASE)
shell: bash
run: |
git worktree add .base-ref ${{ github.event.pull_request.base.sha }}
vcpkg install --dry-run --triplet ${{ inputs.triplet }} --x-manifest-root=.base-ref/${{ inputs.vcpkg-manifest-dir }} $(awk -v FS=',' '{for(i=1; i<=NF; i++) printf "--x-feature=%s ", $i}' <<< "${{ inputs.features }}") --allow-unsupported > /tmp/vcpkg-base-output.txt
# Compare the outputs and generate a report
- name: Compare vcpkg outputs
shell: bash
id: compare
run: |
python3 ${GITHUB_ACTION_PATH}/vcpkg-diff.py > /tmp/vcpkg-report.txt
cat /tmp/vcpkg-report.txt
{
echo 'report<<EOF'
cat /tmp/vcpkg-report.txt
echo EOF
} >> "$GITHUB_OUTPUT"

View File

@ -0,0 +1,101 @@
import re
def extract_packages(data):
"""
Extract package name, triplet, version, and features information from the file content.
"""
packages = {}
lines = data.strip().split("\n")
for line in lines:
# Regex to match the package format and capture features inside brackets
match = re.match(
r"\s*\*?\s+([^\[\]:]+)(?:\[(.*?)\])?:([^\[\]@]+)@([^\s]+)\s+--", line
)
if match:
package_name = match.group(1)
features = match.group(2) if match.group(2) else ""
triplet = match.group(3)
version = match.group(4)
features_list = (
[feature.strip() for feature in features.split(",")] if features else []
)
packages[package_name] = (triplet, version, features_list)
return packages
def compare_features(features1, features2):
"""
Compare two feature lists and return the differences.
"""
added_features = set(features2) - set(features1)
removed_features = set(features1) - set(features2)
return added_features, removed_features
def generate_report(file1_content, file2_content):
# Extract package information from both files
file1_packages = extract_packages(file1_content)
file2_packages = extract_packages(file2_content)
added = []
removed = []
updated = []
# Identify removed and updated packages
for pkg in file1_packages:
if pkg not in file2_packages:
removed.append(pkg)
else:
# Compare version and features
triplet1, version1, features1 = file1_packages[pkg]
triplet2, version2, features2 = file2_packages[pkg]
updated_parts = []
if version1 != version2 or triplet1 != triplet2:
updated_parts.append(f"{version1} -> {version2}")
added_features, removed_features = compare_features(features1, features2)
if added_features:
updated_parts.append("+" + ", ".join(added_features))
if removed_features:
updated_parts.append("-" + ", ".join(removed_features))
if updated_parts:
updated.append(f"{pkg}: " + " ".join(updated_parts))
# Identify added packages
for pkg in file2_packages:
if pkg not in file1_packages:
added.append(pkg)
# Print the report
if added:
print("**Added packages:**")
for pkg in added:
triplet, version, features = file2_packages[pkg]
print(f" 🍓 {pkg}: {version} (Features: {', '.join(features)})")
if removed:
print("\n**Removed packages:**")
for pkg in removed:
triplet, version, features = file1_packages[pkg]
print(f" 🍄 {pkg}: {version} (Features: {', '.join(features)})")
if updated:
print("\n**Updated packages:**")
for pkg in updated:
print(f" 🍇 {pkg}")
def read_file(file_path):
"""
Read the content of a file.
"""
with open(file_path) as file:
return file.read()
# Read files
file1_content = read_file("/tmp/vcpkg-base-output.txt")
file2_content = read_file("/tmp/vcpkg-head-output.txt")
# Generate the report
generate_report(file1_content, file2_content)

6
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"

112
.github/labeler.yml vendored Normal file
View File

@ -0,0 +1,112 @@
"3D":
- any: [
'resources/3d/**/*',
'src/3d/**/*',
'src/app/3d/**/*',
]
"Annotations":
- any: [
'src/core/annotations/**/*',
'src/gui/annotations/**/*',
]
"Chore":
- any: [
'.ci/**/*',
'.docker/**/*',
'.github/**/*',
]
"DB Manager":
- any: ['python/plugins/db_manager/**/*']
"Expressions":
- any: [
'src/core/expression/**/*',
'resources/function_help/**/*',
]
"Form":
- any: [
'src/core/editform/**/*',
'src/gui/attributeformconfig/**/*',
]
"GRASS":
- any: ['python/plugins/grassprovider/**/*']
"GUI/UX":
- any: [
'images/**/*',
'resources/themes/**/*',
# 'src/gui/**/*', too broad
]
"HANA data provider":
- any: [
'src/providers/hana/**/*',
]
"Labeling":
- any: [
'src/app/labeling/**/*',
'src/core/labeling/**/*',
]
"Locator":
- any: [
'src/core/locator/**/*',
'src/gui/locator/**/*',
]
"Mesh":
- any: [
'external/mdal/**/*',
'src/analysis/mesh/**/*',
'src/core/mesh/**/*',
'src/gui/mesh/**/*',
]
"Metasearch":
- any: ['python/plugins/MetaSearch/**/*']
"Point Clouds":
- any: [
'src/app/pointcloud/**/*',
'src/core/pointcloud/**/*',
'src/gui/pointcloud/**/*',
]
"PostGIS data provider":
- any: ['src/providers/postgres/**/*']
"Processing":
- any: [
'python/plugins/processing/**/*',
'src/analysis/**/*',
'src/core/processing/**/*',
'src/process/**/*'
]
"Python Console":
- any: [
'python/console/**/*',
]
"Quick":
- any: [
'src/quickgui/**/*',
]
"Server":
- any: [
'src/server/**/*',
'resources/server/**/*'
]
"Vector tiles":
- any: [
'src/core/vectortile/**/*',
'src/gui/vectortile/**/*',
]

25
.github/workflows/backport.yml vendored Normal file
View File

@ -0,0 +1,25 @@
name: ♻ Backport
on:
pull_request_target:
types:
- closed
- labeled
permissions:
contents: read
jobs:
backport:
runs-on: ubuntu-22.04
name: Backport
permissions:
pull-requests: write
steps:
- name: Backport Bot
id: backport
if: github.event.pull_request.merged && ( ( github.event.action == 'closed' && contains( join( github.event.pull_request.labels.*.name ), 'backport') ) || contains( github.event.label.name, 'backport' ) )
uses: m-kuhn/backport@7f3cab83e4b3b26aefcffda21851c3dc3d389f45 #v1.2.7
with:
github_token: ${{ secrets.GH_TOKEN_BOT }}

222
.github/workflows/build-macos-qt6.yml vendored Normal file
View File

@ -0,0 +1,222 @@
---
name: 🍎 Build - MacOS Qt6
on:
push:
branches:
- master
- release-*
pull_request:
release:
types: ['published']
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build:
strategy:
matrix:
include:
- os: macos-13
triplet: x64-osx-dynamic-release
deployment-target: "10.15"
- os: macos-14
triplet: arm64-osx-dynamic-release
deployment-target: "11.0"
name: build (macos)
runs-on: ${{ matrix.os }}
steps:
- name: 🐣 Checkout
uses: actions/checkout@v4
- name: 🐩 Install CMake and Ninja
uses: lukka/get-cmake@ea004816823209b8d1211e47b216185caee12cc5 # latest
with:
# Pin to specific version to avoid rebuilding too often
# Also helps to avoid spurious build failures like https://github.com/qgis/QGIS/pull/47098
cmakeVersion: 3.30.4
- name: 🎡 Setup vcpkg
id: setup-vcpkg
uses: ./.github/actions/setup-vcpkg
- name: 🎲 Get artifact ids
id: workflow-artifact-ids
uses: ./.github/actions/get-workflow-artifact-ids
- name: 🔨 Prepare build env
run: |
brew install automake bison flex gnu-sed autoconf-archive nasm libtool fdupes
echo $(brew --prefix bison)/bin >> $GITHUB_PATH
echo $(brew --prefix flex)/bin >> $GITHUB_PATH
echo $(brew --prefix libtool)/bin >> $GITHUB_PATH
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: 🍭 Setup XCode
uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
with:
xcode-version: latest-stable
- name: 🛍️ Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
max-size: 500M
key: build-ccache-${{ matrix.triplet }}-qt6-${{ github.event.pull_request.base.ref || github.ref_name }}
save: ${{ github.event_name == 'push' }}
- name: 🛍️ Tune ccache configuration
shell: bash
run: |
# To make ccache work properly with precompiled headers
ccache --set-config sloppiness=pch_defines,time_macros,include_file_mtime,include_file_ctime
- name: 🌱 Install dependencies and generate project files
env:
X_VCPKG_ASSET_SOURCES: x-azurl,https://assetcache.open-vcpkg.org/assetcache,,read
run: |
echo "VCPKG_ROOT: ${VCPKG_ROOT}"
# Install first only with binarycaching, then deduplicate binaries and replace copies with symlinks.
# Nuget doesn't understand the symlink concept
cmake -S . \
-G Ninja \
-B build \
-D QGIS_APP_NAME="QGIS-${{steps.workflow-artifact-ids.outputs.display-name}}" \
-D WITH_VCPKG=ON \
-D BUILD_WITH_QT6=ON \
-D WITH_QTWEBKIT=OFF \
-D WITH_BINDINGS=ON \
-D WITH_ORACLE=ON \
-D VCPKG_TARGET_TRIPLET="${{ matrix.triplet }}" \
-D VCPKG_HOST_TRIPLET="${{ matrix.triplet }}" \
-D VCPKG_INSTALL_OPTIONS="--only-binarycaching" \
-D CMAKE_OSX_DEPLOYMENT_TARGET=${{ matrix.deployment-target }} \
-D ENABLE_UNITY_BUILDS=ON \
-D NUGET_USERNAME=${{ github.actor }} \
-D NUGET_SOURCE="https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" \
-D NUGET_TOKEN=${{ secrets.GITHUB_TOKEN }} || true
fdupes -q -r -1 build/vcpkg_installed/${{ matrix.triplet }}/lib | grep libQt | while read line; do master=""; for file in ${line[*]}; do if [[ "x${master}" == "x" ]]; then master=$file; else rm "${file}"; ln -s $(basename "${master}") "${file}"; fi; done; done
cmake -D VCPKG_INSTALL_OPTIONS="" build
- name: 📑 Upload vcpkg build logs
uses: actions/upload-artifact@v4
if: failure()
with:
name: build-logs-${{ matrix.triplet }}
path: |
${{ env.VCPKG_ROOT }}/buildtrees/**/*.log
- name: 📦 Create SDK
if: github.event_name == 'workflow_dispatch' || github.event_name == 'release'
run: |
./build/_deps/vcpkg-src/vcpkg export --zip --output-dir=./sdk --x-install-root=./build/vcpkg_installed --x-manifest-root=vcpkg
- name: 📤 Upload sdk
if: github.event_name == 'workflow_dispatch' || github.event_name == 'release'
uses: actions/upload-artifact@v4
with:
name: qgis-sdk-${{ matrix.triplet }}
path: |
sdk/vcpkg-export-*.zip
- name: 🌋 Build
run: |
# We make sure the target "all" is built before bundling
# Ideally, we would specify each target that is required to be installed, but this workaround is sufficient for now
cmake --build build
cmake --build build --target bundle
- name: Archive app
run: |
gtar -cpvzf qgis-app-${{steps.workflow-artifact-ids.outputs.filename}}-${{ matrix.triplet }}.tar.gz ./build/_CPack_Packages/Darwin/External/*/*.app
- name: 📤 Upload app
uses: actions/upload-artifact@v4
with:
name: qgis-app-${{steps.workflow-artifact-ids.outputs.filename}}-${{ matrix.triplet }}
path: |
qgis-app-${{steps.workflow-artifact-ids.outputs.filename}}-${{ matrix.triplet }}.tar.gz
schedule_download_comment:
name: Create dmg
runs-on: macos-latest
needs: build
steps:
- name: 🐣 Checkout
uses: actions/checkout@v4
- name: 🔨 Prepare build env
run: |
brew install create-dmg
- name: 🎲 Get artifact ids
id: workflow-artifact-ids
uses: ./.github/actions/get-workflow-artifact-ids
- name: 📤 Download app
uses: actions/download-artifact@v4
with:
pattern: qgis-app-${{steps.workflow-artifact-ids.outputs.filename}}-*
path: |
artifacts
- name: Create universal app
run: |
mkdir -p x64
gtar --strip-components=5 -zxf ./artifacts/qgis-app-${{steps.workflow-artifact-ids.outputs.filename}}-x64-osx-dynamic-release/qgis-app-${{steps.workflow-artifact-ids.outputs.filename}}-x64-osx-dynamic-release.tar.gz -C x64
mkdir -p arm64
gtar --strip-components=5 -zxf ./artifacts/qgis-app-${{steps.workflow-artifact-ids.outputs.filename}}-arm64-osx-dynamic-release/qgis-app-${{steps.workflow-artifact-ids.outputs.filename}}-arm64-osx-dynamic-release.tar.gz -C arm64
pip install lipomerge
lipomerge ./x64 ./arm64 universal
- name: Create dmg
run: |
QGIS_APP_NAME=QGIS-"${{steps.workflow-artifact-ids.outputs.display-name}}"
create-dmg --volname "${QGIS_APP_NAME} Installer" \
--hide-extension ${QGIS_APP_NAME}.app \
--volicon "$(pwd)/images/icons/mac/qgis.icns" \
--background "$(pwd)/platform/macos/installer_background.png" \
--window-pos 200 120 \
--window-size 512 320 \
--icon-size 100 \
--icon "${QGIS_APP_NAME}.app" 130 160 \
--app-drop-link 400 155 \
${QGIS_APP_NAME}-Installer.dmg \
universal/*/*.app
- name: 📤 Upload app
uses: actions/upload-artifact@v4
id: artifact-mac-qt6
with:
name: qgis-${{steps.workflow-artifact-ids.outputs.filename}}-dmg
path: |
*.dmg
- name: Upload release assets
uses: AButler/upload-release-assets@v3.0
if: ${{ github.event_name == 'release' }}
with:
files: '*.dmg'
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Schedule download comment
uses: ./.github/actions/post_sticky_comment
if: github.event_name == 'pull_request'
with:
marker: macos-qt6
body: |
### 🍎 MacOS Qt6 builds
Download [MacOS Qt6 builds of this PR for testing](${{ steps.artifact-mac-qt6.outputs.artifact-url }}).
_This installer is not signed, `control`+click > `open` the app to avoid the warning_
*(Built from commit ${{ github.event.pull_request.head.sha }})*
pr: ${{ github.event.number }}

View File

@ -0,0 +1,157 @@
name: Write build artifact comments
on:
workflow_run:
workflows:
- 🪟 MingW64 Windows 64bit Build
- 🪟 Windows Qt6
- 🧮 Vcpkg report
- 🍎 Build - MacOS Qt6
types:
- completed
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
on-success:
if: github.event.workflow_run.event == 'pull_request'
permissions:
pull-requests: write
runs-on: ubuntu-latest
steps:
- name: 'Download artifact'
id: download_artifact
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
let matchArtifacts = allArtifacts.data.artifacts.filter((artifact) => {
return artifact.name.startsWith('comment_artifacts-');
});
if (matchArtifacts.length > 0)
{
for (const artifact of matchArtifacts) {
const suffix = artifact.name.split('comment_artifacts-')[1]; // Extract the suffix from the artifact name
// Download each matching artifact
let download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: artifact.id,
archive_format: 'zip',
});
// Write each artifact to a zip file named after its suffix
const zipFilePath = `${process.env.GITHUB_WORKSPACE}/data-${suffix}.zip`;
fs.writeFileSync(zipFilePath, Buffer.from(download.data));
console.log(`Downloaded and saved artifact: ${artifact.name} to ${zipFilePath}`);
}
}
else
{
core.setOutput('artifact_id', 0);
}
- name: 'Unzip artifact'
run: |
unzip data-*.zip
- name: 'Post artifact download link as comment on PR'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
function updateCommentSection(prComment, marker, body) {
// Create a regular expression to match the section between start and end markers
const sectionRegex = new RegExp(`(<!-- ====startsection ${marker}-->\\n)([\\s\\S]*?)(<!-- ====endsection ${marker}-->)`, 'm');
// Check if the section with the marker exists
if (sectionRegex.test(prComment)) {
// Replace the existing body text between the markers
return prComment.replace(sectionRegex, `$1${body}\n$3`);
} else {
// If the section doesn't exist, append the new section to the end
return prComment.trim() + `\n\n<!-- ====startsection ${marker}-->\n${body}\n<!-- ====endsection ${marker}-->\n`;
}
}
const fs = require('fs');
const path = require('path');
// Read all files matching the pattern 'comment*.json'
const files = fs.readdirSync('.').filter(file => file.startsWith('comment') && file.endsWith('.json'));
if (files.length === 0) {
console.log('No comment*.json files found');
return;
}
// Take the PR number from the first file
const dataSample = JSON.parse(fs.readFileSync(files[0], 'utf8'));
const prNumber = dataSample.pr_number;
const prComments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
});
const PREFIX = "<!-- !!## stickymarker ##!! -->";
// Find the comment that starts with the specified PREFIX
const comment = prComments.data?.find(c => c.body.startsWith(PREFIX));
let newPrComment;
if (!!comment) {
newPrComment = comment.body;
} else {
newPrComment = PREFIX + "\n";
}
// Loop through all the comment*.json files
for (const file of files) {
try {
const data = JSON.parse(fs.readFileSync(file, 'utf8'));
const marker = data.marker;
const body = data.body;
console.debug(data);
newPrComment = updateCommentSection(newPrComment, marker, body);
} catch (error) {
console.error(`Failed to process file ${file}: ${error.message}`);
}
}
// Update or create the PR comment after processing all the files
if (!!comment) {
// Update the existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: comment.id,
body: newPrComment
});
} else {
// Create a new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: newPrComment
});
}

View File

@ -0,0 +1,106 @@
name: Check if user is running the latest version of QGIS
on:
issues:
types: [opened]
env:
# Extract issue body
ISSUE_BODY: ${{ github.event.issue.body }}
jobs:
check_version_reported:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Get version details
run: |
python ./scripts/get_latest_qgis_versions.py --release="stable" --github_token=${{ secrets.GITHUB_TOKEN }} >> $GITHUB_ENV
- name: Write comment
uses: actions/github-script@v7
with:
script: |
const {ISSUE_BODY, QGIS_VERSION_LTR_PATCH, QGIS_VERSION_STABLE_PATCH} = process.env // Latest released version identified using get_latest_qgis_versions
compareSemanticVersions = (version1, version2) => {
// Returns -1 if version1 < version2
// Returns 1 if version1 > version2
// Returns 0 if version1 = version2
// Assume parameters are string and follow the semantic version : major.minor.patch
var version1 = version1.split(".").map(x => parseInt(x))
var version2 = version2.split(".").map(x => parseInt(x))
//Major version
if ( version1[0] < version2[0] ){
return -1
}
else if ( version1[0] > version2[0] ) {
return 1
}
//Minor version2
if ( version1[1] < version2[1] ){
return -1
}
else if ( version1[1] > version2[1] ) {
return 1
}
//Patch version
if ( version1[2] < version2[2] ){
return -1
}
else if ( version1[2] > version2[2] ) {
return 1
}
return 0
}
// Match qgis version reported e.g : "3.40.0-Bratislava"
// More example here : https://regex101.com/r/jvHJAf/2
var regex = /QGIS [Vv]ersion(?:: | \| )(\d)\.(\d{2})\.(\d*)-[A-Z][a-z]+/
var m = ISSUE_BODY.match(regex)
if ( !m ){
console.log("Debug: No version identified in the body")
return
}
major_version = m[1]
minor_version = m[2]
patch_version = m[3]
user_version = `${major_version}.${minor_version}.${patch_version}`
if ( compareSemanticVersions(user_version, QGIS_VERSION_LTR_PATCH) === -1 ) {
console.log("Debug: Suggest user to try latest LTR release")
let comment = `Thanks for reporting, however it looks like you are using an older version of QGIS (version ${user_version}) instead of latest (Version ${QGIS_VERSION_LTR_PATCH}). Your bug could already be resolved in the latest version. \nIt takes a lot of human effort to triage all the bugs in a project like QGIS, could you please retry with the latest version first?`
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
})
}
else if ( compareSemanticVersions(user_version, QGIS_VERSION_LTR_PATCH) === 0 ) {
console.log("Debug: user is already running latest LTR version")
}
else if ( compareSemanticVersions(user_version, QGIS_VERSION_STABLE_PATCH) === -1 ) {
console.log("Debug: Suggest user to try latest release")
let comment = `Thanks for reporting, however it looks like you are using an older version of QGIS (version ${user_version}) instead of latest (Version ${QGIS_VERSION_STABLE_PATCH}). Your bug could already be resolved in the latest version. \nIt takes a lot of human effort to triage all the bugs in a project like QGIS, could you please retry with the latest version first?`
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
})
}
else {
console.log("Debug: pass, the user is running a supported version so do nothing")
}

219
.github/workflows/code_layout.yml vendored Normal file
View File

@ -0,0 +1,219 @@
name: 🧹 Code Layout
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
push:
branches:
- master
- release-**
- queued_ltr_backports
pull_request:
permissions:
contents: read
env:
DOXYGEN_VERSION: 1.9.8
jobs:
documentation_checks:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python 3.10
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install requirements
run: |
wget https://www.doxygen.nl/files/doxygen-${DOXYGEN_VERSION}.linux.bin.tar.gz
tar -xzf doxygen-${DOXYGEN_VERSION}.linux.bin.tar.gz
python -m pip install --upgrade pip
pip install autopep8 nose2 mock termcolor
- name: Make
run: |
mkdir build
cd build
cmake -DUSE_CCACHE=OFF -DWITH_CORE=OFF -DWITH_APIDOC=ON -DWITH_ASTYLE=ON -DENABLE_TESTS=ON \
-DWITH_DOT=NO -DWERROR=ON -DDOXYGEN_EXECUTABLE=../doxygen-${DOXYGEN_VERSION}/bin/doxygen ..
make -j3 apidoc
- name: Run Tests
run: cd build && ctest -V -R PyQgsDocCoverage
license_check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Requirements
run: |
sudo apt install -y \
cpanminus
cpanm --notest App::Licensecheck
- name: Run License Check
run: ./tests/code_layout/test_licenses.sh
shell_check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Requirements
run: |
sudo apt install -y \
shellcheck
- name: Run Shellcheck
run: ./tests/code_layout/test_shellcheck.sh
banned_keywords_check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run Banned Keywords Test
run: ./tests/code_layout/test_banned_keywords.sh
class_name_check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run class naming conventions check
run: ./tests/code_layout/test_class_names.sh
def_window_title_check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Def Window Title Test
run: ./tests/code_layout/test_defwindowtitle.sh
qgsscrollarea_check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run QgsScrollArea check
run: ./tests/code_layout/test_qgsscrollarea.sh
qvariant_no_brace_init:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: No brace initialization of QVariant variables
run: ./tests/code_layout/test_qvariant_no_brace_init.sh
qt_module_wide_imports:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: No module-wide imports of Qt modules
run: ./tests/code_layout/test_qt_imports.sh
doxygen_layout_check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Requirements
run: |
sudo apt install -y \
expect \
silversearcher-ag
- name: Doxygen Layout Test
run: ./tests/code_layout/test_doxygen_layout.sh
indentation_check:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 100
- name: Install Requirements
run: |
sudo apt install -y \
astyle \
python3-autopep8 \
flip
- name: Indentation Test
run: ./scripts/verify_indentation.sh HEAD~1
spell_check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Requirements
run: |
sudo apt install -y \
expect \
silversearcher-ag
- name: Retrieve changed files
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c #v46
id: changed_files
with:
separator: " "
- name: Spell Test
if: steps.changed_files.outputs.any_changed == 'true'
env:
ALL_CHANGED_FILES: ${{ steps.changed_files.outputs.changed_files }}
run: ./scripts/spell_check/check_spelling.sh
sip_check:
runs-on: ubuntu-latest
steps:
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install Requirements
run: |
python -m pip install --upgrade pip
pip install autopep8 nose2 mock termcolor pyyaml
- name: Checkout
uses: actions/checkout@v4
- name: Sip Checks
run: ./tests/code_layout/sipify/test_sipify.sh
- name: Sip Include Test
run: ./tests/code_layout/sipify/test_sip_include.sh
- name: Sip Files Up To Date
run: ./tests/code_layout/sipify/test_sipfiles.sh
cppcheck:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Requirements
run: |
sudo apt install -y cppcheck
- name: Run cppcheck test
run: ./scripts/cppcheck.sh
moc_check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Run Check
run: python3 scripts/includemocs.py src --dry-run

130
.github/workflows/mingw64.yml vendored Normal file
View File

@ -0,0 +1,130 @@
name: 🪟 MingW64 Windows 64bit Build
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
push:
branches:
- master
- release-**
- queued_ltr_backports
paths:
- 'src/**'
- 'external/**'
- 'python/**'
- 'tests/**'
- 'ms-windows/**'
- 'CMakeLists.txt'
- '.github/workflows/mingw64.yml'
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
mingw64-build:
name: MinGW64 Windows Build
runs-on: ubuntu-latest
container:
image: fedora:40
options: --security-opt seccomp=unconfined
volumes:
- ${{ github.workspace }}:/w
steps:
- uses: actions/checkout@v4
# To be removed
# Workaround a bug where the initial /etc/dnf/dnf.conf file contains
# just the "tsflags=nodocs" line
- name: Replace broken dnf.conf
run: printf '[main]\ngpgcheck=True\ninstallonly_limit=3\nclean_requirements_on_remove=True\nbest=False\nskip_if_unavailable=True\ntsflags=nodocs' > /etc/dnf/dnf.conf
- name: Update system
run: dnf -y update
- name: Install core dependencies
run: dnf -y install zip
- name: Install build dependencies
run: ./ms-windows/mingw/mingwdeps.sh
# Node.js and Yarn for server landingpage webapp
- uses: actions/setup-node@v4
with:
node-version: '22'
- name: Make yarn available
run: corepack enable
- name: Create ccache dir
run: mkdir -p /w/.ccache/QGIS
- name: Restore build cache
uses: actions/cache/restore@v4
with:
path: /w/.ccache/QGIS
key: build-ccache-mingw64-${{ github.event.pull_request.base.ref || github.ref_name }}
restore-keys: |
build-ccache-mingw64-master
- name: Build QGIS Application
run: CCACHE_DIR=/w/.ccache/QGIS ./ms-windows/mingw/build.sh x86_64 nodebug 4
- name: Save build cache for push only
uses: actions/cache/save@v4
if: ${{ github.event_name == 'push' }}
with:
path: /w/.ccache/QGIS
key: build-ccache-mingw64-${{ github.ref_name }}-${{ github.run_id }}
- name: Create Portable zip
run: |
DISTROOT=build_mingw64/dist/usr/x86_64-w64-mingw32/sys-root/mingw
DEBUGROOT=dist_debug
for file in $(find $DISTROOT -name '*.debug' \( -type l -or -type f \)); do
DEST=${file/$DISTROOT/$DEBUGROOT}
mkdir -p "$(dirname $DEST)"
sudo mv "$file" "$DEST"
done
sudo mv $DISTROOT QGIS-Portable
zip -r qgis-portable-win64.zip QGIS-Portable
(cd $DEBUGROOT && zip -r - *) > qgis-portable-win64-debugsym.zip
- name: Save PR number to zips
run: |
echo ${{ github.event.number }} | tee pr_number
zip -u qgis-portable-win64.zip pr_number
zip -u qgis-portable-win64-debugsym.zip pr_number
echo ${{ github.event.pull_request.head.sha }} | tee git_commit
zip -u qgis-portable-win64.zip git_commit
zip -u qgis-portable-win64-debugsym.zip git_commit
- name: Upload QGIS for Windows 64bit
uses: actions/upload-artifact@v4
id: artifact-win64
with:
name: QGIS for Windows 64bit
path: qgis-portable-win64.zip
- name: Upload QGIS for Windows 64bit Debug Symbols
uses: actions/upload-artifact@v4
id: artifact-win64-debug
with:
name: QGIS for Windows 64bit Debug Symbols
path: qgis-portable-win64-debugsym.zip
- name: Schedule download comment
uses: ./.github/actions/post_sticky_comment
if: github.event_name == 'pull_request'
with:
marker: mingw64
body: |
### 🪟 Windows builds
Download [Windows builds of this PR for testing](${{ steps.artifact-win64.outputs.artifact-url }}).
Debug symbols for this build are available [here](${{ steps.artifact-win64-debug.outputs.artifact-url }}).
*(Built from commit ${{ github.event.pull_request.head.sha }})*
pr: ${{ github.event.number }}

100
.github/workflows/ogc.yml vendored Normal file
View File

@ -0,0 +1,100 @@
name: 🗺 OGC tests for QGIS Server
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
push:
branches:
- master
- release-**
- queued_ltr_backports
paths:
- 'src/core/**'
- 'src/auth/**'
- 'src/providers/**'
- 'src/server/**'
- 'src/CMakeLists.txt'
- 'external/**'
- 'CMakeLists.txt'
- '.github/workflows/ogc.yml'
pull_request:
branches:
- master
- release-**
paths:
- 'src/core/**'
- 'src/auth/**'
- 'src/providers/**'
- 'src/server/**'
- 'src/CMakeLists.txt'
- 'external/**'
- 'CMakeLists.txt'
- '.github/workflows/ogc.yml'
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Restore build cache
uses: actions/cache/restore@v4
with:
path: /home/runner/QGIS/.ccache
key: build-ccache-ogc-${{ github.event.pull_request.base.ref || github.ref_name }}
restore-keys: |
build-ccache-ogc-master
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build Docker Container
id: docker-build
uses: docker/build-push-action@v6
with:
tags: qgis/qgis-deps-ogc:${{ github.event.pull_request.base.ref || github.ref_name }}
context: .ci/ogc
file: .ci/ogc/Dockerfile
cache-from: type=gha
cache-to: type=gha,mode=max
load: true
- name: Run build
run: |
docker run -v $(pwd):/usr/src/qgis -v /home/runner/QGIS/.ccache:/root/.ccache ${DOCKER_IMAGE} /usr/src/qgis/.ci/ogc/build.sh
env:
DOCKER_IMAGE: ${{ steps.docker-build.outputs.imageid }}
- name: Save build cache for push only
uses: actions/cache/save@v4
if: ${{ github.event_name == 'push' }}
with:
path: /home/runner/QGIS/.ccache
key: build-ccache-ogc-${{ github.ref_name }}-${{ github.run_id }}
- name: Install pyogctest
run: |
sudo apt-get update && sudo apt-get install python3-virtualenv virtualenv
virtualenv -p /usr/bin/python3 venv && source venv/bin/activate && pip install pyogctest
- name: Run WMS 1.3.0 OGC tests
run: |
source venv/bin/activate && pyogctest -s wms130 -e
docker compose -f .ci/ogc/docker-compose.yml up -d
source venv/bin/activate && pyogctest -n ogc_qgis -s wms130 -v -u http://$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' qgis_server_nginx)/qgisserver_wms130
env:
DOCKER_IMAGE: ${{ steps.docker-build.outputs.imageid }}
- name: Run OGC API Features 1.0 tests
run: |
cd data && git clone https://github.com/qgis/QGIS-Training-Data && cd -
docker compose -f .ci/ogc/docker-compose.yml up -d
source venv/bin/activate && pyogctest -n ogc_qgis -s ogcapif -v -u http://$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' qgis_server_nginx)/qgisserver_ogcapif
env:
DOCKER_IMAGE: ${{ steps.docker-build.outputs.imageid }}

20
.github/workflows/pr-auto-label.yml vendored Normal file
View File

@ -0,0 +1,20 @@
name: "🌈 Triage"
on:
pull_request_target:
types: [ opened, synchronize, reopened ]
permissions:
contents: read
jobs:
triage:
name: "Set on PR"
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v5
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"

148
.github/workflows/pr-auto-milestone.yml vendored Normal file
View File

@ -0,0 +1,148 @@
name: 📅 Auto set milestone on PR
on:
workflow_call:
pull_request_target:
types:
- opened
permissions:
contents: read
env:
QGIS_MAJOR_VERSION: 3
jobs:
pr-without-milestones:
runs-on: ubuntu-latest
if: github.repository == 'qgis/QGIS'
permissions:
issues: write
pull-requests: write
steps:
# list the tags and milestones
- uses: octokit/graphql-action@v2.x
id: graphql_request
with:
query: |
query {
repository(owner: "qgis", name: "QGIS") {
pullRequests(states: OPEN, last: 100) {
edges {
node {
number
title
milestone {
number
}
baseRef {
name
}
}
}
}
milestones(orderBy: {field: CREATED_AT, direction: DESC}, first: 50) {
edges {
node {
title
number
}
}
}
refs(refPrefix: "refs/tags/", orderBy: {field: TAG_COMMIT_DATE, direction: DESC}, first: 30) {
edges {
node {
name
}
}
}
}
}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# take the first unprocessed PR and determine if some remain
- name: Filter PR to check
id: extract_data
env:
JSON_DATA: ${{ steps.graphql_request.outputs.data }}
run: |
# get PRs without milestones
PRS_TO_PROCESS=$(echo "${JSON_DATA}" | jq '.repository.pullRequests.edges[] | select( .node.milestone.number | not ) | .node.number')
NUMBER_OF_PRS=$(echo "${PRS_TO_PROCESS}" | jq -s '. | length')
echo "NUMBER_OF_PRS: ${NUMBER_OF_PRS}"
# early exit
[[ ${NUMBER_OF_PRS} == 0 ]] && echo "has_milestone_to_set=0" >> $GITHUB_OUTPUT && exit 0
# Take the first
PR_NUMBER=$(echo "${PRS_TO_PROCESS}" | jq -s '. | first')
echo "PR_NUMBER: ${PR_NUMBER}"
# Not used for now
RE_RUN_JOB=$(echo "${JSON_DATA}" | jq -s '. | length > 1')
echo "RE_RUN_JOB: ${RE_RUN_JOB}"
# Get the base branch
BASE_BRANCH=$(echo "${JSON_DATA}" | jq -r ".repository.pullRequests.edges[] | select( .node.number == ${PR_NUMBER} ) | .node.baseRef.name")
echo "BASE_BRANCH: ${BASE_BRANCH}"
# master => NOTHING, release_3-10 => _10
MINOR_VERSION=$(echo ${BASE_BRANCH} | sed -r -e 's/^release-[0-9]_([0-9]+)/_\1/;t;d')
echo "MINOR_VERSION: ${MINOR_VERSION}"
# get the max release from the tags
MAX_RELEASE=$(echo "${JSON_DATA}" | jq ".repository.refs.edges[].node.name | select( . | test(\"^final-${QGIS_MAJOR_VERSION}${MINOR_VERSION}\") ) | sub(\"^final-${QGIS_MAJOR_VERSION}_(?<m>[0-9]+)_(?<p>.)\"; .m+\".\"+.p) | tonumber" | jq -s '. | max')
echo "MAX_RELEASE: ${MAX_RELEASE}"
# increase the number to get milestone: round+2 for master, +0.1 for release_xxx branches
INCREASE_OPERATION=$([[ -z ${MINOR_VERSION} ]] && echo "${MAX_RELEASE%.*} + 2.0" || echo "${MAX_RELEASE} + 0.1" )
echo "INCREASE_OPERATION: ${INCREASE_OPERATION}"
MILESTONE_TITLE="${QGIS_MAJOR_VERSION}."$(echo "${INCREASE_OPERATION}" | bc)
echo "MILESTONE_TITLE: ${MILESTONE_TITLE}"
MILESTONE_NUMBER=$(echo "${JSON_DATA}" | jq ".repository.milestones.edges[] | select( .node.title == \"${MILESTONE_TITLE}\" ) | .node.number")
echo "MILESTONE_NUMBER: ${MILESTONE_NUMBER}"
HAS_MILESTONE_TO_CREATE=$([[ -z ${MILESTONE_NUMBER} ]] && echo "1" || echo "0" )
echo "HAS_MILESTONE_TO_CREATE: ${HAS_MILESTONE_TO_CREATE}"
echo "has_milestone_to_set=1" >> $GITHUB_OUTPUT
echo "pr_number=${PR_NUMBER}" >> $GITHUB_OUTPUT
echo "milestone_title=${MILESTONE_TITLE}" >> $GITHUB_OUTPUT
echo "milestone_number=${MILESTONE_NUMBER}" >> $GITHUB_OUTPUT
echo "has_milestone_to_create=${HAS_MILESTONE_TO_CREATE}" >> $GITHUB_OUTPUT
# create the milestone if needed
- name: Create milestone if needed
id: create_milestone
if: steps.extract_data.outputs.has_milestone_to_set == 1 && steps.extract_data.outputs.has_milestone_to_create == 1
uses: octokit/request-action@v2.x
with:
route: POST /repos/qgis/QGIS/milestones
title: ${{ steps.extract_data.outputs.milestone_title }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Compute the milestone number
- name: Compute milestone number from existing or created
id: compute_milestone
if: always() && steps.extract_data.outputs.has_milestone_to_set == 1
env:
MILESTONE_NUMBER_EXISTING: ${{ steps.extract_data.outputs.milestone_number }}
MILESTONE_NUMBER_CREATED_JSON: ${{ steps.create_milestone.outputs.data }}
run: |
FINAL_MILESTONE_NUMBER=$([[ -n ${MILESTONE_NUMBER_EXISTING} ]] && echo "${MILESTONE_NUMBER_EXISTING}" || echo $(echo "${MILESTONE_NUMBER_CREATED_JSON}" | jq .number ))
echo "FINAL_MILESTONE_NUMBER: ${FINAL_MILESTONE_NUMBER}"
echo "milestone_number=${FINAL_MILESTONE_NUMBER}" >> $GITHUB_OUTPUT
# update PR with milestone
- name: update PR milestone
if: steps.extract_data.outputs.has_milestone_to_set == 1
uses: octokit/request-action@v2.x
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
route: PATCH /repos/qgis/QGIS/issues/:pull_number
pull_number: ${{ steps.extract_data.outputs.pr_number }}
milestone: ${{ steps.compute_milestone.outputs.milestone_number }}

View File

@ -0,0 +1,172 @@
name: 📖 PR needs documentation
# a message will be added to the PR to ping the author about her/his responsibility to handle the documentation issue
# an issue is automatically created in the QGIS-Documentation repository when the PR gets merged
on:
pull_request_target:
types:
- opened
- closed
- labeled
permissions:
contents: read
jobs:
ping-author-message:
permissions:
issues: write # for peter-evans/create-or-update-comment to create or update comment
pull-requests: write # for peter-evans/create-or-update-comment to create or update comment
if: github.event.action != 'closed'
runs-on: ubuntu-latest
name: Write comment to ping author about the pull request description
steps:
- name: Create comment about documentation
if: github.event.label.name == 'Needs Documentation'
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
with:
token: ${{ secrets.GH_TOKEN_BOT }}
issue-number: ${{ github.event.pull_request.number }}
body: |
@${{ github.event.pull_request.user.login }}
This pull request has been tagged as **requiring documentation**.
A documentation ticket will be opened at https://github.com/qgis/QGIS-Documentation **when this PR is merged**.
**Please update the description** (not the comments) with helpful description and screenshot to help the work from documentors.
Also, any commit having [needs-doc] or [Needs Documentation] in will see its message pushed to the issue, so please be as verbose as you can.
Thank you!
reactions: 'rocket'
- name: Create comment about changelog
if: github.event.label.name == 'Changelog'
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
with:
token: ${{ secrets.GH_TOKEN_BOT }}
issue-number: ${{ github.event.pull_request.number }}
body: |
@${{ github.event.pull_request.user.login }}
This pull request has been tagged for the [changelog](https://www.qgis.org/en/site/forusers/visualchangelogs.html).
* The description will be harvested so please provide a "nearly-ready" text for the final changelog
* If possible, add a nice illustration of the feature. Only the **first** one in the description will be harvested (GIF accepted as well)
* If you can, it's better to give credits to your sponsor, see below for different formats.
You can edit the description.
<details>
<summary>Format available for credits</summary>
<br />
- `Funded by NAME`
- `Funded by URL`
- `Funded by NAME URL`
- `Sponsored by NAME`
- `Sponsored by URL`
- `Sponsored by NAME URL`
</details>
Thank you!
reactions: '+1'
update-milestone:
if: github.event.pull_request.merged && ( ( github.event.action == 'closed' && contains( github.event.pull_request.labels.*.name, 'Needs Documentation') ) || github.event.label.name == 'Needs Documentation' )
# Update the milestone (if necessary)
name: Update final milestone
permissions:
issues: write
pull-requests: write
contents: read
uses: ./.github/workflows/pr-auto-milestone.yml
create-doc-issue:
if: github.event.pull_request.merged && ( ( github.event.action == 'closed' && contains( github.event.pull_request.labels.*.name, 'Needs Documentation') ) || github.event.label.name == 'Needs Documentation' )
runs-on: ubuntu-latest
name: Create issue on doc repo for labeled issue
steps:
# transform the milestone (e.g. 3.10.4) to a doc label (3.10)
- name: QGIS milestone to Doc label
id: milestone2label
env:
MILESTONE: ${{ github.event.pull_request.milestone.title }}
run: |
LABEL=$(sed -r 's/^([[:digit:]]\.[[:digit:]]+)(\.[[:digit:]]+)?$/\1/' <<< ${MILESTONE})
echo ${LABEL}
echo "label=${LABEL}" >> $GITHUB_OUTPUT
# get the PR body
- name: Get PR body as text
id: get_pr_body
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_BODY: "${{ github.event.pull_request.body }}"
run: |
echo 'body<<EOF' >> $GITHUB_OUTPUT
echo "$PR_BODY" >> $GITHUB_OUTPUT
echo 'EOF' >> $GITHUB_OUTPUT
# get commits from the PR
- name: Get PR commits
uses: octokit/request-action@dad4362715b7fb2ddedf9772c8670824af564f0d # v2.4.0
id: get_pr_commits
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
route: GET /repos/qgis/QGIS/pulls/{pull_number}/commits
pull_number: ${{ github.event.pull_request.number }}
# extracts the matching commits
- name: Filter commits with \[needs?.doc(umentation)?s?\]
id: filtered_commits
env:
JSON_DATA: ${{ steps.get_pr_commits.outputs.data }}
run: |
COMMITS_MESSAGES=$(echo ${JSON_DATA} | jq '.[].commit.message | select( . |test("\\[(feature|needs?.doc(umentation)?s?)\\]"; "i")) | sub("\\[needs?.doc(umentation)?s?\\]"; "\n\n\n\n"; "i")')
echo "commits=$(echo ${COMMITS_MESSAGES} | tr -d '\n' )" >> $GITHUB_OUTPUT
# create the documentation issue
- name: Create Documentation issue
id: doc_issue
uses: dacbd/create-issue-action@cdb57ab6ff8862aa09fee2be6ba77a59581921c2 # v2.0.0
with:
token: ${{ secrets.GH_TOKEN_BOT }}
owner: qgis
repo: QGIS-Documentation
title: ${{ format('{0} (Request in QGIS)', github.event.pull_request.title) }}
# do not modify the QGIS version, an action automatically creates a label in the doc repo
# this is not possible to set labels directly due to security reasons
# the token is in clear, so no rights are given to qgis-bot
body: |
### Request for documentation
From pull request qgis/QGIS#${{ github.event.pull_request.number }}
Author: @${{ github.event.pull_request.user.login }}
QGIS version: ${{ steps.milestone2label.outputs.label }}
**${{ github.event.pull_request.title }}**
### PR Description:
${{ steps.get_pr_body.outputs.body }}
### Commits tagged with [need-docs] or [FEATURE]
${{ steps.filtered_commits.outputs.commits }}
# write comment to ping the PR author
- name: Create comment
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
with:
token: ${{ secrets.GH_TOKEN_BOT }}
issue-number: ${{ github.event.pull_request.number }}
body: |
@${{ github.event.pull_request.user.login }}
A documentation ticket has been opened at https://github.com/qgis/QGIS-Documentation/issues/${{ steps.doc_issue.outputs.number }}
It is **your** responsibility to visit this ticket and add as much detail as possible for the documentation team to correctly document this change.
Thank you!
reactions: 'rocket'

20
.github/workflows/pr_unstale_commit.yml vendored Normal file
View File

@ -0,0 +1,20 @@
name: Remove Labels PR Commit
on: pull_request_target
permissions:
contents: read
jobs:
remove_labels:
permissions:
pull-requests: write # for actions-ecosystem/action-remove-labels to remove PR labels
if: contains(github.event.pull_request.labels.*.name, 'stale')
runs-on: ubuntu-latest
steps:
- uses: actions-ecosystem/action-remove-labels@2ce5d41b4b6aa8503e285553f75ed56e0a40bae0 #v1.0
if: ${{ github.event.comment.user.url != 'https://github.com/apps/github-actions' }}
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
labels: |
stale

106
.github/workflows/pre-commit.yaml vendored Normal file
View File

@ -0,0 +1,106 @@
name: Pre-commit checks
on:
pull_request_target:
push:
issue_comment:
types: [created]
jobs:
pre-commit:
if: github.event_name != 'issue_comment' || github.event.comment.body == '/fix-precommit'
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: write
issues: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 200
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.13'
- name: Install pre-commit
run: pip install pre-commit
- name: Run pre-commit
run: |
if [ "${{ github.event_name }}" == "pull_request_target" ]; then
git fetch origin ${{ github.event.pull_request.base.ref }}:refs/remotes/origin/${{ github.event.pull_request.base.ref }}
git fetch origin pull/${{ github.event.pull_request.number }}/head:pr-head
MODIFIED_FILES=($(git diff --name-only origin/${{ github.event.pull_request.base.ref }} pr-head))
elif [ "${{ github.event_name }}" == "push" ]; then
MODIFIED_FILES=($(git diff --name-only ${{ github.event.before }} ${{ github.sha }}))
else
echo "Unsupported event: ${{ github.event_name }}"
exit 1
fi
echo "Modified files: ${MODIFIED_FILES[@]}"
pre-commit run --files ${MODIFIED_FILES[@]} || (echo "pre-commit failed. Attempting to auto-fix..." && exit 1)
- name: Commit fixes
if: failure()
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git add .
git commit -m "auto-fix pre-commit issues" || echo "No changes to commit"
- name: Auto-commit fixes
if: failure() && github.event_name == 'push'
run: git push || echo "Failed to push changes. Please check permissions or conflicts."
- name: Push fixes to new branch
if: failure() && github.event_name == 'issue_comment' && github.event.comment.body == '/fix-precommit' && github.event.issue.pull_request
run: |
git checkout -b fix/pre-commit-${{ github.event.pull_request.head.sha }}
git push origin fix/pre-commit-${{ github.event.pull_request.head.sha }}
- name: Listen for `/fix-precommit` comment
if: failure() && github.event_name == 'issue_comment' && github.event.comment.body == '/fix-precommit' && github.event.issue.pull_request
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const forkOwner = context.payload.pull_request.head.repo.owner.login;
const forkRepo = context.payload.pull_request.head.repo.name;
const forkBranch = context.payload.pull_request.head.ref;
const baseRepoOwner = context.repo.owner;
const baseRepoName = context.repo.repo;
const headBranch = `fix/pre-commit-${context.payload.pull_request.head.sha}`;
await github.rest.pulls.create({
owner: forkOwner,
repo: forkRepo,
title: "Auto-fix: Pre-commit issues",
head: `${baseRepoOwner}:${headBranch}`,
base: forkBranch,
body: "This PR attempts to fix pre-commit issues automatically.",
});
- name: Comment on PR if pre-commit failed
if: failure() && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number
});
const existingComment = comments.find(comment => comment.body.includes("⚠️ Pre-commit checks failed."));
if (!existingComment) {
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: "⚠️ Pre-commit checks failed. You can fix issues locally by running `pre-commit run --all-files`. Alternatively, comment `/fix-precommit` on this pull request, and I will attempt to auto-fix and open a new pull request for you."
});
}

50
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,50 @@
name: 🚀 Release
on:
push:
tags:
- 'final-*_*_*'
permissions:
contents: read
jobs:
build:
permissions:
contents: none
name: Create Release
runs-on: ubuntu-latest
steps:
- name: Set env
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Version URL
run: |
VERSION=$(echo ${RELEASE_VERSION} | cut -d '-' -f 2 )
if [ ${VERSION: -1} = "0" ]
then
VERSION=$(echo ${VERSION} | cut -d '_' -f1,2 | sed 's/_/\./g')
echo "version_url=https://changelog.qgis.org/en/qgis/version/${VERSION}" >> $GITHUB_ENV
else
PREVIOUS=$(echo ${VERSION} | sed 's/_/\./g' | awk -F. -v OFS=. 'NF==1{print ++$NF}; NF>1{if(length($NF+1)>length($NF))$(NF-1)++; $NF=sprintf("%0*d", length($NF), ($NF-1)%(10^length($NF))); print}' | sed 's/\./_/g')
echo "version_url=https://github.com/qgis/QGIS/compare/final-${PREVIOUS}%5E...final-${VERSION}" >> $GITHUB_ENV
fi
- name: Version name
run: |
VERSION_NAME=$(echo ${{ env.RELEASE_VERSION }} | cut -d '-' -f 2 | sed 's/_/\./g')
echo "version_name=${VERSION_NAME}" >> $GITHUB_ENV
- name: Create release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN_BOT }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ env.version_name }}
body: ${{ env.version_url }}
draft: false
prerelease: false

455
.github/workflows/run-tests.yml vendored Normal file
View File

@ -0,0 +1,455 @@
name: 🧪 QGIS tests
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
push:
branches:
- master
- release-**
- queued_ltr_backports
paths:
- 'src/**'
- 'external/**'
- 'python/**'
- 'tests/**'
- 'CMakeLists.txt'
- '.github/workflows/run-tests.yml'
- '.docker/**'
- '.ci/**'
pull_request:
branches:
- master
- release-**
- queued_ltr_backports
# paths cannot be filtered on this workflow on pull request as it is a required one in the branch protection
# feature request and hacks: https://github.community/t/feature-request-conditional-required-checks/16761
permissions:
contents: read
jobs:
build:
env:
QGIS_WORKSPACE: ${{ github.workspace }} # used in docker compose
RUN_FLAKY_TESTS: ${{ contains( github.event.pull_request.labels.*.name, 'run flaky tests') }}
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.experimental }}
strategy:
matrix:
include:
- distro-version: '24.04'
qt-version: 5
run-tests: true
with-qt6: OFF
with-qt5: ON
with-3d: ON
with-quick: ON
with-clazy: ON
with-grass7: OFF
with-grass8: OFF
with-webengine: OFF
with-pdf4qt: OFF
with-compile-commands: ON
# LD_PRELOAD: /lib/x86_64-linux-gnu/libSegFault.so
experimental: false
unity-builds: ON
- distro-version: '39'
qt-version: 6
run-tests: true
with-qt6: ON
with-qt5: OFF
with-3d: ON
with-quick: ON
with-clazy: OFF
with-grass7: OFF
with-grass8: ON
with-webengine: ON
with-pdf4qt: ON
with-compile-commands: OFF
LD_PRELOAD: ''
experimental: false
unity-builds: ON
fail-fast: false
outputs:
compile_outcome: ${{ steps.compile.outcome }}
tests_failing: ${{ steps.tests.outputs.TESTS_FAILING }}
cdash_url: ${{ steps.tests.outputs.CDASH_URL }}
runners_outcome: ${{ steps.runners.outcome }}
steps:
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # main
with:
tool-cache: true
large-packages: false
docker-images: false
swap-storage: true
- name: Checkout
uses: actions/checkout@v4
- name: Set vars
env:
GITHUB_EVENT_NAME: ${{ github.event_name }}
GITHUB_REF: ${{ github.ref }}
GITHUB_PR_NUMBER: ${{github.event.number}}
run: |
# Be aware that these instructions are duplicated in run-tests job
DOCKER_TAG=$(echo $( [[ ${GITHUB_EVENT_NAME} == pull_request ]] && echo ${GITHUB_BASE_REF} || echo ${GITHUB_REF##*/} ) | sed 's/^master$/latest/')
CTEST_BUILD_NAME=$( [[ ${GITHUB_EVENT_NAME} == pull_request ]] && echo "PR${GITHUB_PR_NUMBER}" || echo ${GITHUB_REF##*/} )"_${GITHUB_SHA}"
echo "DOCKER_TAG=${DOCKER_TAG}" >> $GITHUB_ENV
echo "CTEST_BUILD_NAME=${CTEST_BUILD_NAME}" >> $GITHUB_ENV
echo "QT_VERSION=${{ matrix.qt-version }}" >> $GITHUB_ENV
- name: Print vars
run: |
echo DOCKER_TAG: ${DOCKER_TAG}
echo CTEST_BUILD_NAME: ${CTEST_BUILD_NAME}
echo QT_VERSION: ${QT_VERSION}
- name: Login to Docker Hub
if: ${{ github.event_name == 'push' && github.repository == 'qgis/QGIS' }}
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build Docker Container with Build Environment
id: docker-build
uses: docker/build-push-action@v6
with:
context: .
file: .docker/qgis3-qt${{ matrix.qt-version }}-build-deps.dockerfile
tags: qgis/qgis3-build-deps-${{ matrix.distro-version }}-qt${{ matrix.qt-version }}:${{ github.event.pull_request.base.ref || github.ref_name }}
push: ${{ github.event_name == 'push' && github.repository == 'qgis/QGIS' }}
pull: true
build-args:
DISTRO_VERSION=${{ matrix.distro-version }}
- name: Tag image
run: docker tag ${{ steps.docker-build.outputs.imageid }} qgis3-build-deps
- name: Restore build cache
uses: actions/cache/restore@v4
with:
path: /home/runner/QGIS/.ccache
key: build-ccache-${{ matrix.distro-version }}-qt${{ matrix.qt-version }}-${{ github.event.pull_request.base.ref || github.ref_name }}
restore-keys: |
build-ccache-${{ matrix.distro-version }}-qt${{ matrix.qt-version }}-master
- name: Compile QGIS
id: compile
run: |
docker run -t --name qgis_container \
-v $(pwd):/root/QGIS \
-v /home/runner/QGIS/.ccache:/root/.ccache \
--env-file .docker/docker-variables.env \
--env CCACHE_DIR=/root/.ccache \
--env PUSH_TO_CDASH=true \
--env WITH_QT5=${{ matrix.with-qt5 }} \
--env BUILD_WITH_QT6=${{ matrix.with-qt6 }} \
--env WITH_QUICK=${{ matrix.with-quick }} \
--env WITH_3D=${{ matrix.with-3d }} \
--env WITH_GRASS7=${{ matrix.with-grass7 }} \
--env WITH_GRASS8=${{ matrix.with-grass8 }} \
--env WITH_QTWEBENGINE=${{ matrix.with-webengine }} \
--env WITH_PDF4QT=${{ matrix.with-pdf4qt }} \
--env LD_PRELOAD=${{ matrix.LD_PRELOAD }} \
--env WITH_CLAZY=${{ matrix.with-clazy }} \
--env WITH_COMPILE_COMMANDS=${{ matrix.with-compile-commands }} \
--env ENABLE_UNITY_BUILDS=${{ matrix.unity-builds }} \
qgis3-build-deps \
/root/QGIS/.docker/docker-qgis-build.sh
- name: Save build cache for push only
uses: actions/cache/save@v4
if: ${{ github.event_name == 'push' }}
with:
path: /home/runner/QGIS/.ccache
key: build-ccache-${{ matrix.distro-version }}-qt${{ matrix.qt-version }}-${{ github.ref_name }}-${{ github.run_id }}
- name: Push artifact
id: push_artifact
if: ${{ matrix.run-tests }}
run: tar --exclude='*.o' -cvzf build.tgz build
- uses: actions/upload-artifact@v4
if: ${{ matrix.run-tests }}
with:
name: build-${{ matrix.distro-version }}-qt${{ matrix.qt-version }}.tgz
path: ./build.tgz
retention-days: 1
# - name: Test QGIS runners
# id: runners
# if: ${{ matrix.distro-version == env.DEFAULT_DISTRO_VERSION }}
# run: |
# docker run -d --name qgis-testing-environment \
# -v $(pwd):/root/QGIS \
# -v $(pwd)/tests/src/python:/tests_directory \
# -v $(pwd)/.docker/qgis_resources/test_runner:/usr/bin/test_runner \
# -v $(pwd)/.docker/qgis_resources/supervisor:/etc/supervisor \
# -e QGIS_BUILD_PATH=/root/QGIS/build/output/bin/qgis \
# -e TEST_RUNNER_PATH=/usr/bin/test_runner/qgis_testrunner.py \
# -e DISPLAY=:99 \
# qgis_image \
# /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
# # Wait for xvfb to finish starting
# printf "Waiting for the docker...🐳..."
# sleep 10
# echo " done 🥩"
#
# declare -A testrunners
# # Passing cases:
# testrunners["test_testrunner.run_passing"]=0
# testrunners["test_testrunner.run_skipped_and_passing"]=0
# # Failing cases:
# testrunners["test_testrunner"]=1
# testrunners["test_testrunner.run_all"]=1
# testrunners["test_testrunner.run_failing"]=1
# set +e # do not exit on error
# # Run tests in the docker
# for i in "${!testrunners[@]}"
# do
# echo "::group::docker_test_runner_${i}"
# echo "test ${i}..."
# docker exec -i qgis-testing-environment sh -c "cd /tests_directory && /usr/bin/test_runner/qgis_testrunner.sh ${i}"
# [[ $? -eq "${testrunners[$i]}" ]] && echo "success" || exit 1
# echo "::endgroup::"
# done
# set -e # switch back
# docker stop qgis-testing-environment
run-tests:
name: Run tests
env:
QGIS_WORKSPACE: ${{ github.workspace }} # used in docker compose
runs-on: ubuntu-latest
needs: build
if: always()
strategy:
matrix:
qt-version: [5, 6]
test-batch: [ALL_BUT_PROVIDERS, POSTGRES, HANA, SQLSERVER]
include:
- qt-version: 5
distro-version: 24.04
docker-target: binary-only
- qt-version: 6
distro-version: 39
docker-target: binary-only
- qt-version: 5
distro-version: 24.04
test-batch: ORACLE
docker-target: binary-for-oracle
exclude:
- qt-version: 6
test-batch: HANA
- qt-version: 6
test-batch: POSTGRES
- qt-version: 6
test-batch: SQLSERVER
fail-fast: false
steps:
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # main
with:
tool-cache: true
large-packages: false
docker-images: false
swap-storage: true
- name: Checkout
uses: actions/checkout@v4
- name: Set vars
env:
GITHUB_EVENT_NAME: ${{ github.event_name }}
GITHUB_REF: ${{ github.ref }}
GITHUB_PR_NUMBER: ${{github.event.number}}
run: |
# Be aware that these instructions are duplicated in build job
CTEST_BUILD_NAME=$( [[ ${GITHUB_EVENT_NAME} == pull_request ]] && echo "PR${GITHUB_PR_NUMBER}" || echo ${GITHUB_REF##*/} )"_${GITHUB_SHA}_${{ matrix.test-batch }}"
echo "CTEST_BUILD_NAME=${CTEST_BUILD_NAME}" >> $GITHUB_ENV
echo "QT_VERSION=${{ matrix.qt-version }}" >> $GITHUB_ENV
- name: Print vars
run: |
echo CTEST_BUILD_NAME: ${CTEST_BUILD_NAME}
- name: Login to Docker Hub
if: ${{ github.event_name == 'push' && github.repository == 'qgis/QGIS' }}
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build Docker Container with Testing Environment
id: docker-build
uses: docker/build-push-action@v6
with:
context: .
file: .docker/qgis3-qt${{ matrix.qt-version }}-build-deps.dockerfile
tags: qgis/qgis3-qt${{ matrix.qt-version }}-build-deps-bin-only:${{ github.event.pull_request.base.ref || github.ref_name }}
push: ${{ github.event_name == 'push' && github.repository == 'qgis/QGIS' }}
pull: true
target: ${{ matrix.docker-target }}
build-args:
DISTRO_VERSION=${{ matrix.distro-version }}
- name: Tag image
run: docker tag ${{ steps.docker-build.outputs.imageid }} qgis3-build-deps-binary-image
- name: Print disk space
run: |
echo "DOCKER IMAGES"
docker images
echo "DF -H"
sudo df -h
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: build-${{ matrix.distro-version }}-qt${{ matrix.qt-version }}.tgz
path: .
- name: Extract build artifact
run: |
tar xvzf build.tgz
rm -Rf build.tgz
- name: Print disk space
run: |
echo "DF -H"
sudo df -h
- name: Run tests
id: tests
env:
TEST_BATCH: ${{matrix.test-batch}}
QGIS_COMMON_GIT_DIR: ${{ github.workspace }}
GITHUB_SHA: ${{ github.sha }}
run: |
DOCKERFILE=$( ( [[ ${{ matrix.test-batch }} == "ORACLE" ]] && echo "docker-compose-testing-oracle.yml" ) \
|| ( [[ ${{ matrix.test-batch }} == "POSTGRES" ]] && echo "docker-compose-testing-postgres.yml" ) \
|| ( [[ ${{ matrix.test-batch }} == "SQLSERVER" ]] && echo "docker-compose-testing-mssql.yml" ) \
|| echo "docker-compose-testing.yml" )
[[ ${{ matrix.test-batch }} == "ORACLE" ]] && sudo rm -rf /usr/share/dotnet/sdk
echo "TEST_BATCH=$TEST_BATCH"
echo "DOCKERFILE=$DOCKERFILE"
mkdir -p /tmp/webdav_tests && chmod 777 /tmp/webdav_tests
mkdir -p /tmp/minio_tests/test-bucket && chmod -R 777 /tmp/minio_tests
docker compose -f .docker/$DOCKERFILE run -e GITHUB_SHA=$GITHUB_SHA qgis-deps /root/QGIS/.docker/docker-qgis-test.sh $TEST_BATCH
- name: Fix permissions on test report
if: ${{ failure() }}
run: |
sudo chmod -R 777 qgis_test_report
- name: Dump report contents
if: ${{ failure() }}
run: |
MD_REPORT_FILE="qgis_test_report/summary.md"; [ -f "$MD_REPORT_FILE" ] && cat "$MD_REPORT_FILE" || true
- name: Save PR number to test report
if: ${{ failure() }}
run: |
echo ${{ github.event.number }} | tee qgis_test_report/pr_number
echo ${{ github.event.pull_request.head.sha }} | tee qgis_test_report/git_commit
- name: Archive test results report
if: ${{ failure() }}
uses: actions/upload-artifact@v4
with:
name: test-results-qt${{ matrix.qt-version }}
path: qgis_test_report
clang-tidy:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
needs: build
strategy:
matrix:
include:
- distro-version: '24.04'
qt-version: 5
steps:
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # main
with:
tool-cache: true
large-packages: false
docker-images: false
swap-storage: true
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Login to Docker Hub
if: ${{ github.event_name == 'push' && github.repository == 'qgis/QGIS' }}
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build Docker Container with Testing Environment
id: docker-build
uses: docker/build-push-action@v6
with:
context: .
file: .docker/qgis3-qt${{ matrix.qt-version }}-build-deps.dockerfile
tags: qgis/qgis3-qt${{ matrix.qt-version }}-build-deps-bin-only:${{ github.event.pull_request.base.ref || github.ref_name }}
push: ${{ github.event_name == 'push' && github.repository == 'qgis/QGIS' }}
pull: true
target: ${{ matrix.docker-target }}
build-args:
DISTRO_VERSION=${{ matrix.distro-version }}
- name: Tag image
run: docker tag ${{ steps.docker-build.outputs.imageid }} qgis3-build-deps-binary-image
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: build-${{ matrix.distro-version }}-qt${{ matrix.qt-version }}.tgz
path: .
- name: Extract build artifact
run: |
tar xvzf build.tgz
rm -Rf build.tgz
- name: Run Clang-Tidy
run: |
docker run -t --name qgis_container \
-v $(pwd):/root/QGIS \
-v /home/runner/QGIS/.ccache:/root/.ccache \
--env-file .docker/docker-variables.env \
qgis3-build-deps-binary-image \
/root/QGIS/.docker/docker-qgis-clangtidy.sh

38
.github/workflows/sipify-bot.yml vendored Normal file
View File

@ -0,0 +1,38 @@
name: Run sipify
on:
workflow_dispatch:
push:
branches:
- master
- release-*
jobs:
sipify:
runs-on: [ubuntu-latest]
steps:
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install Requirements
run: pip install nose2 mock termcolor pyyaml
- name: Get PR branch
uses: alessbell/pull-request-comment-branch@ef3408c9757d05f89cb525036383033a313758a0 # v2.1.0
if: ${{ github.event_name == 'issue_comment' }}
id: comment-branch
- uses: actions/checkout@v4
- name: run sipify
run: ./scripts/sipify_all.sh -m
- name: commit
run: |
git config user.name qgis-bot
git config user.email bot@qgis.org
git add .
git commit -m "auto sipify 🍺" || echo "nothing to commit"
git push

93
.github/workflows/stale.yml vendored Normal file
View File

@ -0,0 +1,93 @@
name: 👓 Handle stale issues
on:
schedule:
- cron: "30 2 * * *"
permissions:
contents: read
jobs:
stale:
permissions:
issues: write # for actions/stale to close stale issues
pull-requests: write # for actions/stale to close stale PRs
if: github.repository_owner == 'qgis'
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-pr-message: >
The QGIS project highly values your contribution and would love to see
this work merged!
Unfortunately this PR has not had any activity in the last 14 days and
is being automatically marked as "stale".
If you think this pull request should be merged, please check
- that all unit tests are passing
- that all comments by reviewers have been addressed
- that there is enough information for reviewers, in particular
- link to any issues which this pull request fixes
- add a description of workflows which this pull request fixes
- add screenshots if applicable
- that you have written unit tests where possible
In case you should have any uncertainty, please leave a comment and we will
be happy to help you proceed with this pull request.
If there is no further activity on this pull request, it will be closed in a
week.
close-pr-message: >
While we hate to see this happen, this PR has been automatically closed because
it has not had any activity in the last 21 days. If this pull request should be
reconsidered, please follow the guidelines in the previous comment and reopen
this pull request. Or, if you have any further questions, just ask! We love to
help, and if there's anything the QGIS project can do to help push this PR forward
please let us know how we can assist.
stale-pr-label: 'stale'
exempt-pr-labels: 'Merge After Thaw,Frozen'
days-before-pr-stale: 14
days-before-pr-close: 7
stale-issue-message: >
The QGIS project highly values your report and would love to see it addressed.
However, this issue has been left in feedback mode for the last 14 days and is
being automatically marked as "stale".
If you would like to continue with this issue, please provide any missing information
or answer any open questions. If you could resolve the issue yourself meanwhile,
please leave a note for future readers with the same problem and close the issue.
In case you should have any uncertainty, please leave a comment and we will be
happy to help you proceed with this issue.
If there is no further activity on this issue, it will be closed in a week.
close-issue-message: >
While we hate to see this happen, this issue has been automatically closed because
it has not had any activity in the last 42 days despite being marked as feedback.
If this issue should be reconsidered, please follow the guidelines in the previous
comment and reopen this issue.
Or, if you have any further questions, there are also
[further support channels](https://www.qgis.org/en/site/forusers/support.html)
that can help you.
stale-issue-label: 'stale'
only-issue-labels: 'feedback'
days-before-issue-stale: 14
days-before-issue-close: 28
operations-per-run: 1000

21
.github/workflows/unstale.yml vendored Normal file
View File

@ -0,0 +1,21 @@
name: Remove Labels
on: [issue_comment, pull_request]
permissions:
contents: read
jobs:
remove_labels:
permissions:
issues: write # for actions-ecosystem/action-remove-labels to remove issue labels
pull-requests: write # for actions-ecosystem/action-remove-labels to remove PR labels
if: contains(github.event.issue.labels.*.name, 'stale')
runs-on: ubuntu-latest
steps:
- uses: actions-ecosystem/action-remove-labels@v1
if: ${{ github.event.comment.user.url != 'https://github.com/apps/github-actions' }}
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
labels: |
stale

View File

@ -0,0 +1,36 @@
---
name: 🧮 Vcpkg report
on:
pull_request:
paths:
- 'vcpkg/**'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
vcpkg-check:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 30
- name: Generate diff report
id: vcpkg_diff
uses: ./.github/actions/vcpkg_update_report
with:
vcpkg-manifest-dir: vcpkg
triplet: x64-linux
features: 3d,bindings,gui,opencl,quick,server
- name: Schedule report comment
uses: ./.github/actions/post_sticky_comment
if: github.event_name == 'pull_request'
with:
marker: vcpkg-report
body: |
### 🧮 Vcpkg update report
${{ steps.vcpkg_diff.outputs.report }}
pr: ${{ github.event.number }}

152
.github/workflows/windows-qt6.yml vendored Normal file
View File

@ -0,0 +1,152 @@
---
name: 🪟 Windows Qt6
on:
push:
branches:
- master
- release-**
pull_request:
release:
types: ['published']
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
packages: write
jobs:
build:
name: build (windows)
runs-on: windows-2022
steps:
- name: 🐣 Checkout
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: 🔨 Uninstall system cmake
shell: bash
run: |
choco uninstall cmake.install
- name: 🐩 Install CMake and Ninja
uses: lukka/get-cmake@ea004816823209b8d1211e47b216185caee12cc5
with:
cmakeVersion: 3.31.6
- name: 🧽 Developer Command Prompt for Microsoft Visual C++
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 #v1
- name: 🎡 Setup vcpkg
uses: ./.github/actions/setup-vcpkg
- name: 🦬 Setup flex/bison
uses: robinraju/release-downloader@daf26c55d821e836577a15f77d86ddc078948b05 #v1.12
with:
repository: 'lexxmark/winflexbison'
fileName: '*.zip'
tag: 'v2.5.24'
extract: true
- name: 🛍️ Setup ccache
uses: hendrikmuhs/ccache-action@63069e3931dedbf3b63792097479563182fe70d1 #v1.2
with:
max-size: 1G
key: build-ccache-win64-qt6-${{ github.event.pull_request.base.ref || github.ref_name }}
save: ${{ github.event_name == 'push' }}
- name: 🛍️ Tune ccache configuration
shell: bash
run: |
# To make ccache work properly with precompiled headers
ccache --set-config sloppiness=pch_defines,time_macros,include_file_mtime,include_file_ctime
- name: 🌱 Install dependencies and generate project files
shell: bash
env:
X_VCPKG_ASSET_SOURCES: x-azurl,https://assetcache.open-vcpkg.org/assetcache,,read
run: |
BUILD_DIR=$( cygpath "${{ github.workspace }}/build" )
SOURCE_DIR=$( cygpath "${{ github.workspace }}" )
cmake -S "${SOURCE_DIR}" \
-B "${BUILD_DIR}" \
-G Ninja \
-D CMAKE_BUILD_TYPE=Release \
-D WITH_VCPKG=ON \
-D CREATE_ZIP=ON \
-D VCPKG_TARGET_TRIPLET=x64-windows-release \
-D VCPKG_HOST_TRIPLET=x64-windows-release \
-D WITH_DESKTOP=ON \
-D WITH_3D=ON \
-D WITH_BINDINGS=ON \
-D ENABLE_TESTS=OFF \
-D BUILD_WITH_QT6=ON \
-D USE_CCACHE=ON \
-D ENABLE_UNITY_BUILDS=ON \
-D FLEX_EXECUTABLE="${SOURCE_DIR}/win_flex.exe" \
-D BISON_EXECUTABLE="${SOURCE_DIR}/win_bison.exe" \
-D SIP_BUILD_EXECUTABLE="${BUILD_DIR}\vcpkg_installed\x64-windows-release\tools\python3\Scripts\sip-build.exe" \
-D CMAKE_C_COMPILER_LAUNCHER=ccache \
-D CMAKE_CXX_COMPILER_LAUNCHER=ccache \
-D WITH_QTWEBKIT=OFF \
-D VCPKG_INSTALL_OPTIONS="--x-buildtrees-root=C:/src" \
-D NUGET_USERNAME=${{ github.actor }} \
-D NUGET_TOKEN=${{ secrets.GITHUB_TOKEN }}
- name: 🌋 Build
shell: bash
run: |
cmake --build "${{ github.workspace }}/build" --config Release
# - uses: m-kuhn/action-tmate@patch-1
# if: failure()
- name: 📦 Package
shell: bash
run: |
cmake --build "${{ github.workspace }}/build" --target bundle --config Release
- name: 📦 Create SDK
# if: github.event_name == 'workflow_dispatch' || github.event_name == 'release'
run: |
vcpkg.exe export --zip --output-dir=./sdk --x-install-root=./build/vcpkg_installed --x-manifest-root=vcpkg
- name: 📤 Upload sdk
# if: github.event_name == 'workflow_dispatch' || github.event_name == 'release'
uses: actions/upload-artifact@v4
with:
name: qgis-sdk-x64-windows
path: |
sdk/vcpkg-export-*.zip
- name: 📑 Upload dep build logs
uses: actions/upload-artifact@v4
if: failure()
with:
name: build-logs-x64-windows
path: |
C:/src/**/*.log
- name: 📤 Upload bundle
uses: actions/upload-artifact@v4
id: artifact-win64-qt6
with:
name: qgis-windows-qt6
path: |
build/*-win64.zip
- name: Schedule download comment
uses: ./.github/actions/post_sticky_comment
if: github.event_name == 'pull_request'
with:
marker: mingw64-qt6
body: |
### 🪟 Windows Qt6 builds
Download [Windows Qt6 builds of this PR for testing](${{ steps.artifact-win64-qt6.outputs.artifact-url }}).
*(Built from commit ${{ github.event.pull_request.head.sha }})*
pr: ${{ github.event.number }}

View File

@ -0,0 +1,101 @@
name: Write test failure comment
on:
workflow_run:
workflows: [🧪 QGIS tests]
types:
- completed
permissions:
contents: read
jobs:
on-failure:
strategy:
matrix:
qt-version: [ 5, 6 ]
permissions:
pull-requests: write
runs-on: ubuntu-latest
steps:
- name: 'Download artifact'
id: download_artifact
uses: actions/github-script@v7
with:
script: |
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
let matchArtifacts = allArtifacts.data.artifacts.filter((artifact) => {
return artifact.name == "test-results-qt${{ matrix.qt-version }}"
});
if (matchArtifacts.length>0)
{
let download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifacts[0].id,
archive_format: 'zip',
});
let fs = require('fs');
fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/test-results-qt${{ matrix.qt-version }}.zip`, Buffer.from(download.data));
core.setOutput('artifact_id', matchArtifacts[0].id);
}
else
{
core.setOutput('artifact_id', 0);
}
- name: 'Unzip artifact'
if: fromJSON(steps.download_artifact.outputs.artifact_id) > 0
run: unzip -j test-results-qt${{ matrix.qt-version }}.zip *.md pr_number git_commit || ( e=$? && if [ $e -ne 11 ]; then exit $e; fi )
- name: 'Post test report markdown summary as comment on PR'
if: fromJSON(steps.download_artifact.outputs.artifact_id) > 0
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
let fs = require('fs');
if (fs.existsSync('./summary.md'))
{
const issue_number = Number(fs.readFileSync('./pr_number'));
const git_sha = String(fs.readFileSync('./git_commit')).trim();
const prComments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
});
const PREFIX = "# Tests failed for Qt ${{ matrix.qt-version }}";
let body = PREFIX + "\n\n";
body += "*One or more tests failed using the build from commit " + git_sha + "*\n\n";
body += String(fs.readFileSync('./summary.md')) +
"\n\n**The full test report (included comparison of rendered vs expected images) can be found [here](https://github.com/qgis/QGIS/suites/" + context.payload.workflow_run.check_suite_id + "/artifacts/${{steps.download_artifact.outputs.artifact_id}}).**\n\n" +
"Further documentation on the QGIS test infrastructure can be found in the [Developer's Guide](https://docs.qgis.org/latest/en/docs/developers_guide/unittesting.html).";
const failureComment = prComments.data?.find(c => c.body.startsWith(PREFIX));
if (!!failureComment) {
// update the existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: failureComment.id,
body: body
});
} else {
// submit a new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: body
});
}
}

115
.gitignore vendored Normal file
View File

@ -0,0 +1,115 @@
*-stamp
*.*~
*.autosave
*.aux
*.bak
*.diff
*.gpkg-shm
*.gpkg-wal
*.log*
*.orig
*.out
*.prepare
*.pro.user
*.py.temp
*.pyc
*.sortinc
*.stash
*.tex
*.tmp
*.toc
*~
.*.swp
.DS_Store
.cache/
.gdb_history
.idea
.kdev4/
.project
.pydevproject
.venv
.vscode
.vs
.devcontainer
.worktrees
CMakePresets.json
/CMakeLists.txt.user
/CMakeLists.txt.user.*
/build*
Makefile
Testing/*
Thumb.db
api_doc
compile_commands.json
debian/*.debhelper
debian/*.substvars
debian/qgis.sh
desktop.ini
doc/INSTALL.tex
i18n/*.qm
ms-windows/*.exe*
ms-windows/Installer-Files/postinstall.bat
ms-windows/Installer-Files/preremove.bat
ms-windows/nsis/
ms-windows/osgeo4w/addons/
ms-windows/osgeo4w/binary-*
ms-windows/osgeo4w/build-*
ms-windows/osgeo4w/nsis/
ms-windows/osgeo4w/packages-x86/
ms-windows/osgeo4w/packages-x86_64/
ms-windows/osgeo4w/unpacked/
ms-windows/osgeo4w/untgz/
ms-windows/packages/
ms-windows/progs/
ms-windows/untgz/
python/expressions/
python/plugins/grassprovider/description/algorithms.json
python/plugins/grassprovider/tests/testdata/directions.tif.aux.xml
python/plugins/processing/tests/testdata/*.aux.xml
python/plugins/processing/tests/testdata/custom/*.aux.xml
python/plugins/processing/tests/testdata/custom/grass7/*.aux.xml
python/plugins/processing/tests/testdata/dem.prj
python/plugins/processing/tests/testdata/dem.tfw
python/plugins/processing/tests/testdata/dem.wld
qgis-test.ctest
qgis.kdev4
qgis.supp
qtcreator-build/
resources/themes/*/style.qss.auto
resources/server/src/landingpage/node_modules/
scripts/Debug
scripts/RelWithDebInfo
scripts/astyle.exe
scripts/qgisstyle*
src/core/qgsexpression_texts.cpp
tags
tests/testdata/*.aux.xml
tests/testdata/cache/
tests/testdata/checker360by180.asc.aux.xml
tests/testdata/control_images/*/*.aux.xml
tests/testdata/dPAOWM_styles.db
tests/testdata/grass/wgs84/test/.gislock
tests/testdata/grass/wgs84/test6/.gislock
tests/testdata/grass/wgs84/test7/.gislock
tests/testdata/landsat-int16-b1.tif.aux.xml
tests/testdata/mGuhmd_styles.db
tests/testdata/mesh/trap_steady_05_3D.nc.aux.xml
tests/testdata/oOQkbL_styles.db
tests/testdata/point_clouds/las/cloud.copc.laz
tests/testdata/project_translation/points_translation_de_attachments.zip
tests/testdata/qgstestproject_relative_path_test.qgs
tests/testdata/qgstestproject_relative_path_test_attachments.zip
tests/testdata/rKinSs_styles.db
tests/testdata/raster/*.aux.xml
tests/testdata/raster/band1_byte_noct_epsg4326.tif.aux.xml
tests/testdata/raster/band1_float32_noct_epsg4326.tif.aux.xml
tests/testdata/raster/band1_int16_noct_epsg4326.tif.aux.xml
tests/testdata/raster/band3_float32_noct_epsg4326.tif.aux.xml
tests/testdata/raster/band3_int16_noct_epsg4326.tif.aux.xml
tests/testdata/tenbytenraster.asc.aux.xml
tests/testdata/test_plugin_path/plugin_started.txt
tests/testdata/test_qgis_config_path/profiles/default/*
!tests/testdata/test_qgis_config_path/profiles/default/python
tests/testdata/widget_config.qlr
tests/testdata/zip/testtar.tgz.properties
venv

223
.mailmap Normal file
View File

@ -0,0 +1,223 @@
Alessandro Pasotti <elpaso@itopen.it> <apasotti@boundlessgeo.com>
Alessandro Pasotti <elpaso@itopen.it> <apasotti@gmail.com>
Alessandro Pasotti <elpaso@itopen.it> <apasottis@boundlessgeo.com>
Alessandro Pasotti <elpaso@itopen.it> elpaso <elpaso@itopen.it>
Alexander Bruy <alexander.bruy@gmail.com>
Alexander Bruy <alexander.bruy@gmail.com> <alexbruy@c8812cc2-4d05-0410-92ff-de0c093fc19c>
Alexander Bruy <alexander.bruy@gmail.com> <alexander.bruy@gmail.com@881b9c09-3ef8-f3c2-ec3d-21d735c97f4d>
Alexandre Neto <senhor.neto@gmail.com> Alexandre <senhor.neto@gmail.com>
Alexandre Neto <senhor.neto@gmail.com> SrNetoChan <senhor.neto@gmail.com>
Alex <roya0045@users.noreply.github.com> roya0045 <roya0045@users.noreply.github.com>
Alister Hood <alister.hood@gmail.com> Alister <alister.hood@gmail.com>
Alister Hood <alister.hood@gmail.com> Alister <alister.hood@synergine.com>
Alister Hood <alister.hood@gmail.com> AlisterH <alister.hood@gmail.com>
Andreas Neumann <a.neumann@carto.net> andreasneumann <a.neumann@carto.net>
Anita Graser <anitagraser@gmx.at> anitagraser <anitagraser@gmx.at>
Arnaud Morvan <arnaud.morvan@camptocamp.com> arnaud.morvan@camptocamp.com <arnaud.morvan@camptocamp.com>
Asger Skovbo Petersen <asgerpetersen@gmail.com> AsgerPetersen <asgerpetersen@gmail.com>
Borys Jurgiel <info@borysjurgiel.pl> borys <info@borysjurgiel.pl>
Borys Jurgiel <info@borysjurgiel.pl> <info at borysjurgiel dot pl>
Borys Jurgiel <info@borysjurgiel.pl> borysiasty <borysiasty@c8812cc2-4d05-0410-92ff-de0c093fc19c>
Clemens Raffler <clemens.raffler@gmail.com> <root676@users.noreply.github.com>
Clemens Raffler <clemens.raffler@gmail.com> root676 <clemens.raffler@gmail.com>
Clemens Raffler <clemens.raffler@gmail.com> root676 <clemens.raffler@gmx.at>
D'Hont René-Luc <rldhont@gmail.com>
Damiano Lombardi <damiano@opengis.ch> Damiano <damiano@opengis.ch>
Damiano Lombardi <damiano@opengis.ch> Damiano <lombardi.damiano@gmail.com>
Damiano Lombardi <damiano@opengis.ch> <lombardi@customcut.ch>
Damiano Lombardi <damiano@opengis.ch> <lombardi.damiano@gmail.com>
Damiano Lombardi <damiano@opengis.ch> domi <lombardi@customcut.ch>
David Marteau <dmarteau@3liz.com> <david@innophi.com>
David Marteau <dmarteau@3liz.com> <dhmarteau@gmail.com>
David Signer <david@opengis.ch> David <david@opengis.ch>
David Signer <david@opengis.ch> signedav <david@opengis.ch>
Etienne Trimaille <etienne.trimaille@gmail.com> <etienne@Etiennes-MacBook-Pro.local>
Etienne Trimaille <etienne.trimaille@gmail.com> <gustrimaille@yahoo.fr>
Etienne Trimaille <etienne.trimaille@gmail.com> Étienne Trimaille <gustrimaille@yahoo.fr>
Even Rouault <even.rouault@spatialys.com> <even.rouault@mines-paris.org>
Francisco Raga <All4Gis@users.noreply.github.com> Fran Raga <All4Gis@users.noreply.github.com>
Gary Sherman <gsherman@geoapt.com> <gsherman@c8812cc2-4d05-0410-92ff-de0c093fc19c>
Germán Carrillo <gcarrillo@linuxmail.org> gacarrillor <gcarrillo@linuxmail.org>
Germán Carrillo <gcarrillo@linuxmail.org> gacarrillor <geotux_tuxman@linuxmail.org>
Germán Carrillo <gcarrillo@linuxmail.org> <geotux_tuxman@linuxmail.org>
Germán Carrillo <gcarrillo@linuxmail.org> Germán <geotux_tuxman@linuxmail.org>
Germán Carrillo <gcarrillo@linuxmail.org> Germap <gcarrillo@linuxmail.org>
Giovanni Allegri <giovanni.allegri@gmail.com> giohappy <giohappy@gmail.com>
Giovanni Manghi <giovanni.manghi@naturalgis.pt> gioman <giovanni.manghi@faunalia.pt>
Giovanni Manghi <giovanni.manghi@naturalgis.pt> <gio@sibirica.(none)>
Giovanni Manghi <giovanni.manghi@naturalgis.pt> <giovanni.manghi@faunalia.pt>
Giovanni Manghi <giovanni.manghi@naturalgis.pt> Giovanni Manghi <giovanni@sibirica.(none)>
Giuseppe Sucameli <brush.tyler@gmail.com> <brushtyler@881b9c09-3ef8-f3c2-ec3d-21d735c97f4d>
Giuseppe Sucameli <brush.tyler@gmail.com> <brushtyler@c8812cc2-4d05-0410-92ff-de0c093fc19c>
Harrissou Sant-anna <delazj@gmail.com> DelazJ <delazj@gmail.com>
Ivan Ivanov <ivan.ivanov@suricactus.com> <suricactus@users.noreply.github.com>
Jacky Volpes <jacky.volpes@oslandia.com> <34267385+Djedouas@users.noreply.github.com>
Jean-Roc Morreale <jr.morreale@enoreth.net> Jean Roc <jr.morreale@enoreth.net>
Jean-Roc Morreale <jr.morreale@enoreth.net> MORREALE Jean-Roc <jr.morreale@enoreth.net>
Jorge Gustavo Rocha <jgr@geomaster.pt> <jgr@di.uminho.pt>
Julien Cabieces <julien.cabieces@oslandia.com> <julien@julien-laptop.home>
Jürgen E. Fischer <jef@norbit.de>
Jürgen E. Fischer <jef@norbit.de> <fischer@linux-buechse.de>
Jürgen E. Fischer <jef@norbit.de> <jef@c8812cc2-4d05-0410-92ff-de0c093fc19c>
Jürgen E. Fischer <jef@norbit.de> <jef@FARAMIR>
Jürgen E. Fischer <jef@norbit.de> Juergen E. Fischer <jef@norbit.de>
Jürgen E. Fischer <jef@norbit.de> Juergen Fischer <jef@norbit.de>
Jürgen E. Fischer <jef@norbit.de> Jürgen Fischer <jef@norbit.de>
Larry Shaffer <lshaffer@federal.planet.com> <lshaffer@boundlessgeo.com>
Larry Shaffer <lshaffer@federal.planet.com> <dakcarto@users.noreply.github.com>
Larry Shaffer <lshaffer@federal.planet.com> <larrys@dakotacarto.com>
Loïc Bartoletti <loic.bartoletti@oslandia.com>
Loïc Bartoletti <loic.bartoletti@oslandia.com> <l.bartoletti@free.fr>
Loïc Bartoletti <loic.bartoletti@oslandia.com> <coder@tuxfamily.org>
Loïc Bartoletti <loic.bartoletti@oslandia.com> <lbartoletti@tuxfamily.org>
Loïc Bartoletti <loic.bartoletti@oslandia.com> <lbartoletti@users.noreply.github.com>
Luigi Pirelli <luipir@gmail.com> luipir <luipir@gmail.com>
Marco Bernasocchi <marco@opengis.ch> <marco@bernawebdesign.ch>
Marco Bernasocchi <marco@opengis.ch> <marco@muse.(none)>
Marco Bernasocchi <marco@opengis.ch> <marco@placebo.(none)>
Marco Hugentobler <marco.hugentobler@sourcepole.ch> <marco@hugis1.(none)>
Marco Hugentobler <marco.hugentobler@sourcepole.ch> <marco@marco-laptop.(none)>
Marco Hugentobler <marco.hugentobler@sourcepole.ch> <marco@sourcepole.ch>
Marco Hugentobler <marco.hugentobler@sourcepole.ch> mhugent <marco.hugentobler@sourcepole.ch>
Marco Hugentobler <marco.hugentobler@sourcepole.ch> mhugent <mhugent@c8812cc2-4d05-0410-92ff-de0c093fc19c>
Mario Baranzini <mario.baranzini@gmail.com> <mario@opengis.ch>
Mario Baranzini <mario.baranzini@gmail.com> <marioba@users.noreply.github.com>
Markus Neteler <neteler@gmail.com> <neteler@osgeo.org>
Markus Neteler <neteler@gmail.com> <neteler@oboe.localdomain>
Martin Dobias <wonder.sk@gmail.com> <wonder@c8812cc2-4d05-0410-92ff-de0c093fc19c>
Mathieu Pellerin <nirvn.asia@gmail.com>
Matteo Ghetta <matteo.ghetta@gmail.com> ghtmtt <matteo.ghetta@gmail.com>
Matteo Ghetta <matteo.ghetta@gmail.com> matteo <matteo.ghetta@gmail.com>
Matteo Ghetta <matteo.ghetta@gmail.com> Matteo <matteo.ghetta@gmail.com>
Matthias Kuhn <matthias@opengis.ch> <matthias.kuhn@gmx.ch>
Matthias Kuhn <matthias@opengis.ch> <kk@kk-office.gslwd>
Matthias Kuhn <matthias@opengis.ch> matthias-kuhn <matthias.kuhn@gmx.ch>
Nathan Woodrow <madmanwoo@gmail.com> Nathan <nathan_woodrow@technologyonecorp.com>
Nathan Woodrow <madmanwoo@gmail.com> <nathan.woodrow@mapsolutions.com.au>
Nathan Woodrow <madmanwoo@gmail.com> <nathan_woodrow@technologyonecorp.com>
Nathan Woodrow <madmanwoo@gmail.com> <woodrow.nathan@gmail.com>
Nathan Woodrow <madmanwoo@gmail.com> <woo@woo-mint.(none)>
Nedjima Belgacem <gb_nedjima@esi.dz> NEDJIMAbelgacem <gb_nedjima@esi.dz>
Nedjima Belgacem <gb_nedjima@esi.dz> nedjima <gb_nedjima@esi.dz>
Nedjima Belgacem <gb_nedjima@esi.dz> Belgacem <gb_nedjima@esi.dz>
Nicolas Godet <nicolas.godet@outlook.fr> nicogodet <39594821+nicogodet@users.noreply.github.com>
Nicolas Godet <nicolas.godet@outlook.fr> nicogodet <nicolas.godet@outlook.fr>
Nicolas Godet <nicolas.godet@outlook.fr> <39594821+nicogodet@users.noreply.github.com>
Nyall Dawson <nyall.dawson@gmail.com> nyalldawson <nyall.dawson@gmail.com>
Nyall Dawson <nyall.dawson@gmail.com> <nyall@localhost.localdomain>
Nyall Dawson <nyall.dawson@gmail.com> Nyall <nyall.dawson@gmail.com>
Olivier Dalang <olivier.dalang@gmail.com> olivierdalang <olivier.dalang@epfl.ch>
Olivier Dalang <olivier.dalang@gmail.com> olivierdalang <olivier.dalang@gmail.com>
Olivier Dalang <olivier.dalang@gmail.com> olivier <olivier.dalang@gmail.com>
Otto Dassau <dassau@gbd-consult.de> dassau <dassau@c8812cc2-4d05-0410-92ff-de0c093fc19c>
Otto Dassau <dassau@gbd-consult.de> dassau <dassau@gbd-consult.de>
Paolo Cavallini <cavallini@faunalia.it>
Paolo Cavallini <cavallini@faunalia.it> <pcav@c8812cc2-4d05-0410-92ff-de0c093fc19c>
Paul Blottiere <blottiere.paul@gmail.com> Blottiere Paul <blottiere.paul@gmail.com>
Peter Petrik <zilolv@gmail.com> PeterPetrik <zilolv@gmail.com>
Radim Blazek <radim.blazek@gmail.com> <rblazek@c8812cc2-4d05-0410-92ff-de0c093fc19c>
Raymond Nijssen <r.nijssen@terglobo.nl> raymondnijssen <r.nijssen@terglobo.nl>
Régis Haubourg <regis@qgis.org> <regis.haubourg@eau-adour-garonne.fr>
Régis Haubourg <regis@qgis.org> <regis.haubourg@oslandia.com>
Richard Duivenvoorde <richard@duif.net> rduivenvoorde <rduivenvoorde@c8812cc2-4d05-0410-92ff-de0c093fc19c>
Richard Duivenvoorde <richard@duif.net> <rdmailings@duif.net>
Saber <saber.razmjooei@lutraconsulting.co.uk> Lutra <saber.razmjooei@lutraconsulting.co.uk>
Saber <saber.razmjooei@lutraconsulting.co.uk> saber <saber.razmjooei@lutraconsulting.co.uk>
Saber <saber.razmjooei@lutraconsulting.co.uk> Sab <saber.razmjooei@lutraconsulting.co.uk>
Salvatore Fiandaca <pigrecoinfinito@gmail.com> Salvatore <pigrecoinfinito@gmail.com>
Salvatore Larosa <lrssvtml@gmail.com>
Samweli Mwakisambwe <samweli@kartoza.com> <smwltwesa6@gmail.com>
Samweli Mwakisambwe <samweli@kartoza.com> Samweli <samweli@kartoza.com>
Samweli Mwakisambwe <samweli@kartoza.com> Samweli <smwltwesa6@gmail.com>
Sandro Santilli <strk@kbt.io> <strk@keybit.net>
Stefanos Natsis <uclaros@gmail.com> <uclaros@debian-BULLSEYE-live-builder-AMD64>
Stefanos Natsis <uclaros@gmail.com> uclaros <Ucla ros 1>
Stefanos Natsis <uclaros@gmail.com> uclaros <uclaros@gmail.com>
Thomas Gratier <thomas_gratier@yahoo.fr> ThomasG77 <thomas_gratier@yahoo.fr>
Tim Sutton <tim@linfiniti.com> <tim@kartoza.com>
Tim Sutton <tim@linfiniti.com> <timlinux@c8812cc2-4d05-0410-92ff-de0c093fc19c>
Tom Chadwin <tomchadwin@astuntechnology.com> <tom.chadwin@nnpa.org.uk>
Tom Chadwin <tomchadwin@astuntechnology.com> <tomchadwin@users.noreply.github.com>
Tomas Mizera <tomas.mizera@lutraconsulting.co.uk> tomasMizera <tomas.mizera2@gmail.com>
Tomas Mizera <tomas.mizera@lutraconsulting.co.uk> <tomas.mizera2@gmail.com>
Tomas Mizera <tomas.mizera@lutraconsulting.co.uk> tomasMizera <tomas.mizera@lutraconsulting.co.uk>
Tudor Bărăscu <tudor.barascu@qtibia.ro> Tudor Barascu <tudor.barascu@qtibia.ro>
Víctor Olaya <volayaf@gmail.com>
Víctor Olaya <volayaf@gmail.com> <volayaf@881b9c09-3ef8-f3c2-ec3d-21d735c97f4d>
Víctor Olaya <volayaf@gmail.com> <volayaf@gmail.com@881b9c09-3ef8-f3c2-ec3d-21d735c97f4d>
Vincent Cloarec <vcloarec@gmail.com> vcloarec <vcloarec@gmail.com>
Werner Macho <werner.macho@gmail.com> macho <macho@c8812cc2-4d05-0410-92ff-de0c093fc19c>
Werner Macho <werner.macho@gmail.com> <macho@void.(none)>
William Kyngesburye <kyngchaos@kyngchaos.com> kyngchaos <kyngchaos@c8812cc2-4d05-0410-92ff-de0c093fc19c>
William Kyngesburye <kyngchaos@kyngchaos.com> <kyngchaos@sumomo.attlocal.net>
William Kyngesburye <kyngchaos@kyngchaos.com> <kyngchaos@Sumomo.attlocal.net>
Yves Jacolin <yves.jacolin@camptocamp.com> Jacolin <yves.jacolin@camptocamp.com>

48
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,48 @@
exclude: |
(?x)^(
python/.*/auto_\w+/.*.py|
external/.*|
tests/testdata/script_with_error.py
)$
fail_fast: false
repos:
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v19.1.6
# if adding directory handled by clang-format
# you need to adapt prepare_commit and verify_indentation scripts accordingly
hooks:
- id: clang-format
types_or: [c++, c, c#]
exclude: |
(?x)^(
src/core/.*|
tests/code_layout/sipify/sipifyheader.h
)$
- repo: https://github.com/asottile/pyupgrade
rev: v3.19.1
hooks:
- id: pyupgrade
args: [--py39-plus]
- repo: https://github.com/psf/black
rev: 24.10.0
hooks:
- id: black
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
args: ["--profile", "black", "--filter-files"]
- repo: local
hooks:
- id: prepare_commit
name: prepare_commit
entry: ./scripts/prepare_commit.sh
language: system
always_run: true
pass_filenames: false

52
.tx/config Normal file
View File

@ -0,0 +1,52 @@
[main]
host = https://www.transifex.com
[o:qgis:p:QGIS:r:qgis-application]
file_filter = i18n/qgis_<lang>.ts
source_file = i18n/qgis_en.ts
source_lang = en
type = QT
minimum_perc = 35
trans.cs = i18n/qgis_cs.ts
trans.de = i18n/qgis_de.ts
trans.es = i18n/qgis_es.ts
trans.fi = i18n/qgis_fi.ts
trans.it = i18n/qgis_it.ts
trans.ru = i18n/qgis_ru.ts
trans.sk = i18n/qgis_sk.ts
trans.ar = i18n/qgis_ar.ts
trans.hu = i18n/qgis_hu.ts
trans.lv = i18n/qgis_lv.ts
trans.ca = i18n/qgis_ca.ts
trans.ja = i18n/qgis_ja.ts
trans.nb = i18n/qgis_nb.ts
trans.pl = i18n/qgis_pl.ts
trans.pt_PT = i18n/qgis_pt_PT.ts
trans.tr = i18n/qgis_tr.ts
trans.uk = i18n/qgis_uk.ts
trans.hr = i18n/qgis_hr.ts
trans.en_US = i18n/qgis_en_US.ts
trans.fr = i18n/qgis_fr.ts
trans.ko = i18n/qgis_ko.ts
trans.lt = i18n/qgis_lt.ts
trans.pt_BR = i18n/qgis_pt_BR.ts
trans.sr@latin = i18n/qgis_sr@latin.ts
trans.vi = i18n/qgis_vi.ts
trans.el = i18n/qgis_el.ts
trans.eo = i18n/qgis_eo.ts
trans.hi = i18n/qgis_hi.ts
trans.nl = i18n/qgis_nl.ts
trans.ro = i18n/qgis_ro.ts
trans.bs = i18n/qgis_bs.ts
trans.et = i18n/qgis_et.ts
trans.km = i18n/qgis_km.ts
trans.sl = i18n/qgis_sl.ts
trans.sr = i18n/qgis_sr.ts
trans.zh-Hant = i18n/qgis_zh-Hant.ts
trans.eu = i18n/qgis_eu.ts
trans.gl = i18n/qgis_gl.ts
trans.id = i18n/qgis_id.ts
trans.sv = i18n/qgis_sv.ts
trans.zh-Hans = i18n/qgis_zh-Hans.ts
trans.da = i18n/qgis_da.ts

27
AUTHORS
View File

@ -1,27 +0,0 @@
# The following have contributed to QGis:
# --------------------------------------------------------
# Please note that this file is parsed by the about box
# for the contributors list, so names should be strictly
# in the format:
# name [tab] <email>
#
# The name will be used to infer the image name, with spaces
# replaced by underscores. If no matching image is found
# a blank image will be displayed.
# Images are read out of $PREFIX/share/images/contributors/
# ---------------------------------------------------------
Gary E.Sherman <sherman at mrcc dot com>
Steve Halasz <stevehalasz at users.sourceforge.net>
Marco Hugentobler <mhugent at users.sourceforge.net>
Tim Sutton <tim at linfiniti.com>
Denis Antipov <rawbytes at users.sourceforge.net>
Mark Coletti <mcoletti at users.sourceforge.net>
Lars Luthman <larsl at users.sourceforge.net>
Jens Oberender <j.obi at troja.net>
Christoph Spoerri <spoerri at users.sourceforge.net>
Carl Anderson <>
Gavin Macaulay <g_j_m at users.sourceforge.net>
Masaru Hoshi <hoshi at users.sourceforge.net>
Peter Brewer <p.w.brewer at rdg dot ac dot uk>
Radim Blazek <blazek at itc.it>
Tom Elwertowski <telwertowski at users.sourceforge.net>

40
BUGS
View File

@ -1,20 +1,26 @@
BUGS,v 1.4 2004/02/25 05:42:07 gsherman Exp
-----------------------------------------------------------------------------
Known issues and bugs in this release (QGIS 0.1 'Moroz')
RASTER:
1. Very large rasters cause crash [Bug 898642]
Help I think I found a bug!
---------------------------
VECTOR:
1. OGR layers (for example shapefiles) do not reliably select or identify
features. Any feature that intersects the MBR (minimum bounding rectangle)
of the selection rectangle will be returned. This results in more features
being returned than desired.[Bug 896254]
2. Zooming in very close can result in a scrambled display. [Bug 895506]
3. Drawing polygons with patterns other than solid may leave "holes" where the
polygons are not properly rendered.[Bug 889454]
If you find a bug in QGIS, first check if it has already been reported:
PLUGINS:
1. SPIT crashes on empty/invalid data in a shapefile [Bug 903940]
https://github.com/qgis/QGIS/issues
For additional information, see the QGIS Bugs page at:
http://sourceforge.net/tracker/?group_id=55820&atid=478378
If you can't find an existing ticket, report a new one, using the bug report template provided.
Some hints about when you should file a bug:
- Just because a bug is filed doesn't always mean we can or will fix it.
Sometimes people ask for things that will require many man hours to do and
offer little reward to work ratio benefit when compared to the other issues
in the queue. Also some things are simply not fixable due to whatever
technical reason.
- Sometimes we don't fix a bug because the user's vision of how QGIS should
behave doesn't match ours. Hey we are all humans it can happen...
- Always check that your bug has not already been filed by someone else since
dealing with duplicate tickets causes a lot of time wasting.
- Be prepared to provided further feedback after the initial triage.
- Don't be offended if we don't see tickets as having the same priority as you
do. While we appreciate it's inconvenient if some issue prevents you doing
your work, we need to take the big picture view of things and focus on
things that affect the largest proportion of our user base.

1237
CMakeLists.txt Normal file

File diff suppressed because it is too large Load Diff

37
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,37 @@
# Contributing
## Developer guide
A [complete developer guide](https://docs.qgis.org/latest/en/docs/developers_guide/index.html) is also available to explain the development process, the unit testing system and more!
You may also want to consult the build process for QGIS which is fully detailed in the [install guide](INSTALL.md).
## Bug reporting and bug fixing
You can help us **by submitting bug reports or fixing bugs** in the [QGIS bug tracker](https://github.com/qgis/QGIS/issues/).
## New features and enhancements
If you wish to contribute patches you can:
1. [Fork the project](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo)
2. Install the [pre-commit](https://pre-commit.com/) hook: `pre-commit install --install-hooks` (version 4.1+ required)
3. Make your changes
4. Commit to your repository
5. [Create a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)
The development team can then review your contribution and commit it upstream as appropriate.
If you commit a new feature, add `[FEATURE]` to your commit message AND give a clear description of the new feature. The label `Needs documentation` will be added by maintainers and will automatically create an issue on the QGIS-Documentation repo, where you or others should write documentation about it.
For large-scale changes, you can open a [QEP (QGIS Enhancement Proposal)](https://github.com/qgis/QGIS-Enhancement-Proposals). QEPs are used in the process of creating and discussing new enhancements or policy for QGIS.
## Translations
Please help translate QGIS to your language. At this moment about forty languages are already available in the Desktop user interface and about eighty languages are available in transifex ready to be translated.
The [translation](https://docs.qgis.org/latest/en/docs/documentation_guidelines/do_translations.html) process is managed by the [Translation Team](https://qgis.org/community/organisation/#translation) and all the activities are done under the [Transifex](https://www.transifex.com/qgis/) platform.
## Other ways to contribute
If you are not a developer, there are many other possibilities that do not require programming skills to help QGIS to evolve. Check our [project homepage for more information](https://qgis.org/community/involve/).

43
COPYING
View File

@ -1,12 +1,12 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
@ -225,7 +225,7 @@ impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
@ -277,12 +277,12 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
END OF TERMS AND CONDITIONS
In addition, as a special exception, the QGIS Development Team gives
permission to link the code of this program with the Qt library,
including but not limited to the following versions (both free and
commercial): Qt/Non-commerical Windows, Qt/Windows, Qt/X11, Qt/Mac, and
commercial): Qt/Non-commercial Windows, Qt/Windows, Qt/X11, Qt/Mac, and
Qt/Embedded (or with modified versions of Qt that use the same license
as Qt), and distribute linked combinations including the two. You must
obey the GNU General Public License in all respects for all of the code
@ -292,7 +292,7 @@ so. If you do not wish to do so, delete this exception statement from
your version.
How to Apply These Terms to Your New Programs
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
@ -316,17 +316,16 @@ the "copyright" line and a pointer to where the full notice is found.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
@ -349,5 +348,5 @@ necessary. Here is a sample; alter the names:
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

499904
ChangeLog

File diff suppressed because it is too large Load Diff

229
INSTALL
View File

@ -1,229 +0,0 @@
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
Foundation, Inc.
This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it.
Basic Installation
==================
These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. (Caching is
disabled by default to prevent problems with accidental use of stale
cache files.)
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You only need
`configure.ac' if you want to change it or regenerate `configure' using
a newer version of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. Run `./configure --help'
for details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
If you have to use a `make' that does not support the `VPATH'
variable, you have to compile the package for one architecture at a
time in the source code directory. After you have installed the
package for one architecture, use `make distclean' before reconfiguring
for another architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the
_same_ architectures, `configure' can figure that out, but if it prints
a message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the `--target=TYPE' option to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
will cause the specified gcc to be used as the C compiler (unless it is
overridden in the site shell script).
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of the options to `configure', and exit.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

1394
INSTALL.md Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +0,0 @@
To build and install the source checked out from Subversion:
./autogen.sh <configure options>
make
make install
Configure options to autogen.sh can include any of the options available to
configure. Run ./configure --help to get a list of options.
Example to configure for installing in /usr/local/qgis:
./autogen.sh --prefix=/usr/local/qgis
make
make install

View File

@ -1,59 +0,0 @@
# Copyright (C) 2003 Gary Sherman <sherman at mrcc.com>
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
EXTRA_DIST = \
AUTHORS \
BUGS \
ChangeLog \
COPYING \
create_qm_files.sh \
doc \
INSTALL \
$(man1_MANS) \
NEWS \
qgis.spec \
qgsconfig.h.in \
README \
TODO \
update_ts_files.sh
man1_MANS = qgis.man
docdatadir = $(datadir)/$(PACKAGE)/doc
docdata_DATA = AUTHORS
if HAVE_QT3
SUBDIRS = src widgets providers plugins doc tools i18n designer_plugins helpviewer
endif
if HAVE_QT4
SUBDIRS = src widgets providers plugins doc tools i18n
endif
pkginclude_HEADERS = qgsconfig.h
UIcheck:
@UIS=`find . -name *.ui` && \
if [ `grep "UI version" $$UIS | sed -e '/3.1/d' -e '/3.3/d' | wc -l` -ne 0 ]; then \
echo -e "\nWrong UI version:"; \
grep "UI version" $$UIS | sed -e '/3.1/d' -e '/3.3/d' -e 's/:.*version="\([0-9\.]*\)".*/ is version \1/g'; \
echo; \
exit 1; \
fi
release: UIcheck distdir
-chmod -R a+r $(distdir)
GZIP=$(GZIP_ENV) $(AMTAR)$(TAR) chozf $(distdir).tar.gz $(distdir)
rm -f $(distdir)/qgis.spec
sed '/^Source:/s/\.tar\.gz$$/\.tar\.bz2/' qgis.spec \
> $(distdir)/qgis.spec
BZIP2=$(BZIP2_ENV) $(AMTAR)$(TAR) --bzip2 -chof $(distdir).tar.bz2 $(distdir)
-rm -rf $(distdir)

4270
NEWS.md Normal file

File diff suppressed because it is too large Load Diff

71
PROVENANCE Normal file
View File

@ -0,0 +1,71 @@
<!--
This file documents the code provenance review for QGIS as part of the
OSGEO incubation process and should remain in the QGIS source tree. It
should not be included in release packages.
This file is in MediaWiki format for inclusion on the OSGEO wiki.
-->
Note the authoritative copy of this document is stored in the QGIS repository.
= Committers Past and Present =
dassau - Otto Dassau
ersts - Peter Ersts
g_j_m - Gavin Macaulay
godofredo - Godofredo Contreras
gsherman - Gary Sherman
homann - Magnus Homann
hoshi - Masaru Hoshi
jef - Jürgen Fischer
jobi - Jens Oberender
larsl - Lars Luthman
leo.lami - Leonardo Lami
mcoletti - Mark Coletti
mhugent - Marco Hugentobler
morb_au - Brendan Morley
perrygeo - Matthew Perry
rabla/rblazek - Radim Blazek
rawbytes - Denis Antipov
sbr00pwb - Peter Brewer
shalasz/stevehalasz - Steve Halasz
spoerri - Christoph Spoerri
StevenB - Steven Bell
telwertowski - Tom Elwertowski
timlinux - Tim Sutton
warmerdam - Frank Warmerdam
what_nick - Tisham Dhar
wonder - Martin Dobias
= Outstanding Issues =
No issues were discovered in the code review. All external code was
examined to make sure there were no license problems (see below).
= Included Libraries =
The following libraries are used in QGIS:
* GDAL/OGR
* GSL (optional)
* Qt
* PostgreSQL (optional)
* Python (optional)
* GRASS (optional)
* PyQt (optional)
* Sip (optional)
* Sqlite3
= Source Code Review =
All non-generated source files were manually reviewed for copyright and
license statements, as well as potential issues. This constituted a
review of 364 implementation files (.cpp and .cc), 378 header files
(.h), and 21 Python scripts in the src directory and its subdirectories:
app
designer
core
gui
helpviewer
mac
plugins
providers
ui
Where copyright and/or GPL license statement were missing, it was added
after ensuring it was appropriate. All code within the project is
licensed under the GPL or LGPL, version 2.
== External Source Files ==
The following files are included in the QGIS source tree from external
sources. The source, license, and copyright are noted for each.

70
README
View File

@ -1,70 +0,0 @@
README for QGIS version 0.7 'Seamus'
Quantum GIS (QGIS) is an Open Source Geographic Information System. The
project was born in May of 2002 and was established as a project on
SourceForge in June of the same year. We've worked hard to make GIS
software (which is traditionaly expensive commerical software) a viable
prospect for anyone with basic access to a Personal Computer. QGIS
currently runs on most Unix platforms, Window, and OS X. QGIS is
developed using the Qt toolkit (http://www.trolltech.com) and C++. This
means that QGIS feels snappy to use and has a pleasing, easy to use
graphical user interface.
QGIS aims to be an easy to use GIS, providing common functions and
features. The initial goal was to provide a GIS data viewer. QGIS has
reached that point in its evolution and is being used by many for their
daily GIS data viewing needs. QGIS supports a number of raster and
vector data formats, with new support easily added using the plugin
architecture.
QGIS is released under the GNU Public License (GPL). Devloping QGIS
under this license means that you can (if you want to) inspect and
modify the source code and guarantees that you, our happy user will
always have access to a GIS program that is free of cost and can be
freely modified.
This release adds:
* Projection support
Supported raster formats include:
Grass
USGS DEM
ArcInfo binary grid
ArcInfo ASCII grid
ERDAS Imagine
SDTS
GeoTiff
Tiff with world file
Supported vector formats include:
ESRI Shapefiles
PostgreSQL/PostGIS
GRASS
NOTE -- Please follow the installation instructions carefully.
After untarring the distribution, you can find the HTML version of the
installation document in qgis/doc/index.html. The installation document is
also available as PDF in the same directory or on the website at
http://qgis.org/docs/install.html.
HELP US -- Please submit bug reports using the QGIS bug tracker at:
http://sourceforge.net/tracker/?group_id=55820&atid=478378
When reporting a bug, either login to SourceForge or, if you don't
have a SourceForge id, provide an email address where we can
request additional information.
Please do not use the Bugs forum to report bugs.
SUPPORT - You can get support in the following ways:
1. Using the QGIS community site at http://community.qgis.org
2. Joining the qgis-users mailing list at:
http://lists.sourceforge.net/lists/listinfo/qgis-user
3. Using IRC by joining the #qgis channel on irc.freenode.net.
Please wait around for a response to your question as many
folks on the channel are doing other things and it may take a
while for them to notice your question.

190
README.md Normal file
View File

@ -0,0 +1,190 @@
<img src="images/README-md/main_logo.png" width="300">
[![🧪 QGIS tests](https://github.com/qgis/QGIS/actions/workflows/run-tests.yml/badge.svg)](https://github.com/qgis/QGIS/actions/workflows/run-tests.yml?query=branch%3Amaster+event%3Apush)
[![Docker Status](https://img.shields.io/docker/automated/qgis/qgis.svg)](https://hub.docker.com/r/qgis/qgis/tags)
[![Build Status](https://dev.azure.com/qgis/QGIS/_apis/build/status/qgis.QGIS?branchName=master)](https://dev.azure.com/qgis/QGIS/_build/latest?definitionId=1&branchName=master)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/qgis/QGIS/badge)](https://securityscorecards.dev/viewer/?uri=github.com/qgis/QGIS)
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/1581/badge)](https://www.bestpractices.dev/projects/1581)
[![🪟 MingW64 Windows 64bit Build](https://github.com/qgis/QGIS/actions/workflows/mingw64.yml/badge.svg)](https://github.com/qgis/QGIS/actions/workflows/mingw64.yml?query=branch%3Amaster+event%3Apush)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5869837.svg)](https://doi.org/10.5281/zenodo.5869837)
QGIS is a full-featured, user-friendly, free-and-open-source (FOSS) geographical information system (GIS) that runs on Unix platforms, Windows, and MacOS.
<!-- TOC generated with https://freelance-tech-writer.github.io/table-of-contents-generator/index.html -->
- [Features](#features)
- [1. Flexible and powerful spatial data management](#1-flexible-and-powerful-spatial-data-management)
- [2. Beautiful cartography](#2-beautiful-cartography)
- [3. Advanced and robust geospatial analysis](#3-advanced-and-robust-geospatial-analysis)
- [4. Powerful customization and extensibility](#4-powerful-customization-and-extensibility)
- [5. QGIS Server](#5-qgis-server)
- [Under the hood](#under-the-hood)
- [Versions and release cycle](#versions-and-release-cycle)
- [Free and Open Source](#free-and-open-source)
- [Installing and using QGIS](#installing-and-using-qgis)
- [Documentation](#documentation)
- [Help and support channels](#help-and-support-channels)
- [Get involved with the community](#get-involved-with-the-community)
## Features
### 1. Flexible and powerful spatial data management
- Support for raster, vector, mesh, and point cloud data in a range of industry-standard formats
- *Raster formats include*: GeoPackage, GeoTIFF, GRASS, ArcInfo binary and ASCII grids, ERDAS Imagine SDTS, WMS, WCS, PostgreSQL/PostGIS, and [other GDAL supported formats](https://gdal.org/drivers/raster/index.html).
- *Vector formats include*: GeoPackage, ESRI shapefiles, GRASS, SpatiaLite, PostgreSQL/PostGIS, MSSQL, Oracle, WFS, Vector Tiles and [other OGR supported formats](https://www.gdal.org/ogr_formats.html).
- *Mesh formats include*: NetCDF, GRIB, 2DM, and [other MDAL supported formats](https://github.com/lutraconsulting/MDAL#supported-formats).
- *Point-cloud format*: LAS/LAZ and EPT datasets.
- Data abstraction framework, with local files, spatial databases (PostGIS, SpatiaLite, SQL Server, Oracle, SAP HANA), and web services (WMS, WCS, WFS, ArcGIS REST) all accessed through a unified data model and browser interface, and as flexible layers in user-created projects
- Spatial data creation via visual and numerical digitizing and editing, as well as georeferencing of raster and vector data
- On-the-fly reprojection between coordinate reference systems (CRS)
- Nominatim (OpenStreetMap) geocoder access
- Temporal support
*Example: Temporal animation*
![Example: Temporal animation](images/README-md/icebergs.gif "Temporal animation")
*Example: 3D map view*
![Example: 3D map view](https://docs.qgis.org/latest/en/_images/3dmapview.png "3D map view")
### 2. Beautiful cartography
- Large variety of rendering options in 2D and 3D
- Fine control over symbology, labeling, legends and additional graphical elements for beautifully rendered maps
- Respect for embedded styling in many spatial data sources (e.g. KML and TAB files, Mapbox-GL styled vector tiles)
- In particular, near-complete replication (and significant extension) of symbology options that are available in proprietary software by ESRI
- Advanced styling using data-defined overrides, blending modes, and draw effects
- 500+ built-in color ramps (cpt-city, ColorBrewer, etc.)
- Create and update maps with specified scale, extent, style, and decorations via saved layouts
- Generate multiple maps (and reports) automatically using QGIS Atlas and QGIS Reports
- Display and export elevation profile plots with flexible symbology
- Flexible output direct to printer, or as image (raster), PDF, or SVG for further customization
- On-the-fly rendering enhancements using geometry generators (e.g. create and style new geometries from existing features)
- Preview modes for inclusive map making (e.g. monochrome, color blindness)
*[Example: Map of Bogota, Colombia in the style of Starry Starry Night, by Andrés Felipe Lancheros Sánchez](https://flic.kr/p/2jFfGJP)*
![Map of Bogota, Colombia in the style of Starry Starry Night](https://live.staticflickr.com/65535/50327326323_3da28f0d86_b.jpg "Map of Bogota, Colombia in the style of Starry Starry Night")
For more maps created with QGIS, visit the [QGIS Map Showcase Flickr Group](https://www.flickr.com/groups/2244553@N22/pool/with/50355460063/).
![QGIS Map Showcase](images/README-md/qgis_map_showcase.png "QGIS Map Showcase")
### 3. Advanced and robust geospatial analysis
- Powerful processing framework with 200+ native processing algorithms
- Access to 1000+ processing algorithms via providers such as GDAL, SAGA, GRASS, OrfeoToolbox, as well as custom models and processing scripts
- Geospatial database engine (filters, joins, relations, forms, etc.), as close to datasource- and format-independent as possible
- Immediate visualization of geospatial query and geoprocessing results
- Model designer and batch processing
*Example: Travel isochrones*
![Example: Travel isochrones](images/README-md/network_analysis_2.png "Travel isochrones")
*Example: Model designer*
![Example: model designer](https://docs.qgis.org/latest/en/_images/models_model.png "Model designer")
### 4. Powerful customization and extensibility
- Fully customizable user experience, including user interface and application settings that cater to power-users and beginners alike
- Rich [expression engine](https://docs.qgis.org/testing/en/docs/user_manual/working_with_vector/expression.html) for maximum flexibility in visualization and processing
- Broad and varied [plugin ecosystem](https://plugins.qgis.org/) that includes data connectors, digitizing aids, advanced analysis and charting tools,
in-the-field data capture, conversion of ESRI style files, etc.
- Style manager for creating, storing, and managing styles
- [QGIS style hub](https://plugins.qgis.org/styles/) for easy sharing of styles
- Python and C++ API for standalone (headless) applications as well as in-application comprehensive scripting (PyQGIS)
*Example: Style manager*
![Example: Style manager](https://docs.qgis.org/latest/en/_images/stylemanager.png "Style Manager")
*Example: Plugins*
![Example: Plugins](images/README-md/plugins_1.png "Plugins")
<!-- Kill this one for now, since the example provided is Python2 not 3
Example: Python console
![Example: Python console](https://docs.qgis.org/latest/en/_images/python_console_editor.png "Python console")
-->
### 5. QGIS Server
Headless map server -- running on Linux, macOS, Windows, or in a docker container -- that shares the same code base as QGIS.
- Industry-standard protocols (WMS, WFS, WFS3/OGC API for Features and WCS) allow plug-n-play with any software stack
- Works with any web server (Apache, nginx, etc) or standalone
- All beautiful QGIS cartography is supported with best-in-class support for printing
- Fully customizable with Python scripting support
*Example: QGIS server WMS response*
![Example: QGIS Server response to a WMS request](https://docs.qgis.org/latest/en/_images/server_selection_parameter.png "QGIS Server response to a WMS request")
*Example: QGIS server WFS response*
![Example: QGIS Server response to a WFS Feature request](https://docs.qgis.org/latest/en/_images/server_wfs3_feature.png "QGIS Server response to a WFS Feature request")
## Under the hood
QGIS is developed using the [Qt toolkit](https://qt.io) and C++, since 2002, and has a pleasing, easy to use graphical
user interface with multilingual support. It is maintained by an active developer team and supported by vibrant
community of GIS professionals and enthusiasts as well as geospatial data publishers and end-users.
### Versions and release cycle
QGIS development and releases follow a [time based schedule/roadmap](https://www.qgis.org/en/site/getinvolved/development/roadmap.html). There are three main branches of QGIS that users can install. These are the **Long Term Release (LTR)** branch, the **Latest Release (LR)** branch, and the **Development (Nightly)** branch.
Every month, there is a **Point Release** that provides bug-fixes to the LTR and LR.
### Free and Open Source
QGIS is released under the GNU Public License (GPL) Version 2 or any later version.
Developing QGIS under this license means that you can (if you want to) inspect
and modify the source code and guarantees that you, our happy user will always
have access to a GIS program that is free of cost and can be freely
modified.
QGIS is part of the Open-Source Geospatial Foundation ([OSGeo](https://www.osgeo.org/)), offering a range of complementary open-source GIS software projects.
## Installing and using QGIS
Precompiled binaries for QGIS are available at [the QGIS.org download page](https://www.qgis.org/en/site/forusers/download.html).
Please follow the installation instructions carefully.
The [building guide](INSTALL.md) can be used to get started with building QGIS from source.
For installation of QGIS Server, see its [getting started documentation](https://docs.qgis.org/testing/en/docs/server_manual/getting_started.html).
### Documentation
A range of [documentation](https://qgis.org/resources/hub/#documentation) is available. This includes:
- [Training Manual](https://docs.qgis.org/latest/en/docs/training_manual/index.html)
- [QGIS User Guide](https://docs.qgis.org/latest/en/docs/user_manual/index.html)
- [QGIS Server Guide](https://docs.qgis.org/latest/en/docs/server_manual/index.html)
- [Visual Changelog](https://qgis.org/project/visual-changelogs/)
- [Documentation Guidelines](https://docs.qgis.org/latest/en/docs/documentation_guidelines/index.html)
- [QGIS Python (PyQGIS) Cookbook](https://docs.qgis.org/latest/en/docs/pyqgis_developer_cookbook/index.html)
- [QGIS Python (PyQGIS) API](https://qgis.org/pyqgis/)
- [QGIS C++ API](https://qgis.org/api/)
- [Developers Guide](https://docs.qgis.org/latest/en/docs/developers_guide/index.html)
### Help and support channels
There are several channels where you can find help and support for QGIS:
- Using the [QGIS community site](https://qgis.org)
- Joining the [qgis-users mailing list](https://lists.osgeo.org/mailman/listinfo/qgis-user)
- Chatting with other users real-time. *Please wait around for a response to your question as many folks on the channel are doing other things and it may take a while for them to notice your question. The following paths all take you to the same chat room:*
- Using an IRC client and joining the
[#qgis](https://web.libera.chat/?channels=#qgis) channel on irc.libera.chat.
- Using a Matrix client and joining the [#qgis:osgeo.org](https://matrix.to/#/#qgis:osgeo.org) room.
- At the [GIS stackexchange](https://gis.stackexchange.com/) or [r/QGIS reddit](https://www.reddit.com/r/QGIS/), which are not maintained by the QGIS team, but where the QGIS and broader GIS community provides lots of advice
- [Other support channels](https://qgis.org/resources/support/)
## Get involved with the community
[Contribution guidelines for this project](CONTRIBUTING.md)

10
TODO
View File

@ -1,10 +0,0 @@
TODO,v 1.21 2004/06/03 18:36:46 gsherman Exp
#############################################################################
TODO List for 0.8 (in no order of importance)
#############################################################################
1. Complete WMS support
2. Implement new legend
3. New GRASS tools in toolbox
4. Editing fixups
5. Implement Phase I of take over the world
6. Rethink Phase I

View File

@ -1,684 +0,0 @@
dnl ------------------------------------------------------------------------
dnl Detect if this is a 64bit environment
dnl
dnl it sets:
dnl _lib
dnl ------------------------------------------------------------------------
AC_DEFUN([AQ_CHECK_LIB64],
[
if test `echo ${libdir} | sed -e 's#.*lib64.*#64#'` = "64"; then
_lib="lib64"
else
_lib="lib"
fi
])
dnl ------------------------------------------------------------------------
dnl Detect GDAL/OGR
dnl
dnl use AQ_CHECK_GDAL to detect GDAL and OGR
dnl it sets:
dnl GDAL_CFLAGS
dnl GDAL_LDADD
dnl ------------------------------------------------------------------------
# Check for GDAL and OGR compiler and linker flags
AC_DEFUN([AQ_CHECK_GDAL],
[
AC_ARG_WITH([gdal],
AC_HELP_STRING([--with-gdal=path],
[Full path to 'gdal-config' script, e.g. '--with-gdal=/usr/local/bin/gdal-config']),
[ac_gdal_config_path=$withval])
if test x"$ac_gdal_config_path" = x ; then
ac_gdal_config_path=`which gdal-config`
fi
ac_gdal_config_path=`dirname $ac_gdal_config_path 2> /dev/null`
AC_PATH_PROG(GDAL_CONFIG, gdal-config, no, $ac_gdal_config_path)
if test x${GDAL_CONFIG} = xno ; then
AC_MSG_ERROR([gdal-config not found! Supply it with --with-gdal=PATH])
else
AC_MSG_CHECKING([for OGR in GDAL])
if test x`$GDAL_CONFIG --ogr-enabled` = "xno" ; then
AC_MSG_ERROR([GDAL must be compiled with OGR support and currently is not.])
fi
AC_MSG_RESULT(yes)
AC_MSG_CHECKING([GDAL_CFLAGS])
GDAL_CFLAGS=`$GDAL_CONFIG --cflags`
AC_MSG_RESULT($GDAL_CFLAGS)
AC_MSG_CHECKING([GDAL_LDADD])
GDAL_LDADD=`$GDAL_CONFIG --libs`
AC_MSG_RESULT($GDAL_LDADD)
ac_gdalogr_version=`$GDAL_CONFIG --version`
ac_gdalogr="yes"
fi
AC_SUBST(GDAL_CFLAGS)
AC_SUBST(GDAL_LDADD)
])
dnl ------------------------------------------------------------------------
dnl Detect GEOS
dnl
dnl use AQ_CHECK_GEOS to detect GEOS
dnl it sets:
dnl GEOS_CFLAGS
dnl GEOS_LDADD
dnl ------------------------------------------------------------------------
# Check for GEOS
AC_DEFUN([AQ_CHECK_GEOS],
[
AC_ARG_WITH([geos],
AC_HELP_STRING([--with-geos=path],
[Full path to 'geos-config' script, e.g. '--with-geos=/usr/local/bin/geos-config']),
[ac_geos_config_path=$withval])
if test x"$ac_geos_config_path" = x ; then
ac_geos_config_path=`which geos-config`
fi
ac_geos_config_path=`dirname $ac_geos_config_path 2> /dev/null`
AC_PATH_PROG(GEOS_CONFIG, geos-config, no, $ac_geos_config_path)
if test x${GEOS_CONFIG} = xno ; then
AC_MSG_ERROR([geos-config not found! Supply it with --with-geos=PATH])
else
ac_geos_version=`${GEOS_CONFIG} --version`
if test `echo ${ac_geos_version} | sed -e 's#2\.[0-9].*#OK#'` != OK ; then
AC_MSG_ERROR([Geos Version 2.x.x is needed, but you have $ac_geos_version!])
else
AC_MSG_CHECKING([GEOS_CFLAGS])
GEOS_CFLAGS=`$GEOS_CONFIG --cflags`
AC_MSG_RESULT($GEOS_CFLAGS)
AC_MSG_CHECKING([GEOS_LDADD])
GEOS_LDADD=`$GEOS_CONFIG --libs`
AC_MSG_RESULT($GEOS_LDADD)
ac_geos="yes"
fi
fi
AC_SUBST(GEOS_CFLAGS)
AC_SUBST(GEOS_LDADD)
])
dnl ------------------------------------------------------------------------
dnl Detect QT3
dnl
dnl use AQ_CHECK_QT to detect QT3
dnl it sets:
dnl QT_CXXFLAGS
dnl QT_LDADD
dnl QT_GUILINK
dnl QASSISTANTCLIENT_LDADD
dnl ------------------------------------------------------------------------
# Check for Qt compiler flags, linker flags, and binary packages
AC_DEFUN([AQ_CHECK_QT],
[
AC_REQUIRE([AC_PROG_CXX])
AC_REQUIRE([AC_PATH_X])
AC_MSG_CHECKING([QTDIR])
AC_ARG_WITH([qtdir], [ --with-qtdir=DIR Qt installation directory [default=/usr/local]], QTDIR=$withval)
# Check that QTDIR is defined or that --with-qtdir given
if test x$QTDIR = x ; then
QT_SEARCH=" /usr/lib/qt31 /usr/lib64/qt31 /usr/local/qt31 /usr/lib/qt3 /usr/lib64/qt3 /usr/local/qt3 /usr/lib/qt2 /usr/lib64/qt2 /usr/local/qt2 /usr/lib/qt /usr/lib64/qt /usr/local/qt /usr /usr/local"
for i in $QT_SEARCH; do
if test x$QTDIR = x; then
if test -f $i/include/qt/qglobal.h -o -f $i/include/qglobal.h -o -f $i/include/qt3/qglobal.h; then
QTDIR=$i
fi
fi
done
fi
if test x$QTDIR = x ; then
AC_MSG_ERROR([*** QTDIR must be defined, or --with-qtdir option given])
fi
AC_MSG_RESULT([$QTDIR])
# Change backslashes in QTDIR to forward slashes to prevent escaping
# problems later on in the build process, mainly for Cygwin build
# environment using MSVC as the compiler
# (include/Qt is used on Qt4)
# TODO: Use sed instead of perl
QTDIR=`echo $QTDIR | perl -p -e 's/\\\\/\\//g'`
# Check for QT includedir
if test -f $QTDIR/include/qt/qglobal.h; then
QTINC=$QTDIR/include/qt
QTVERTEST=$QTDIR/include/qt
elif test -f $QTDIR/include/qt3/qglobal.h; then
QTINC=$QTDIR/include/qt3
QTVERTEST=$QTDIR/include/qt3
elif test -f $QTDIR/include/Qt/qglobal.h; then
QTINC=$QTDIR/include
QTVERTEST=$QTDIR/include/Qt
else
QTINC=$QTDIR/include
QTVERTEST=$QTDIR/include
fi
# Figure out which version of Qt we are using
AC_MSG_CHECKING([Qt version])
QT_VER=`grep 'define.*QT_VERSION_STR\W' $QTVERTEST/qglobal.h | perl -p -e 's/\D//g'`
case "${QT_VER}" in
41*|40*)
QT_MAJOR="4"
QT4_3SUPPORTINC=$QTDIR/include/Qt3Support
QT4_COREINC=$QTDIR/include/QtCore
QT4_DESIGNERINC=$QTDIR/include/QtDesigner
QT4_GUIINC=$QTDIR/include/QtGui
QT4_NETWORKINC=$QTDIR/include/QtNetwork
QT4_OPENGLINC=$QTDIR/include/QtOpenGL
QT4_SQLINC=$QTDIR/include/QtSql
QT4_XMLINC=$QTDIR/include/QtXml
QT4_DEFAULTINC=$QTDIR/mkspecs/default
;;
33*)
QT_MAJOR="3"
;;
# 32*)
# QT_MAJOR="3"
# ;;
# 31*)
# QT_MAJOR="3"
# ;;
*)
AC_MSG_ERROR([*** Qt version 3.3.x or higher is required])
;;
esac
AC_MSG_RESULT([$QT_VER ($QT_MAJOR)])
if test $QT_MAJOR = "3" ; then
# Check that moc is in path
AC_CHECK_PROG(MOC, moc, moc)
if test x$MOC = x ; then
AC_MSG_ERROR([*** moc must be in path])
fi
# uic is the Qt user interface compiler
AC_CHECK_PROG(UIC, uic, uic)
if test x$UIC = x ; then
AC_MSG_ERROR([*** uic must be in path])
fi
fi
if test $QT_MAJOR = "4" ; then
# Hard code things for the moment
# Check that moc is in path
AC_CHECK_PROG(MOC, moc, $QTDIR/bin/moc, , $QTDIR/bin)
if test x$MOC = x ; then
AC_MSG_ERROR([*** moc must be in path])
fi
# uic3 is the Qt user interface compiler in Qt3 legacy mode
AC_CHECK_PROG(UIC, uic3, $QTDIR/bin/uic3, , $QTDIR/bin)
if test x$UIC = x ; then
AC_MSG_ERROR([*** uic3 must be in path])
fi
fi
# qembed is the Qt data embedding utility.
# It is located in $QTDIR/tools/qembed, and must be compiled and installed
# manually, we'll let it slide if it isn't present
### AC_CHECK_PROG(QEMBED, qembed, qembed)
# Calculate Qt include path
if test $QT_MAJOR = "3" ; then
QT_CXXFLAGS="-I$QTINC"
fi
if test $QT_MAJOR = "4" ; then
QT_CXXFLAGS="-DQT3_SUPPORT -I$QT4_DEFAULTINC -I$QT4_3SUPPORTINC -I$QT4_COREINC -I$QT4_DESIGNERINC -I$QT4_GUIINC -I$QT4_NETWORKINC -I$QT4_OPENGLINC -I$QT4_SQLINC -I$QT4_XMLINC -I$QTINC"
fi
QT_IS_EMBEDDED="no"
# On unix, figure out if we're doing a static or dynamic link
case "${host}" in
*-cygwin)
AC_DEFINE_UNQUOTED(WIN32, "", Defined if on Win32 platform)
echo "$QTDIR/lib/qt-mt$QT_VER.lib"
if test -f "$QTDIR/lib/qt-mt$QT_VER.lib" ; then
QT_LIB="qt-mt$QT_VER.lib"
QT_IS_STATIC="no"
QT_IS_MT="yes"
elif test -f "$QTDIR/lib/qt$QT_VER.lib" ; then
QT_LIB="qt$QT_VER.lib"
QT_IS_STATIC="no"
QT_IS_MT="no"
elif test -f "$QTDIR/lib/qt.lib" ; then
QT_LIB="qt.lib"
QT_IS_STATIC="yes"
QT_IS_MT="no"
elif test -f "$QTDIR/lib/qt-mt.lib" ; then
QT_LIB="qt-mt.lib"
QT_IS_STATIC="yes"
QT_IS_MT="yes"
fi
;;
*-darwin*)
# determin static or dynamic -- prefer dynamic
QT_IS_DYNAMIC=`ls $QTDIR/lib/libqt*.dylib 2> /dev/null`
if test "x$QT_IS_DYNAMIC" = x; then
QT_IS_STATIC=`ls $QTDIR/lib/libqt*.a 2> /dev/null`
if test "x$QT_IS_STATIC" = x; then
QT_IS_STATIC="no"
AC_MSG_ERROR([*** Couldn't find any Qt libraries in $QTDIR/${_lib}])
else
QT_IS_STATIC="yes"
fi
else
QT_IS_STATIC="no"
fi
# set link parameters based on shared/mt libs or static lib
if test "x`ls $QTDIR/lib/libqt.a* 2> /dev/null`" != x ; then
QT_LIB="-lqt"
QT_IS_MT="no"
elif test "x`ls $QTDIR/lib/libqt-mt.*.dylib 2> /dev/null`" != x ; then
QT_LIB="-lqt-mt"
QT_IS_MT="yes"
elif test "x`ls $QTDIR/lib/libqt.*.dylib 2> /dev/null`" != x ; then
QT_LIB="-lqt"
QT_IS_MT="no"
elif test "x`ls $QTDIR/lib/libqte.* 2> /dev/null`" != x ; then
QT_LIB="-lqte"
QT_IS_MT="no"
QT_IS_EMBEDDED="yes"
elif test "x`ls $QTDIR/lib/libqte-mt.* 2> /dev/null`" != x ; then
QT_LIB="-lqte-mt"
QT_IS_MT="yes"
QT_IS_EMBEDDED="yes"
fi
;;
*)
# determin static or dynamic -- prefer dynamic
QT_IS_DYNAMIC=`ls $QTDIR/${_lib}/libqt*.so $QTDIR/${_lib}/libQtCore.so 2> /dev/null`
if test "x$QT_IS_DYNAMIC" = x; then
QT_IS_STATIC=`ls $QTDIR/${_lib}/libqt*.a $QTDIR/${_lib}/libQtCore.a 2> /dev/null`
if test "x$QT_IS_STATIC" = x; then
QT_IS_STATIC="no"
AC_MSG_ERROR([*** Couldn't find any Qt libraries in $QTDIR/${_lib}])
else
QT_IS_STATIC="yes"
fi
else
QT_IS_STATIC="no"
fi
# set link parameters based on shared/mt libs or static lib
if test "x`ls $QTDIR/${_lib}/libqt.a* 2> /dev/null`" != x ; then
QT_LIB="-lqt"
QT_IS_MT="no"
elif test "x`ls $QTDIR/${_lib}/libqt-mt.so* 2> /dev/null`" != x ; then
QT_LIB="-lqt-mt"
QT_IS_MT="yes"
elif test "x`ls $QTDIR/${_lib}/libqt.so* 2> /dev/null`" != x ; then
QT_LIB="-lqt"
QT_IS_MT="no"
elif test "x`ls $QTDIR/${_lib}/libqte.* 2> /dev/null`" != x ; then
QT_LIB="-lqte"
QT_IS_MT="no"
QT_IS_EMBEDDED="yes"
elif test "x`ls $QTDIR/${_lib}/libqte-mt.* 2> /dev/null`" != x ; then
QT_LIB="-lqte-mt"
QT_IS_MT="yes"
QT_IS_EMBEDDED="yes"
elif test "x`ls $QTDIR/${_lib}/libQtCore.* 2> /dev/null`" != x ; then
QT_LIB="-lQtCore -lQt3Support -lQtGui -lQtNetwork"
QT_CXXFLAGS="-DQT3_SUPPORT -I$QT4_DEFAULTINC -I$QT4_3SUPPORTINC -I$QT4_COREINC -I$QT4_DESIGNERINC -I$QT4_GUIINC -I$QT4_NETWORKINC -I$QT4_OPENGLINC -I$QT4_SQLINC -I$QT4_XMLINC -I$QTINC"
QT_IS_MT="yes"
fi
;;
esac
AC_MSG_CHECKING([if Qt is static])
AC_MSG_RESULT([$QT_IS_STATIC])
AC_MSG_CHECKING([if Qt is multithreaded])
AC_MSG_RESULT([$QT_IS_MT])
AC_MSG_CHECKING([if Qt is embedded])
AC_MSG_RESULT([$QT_IS_EMBEDDED])
QT_GUILINK=""
QASSISTANTCLIENT_LDADD="-lqassistantclient"
case "${host}" in
*irix*)
QT_LIBS="$QT_LIB"
if test $QT_IS_STATIC = yes ; then
QT_LIBS="$QT_LIBS -L$x_libraries -lXext -lX11 -lm -lSM -lICE"
fi
;;
*linux*)
QT_LIBS="$QT_LIB"
if test $QT_IS_STATIC = yes && test $QT_IS_EMBEDDED = no; then
QT_LIBS="$QT_LIBS -L$x_libraries -lXext -lX11 -lm -lSM -lICE -ldl -ljpeg"
fi
;;
*freebsd*)
QT_LIBS="$QT_LIB"
if test $QT_IS_STATIC = yes && test $QT_IS_EMBEDDED = no; then
QT_LIBS="$QT_LIBS -L$x_libraries -lXext -lX11 -lm -lSM -lICE -ldl -ljpeg -lpthread"
else
QT_LIBS="$QT_LIBS -lpthread"
fi
;;
*darwin*)
QT_LIBS="$QT_LIB"
if test $QT_IS_STATIC = yes && test $QT_IS_EMBEDDED = no; then
QT_LIBS="$QT_LIBS -L$x_libraries -lXext -lX11 -lm -lSM -lICE -ldl -ljpeg"
fi
;;
*osf*)
# Digital Unix (aka DGUX aka Tru64)
QT_LIBS="$QT_LIB"
if test $QT_IS_STATIC = yes ; then
QT_LIBS="$QT_LIBS -L$x_libraries -lXext -lX11 -lm -lSM -lICE"
fi
;;
*solaris*)
QT_LIBS="$QT_LIB"
if test $QT_IS_STATIC = yes ; then
QT_LIBS="$QT_LIBS -L$x_libraries -lXext -lX11 -lm -lSM -lICE -lresolv -lsocket -lnsl"
fi
;;
*win*)
# linker flag to suppress console when linking a GUI app on Win32
QT_GUILINK="/subsystem:windows"
if test $QT_MAJOR = "3" ; then
if test $QT_IS_MT = yes ; then
QT_LIBS="/nodefaultlib:libcmt"
else
QT_LIBS="/nodefaultlib:libc"
fi
fi
if test $QT_IS_STATIC = yes ; then
QT_LIBS="$QT_LIBS $QT_LIB kernel32.lib user32.lib gdi32.lib comdlg32.lib ole32.lib shell32.lib imm32.lib advapi32.lib wsock32.lib winspool.lib winmm.lib netapi32.lib"
if test $QT_MAJOR = "3" ; then
QT_LIBS="$QT_LIBS qtmain.lib"
fi
else
QT_LIBS="$QT_LIBS $QT_LIB"
if test $QT_MAJOR = "3" ; then
QT_CXXFLAGS="$QT_CXXFLAGS -DQT_DLL"
QT_LIBS="$QT_LIBS qtmain.lib qui.lib user32.lib netapi32.lib"
fi
fi
QASSISTANTCLIENT_LDADD="qassistantclient.lib"
;;
esac
if test x"$QT_IS_EMBEDDED" = "xyes" ; then
QT_CXXFLAGS="-DQWS $QT_CXXFLAGS"
fi
if test x"$QT_IS_MT" = "xyes" ; then
QT_CXXFLAGS="$QT_CXXFLAGS -D_REENTRANT -DQT_THREAD_SUPPORT"
fi
QT_LDADD="-L$QTDIR/${_lib} $QT_LIBS"
if test x$QT_IS_STATIC = xyes ; then
OLDLIBS="$LIBS"
LIBS="$QT_LDADD"
AC_CHECK_LIB(Xft, XftFontOpen, QT_LDADD="$QT_LDADD -lXft")
LIBS="$LIBS"
fi
AC_MSG_CHECKING([QT_CXXFLAGS])
AC_MSG_RESULT([$QT_CXXFLAGS])
AC_MSG_CHECKING([QT_LDADD])
AC_MSG_RESULT([$QT_LDADD])
AC_SUBST(QT_CXXFLAGS)
AC_SUBST(QT_LDADD)
AC_SUBST(QT_GUILINK)
AC_SUBST(QASSISTANTCLIENT_LDADD)
AC_SUBST(QTDIR)
])
# Configure path for the GNU Scientific Library
# Christopher R. Gabriel <cgabriel@linux.it>, April 2000
AC_DEFUN([AM_PATH_GSL],
[
AC_ARG_WITH(gsl-prefix,[ --with-gsl-prefix=PFX Prefix where GSL is installed (optional)],
gsl_prefix="$withval", gsl_prefix="")
AC_ARG_WITH(gsl-exec-prefix,[ --with-gsl-exec-prefix=PFX Exec prefix where GSL is installed (optional)],
gsl_exec_prefix="$withval", gsl_exec_prefix="")
AC_ARG_ENABLE(gsltest, [ --disable-gsltest Do not try to compile and run a test GSL program],
, enable_gsltest=yes)
if test "x${GSL_CONFIG+set}" != xset ; then
if test "x$gsl_prefix" != x ; then
GSL_CONFIG="$gsl_prefix/bin/gsl-config"
fi
if test "x$gsl_exec_prefix" != x ; then
GSL_CONFIG="$gsl_exec_prefix/bin/gsl-config"
fi
fi
AC_PATH_PROG(GSL_CONFIG, gsl-config, no)
min_gsl_version=ifelse([$1], ,0.2.5,$1)
AC_MSG_CHECKING(for GSL - version >= $min_gsl_version)
no_gsl=""
if test "$GSL_CONFIG" = "no" ; then
no_gsl=yes
else
GSL_CFLAGS=`$GSL_CONFIG --cflags`
GSL_LIBS=`$GSL_CONFIG --libs`
gsl_major_version=`$GSL_CONFIG --version | \
sed 's/^\([[0-9]]*\).*/\1/'`
if test "x${gsl_major_version}" = "x" ; then
gsl_major_version=0
fi
gsl_minor_version=`$GSL_CONFIG --version | \
sed 's/^\([[0-9]]*\)\.\{0,1\}\([[0-9]]*\).*/\2/'`
if test "x${gsl_minor_version}" = "x" ; then
gsl_minor_version=0
fi
gsl_micro_version=`$GSL_CONFIG --version | \
sed 's/^\([[0-9]]*\)\.\{0,1\}\([[0-9]]*\)\.\{0,1\}\([[0-9]]*\).*/\3/'`
if test "x${gsl_micro_version}" = "x" ; then
gsl_micro_version=0
fi
if test "x$enable_gsltest" = "xyes" ; then
ac_save_CFLAGS="$CFLAGS"
ac_save_LIBS="$LIBS"
CFLAGS="$CFLAGS $GSL_CFLAGS"
LIBS="$LIBS $GSL_LIBS"
rm -f conf.gsltest
AC_TRY_RUN([
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* my_strdup (const char *str);
char*
my_strdup (const char *str)
{
char *new_str;
if (str)
{
new_str = (char *)malloc ((strlen (str) + 1) * sizeof(char));
strcpy (new_str, str);
}
else
new_str = NULL;
return new_str;
}
int main (void)
{
int major = 0, minor = 0, micro = 0;
int n;
char *tmp_version;
system ("touch conf.gsltest");
/* HP/UX 9 (%@#!) writes to sscanf strings */
tmp_version = my_strdup("$min_gsl_version");
n = sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) ;
if (n != 2 && n != 3) {
printf("%s, bad version string\n", "$min_gsl_version");
exit(1);
}
if (($gsl_major_version > major) ||
(($gsl_major_version == major) && ($gsl_minor_version > minor)) ||
(($gsl_major_version == major) && ($gsl_minor_version == minor) && ($gsl_micro_version >= micro)))
{
exit(0);
}
else
{
printf("\n*** 'gsl-config --version' returned %d.%d.%d, but the minimum version\n", $gsl_major_version, $gsl_minor_version, $gsl_micro_version);
printf("*** of GSL required is %d.%d.%d. If gsl-config is correct, then it is\n", major, minor, micro);
printf("*** best to upgrade to the required version.\n");
printf("*** If gsl-config was wrong, set the environment variable GSL_CONFIG\n");
printf("*** to point to the correct copy of gsl-config, and remove the file\n");
printf("*** config.cache before re-running configure\n");
exit(1);
}
}
],, no_gsl=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
CFLAGS="$ac_save_CFLAGS"
LIBS="$ac_save_LIBS"
fi
fi
if test "x$no_gsl" = x ; then
AC_MSG_RESULT(yes)
ifelse([$2], , :, [$2])
else
AC_MSG_RESULT(no)
if test "$GSL_CONFIG" = "no" ; then
echo "*** The gsl-config script installed by GSL could not be found"
echo "*** If GSL was installed in PREFIX, make sure PREFIX/bin is in"
echo "*** your path, or set the GSL_CONFIG environment variable to the"
echo "*** full path to gsl-config."
else
if test -f conf.gsltest ; then
:
else
echo "*** Could not run GSL test program, checking why..."
CFLAGS="$CFLAGS $GSL_CFLAGS"
LIBS="$LIBS $GSL_LIBS"
AC_TRY_LINK([
#include <stdio.h>
], [ return 0; ],
[ echo "*** The test program compiled, but did not run. This usually means"
echo "*** that the run-time linker is not finding GSL or finding the wrong"
echo "*** version of GSL. If it is not finding GSL, you'll need to set your"
echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
echo "*** to the installed location Also, make sure you have run ldconfig if that"
echo "*** is required on your system"
echo "***"
echo "*** If you have an old version installed, it is best to remove it, although"
echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
[ echo "*** The test program failed to compile or link. See the file config.log for the"
echo "*** exact error that occured. This usually means GSL was incorrectly installed"
echo "*** or that you have moved GSL since it was installed. In the latter case, you"
echo "*** may want to edit the gsl-config script: $GSL_CONFIG" ])
CFLAGS="$ac_save_CFLAGS"
LIBS="$ac_save_LIBS"
fi
fi
# GSL_CFLAGS=""
# GSL_LIBS=""
ifelse([$3], , :, [$3])
fi
AC_SUBST(GSL_CFLAGS)
AC_SUBST(GSL_LIBS)
rm -f conf.gsltest
])
dnl Python
dnl Available from the GNU Autoconf Macro Archive at:
dnl http://www.gnu.org/software/ac-archive/htmldoc/ax_python.html
dnl
AC_DEFUN([AX_PYTHON],
[
AC_ARG_WITH([python],
AC_HELP_STRING([--with-python],
[Include Python scripting support ]))
if test x"$with_python" = "x"; then
AC_MSG_RESULT( Not using python )
ac_use_python=no
else
AC_MSG_CHECKING(for python build information)
for python in python2.4 python2.3 python2.2 python2.1 python; do
AC_CHECK_PROGS(PYTHON_BIN, [$python])
ax_python_bin=$PYTHON_BIN
if test x$ax_python_bin != x; then
AC_CHECK_LIB($ax_python_bin, main, ax_python_lib=$ax_python_bin, ax_python_lib=no)
AC_CHECK_HEADER([$ax_python_bin/Python.h],
[[ax_python_header=`locate $ax_python_bin/Python.h | sed -e s,/Python.h,,`]],
ax_python_header=no)
if test $ax_python_lib != no; then
if test $ax_python_header != no; then
break;
fi
fi
fi
done
if test x$ax_python_bin = x; then
ax_python_bin=no
fi
if test x$ax_python_header = x; then
ax_python_header=no
fi
if test x$ax_python_lib = x; then
ax_python_lib=no
fi
AC_MSG_RESULT([ results of the Python check:])
AC_MSG_RESULT([ Binary: $ax_python_bin])
AC_MSG_RESULT([ Library: $ax_python_lib])
AC_MSG_RESULT([ Include Dir: $ax_python_header])
AC_MSG_RESULT([ Have python: $ac_use_python])
if test x$ax_python_header != xno; then
PYTHON_INCLUDE_DIR=-I$ax_python_header
AC_SUBST(PYTHON_INCLUDE_DIR)
fi
if test x$ax_python_lib != xno; then
PYTHON_LIB=-l$ax_python_lib
AC_SUBST(PYTHON_LIB)
fi
if test x$ax_python_header != xno; then
dnl & x$ax_python_lib != xno; then
ac_use_python=yes
HAVE_PYTHON=-DHAVE_PYTHON
fi
fi
AM_CONDITIONAL([USE_PYTHON], [test "$ac_use_python" = "yes"])
])
dnl

View File

@ -1,110 +0,0 @@
#!/bin/sh
# Automakeversion
AM_1=1
AM_2=7
AM_3=2
# Autoconfversion
AC_1=2
AC_2=57
# Libtoolversion
LT_1=1
LT_2=4
# Libtoolname
LIBTOOL=libtool
LIBTOOLIZE=libtoolize
if [ "`uname`" = "Darwin" ]; then
LIBTOOL=glibtool
LIBTOOLIZE=glibtoolize
fi
# Check automake version
AM_VERSION=`automake --version | sed -n -e 's#[^0-9]* \([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*$#\1 \2 \3#p'`
AM_V1=`echo $AM_VERSION | awk '{print $1}'`
AM_V2=`echo $AM_VERSION | awk '{print $2}'`
AM_V3=`echo $AM_VERSION | awk '{print $3}'`
if [ $AM_1 -gt $AM_V1 ]; then
AM_ERROR=1
else
if [ $AM_1 -eq $AM_V1 ]; then
if [ $AM_2 -gt $AM_V2 ]; then
AM_ERROR=1
else
if [ $AM_2 -eq $AM_V2 ]; then
if [ $AM_3 -gt $AM_V3 ]; then
AM_ERROR=1
fi
fi
fi
fi
fi
if [ "$AM_ERROR" = "1" ]; then
echo -e '\E[31;m'
echo -n "Your automake version `automake --version | sed -n -e 's#[^0-9]* \([0-9]*\.[0-9]*\.[0-9]*\).*#\1#p'`"
echo " is older than the suggested one, $AM_1.$AM_2.$AM_3"
echo "Go on at your own risk. :-)"
echo
tput sgr0
fi
# Check autoconf version
AC_VERSION=`autoconf --version | sed -n -e 's#[^0-9]* \([0-9]*\)\.\([0-9]*\).*$#\1 \2#p'`
AC_V1=`echo $AC_VERSION | awk '{print $1}'`
AC_V2=`echo $AC_VERSION | awk '{print $2}'`
if [ $AC_1 -gt $AC_V1 ]; then
AC_ERROR=1
else
if [ $AC_1 -eq $AC_V1 ]; then
if [ $AC_2 -gt $AC_V2 ]; then
AC_ERROR=1
fi
fi
fi
if [ "$AC_ERROR" = "1" ]; then
echo -e '\E[31;m'
echo -n "Your autoconf version `autoconf --version | sed -n -e 's#[^0-9]* \([0-9]*\.[0-9]*\).*#\1#p'`"
echo " is older than the suggested one, $AC_1.$AC_2"
echo "Go on at your own risk. :-)"
echo
tput sgr0
fi
# Check libtool version
LT_VERSION=`$LIBTOOL --version | sed -n -e 's#[^0-9]* \([0-9]*\)\.\([0-9]*\).*$#\1 \2#p'`
LT_V1=`echo $LT_VERSION | awk '{print $1}'`
LT_V2=`echo $LT_VERSION | awk '{print $2}'`
if [ $LT_1 -gt $LT_V1 ]; then
LT_ERROR=1
else
if [ $LT_1 -eq $LT_V1 ]; then
if [ $LT_2 -gt $LT_V2 ]; then
LT_ERROR=1
fi
fi
fi
if [ "$LT_ERROR" = "1" ]; then
echo -e '\E[31;m'
echo -n "Your libtool version `$LIBTOOL --version | sed -n -e 's#[^0-9]* \([0-9]*\.[0-9]*\).*#\1#p'`"
echo " is older than the suggested one, $LT_1.$LT_2"
echo "Go on at your own risk. :-)"
echo
tput sgr0
fi
echo Configuring build environment for QGIS
aclocal \
&& $LIBTOOLIZE --force --copy \
&& autoheader --force -W all \
&& automake --add-missing --foreign --copy \
&& autoconf --force \
&& echo Now running configure to configure QGIS \
&& ./configure $@

View File

@ -1,3 +0,0 @@
output.*
requests
traces.*

64
cmake/Bundle.cmake Normal file
View File

@ -0,0 +1,64 @@
set(CPACK_GENERATOR)
set(CPACK_OUTPUT_CONFIG_FILE "${CMAKE_BINARY_DIR}/BundleConfig.cmake")
add_custom_target(bundle
COMMAND ${CMAKE_CPACK_COMMAND} "--config" "${CMAKE_BINARY_DIR}/BundleConfig.cmake" "--verbose"
COMMENT "Running CPACK. Please wait..."
DEPENDS qgis)
if(WIN32 AND NOT UNIX)
set (CREATE_NSIS FALSE CACHE BOOL "Create an installer using NSIS")
endif()
set (CREATE_ZIP FALSE CACHE BOOL "Create a ZIP package")
# Do not warn about runtime libs when building using VS Express
if(NOT DEFINED CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS)
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS ON)
endif()
if(QGIS_INSTALL_SYS_LIBS)
include(InstallRequiredSystemLibraries)
endif()
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "QGIS")
set(CPACK_PACKAGE_VENDOR "Open Source Geospatial Foundation")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "QGIS ${COMPLETE_VERSION}")
set(CPACK_PACKAGE_EXECUTABLES "qgis" "QGIS")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md")
if(CREATE_NSIS)
# There is a bug in NSI that does not handle full unix paths properly. Make
# sure there is at least one set of four (4) backslashes.
set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/win_build\\\\sidebar.bmp")
set(CPACK_NSIS_INSTALLED_ICON_NAME "\\\\qgis.exe")
set(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} QGIS")
set(CPACK_NSIS_HELP_LINK "http:\\\\\\\\qgis.org")
set(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\qgis.org")
set(CPACK_NSIS_CONTACT "info@qgis.org")
set(CPACK_NSIS_MODIFY_PATH ON)
endif()
if(CREATE_ZIP)
list(APPEND CPACK_GENERATOR "ZIP")
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND QGIS_MAC_BUNDLE)
set(CREATE_DMG FALSE CACHE BOOL "Create a dmg bundle")
set(PYMACDEPLOYQT_EXECUTABLE "${CMAKE_SOURCE_DIR}/platform/macos/pymacdeployqt.py")
configure_file("${CMAKE_SOURCE_DIR}/platform/macos/Info.plist.in" "${CMAKE_BINARY_DIR}/platform//macos/Info.plist" @ONLY)
install(FILES "${CMAKE_BINARY_DIR}/platform/macos/Info.plist" DESTINATION "${APP_CONTENTS_DIR}")
set(CPACK_DMG_VOLUME_NAME "${PROJECT_NAME}")
set(CPACK_DMG_FORMAT "UDBZ")
list(APPEND CPACK_GENERATOR "External")
message(STATUS " + macdeployqt/DMG YES ")
configure_file(${CMAKE_SOURCE_DIR}/platform/macos/CPackMacDeployQt.cmake.in "${CMAKE_BINARY_DIR}/CPackExternal.cmake" @ONLY)
set(CPACK_EXTERNAL_PACKAGE_SCRIPT "${CMAKE_BINARY_DIR}/CPackExternal.cmake")
set(CPACK_EXTERNAL_ENABLE_STAGING ON)
set(CPACK_PACKAGING_INSTALL_PREFIX "/${QGIS_APP_NAME}.app")
endif()
include(CPack)

View File

@ -0,0 +1,42 @@
# Macros/functions for debugging CMake
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Copyright (c) 2016, Larry Shaffer, <lshaffer (at) boundlessgeo (dot) com>>
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
# Dump current CMake variables to file
#
# Usage:
# INCLUDE(CMakeDebugMacros)
# DUMP_CMAKE_VARS() or DUMP_CMAKE_VARS("regex")
#
# regex: optional ARGV0 regular expression for filtering output variable names
#
# Outputs the result relative to the current CMake file being processed and
# writes to a file with name "<file-basename>_cmake-vars.txt" to the current
# build (binary) directory
#
function(DUMP_CMAKE_VARS)
get_filename_component(_basename ${CMAKE_CURRENT_LIST_FILE} NAME_WE)
set(_out "${CMAKE_CURRENT_BINARY_DIR}/${_basename}_cmake-vars.txt")
set(_cmake_vars "")
get_cmake_property(_varNames VARIABLES)
foreach(_varName ${_varNames})
if(ARGV0)
string(REGEX MATCH "${ARGV0}" _match "${_varName}")
if(_match)
set(_cmake_vars "${_cmake_vars}\n\n${_varName}=${${_varName}}")
endif()
else()
set(_cmake_vars "${_cmake_vars}\n\n${_varName}=${${_varName}}")
endif()
endforeach()
message(STATUS "Dumping current CMake variables to ...\n ${_out}")
file(WRITE "${_out}" "${_cmake_vars}")
endfunction(DUMP_CMAKE_VARS)

View File

@ -0,0 +1,22 @@
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,4 @@
EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E compare_files ${SRC} ${DST} RESULT_VARIABLE result)
IF(result)
EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E copy ${SRC} ${DST})
ENDIF(result)

Some files were not shown because too many files have changed in this diff Show More