Cet article est la suite de la première partie de l'article sur Habré , où il a été décrit en détail sur le déploiement de la pile Django sur MS Windows. Ensuite, nous fournirons des instructions pas à pas pour créer un programme d'installation qui automatisera le processus d'installation de la pile sur d'autres ordinateurs sans avoir besoin de travailler en ligne de commande, de créer des machines virtuelles, etc., où toute la séquence d'actions sera réduite aux actions Suivant -> Suivant -> Terminer.
Alors, que doit faire l'installateur:
- Décompressez tous les programmes et composants nécessaires dans un répertoire spécifié par l'utilisateur.
- Effectuer des vérifications avant l'installation.
- Enregistrez l'interpréteur Python dans le registre Windows.
- Installez, si elles ne sont pas déjà installées, les bibliothèques de dépendances logicielles.
- Créez des services Apache et PostgreSQL, puis démarrez-les.
- Un avantage supplémentaire sera la création automatique d'un programme de désinstallation qui supprimera la pile installée si l'utilisateur le souhaite.
Parmi les options possibles pour les installateurs, nous choisirons l'installateur gratuit Inno Setup, car il vous permet de faire tout ce qui précède, vous permettant de créer des installateurs sans avoir à exécuter beaucoup de scripts. Par rapport à Wix, la syntaxe du fichier d'installation est au format ini, qui est plus facile à lire et à modifier que xml. Aujourd'hui, il concurrence et surpasse même de nombreux installateurs commerciaux en termes de fonctionnalités et de stabilité.
Mieux encore, aucun script n'est requis pour créer un programme d'installation de base, car Inno Setup est livré avec un assistant graphique qui fait un travail étonnamment bon pour les installateurs de base.
La logique d'installation peut être écrite en Pascal, plutôt que les actions personnalisées alambiquées dans Wix. Son seul inconvénient est qu'il ne crée que des fichiers exe, le format de fichier msi n'est pas pris en charge.
Étape 1: Installation d'Inno Setup
Des commentaires supplémentaires ne sont pas nécessaires ici, car télécharger et installer le programme d'installation est simple.
Étape 2: Script de l'installation d'Inno Setup
Créons un stub Inno Setup script (fichier * .iss) à l'aide de l'assistant de script d'installation.
En conséquence, un fichier * .iss sera créé avec le contenu suivant:
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "Severcart"
#define MyAppVersion "1.21.0"
#define MyAppPublisher "Severcart Inc."
#define MyAppURL "https://www.severcart.ru/"
[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{4FAF87DC-4DBD-42CE-A2A2-B6D559E76BDC}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName=c:\severcart
DefaultGroupName={#MyAppName}
; Uncomment the following line to run in non administrative install mode (install for current user only.)
;PrivilegesRequired=lowest
OutputDir=C:\Users\Developer\Desktop\Output
OutputBaseFilename=mysetup
Compression=lzma
SolidCompression=yes
WizardStyle=modern
[Languages]
Name: "russian"; MessagesFile: "compiler:Languages\Russian.isl"
[Files]
Source: "C:\severcart\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
Étape 3. Vérifications avant l'installation
Avant de décompresser les programmes dans le répertoire et de modifier le registre, vous devez vérifier que les ports TCP sont libres pour qu'Apache et PostgreSQL fonctionnent, vous devez également vérifier la configuration système minimale requise de Windows, car comme déjà mentionné dans la première partie de cet article, la version installée de Python ne fonctionnera qu'à partir de la version de MS Windows 8 (noyau version 6.2) .
Pour effectuer les vérifications nécessaires, utilisons la section [Code] du fichier d'installation. Section [Code]Est une section facultative qui définit un script Pascal. Le script Pascal peut être utilisé pour personnaliser l'installation ou la désinstallation de différentes manières. Notez que la création d'un script Pascal n'est pas facile et nécessite une expérience avec Inno Setup et des compétences en programmation en Pascal, ou du moins dans un langage de programmation similaire. Pour vérifier la disponibilité des ports TCP, nous allons créer la fonction suivante: Nous allons appeler les fonctions de test dans la fonction InitializeSetup , qui est appelée lors de l'initialisation de l'installation. Renvoie False pour annuler l'installation, sinon True .
function IsWindowsVersionOrNewer(Major, Minor: Integer): Boolean;
var
Version: TWindowsVersion;
begin
GetWindowsVersionEx(Version);
Result := (Version.Major > Major) or ((Version.Major = Major) and (Version.Minor >= Minor));
end;
function IsWindows8OrNewer: Boolean;
begin
Result := IsWindowsVersionOrNewer(6, 2);
end;
function CheckPortOccupied(Port:String):Boolean;
var
ResultCode: Integer;
begin
Exec(ExpandConstant('{cmd}'), '/C netstat -na | findstr'+' /C:":'+Port+' "', '',0,ewWaitUntilTerminated, ResultCode);
if ResultCode <> 1 then
begin
Log('this port('+Port+') is occupied');
Result := True;
end else
begin
Result := False;
end;
end;
function InitializeSetup(): Boolean;
var
port_80_check, port_5432_check: boolean;
begin
if not IsWindows8OrNewer() then begin
MsgBox(' . Windows 2012 Windows 8.0.',mbError,MB_OK);
Abort();
Result := False;
end;
port_80_check := CheckPortOccupied('8080');
if port_80_check then begin
MsgBox(' . TCP 8080 .',mbError,MB_OK);
Abort();
Result := False;
end;
port_5432_check := CheckPortOccupied('5432');
if port_5432_check then begin
MsgBox(' . TCP 5432 .',mbError,MB_OK);
Result := False;
Abort();
end;
Result := True;
Étape 4. Enregistrez Python dans le registre Windows
Cette section facultative définit toutes les clés / valeurs de registre que le programme d'installation doit créer ou modifier sur le système de l'utilisateur.
Pour ce faire, ajoutez les clés PYTHONPATH et PYTHONHOME et mettez à jour la variable Path .
sys.path contient une liste de chaînes qui fournissent des emplacements de recherche pour les modules et les packages pour un futur projet Python. Il est initialisé à partir de la variable d'environnement PYTHONPATH et d'autres paramètres.
PYTHONHOME est le répertoire de base de Python.
PATH est une variable d'environnement que le système d'exploitation utilise pour rechercher des exécutables dans la ligne de commande ou la fenêtre du terminal.
[Registry]
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}\python;{app}\python\Scripts"
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: expandsz; ValueName: "PYTHONPATH"; ValueData: "{app}\python"
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: expandsz; ValueName: "PYTHONHOME"; ValueData: "{app}\python"
Étape 5. Créez des fichiers de configuration pour les services Apache et PostgreSQL
Pour créer des fichiers de configuration, nous utiliserons 2 scripts Python qui généreront une configuration basée sur le chemin d'installation spécifié par l'utilisateur.
Les scripts seront appelés dans la section [Exécuter] du programme d' installation.
La section [Exécuter] est facultative et spécifie un nombre quelconque de programmes à exécuter une fois que le programme a été installé avec succès, mais avant que le programme d'installation n'affiche la boîte de dialogue finale.
Ensuite, dans la même section, ajoutez l'installation cachée des packages redistribuables Visual Studio sans laquelle les services Apache et PostgreSQL ne fonctionneront pas. Contenu du fichier create_http_conf.py
[Run]
Filename: "{app}\common\VC_redist.x86apache.exe"; Parameters: "/install /passive"; Flags: waituntilterminated
Filename: "{app}\common\vcredist_x86pg.exe"; Parameters: "/install /passive"; Flags: runhidden;
Filename: "{app}\python\python.exe" ;Parameters: "{app}\common\create_http_conf.py"; Flags: runhidden
Filename: "{app}\python\python.exe" ;Parameters: "{app}\common\edit_pg_conf.py"; Flags: runhidden
Filename: "{app}\common\install.bat";Flags: runhidden
Filename: "{app}\common\services_start.bat"; Flags: runhidden
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import sys, os
base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
base_path_un = base_path.replace('\\', '/')
apache_conf_path = os.path.join(base_path, 'Apache24', 'conf', 'extra', 'httpd-wsgi.conf')
print('base_path=',base_path)
CONF = """
LoadFile "%(base)s/python/python39.dll"
LoadModule wsgi_module "%(base)s/python/lib/site-packages/mod_wsgi/server/mod_wsgi.cp39-win32.pyd"
WSGIPythonHome "%(base)s/python"
Alias /static "%(base)s/app/static"
Alias /media "%(base)s/app/media"
<Directory "%(base)s/app/static">
# for Apache 2.4
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
<Directory "%(base)s/app/media">
# for Apache 2.4
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
WSGIScriptAlias / "%(base)s/app/conf/wsgi_prod.py"
WSGIPythonPath "%(base)s/python/"
<Directory "%(base)s/app/conf/">
<Files wsgi_prod.py>
Require all granted
</Files>
</Directory>
"""
conf_content = CONF % {'base': base_path_un}
with open(apache_conf_path, 'w') as fp:
fp.write(conf_content)
# Read in the file
apache_main = os.path.join(base_path, 'Apache24', 'conf', 'httpd.conf')
with open(apache_main, 'r') as file :
filedata = file.read()
# Replace the target string
replace_pattern = 'Define SRVROOT "%(base)s/Apache24"' % {'base' : base_path_un}
find_pattern = 'Define SRVROOT "C:/severcart/Apache24"'
filedata = filedata.replace(find_pattern, replace_pattern)
# Write the file out again
with open(apache_main, 'w') as file:
file.write(filedata)
Contenu edit_pg_conf.py
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import sys, os
"""
c:/djangostack/postgresql/bin/postgres.exe "-D" "c:\djangostack\postgresql\data"
"""
base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
base_path_un = base_path.replace('\\', '/')
pg_conf_path = os.path.join(base_path, 'postgresql', 'data', 'postmaster.opts')
# Read in the file
pg_conf_path = os.path.join(base_path, 'postgresql', 'data', 'postmaster.opts')
with open(pg_conf_path, 'r') as file :
filedata = file.read()
# Replace the target string
replace_pattern = base_path_un + '/'
find_pattern = "C:/severcart/"
filedata = filedata.replace(find_pattern, replace_pattern)
# Write the file out again
with open(pg_conf_path, 'w') as file:
file.write(filedata)
Fichier Install.bat Contenu Fichier services_start.bat
@echo off
..\Apache24\bin\httpd.exe -k install -n "Apache" > install.log 2>&1
..\postgresql\bin\pg_ctl.exe register -N "PostgreSQL" -D ..\postgresql\data > install.log 2>&1
@echo off
net start "Apache"
net start "PostgreSQL"
Étape 6: créez le programme de désinstallation
Pour tout installateur, il est également nécessaire de prévoir la possibilité de créer un programme de désinstallation. Heureusement, Inno Setup fera le travail pour nous, à l'exception de certaines étapes qui doivent être prises pour nettoyer les traces de la présence du programme dans le système d'exploitation.
Pour ce faire, dans la section [UninstallRun] , nous enregistrerons l'exécution du script bat Windows pour arrêter les services installés, ainsi que pour les supprimer. Le contenu du script bat: le script arrête les services, puis supprime les services Apache et PostgreSQL de la liste des services système Windows.
[UninstallRun]
Filename: "{app}\common\remove.bat"; Flags: runhidden
@echo off
SC STOP Apache
SC STOP PostgreSQL
SC DELETE Apache
SC DELETE PostgreSQL
Étape 7. Signature du fichier exécutable du programme d'installation ES du développeur
Les certificats de signature de code sont utilisés par les développeurs de logiciels pour signer numériquement des applications et des programmes afin de prouver qu'un fichier téléchargé par un utilisateur est authentique et n'a pas été falsifié. Ceci est particulièrement important pour les éditeurs qui distribuent leurs logiciels via des sites de téléchargement tiers sur lesquels ils n'ont aucun contrôle. Les principaux systèmes d'exploitation afficheront aux utilisateurs finaux un message d'erreur si le logiciel qu'ils tentent d'installer n'est pas signé par une autorité de certification de confiance.
Vous pouvez par exemple acheter un certificat de développeur PFX ici . Le certificat est acheté pendant un an.
L'avant-dernière étape pour travailler avec le programme d'installation sera de lancer automatiquement le programme signtool.exe pour signer le programme d'installation terminé au format exe une fois que le programme Inno Setup a terminé son travail. SignTool est un programme de ligne de commande qui signe numériquement les fichiers, vérifie les signatures de fichiers et les horodatages des fichiers. Par défaut, le programme signtool.exe n'est pas inclus dans la distribution Windows, nous téléchargeons et installons donc le SDK Windows 10 .
Une fois l'installation terminée, vous trouverez signtool.exe dans les répertoires:
- x86 -> c: \ Program Files (x86) \ Windows Kits \ 10 \ bin \ x86 \
- x64 -> c: \ Program Files (x86) \ Windows Kits \ 10 \ bin \ x64 \
Pour ceux qui souhaitent se familiariser avec le programme de signature, visitez le site Web officiel du développeur pour plus de détails . Il répertorie toutes les options de ligne de commande et les exemples d'utilisation. Allons-nous en.
Ensuite, configurons la signature automatique du fichier. Sélectionnez "Configurer les outils de signe ..." dans le menu "Outils" .
Cliquez ensuite sur le bouton "Ajouter"
Donnez un nom à l'outil. C'est le nom que vous utiliserez pour faire référence à l'outil dans les scripts du programme d'installation. J'ai nommé le mien signtool parce que j'utilise signtool.exe.
Collez le texte que vous utilisez pour signer les fichiers exécutables à partir de la ligne de commande. Remplacez le nom du fichier à signer par $ f. Inno Setup remplacera la variable $ f par le fichier signé.
"C: \ Program Files (x86) \ Windows Kits \ 10 \ bin \ x86 \ signtool.exe" sign / f "C: \ MY_CODE_SIGNING.PFX" / t timestamp.comodoca.com/authenticode / p MY_PASSWORD $ f
Après avoir appuyé sur OK, vous avez terminé la configuration de l'outil de signature.
Ajoutons le script suivant à la section [Setup] pour utiliser l'outil de signature que nous venons de configurer. Cela suppose que vous avez nommé votre outil signtool.
SignTool=signtool
Étape 8. Assemblage du programme d'installation
Fichier d'installation final d'InnoSetup
#define MyAppName «Severcart»
#define MyAppVersion «1.21.0»
#define MyAppPublisher «Severcart Inc.»
#define MyAppURL «www.severcart.ru»
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
SignTool=signtool
AppId={{2CF113D5-B49D-47EF-B85F-AE06EB0E78EB}}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName=c:\severcart
DefaultGroupName={#MyAppName}
OutputBaseFilename=setup
Compression=lzma
SolidCompression=yes
ChangesEnvironment=yes
; Uninstall options
Uninstallable=yes
CreateUninstallRegKey=yes
;WizardSmallImageFile=logo3.bmp
[Icons]
Name: "{userdesktop}\severcart"; Filename: «127.0.0.1:8080/»
[Languages]
Name: «russian»; MessagesFile: «compiler:Languages\Russian.isl»
[Files]
Source: «C:\severcart\*»; Excludes: "*.pyc"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
[Registry]
Root: HKLM; Subkey: «SYSTEM\CurrentControlSet\Control\Session Manager\Environment»; \
ValueType: expandsz; ValueName: «Path»; ValueData: "{olddata};{app}\python;{app}\python\Scripts"
Root: HKLM; Subkey: «SYSTEM\CurrentControlSet\Control\Session Manager\Environment»; \
ValueType: expandsz; ValueName: «PYTHONPATH»; ValueData: "{app}\python"
Root: HKLM; Subkey: «SYSTEM\CurrentControlSet\Control\Session Manager\Environment»; \
ValueType: expandsz; ValueName: «PYTHONHOME»; ValueData: "{app}\python"
[Run]
Filename: "{app}\common\VC_redist.x86apache"; Parameters: "/install /passive"; Flags: waituntilterminated
Filename: "{app}\common\vcredist_x86pg"; Parameters: "/install /passive"; Flags: runhidden;
Filename: "{app}\python\python.exe" ;Parameters: "{app}\common\create_http_conf.py"; Flags: runhidden
Filename: "{app}\python\python.exe" ;Parameters: "{app}\common\edit_pg_conf.py"; Flags: runhidden
Filename: "{app}\common\install.bat";Flags: runhidden
Filename: "{app}\common\services_start.bat"; Flags: runhidden
[UninstallRun]
Filename: "{app}\common\remove.bat"; Flags: runhidden
[Code]
function IsWindowsVersionOrNewer(Major, Minor: Integer): Boolean;
var
Version: TWindowsVersion;
begin
GetWindowsVersionEx(Version);
Result :=
(Version.Major > Major) or
((Version.Major = Major) and (Version.Minor >= Minor));
end;
function IsWindows8OrNewer: Boolean;
begin
Result := IsWindowsVersionOrNewer(6, 2);
end;
function CheckPortOccupied(Port:String):Boolean;
var
ResultCode: Integer;
begin
Exec(ExpandConstant('{cmd}'), '/C netstat -na | findstr'+' /C:":'+Port+' "', '',0,ewWaitUntilTerminated, ResultCode);
if ResultCode <> 1 then
begin
Log('this port('+Port+') is occupied');
Result := True;
end else
begin
Result := False;
end;
end;
function InitializeSetup(): Boolean;
var
port_80_check, port_5432_check: boolean;
begin
if not IsWindows8OrNewer() then begin
MsgBox(' . Windows 2012 Windows 8.0.',mbError,MB_OK);
Abort();
Result := False;
end;
port_80_check := CheckPortOccupied('8080');
if port_80_check then begin
MsgBox(' . TCP 8080 .',mbError,MB_OK);
Abort();
Result := False;
end;
port_5432_check := CheckPortOccupied('5432');
if port_5432_check then begin
MsgBox(' . TCP 5432 .',mbError,MB_OK);
Result := False;
Abort();
end;
Result := True;
end;
#define MyAppVersion «1.21.0»
#define MyAppPublisher «Severcart Inc.»
#define MyAppURL «www.severcart.ru»
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
SignTool=signtool
AppId={{2CF113D5-B49D-47EF-B85F-AE06EB0E78EB}}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName=c:\severcart
DefaultGroupName={#MyAppName}
OutputBaseFilename=setup
Compression=lzma
SolidCompression=yes
ChangesEnvironment=yes
; Uninstall options
Uninstallable=yes
CreateUninstallRegKey=yes
;WizardSmallImageFile=logo3.bmp
[Icons]
Name: "{userdesktop}\severcart"; Filename: «127.0.0.1:8080/»
[Languages]
Name: «russian»; MessagesFile: «compiler:Languages\Russian.isl»
[Files]
Source: «C:\severcart\*»; Excludes: "*.pyc"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
[Registry]
Root: HKLM; Subkey: «SYSTEM\CurrentControlSet\Control\Session Manager\Environment»; \
ValueType: expandsz; ValueName: «Path»; ValueData: "{olddata};{app}\python;{app}\python\Scripts"
Root: HKLM; Subkey: «SYSTEM\CurrentControlSet\Control\Session Manager\Environment»; \
ValueType: expandsz; ValueName: «PYTHONPATH»; ValueData: "{app}\python"
Root: HKLM; Subkey: «SYSTEM\CurrentControlSet\Control\Session Manager\Environment»; \
ValueType: expandsz; ValueName: «PYTHONHOME»; ValueData: "{app}\python"
[Run]
Filename: "{app}\common\VC_redist.x86apache"; Parameters: "/install /passive"; Flags: waituntilterminated
Filename: "{app}\common\vcredist_x86pg"; Parameters: "/install /passive"; Flags: runhidden;
Filename: "{app}\python\python.exe" ;Parameters: "{app}\common\create_http_conf.py"; Flags: runhidden
Filename: "{app}\python\python.exe" ;Parameters: "{app}\common\edit_pg_conf.py"; Flags: runhidden
Filename: "{app}\common\install.bat";Flags: runhidden
Filename: "{app}\common\services_start.bat"; Flags: runhidden
[UninstallRun]
Filename: "{app}\common\remove.bat"; Flags: runhidden
[Code]
function IsWindowsVersionOrNewer(Major, Minor: Integer): Boolean;
var
Version: TWindowsVersion;
begin
GetWindowsVersionEx(Version);
Result :=
(Version.Major > Major) or
((Version.Major = Major) and (Version.Minor >= Minor));
end;
function IsWindows8OrNewer: Boolean;
begin
Result := IsWindowsVersionOrNewer(6, 2);
end;
function CheckPortOccupied(Port:String):Boolean;
var
ResultCode: Integer;
begin
Exec(ExpandConstant('{cmd}'), '/C netstat -na | findstr'+' /C:":'+Port+' "', '',0,ewWaitUntilTerminated, ResultCode);
if ResultCode <> 1 then
begin
Log('this port('+Port+') is occupied');
Result := True;
end else
begin
Result := False;
end;
end;
function InitializeSetup(): Boolean;
var
port_80_check, port_5432_check: boolean;
begin
if not IsWindows8OrNewer() then begin
MsgBox(' . Windows 2012 Windows 8.0.',mbError,MB_OK);
Abort();
Result := False;
end;
port_80_check := CheckPortOccupied('8080');
if port_80_check then begin
MsgBox(' . TCP 8080 .',mbError,MB_OK);
Abort();
Result := False;
end;
port_5432_check := CheckPortOccupied('5432');
if port_5432_check then begin
MsgBox(' . TCP 5432 .',mbError,MB_OK);
Result := False;
Abort();
end;
Result := True;
end;
Étape 9. Vérification du travail de l'installateur
C'est tout, merci pour votre attention.