Repository: rdiff-backup/rdiff-backup (language: python)

Issue:
[BUG] pyproject.toml license field should be GPL-2.0-or-later
## Bug summary

The current value for license field in pyproject.toml is "GPLv2+", but this should now be using the SPDX notation so should be "GPL-2.0-or-later".

## Version, Python, Operating System

Current github version, 2.4.1+

## rdiff-backup call

N/A

## What happened and what did you expect?

It is currently the old standard value ("GPLv2+"), but should be replaced with the new SPDX value ("GPL-2.0-or-later").

## More information

Obviously not an urgent matter, and can be addressed during some routine maintenance.



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 2fa7df8fa..a0e560803 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -54,14 +54,14 @@ jobs:
     - uses: actions/checkout@v3
       with:
         fetch-depth: 0  # to have the correct version
-    - name: Install asciidoctor to generate manpages
+    - name: Install asciidoctor to generate manpages and other dependencies
       run: |
         sudo apt-get --assume-yes update
         sudo apt-get --assume-yes install asciidoctor
     - name: create source dist package
       run: |
-        pip install --upgrade setuptools setuptools-scm  # workaround for old versions
-        python setup.py sdist
+        pip install build  # package python3-build is too old
+        pyproject-build --sdist
     - name: Upload sdist artifact
       uses: actions/upload-artifact@v3
       with:
diff --git a/.github/workflows/weekly.yml b/.github/workflows/weekly.yml
index 93f4b3bac..dc8759577 100644
--- a/.github/workflows/weekly.yml
+++ b/.github/workflows/weekly.yml
@@ -49,14 +49,14 @@ jobs:
     - uses: actions/checkout@v3
       with:
         fetch-depth: 0  # to have the correct version
-    - name: Install asciidoctor to generate manpages
+    - name: Install asciidoctor to generate manpages and other dependencies
       run: |
         sudo apt-get --assume-yes update
         sudo apt-get --assume-yes install asciidoctor
     - name: create source dist package
       run: |
-        pip install --upgrade setuptools setuptools-scm  # workaround for old versions
-        python setup.py sdist
+        pip install build  # package python3-build is too old
+        pyproject-build --sdist
     - name: Upload sdist artifact
       uses: actions/upload-artifact@v3
       with:
diff --git a/Makefile b/Makefile
index 83a36f260..ad42c7427 100644
--- a/Makefile
+++ b/Makefile
@@ -37,20 +37,9 @@ test-runtime-slow: test-runtime-files
 test-misc: clean build test-static test-runtime-slow
 
 build:
-	# Build rdiff-backup (assumes src/ is in directory 'rdiff-backup' and it's
-	# parent is writeable)
-	${RUN_COMMAND} ./setup.py build
-
-bdist_wheel:
-	# Prepare wheel for deployment.
-	# See the notes for target "build"
-	# auditwheel unfortunately does not work with modern glibc
-	${RUN_COMMAND} ./setup.py bdist_wheel
-	# ${RUN_COMMAND} auditwheel repair dist/*.whl
-
-sdist:
-	# Prepare wheel for deployment.
-	${RUN_COMMAND} ./setup.py sdist
+	# Build rdiff-backup (assumes src/ is in directory 'rdiff-backup' and
+	# its parent is writeable)
+	${RUN_COMMAND} pyproject-build
 
 dist_deb:
 	${RUN_COMMAND} debian/autobuild.sh
diff --git a/README.adoc b/README.adoc
index f522c2571..2fb056741 100644
--- a/README.adoc
+++ b/README.adoc
@@ -96,7 +96,7 @@ ARM/MIPS/etc, you may need the build dependencies `build-essentials`, `librsync-
 sudo yum install centos-release-scl
 sudo yum install rh-python36 gcc libacl-devel
 scl enable rh-python36 bash
-sudo pip install rdiff-backup pyxattr pylibacl
+sudo pip install rdiff-backup pyxattr pylibacl  # or rdiff-backup[meta]
 echo 'exec scl enable rh-python36 -- rdiff-backup "$@"' | sudo tee /usr/bin/rdiff-backup
 sudo chmod +x /usr/bin/rdiff-backup
 ----
@@ -110,24 +110,24 @@ sudo pip3 install rdiff-backup
 
 === Other Linux and UN*X-oid systems, e.g. BSD (from PyPi)
 
-You need to make sure that the following requirements are met:
+You need to make sure that the following requirements are met, using your system's package/software/application manager, searching there for the following keywords:
 
-* Python 3.9 or higher
-* pip3 e.g. installed with `+curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py; sudo python3 get-pip.py+`.
-* librsync 2.0.0 or higher (also named librsync2)
-* pylibacl (optional, to support ACLs)
-* pyxattr (optional, to support extended attributes) - the xattr library (without py) isn't regularly tested but should work and you will be helped
-* psutil as an optional dependency (else rdiff-backup uses `ps`/`tasklist`)
-* SSH for remote operations
+* __Python__, 3.9 or higher
+* Python __pip__ or __pip3__, e.g. with `python -m ensurepip --upgrade`
+* __librsync__ or __librsync2__, 2.0.0 or higher
+* __libacl__ or __libacl1__ or simply __acl__ (optional, to support ACLs)
+* SSH, generally __OpenSSH__, client and/or server (optional, for remote operations)
 
-Then you should only need to call the following before you can use rdiff-backup:
+Then you should only need to call one of the following before you can use rdiff-backup:
 
+[source,shell]
 ----
-sudo pip3 install rdiff-backup
+sudo pip3 install rdiff-backup        # without optional dependencies
+sudo pip3 install rdiff-backup[meta]  # with support for metadata, ACLs and EAs
 ----
 
-NOTE: especially if your platform is not i386 or amd64, e.g.
-ARM/MIPS/PowerPC/etc, but also if the pip3 installation fails with `+include [...].h+` files missing, you may need the build dependencies named like `python3-devel` or `librsync-dev`.
+NOTE: especially if your platform is _not_ i386 or amd64, e.g.
+ARM/MIPS/PowerPC/etc, but also if the pip3 installation fails with `#include [...].h` files missing, you may need the build dependencies named like `python3-devel`, `librsync-dev` or `libacl1-dev`.
 
 === Windows
 
