Initial commit
This commit is contained in:
29 files changed
+2780
No files matched your search
@@ -0,0 +1,157 @@
|
||||
# GitHub Copilot Instructions: Qt5/C++11 to Qt6/C++23 Migration
|
||||
|
||||
## Mission
|
||||
Migrate the legacy Qt5/C++11 desktop application to Qt6/C++23, preserve behavior unless change is strictly required, and validate the result completely in the repository’s Docker-based CI workflow.
|
||||
|
||||
## Operating Mode
|
||||
- Work autonomously from analysis through validation.
|
||||
- Do not stop after editing code.
|
||||
- Continue until configure, build, tests, and policy checks have been attempted in Docker.
|
||||
- Do not ask for confirmation during normal implementation.
|
||||
- Stop early only if required source material is missing, the task is impossible, or a destructive action would be required.
|
||||
|
||||
## Boundaries
|
||||
- Read the legacy project from `${PROJECT_DIR}`.
|
||||
- Write the migrated project to `qt6-after/qt6-migrated-benchmark`.
|
||||
- Do not modify the legacy source tree in place.
|
||||
- Limit changes to the target tree and only the CI/build/test files needed to support migration and validation.
|
||||
|
||||
## Main Migration Targets
|
||||
- Upgrade Qt5 to Qt6.
|
||||
- Upgrade C++11/14/17 code to C++23.
|
||||
- Keep Qt Core, Gui, and Widgets explicitly linked.
|
||||
- Replace `QRegExp` with `QRegularExpression`.
|
||||
- Replace `QDesktopWidget` and `QApplication::desktop()` with `QScreen`-based Qt6 APIs.
|
||||
- Remove legacy `QTextCodec` usage and adopt Qt6-safe text handling.
|
||||
- Replace old `SIGNAL`/`SLOT` syntax with function-pointer connect syntax.
|
||||
- Replace `0`/`NULL` pointer literals with `nullptr`.
|
||||
- Preserve `.ui` and `.qrc` integration.
|
||||
- Preserve behavior unless Qt6 compatibility requires adaptation.
|
||||
|
||||
## C++23 Modernization Rules
|
||||
- Preserve semantics first; modernize second.
|
||||
- Use `auto` when the type is obvious; avoid it when it hides important type information.
|
||||
- Prefer structured bindings where clearer.
|
||||
- Replace raw owning pointers/manual `delete` with RAII, usually `std::unique_ptr`.
|
||||
- Use `std::make_unique` / `std::make_shared`; use `std::shared_ptr` only for real shared ownership.
|
||||
- Use `std::string_view` only when lifetime safety is clear.
|
||||
- Prefer `std::span` for non-owning contiguous data; use `std::mdspan` only when multidimensional access clearly benefits.
|
||||
- Prefer `.contains()` over `find(...) != end()` where available.
|
||||
- Prefer algorithms and ranges over manual loops when readability improves.
|
||||
- Use `[[nodiscard]]` when ignoring a result is likely a bug.
|
||||
- Prefer early returns over deeply nested control flow.
|
||||
- Use `std::optional` monadic operations (`and_then`, `transform`, `or_else`) when clearer.
|
||||
- Prefer `constexpr`, `if constexpr`, concepts, and `requires` over legacy `std::enable_if`/SFINAE where practical.
|
||||
- Add `noexcept`, `override`, `final`, `= default`, and `= delete` where correct and useful.
|
||||
- Prefer `enum class` over unscoped enums where practical.
|
||||
- Prefer `std::print` / `std::println` when supported by the toolchain.
|
||||
- Prefer typed `std::chrono` durations and `std::jthread` where appropriate.
|
||||
|
||||
## Safety Rules
|
||||
- Do not change business logic unless explicitly requested or required for Qt6 compatibility.
|
||||
- Do not introduce unsupported Qt6/C++23 features.
|
||||
- Do not silently change ABI, ownership, lifetime, exception behavior, performance, UI behavior, or event ordering.
|
||||
- Do not worsen readability for the sake of modernization.
|
||||
- Avoid dangling references, dangling `std::string_view`, and ownership ambiguity.
|
||||
- Keep includes minimal and preserve repository-local formatting/style.
|
||||
|
||||
## Tests
|
||||
- For every code change inside a method, add at least three tests covering the changed behavior.
|
||||
- Place generated tests in `qt6-after/qt6-migrated-benchmark/tests`.
|
||||
- Use policy-compatible test filenames such as:
|
||||
- `test_<name>.cpp`
|
||||
- `<name>_test.cpp`
|
||||
- `<name>test.cpp`
|
||||
- `<name>gtest.cpp`
|
||||
- Update CMake so the migrated app and all tests build and run with CTest.
|
||||
- Ensure all tests are registered with CTest.
|
||||
|
||||
## Docker-First Validation
|
||||
Use `lifemaps/ci-cpp:latest` as the authoritative environment. Do not substitute host tools for missing container tools. Treat `Dockerfile.ci` as the source of truth for CI dependencies.
|
||||
|
||||
### Required validation sequence
|
||||
1. Configure in Docker
|
||||
2. Build in Docker
|
||||
3. Run tests in Docker
|
||||
4. If tests pass, run `python3 ci/check_pr_policies.py` in Docker
|
||||
|
||||
### Recommended commands
|
||||
- Configure:
|
||||
`cmake -S qt6-after/qt6-migrated-benchmark -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug`
|
||||
- Build:
|
||||
`cmake --build build --parallel`
|
||||
- Test:
|
||||
`ctest --test-dir build --output-on-failure`
|
||||
- Policy:
|
||||
`python3 ci/check_pr_policies.py`
|
||||
|
||||
Adapt paths/flags only if repository inspection proves they must differ.
|
||||
|
||||
## Missing-Tool Remediation
|
||||
If Docker validation fails because a required tool/package is missing:
|
||||
- identify the exact missing dependency
|
||||
- update `Dockerfile.ci` minimally
|
||||
- rebuild `lifemaps/ci-cpp:latest`
|
||||
- rerun the full validation sequence
|
||||
|
||||
Continue until:
|
||||
- validation succeeds, or
|
||||
- the next blocker is a genuine project/code issue
|
||||
|
||||
## Failure Classification
|
||||
Environment failures:
|
||||
- command not found
|
||||
- missing compiler/toolchain utility
|
||||
- missing Qt dev package
|
||||
- missing CMake/Ninja/CTest support tool
|
||||
- missing dependency required by `ci/check_pr_policies.py`
|
||||
|
||||
Project failures:
|
||||
- compile errors
|
||||
- linker errors
|
||||
- failing tests
|
||||
- formatting/policy failures caused by migration changes
|
||||
|
||||
## Policy Awareness
|
||||
- `ci/check_pr_policies.py` checks formatting for changed C/C++ files, expects related tests, and verifies commit-signature conditions in its diff range.
|
||||
- Ensure Docker validation runs with mounted workspace and git metadata available.
|
||||
- Do not claim success unless the policy script passes.
|
||||
|
||||
## Execution Plan
|
||||
1. Inspect `${PROJECT_DIR}` and the target tree.
|
||||
2. Identify Qt5 and legacy C++ constructs to migrate.
|
||||
3. Migrate incrementally in `qt6-after/qt6-migrated-benchmark`.
|
||||
4. Add/update tests with each behavior-relevant change.
|
||||
5. Update CMake/test registration.
|
||||
6. Validate in Docker.
|
||||
7. If missing dependencies are found, update `Dockerfile.ci`, rebuild, and rerun.
|
||||
8. Repeat until success or a real project defect remains.
|
||||
|
||||
## Reporting
|
||||
Group change explanations by:
|
||||
- CMake / build-system migration
|
||||
- Qt API replacements
|
||||
- C++ modernization
|
||||
- UI/resource preservation
|
||||
- tests added
|
||||
- `Dockerfile.ci` / container updates
|
||||
|
||||
Also provide a concise changed-files summary.
|
||||
|
||||
## Completion Criteria
|
||||
Success requires:
|
||||
- migrated project exists under `qt6-after/qt6-migrated-benchmark`
|
||||
- configure succeeds in Docker
|
||||
- build succeeds in Docker
|
||||
- tests succeed in Docker
|
||||
- `python3 ci/check_pr_policies.py` succeeds in Docker after tests pass
|
||||
|
||||
## Final Response
|
||||
- State whether migration is fully validated or which blocker remains.
|
||||
- List the exact Docker commands used for image rebuild, configure, build, test, and policy check.
|
||||
- For every failed attempt, include:
|
||||
- exact command
|
||||
- key error
|
||||
- environment vs project classification
|
||||
- fix applied
|
||||
- End with a short summary of any remaining blocker.
|
||||
Executable
+233
@@ -0,0 +1,233 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
TARGET_DIR="${1:-qt5-before/qt5-legacy-migration-benchmark}"
|
||||
mkdir -p "${TARGET_DIR}"
|
||||
|
||||
cat > "${TARGET_DIR}/CMakeLists.txt" <<'FILE_EOF'
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(Qt5LegacyMigrationBenchmark LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
add_executable(Qt5LegacyMigrationBenchmark
|
||||
main.cpp
|
||||
MainWindow.h
|
||||
MainWindow.cpp
|
||||
MainWindow.ui
|
||||
resources.qrc
|
||||
)
|
||||
|
||||
target_link_libraries(Qt5LegacyMigrationBenchmark
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
Qt5::Widgets
|
||||
)
|
||||
FILE_EOF
|
||||
|
||||
cat > "${TARGET_DIR}/MainWindow.h" <<'FILE_EOF'
|
||||
#pragma once
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QRegExp>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = 0);
|
||||
~MainWindow();
|
||||
|
||||
private slots:
|
||||
void onValidateClicked();
|
||||
void onScreenInfoClicked();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
QRegExp legacyPattern;
|
||||
};
|
||||
FILE_EOF
|
||||
|
||||
cat > "${TARGET_DIR}/MainWindow.cpp" <<'FILE_EOF'
|
||||
#include "MainWindow.h"
|
||||
#include "ui_MainWindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDesktopWidget>
|
||||
#include <QTextCodec>
|
||||
#include <QPixmap>
|
||||
#include <QString>
|
||||
#include <QRect>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
, legacyPattern("^[A-Za-z]+\\d+$")
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
|
||||
QString title = codec->toUnicode("Qt5 Legacy Migration Benchmark");
|
||||
setWindowTitle(title);
|
||||
|
||||
ui->label->setText(codec->toUnicode("Bitte Text wie Test123 eingeben."));
|
||||
ui->iconLabel->setPixmap(QPixmap(":/icons/app.png").scaled(48, 48));
|
||||
|
||||
connect(ui->validateButton, SIGNAL(clicked()), this, SLOT(onValidateClicked()));
|
||||
connect(ui->screenButton, SIGNAL(clicked()), this, SLOT(onScreenInfoClicked()));
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void MainWindow::onValidateClicked()
|
||||
{
|
||||
QString text = ui->lineEdit->text();
|
||||
|
||||
if (legacyPattern.exactMatch(text)) {
|
||||
ui->resultLabel->setText("Match");
|
||||
} else {
|
||||
ui->resultLabel->setText("No match");
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onScreenInfoClicked()
|
||||
{
|
||||
QRect screenGeometry = QApplication::desktop()->screenGeometry();
|
||||
QString info = QString("Screen: %1x%2")
|
||||
.arg(screenGeometry.width())
|
||||
.arg(screenGeometry.height());
|
||||
|
||||
ui->resultLabel->setText(info);
|
||||
}
|
||||
FILE_EOF
|
||||
|
||||
cat > "${TARGET_DIR}/main.cpp" <<'FILE_EOF'
|
||||
#include <QApplication>
|
||||
#include <QTextCodec>
|
||||
#include "MainWindow.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
|
||||
#endif
|
||||
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
FILE_EOF
|
||||
|
||||
cat > "${TARGET_DIR}/MainWindow.ui" <<'FILE_EOF'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>420</width>
|
||||
<height>240</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Qt5 Legacy App</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Initial text</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Enter value like Test123</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="iconLabel">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="buttonLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="validateButton">
|
||||
<property name="text">
|
||||
<string>Validate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="screenButton">
|
||||
<property name="text">
|
||||
<string>Screen Info</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="resultLabel">
|
||||
<property name="text">
|
||||
<string>Result appears here</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
FILE_EOF
|
||||
|
||||
cat > "${TARGET_DIR}/resources.qrc" <<'FILE_EOF'
|
||||
<RCC>
|
||||
<qresource prefix="/icons">
|
||||
<file>app.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
FILE_EOF
|
||||
|
||||
(
|
||||
cd "${TARGET_DIR}"
|
||||
python3 - <<'FILE_EOF'
|
||||
import base64
|
||||
png = base64.b64decode(
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAusB9Wn8nKsAAAAASUVORK5CYII="
|
||||
)
|
||||
with open("app.png", "wb") as f:
|
||||
f.write(png)
|
||||
FILE_EOF
|
||||
)
|
||||
|
||||
echo "Qt5 legacy benchmark created at: ${TARGET_DIR}"
|
||||
@@ -0,0 +1,119 @@
|
||||
# GitHub Copilot Repository Instructions: C++ Modernization
|
||||
|
||||
## Project Context
|
||||
- **Language:** C++
|
||||
- **Target Standard:** C++23 (Strict enforcement)
|
||||
- **Migration Goal:** Systematically upgrade legacy C++11/C++14/C++17 code to modern C++23 paradigms.
|
||||
|
||||
## Core Objective
|
||||
Modernize the codebase incrementally and safely. Preserve existing behavior unless the task explicitly requests functional changes. Prefer small, reviewable refactors that improve correctness, safety, readability, and maintainability.
|
||||
|
||||
## Global Migration Principles
|
||||
- Preserve semantics first; modernize second.
|
||||
- Prefer standard C++23 library facilities over custom utilities where equivalent.
|
||||
- Favor compile-time validation, explicit ownership, and strong type safety.
|
||||
- Reduce boilerplate only when readability improves.
|
||||
- Avoid unnecessary churn in code that is already modern and clear.
|
||||
- Keep ABI-sensitive or externally exposed interfaces stable unless breaking changes are explicitly allowed.
|
||||
- For larger migrations, refactor file-by-file or subsystem-by-subsystem.
|
||||
|
||||
## Migration Rules
|
||||
|
||||
### 1. Type Inference & Variables
|
||||
- Replace explicit types with `auto` where the type is obvious from the initializer.
|
||||
- Do not use `auto` when it obscures important type information or changes value/reference semantics unintentionally.
|
||||
- Prefer `const auto` and `const auto&` where appropriate.
|
||||
- Use structured bindings (`auto [x, y] = ...`) instead of `std::tie`, `.first/.second`, or tuple indexing where it improves clarity.
|
||||
- Prefer uniform initialization where appropriate.
|
||||
|
||||
### 2. Memory & Resource Management
|
||||
- Replace raw owning pointers and manual `delete` with `std::unique_ptr` or `std::shared_ptr`.
|
||||
- Prefer `std::unique_ptr` by default; use `std::shared_ptr` only for true shared ownership.
|
||||
- Use `std::make_unique` and `std::make_shared`.
|
||||
- Enforce RAII for all resource management.
|
||||
- Replace manual lifetime management with scoped objects where possible.
|
||||
- Distinguish clearly between owning and non-owning access; prefer references, `std::span`, or observer-style usage for non-owning views.
|
||||
|
||||
### 3. Containers, Views & Strings
|
||||
- Use `std::string_view` for read-only string parameters where lifetime safety is guaranteed.
|
||||
- Never introduce dangling `std::string_view`.
|
||||
- Replace `if (items.find(key) != items.end())` with `if (items.contains(key))` where supported.
|
||||
- Prefer `.starts_with()`, `.ends_with()`, and `.contains()` when they improve readability.
|
||||
- Prefer `std::span` for non-owning contiguous views.
|
||||
- Use `std::mdspan` for multidimensional indexing only where it meaningfully improves safety or clarity.
|
||||
- Prefer standard algorithms and ranges over manual loops when they improve readability and maintainability.
|
||||
- Avoid unnecessary copies; prefer move semantics, `emplace`, and views where safe.
|
||||
|
||||
### 4. Control Flow & Error Handling
|
||||
- Prefer early returns over deep nesting.
|
||||
- Use `[[nodiscard]]` for functions whose return values should not be ignored.
|
||||
- Modernize `std::optional` usage with `.and_then()`, `.transform()`, and `.or_else()` where this makes the logic clearer.
|
||||
- Replace sentinel values with `std::optional`, strong types, or `std::expected` if supported by the project/toolchain.
|
||||
- Preserve existing exception guarantees and error behavior unless changes are explicitly requested.
|
||||
|
||||
### 5. Formatting & Output
|
||||
- Replace `printf` and legacy `<iostream>` console output with `<print>` where toolchain support exists.
|
||||
- Use `std::print` and `std::println` for standard console output.
|
||||
- If `<print>` is unavailable in the project toolchain, note the limitation and prefer the most modern supported alternative.
|
||||
- Do not mix output styles in the same updated code path without a strong reason.
|
||||
|
||||
### 6. Compile-Time Optimization & Templates
|
||||
- Maximize appropriate use of `constexpr`.
|
||||
- Use `consteval` and `constinit` where semantically beneficial.
|
||||
- Replace legacy SFINAE / `std::enable_if` with Concepts and `requires` clauses.
|
||||
- Use `if constexpr` to simplify compile-time branching.
|
||||
- Prefer readable template constraints and diagnostics over complex metaprogramming.
|
||||
|
||||
### 7. API & Interface Modernization
|
||||
- Add `noexcept` where correct and useful.
|
||||
- Use `override` consistently for overridden virtual functions.
|
||||
- Use `final` where appropriate.
|
||||
- Prefer `= default` and `= delete` for special member functions.
|
||||
- Prefer `enum class` over unscoped enums where practical.
|
||||
- Replace output parameters with return values or small result structs where this improves clarity and does not break required interfaces.
|
||||
|
||||
### 8. Concurrency & Time
|
||||
- Prefer modern standard library concurrency primitives.
|
||||
- Use `std::jthread` instead of `std::thread` where automatic joining and cancellation semantics are beneficial.
|
||||
- Prefer typed `std::chrono` durations and literals over raw integer time values.
|
||||
|
||||
## Code Style Enforcement
|
||||
- Avoid C-style macros where `constexpr`, `const`, enums, or inline functions are better.
|
||||
- Never introduce deprecated or removed standard library facilities.
|
||||
- Prefer expressive, self-documenting code over mechanical modernization.
|
||||
- Keep includes minimal and correct.
|
||||
- Avoid hidden lifetime bugs, dangling references, dangling views, and ownership ambiguity.
|
||||
- Preserve repository formatting and local style conventions unless explicitly changing them.
|
||||
|
||||
## Safety Constraints
|
||||
- Do not change business logic unless explicitly requested.
|
||||
- Do not silently alter ownership semantics without calling it out.
|
||||
- Do not replace code with newer constructs if the result is harder to read.
|
||||
- Do not introduce C++23 features that are unsupported by the project compiler/toolchain.
|
||||
- Highlight any modernization that may affect ABI, performance, exception behavior, or object lifetime.
|
||||
|
||||
## Review Checklist
|
||||
For each proposed migration, verify:
|
||||
- Behavior is preserved.
|
||||
- Ownership and lifetime are clearer and safer.
|
||||
- Readability is improved.
|
||||
- Interface compatibility is maintained unless breaking changes are allowed.
|
||||
- C++23 features are applied only where beneficial.
|
||||
- Toolchain compatibility is respected.
|
||||
- Tests and warnings should still pass after the change.
|
||||
|
||||
## Expected Copilot Behavior
|
||||
When modernizing code:
|
||||
1. Start from the existing implementation and refactor incrementally.
|
||||
2. Prefer minimal, reviewable patches over broad rewrites.
|
||||
3. Briefly explain non-trivial modernizations.
|
||||
4. Call out risky or behavior-adjacent changes explicitly.
|
||||
5. Provide optional follow-up refactors separately when they are useful but non-essential.
|
||||
6. Avoid touching unrelated code.
|
||||
|
||||
## Preferred Output Format
|
||||
For each migration task, provide:
|
||||
- the modernized code,
|
||||
- a short rationale,
|
||||
- any compatibility/toolchain caveats,
|
||||
- and optional next-step improvements.tes
|
||||
@@ -0,0 +1,152 @@
|
||||
Migrate the legacy Qt5/C++11 desktop application to Qt6/C++23 and validate the migration completely using the repository’s Docker-based CI workflow.
|
||||
|
||||
Operating mode:
|
||||
- Execute the task autonomously from analysis through validation.
|
||||
- Do not stop after code edits; continue until configure, build, tests, and policy checks have been attempted in the CI container workflow.
|
||||
- Do not ask for confirmation between normal implementation steps.
|
||||
- Only stop early if the repository is missing required source material, the task is logically impossible, or a destructive action would be required.
|
||||
|
||||
Project boundaries:
|
||||
- Read the legacy source project from ${PROJECT_DIR}.
|
||||
- Write the migrated project into qt6-after/qt6-migrated-benchmark.
|
||||
- Do not modify the legacy source tree in place.
|
||||
- Keep the migration isolated to the target tree and related CI/build/test files only when necessary.
|
||||
|
||||
Primary migration goals:
|
||||
- Update the build system from Qt5 to Qt6.
|
||||
- Upgrade the language standard from C++11 to C++23.
|
||||
- Keep Qt Core, Gui, and Widgets explicitly linked.
|
||||
- Replace QRegExp with QRegularExpression.
|
||||
- Replace QDesktopWidget and QApplication::desktop() usage with QScreen-based Qt6 APIs.
|
||||
- Remove legacy QTextCodec usage and adopt modern Qt6-safe text handling.
|
||||
- Replace old SIGNAL/SLOT syntax with function-pointer connect syntax.
|
||||
- Replace legacy null pointer literals with nullptr.
|
||||
- Preserve .ui integration.
|
||||
- Preserve .qrc integration.
|
||||
- Preserve application behavior unless a Qt6-compatible adaptation is strictly necessary.
|
||||
|
||||
Testing requirements:
|
||||
- For every code change inside a method, add at least three tests covering the changed behavior.
|
||||
- Place all generated tests in qt6-after/qt6-migrated-benchmark/tests.
|
||||
- Keep test filenames compatible with repository policy checks, for example patterns like:
|
||||
- test_<name>.cpp
|
||||
- <name>_test.cpp
|
||||
- <name>test.cpp
|
||||
- <name>gtest.cpp
|
||||
- Update CMake so the migrated application and all tests are buildable and runnable with CTest.
|
||||
- Ensure tests are actually registered with CTest.
|
||||
|
||||
Container-first build policy:
|
||||
- Use lifemaps/ci-cpp:latest as the authoritative environment for configure, build, test, and policy validation.
|
||||
- Do not rely on host-installed build tools as a substitute for missing container tools.
|
||||
- Execute all validation commands inside Docker using the mounted repository workspace.
|
||||
- Treat Dockerfile.ci as the source of truth for CI dependencies and container tool availability.
|
||||
|
||||
Execution plan:
|
||||
1. Inspect the legacy project under ${PROJECT_DIR}.
|
||||
2. Inspect the target tree qt6-after/qt6-migrated-benchmark.
|
||||
3. Identify all Qt5/C++11 constructs that must be migrated.
|
||||
4. Apply the migration incrementally in the target tree.
|
||||
5. Add or update tests together with each behavior-relevant code change.
|
||||
6. Update CMake and test registration.
|
||||
7. Validate inside the Docker container.
|
||||
8. If validation reveals missing tools inside the container, update Dockerfile.ci, rebuild the image, and rerun validation.
|
||||
9. Repeat until full success or until a genuine project defect remains.
|
||||
|
||||
Mandatory container validation sequence:
|
||||
- Run CMake configure inside lifemaps/ci-cpp:latest.
|
||||
- Run the build inside lifemaps/ci-cpp:latest.
|
||||
- Run tests with CTest inside lifemaps/ci-cpp:latest.
|
||||
- Only if tests succeed, run:
|
||||
python3 ci/check_pr_policies.py
|
||||
inside the same Docker container against the mounted workspace.
|
||||
|
||||
Missing-tool remediation loop:
|
||||
- If configure, build, test, or policy validation fails because a required tool or package is missing in the container:
|
||||
- identify the missing tool precisely
|
||||
- update Dockerfile.ci to install it
|
||||
- rebuild the Docker image
|
||||
- rerun the full validation sequence in the rebuilt image
|
||||
- Do not stop after rebuilding once if another missing dependency appears.
|
||||
- Continue until:
|
||||
- the environment is complete and the next failure is a real project/code issue, or
|
||||
- the entire validation flow succeeds
|
||||
|
||||
Failure classification rules:
|
||||
- Treat these as environment failures:
|
||||
- command not found
|
||||
- missing compiler/toolchain utility
|
||||
- missing Qt development package
|
||||
- missing CMake/Ninja/CTest support tool
|
||||
- missing formatting or git verification dependency needed by ci/check_pr_policies.py
|
||||
- Treat these as project failures:
|
||||
- compile errors in migrated source
|
||||
- linker errors caused by project configuration or code
|
||||
- failing tests
|
||||
- policy check failures caused by formatting, missing tests, or related project issues introduced by the migration
|
||||
|
||||
Policy-check awareness:
|
||||
- The repository policy script checks changed C/C++ files for formatting via clang-format.
|
||||
- The policy script also expects related tests for changed C/C++ files.
|
||||
- The policy script verifies commit signatures in its comparison range.
|
||||
- When running local validation in the container, ensure the workspace and git metadata are available so the script can evaluate diffs properly.
|
||||
- If the script fails because of issues caused by your migration, fix them and rerun validation.
|
||||
- Do not claim policy success unless the script passes.
|
||||
|
||||
Container command expectations:
|
||||
- Use Docker commands that mount the current repository into /workspace or an equivalent work directory.
|
||||
- Run commands from the mounted repository root.
|
||||
- Use explicit configure/build/test commands rather than vague summaries.
|
||||
- Reuse the same image name lifemaps/ci-cpp:latest unless Dockerfile.ci changes require rebuilding that image.
|
||||
|
||||
Recommended validation shape:
|
||||
- Configure:
|
||||
cmake -S qt6-after/qt6-migrated-benchmark -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug
|
||||
- Build:
|
||||
cmake --build build --parallel
|
||||
- Test:
|
||||
ctest --test-dir build --output-on-failure
|
||||
- Policy:
|
||||
python3 ci/check_pr_policies.py
|
||||
- If the repository uses a different build directory or requires additional flags discovered during inspection, adapt accordingly.
|
||||
|
||||
Dockerfile maintenance rules:
|
||||
- If you modify Dockerfile.ci, keep changes minimal and focused on missing CI dependencies.
|
||||
- Do not remove already needed packages without evidence.
|
||||
- After editing Dockerfile.ci, rebuild the CI image before retrying validation.
|
||||
- Use the rebuilt image for all subsequent validation attempts.
|
||||
|
||||
Change reporting requirements:
|
||||
- Briefly explain each migration change.
|
||||
- Group the explanation by:
|
||||
- CMake / build-system migration
|
||||
- Qt API replacements
|
||||
- C++ modernization
|
||||
- UI/resource preservation
|
||||
- tests added
|
||||
- Dockerfile.ci / container updates
|
||||
- Include a concise changed-files summary.
|
||||
|
||||
Completion criteria:
|
||||
- Success requires all of the following:
|
||||
- migrated project exists under qt6-after/qt6-migrated-benchmark
|
||||
- configure succeeds in the Docker container
|
||||
- build succeeds in the Docker container
|
||||
- tests succeed in the Docker container
|
||||
- python3 ci/check_pr_policies.py succeeds in the Docker container after tests pass
|
||||
- If full success is not achieved, continue until the remaining blocker is a genuine project problem rather than a missing CI dependency.
|
||||
|
||||
Final response requirements:
|
||||
- State whether the migration is fully validated or which blocker remains.
|
||||
- List the exact Docker commands used for:
|
||||
- image rebuild
|
||||
- configure
|
||||
- build
|
||||
- test
|
||||
- policy check
|
||||
- For every failed attempt, report:
|
||||
- the exact command
|
||||
- the key error
|
||||
- whether it was an environment issue or a project issue
|
||||
- the fix applied, if any
|
||||
- End with a short summary of what remains, if anything.
|
||||
Executable
+50
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT_DIR="${1:-qt5-before/qt5-legacy-migration-benchmark}"
|
||||
COPILOT_MODEL="${2:-qwen3.5-397b-a17b}"
|
||||
|
||||
need_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || {
|
||||
echo "ERROR: '$1' not found in PATH." >&2
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
need_cmd entire
|
||||
need_cmd copilot
|
||||
need_cmd git
|
||||
|
||||
if ! git rev-parse --show-toplevel >/dev/null 2>&1; then
|
||||
echo "ERROR: Dieses Skript muss innerhalb eines bestehenden Git-Repositories gestartet werden." >&2
|
||||
echo "Bitte zuerst im Repo-Root 'git init' oder in einem bestehenden Repo arbeiten." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
if [ ! -d "$PROJECT_DIR" ]; then
|
||||
echo "ERROR: project directory '$PROJECT_DIR' not found relative to repo root '$REPO_ROOT'." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Repo root: $REPO_ROOT"
|
||||
echo "Legacy project: $PROJECT_DIR"
|
||||
echo "Copilot model: $COPILOT_MODEL"
|
||||
|
||||
entire agent add copilot-cli
|
||||
entire status
|
||||
|
||||
git add .
|
||||
if git diff --cached --quiet; then
|
||||
git commit --allow-empty -m "baseline: Qt5/C++11 legacy benchmark before Qt6/C++23 migration"
|
||||
else
|
||||
git commit -m "baseline: Qt5/C++11 legacy benchmark before Qt6/C++23 migration"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== Checkpoints vor der Session =="
|
||||
entire checkpoint list
|
||||
|
||||
envsubst < scripts/migration.prompt
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT_DIR="${1:-qt5-before/qt5-legacy-migration-benchmark}"
|
||||
COPILOT_MODEL="${2:-qwen3.5-397b-a17b}"
|
||||
|
||||
need_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || {
|
||||
echo "ERROR: '$1' not found in PATH." >&2
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
need_cmd entire
|
||||
need_cmd copilot
|
||||
need_cmd git
|
||||
|
||||
echo
|
||||
echo "== Git status after Copilot session =="
|
||||
git status --short
|
||||
|
||||
git add .
|
||||
|
||||
if git diff --cached --quiet; then
|
||||
echo "No changes to commit."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git commit -m "migrate: Qt5/C++11 app to Qt6/C++23 with tests and modern Qt APIs"
|
||||
|
||||
echo
|
||||
echo "== Checkpoints nach der Session =="
|
||||
entire checkpoint list
|
||||
entire checkpoint explain HEAD || true
|
||||
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT_DIR="${1:-qt5-before/qt5-legacy-migration-benchmark}"
|
||||
COPILOT_MODEL="${2:-qwen3.5-397b-a17b}"
|
||||
|
||||
need_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || {
|
||||
echo "ERROR: '$1' not found in PATH." >&2
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
need_cmd entire
|
||||
need_cmd copilot
|
||||
need_cmd git
|
||||
|
||||
if ! git rev-parse --show-toplevel >/dev/null 2>&1; then
|
||||
echo "ERROR: Dieses Skript muss innerhalb eines bestehenden Git-Repositories gestartet werden." >&2
|
||||
echo "Bitte zuerst im Repo-Root 'git init' oder in einem bestehenden Repo arbeiten." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
if [ ! -d "$PROJECT_DIR" ]; then
|
||||
echo "ERROR: project directory '$PROJECT_DIR' not found relative to repo root '$REPO_ROOT'." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Repo root: $REPO_ROOT"
|
||||
echo "Legacy project: $PROJECT_DIR"
|
||||
echo "Copilot model: $COPILOT_MODEL"
|
||||
|
||||
entire agent add copilot-cli
|
||||
entire status
|
||||
|
||||
git add .
|
||||
if git diff --cached --quiet; then
|
||||
git commit --allow-empty -m "baseline: Qt5/C++11 legacy benchmark before Qt6/C++23 migration"
|
||||
else
|
||||
git commit -m "baseline: Qt5/C++11 legacy benchmark before Qt6/C++23 migration"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== Checkpoints vor der Session =="
|
||||
entire checkpoint list
|
||||
|
||||
envsubst < scripts/migration.prompt | copilot --model "${COPILOT_MODEL}"
|
||||
|
||||
echo
|
||||
echo "== Git status after Copilot session =="
|
||||
git status --short
|
||||
git add .
|
||||
|
||||
if git diff --cached --quiet; then
|
||||
echo "No changes to commit."
|
||||
else
|
||||
git commit -m "migrate: Qt5/C++11 app to Qt6/C++23 with tests and modern Qt APIs"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== Checkpoints nach der Session =="
|
||||
entire checkpoint list
|
||||
entire checkpoint explain HEAD || true
|
||||
|
||||
read -r -p "Optional Rewind testen? [y/N] " DO_REWIND
|
||||
if [[ "${DO_REWIND:-N}" =~ ^[Yy]$ ]]; then
|
||||
if ! entire checkpoint rewind; then
|
||||
echo "WARN: rewind not supported or failed."
|
||||
fi
|
||||
fi
|
||||
|
||||
read -r -p "Optional Session-Resume-Hinweis ausgeben? [y/N] " DO_RESUME
|
||||
if [[ "${DO_RESUME:-N}" =~ ^[Yy]$ ]]; then
|
||||
CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
|
||||
if ! entire session resume "${CURRENT_BRANCH}"; then
|
||||
echo "WARN: resume not supported or failed."
|
||||
fi
|
||||
fi
|
||||
Executable
+68
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT_DIR="${1:-qt5-before/qt5-legacy-migration-benchmark}"
|
||||
COPILOT_MODEL="${2:-qwen3.5-397b-a17b}"
|
||||
|
||||
need_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || {
|
||||
echo "ERROR: '$1' not found in PATH." >&2
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
need_cmd entire
|
||||
need_cmd copilot
|
||||
need_cmd git
|
||||
|
||||
if ! git rev-parse --show-toplevel >/dev/null 2>&1; then
|
||||
echo "ERROR: Dieses Skript muss innerhalb eines bestehenden Git-Repositories gestartet werden." >&2
|
||||
echo "Bitte zuerst im Repo-Root 'git init' oder in einem bestehenden Repo arbeiten." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
if [ ! -d "$PROJECT_DIR" ]; then
|
||||
echo "ERROR: project directory '$PROJECT_DIR' not found relative to repo root '$REPO_ROOT'." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Repo root: $REPO_ROOT"
|
||||
echo "Legacy project: $PROJECT_DIR"
|
||||
echo "Copilot model: $COPILOT_MODEL"
|
||||
|
||||
entire agent add copilot-cli
|
||||
entire status
|
||||
|
||||
git add .
|
||||
if git diff --cached --quiet; then
|
||||
git commit --allow-empty -m "baseline: Qt5/C++11 legacy benchmark before Qt6/C++23 migration"
|
||||
else
|
||||
git commit -m "baseline: Qt5/C++11 legacy benchmark before Qt6/C++23 migration"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== Checkpoints vor der Session =="
|
||||
entire checkpoint list
|
||||
|
||||
envsubst < scripts/migration.prompt | copilot --model "${COPILOT_MODEL}"
|
||||
|
||||
echo
|
||||
echo "== Git status after Copilot session =="
|
||||
git status --short
|
||||
|
||||
git add .
|
||||
|
||||
if git diff --cached --quiet; then
|
||||
echo "No changes to commit."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git commit -m "migrate: Qt5/C++11 app to Qt6/C++23 with tests and modern Qt APIs"
|
||||
|
||||
echo
|
||||
echo "== Checkpoints nach der Session =="
|
||||
entire checkpoint list
|
||||
entire checkpoint explain HEAD || true
|
||||
Executable
+149
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
red() { printf "\033[31m%s\033[0m\n" "$*"; }
|
||||
green() { printf "\033[32m%s\033[0m\n" "$*"; }
|
||||
yellow() { printf "\033[33m%s\033[0m\n" "$*"; }
|
||||
blue() { printf "\033[34m%s\033[0m\n" "$*"; }
|
||||
|
||||
fail() {
|
||||
red "FEHLER: $*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
check_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || fail "'$1' nicht gefunden"
|
||||
}
|
||||
|
||||
mask() {
|
||||
local s="${1:-}"
|
||||
local n=${#s}
|
||||
if [ "$n" -le 8 ]; then
|
||||
printf '********'
|
||||
else
|
||||
printf '%s****%s' "${s:0:4}" "${s: -4}"
|
||||
fi
|
||||
}
|
||||
|
||||
check_env() {
|
||||
[ -n "${COPILOT_PROVIDER_TYPE:-}" ] || fail "COPILOT_PROVIDER_TYPE fehlt"
|
||||
[ -n "${COPILOT_PROVIDER_API_KEY:-}" ] || fail "COPILOT_PROVIDER_API_KEY fehlt"
|
||||
[ -n "${COPILOT_PROVIDER_BASE_URL:-}" ] || fail "COPILOT_PROVIDER_BASE_URL fehlt"
|
||||
[ -n "${COPILOT_MODEL:-}" ] || fail "COPILOT_MODEL fehlt"
|
||||
}
|
||||
|
||||
print_env_summary() {
|
||||
blue "== Konfiguration =="
|
||||
echo "Provider : ${COPILOT_PROVIDER_TYPE}"
|
||||
echo "Base URL : ${COPILOT_PROVIDER_BASE_URL}"
|
||||
echo "Modell : ${COPILOT_MODEL}"
|
||||
echo "API Key : $(mask "${COPILOT_PROVIDER_API_KEY}")"
|
||||
echo
|
||||
}
|
||||
|
||||
probe_models() {
|
||||
blue "== Prüfe Models-Endpoint =="
|
||||
local models_url="${COPILOT_PROVIDER_BASE_URL%/}/models"
|
||||
|
||||
local http_code
|
||||
http_code="$(curl -sS -o /tmp/copilot_models_probe.json \
|
||||
-w "%{http_code}" \
|
||||
-H "Authorization: Bearer ${COPILOT_PROVIDER_API_KEY}" \
|
||||
"$models_url" || true)"
|
||||
|
||||
echo "GET $models_url"
|
||||
echo "HTTP $http_code"
|
||||
|
||||
if [ "$http_code" = "200" ]; then
|
||||
green "Models-Endpoint erreichbar"
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
echo
|
||||
yellow "Gefundene Modelle (erste 20):"
|
||||
jq -r '
|
||||
if .data then .data[]?.id
|
||||
elif type=="array" then .[]?.id
|
||||
else empty end
|
||||
' /tmp/copilot_models_probe.json | head -20
|
||||
echo
|
||||
if jq -e --arg model "${COPILOT_MODEL}" '
|
||||
if .data then any(.data[]?; .id == $model)
|
||||
elif type=="array" then any(.[]?; .id == $model)
|
||||
else false end
|
||||
' /tmp/copilot_models_probe.json >/dev/null 2>&1; then
|
||||
green "Modell '${COPILOT_MODEL}' im Models-Endpoint gefunden"
|
||||
else
|
||||
yellow "Modell '${COPILOT_MODEL}' nicht eindeutig im Models-Endpoint gefunden"
|
||||
fi
|
||||
else
|
||||
yellow "jq nicht installiert; JSON-Antwort nicht geparst"
|
||||
fi
|
||||
else
|
||||
red "Models-Endpoint nicht erfolgreich erreichbar"
|
||||
echo
|
||||
sed -n '1,120p' /tmp/copilot_models_probe.json || true
|
||||
echo
|
||||
fi
|
||||
}
|
||||
|
||||
probe_chat() {
|
||||
blue "== Prüfe Chat-Completions minimal =="
|
||||
local chat_url="${COPILOT_PROVIDER_BASE_URL%/}/chat/completions"
|
||||
|
||||
cat >/tmp/copilot_chat_probe.json <<JSON
|
||||
{
|
||||
"model": "${COPILOT_MODEL}",
|
||||
"messages": [
|
||||
{ "role": "user", "content": "Reply with exactly: OK" }
|
||||
],
|
||||
"stream": false
|
||||
}
|
||||
JSON
|
||||
|
||||
local http_code
|
||||
http_code="$(curl -sS -o /tmp/copilot_chat_probe_response.json \
|
||||
-w "%{http_code}" \
|
||||
-H "Authorization: Bearer ${COPILOT_PROVIDER_API_KEY}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @/tmp/copilot_chat_probe.json \
|
||||
"$chat_url" || true)"
|
||||
|
||||
echo "POST $chat_url"
|
||||
echo "HTTP $http_code"
|
||||
|
||||
if [ "$http_code" = "200" ]; then
|
||||
green "Chat-Completions funktioniert"
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
echo
|
||||
yellow "Antwortauszug:"
|
||||
jq -r '.choices[0].message.content // .choices[0].delta.content // "keine textantwort gefunden"' \
|
||||
/tmp/copilot_chat_probe_response.json
|
||||
echo
|
||||
else
|
||||
sed -n '1,80p' /tmp/copilot_chat_probe_response.json || true
|
||||
fi
|
||||
else
|
||||
red "Chat-Completions fehlgeschlagen"
|
||||
echo
|
||||
sed -n '1,160p' /tmp/copilot_chat_probe_response.json || true
|
||||
echo
|
||||
fi
|
||||
}
|
||||
|
||||
run_copilot() {
|
||||
blue "== Starte Copilot CLI =="
|
||||
exec copilot "$@"
|
||||
}
|
||||
|
||||
main() {
|
||||
check_cmd curl
|
||||
check_cmd copilot
|
||||
check_env
|
||||
print_env_summary
|
||||
probe_models
|
||||
echo
|
||||
probe_chat
|
||||
echo
|
||||
run_copilot "$@"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in new issue
Block a user