3 Commits
Author SHA1 Message Date
tuxgyverandClaude Opus 5 bc080fd76a chore: version 0.1.3
Premiere version publiee avec un binaire Windows fonctionnel : le .exe
produit sous Wine demarrait sans plugin de plateforme Qt (voir CHANGELOG).
Ajoute egalement le Makefile, le README et la cible de publication
multi-depots.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 22:53:01 +02:00
tuxgyverandClaude Opus 5 59b6c75942 fix: le .exe Windows demarrait sans plugin de plateforme Qt
Le hook PySide6 de PyInstaller importe QtCore pour localiser les plugins Qt.
Depuis Qt 6.10, Qt6Core.dll est lie a l'ICU de Windows (icuuc.dll, System32),
que Wine n'implemente pas : l'import echouait, le hook ne collectait aucun
plugin, et le binaire produit refusait de demarrer sous Windows avec
« could not initialize Qt platform plugin "windows" ».

- La build Wine epingle PySide6<6.10 (PYSIDE6_CONSTRAINT pour surcharger).
- Verification avant compilation que PySide6 s'importe reellement.
- Verification apres compilation que qwindows.dll est embarque.
- Reinstallation des dependances declenchee par empreinte de requirements.txt
  et de la contrainte, au lieu de la seule presence de PyInstaller.

Binaire verifie sous Wine : GUI (fenetre a trois onglets) et CLI OK, 45 Mo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 22:46:00 +02:00
tuxgyverandClaude Opus 5 599192fd67 build: Makefile categorise, README et compilation Windows depuis Linux
- Makefile avec aide auto-documentee par categories (`make help`) :
  installation, utilisation, compilation, publication, nettoyage.
- packaging/build_windows_wine.sh : produit le .exe Windows natif depuis
  Linux via un PyInstaller Windows execute dans un prefixe Wine dedie
  (PyInstaller ne cross-compilant pas). Installation des dependances
  idempotente, builds suivants incrementaux.