diff --git a/bindep.txt b/bindep.txt
index 3559ebcea..547a534bf 100644
--- a/bindep.txt
+++ b/bindep.txt
@@ -35,6 +35,8 @@ python-pyxattr [platform:pacman usage]
 
 python3-devel [platform:redhat devel]
 python3-dev [platform:dpkg devel]
+python-build [platform:pacman devel]
+python3-build [!platform:pacman devel]
 python-devtools [platform:pacman devel]
 python3-wheel [!platform:pacman devel]
 python-wheel [platform:pacman devel]
diff --git a/debian/autobuild.sh b/debian/autobuild.sh
index 5f850c2a9..490ebfcdc 100755
--- a/debian/autobuild.sh
+++ b/debian/autobuild.sh
@@ -4,7 +4,7 @@ set -e
 
 # Automatically update changelog with new version number as the deb package
 # version will be what the latest entry in debian/changelog states
-VERSION="$(./setup.py --version)"
+VERSION="$(./tools/get_project_metadata.py Version)"
 # e.g. VERSION=2.2.3.dev5+gf11a1d0.d20230116
 dch -b -v "${VERSION}" "Automatic build"
 
diff --git a/docs/DEVELOP.adoc b/docs/DEVELOP.adoc
index 756667885..d3ac47933 100644
--- a/docs/DEVELOP.adoc
+++ b/docs/DEVELOP.adoc
@@ -16,7 +16,10 @@ NOTE: Suggest https://github.com/rdiff-backup/rdiff-backup/issues/new?title=Docs
 
 Simply clone the source with:
 
- git clone https://github.com/rdiff-backup/rdiff-backup.git
+[source,shell]
+----
+git clone https://github.com/rdiff-backup/rdiff-backup.git
+----
 
 NOTE: If you plan to provide your own code, you should first fork our repo and clone your own forked repo (probably using ssh not https).
 How is described at https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/working-with-forks
@@ -180,33 +183,29 @@ By default the `Makefile` runs all of it's command in a clean Docker container,
 
 The CI pipeline also uses the `Makefile`, so if all commands in the `Makefile` succeed locally, the CI is most likely to pass as well.
 
-=== Build and install with setup.py
+=== Build and install
 
 To install, simply run:
 
- pip install .
+[source,shell]
+----
+pip install .
+----
 
 TIP: if pip isn't present on your system, or too old, you can install or upgrade it with `python -m ensurepip --upgrade`
 
-The build process can be also be run separately:
+The build process can be also be run separately using `pyproject-build`.
 
- python3 setup.py build
-
-The setup script expects to find librsync headers and libraries in the default location, usually /usr/include and /usr/lib.
-If you want the setup script to check different locations, use the --librsync-dir switch or the LIBRSYNC_DIR environment variable.
+The `setup.py` script expects to find librsync headers and libraries in the default location, usually `/usr/include` and `/usr/lib`.
+If you want the setup script to check different locations, use the `LIBRSYNC_DIR` environment variable.
 For instance to instruct the setup program to look in `/usr/local/include` and `/usr/local/lib` for the librsync files run:
 
- python3 setup.py --librsync-dir=/usr/local build
-
-Finally, the `--lflags` and `--libs` options, and the `LFLAGS` and `LIBS` environment variables are also recognized.
-Running setup.py with no arguments will display some help.
-Additional help is displayed by the command:
-
- python3 setup.py install --help
-
-More information about using setup.py and how rdiff-backup is installed is available from the Python guide, Installing Python Modules for System Administrators, located at https://docs.python.org/3/install/index.html
+[source,shell]
+----
+LIBRSYNC_DIR=/usr/local pyproject-build
+----
 
-NOTE: if you plan to use `./setup.py bdist_rpm` to create an RPM, you would need rpm-build but be aware that it will currently fail due to a https://github.com/pypa/setuptools/issues/1277[known bug in setuptools with compressed man pages].
+Finally, the `LFLAGS` and `LIBS` environment variables are also recognized.
 
 To build from source on Windows, check the link:../tools/windows[Windows tools] to build a single executable file which contains Python, librsync, and all required modules.
 
