Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .git_archival.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node: $Format:%H$
node-date: $Format:%cI$
describe-name: $Format:%(describe:tags=true)$
ref-names: $Format:%D$
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.git_archival.txt export-subst
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,8 @@ target/
# IDE
.idea/

# Virtual Environments
venv/

# Build Artifacts
dronecan_gui_tool/_version_generated.py
19 changes: 15 additions & 4 deletions dronecan_gui_tool/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,23 @@

logging.basicConfig(stream=sys.stderr, level=logging_level,
format='%(asctime)s %(levelname)s %(name)s %(message)s')

from .version import __version__
try:
from .version import __version_tuple__
except ModuleNotFoundError:
__version_tuple__ = (0, 0, 0, "unknown")
__version__ = [x for x in __version_tuple__ if isinstance(x, int)]
if args.version:
v = '.'.join(map(str, __version__))
metadata_parts = [x for x in __version_tuple__ if isinstance(x, str)]
is_clean_release = len(metadata_parts) == 0
is_dirty = any(".d" in part for part in metadata_parts)
version_info = '.'.join(map(str, __version__))
Comment thread
joshanne marked this conversation as resolved.
metadata_info = '.'.join(map(str, metadata_parts))
print("DroneCAN GUI Tool is an application for DroneCAN bus management and diagnostics")
print(f"DroneCAN GUI Tool Version: {v}")
print(f"DroneCAN GUI Tool Version: {version_info}")
if not is_clean_release:
print(f"Development Build: {metadata_info}")
if is_dirty:
print("Warning: Built from a dirty working tree!")
sys.exit(0)

log_file = tempfile.NamedTemporaryFile(mode='w', prefix='dronecan_gui_tool-', suffix='.log', delete=False)
Expand Down
94 changes: 93 additions & 1 deletion dronecan_gui_tool/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,99 @@
# Andrew Tridgell
#
#
__version__ = 1, 2, 28

import os
import subprocess
import re

# Note: This version is determined dynamically at build time or runtime.
__version_tuple__ = None

# 1. Try running git describe first (live git repository state)
try:

git_describe = subprocess.check_output(
["git", "describe", "--tags", "--long", "--dirty"],
stderr=subprocess.DEVNULL,
text=True
).strip()
Comment thread
joshanne marked this conversation as resolved.
Outdated
is_dirty = git_describe.endswith("-dirty")
if is_dirty:
git_describe = git_describe[:-6] # slice off the '-dirty'

# Split from the right, because the tag itself might contain hyphens (e.g., v1.0-beta)
parts = git_describe.rsplit("-", 2)

if len(parts) == 3:
base_tag = parts[0]
commits_since = int(parts[1])
sha = parts[2]

# Parse base tag into tuple (e.g., "1.2.28" -> (1, 2, 28))
# Remove leading 'v' if present
if base_tag.startswith('v'):
base_tag = base_tag[1:]

tag_parts = tuple(int(x) for x in base_tag.split('.') if x.isdigit())

__version_tuple__ = tag_parts
if commits_since > 0:
__version_tuple__ += (f"source-post{commits_since}", sha)
if is_dirty:
__version_tuple__ += ("dirty", )
except (FileNotFoundError, subprocess.CalledProcessError):
# 2. Try to import the generated version information (built wheels/MSIs)
try:
from ._version_generated import __version_tuple__
except ImportError:
# 3. Fall back to reading .git_archival.txt (GitHub source ZIPs)
__version_tuple__ = (0, 0, 0, "unknown")

archival_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".git_archival.txt")
if os.path.isfile(archival_path):
with open(archival_path, 'r', encoding='utf-8') as f:
content = f.read()

# Extract node hash
node_match = re.search(r'^node:[ \t]*([a-f0-9]{40})$', content, re.MULTILINE)
# Extract describe-name
describe_match = re.search(r'^describe-name:[ \t]*(.+)$', content, re.MULTILINE)
# Extract ref-names
ref_match = re.search(r'^ref-names:[ \t]*(.+)$', content, re.MULTILINE)

if node_match and not node_match.group(1).startswith('$'):
sha = 'g' + node_match.group(1)[:7]
base_tag = None
commits_since = 0

if describe_match and not describe_match.group(1).startswith('$'):
describe_str = describe_match.group(1).strip()
parts = describe_str.rsplit("-", 2)

