Skip to content

Commit 20c3a64

Browse files
Merge remote-tracking branch 'plotjuggler/main' into sync/main-to-internal-main-2026-05-21
2 parents 78b4c5b + fbb4241 commit 20c3a64

156 files changed

Lines changed: 7748 additions & 1205 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.clang-format

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,10 @@ AlignAfterOpenBracket: AlwaysBreak
2121
AllowShortBlocksOnASingleLine: Empty
2222
AllowShortFunctionsOnASingleLine: Empty
2323
AllowShortIfStatementsOnASingleLine: Never
24+
25+
---
26+
# Same column limit and indent as C++ for the protobuf schemas under pj_base/proto/.
27+
Language: Proto
28+
BasedOnStyle: Google
29+
ColumnLimit: 120
30+
IndentWidth: 2

.github/workflows/linux-ci.yml

Lines changed: 62 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,22 @@ jobs:
7272
shell: bash
7373
run: |
7474
set -euo pipefail
75-
# Hash every conanfile.txt under the tree (top-level today,
76-
# pj_ported_plugins/ in the near future) so the key invalidates
77-
# whenever any of them changes.
78-
hash=$(find . -name conanfile.txt -not -path './build/*' -not -path './.git/*' \
75+
# Hash every conanfile.{py,txt} under the tree so the key invalidates
76+
# whenever any of them changes. The top-level is now conanfile.py
77+
# (Conan recipe); subtrees like pj_ported_plugins/ still use .txt.
78+
hash=$(find . \( -name 'conanfile.py' -o -name 'conanfile.txt' \) \
79+
-not -path './build/*' -not -path './.git/*' \
7980
-print0 | sort -z | xargs -0 sha256sum | sha256sum | cut -c1-16)
8081
owner="${GITHUB_REPOSITORY_OWNER,,}"
8182
# Build-type suffix leaves room for a future debug-asan variant
8283
# without colliding on the same tag.
8384
tag="ghcr.io/${owner}/plotjuggler-core-conan-cache:linux-gcc-relwithdebinfo-${hash}"
85+
main_tag="ghcr.io/${owner}/plotjuggler-core-conan-cache:linux-gcc-relwithdebinfo-main"
86+
echo "hash=${hash}" >> "${GITHUB_OUTPUT}"
8487
echo "tag=${tag}" >> "${GITHUB_OUTPUT}"
88+
echo "main_tag=${main_tag}" >> "${GITHUB_OUTPUT}"
8589
echo "Cache tag: ${tag}"
90+
echo "Main fallback cache tag: ${main_tag}"
8691
8792
- name: Login to ghcr.io
8893
# Required for both pull (private packages) and push. GITHUB_TOKEN is
@@ -100,23 +105,33 @@ jobs:
100105
shell: bash
101106
run: |
102107
set +e
103-
tag="${{ steps.conan_cache.outputs.tag }}"
108+
exact_tag="${{ steps.conan_cache.outputs.tag }}"
109+
main_tag="${{ steps.conan_cache.outputs.main_tag }}"
104110
pull_dir="${RUNNER_TEMP}/conan-cache-pull"
105111
mkdir -p "${pull_dir}"
106-
(
107-
cd "${pull_dir}"
108-
oras pull "${tag}" 2>&1
109-
)
110-
pulled=$?
111112
tarball="${pull_dir}/conan-cache.tar.zst"
112-
if [ "${pulled}" -eq 0 ] && [ -f "${tarball}" ]; then
113-
echo "Cache HIT: extracting ${tarball}"
114-
mkdir -p "${HOME}/.conan2"
115-
tar --zstd -xf "${tarball}" -C "${HOME}"
116-
echo "CONAN_CACHE_HIT=1" >> "${GITHUB_ENV}"
117-
else
118-
echo "Cache MISS for ${tag} (cold start or first build of this conanfile)"
119-
fi
113+
114+
for tag in "${exact_tag}" "${main_tag}"; do
115+
rm -f "${tarball}"
116+
echo "Trying Conan cache: ${tag}"
117+
(
118+
cd "${pull_dir}"
119+
oras pull "${tag}" 2>&1
120+
)
121+
pulled=$?
122+
if [ "${pulled}" -eq 0 ] && [ -f "${tarball}" ]; then
123+
echo "Cache HIT: extracting ${tarball}"
124+
mkdir -p "${HOME}/.conan2"
125+
tar --zstd -xf "${tarball}" -C "${HOME}"
126+
echo "CONAN_CACHE_HIT=1" >> "${GITHUB_ENV}"
127+
echo "CONAN_CACHE_HIT_TAG=${tag}" >> "${GITHUB_ENV}"
128+
if [ "${tag}" = "${exact_tag}" ]; then
129+
echo "CONAN_CACHE_EXACT_HIT=1" >> "${GITHUB_ENV}"
130+
fi
131+
exit 0
132+
fi
133+
echo "Cache MISS for ${tag}"
134+
done
120135
# Always exit 0 — a missing tag is not a CI failure.
121136
exit 0
122137
@@ -128,17 +143,18 @@ jobs:
128143
cache: 'true'
129144

130145
- name: Install system packages
131-
run: sudo apt-get update && sudo apt-get install -y xvfb ccache zstd
146+
run: sudo apt-get update && sudo apt-get install -y xvfb ccache ninja-build zstd
132147

133148
- name: Configure ccache
134149
# Compiler-output cache for our own C++ — complementary to the Conan
135150
# cache (which holds prebuilt third-party packages, not our objects).
136151
uses: actions/cache@v4
137152
with:
138153
path: ~/.cache/ccache
139-
key: ccache-linux-${{ github.ref_name }}-${{ github.sha }}
154+
key: ccache-linux-relwithdebinfo-${{ steps.conan_cache.outputs.hash }}-${{ github.sha }}
140155
restore-keys: |
141-
ccache-linux-${{ github.ref_name }}-
156+
ccache-linux-relwithdebinfo-${{ steps.conan_cache.outputs.hash }}-
157+
ccache-linux-relwithdebinfo-
142158
ccache-linux-
143159
144160
- name: Set ccache limits
@@ -147,15 +163,19 @@ jobs:
147163
ccache --set-config=compression=true
148164
ccache -z
149165
150-
- name: Build
151-
run: ./build.sh
166+
- name: Conan install
167+
run: >
168+
conan install . --output-folder=build --build=missing
169+
-s build_type=RelWithDebInfo -s compiler.cppstd=20
170+
-o "plotjuggler_core/*:with_tests=True"
171+
-o "plotjuggler_core/*:with_parquet_example=False"
152172
153173
- name: Save Conan cache to ghcr.io
154174
# Only push from the canonical repo on real pushes (forks lack write
155-
# access to ghcr.io packages). Skip on cache HIT — the tag content is
156-
# already up to date, no point re-uploading the same bytes. Skip if
175+
# access to ghcr.io packages). Skip on exact cache HIT — the tag content
176+
# is already up to date, no point re-uploading the same bytes. Skip if
157177
# neither oras install path succeeded (graceful degradation).
158-
if: github.event_name == 'push' && github.repository == 'PlotJuggler/plotjuggler_core' && env.CONAN_CACHE_HIT != '1' && (steps.setup_oras.outcome == 'success' || steps.setup_oras_fallback.outcome == 'success')
178+
if: github.event_name == 'push' && github.repository == 'PlotJuggler/plotjuggler_core' && env.CONAN_CACHE_EXACT_HIT != '1' && (steps.setup_oras.outcome == 'success' || steps.setup_oras_fallback.outcome == 'success')
159179
shell: bash
160180
run: |
161181
set -euo pipefail
@@ -175,11 +195,26 @@ jobs:
175195
(
176196
cd "${RUNNER_TEMP}"
177197
oras push "${tag}" "conan-cache.tar.zst:application/vnd.oci.image.layer.v1.tar+zstd"
198+
if [ "${GITHUB_REF_NAME}" = "main" ]; then
199+
oras push "${{ steps.conan_cache.outputs.main_tag }}" "conan-cache.tar.zst:application/vnd.oci.image.layer.v1.tar+zstd"
200+
fi
178201
)
179202
203+
- name: Configure
204+
run: >
205+
cmake -S . -B build -G Ninja
206+
-DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/build/conan_toolchain.cmake
207+
-DCMAKE_BUILD_TYPE=RelWithDebInfo
208+
-DCMAKE_C_COMPILER_LAUNCHER=ccache
209+
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
210+
-DPJ_BUILD_PARQUET_IMPORT_EXAMPLE=OFF
211+
212+
- name: Build
213+
run: cmake --build build
214+
180215
- name: ccache stats
181216
if: always()
182217
run: ccache -s
183218

184219
- name: Test
185-
run: xvfb-run -a ./test.sh
220+
run: xvfb-run -a ctest --test-dir build --output-on-failure

.github/workflows/release.yml

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
name: Release
2+
3+
# Triggers on tag push (e.g. `git push origin v0.2.0`). Builds the Conan
4+
# package, uploads it to the project's Cloudsmith remote, and publishes a
5+
# GitHub Release with auto-generated notes.
6+
#
7+
# Secrets required (set in repo Settings → Secrets and variables → Actions):
8+
# CLOUDSMITH_USER — Cloudsmith username (e.g. "davide-faconti")
9+
# CLOUDSMITH_API_KEY — Cloudsmith API key with write access to the
10+
# plotjuggler/plotjuggler repository
11+
#
12+
# Manual trigger: workflow_dispatch lets you re-run for an existing tag if
13+
# the first attempt failed (e.g. flaky upload). Set `tag` input to e.g. v0.1.0.
14+
15+
on:
16+
push:
17+
tags:
18+
- 'v*'
19+
workflow_dispatch:
20+
inputs:
21+
tag:
22+
description: 'Tag to (re-)release (e.g. v0.1.0). Must already exist.'
23+
required: true
24+
25+
concurrency:
26+
group: release-${{ github.ref }}
27+
cancel-in-progress: false # never cancel an in-flight release
28+
29+
jobs:
30+
release:
31+
runs-on: ubuntu-22.04
32+
permissions:
33+
contents: write # required to create the GitHub Release
34+
steps:
35+
- name: Resolve ref
36+
id: ref
37+
run: |
38+
if [[ -n "${{ inputs.tag }}" ]]; then
39+
echo "ref=${{ inputs.tag }}" >> "$GITHUB_OUTPUT"
40+
echo "tag=${{ inputs.tag }}" >> "$GITHUB_OUTPUT"
41+
else
42+
echo "ref=${GITHUB_REF}" >> "$GITHUB_OUTPUT"
43+
echo "tag=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT"
44+
fi
45+
# Strip leading 'v' for the Conan version (v0.1.0 -> 0.1.0).
46+
version="${GITHUB_REF_NAME#v}"
47+
version="${version:-${{ inputs.tag }}}"
48+
version="${version#v}"
49+
echo "version=${version}" >> "$GITHUB_OUTPUT"
50+
51+
- uses: actions/checkout@v4
52+
with:
53+
ref: ${{ steps.ref.outputs.ref }}
54+
55+
- uses: conan-io/setup-conan@v1
56+
57+
- name: Detect Conan profile
58+
run: |
59+
conan profile detect --force
60+
conan profile show
61+
62+
- name: Verify recipe version matches tag
63+
# Prevents the common footgun of tagging vX.Y.Z but forgetting to bump
64+
# `version` in conanfile.py. Fails fast before we publish.
65+
run: |
66+
recipe_version=$(python3 -c "import re; print(re.search(r'^\s*version\s*=\s*\"([^\"]+)\"', open('conanfile.py').read(), re.M).group(1))")
67+
if [[ "${recipe_version}" != "${{ steps.ref.outputs.version }}" ]]; then
68+
echo "::error::conanfile.py version (${recipe_version}) does not match tag (${{ steps.ref.outputs.version }})"
69+
exit 1
70+
fi
71+
echo "Version match: ${recipe_version}"
72+
73+
- name: Build Conan package
74+
run: |
75+
conan create . \
76+
--build=missing \
77+
-s build_type=Release \
78+
-s compiler.cppstd=20
79+
80+
- name: Configure Cloudsmith remote
81+
env:
82+
CLOUDSMITH_USER: ${{ secrets.CLOUDSMITH_USER }}
83+
CLOUDSMITH_API_KEY: ${{ secrets.CLOUDSMITH_API_KEY }}
84+
run: |
85+
if [[ -z "$CLOUDSMITH_USER" || -z "$CLOUDSMITH_API_KEY" ]]; then
86+
echo "::error::CLOUDSMITH_USER / CLOUDSMITH_API_KEY secrets not configured"
87+
exit 1
88+
fi
89+
# `add ... --force` makes the step idempotent across re-runs.
90+
conan remote add plotjuggler-cloudsmith https://conan.cloudsmith.io/plotjuggler/plotjuggler --force
91+
conan remote login plotjuggler-cloudsmith "$CLOUDSMITH_USER" -p "$CLOUDSMITH_API_KEY"
92+
93+
- name: Upload package to Cloudsmith
94+
run: |
95+
conan upload "plotjuggler_core/${{ steps.ref.outputs.version }}" \
96+
-r plotjuggler-cloudsmith \
97+
--confirm \
98+
--check
99+
100+
- name: Create GitHub Release
101+
# softprops/action-gh-release: handles auto-generated notes + idempotent
102+
# re-runs (skips if a release for the tag already exists).
103+
uses: softprops/action-gh-release@v2
104+
with:
105+
tag_name: ${{ steps.ref.outputs.tag }}
106+
name: plotjuggler_core ${{ steps.ref.outputs.tag }}
107+
generate_release_notes: true
108+
body: |
109+
## Install via Conan
110+
111+
```bash
112+
conan remote add plotjuggler https://conan.cloudsmith.io/plotjuggler/plotjuggler
113+
```
114+
115+
Add to your `conanfile.py` / `conanfile.txt`:
116+
117+
```python
118+
requires = ("plotjuggler_core/${{ steps.ref.outputs.version }}",)
119+
```
120+
121+
Link in CMake:
122+
123+
```cmake
124+
find_package(plotjuggler_core REQUIRED COMPONENTS plugin_sdk)
125+
target_link_libraries(my_plugin PRIVATE plotjuggler_core::plugin_sdk)
126+
```
127+
128+
See [README.md](https://github.com/PlotJuggler/plotjuggler_core/blob/main/README.md)
129+
for available components (`base`, `datastore`, `plugin_sdk`, `plugin_host`)
130+
and consumer examples.

.github/workflows/windows-ci.yml

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,14 @@ jobs:
7474
id: conan_cache
7575
shell: pwsh
7676
run: |
77-
$hash = (Get-FileHash conanfile.txt -Algorithm SHA256).Hash.Substring(0, 16).ToLower()
77+
$hash = (Get-FileHash conanfile.py -Algorithm SHA256).Hash.Substring(0, 16).ToLower()
7878
$owner = "${{ github.repository_owner }}".ToLower()
7979
$tag = "ghcr.io/$owner/plotjuggler-core-conan-cache:windows-msvc-$hash"
80+
$mainTag = "ghcr.io/$owner/plotjuggler-core-conan-cache:windows-msvc-main"
8081
"tag=$tag" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
82+
"main_tag=$mainTag" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
8183
Write-Host "Cache tag: $tag"
84+
Write-Host "Main fallback cache tag: $mainTag"
8285
8386
- name: Login to ghcr.io
8487
# Required for both pull (private packages) and push. GITHUB_TOKEN is
@@ -95,24 +98,35 @@ jobs:
9598
if: github.repository_owner == 'PlotJuggler' && (steps.setup_oras.outcome == 'success' || steps.setup_oras_fallback.outcome == 'success')
9699
shell: pwsh
97100
run: |
98-
$tag = "${{ steps.conan_cache.outputs.tag }}"
101+
$exactTag = "${{ steps.conan_cache.outputs.tag }}"
102+
$mainTag = "${{ steps.conan_cache.outputs.main_tag }}"
99103
$pullDir = Join-Path $env:RUNNER_TEMP "conan-cache-pull"
100104
New-Item -ItemType Directory -Force -Path $pullDir | Out-Null
101-
Push-Location $pullDir
102-
try {
103-
oras pull $tag 2>&1 | Out-Host
104-
$pulled = $LASTEXITCODE
105-
} finally {
106-
Pop-Location
107-
}
108105
$tarball = Join-Path $pullDir "conan-cache.tar.zst"
109-
if ($pulled -eq 0 -and (Test-Path $tarball)) {
110-
Write-Host "Cache HIT: extracting $tarball"
111-
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.conan2" | Out-Null
112-
tar --zstd -xf $tarball -C $env:USERPROFILE
113-
"CONAN_CACHE_HIT=1" | Out-File -FilePath $env:GITHUB_ENV -Append
114-
} else {
115-
Write-Host "Cache MISS for $tag (cold start or first build of this conanfile)"
106+
107+
foreach ($tag in @($exactTag, $mainTag)) {
108+
Remove-Item $tarball -Force -ErrorAction SilentlyContinue
109+
Write-Host "Trying Conan cache: $tag"
110+
Push-Location $pullDir
111+
try {
112+
oras pull $tag 2>&1 | Out-Host
113+
$pulled = $LASTEXITCODE
114+
} finally {
115+
Pop-Location
116+
}
117+
if ($pulled -eq 0 -and (Test-Path $tarball)) {
118+
Write-Host "Cache HIT: extracting $tarball"
119+
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.conan2" | Out-Null
120+
tar --zstd -xf $tarball -C $env:USERPROFILE
121+
"CONAN_CACHE_HIT=1" | Out-File -FilePath $env:GITHUB_ENV -Append
122+
"CONAN_CACHE_HIT_TAG=$tag" | Out-File -FilePath $env:GITHUB_ENV -Append
123+
if ($tag -eq $exactTag) {
124+
"CONAN_CACHE_EXACT_HIT=1" | Out-File -FilePath $env:GITHUB_ENV -Append
125+
}
126+
$global:LASTEXITCODE = 0
127+
exit 0
128+
}
129+
Write-Host "Cache MISS for $tag"
116130
}
117131
# Reset exit code so a missing tag doesn't fail the step
118132
$global:LASTEXITCODE = 0
@@ -124,13 +138,14 @@ jobs:
124138
run: >
125139
conan install . --output-folder=build --build=missing
126140
-s build_type=Release -s compiler.cppstd=20
141+
-o "plotjuggler_core/*:with_tests=True"
127142
128143
- name: Save Conan cache to ghcr.io
129144
# Only push from the canonical repo on real pushes (forks lack write
130-
# access to ghcr.io packages). Skip on cache HIT — the tag content is
131-
# already up to date, no point re-uploading the same bytes. Skip if
145+
# access to ghcr.io packages). Skip on exact cache HIT — the tag content
146+
# is already up to date, no point re-uploading the same bytes. Skip if
132147
# neither oras install path succeeded (graceful degradation).
133-
if: github.event_name == 'push' && github.repository == 'PlotJuggler/plotjuggler_core' && env.CONAN_CACHE_HIT != '1' && (steps.setup_oras.outcome == 'success' || steps.setup_oras_fallback.outcome == 'success')
148+
if: github.event_name == 'push' && github.repository == 'PlotJuggler/plotjuggler_core' && env.CONAN_CACHE_EXACT_HIT != '1' && (steps.setup_oras.outcome == 'success' || steps.setup_oras_fallback.outcome == 'success')
134149
shell: pwsh
135150
run: |
136151
$tag = "${{ steps.conan_cache.outputs.tag }}"
@@ -149,6 +164,9 @@ jobs:
149164
Push-Location $env:RUNNER_TEMP
150165
try {
151166
oras push $tag "conan-cache.tar.zst:application/vnd.oci.image.layer.v1.tar+zstd"
167+
if ($env:GITHUB_REF_NAME -eq "main") {
168+
oras push "${{ steps.conan_cache.outputs.main_tag }}" "conan-cache.tar.zst:application/vnd.oci.image.layer.v1.tar+zstd"
169+
}
152170
} finally {
153171
Pop-Location
154172
}

0 commit comments

Comments
 (0)