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>
This commit is contained in:
@@ -5,3 +5,5 @@ dist/
|
|||||||
*.spec
|
*.spec
|
||||||
.build-venv-linux/
|
.build-venv-linux/
|
||||||
.build-venv-windows/
|
.build-venv-windows/
|
||||||
|
.build-wine/
|
||||||
|
.build-wine-cache/
|
||||||
|
|||||||
@@ -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 ""
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
> Le `.exe` s'appuie sur l'ICU fourni par le système (`icuuc.dll` dans
|
||||||
|
> `System32`), présent depuis Windows 10 1703 et Windows Server 2019. Il ne
|
||||||
|
> peut pas être testé sous Wine, qui ne fournit pas cette bibliothèque.
|
||||||
|
|
||||||
|
## 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.
|
||||||
Executable
+78
@@ -0,0 +1,78 @@
|
|||||||
|
#!/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}"
|
||||||
|
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 le prefixe est neuf. FORCE_DEPS=1 pour forcer une mise a jour.
|
||||||
|
if [ ! -d "$PY_DIR/Lib/site-packages/PyInstaller" ] || [ "${FORCE_DEPS:-0}" = "1" ]; then
|
||||||
|
echo ">> Installation des dependances Windows (peut prendre plusieurs minutes)"
|
||||||
|
wine "$WPY" -m pip install -q --no-warn-script-location \
|
||||||
|
-r requirements.txt pyinstaller
|
||||||
|
else
|
||||||
|
echo ">> Dependances Windows deja presentes (FORCE_DEPS=1 pour les mettre a jour)"
|
||||||
|
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
|
||||||
|
echo
|
||||||
|
echo "Binaire produit : dist/windows/JoinDomainGUI.exe"
|
||||||
|
echo "Lancement : clic droit -> Executer en tant qu'administrateur"
|
||||||
Reference in New Issue
Block a user