if len(parts) == 3 and parts[1].isdigit() and parts[2].startswith('g'):
base_tag = parts[0]
commits_since = int(parts[1])
else:
base_tag = describe_str

if not base_tag and ref_match and not ref_match.group(1).startswith('$'):
refs = ref_match.group(1).split(', ')
tags = [r[5:] for r in refs if r.startswith('tag: ')]
if tags:
base_tag = tags[0]

if base_tag:
if base_tag.startswith('v'):
base_tag = base_tag[1:]

tag_parts = tuple(int(x) for x in base_tag.split('.') if x.isdigit())
if tag_parts:
__version_tuple__ = tag_parts
if commits_since > 0:
__version_tuple__ += (f"source-post{commits_since}", sha)
else:
__version_tuple__ = (0, 0, 0, "source", sha)
else:
__version_tuple__ = (0, 0, 0, "source", sha)
else:
print("Warning: Git is not available and .git_archival.txt not found")
25 changes: 18 additions & 7 deletions dronecan_gui_tool/widgets/about_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,32 @@
#

import dronecan
from ..version import __version__
try:
from ..version import __version_tuple__
except ImportError:
__version_tuple__ = (0, 0, 0, "unknown")
from . import get_icon, get_app_icon
from PyQt6.QtWidgets import QDialog, QTableWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, \
QTableWidgetItem, QHeaderView
from PyQt6.QtGui import QIcon
from PyQt6.QtCore import Qt, PYQT_VERSION_STR, QSize

numeric_parts = [x for x in __version_tuple__ if isinstance(x, int)]
metadata_parts = [x for x in __version_tuple__ if isinstance(x, str)]
is_clean_release = len(metadata_parts) == 0
is_dirty = any(".d" in part for part in metadata_parts)
version_info = '.'.join(map(str, numeric_parts))
Comment thread
joshanne marked this conversation as resolved.
metadata_info = '.'.join(map(str, metadata_parts))

ABOUT_TEXT = ('''
<h3>DroneCAN GUI Tool v{0}</h3>
Cross-platform application for <a href="http://dronecan.org/">DroneCAN bus</a> management and diagnostics.
ABOUT_TEXT = (f"""
<h3>DroneCAN GUI Tool v{version_info}</h3>
{f"<h4>Dev Build {'(Dirty)' if is_dirty else ''}: {metadata_info}</h4>" if not is_clean_release else ""}

This application is distributed under the terms of the MIT software license. The source repository and the bug \
tracker are located at <a href="https://github.com/DroneCAN/gui_tool">https://github.com/DroneCAN/gui_tool</a>.
'''.format('.'.join(map(str, __version__)))).strip().replace('\n', '\n<br/>')
<p>Cross-platform application for <a href="http://dronecan.org/">DroneCAN bus</a> management and diagnostics.</p>

<p>This application is distributed under the terms of the MIT software license. The source repository and the bug \
tracker are located at <a href="https://github.com/DroneCAN/gui_tool">https://github.com/DroneCAN/gui_tool</a>.</p>
""")


def _list_3rd_party():
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
# you need to drop setup_requires from setup.py as well.
# https://peps.python.org/pep-0518/#rationale
[build-system]
requires = ["setuptools>=42",'setuptools_git>=1.0']
requires = ["setuptools>=42",'setuptools_git>=1.0',"setuptools_scm[toml]>=6.2"]
build-backend = "setuptools.build_meta"
7 changes: 5 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
upgrade_code = '{D5CD6E19-2545-32C7-A62A-4595B28BCDC3}'

sys.path.append(os.path.join(SOURCE_DIR, PACKAGE_NAME))
from version import __version__

assert sys.version_info[0] == 3, 'Python 3 is required'

Expand All @@ -36,10 +35,14 @@
#
args = dict(
name=PACKAGE_NAME,
version='.'.join(map(str, __version__)),
use_scm_version={
"write_to": "dronecan_gui_tool/_version_generated.py",
"version_scheme": "post-release"
},
packages=find_packages(),
install_requires=[
'setuptools>=18.5',
'setuptools-scm>=6.2',
'dronecan>=1.0.25',
'pyserial>=3.0',
'pymavlink>=2.4.26',
Expand Down
Loading