Skip to content

Commit 9cfeec8

Browse files
committed
N°9144 Sequencer unittest, WizardState object, MetaModel startup optimization, shellparameter escape
1 parent 9875bae commit 9cfeec8

28 files changed

+367
-137
lines changed

setup/ajax.dataloader.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ function FatalErrorCatcher($sOutput)
138138
ini_set('display_errors', true);
139139
ini_set('display_startup_errors', true);
140140

141-
require_once(APPROOT.'/setup/wizardcontroller.class.inc.php');
141+
require_once(APPROOT.'/setup/wizardsteps_autoload.php');
142142

143143
$sClass = utils::ReadParam('step_class', '');
144144
$sState = utils::ReadParam('step_state', '');

setup/feature_removal/ModelReflectionSerializer.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use CoreException;
77
use Exception;
88
use IssueLog;
9+
use MetaModel;
910
use SetupLog;
1011
use utils;
1112

@@ -34,11 +35,25 @@ final public static function SetInstance(?ModelReflectionSerializer $oInstance):
3435
public function GetModelFromEnvironment(string $sEnv): array
3536
{
3637
IssueLog::Info(__METHOD__, null, ['env' => $sEnv]);
38+
39+
$sCurrentEnvt = MetaModel::GetEnvironment();
40+
if ($sCurrentEnvt === $sEnv) {
41+
$aClasses = MetaModel::GetClasses();
42+
if (count($aClasses) === 0) {
43+
//MetaModel not started yet
44+
$sConfFile = utils::GetConfigFilePath($sEnv);
45+
46+
MetaModel::Startup($sConfFile, false /* $bModelOnly */, false /* $bAllowCache */, false /* $bTraceSourceFiles */, $sEnv);
47+
$aClasses = MetaModel::GetClasses();
48+
}
49+
return $aClasses;
50+
}
51+
3752
$sPHPExec = trim(utils::GetConfig()->Get('php_path'));
3853
$sOutput = "";
3954
$iRes = 0;
4055

41-
$sCommandLine = sprintf("$sPHPExec %s/get_model_reflection.php --env=%s", __DIR__, $sEnv);
56+
$sCommandLine = sprintf("$sPHPExec %s/get_model_reflection.php --env=%s", __DIR__, escapeshellarg($sEnv));
4257
exec($sCommandLine, $sOutput, $iRes);
4358
if ($iRes != 0) {
4459
$this->LogErrorWithProperLogger("Cannot get classes", null, ['env' => $sEnv, 'code' => $iRes, "output" => $sOutput]);

setup/sequencers/ApplicationInstallSequencer.php

Lines changed: 56 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,8 @@
4040
*/
4141
class ApplicationInstallSequencer extends StepSequencer
4242
{
43-
/** @var \Parameters */
44-
protected $oParams;
45-
protected static $bMetaModelStarted = false;
43+
protected Parameters $oParams;
44+
protected static bool $bMetaModelStarted = false;
4645

4746
protected Config $oConfig;
4847

@@ -52,7 +51,7 @@ class ApplicationInstallSequencer extends StepSequencer
5251
* @throws \ConfigException
5352
* @throws \CoreException
5453
*/
55-
public function __construct($oParams)
54+
public function __construct(Parameters $oParams)
5655
{
5756
$this->oParams = $oParams;
5857

@@ -100,6 +99,27 @@ protected function GetConfig()
10099
return $oConfig;
101100
}
102101

102+
protected function DoLogParameters($sPrefix = 'install-', $sOperation = 'Installation')
103+
{
104+
// Log the parameters...
105+
$oDoc = new DOMDocument('1.0', 'UTF-8');
106+
$oDoc->preserveWhiteSpace = false;
107+
$oDoc->formatOutput = true;
108+
$this->oParams->ToXML($oDoc, null, 'installation');
109+
$sXML = $oDoc->saveXML();
110+
$sSafeXml = preg_replace("|<pwd>([^<]*)</pwd>|", "<pwd>**removed**</pwd>", $sXML);
111+
SetupLog::Info("======= ".$sOperation." starts =======\nParameters:\n$sSafeXml\n");
112+
113+
// Save the response file as a stand-alone file as well
114+
$sFileName = $sPrefix.date('Y-m-d');
115+
$index = 0;
116+
while (file_exists(APPROOT.'log/'.$sFileName.'.xml')) {
117+
$index++;
118+
$sFileName = $sPrefix.date('Y-m-d').'-'.$index;
119+
}
120+
file_put_contents(APPROOT.'log/'.$sFileName.'.xml', $sSafeXml);
121+
}
122+
103123
/**
104124
* Executes the next step of the installation and reports about the progress
105125
* and the next step to perform
@@ -117,32 +137,16 @@ public function ExecuteStep($sStep = '', $sInstallComment = null)
117137
$this->EnterReadOnlyMode();
118138
switch ($sStep) {
119139
case '':
140+
141+
$this->DoLogParameters();
142+
120143
$aResult = [
121144
'status' => self::OK,
122145
'message' => '',
123146
'percentage-completed' => 0,
124147
'next-step' => 'copy',
125148
'next-step-label' => 'Copying data model files',
126149
];
127-
128-
// Log the parameters...
129-
$oDoc = new DOMDocument('1.0', 'UTF-8');
130-
$oDoc->preserveWhiteSpace = false;
131-
$oDoc->formatOutput = true;
132-
$this->oParams->ToXML($oDoc, null, 'installation');
133-
$sXML = $oDoc->saveXML();
134-
$sSafeXml = preg_replace("|<pwd>([^<]*)</pwd>|", "<pwd>**removed**</pwd>", $sXML);
135-
SetupLog::Info("======= Installation starts =======\nParameters:\n$sSafeXml\n");
136-
137-
// Save the response file as a stand-alone file as well
138-
$sFileName = 'install-'.date('Y-m-d');
139-
$index = 0;
140-
while (file_exists(APPROOT.'log/'.$sFileName.'.xml')) {
141-
$index++;
142-
$sFileName = 'install-'.date('Y-m-d').'-'.$index;
143-
}
144-
file_put_contents(APPROOT.'log/'.$sFileName.'.xml', $sSafeXml);
145-
146150
break;
147151

148152
case 'copy':
@@ -239,15 +243,10 @@ public function ExecuteStep($sStep = '', $sInstallComment = null)
239243

240244
case 'after-db-create':
241245
$aAdminParams = $this->oParams->Get('admin_account');
242-
$sAdminUser = $aAdminParams['user'];
243-
$sAdminPwd = $aAdminParams['pwd'];
244-
$sAdminLanguage = $aAdminParams['language'];
245246
$aSelectedModules = $this->oParams->Get('selected_modules', []);
246247

247248
$this->AfterDBCreate(
248-
$sAdminUser,
249-
$sAdminPwd,
250-
$sAdminLanguage,
249+
$aAdminParams,
251250
$aSelectedModules
252251
);
253252

@@ -261,7 +260,7 @@ public function ExecuteStep($sStep = '', $sInstallComment = null)
261260
break;
262261

263262
case 'load-data':
264-
$aSelectedModules = $this->oParams->Get('selected_modules');
263+
$aSelectedModules = $this->oParams->Get('selected_modules', []);
265264
$bSampleData = ($this->oParams->Get('sample_data', 0) == 1);
266265

267266
$this->DoLoadFiles(
@@ -299,7 +298,6 @@ public function ExecuteStep($sStep = '', $sInstallComment = null)
299298
'next-step-label' => 'Completed',
300299
'percentage-completed' => 100,
301300
];
302-
$this->ExitReadOnlyMode();
303301
break;
304302

305303
default:
@@ -312,29 +310,18 @@ public function ExecuteStep($sStep = '', $sInstallComment = null)
312310
];
313311
break;
314312
}
313+
$this->ExitReadOnlyMode();
315314
} catch (Exception $e) {
316315
$aResult = [
317316
'status' => self::ERROR,
318317
'message' => $e->getMessage(),
319318
'next-step' => '',
320319
'next-step-label' => '',
321320
'percentage-completed' => 100,
321+
'error_code' => $e->getCode(),
322322
];
323323

324-
SetupLog::Error('An exception occurred: '.$e->getMessage().' at line '.$e->getLine().' in file '.$e->getFile());
325-
$idx = 0;
326-
// Log the call stack, but not the parameters since they may contain passwords or other sensitive data
327-
SetupLog::Ok("Call stack:");
328-
foreach ($e->getTrace() as $aTrace) {
329-
$sLine = empty($aTrace['line']) ? "" : $aTrace['line'];
330-
$sFile = empty($aTrace['file']) ? "" : $aTrace['file'];
331-
$sClass = empty($aTrace['class']) ? "" : $aTrace['class'];
332-
$sType = empty($aTrace['type']) ? "" : $aTrace['type'];
333-
$sFunction = empty($aTrace['function']) ? "" : $aTrace['function'];
334-
$sVerb = empty($sClass) ? $sFunction : "$sClass{$sType}$sFunction";
335-
SetupLog::Ok("#$idx $sFile($sLine): $sVerb(...)");
336-
$idx++;
337-
}
324+
$this->ReportException($e);
338325
} finally {
339326
$fDuration = round(microtime(true) - $fStart, 2);
340327
SetupLog::Info("##### STEP {$sStep} duration: {$fDuration}s");
@@ -343,6 +330,24 @@ public function ExecuteStep($sStep = '', $sInstallComment = null)
343330
return $aResult;
344331
}
345332

333+
protected function ReportException(Exception $e)
334+
{
335+
SetupLog::Error('An exception occurred: '.$e->getMessage().' at line '.$e->getLine().' in file '.$e->getFile());
336+
$idx = 0;
337+
// Log the call stack, but not the parameters since they may contain passwords or other sensitive data
338+
SetupLog::Ok("Call stack:");
339+
foreach ($e->getTrace() as $aTrace) {
340+
$sLine = empty($aTrace['line']) ? "" : $aTrace['line'];
341+
$sFile = empty($aTrace['file']) ? "" : $aTrace['file'];
342+
$sClass = empty($aTrace['class']) ? "" : $aTrace['class'];
343+
$sType = empty($aTrace['type']) ? "" : $aTrace['type'];
344+
$sFunction = empty($aTrace['function']) ? "" : $aTrace['function'];
345+
$sVerb = empty($sClass) ? $sFunction : "$sClass{$sType}$sFunction";
346+
SetupLog::Ok("#$idx $sFile($sLine): $sVerb(...)");
347+
$idx++;
348+
}
349+
}
350+
346351
protected function EnterReadOnlyMode()
347352
{
348353
if ($this->GetTargetEnv() != 'production') {
@@ -793,11 +798,14 @@ protected static function MoveColumns($sDBPrefix)
793798
}
794799

795800
protected function AfterDBCreate(
796-
$sAdminUser,
797-
$sAdminPwd,
798-
$sAdminLanguage,
801+
$aAdminParams,
799802
$aSelectedModules
800803
) {
804+
805+
$sAdminUser = $aAdminParams['user'];
806+
$sAdminPwd = $aAdminParams['pwd'];
807+
$sAdminLanguage = $aAdminParams['language'];
808+
801809
$aParamValues = $this->oParams->GetParamForConfigArray();
802810
$sTargetEnvironment = $this->GetTargetEnv();
803811
$sModulesDir = $this->GetTargetDir();

setup/sequencers/DataAuditSequencer.php

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ public function ExecuteStep($sStep = '', $sInstallComment = null)
6060
$this->EnterReadOnlyMode();
6161
switch ($sStep) {
6262
case '':
63+
$this->DoLogParameters('data-audit-', 'Data Audit');
64+
6365
$aResult = [
6466
'status' => self::OK,
6567
'message' => '',
@@ -68,24 +70,6 @@ public function ExecuteStep($sStep = '', $sInstallComment = null)
6870
'next-step-label' => 'Compiling the data model',
6971
];
7072

71-
// Log the parameters...
72-
$oDoc = new DOMDocument('1.0', 'UTF-8');
73-
$oDoc->preserveWhiteSpace = false;
74-
$oDoc->formatOutput = true;
75-
$this->oParams->ToXML($oDoc, null, 'installation');
76-
$sXML = $oDoc->saveXML();
77-
$sSafeXml = preg_replace("|<pwd>([^<]*)</pwd>|", "<pwd>**removed**</pwd>", $sXML);
78-
SetupLog::Info("======= Data Audit starts =======\nParameters:\n$sSafeXml\n");
79-
80-
// Save the response file as a stand-alone file as well
81-
$sFileName = 'data-audit-'.date('Y-m-d');
82-
$index = 0;
83-
while (file_exists(APPROOT.'log/'.$sFileName.'.xml')) {
84-
$index++;
85-
$sFileName = 'data-audit-'.date('Y-m-d').'-'.$index;
86-
}
87-
file_put_contents(APPROOT.'log/'.$sFileName.'.xml', $sSafeXml);
88-
8973
break;
9074

9175
case 'compile':
@@ -160,20 +144,7 @@ public function ExecuteStep($sStep = '', $sInstallComment = null)
160144
'error_code' => $e->getCode(),
161145
];
162146

163-
SetupLog::Error('An exception occurred: '.$e->getMessage().' at line '.$e->getLine().' in file '.$e->getFile());
164-
$idx = 0;
165-
// Log the call stack, but not the parameters since they may contain passwords or other sensitive data
166-
SetupLog::Ok("Call stack:");
167-
foreach ($e->getTrace() as $aTrace) {
168-
$sLine = empty($aTrace['line']) ? "" : $aTrace['line'];
169-
$sFile = empty($aTrace['file']) ? "" : $aTrace['file'];
170-
$sClass = empty($aTrace['class']) ? "" : $aTrace['class'];
171-
$sType = empty($aTrace['type']) ? "" : $aTrace['type'];
172-
$sFunction = empty($aTrace['function']) ? "" : $aTrace['function'];
173-
$sVerb = empty($sClass) ? $sFunction : "$sClass{$sType}$sFunction";
174-
SetupLog::Ok("#$idx $sFile($sLine): $sVerb(...)");
175-
$idx++;
176-
}
147+
$this->ReportException($e);
177148
$this->ExitReadOnlyMode();
178149
} finally {
179150
$fDuration = round(microtime(true) - $fStart, 2);

setup/sequencers/StepSequencer.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ abstract class StepSequencer
2323
public const ERROR = 2;
2424
public const WARNING = 3;
2525
public const INFO = 4;
26+
protected array $aStepsHistory = [];
27+
28+
public function LogStep($sStep, $aResult)
29+
{
30+
$this->aStepsHistory[] = ['step' => $sStep, 'result' => $aResult];
31+
}
32+
public function GetHistory()
33+
{
34+
return $this->aStepsHistory;
35+
}
2636

2737
/**
2838
* Runs all the installation steps in one go and directly outputs
@@ -35,12 +45,13 @@ abstract class StepSequencer
3545
*
3646
* @return boolean True if the installation was successful, false otherwise
3747
*/
38-
public function ExecuteAllSteps($bVerbose = true, &$sMessage = null, $sComment = null)
48+
public function ExecuteAllSteps(bool $bVerbose = true, ?string &$sMessage = null, ?string $sComment = null)
3949
{
4050
$sStep = '';
4151
$sStepLabel = '';
4252
$iOverallStatus = self::OK;
4353
do {
54+
4455
if ($bVerbose) {
4556
if ($sStep != '') {
4657
echo "$sStepLabel\n";
@@ -50,6 +61,7 @@ public function ExecuteAllSteps($bVerbose = true, &$sMessage = null, $sComment =
5061
}
5162
}
5263
$aRes = $this->ExecuteStep($sStep, $sComment);
64+
$this->LogStep($sStep, $aRes);
5365
$sStep = $aRes['next-step'];
5466
$sStepLabel = $aRes['next-step-label'];
5567
$sMessage = $aRes['message'];

setup/unattended-install/InstallationFileService.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
require_once(APPROOT.'/application/utils.inc.php');
77
require_once(APPROOT.'/setup/setuppage.class.inc.php');
8-
require_once(APPROOT.'/setup/wizardcontroller.class.inc.php');
8+
require_once(APPROOT.'/setup/wizardsteps_autoload.php');
99

1010
class InstallationFileService
1111
{

setup/wizard.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
require_once(APPROOT.'/application/utils.inc.php');
3232
require_once(APPROOT.'/core/config.class.inc.php');
3333
require_once(APPROOT.'/setup/setuppage.class.inc.php');
34-
require_once(APPROOT.'/setup/wizardcontroller.class.inc.php');
34+
require_once(APPROOT.'/setup/wizardsteps_autoload.php');
3535

3636
Session::Start();
3737
clearstatcache(); // Make sure we know what we are doing !

setup/wizardcontroller.class.inc.php

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,6 @@
2424
require_once(APPROOT.'core/mutex.class.inc.php');
2525
require_once(APPROOT.'setup/extensionsmap.class.inc.php');
2626

27-
require_once(APPROOT.'setup/wizardsteps/WizardStep.php');
28-
require_once(APPROOT.'setup/wizardsteps/AbstractWizStepInstall.php');
29-
require_once(APPROOT.'setup/wizardsteps/WizStepWelcome.php');
30-
require_once(APPROOT.'setup/wizardsteps/WizStepInstallOrUpgrade.php');
31-
require_once(APPROOT.'setup/wizardsteps/WizStepDetectedInfo.php');
32-
require_once(APPROOT.'setup/wizardsteps/WizStepLicense.php');
33-
require_once(APPROOT.'setup/wizardsteps/WizStepLicense2.php');
34-
require_once(APPROOT.'setup/wizardsteps/AbstractWizStepMiscParams.php');
35-
require_once(APPROOT.'setup/wizardsteps/WizStepAdminAccount.php');
36-
require_once(APPROOT.'setup/wizardsteps/WizStepInstall.php');
37-
require_once(APPROOT.'setup/wizardsteps/WizStepDataAudit.php');
38-
require_once(APPROOT.'setup/wizardsteps/WizStepDBParams.php');
39-
require_once(APPROOT.'setup/wizardsteps/WizStepDone.php');
40-
require_once(APPROOT.'setup/wizardsteps/WizStepInstallMiscParams.php');
41-
require_once(APPROOT.'setup/wizardsteps/WizStepModulesChoice.php');
42-
require_once(APPROOT.'setup/wizardsteps/WizStepSummary.php');
43-
require_once(APPROOT.'setup/wizardsteps/WizStepUpgradeMiscParams.php');
44-
4527
/**
4628
* Engine for displaying the various pages of a "wizard"
4729
* Each "step" of the wizard must be implemented as
@@ -176,8 +158,8 @@ protected function Next()
176158
}
177159
$aPossibleSteps = $oStep->GetPossibleSteps();
178160
$aNextStepInfo = $oStep->UpdateWizardStateAndGetNextStep(true); // true => moving forward
179-
if (in_array($aNextStepInfo['class'], $aPossibleSteps)) {
180-
$oNextStep = $this->NewStep($aNextStepInfo['class'], $aNextStepInfo['state']);
161+
if (in_array($aNextStepInfo->GetNextStep(), $aPossibleSteps)) {
162+
$oNextStep = $this->NewStep($aNextStepInfo->GetNextStep(), $aNextStepInfo->GetState());
181163
$this->DisplayStep($oNextStep);
182164
} else {
183165
throw new Exception("Internal error: Unexpected next step '{$aNextStepInfo['class']}'. The possible next steps are: ".implode(', ', $aPossibleSteps));

0 commit comments

Comments
 (0)