@@ -270,7 +269,7 @@ For more details on testing, see the `test` sections in the link:../Makefile[Mak
 === Trace back a coredump
 
 At the time of writing these notes, there was an issue where calling the program generates a `Segmentation fault (core dumped)`.
-This chapter is based on this experience debugging under Fedora 29.
+This chapter is based on this experience debugging under Fedora 29 (then partially tested again under Fedora 39).
 
 References:
 
@@ -279,46 +278,49 @@ References:
 * Debugging dynamically loaded extensions: https://www.oreilly.com/library/view/python-cookbook/0596001673/ch16s08.html
 * Debugging Memory Problems: https://www.oreilly.com/library/view/python-cookbook/0596001673/ch16s09.html
 
-NOTE: This assumes gdb was already installed.
-
 . First install:
++
+[source,shell]
+----
+sudo dnf install python3-debug gdb
+sudo dnf debuginfo-install --exclude "*.i686" \  #<1>
+	python3-debug bzip2-libs glibc librsync libxcrypt openssl-libs \
+	popt sssd-client xz-libs zlib
+----
+<1>The exclude pattern was necessary to avoid installing 32 bits library
 
-  sudo dnf install python3-debug
-  sudo dnf debuginfo-install python3-debug-3.7.3-1.fc29.x86_64
-  sudo dnf debuginfo-install bzip2-libs-1.0.6-28.fc29.x86_64 glibc-2.28-27.fc29.x86_64 \
-      librsync-1.0.0-8.fc29.x86_64 libxcrypt-4.4.4-2.fc29.x86_64 \
-      openssl-libs-1.1.1b-3.fc29.x86_64 popt-1.16-15.fc29.x86_64 \
-      sssd-client-2.1.0-2.fc29.x86_64 xz-libs-5.2.4-3.fc29.x86_64 zlib-1.2.11-14.fc29.x86_64
-
+. Create a virtualenv with `python3-debug`, and activate it
 . Then run:
 
-  python3 ./setup.py clean --all
-  python3-debug ./setup.py clean --all
-  CFLAGS='-Wall -O0 -g' python3-debug ./setup.py build
-  PATH=$PWD/build/scripts-3.7:$PATH PYTHONPATH=$PWD/build/lib.linux-x86_64-3.7-pydebug/ python -m rdiffbackup.run -v 10 \
-      /some/dir1 /some/dir2
-  [...]
-  Segmentation fault (core dumped)
+[source,console]
+----
+$ CFLAGS='-Wall -O0 -g' pip install .
+$ python3-debug -m rdiffbackup.run -v 10 backup /some/dir1 /some/dir2
+[...]
+Segmentation fault (core dumped)
+----
 
 NOTE: The CFLAGS avoids optimizations making debugging too complicated
 
-At this stage `coredumpctl list` shows that coredump is the last one, so that one can call `coredumpctl gdb`, which itself tells (in multiple steps) that we missing some more debug information, hence the above `debuginfo-install` statements (assuming guess you could install the packages without version information if you're sure they fit the installed package versions).
+At this stage `coredumpctl list` shows that coredump is the last one, so that one can call `coredumpctl gdb`, which itself tells (in multiple steps) that we missing some more debug information, hence the above `debuginfo-install` statements.
 
 So now back into `coredumpctl gdb`, with some commands:
 
- help
- help stack
- backtrace
- bt full
- py-bt
- frame <FrameNumber>
- p <SomeVar>
-
-. get a backtrace of all function calls leading to the coredump (also `bt`)
-. backtrace with local vars
-. py-bt is the Python version of backtrace
-. jump between frames as listed by bt using their `#FrameNumber`
-. print some variable/expression in the context of the selected frame
+[source]
+----
+help
+help stack
+backtrace  #<1>
+bt full  #<2>
+py-bt  #<3>
+frame <FrameNumber>  #<4>
+p __SomeVar__  #<5>
+----
+<1>get a backtrace of all function calls leading to the coredump (also `bt`)
+<2>backtrace with local vars
+<3>py-bt is the Python version of backtrace
+<4>jump between frames as listed by bt using their `#FrameNumber`
+<5>print some variable/expression in the context of the selected frame
 
 Jumping between frames and printing the different variables, we can recognize that:
 
@@ -330,9 +332,16 @@ I can't directly influence and it has been created via the `rs_patch_begin` func
 
 At this stage, it seems that the core file has given most of its secrets and we need to debug the live program:
 
- $ PYTHONTRACEMALLOC=1 PATH=$PWD/build/scripts-3.7:$PATH PYTHONPATH=$PWD/build/lib.linux-x86_64-3.7-pydebug/ gdb python3-debug
- (gdb) break rdiff_backup/_librsyncmodule.c:_librsync_new_patchmaker
- (gdb) run build/scripts-3.7/rdiff-backup /some/source/dir /some/target/dir
+[source,console]
+----
+$ PYTHONTRACEMALLOC=1 gdb -args python3-debug -m rdiffbackup.run backup \
+	/some/source/dir /some/target/dir
+(gdb) break rdiff_backup/_librsyncmodule.c:_librsync_new_patchmaker
+(gdb) run
+----
+
+TIP: if you are not sure about the correct break statement, run once the program without it.
+Then the module will have been loaded, and autocompletion on the `break` command (with twice <TAB>) can help you find the right file and place.
 
 The debugger runs until the breakpoint is reached, after which a succession of `next` and `print <SomeVar>` allows me to analyze the code step by step, and to come to the conclusion that `+cfile = fdopen(python_fd, ...+` is somehow wrong as it creates a null file pointer whereas `python_fd` looks like a valid file descriptor (an integer equal to 5).
 
@@ -340,9 +349,10 @@ The debugger runs until the breakpoint is reached, after which a succession of `
 
 If you get something looking like a `ResourceWarning: Enable tracemalloc to get the object allocation traceback`
 
- PYTHONTRACEMALLOC=1 PATH=$PWD/build/scripts-3.7:$PATH \
- PYTHONPATH=$PWD/build/lib.linux-x86_64-3.7-pydebug/ \
- 	rdiff-backup -v 10 /tmp/äłtèr /var/tmp/rdiff
+[source,shell]
+----
+PYTHONTRACEMALLOC=1 rdiff-backup -v 10 backup /tmp/äłtèr /var/tmp/rdiff
+----
 
 This tells you indeed where the file was opened: `Object allocated at (most recent call last)` but it still requires deeper analysis to understand the reason.
 
@@ -353,9 +363,12 @@ NOTE: See https://docs.python.org/3/library/tracemalloc.html for more informatio
 In order to make sure the debug messages are properly sorted, you need to have the verbosity level 9 set-up, mix stdout and stderr, and then use the date/time output to properly sort the lines coming both from server and client, while making sure that lines belonging together stay together.
 The result command line might look as follows:
 
- rdiff-backup -v9 localhost::/sourcedir /backupdir 2>&1 | awk \
- 	'/^2019-09-16/ { if (line) print line; line = $0 } ! /^2019-09-16/ { line = line " ## " $0 }' \
- 	| sort | sed 's/ ## /\n/g'
+[source,shell]
+----
+rdiff-backup -v9 localhost::/sourcedir /backupdir 2>&1 | awk \
+	'/^2019-09-16/ { if (line) print line; line = $0 } ! /^2019-09-16/ { line = line " ## " $0 }' \
+	| sort | sed 's/ ## /\n/g'
+----
 
 Since version 2.1+, you can use the server's `--debug` option to debug remotely the server process.
 Make sure first that you've installed rpdb (remote pdb) and netcat (also called nc or ncat).
@@ -363,23 +376,22 @@ Make sure first that you've installed rpdb (remote pdb) and netcat (also called
 If you make sure that you run the latest code version, and set all the environment variables correctly, you can then connect remotely to the spawned server process:
 
 ----
-./setup.py build
-PATH=$PWD/build/scripts-3.9:$PATH PYTHONPATH=$PWD/build/lib.linux-x86_64-3.9 \
-	python -m pdb -m rdiffbackup.run --remote-schema \
-		"ssh -C {h}  # <1>
-		RDIFF_BACKUP_DEBUG=0.0.0.0:4445  # <2>
-		PATH=$PWD/build/scripts-3.9:$PATH
-		PYTHONPATH=$PWD/build/lib.linux-x86_64-3.9
-		rdiff-backup server --debug" \  # <3>
-	backup source_dir localhost::/target_dir
+source .../rdb/bin/activate  # <1>
+pip install .
+python -m pdb -m rdiffbackup.run --remote-schema \
+	"ssh -C {h}
+	RDIFF_BACKUP_DEBUG=0.0.0.0:4445  # <2>
+	.../rdb/bin/rdiff-backup server --debug" \  # <3>
+backup source_dir localhost::/target_dir
 pdb is running on 0.0.0.0:4445  # <4>
 ----
-<1> the double quotes are important to make sure that the PATH variable is resolved locally
+<1> see above how to create a virtualenv fit for rdiff-backup
 <2> this variable is optional and only required if you want another address/port
 <3> note the `--debug` option necessary to set a breakpoint early in the process
 <4> here the address:port where the debug process is listening, the default is 127.0.0.1:4444
 
-Once you've done this, in another terminal, you can call `ncat localhost 4445` (or 4444 by default) and you'll arrive in the pdb command line. You're one or two `n(ext)` steps away from the pre-check method, so you can start to debug the server process relatively early (not the argument parsing step though).
+Once you've done this, in another terminal, you can call `netcat localhost 4445` (resp. `ncat` or `nc`, and 4444 by default) and you'll arrive on the pdb command line.
+You're one or two `n(ext)` steps away from the pre-check method, so you can start to debug the server process relatively early (not the argument parsing step though).
 
 TIP: rpdb is just a wrapper around pdb so it acts very similarly.
 
@@ -423,12 +435,10 @@ But don't do it because you can but only because you must!
 
 ==== Profiling without code changes
 
-After having called `./setup.py build`, you may call something like the following to profile the current code (adapt to your Python version):
+After having created and activated the usual virtualenv, you may call something like the following to profile the current code (adapt to your Python version):
 
 ----
-PATH=$PWD/build/scripts-3.8:$PATH PYTHONPATH=$PWD/build/lib.linux-x86_64-3.8 \
-	python -m cProfile -s tottime \
-	build/scripts-3.8/rdiff-backup [... rdiff-backup parameters ...]
+python -m cProfile -s tottime -m rdiffbackup.run [... rdiff-backup parameters ...]
 ----
 
 The `-s tottime` option _sorts_ by total time spent in the function.
@@ -440,17 +450,12 @@ at  https://pythonhosted.org//ProfileEye/ ?
 You may also do memory profiling using the https://pypi.org/project/memory-profiler/[memory-profiler], though more detailed information requires changes to the code by adding the `@profile` decorator to functions:
 
 ----
-pip install --user memory-profiler
-PATH=$PWD/build/scripts-3.8:$PATH PYTHONPATH=$PWD/build/lib.linux-x86_64-3.8 \
-	mprof run \
-	build/scripts-3.8/rdiff-backup [... rdiff-backup parameters ...]
-mprof plot
-mprof clean
+pip install memory-profiler matplotlib
+mprof run rdiff-backup [... rdiff-backup parameters ...]
+mprof plot --output mprofile.png
+mprof clean && rm mprofile.png
 ----
 
-NOTE: sometimes calling rdiff-backup this way fails, it's due to the script having a wrong interpreter (because of wheel building).
-Call `./setup.py clean --all && ./setup.py build` to fix it.
-
 TIP: there is also a https://pypi.org/project/line-profiler/[line-profiler], but I didn't try it because it requires changes to the code (again the `@profile` decorator).
 
 ==== More profiling with code changes
diff --git a/docs/_site_README.adoc b/docs/_site_README.adoc
index 71b9febd9..477d76ca3 100644
--- a/docs/_site_README.adoc
+++ b/docs/_site_README.adoc
@@ -28,6 +28,6 @@ Few things could still be addressed in due time:
 
 . https://github.com/asciidoctor/jekyll-asciidoc/#stylesheet-for-code-highlighting[code hightlighting] doesn't seem to work (didn't try yet)
 . https://github.com/asciidoctor/jekyll-asciidoc/#font-based-admonition-and-inline-icons[Font-based Admonition and Inline Icons] don't seem to work (tried, failed).
-. a clearer separation of user and developer documentation might be helpful, also physically in different sub-folders (to be reflected in setup.py for packaging).
+. a clearer separation of user and developer documentation might be helpful, also physically in different sub-folders (to be reflected in pyproject.toml for packaging).
 . a more automated generation of the navigation bar could then possibly be addressed, with an overarching Table of Content accross the whole site.
 . the whole style could use a professional revamp, especially the footer looks uncool to my eyes.
diff --git a/docs/arch/completion.adoc b/docs/arch/completion.adoc
index 626f2ac39..0ce4fcb3d 100644
--- a/docs/arch/completion.adoc
+++ b/docs/arch/completion.adoc
@@ -126,9 +126,7 @@ The options are sorted by ignoring the hyphens, this means that actions and opti
 It should be pretty simple in most cases, if you know how to create a fork and a pull request against rdiff-backup's Git repo:
 
 . add a subdirectory and script to `tools/completions`, e.g. `bash/rdiff-backup` (the script must have its definitive name on the file system, hence the sub-directory)
-. add an entry of the form `("<relative-target-directory>", ["tools/completions/myshell/myscript"]),` in the `data_file` parameter of the `setup.py` script.
-  Take the already existing bash entry `("share/bash-completion/completions", ["tools/completions/bash/rdiff-backup"]),` as sample.
-+
-IMPORTANT: pay attention to the final comma!
+. add an entry of the form `"<relative-target-directory>" = ["tools/completions/myshell/myscript"]` in the `[tool.setuptools.data-files]` section of the `pyproject.toml` file.
+  Take the already existing bash entry `"share/bash-completion/completions" = ["tools/completions/bash/rdiff-backup"]` as sample.
 
 That's it, test (e.g. using `pip install .`), commit and push, a pull request is then just a click or two away.
diff --git a/pyproject.toml b/pyproject.toml
index a86585c4b..6cced7ea2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -13,7 +13,7 @@ requires-python = ">=3.6"
 keywords = [
 	'backup', 'simple', 'easy', 'remote', 'incremental', 'efficient', 'cross-platform'
 ]
-license = {text = "GPLv2+"}
+license = {text = "GPL-2.0-or-later"}
 classifiers = [
 	'Development Status :: 5 - Production/Stable',
 	'Environment :: Console',
diff --git a/requirements.txt b/requirements.txt
index f22b7b3da..2e956b3e9 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -16,15 +16,15 @@
 #--- mandatory ---
 
 # we need specific versions to properly support pyproject.toml and git archives
-setuptools >= 67.0.0
-setuptools-scm >= 7.1.0
 importlib-metadata ; python_version < "3.8"
-PyYAML  # for rdiff-backup >= 2.1
-
 pywin32 ; platform_system=="Windows"
+PyYAML  # for rdiff-backup >= 2.1
 
 #--- building packages ---
 
+setuptools >= 67.0.0
+setuptools-scm >= 7.1.0
+build >= 0.8.0
 twine
 wheel
 #py2exe; platform_system=="Windows"
diff --git a/requs/base.txt b/requs/base.txt
index c26206ad6..a85153093 100644
--- a/requs/base.txt
+++ b/requs/base.txt
@@ -2,9 +2,6 @@
 #--- mandatory ---
 
 # we need specific versions to properly support pyproject.toml and git archives
-setuptools >= 67.0.0
-setuptools-scm >= 7.1.0
 importlib-metadata ; python_version < "3.8"
-PyYAML  # for rdiff-backup >= 2.1
-
 pywin32 ; platform_system=="Windows"
+PyYAML  # for rdiff-backup >= 2.1
diff --git a/requs/build.txt b/requs/build.txt
index f786ae395..7bff3d9dc 100644
--- a/requs/build.txt
+++ b/requs/build.txt
@@ -1,6 +1,9 @@
 
 #--- building packages ---
 
+setuptools >= 67.0.0
+setuptools-scm >= 7.1.0
+build >= 0.8.0
 twine
 wheel
 #py2exe; platform_system=="Windows"
diff --git a/setup.py b/setup.py
index c868cd215..0c095ed1b 100755
--- a/setup.py
+++ b/setup.py
@@ -27,43 +27,30 @@
     LFLAGS = os.environ.get("LFLAGS", [])
     LIBS = os.environ.get("LIBS", [])
 
-    # Handle --librsync-dir=[PATH] and --lflags=[FLAGS]
-    args = sys.argv[:]
-    for arg in args:
-        if arg.startswith("--librsync-dir="):
-            LIBRSYNC_DIR = arg.split("=")[1]
-            sys.argv.remove(arg)
-        elif arg.startswith("--lflags="):
-            LFLAGS = arg.split("=")[1].split()
-            sys.argv.remove(arg)
-        elif arg.startswith("--libs="):
-            LIBS = arg.split("=")[1].split()
-            sys.argv.remove(arg)
-
-        if LFLAGS or LIBS:
-            lflags_arg = LFLAGS + LIBS
-
-        if LIBRSYNC_DIR and len(sys.argv) > 1:
-            incdir_list = [os.path.join(LIBRSYNC_DIR, "include")]
-            libdir_list = [os.path.join(LIBRSYNC_DIR, "lib")]
-            if os.name == "nt":
-                rsyncdll_src = os.path.join(LIBRSYNC_DIR, "bin", "rsync.dll")
-                rsyncdll_dst = os.path.join("src", "rdiff_backup", "rsync.dll")
-                # rather ugly workaround, but it should be good enough
-                if "clean" in sys.argv:
-                    if os.path.exists(rsyncdll_dst) and "--all" in sys.argv:
-                        print(f"removing {rsyncdll_dst}")
-                        if "--dry-run" not in sys.argv:
-                            os.remove(rsyncdll_dst)
-                elif ("--version" not in sys.argv and "-V" not in sys.argv
-                      and "--help" not in sys.argv):
-                    if (not os.path.exists(rsyncdll_dst)
-                            or not filecmp.cmp(rsyncdll_src, rsyncdll_dst)):
-                        print(f"copying {rsyncdll_src} -> {rsyncdll_dst}")
-                        if "--dry-run" not in sys.argv:
-                            shutil.copyfile(rsyncdll_src, rsyncdll_dst)
+    if LFLAGS or LIBS:
+        lflags_arg = LFLAGS + LIBS
         if "-lrsync" in LIBS:
             libname = []
+    if LIBRSYNC_DIR:
+        incdir_list = [os.path.join(LIBRSYNC_DIR, "include")]
+        libdir_list = [os.path.join(LIBRSYNC_DIR, "lib")]
+
+        if os.name == "nt":
+            rsyncdll_src = os.path.join(LIBRSYNC_DIR, "bin", "rsync.dll")
+            rsyncdll_dst = os.path.join("src", "rdiff_backup", "rsync.dll")
+            # rather ugly workaround, but it should be good enough
+            if "clean" in sys.argv:
+                if os.path.exists(rsyncdll_dst) and "--all" in sys.argv:
+                    print(f"removing {rsyncdll_dst}")
+                    if "--dry-run" not in sys.argv:
+                        os.remove(rsyncdll_dst)
+            elif ("--version" not in sys.argv and "-V" not in sys.argv
+                  and "--help" not in sys.argv):
+                if (not os.path.exists(rsyncdll_dst)
+                        or not filecmp.cmp(rsyncdll_src, rsyncdll_dst)):
+                    print(f"copying {rsyncdll_src} -> {rsyncdll_dst}")
+                    if "--dry-run" not in sys.argv:
+                        shutil.copyfile(rsyncdll_src, rsyncdll_dst)
 
 if os.name == "nt":
     # We rely on statically linked librsync
@@ -242,10 +229,6 @@ def run(self):
     # options is a hash of hash with command -> option -> value
     # the value happens here to be a list of file couples/tuples
     options={
-        'pre_build_templates': {'template_files': [
-            ("tools/rdiff-backup.spec.template", "build/rdiff-backup.spec"),
-            ("tools/rdiff-backup.spec.template-fedora", "build/rdiff-backup.fedora.spec"),
-        ]},
         "pre_build_exec": {"commands": [
             ("asciidoctor -b manpage -a revdate=\"{date}\" "
              "-a revnumber=\"{ver}\" -o {outfile} {infile}",
diff --git a/tools/crossversion/README.adoc b/tools/crossversion/README.adoc
index 627b1892c..13cbdc419 100644
--- a/tools/crossversion/README.adoc
+++ b/tools/crossversion/README.adoc
@@ -18,13 +18,5 @@ You may call the smoke tests using the following command and validate that nothi
 ansible-playbook -v playbook-smoke-test.yml
 ----
 
-You can use the current development version by using something like the following, after having built from source using `./setup.py build`:
-
-----
-PATH=../../build/scripts-3.8:$PATH PYTHONPATH=../../build/lib.linux-x86_64-3.8 \
-	ansible-playbook -v playbook-smoke-test.yml
-----
-
-____
-*CAUTION:* the version shown locally might be DEV or any other version 	installed elsewhere locally, but the version used is definitely the 	built development version.
-____
+You can use the current development version by creating and activating a virtualenv and installing the current code into it with `pip install .`.
+Use `pip install .[meta]` (the dot is still there) to install also optional dependencies to manage metadata (ACL, EA...).
diff --git a/tools/get_changelog_since.sh b/tools/get_changelog_since.sh
index 81899e8be..f3082e551 100755
--- a/tools/get_changelog_since.sh
+++ b/tools/get_changelog_since.sh
@@ -45,7 +45,7 @@ fi
 
 echo "(make sure the version is the next correct one)" >&2
 echo
-echo "${H}${H} New in v$($(dirname $0)/../setup.py --version) ($(date -I))"
+echo "${H}${H} New in v$(./tools/get_project_metadata.py Version) ($(date -I))"
 
 echo -e "\n${H}${H}${H} Changes\n"
 git log ${RELTAG}.. |
diff --git a/tools/get_project_metadata.py b/tools/get_project_metadata.py
new file mode 100755
index 000000000..1a64580c9
--- /dev/null
+++ b/tools/get_project_metadata.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# Alternative using the build front-end to `python -m setuptools_scm`
+
+import argparse
+import pathlib
+
+import build.util
+
+
+def get_args():
+    """Parse the command line arguments"""
+    args_parser = argparse.ArgumentParser(
+        description="Output some or all metadata of a given project")
+    args_parser.add_argument('--path', '-p', default='.',
+                             help="Path where to find the project (default: current path)")
+    args_parser.add_argument('keys', nargs='*',
+                             help="Metadata keys to output (else output all metadata)")
+    args = args_parser.parse_args()
+    return args
+
+
+def get_metadata(path='.'):
+    """Get project metadata from the given path"""
+    path = pathlib.Path(path)
+    try:
+        metadata = build.util.project_wheel_metadata(path, isolated=False)
+    except build.BuildBackendException:
+        metadata = build.util.project_wheel_metadata(path, isolated=True)
+    return metadata
+
+
+def main():
+    args = get_args()
+
+    metadata = get_metadata(args.path)
+
+    if args.keys:
+        for key in args.keys:
+            print(metadata[key])
+    else:
+        print(metadata)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tools/misc/setup_dev_archlinux.sh b/tools/misc/setup_dev_archlinux.sh
index f8deb0fc0..d38643b1f 100755
--- a/tools/misc/setup_dev_archlinux.sh
+++ b/tools/misc/setup_dev_archlinux.sh
@@ -3,8 +3,9 @@
 # run it as root, it was developed under the conditions of a container,
 # e.g. created with:
 #     podman run -it docker.io/library/archlinux
-# CAUTION: it is more meant as an example of helpful commands for a developer/tester
-#          not fully knowledgeable of the platform than as a truly and fully tested script.
+# CAUTION: it is more meant as an example of helpful commands for a
+#          developer/tester not fully knowledgeable of the platform than as
+#          a truly and fully tested script.
 
 DEVUSER=devuser
 
@@ -38,8 +39,5 @@ tar xvf ./rdiff-backup-filesrepo/rdiff-backup_testfiles.tar
 #./rdiff-backup-filesrepo/rdiff-backup_testfiles.fix.sh 1234 1234
 
 # after that, as `DEVUSER`, following commands should be possible (for example)
-#  ./setup.py clean --all
-#  ./setup.py build
-#  PATH=$PWD/build/scripts-3.8:$PATH PYTHONPATH=$PWD/build/lib.linux-x86_64-3.8 rdiff-backup --version
-#  PATH=$PWD/build/scripts-3.8:$PATH PYTHONPATH=$PWD/build/lib.linux-x86_64-3.8 python testing/eas_aclstest.py
-
+#  pip install .
+#  rdiff-backup [...]
diff --git a/tools/rdiff-backup.spec.template b/tools/rdiff-backup.spec.template
deleted file mode 100644
index bb9bdbdf4..000000000
--- a/tools/rdiff-backup.spec.template
+++ /dev/null
@@ -1,149 +0,0 @@
-# Note this spec file is overly complex to cover every issue.
-# For modern systems you would be recommended starting from the Fedora version
-
-%define PYTHON_NAME %((rpm -q --quiet python3 && echo python3) || echo python)
-%define PYTHON_VERSION %(%{PYTHON_NAME} -c 'import sys; print(sys.version[:3])')
-%define NEXT_PYTHON_VERSION %(%{PYTHON_NAME} -c 'import sys; print("%d.%d" % (sys.version_info[0], sys.version_info[1]+1))')
-
-# Note this in not necessarily the same at the version, so confirm
-%define gittag {{ version }}
-
-Version: %{gittag}
-Summary: Convenient and transparent local/remote incremental mirror/backup
-Name: rdiff-backup
-Release: 1
-Epoch: 0
-URL: https://rdiff-backup.net/
-Source: https://github.com/%{name}/%{name}/releases/download/v%{gittag}/%{name}-%{version}.tar.gz
-License: GPLv2+
-Group: Applications/Archiving
-BuildRoot:	%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-Requires: %{PYTHON_NAME} >= %{PYTHON_VERSION}, %{PYTHON_NAME} < %{NEXT_PYTHON_VERSION}
-%if %{PYTHON_VERSON} < 3.8
-Requires: %{PYTHON_NAME}-importlib-metadata
-%endif
-Requires: ${PYTHON_NAME}-PyYAML
-
-BuildPrereq: %{PYTHON_NAME}-devel >= 3.6, librsync-devel >= 1.0.0
-BuildPrereq: %{PYTHON_NAME}-setuptools
-BuildPrereq: %{PYTHON_NAME}-setuptools_scm
-BuildPrereq: gcc
-#Required to generate the manpages
-BuildPrereq: rubygem-asciidoctor
-
-%description
-rdiff-backup is a script, written in Python, that backs up one
-directory to another and is intended to be run periodically (nightly
-from cron for instance). The target directory ends up a copy of the
-source directory, but extra reverse diffs are stored in the target
-directory, so you can still recover files lost some time ago. The idea
-is to combine the best features of a mirror and an incremental
-backup. rdiff-backup can also operate in a bandwidth efficient manner
-over a pipe, like rsync. Thus you can use rdiff-backup and ssh to
-securely back a hard drive up to a remote location, and only the
-differences from the previous backup will be transmitted.
-
-%prep
-%setup -q
-
-%build
-%{PYTHON_NAME} setup.py build
-
-%install
-%{PYTHON_NAME} setup.py install --root $RPM_BUILD_ROOT
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-%files
-%defattr(-,root,root)
-%{_bindir}/rdiff-backup
-%{_bindir}/rdiff-backup-statistics
-%{_bindir}/rdiff-backup-delete
-%{_mandir}/man1/rdiff-backup*
-%dir %{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiff_backup
-%{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiff_backup/*.py
-%dir %{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiff_backup/__pycache__
-%{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiff_backup/__pycache__/*.pyc
-%{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiff_backup/*.so
-%{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiff_backup-*.egg-info
-%dir %{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup
-%{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/*.py
-%dir %{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/__pycache__
-%{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/__pycache__/*.pyc
-%dir %{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/actions
-%{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/actions/*.py
-%dir %{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/actions/__pycache__
-%{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/actions/__pycache__/*.pyc
-%dir %{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/utils
-%{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/utils/*.py
-%dir %{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/utils/__pycache__
-%{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/utils/__pycache__/*.pyc
-%dir %{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/meta
-%{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/meta/*.py
-%dir %{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/meta/__pycache__
-%{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/meta/__pycache__/*.pyc
-%dir %{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/locations
-%{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/locations/*.py
-%dir %{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/locations/__pycache__
-%{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/locations/__pycache__/*.pyc
-%dir %{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/locations/map
-%{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/locations/map/*.py
-%dir %{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/locations/map/__pycache__
-%{_libdir}/python%{PYTHON_VERSION}/site-packages/rdiffbackup/locations/map/__pycache__/*.pyc
-%{_datadir}/bash-completion/completions/rdiff-backup
-%doc CHANGELOG.adoc COPYING README.adoc docs/*.adoc
-
-%changelog
-* Sat Jul 25 2020 Frank Crawford <frank@crawford.emu.id.au> 2.0.5-1
-- Last bug-fix before code clean-up
-
-* Sat May 23 2020 Frank Crawford <frank@crawford.emu.id.au> 2.0.3-1
-- Version 2.0.3 - Bugfix release
-
-* Sun Mar 15 2020 Eric Lavarde <ewl+rdiffbackup@lavar.de> 2.0.0-1
-- Version 2.0.0 - ready for the future
-
-* Sat Nov 23 2019 Eric Lavarde <ewl+rdiffbackup@lavar.de> 1.4.0b0-1
-- Beta release of upgrade to Python3.
-
-* Sat Feb 16 2019 Eric Lavarde <ewl+rdiffbackup@lavar.de> 1.3.0-1
-- Update URLs
-
-* Wed Nov 15 2006 Gordon Rowell <gordonr@gormand.com.au> 1.1.7-1
-- Update URLs
-
-* Mon Aug 22 2005 Ben Escoto <ben@emerose.org> - 1.0.0-3
-- Matthijs van der Klip's patch to fix python2 support
-
-* Tue Aug 16 2005 Ben Escoto <ben@emerose.org> - 1.0.0-2
-- Removing /usr/share/doc in build for some obscure reason
-
-* Mon Mar 28 2005 Ben Escoto <ben@emerose.org> - 0.13.5-1
-- Set librsync >= 0.9.7 to encourage upgrade
-
-* Sat Dec 15 2003 Ben Escoto <bescoto@stanford.edu> - 0.12.6-2
-- Readded python2/python code; turns out not everyone calls it python
-- A number of changes from Fedora rpm.
-
-* Sun Oct 05 2003 Ben Escoto <bescoto@stanford.edu> - 0:0.12.5-0.fdr.1
-- Added epochs to python versions, more concise %%defines, %%ghost files
-
-* Thu Sep 11 2003 Ben Escoto <bescoto@stanford.edu> - 0.12.4-1
-- Removed code that selected between python2 and python; I think
-  everyone calls it python now.
-
-* Thu Aug 16 2003 Ben Escoto <bescoto@stanford.edu> - 0:0.12.3-0.fdr.4
-- Implemented various suggestions of Fedora QA
-
-* Thu Aug 8 2003 Ben Escoto <bescoto@stanford.edu>
-- Set librsync >= 0.9.6, because rsync.h renamed to librsync.h
-
-* Sun Jul 20 2003 Ben Escoto <bescoto@stanford.edu>
-- Minor changes to comply with Fedora standards.
-
-* Sun Jan 19 2002 Troels Arvin <troels@arvin.dk>
-- Builds, no matter if Python 2.2 is called python2-2.2 or python-2.2.
-
-* Sun Nov 4 2001 Ben Escoto <bescoto@stanford.edu>
-- Initial RPM
diff --git a/tools/rdiff-backup.spec.template-fedora b/tools/rdiff-backup.spec.template-fedora
deleted file mode 100644
index afdee89e6..000000000
--- a/tools/rdiff-backup.spec.template-fedora
+++ /dev/null
@@ -1,69 +0,0 @@
-# This spec file works for Fedora, but is NOT necessarily the official one
-# used to build the package.
-
-%global gittag {{ version }}
-
-Version: %{gittag}
-Summary: Convenient and transparent local/remote incremental mirror/backup
-Name: rdiff-backup
-Release: 1%{?dist}
-
-URL: https://rdiff-backup.net/
-Source0: https://github.com/%{name}/%{name}/releases/download/v%{gittag}/%{name}-%{version}.tar.gz
-
-License: GPLv2+
-BuildRequires: python3-devel >= 3.6, librsync-devel >= 1.0.0
-BuildRequires: python3-setuptools
-BuildRequires: python3-setuptools_scm
-BuildRequires: gcc
-#required to generate the manpages
-BuildRequires: rubygem-asciidoctor
-
-#recommended runtime dependencies
-Recommends: py3libacl
-Recommends: python3-pyxattr
-Recommends: python3-psutil
-
-%description
-rdiff-backup is a script, written in Python, that backs up one
-directory to another and is intended to be run periodically (nightly
-from cron for instance). The target directory ends up a copy of the
-source directory, but extra reverse diffs are stored in the target
-directory, so you can still recover files lost some time ago. The idea
-is to combine the best features of a mirror and an incremental
-backup. rdiff-backup can also operate in a bandwidth efficient manner
-over a pipe, like rsync. Thus you can use rdiff-backup and ssh to
-securely back a hard drive up to a remote location, and only the
-differences from the previous backup will be transmitted.
-
-%prep
-%autosetup -n %{name}-%{version} -p1
-
-%build
-%py3_build
-
-%install
-%py3_install
-
-# Remove doc files so we package them with rpmbuild
-rm -rf $RPM_BUILD_ROOT/usr/share/doc/*
-
-%files
-%defattr(-,root,root)
-%{_bindir}/rdiff-backup
-%{_bindir}/rdiff-backup-statistics
-%{_bindir}/rdiff-backup-delete
-%{_mandir}/man1/rdiff-backup*
-%{python3_sitearch}/rdiff_backup/
-%{python3_sitearch}/rdiff_backup-*.egg-info
-%{python3_sitearch}/rdiffbackup/
-%{_datadir}/bash-completion/completions/rdiff-backup
-%doc CHANGELOG.adoc README.adoc
-%doc docs/credits.adoc docs/DEVELOP.adoc docs/examples.adoc
-%doc docs/FAQ.adoc docs/migration.adoc
-%license COPYING
-
-%changelog
-* Sun Mar 15 2020 Eric Lavarde <ewl+rdiffbackup@lavar.de> 2.0.0-1
-- Version 2.0.0 - ready for the future
-
diff --git a/tools/win_build_rdiffbackup.sh b/tools/win_build_rdiffbackup.sh
index 8941a21b1..1884e4a2d 100644
--- a/tools/win_build_rdiffbackup.sh
+++ b/tools/win_build_rdiffbackup.sh
@@ -29,7 +29,7 @@ fi
 LIBRSYNC_DIR=${HOME}/librsync${bits}
 export LIBRSYNC_DIR
 
-RDIFF_BACKUP_VERSION=rdiff-backup-$(${PYEXE} setup.py --version)-${bits}
+RDIFF_BACKUP_VERSION=rdiff-backup-$(./tools/get_project_metadata.py Version)-${bits}
 export RDIFF_BACKUP_VERSION
 
 ${TOXEXE} -c tox_win.ini -e buildexe
diff --git a/tools/win_package_rdiffbackup.sh b/tools/win_package_rdiffbackup.sh
index 47d8ccb47..4af2843ca 100644
--- a/tools/win_package_rdiffbackup.sh
+++ b/tools/win_package_rdiffbackup.sh
@@ -23,7 +23,7 @@ then
 	PYEXE=${py_dir}/${PYEXE}
 fi
 
-ver_name=rdiff-backup-$(${PYEXE} setup.py --version)
+ver_name=rdiff-backup-$(./tools/get_project_metadata.py Version)
 
 cp CHANGELOG.adoc COPYING README.adoc docs/*.adoc \
 	build/${ver_name}-${bits}
diff --git a/tox_dist.ini b/tox_dist.ini
index 91243c7c9..207d644ab 100644
--- a/tox_dist.ini
+++ b/tox_dist.ini
@@ -18,6 +18,6 @@ deps = -r{toxinidir}/requs/base.txt
        -r{toxinidir}/requs/optional.txt
        -r{toxinidir}/requs/build.txt
 commands_pre =
-    python setup.py clean --all
+    python setup.py clean --all  # FIXME else man-pages and RPM specs remain
 commands =
-    python setup.py bdist_wheel
+    pyproject-build
diff --git a/tox_win.ini b/tox_win.ini
index f05c6a98e..1adcdf231 100644
--- a/tox_win.ini
+++ b/tox_win.ini
@@ -97,7 +97,7 @@ deps = -r{toxinidir}/requs/base.txt
        -r{toxinidir}/requs/build.txt
 # add hook file to hooks-dir for each new plugin manager!
 commands =
-    python setup.py bdist_wheel
+    pyproject-build
     pyinstaller --onefile --distpath build/{env:RDIFF_BACKUP_VERSION} \
         --additional-hooks-dir=tools \
         --console {envsitepackagesdir}/rdiffbackup/run.py \


Test patch:
diff --git a/tools/win_test_rdiffbackup.sh b/tools/win_test_rdiffbackup.sh
index bf72a64e7..8d18b8905 100644
--- a/tools/win_test_rdiffbackup.sh
+++ b/tools/win_test_rdiffbackup.sh
@@ -27,7 +27,7 @@ fi
 LIBRSYNC_DIR=${HOME}/librsync${bits}
 export LIBRSYNC_DIR
 
-ver_name=rdiff-backup-$(${PYEXE} setup.py --version)
+ver_name=rdiff-backup-$(./tools/get_project_metadata.py Version)
 py_ver_brief=${PYTHON_VERSION%.[0-9]}
 
 # Extract the test files one directory higher