diff --git a/workstation-setup/src/CMakeLists.txt b/workstation-setup/src/CMakeLists.txt index 602779b..0e1624f 100644 --- a/workstation-setup/src/CMakeLists.txt +++ b/workstation-setup/src/CMakeLists.txt @@ -11,11 +11,9 @@ qt_add_qml_module(nixos-workstations-setup Main.qml ) -target_compile_definitions(nixos-workstations-setup +target_include_directories(nixos-workstations-setup PRIVATE - PASSWORD_HELPER_PATH="${PASSWORD_HELPER_PATH}" - PIN_HELPER_PATH="${PIN_HELPER_PATH}" - TARGET_USER="${TARGET_USER}" + ${CMAKE_CURRENT_BINARY_DIR}/../generated ) target_link_libraries(nixos-workstations-setup diff --git a/workstation-setup/src/Config.h.in b/workstation-setup/src/Config.h.in new file mode 100644 index 0000000..ab15c0d --- /dev/null +++ b/workstation-setup/src/Config.h.in @@ -0,0 +1,4 @@ +#pragma once + +#define NIXOS_WORKSTATIONS_PASSWORD_HELPER_PATH R"(@PASSWORD_HELPER_PATH@)" +#define NIXOS_WORKSTATIONS_PIN_HELPER_PATH R"(@PIN_HELPER_PATH@)" diff --git a/workstation-setup/src/main.cpp b/workstation-setup/src/main.cpp index ca4dedc..52de545 100644 --- a/workstation-setup/src/main.cpp +++ b/workstation-setup/src/main.cpp @@ -1,16 +1,38 @@ #include "ProvisioningBackend.h" +#include +#include +#include +#include +#include #include #include #include #include #include +#include + +#include #include int main(int argc, char *argv[]) { - // Les champs contiennent temporairement des secrets : pas de core dump. + // --diagnose doit aussi fonctionner depuis un TTY sans session graphique. + // QGuiApplication reste utilisé pour partager exactement le même parsing, + // mais la plate-forme Qt passe alors en mode offscreen si rien n'est imposé. + bool diagnoseRequested = false; + for (int i = 1; i < argc; ++i) { + if (std::strcmp(argv[i], "--diagnose") == 0) { + diagnoseRequested = true; + break; + } + } + if (diagnoseRequested && qEnvironmentVariableIsEmpty("QT_QPA_PLATFORM")) { + qputenv("QT_QPA_PLATFORM", QByteArrayLiteral("offscreen")); + } + + // Les champs contiennent temporairement des secrets : aucun core dump. rlimit coreLimit { 0, 0 }; setrlimit(RLIMIT_CORE, &coreLimit); @@ -19,34 +41,89 @@ int main(int argc, char *argv[]) QGuiApplication::setOrganizationName(QStringLiteral("Raspot")); QGuiApplication::setOrganizationDomain(QStringLiteral("raspot.in")); QGuiApplication::setApplicationName(QStringLiteral("NixOS Workstations Setup")); + QGuiApplication::setApplicationVersion(QStringLiteral("1.1.0")); QGuiApplication::setDesktopFileName(QStringLiteral("org.raspot.nixosworkstations.setup")); + QCommandLineParser parser; + parser.setApplicationDescription(QStringLiteral("Assistant de finalisation NixOS Workstations")); + parser.addHelpOption(); + parser.addVersionOption(); + + QCommandLineOption targetUserOption( + QStringList { QStringLiteral("u"), QStringLiteral("target-user") }, + QStringLiteral("Compte autorisé à exécuter l'assistant."), + QStringLiteral("user")); + parser.addOption(targetUserOption); + + QCommandLineOption diagnoseOption( + QStringList { QStringLiteral("diagnose") }, + QStringLiteral("Affiche l'état de l'assistant puis quitte.")); + parser.addOption(diagnoseOption); + + QCommandLineOption forceUiOption( + QStringList { QStringLiteral("force-ui") }, + QStringLiteral("Affiche l'interface même si la configuration est déjà terminée.")); + parser.addOption(forceUiOption); + + parser.process(app); + + const QString targetUser = parser.value(targetUserOption).trimmed(); + if (targetUser.isEmpty()) { + qCritical().noquote() + << "ERREUR: --target-user est obligatoire. Exemple:" + << QCoreApplication::applicationName() + << "--target-user alice"; + return 2; + } + + ProvisioningBackend provisioning(targetUser); + + if (parser.isSet(diagnoseOption)) { + qInfo().noquote() << "version=1.1.0"; + qInfo().noquote() << "current_user=" + provisioning.currentUser(); + qInfo().noquote() << "target_user=" + provisioning.targetUser(); + qInfo().noquote() << "authorized=" + (provisioning.authorizedUser() ? QStringLiteral("yes") : QStringLiteral("no")); + qInfo().noquote() << "state_dir=" + provisioning.stateDirectory(); + qInfo().noquote() << "password_marker=" + provisioning.passwordMarker(); + qInfo().noquote() << "password_done=" + (provisioning.passwordDone() ? QStringLiteral("yes") : QStringLiteral("no")); + qInfo().noquote() << "pin_marker=" + provisioning.pinMarker(); + qInfo().noquote() << "pin_done=" + (provisioning.pinDone() ? QStringLiteral("yes") : QStringLiteral("no")); + qInfo().noquote() << "log=" + provisioning.diagnosticLogPath(); + return provisioning.authorizedUser() ? 0 : 3; + } + + // Le lanceur filtre déjà le compte, mais le backend vérifie également. + // Contrairement à la V1, on ne quitte plus sans explication. + if (!provisioning.authorizedUser()) { + qCritical().noquote() + << "ERREUR: l'assistant est prévu pour" + << provisioning.targetUser() + << "mais il est exécuté par" + << provisioning.currentUser(); + return 3; + } + + if (provisioning.complete() && !parser.isSet(forceUiOption)) { + qInfo().noquote() + << "NixOS Workstations Setup: configuration déjà terminée." + << "Utilisez --force-ui pour afficher l'écran récapitulatif."; + return 0; + } + QIcon::setThemeName(QStringLiteral("breeze")); if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE")) { QQuickStyle::setStyle(QStringLiteral("Basic")); } - ProvisioningBackend provisioning; - - // Défense en profondeur : le lanceur filtre déjà l'utilisateur, mais - // le backend refuse également toute opération pour un autre compte. - if (!provisioning.authorizedUser()) { - return 0; - } - - // Si les deux marqueurs existent, l'assistant n'a plus rien à faire. - if (provisioning.complete()) { - return 0; - } - QQmlApplicationEngine engine; engine.rootContext()->setContextProperty(QStringLiteral("provisioning"), &provisioning); engine.loadFromModule(QStringLiteral("org.raspot.nixosworkstations.setup"), QStringLiteral("Main")); if (engine.rootObjects().isEmpty()) { - return 1; + qCritical() << "ERREUR: impossible de charger l'interface QML."; + return 4; } return app.exec();