build: change the fallback version suffix to `+git.{sha}`

Seems to be more commonly used than the current `-commit-{sha}`.
Also cleanup/simplify the version handling code and fix the list
of dependencies in the CI scripts.

Change-Id: Ib119accf51899224eaed1963e7d7e6d71bc0c30b
diff --git a/.editorconfig b/.editorconfig
index 624ad9b..f9b3c4d 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -26,3 +26,4 @@
 [*.{yaml,yml}]
 indent_style = space
 indent_size = 2
+trim_trailing_whitespace = true
diff --git a/.gitignore b/.gitignore
index 6ff803e..dc40a00 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,22 +1,8 @@
-# Emacs
+# Backup files
 *~
-\#*\#
-/.emacs.desktop
-/.emacs.desktop.lock
-*.elc
-.\#*
-
-# Visual Studio Code
-.vscode/
-
-# KDevelop
-*.kdev*
-
-# macOS
-.DS_Store
-.AppleDouble
-.LSOverride
-._*
+*.bak
+*.orig
+*.rej
 
 # Waf build system
 /build/
@@ -28,5 +14,21 @@
 __pycache__/
 *.py[cod]
 
+# Emacs
+\#*\#
+/.emacs.desktop
+/.emacs.desktop.lock
+*.elc
+.\#*
+
+# Visual Studio Code
+.vscode/
+
+# macOS
+.DS_Store
+.AppleDouble
+.LSOverride
+._*
+
 # Other
 /VERSION.info
diff --git a/.jenkins.d/00-deps.sh b/.jenkins.d/00-deps.sh
index d21e972..2bdc040 100755
--- a/.jenkins.d/00-deps.sh
+++ b/.jenkins.d/00-deps.sh
@@ -2,7 +2,8 @@
 set -eo pipefail
 
 APT_PKGS=(
-    build-essential
+    dpkg-dev
+    g++
     libboost-chrono-dev
     libboost-date-time-dev
     libboost-dev
@@ -16,7 +17,7 @@
     libsqlite3-dev
     libssl-dev
     pkg-config
-    python3-minimal
+    python3
 )
 FORMULAE=(boost openssl pkg-config)
 PIP_PKGS=()
diff --git a/README.md b/README.md
index ccf5766..2819488 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,9 @@
 # PSync: Partial and Full Synchronization Library for NDN
 
+![Latest version](https://img.shields.io/github/v/tag/named-data/PSync?label=Latest%20version)
+![Language](https://img.shields.io/badge/C%2B%2B-17-blue)
 [![CI](https://github.com/named-data/PSync/actions/workflows/ci.yml/badge.svg)](https://github.com/named-data/PSync/actions/workflows/ci.yml)
 [![Docs](https://github.com/named-data/PSync/actions/workflows/docs.yml/badge.svg)](https://github.com/named-data/PSync/actions/workflows/docs.yml)
-![Language](https://img.shields.io/badge/C%2B%2B-17-blue)
-![Latest version](https://img.shields.io/github/v/tag/named-data/PSync?label=Latest%20version)
 
 The PSync library implements the
 [PSync protocol](https://named-data.net/wp-content/uploads/2017/05/scalable_name-based_data_synchronization.pdf).
diff --git a/docs/conf.py b/docs/conf.py
index d4bf63c..dd5c245 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -10,7 +10,7 @@
 # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
 
 project = 'PSync: Partial/Full Synchronization Protocol for NDN'
-copyright = 'Copyright © 2018-2023 Named Data Networking Project.'
+copyright = 'Copyright © 2018-2024 Named Data Networking Project.'
 author = 'Named Data Networking Project'
 
 # The short X.Y version.
diff --git a/wscript b/wscript
index 8230aad..9a77fba 100644
--- a/wscript
+++ b/wscript
@@ -161,43 +161,43 @@
     Context.g_module.VERSION_SPLIT = VERSION_BASE.split('.')
 
     # first, try to get a version string from git
-    gotVersionFromGit = False
+    version_from_git = ''
     try:
-        cmd = ['git', 'describe', '--always', '--match', f'{GIT_TAG_PREFIX}*']
-        out = subprocess.run(cmd, capture_output=True, check=True, text=True).stdout.strip()
-        if out:
-            gotVersionFromGit = True
-            if out.startswith(GIT_TAG_PREFIX):
-                Context.g_module.VERSION = out.lstrip(GIT_TAG_PREFIX)
+        cmd = ['git', 'describe', '--abbrev=8', '--always', '--match', f'{GIT_TAG_PREFIX}*']
+        version_from_git = subprocess.run(cmd, capture_output=True, check=True, text=True).stdout.strip()
+        if version_from_git:
+            if GIT_TAG_PREFIX and version_from_git.startswith(GIT_TAG_PREFIX):
+                Context.g_module.VERSION = version_from_git[len(GIT_TAG_PREFIX):]
+            elif not GIT_TAG_PREFIX and ('.' in version_from_git or '-' in version_from_git):
+                Context.g_module.VERSION = version_from_git
             else:
-                # no tags matched
-                Context.g_module.VERSION = f'{VERSION_BASE}-commit-{out}'
+                # no tags matched (or we are in a shallow clone)
+                Context.g_module.VERSION = f'{VERSION_BASE}+git.{version_from_git}'
     except (OSError, subprocess.SubprocessError):
         pass
 
-    versionFile = ctx.path.find_node('VERSION.info')
-    if not gotVersionFromGit and versionFile is not None:
+    # fallback to the VERSION.info file, if it exists and is not empty
+    version_from_file = ''
+    version_file = ctx.path.find_node('VERSION.info')
+    if version_file is not None:
         try:
-            Context.g_module.VERSION = versionFile.read()
-            return
-        except EnvironmentError:
-            pass
+            version_from_file = version_file.read().strip()
+        except OSError as e:
+            Logs.warn(f'{e.filename} exists but is not readable ({e.strerror})')
+    if version_from_file and not version_from_git:
+        Context.g_module.VERSION = version_from_file
+        return
 
-    # version was obtained from git, update VERSION file if necessary
-    if versionFile is not None:
-        try:
-            if versionFile.read() == Context.g_module.VERSION:
-                # already up-to-date
-                return
-        except EnvironmentError as e:
-            Logs.warn(f'{versionFile} exists but is not readable ({e.strerror})')
-    else:
-        versionFile = ctx.path.make_node('VERSION.info')
-
+    # update VERSION.info if necessary
+    if version_from_file == Context.g_module.VERSION:
+        # already up-to-date
+        return
+    if version_file is None:
+        version_file = ctx.path.make_node('VERSION.info')
     try:
-        versionFile.write(Context.g_module.VERSION)
-    except EnvironmentError as e:
-        Logs.warn(f'{versionFile} is not writable ({e.strerror})')
+        version_file.write(Context.g_module.VERSION)
+    except OSError as e:
+        Logs.warn(f'{e.filename} is not writable ({e.strerror})')
 
 def dist(ctx):
     ctx.algo = 'tar.xz'