- README.md : fonctionnalites, usage GUI/CLI, compilation, publication.
- `make publish` pousse branche et tags vers tous les depots configures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 22:11:39 +02:00
6 changed files with 336 additions and 1 deletions
+2
View File
@@ -5,3 +5,5 @@ dist/
*.spec
.build-venv-linux/
.build-venv-windows/
.build-wine/
.build-wine-cache/
+16
View File
@@ -1,5 +1,21 @@
# Changelog
## [0.1.3] - 2026-09-08
### Fixed
- Le binaire Windows produit sous Wine ne démarrait pas (« could not initialize
Qt platform plugin "windows" ») : le hook PySide6 de PyInstaller importe
QtCore pour localiser les plugins Qt, or Qt 6.10+ lie `Qt6Core.dll` à l'ICU
de Windows (`icuuc.dll`), absent de Wine. L'import échouait et aucun plugin
n'était embarqué. La compilation Windows épingle désormais `PySide6<6.10` et
vérifie explicitement l'import de PySide6 puis la présence de `qwindows.dll`.
### Added
- `Makefile` avec aide auto-documentée par catégories (`make help`).
- `packaging/build_windows_wine.sh` : production du `.exe` Windows depuis Linux.
- `README.md`.
- `make publish` : pousse branche et tags vers tous les dépôts Gitea configurés.
## [0.1.2] - 2026-09-04
### Changed
+87
View File
@@ -0,0 +1,87 @@
# JoinDomainGUI — diagnostic reseau AD + jointure de domaine
# `make` seul (ou `make help`) affiche les cibles disponibles.
.DEFAULT_GOAL := help
VENV := .build-venv-linux
PY := $(VENV)/bin/python
PIP := $(VENV)/bin/pip
VERSION := $(shell sed -n 's/^__version__ = "\(.*\)"/\1/p' domainjoin/__init__.py)
DOMAIN ?= h3adm.lan
BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
REMOTES := $(shell git remote)
##@ 📦 Installation
$(VENV)/bin/python:
python3 -m venv --system-site-packages $(VENV)
$(PIP) install --upgrade pip -q
$(PIP) install -q -r requirements.txt
.PHONY: install
install: $(VENV)/bin/python ## Cree l'environnement virtuel et installe les dependances
@echo "✅ Environnement pret : $(VENV)"
##@ 🚀 Utilisation
.PHONY: run
run: install ## Lance l'interface graphique
$(PY) main.py
.PHONY: diagnose
diagnose: install ## Lance le diagnostic reseau en CLI (make diagnose DOMAIN=exemple.lan)
$(PY) main.py diagnose --domain $(DOMAIN)
##@ 🏗️ Compilation
.PHONY: build
build: build-linux build-windows ## Compile les binaires Linux et Windows
.PHONY: build-linux
build-linux: ## Compile le binaire Linux autonome (dist/JoinDomainGUI)
./packaging/build_linux.sh
.PHONY: build-windows
build-windows: ## Compile le .exe Windows depuis Linux via Wine (dist/windows/JoinDomainGUI.exe)
./packaging/build_windows_wine.sh
##@ 🚢 Publication
.PHONY: remotes
remotes: ## Liste les depots distants configures
@git remote -v | awk '$$3 == "(push)" { printf " %-10s %s\n", $$1, $$2 }'
.PHONY: publish
publish: ## Pousse la branche courante et les tags vers tous les depots (Gitea)
@git diff --quiet HEAD || { echo "❌ Modifications non commitees — commit avant de publier."; exit 1; }
@for remote in $(REMOTES); do \
echo "🚀 $$remote ← $(BRANCH)"; \
git push $$remote $(BRANCH) || exit 1; \
git push $$remote --tags || exit 1; \
done
@echo "✅ Publie sur : $(REMOTES)"
##@ 🧹 Nettoyage
.PHONY: clean
clean: ## Supprime les artefacts de compilation et les caches Python
rm -rf build dist
find . -path ./$(VENV) -prune -o -name '__pycache__' -type d -print0 | xargs -0 rm -rf
.PHONY: distclean
distclean: clean ## Nettoyage complet : + environnements virtuels, prefixe Wine et telechargements
rm -rf $(VENV) .build-venv-windows .build-wine .build-wine-cache
##@ ️ Aide
.PHONY: version
version: ## Affiche la version courante
@echo "JoinDomainGUI $(VERSION)"
.PHONY: help
help: ## Affiche cette aide
@echo "JoinDomainGUI $(VERSION)"
@awk 'BEGIN {FS = ":.*?## "} \
/^[a-zA-Z0-9_.-]+:.*?##/ { printf " \033[36m%-16s\033[0m %s\n", $$1, $$2 } \
/^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) }' $(MAKEFILE_LIST)
@echo ""
+121
View File
@@ -0,0 +1,121 @@
# JoinDomainGUI
Outil de **diagnostic réseau Active Directory** et de **jointure de domaine**,
avec interface graphique (PySide6) et interface en ligne de commande.
Fonctionne sous **Linux** (`realmd`) et sous **Windows** (PowerShell `Add-Computer`),
le backend étant choisi automatiquement selon la plateforme.
## Fonctionnalités
- **Diagnostic réseau AD** : résolution DNS du domaine, enregistrements SRV
(LDAP / Kerberos), ping des contrôleurs de domaine, test des ports AD
(53, 88, 389, 445, 464, 636, 3268), synchronisation NTP et présence des
outils système requis.
- **Jointure de domaine** avec unité d'organisation et nom de machine
optionnels, et détection du besoin de redémarrage.
- **Installation des prérequis Linux** manquants en un clic ou une commande
(`realmd`, `sssd`, `adcli`, `samba-common-bin`, `packagekit` via `apt-get`).
- **Interface graphique** à trois onglets : Diagnostic réseau, Rejoindre le
domaine, À propos.
- **Interface en ligne de commande** utilisable sans environnement graphique
(SSH, déploiement scripté) : la CLI n'importe jamais PySide6.
- **Le mot de passe ne transite jamais par la ligne de commande** : il est
transmis au sous-processus via stdin ou son environnement, et n'apparaît
donc pas dans `ps` ni dans l'historique du shell.
## Installation
```bash
make install # crée l'environnement virtuel et installe les dépendances
```
Dépendances : Python 3.11+, `PySide6`, `dnspython`, `ntplib`.
## Utilisation
### Interface graphique
```bash
make run # depuis les sources
sudo ./dist/JoinDomainGUI # binaire autonome Linux
```
La jointure de domaine nécessite les droits root / administrateur ; le
diagnostic, non.
### Ligne de commande
```bash
# Diagnostic réseau
python main.py diagnose --domain exemple.lan
make diagnose DOMAIN=exemple.lan
# Jointure de domaine (root / administrateur requis)
echo 'motdepasse' | sudo python main.py join \
--domain exemple.lan --username administrateur --password-stdin
# Installation des prérequis système (Linux / apt uniquement)
sudo python main.py install-prereqs
```
Sans mot de passe fourni, il est demandé de façon interactive et masquée.
`--password` existe mais est déconseillé (visible dans `ps` et l'historique).
Code de sortie : `0` si tout va bien, `1` si un test échoue ou si la jointure
échoue, `2` en cas de droits insuffisants ou de backend indisponible.
## Compilation des binaires
```bash
make build-linux # -> dist/JoinDomainGUI (ELF autonome)
make build-windows # -> dist/windows/JoinDomainGUI.exe (PE64 autonome)
make build # les deux
```
PyInstaller ne fait pas de cross-compilation. Le binaire Windows est donc
produit depuis Linux en exécutant un vrai PyInstaller Windows dans un
préfixe **Wine** dédié (`packaging/build_windows_wine.sh`) : le `.exe` obtenu
est un binaire Windows natif. Le premier appel télécharge un Python Windows
embarqué et les dépendances (plusieurs minutes) ; les suivants sont
incrémentaux.
Sur une machine Windows, `packaging/build_windows.bat` fait le même travail
nativement.
La build Wine épingle **Qt 6.9** (`PySide6<6.10`) : à partir de Qt 6.10,
`Qt6Core.dll` dépend de l'ICU fourni par Windows (`icuuc.dll` dans `System32`),
que Wine n'implémente pas. PySide6 y devient inimportable — et le hook PySide6
de PyInstaller, qui importe QtCore pour localiser les plugins Qt, échoue alors
*silencieusement* et produit un `.exe` sans plugin de plateforme, qui refuse de
démarrer sous Windows (« could not initialize Qt platform plugin windows »). Le
script vérifie donc, avant compilation, que PySide6 s'importe, et après
compilation, que `qwindows.dll` est bien embarqué.
## Publication
```bash
make publish # pousse la branche courante et les tags vers tous les dépôts
```
Le projet est publié sur deux instances Gitea :
[git.tuxtech.fr](https://git.tuxtech.fr/tuxgyver/JoinDomainGUI) (`origin`) et
[git.h3campus.fr](https://git.h3campus.fr/Johnny/JoinDomainGUI) (`h3campus`).
## Structure
```
main.py Point d'entrée : GUI sans argument, CLI sinon
domainjoin/
├── cli.py Interface en ligne de commande
├── gui.py Interface PySide6
├── diagnostics.py Moteur de diagnostic réseau
├── worker.py Exécution en arrière-plan pour la GUI
├── privileges.py Détection des droits root/administrateur
└── backend/
├── base.py Interface commune de jointure
├── linux_realmd.py Backend Linux (realmd / adcli)
└── windows_addcomputer.py Backend Windows (Add-Computer)
packaging/ Scripts de compilation PyInstaller
```
Voir [CHANGELOG.md](CHANGELOG.md) pour l'historique des versions.
+1 -1
View File
@@ -1 +1 @@
__version__ = "0.1.2"
__version__ = "0.1.3"
+109
View File
@@ -0,0 +1,109 @@
#!/usr/bin/env bash
# Fabrique le binaire Windows autonome (.exe) de JoinDomainGUI DEPUIS LINUX,
# en pilotant un Python Windows embarque dans un prefixe Wine dedie.
#
# PyInstaller ne cross-compile pas : on execute donc un vrai PyInstaller Windows
# sous Wine. Le .exe produit est un binaire Windows natif.
#
# Prerequis : wine (>= 8), curl, unzip.
set -euo pipefail
cd "$(dirname "$0")/.."
PYTHON_VERSION="${PYTHON_VERSION:-3.12.10}"
# Depuis Qt 6.10, Qt6Core.dll est lie a l'ICU fourni par Windows (icuuc.dll dans
# System32, present depuis Win10 1703). Wine ne fournit pas cette DLL : PySide6
# y devient inimportable, et le hook PySide6 de PyInstaller -- qui importe QtCore
# pour localiser les plugins Qt -- echoue alors SILENCIEUSEMENT et produit un
# .exe depourvu de plugin de plateforme ("could not initialize Qt platform
# plugin windows" au lancement). On contraint donc cette build a Qt 6.9.
PYSIDE6_CONSTRAINT="${PYSIDE6_CONSTRAINT:-PySide6<6.10}"
WINEPREFIX="${WINEPREFIX:-$PWD/.build-wine}"
export WINEPREFIX
export WINEARCH=win64
export WINEDEBUG="${WINEDEBUG:--all}"
PY_DIR="$WINEPREFIX/drive_c/python"
WPY="c:\\python\\python.exe"
CACHE=".build-wine-cache"
command -v wine >/dev/null || { echo "wine est requis (apt install wine)" >&2; exit 1; }
mkdir -p "$CACHE"
if [ ! -d "$WINEPREFIX" ]; then
echo ">> Initialisation du prefixe Wine ($WINEPREFIX)"
wineboot --init >/dev/null 2>&1
wineserver -w
fi
if [ ! -f "$PY_DIR/python.exe" ]; then
ZIP="$CACHE/python-$PYTHON_VERSION-embed-amd64.zip"
[ -f "$ZIP" ] || curl -fL --retry 3 -o "$ZIP" \
"https://www.python.org/ftp/python/$PYTHON_VERSION/python-$PYTHON_VERSION-embed-amd64.zip"
echo ">> Installation de Python $PYTHON_VERSION (Windows) dans le prefixe"
rm -rf "$PY_DIR"
mkdir -p "$PY_DIR"
unzip -q "$ZIP" -d "$PY_DIR"
# La distribution "embeddable" desactive site-packages : on le reactive
# pour que pip et les paquets installes soient importables.
sed -i 's/^#import site/import site/' "$PY_DIR"/python*._pth
fi
if [ ! -f "$PY_DIR/Scripts/pip.exe" ]; then
GETPIP="$CACHE/get-pip.py"
[ -f "$GETPIP" ] || curl -fL --retry 3 -o "$GETPIP" https://bootstrap.pypa.io/get-pip.py
echo ">> Installation de pip"
cp "$GETPIP" "$PY_DIR/get-pip.py"
wine "$WPY" c:\\python\\get-pip.py --no-warn-script-location
fi
# pip sous Wine est lent (plusieurs minutes pour le wheel PySide6) : on ne
# reinstalle que si requirements.txt ou la contrainte ont change (FORCE_DEPS=1
# pour forcer).
DEPS_STAMP="$PY_DIR/.deps-stamp"
WANT_HASH="$(cat requirements.txt <(echo "$PYSIDE6_CONSTRAINT") | sha256sum | cut -d' ' -f1)"
if [ "${FORCE_DEPS:-0}" = "1" ] || [ "$(cat "$DEPS_STAMP" 2>/dev/null)" != "$WANT_HASH" ]; then
echo ">> Installation des dependances Windows (peut prendre plusieurs minutes)"
printf '%s\n' "$PYSIDE6_CONSTRAINT" > "$PY_DIR/constraints.txt"
# Desinstallation prealable : pip ne retrograde pas toujours un paquet deja
# installe qui viole une contrainte nouvellement ajoutee.
wine "$WPY" -m pip uninstall -q -y PySide6 PySide6-Essentials PySide6-Addons shiboken6 >/dev/null 2>&1 || true
wine "$WPY" -m pip install -q --no-warn-script-location \
-c c:\\python\\constraints.txt -r requirements.txt pyinstaller
echo "$WANT_HASH" > "$DEPS_STAMP"
else
echo ">> Dependances Windows a jour (FORCE_DEPS=1 pour les reinstaller)"
fi
# Garde-fou : si PySide6 ne s'importe pas ici, le hook PyInstaller ne collectera
# aucun plugin Qt et produira un .exe casse sans le signaler. Echouer tot.
echo ">> Verification de PySide6 sous Wine"
if ! wine "$WPY" -c "import PySide6.QtWidgets" 2>&1; then
echo "ERREUR : PySide6 n'est pas importable sous Wine — le .exe produit serait" >&2
echo " depourvu de plugins Qt. Verifiez PYSIDE6_CONSTRAINT." >&2
exit 1
fi
echo ">> Compilation du .exe"
wine "$WPY" -m PyInstaller \
--noconfirm \
--onefile \
--windowed \
--name JoinDomainGUI \
--distpath dist/windows \
--workpath build/windows \
--specpath build/windows \
main.py
wineserver -w
# Garde-fou : sans qwindows.dll, l'application refuse de demarrer sous Windows.
if ! grep -qi 'qwindows.dll' build/windows/JoinDomainGUI/PKG-00.toc; then
echo "ERREUR : le plugin de plateforme qwindows.dll est absent du binaire." >&2
exit 1
fi
echo
echo "Binaire produit : dist/windows/JoinDomainGUI.exe"
echo "Lancement : clic droit -> Executer en tant qu'administrateur"