Passed
Push — master ( f01d00...2f7647 )
by Nicolaas
03:27
created

ModuleUpgrader::loadVarsForModule()   F

Complexity

Conditions 20
Paths > 20000

Size

Total Lines 107
Code Lines 63

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
eloc 63
c 3
b 1
f 0
dl 0
loc 107
rs 0
cc 20
nc 24576
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Sunnysideup\UpgradeToSilverstripe4;
4
5
use Sunnysideup\PHP2CommandLine\PHP2CommandLineSingleton;
6
7
class ModuleUpgrader
8
{
9
    #########################################
10
    # TASKS
11
    #########################################
12
13
    /**
14
     * A list of task groups
15
     *
16
     * @var array
17
     */
18
    protected $taskSteps = [
19
        's00' => 'Generic',
20
        's10' => 'Prepare Codebase',
21
        's20' => 'Upgrade Structure',
22
        's30' => 'Prepare Code',
23
        's40' => 'Upgrade Code',
24
        's50' => 'Upgrade Fixes',
25
        's60' => 'Check',
26
        's70' => 'Finalise',
27
        's99' => 'ERROR!',
28
    ];
29
30
    /**
31
     * An array of all the 'taskName's of the tasks that you wish to run during the execution of this upgrader task.
32
     * This array can be overriden in the example-index.php file that you create.
33
     * You can enter a full name space if you need to.
34
     * The final -x will be removed.  We add -1 or -2 to run the same task multiple times.
35
     *
36
     * @var array
37
     */
38
    protected $listOfTasks = [
39
        //Step1: Prepare
40
        'CheckThatFoldersAreReady' => [],
41
        'ResetWebRootDir-1' => [],
42
43
        'CheckoutDevMaster-1' => [],
44
        'FindFilesWithMoreThanOneClass' => [],
45
        'AddLegacyBranch' => [],
46
        'ResetWebRootDir-2' => [],
47
48
        'CheckoutDevMaster-2' => [],
49
        'AddUpgradeBranch' => [],
50
        'CreatePublicFolder' => [],
51
        'AddTableName' => [],
52
        'ChangeControllerInitToProtected' => [],
53
        // 'AddTableNamePrivateStatic' => [],
54
        'RemoveComposerRequirements' => [
55
            'package' => 'silverstripe/framework',
56
        ],
57
        'RecomposeHomeBrew' => [],
58
        'UpdateComposerRequirements' => [],
59
        'RemoveInstallerFolder' => [],
60
        'ResetWebRootDir-3' => [],
61
62
        //Step2: MoveToNewVersion
63
        'ComposerInstallProject' => [],
64
        'Recompose' => [],
65
66
        //Step3: FixBeforeStart
67
        'ChangeEnvironment' => [],
68
        'MoveCodeToSRC' => [],
69
        'CreateClientFolder' => [],
70
        'SearchAndReplace' => [],
71
        'FixRequirements' => [],
72
        'UpperCaseFolderNamesForPSR4' => [],
73
74
        //Step4: CoreUpgrade
75
        'AddNamespace' => [],
76
        'Upgrade' => [],
77
        'AddPSR4Autoloading' => [],
78
79
        //Step5: FixUpgrade
80
        'FixBadUseStatements' => [],
81
        'InspectAPIChanges-1' => [],
82
        'DatabaseMigrationLegacyYML' => [],
83
        'Reorganise' => [],
84
        'UpdateComposerModuleType' => [],
85
        'AddVendorExposeDataToComposer' => [],
86
        'InspectAPIChanges-2' => [],
87
        // 'WebRootUpdate' => [],
88
        //step6: Check
89
        'ApplyPSR2' => [],
90
        'FinalDevBuild' => [],
91
        'RunImageTask' => [],
92
        'DoMigrateSiteTreeLinkingTask' => [],
93
        'FindFilesWithSimpleUseStatements' => [],
94
        //step7: Lock-in
95
        'FinaliseUpgradeWithMergeIntoMaster' => [],
96
    ];
97
98
    protected $frameworkComposerRestraint = '^4.4';
99
100
    /**
101
     * Should the session details be deleted before we start?
102
     * @var bool
103
     */
104
    protected $restartSession = false;
105
106
    /**
107
     * Should the session details be deleted before we start?
108
     * @var bool
109
     */
110
    protected $runLastOneAgain = false;
111
112
    /**
113
     * are we upgrading a module or a whole project?
114
     * @var bool
115
     */
116
    protected $isModuleUpgrade = true;
117
118
    /**
119
     * The default namespace for all tasks
120
     * @var string
121
     */
122
    protected $defaultNamespaceForTasks = 'Sunnysideup\UpgradeToSilverstripe4\Tasks\IndividualTasks';
123
124
    /**
125
     * if set to true it will run each step and then stop.
126
     * It was save the last step.
127
     * When your run it again, it will start on the next step.
128
     *
129
     * @var bool
130
     */
131
    protected $runInteractively = false;
132
133
    /**
134
     * Show ALL the information or just a little bit.
135
     * @var bool
136
     */
137
    protected $verbose = false;
138
139
    /**
140
     * start the upgrade sequence at a particular task
141
     * @var string
142
     */
143
    protected $startFrom = '';
144
145
    /**
146
     * end the upgrade sequence after a particular task
147
     * @var string
148
     */
149
    protected $endWith = '';
150
151
    /**
152
     * only run this task ...
153
     * @var string
154
     */
155
    protected $onlyRun = '';
156
157
    /**
158
     * finish the run with a merge into master.
159
     * @var boolean
160
     */
161
    protected $runIrreversibly = false;
162
163
    #########################################
164
    # MODULES
165
    #########################################
166
167
    /**
168
     * specified like this:
169
     *      [
170
     *          'VendorName' => 'A',
171
     *          'VendorNamespace' => 'A',
172
     *          'PackageName' => 'Package1',
173
     *          'PackageNamespace' => 'Package1',
174
     *          'GitLink' => '[email protected]:foor/bar-1.git',
175
     *          'UpgradeAsFork' => false
176
     *      ],
177
     *      [
178
     *          'VendorName' => 'A',
179
     *          'VendorNamespace' => 'A',
180
     *          'PackageName' => 'Package2',
181
     *          'PackageNamespace' => 'Package2',
182
     *          'GitLink' => '[email protected]:foor/bar-2.git',
183
     *          'UpgradeAsFork' => false
184
     *      ],
185
     * required are:
186
     * - VendorName
187
     * - PacakageName
188
     * The rest can be deduced (theoretically)
189
     * @var array of array modules to upgrade
190
     */
191
    protected $arrayOfModules = [];
192
193
    #########################################
194
    # VENDOR / PACKAGE / GIT DETAILS
195
    #########################################
196
197
    /**
198
     * name of the branch created to do the upgrade
199
     * @var string branch name
200
     */
201
    protected $nameOfTempBranch = 'temp-upgradeto4-branch';
202
203
    /**
204
     * Name of module vendor
205
     * @var string
206
     */
207
    protected $vendorName = '';
208
209
    /**
210
     * module vendors namespace
211
     * @var string
212
     */
213
    protected $vendorNamespace = '';
214
215
    /**
216
     * Package name for the module
217
     * @var string
218
     */
219
    protected $packageName = '';
220
221
    /**
222
     * e.g. install folder for package in SS3.
223
     * @var string
224
     */
225
    protected $packageFolderNameForInstall = '';
226
227
    /**
228
     * e.g. sunnysideup/my-cool-module
229
     * @var string
230
     */
231
    protected $vendorAndPackageFolderNameForInstall = '';
232
233
    /**
234
     *Name space for the modules package
235
     * @var string
236
     */
237
    protected $packageNamespace = '';
238
239
    /**
240
     * git link for the module in ssh form
241
     * e.g. [email protected]:sunnysideup/silverstripe-dynamiccache.git
242
     * @var string
243
     */
244
    protected $gitLink = '';
245
246
    /**
247
     * git link for the module in https form
248
     * e.g. https://github.com/sunnysideup/silverstripe-dynamiccache/
249
     * @var string
250
     */
251
    protected $gitLinkAsHTTPS = '';
252
253
    /**
254
     * git link for the module in raw https form
255
     * e.g. https://raw.githubusercontent.com/sunnysideup/silverstripe-dynamiccache/
256
     * @var string
257
     */
258
    protected $gitLinkAsRawHTTPS = '';
259
260
    /**
261
     * Should the upgrade to this module create a fork
262
     * @var bool
263
     */
264
    protected $upgradeAsFork = false;
265
266
    #########################################
267
    # COMPOSER
268
    #########################################
269
270
    /**
271
     * e.g. COMPOSER_HOME="/home/UserName"
272
     *
273
     * @var string
274
     */
275
    protected $composerEnvironmentVars = '';
276
277
    #########################################
278
    # LOCATIONS
279
    #########################################
280
281
    //TODO double check descriptions for these variables as still rather ambiguous
282
283
    /**
284
     * The folder for storing the log file in
285
     * used in setting the php2 command line printer up
286
     * @var string
287
     */
288
    protected $logFolderDirLocation = '';
289
290
    /**
291
     * location of web root above module
292
     * @var string directory
293
     */
294
    protected $aboveWebRootDirLocation = '/var/www';
295
296
    /**
297
     * @var string
298
     */
299
    protected $webRootName = 'upgradeto4';
300
301
    /**
302
     * //e.g. 'upgrade-code'
303
     * //e.g. '~/.composer/vendor/bin/upgrade-code'
304
     * //e.g. '/var/www/silverstripe-upgrade_to_silverstripe_4/vendor/silverstripe/upgrader/bin/upgrade-code'
305
     * @var string
306
     */
307
    protected $locationOfThisUpgrader = '';
308
309
    /**
310
     * //e.g. 'upgrade-code'
311
     * //e.g. '~/.composer/vendor/bin/upgrade-code'
312
     * //e.g. '/var/www/silverstripe-upgrade_to_silverstripe_4/vendor/silverstripe/upgrader/bin/upgrade-code'
313
     * @var string
314
     */
315
    protected $locationOfSSUpgradeModule = '';
316
317
    ###############################
318
    # HELPERS
319
    ###############################
320
321
    /**
322
     *Reference to the commandline printer that outputs everything to the command line
323
     * @var PHP2CommandLineSingleton
324
     */
325
    protected $commandLineExec = null;
326
327
    /**
328
     * does the exec output Key Notes?
329
     * @var bool
330
     */
331
    protected $makeKeyNotes = false;
332
333
    /**
334
     * @var string
335
     */
336
    protected $originComposerFileLocation = '';
337
338
    protected $sessionFileName = 'Session_For';
339
340
    /**
341
     * Holds the only instance of me
342
     * @var ModuleUpgrader|null
343
     */
344
    private static $_singleton = null;
345
346
    /**
347
     * Is this the last TASK we are running?
348
     * @var bool
349
     */
350
    private $lastMethodHasBeenRun = false;
351
352
    /**
353
     * @var string
354
     */
355
    private $logFileLocation = '';
356
357
    /**
358
     * Combination of the web dir root name and the aboveWebRootDirLocation
359
     * @var string
360
     */
361
    private $webRootDirLocation = '';
362
363
    /**
364
     * Combination of the web dir root name and the aboveWebRootDirLocation
365
     * @var string
366
     */
367
    private $themeDirLocation = '';
368
369
    /**
370
     * Directory that holds the module
371
     * or project.
372
     *
373
     * This is an array because a project can hold more than one
374
     * folder (e.g. mysite or app and specialstuff)
375
     *
376
     * a module is only one folder
377
     *
378
     * @var array
379
     */
380
    private $moduleDirLocations = [];
381
382
    /**
383
     * Starts the output to the commandline / browser
384
     */
385
    public function __construct()
386
    {
387
        $this->startPHP2CommandLine();
388
        if (! $this->locationOfThisUpgrader) {
389
            $this->locationOfThisUpgrader = dirname(__DIR__);
390
        }
391
        if (! $this->locationOfSSUpgradeModule) {
392
            $this->locationOfSSUpgradeModule = $this->locationOfThisUpgrader .
393
                '/vendor/silverstripe/upgrader/bin/upgrade-code';
394
        }
395
    }
396
397
    /**
398
     * Ends output to commandline / browser
399
     */
400
    public function __destruct()
401
    {
402
        $this->endPHP2CommandLine();
403
    }
404
405
    /**
406
     * creates magic getters and setters
407
     * if you call $this->getFooBar() then it will get the variable FooBar even if the method
408
     * getFooBar does not exist.
409
     *
410
     * if you call $this->setFooBar('hello') then it will set the variable FooBar even if the method
411
     * setFooBar does not exist.
412
     *
413
     * See: http://php.net/manual/en/language.oop5.overloading.php#object.call
414
     *
415
     * @param  string   $function name of the function
416
     * @param  array    $args     parameters provided to the getter / setter
417
     *
418
     * @return mixed|Sunnysideup\UpgradeToSilverstripe4\ModuleUpgrader
0 ignored issues
show
Bug introduced by
The type Sunnysideup\UpgradeToSil...rstripe4\ModuleUpgrader was not found. Did you mean Sunnysideup\UpgradeToSilverstripe4\ModuleUpgrader? If so, make sure to prefix the type with \.
Loading history...
419
     */
420
    public function __call($function, $args)
421
    {
422
        $getOrSet = substr($function, 0, 3);
423
        if ($getOrSet === 'set' || $getOrSet === 'get') {
424
            $var = lcfirst(ltrim($function, $getOrSet));
425
            if (property_exists($this, $var)) {
426
                if ($getOrSet === 'get') {
427
                    if (strpos($var, 'DirLocation') !== false || strpos($var, 'FileLocation') !== false) {
428
                        return $this->checkIfPathExistsAndCleanItUp($this->{$var}, true);
429
                    }
430
                    return $this->{$var};
431
                } elseif ($getOrSet === 'set') {
432
                    $this->{$var} = $args[0];
433
434
                    return $this;
435
                }
436
            } else {
437
                user_error('Fatal error: can not get/set variable in ModuleUpgrader::' . $var, E_USER_ERROR);
438
            }
439
        } else {
440
            user_error('Fatal error: Call to undefined method ModuleUpgrader::' . $function . '()', E_USER_ERROR);
441
        }
442
    }
443
444
    /**
445
     * Create the only instance of me and return it
446
     * @return ModuleUpgrader
447
     */
448
    public static function create()
449
    {
450
        if (self::$_singleton === null) {
451
            self::$_singleton = new self();
452
        }
453
        return self::$_singleton;
454
    }
455
456
    /**
457
     * Removes the given task from the list of tasks to execute
458
     * @param  string $taskName name of the task
459
     * @param  string $variableName name of the task
460
     * @param  mixed $variableValue name of the task
461
     *
462
     * @return ModuleUpgrader
463
     */
464
    public function setVariableForTask($taskName, $variableName, $variableValue)
465
    {
466
        $key = $this->positionForTask($taskName);
467
        if ($key !== false) {
468
            $this->listOfTasks[$taskName][$variableName] = $variableValue;
469
        } else {
470
            user_error('Could not find ' . $taskName . '. Choose from ' . implode(', ', array_keys($this->listOfTasks)));
471
        }
472
473
        return $this;
474
    }
475
476
    /**
477
     * Removes the given task from the list of tasks to execute
478
     * @param  string $s name of the task to remove
479
     *
480
     * @return ModuleUpgrader
481
     */
482
    public function removeFromListOfTasks($s)
483
    {
484
        $key = $this->positionForTask($s);
485
        if ($key !== false) {
486
            unset($this->listOfTasks[$key]);
487
        } else {
488
            user_error('Removing non existent task ' . $key . '. Choose from ' . implode(', ', $this->listOfTasks));
0 ignored issues
show
Bug introduced by
Are you sure $key of type false|integer|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

488
            user_error('Removing non existent task ' . /** @scrutinizer ignore-type */ $key . '. Choose from ' . implode(', ', $this->listOfTasks));
Loading history...
489
        }
490
491
        return $this;
492
    }
493
494
    /**
495
     * Inserts another task to the list of tasks at a given position in the order of execution, if it is set
496
     * TODO These parameter names need some more refining
497
     * @param string|array  $oneOrMoreTasks the tasks to be inserted
498
     * @param bool          $insertBeforeOrAfter If to insert before or after
499
     * @param bool          $isBefore
500
     *
501
     * @return ModuleUpgrader
502
     */
503
    public function addToListOfTasks($oneOrMoreTasks, $insertBeforeOrAfter, $isBefore)
504
    {
505
        if (! is_array($oneOrMoreTasks)) {
506
            $oneOrMoreTasks = [$oneOrMoreTasks];
507
        }
508
        foreach ($this->listOfTasks as $key => $task) {
509
            if ($task === $insertBeforeOrAfter) {
510
                if ($isBefore) {
511
                    $pos = $key - 1;
512
                }
513
                array_splice(
514
                    $this->listOfTasks,
515
                    $pos,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $pos does not seem to be defined for all execution paths leading up to this point.
Loading history...
516
                    0,
517
                    $oneOrMoreTasks
518
                );
519
            }
520
        }
521
        return $this;
522
    }
523
524
    /**
525
     * @param bool $b
526
     */
527
    public function setRunImmediately($b)
528
    {
529
        $this->commandLineExec->setRunImmediately($b);
530
531
        return $this;
532
    }
533
534
    /**
535
     * Whether execution should come to a halt when an error is reached
536
     * @return bool
537
     */
538
    public function getBreakOnAllErrors()
539
    {
540
        return $this->commandLineExec->getBreakOnAllErrors();
541
    }
542
543
    /**
544
     * Whether execution should come to a halt when an error is reached
545
     * @return bool
546
     */
547
    public function getIsProjectUpgrade()
548
    {
549
        return $this->isModuleUpgrade ? false : true;
550
    }
551
552
    /**
553
     * @param bool $b
554
     */
555
    public function setBreakOnAllErrors($b)
556
    {
557
        $this->commandLineExec->setBreakOnAllErrors($b);
558
559
        return $this;
560
    }
561
562
    /**
563
     * Appends the given module in the form of all its module data that has to be formatted in an array
564
     * to the array of modules that will be worked with during the upgrade procedure.
565
     *
566
     * @param array $a data to append
567
     * @return ModuleUpgrader
568
     */
569
    public function addModule($a)
570
    {
571
        $this->arrayOfModules[] = $a;
572
573
        return $this;
574
    }
575
576
    /**
577
     * returns an array of existing paths
578
     *
579
     * @return array
580
     */
581
    public function getExistingModuleDirLocations()
582
    {
583
        $array = [];
584
        foreach ($this->moduleDirLocations as $location) {
585
            if ($location = $this->checkIfPathExistsAndCleanItUp($location)) {
586
                $array[$location] = $location;
587
            }
588
        }
589
        if (count($array) === 0) {
590
            if ($this->getIsModuleUpgrade()) {
0 ignored issues
show
Bug introduced by
The method getIsModuleUpgrade() does not exist on Sunnysideup\UpgradeToSilverstripe4\ModuleUpgrader. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

590
            if ($this->/** @scrutinizer ignore-call */ getIsModuleUpgrade()) {
Loading history...
591
            } else {
592
                user_error(
593
                    'You need to set moduleDirLocations (setModuleDirLocations)
594
                    as there are currently none.'
595
                );
596
            }
597
        }
598
599
        return $array;
600
    }
601
602
    public function getExistingModuleDirLocationsWithThemeFolders()
603
    {
604
        $array = $this->getExistingModuleDirLocations();
605
        if ($this->themeDirLocation) {
606
            $array[$this->themeDirLocation] = $this->themeDirLocation;
607
        }
608
609
        return $array;
610
    }
611
612
    /**
613
     * returns path for module
614
     *
615
     * @return string
616
     */
617
    public function getExistingFirstModuleDirLocation()
618
    {
619
        $locations = array_values($this->getExistingModuleDirLocations());
620
        return array_shift($locations);
621
    }
622
623
    ###############################
624
    # USEFUL COMMANDS
625
    ###############################
626
627
    /**
628
     * Executes given operations on the PHP2CommandLineSingleton instance
629
     * Documentation for this can be found in the PHP2CommandLineSingleton module
630
     *
631
     * @param  string  $newDir                  root dir for ommand
632
     * @param  string  $command                 actual command
633
     * @param  string  $comment                 comment
634
     * @param  boolean $alwaysRun               run even if you are just preparing a real run. Default FALSE
635
     * @param  string  $keyNotesLogFileLocation
636
     *
637
     * @return void
638
     */
639
    public function execMe(
640
        $newDir,
641
        $command,
642
        $comment,
643
        $alwaysRun = false,
644
        $keyNotesLogFileLocation = ''
645
    ) {
646
        if ($keyNotesLogFileLocation) {
647
            $this->commandLineExec
648
                ->setMakeKeyNotes(true)
649
                ->setKeyNotesFileLocation($keyNotesLogFileLocation);
650
        } else {
651
            $this->commandLineExec
652
                ->setMakeKeyNotes(false);
653
        }
654
655
        return $this->commandLineExec->execMe($newDir, $command, $comment, $alwaysRun);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->commandLineExec->..., $comment, $alwaysRun) targeting Sunnysideup\PHP2CommandL...LineSingleton::execMe() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
656
    }
657
658
    /**
659
     * Executes given operations on the PHP2CommandLineSingleton instance
660
     * Documentation for this can be found in the PHP2CommandLineSingleton module
661
     */
662
    public function colourPrint($mixedVar, $colour = 'dark_gray', $newLineCount = 1)
663
    {
664
        return $this->commandLineExec->colourPrint($mixedVar, $colour, $newLineCount);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->commandLineExec->...$colour, $newLineCount) targeting Sunnysideup\PHP2CommandL...ingleton::colourPrint() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
665
    }
666
667
    /**
668
     * Locates the directory in which the code is kept within the module directory
669
     *
670
     * If it can be found returns the location otherwise it errors
671
     *
672
     * @return array codedirlocation
673
     */
674
    public function findNameSpaceAndCodeDirs()
675
    {
676
        $codeDirs = [];
677
        $locations = $this->getExistingModuleDirLocations();
678
        foreach ($locations as $location) {
679
            $codeDir = $this->findMyCodeDir($location);
680
            if ($codeDir) {
681
                if ($this->getIsModuleUpgrade()) {
682
                    $baseNameSpace = $this->getVendorNamespace() . '\\' . $this->getPackageNamespace() . '\\';
0 ignored issues
show
Bug introduced by
The method getPackageNamespace() does not exist on Sunnysideup\UpgradeToSilverstripe4\ModuleUpgrader. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

682
                    $baseNameSpace = $this->getVendorNamespace() . '\\' . $this->/** @scrutinizer ignore-call */ getPackageNamespace() . '\\';
Loading history...
Bug introduced by
The method getVendorNamespace() does not exist on Sunnysideup\UpgradeToSilverstripe4\ModuleUpgrader. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

682
                    $baseNameSpace = $this->/** @scrutinizer ignore-call */ getVendorNamespace() . '\\' . $this->getPackageNamespace() . '\\';
Loading history...
683
                } else {
684
                    $nameSpaceKey = ucwords(basename($location));
685
                    if (strtolower($nameSpaceKey) === 'app' || strtolower($nameSpaceKey) === 'mysite') {
686
                        $nameSpaceKey = $this->getPackageNamespace();
687
                    }
688
                    $baseNameSpace = $this->getVendorNamespace() . '\\' . $nameSpaceKey . '\\';
689
                }
690
                $codeDirs[$baseNameSpace] = $codeDir;
691
            }
692
        }
693
694
        return $codeDirs;
695
    }
696
697
    public function findMyCodeDir($moduleDir)
698
    {
699
        if (file_exists($moduleDir)) {
700
            $test1 = $moduleDir . '/code';
701
            $test2 = $moduleDir . '/src';
702
            if (file_exists($test1) && file_exists($test2)) {
703
                user_error('There is a code and a src dir for ' . $moduleDir, E_USER_NOTICE);
704
            } elseif (file_exists($test1)) {
705
                return $moduleDir . '/code';
706
            } elseif (file_exists($test2)) {
707
                return $moduleDir . '/src';
708
            } else {
709
                user_error('Can not find code/src dir for ' . $moduleDir, E_USER_NOTICE);
710
            }
711
        }
712
    }
713
714
    public function getGitRootDir()
715
    {
716
        if ($this->getIsModuleUpgrade()) {
717
            $location = $this->getExistingFirstModuleDirLocation();
718
            if (! $location) {
719
                return $this->moduleDirLocations[0];
720
            }
721
        } else {
722
            $location = $this->getWebRootDirLocation();
0 ignored issues
show
Bug introduced by
The method getWebRootDirLocation() does not exist on Sunnysideup\UpgradeToSilverstripe4\ModuleUpgrader. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

722
            /** @scrutinizer ignore-call */ 
723
            $location = $this->getWebRootDirLocation();
Loading history...
723
        }
724
725
        return $location;
726
    }
727
728
    /**
729
     * Cleans an input string and returns a more natural human readable version
730
     * @param  string $str input string
731
     * @param  array  $noStrip
732
     * @return string cleaned string
733
     */
734
    public function camelCase($str, array $noStrip = [])
735
    {
736
        $str = str_replace('-', ' ', $str);
737
        $str = str_replace('_', ' ', $str);
738
        // non-alpha and non-numeric characters become spaces
739
        $str = preg_replace('/[^a-z0-9' . implode('', $noStrip) . ']+/i', ' ', $str);
740
        $str = trim($str);
741
        // uppercase the first character of each word
742
        $str = ucwords($str);
743
        return str_replace(' ', '', $str);
744
    }
745
746
    /**
747
     * returns path in a consistent format
748
     * e.g. /var/www
749
     *
750
     * @param  string $path
751
     *
752
     * @return string | null
753
     */
754
    public function checkIfPathExistsAndCleanItUp($path, $returnEvenIfItDoesNotExists = false)
755
    {
756
        $originalPath = $path;
0 ignored issues
show
Unused Code introduced by
The assignment to $originalPath is dead and can be removed.
Loading history...
757
        $path = str_replace('///', '/', $path);
758
        $path = str_replace('//', '/', $path);
759
        if (file_exists($path)) {
760
            $path = realpath($path);
761
        }
762
        if (file_exists($path) || $returnEvenIfItDoesNotExists) {
763
            return rtrim($path, '/');
764
        }
765
    }
766
767
    ###############################
768
    # RUN
769
    ###############################
770
771
    public function createListOfTasks()
772
    {
773
        $html = '<h1>List of Tasks in run order</h1>';
774
        $count = 0;
775
        $totalCount = count($this->listOfTasks);
0 ignored issues
show
Unused Code introduced by
The assignment to $totalCount is dead and can be removed.
Loading history...
776
        $previousStep = '';
777
        foreach ($this->listOfTasks as $class => $params) {
778
            $properClass = current(explode('-', $class));
779
            $nameSpacesArray = explode('\\', $class);
780
            $shortClassCode = end($nameSpacesArray);
781
            if (! class_exists($properClass)) {
782
                $properClass = $this->defaultNamespaceForTasks . '\\' . $properClass;
783
            }
784
            if (class_exists($properClass)) {
785
                $count++;
786
                $runItNow = $this->shouldWeRunIt($shortClassCode);
0 ignored issues
show
Unused Code introduced by
The assignment to $runItNow is dead and can be removed.
Loading history...
787
                $params['taskName'] = $shortClassCode;
788
                $obj = $properClass::create($this, $params);
789
                if ($obj->getTaskName()) {
790
                    $params['taskName'] = $obj->getTaskName();
791
                }
792
                $reflectionClass = new \ReflectionClass($properClass);
793
                $path = 'https://github.com/sunnysideup/silverstripe-upgrade_to_silverstripe_4/tree/master/src/';
794
                $path .= str_replace('\\', '/', $reflectionClass->getName()) . '.php';
795
                $path = str_replace('Sunnysideup/UpgradeToSilverstripe4/', '', $path);
796
                $currentStepCode = $obj->getTaskStepCode();
797
                $currentStep = $obj->getTaskStep($currentStepCode);
798
                if ($currentStepCode === 's00') {
799
                    //do nothing when it is an anytime step
800
                } else {
801
                    if ($previousStep !== $currentStep) {
802
                        $html .= '<h2>' . $currentStep . '</h2>';
803
                    }
804
                    $previousStep = $currentStep;
805
                }
806
                $html .= '<h4>' . $count . ': ' . $obj->getTitle() . '</h4>';
807
                $html .= '<p>' . $obj->getDescription() . '<br />';
808
                $html .= '<strong>Code: </strong>' . $class;
809
                $html .= '<br /><strong>Class Name: </strong><a href="' . $path . '">' . $reflectionClass->getShortName() . '</a>';
810
                $html .= '</p>';
811
                $obj = $properClass::deleteTask($params);
0 ignored issues
show
Unused Code introduced by
The assignment to $obj is dead and can be removed.
Loading history...
812
            } else {
813
                user_error($properClass . ' could not be found as class', E_USER_ERROR);
814
            }
815
        }
816
        $dir = __DIR__ . '/../docs/en/';
817
        file_put_contents(
818
            $dir . '/AvailableTasks.md',
819
            $html
820
        );
821
    }
822
823
    /**
824
     * Starts the command line output and prints some opening information to the output
825
     * also initalises various environment variables
826
     */
827
    public function run()
828
    {
829
        $this->startPHP2CommandLine();
830
        for ($i = 0; $i < 500; $i++) {
831
            $this->colourPrint(
832
                '.',
833
                'light_red',
834
                5
835
            );
836
        }
837
        //Init UTIL and helper objects
838
        $this->colourPrint(
839
            '===================== START ======================',
840
            'light_red',
841
            5
842
        );
843
        $this->loadNextStepInstructions();
844
        $this->aboveWebRootDirLocation = $this->checkIfPathExistsAndCleanItUp($this->aboveWebRootDirLocation);
845
        $this->webRootDirLocation = $this->checkIfPathExistsAndCleanItUp($this->aboveWebRootDirLocation . '/' . $this->webRootName, true);
846
        $this->themeDirLocation = $this->checkIfPathExistsAndCleanItUp($this->webRootDirLocation . '/themes', true);
847
        foreach ($this->arrayOfModules as $counter => $moduleDetails) {
848
            $this->loadVarsForModule($moduleDetails);
849
            $this->workOutMethodsToRun();
850
            $this->printVarsForModule($moduleDetails);
851
            foreach ($this->listOfTasks as $class => $params) {
852
                $properClass = current(explode('-', $class));
853
                $nameSpacesArray = explode('\\', $class);
854
                $shortClassCode = end($nameSpacesArray);
855
                if (! class_exists($properClass)) {
856
                    $properClass = $this->defaultNamespaceForTasks . '\\' . $properClass;
857
                }
858
                if (class_exists($properClass)) {
859
                    $runItNow = $this->shouldWeRunIt($shortClassCode);
860
                    $params['taskName'] = $shortClassCode;
861
                    $obj = $properClass::create($this, $params);
862
                    if ($obj->getTaskName()) {
863
                        $params['taskName'] = $obj->getTaskName();
864
                    }
865
                    if ($runItNow) {
866
                        $this->colourPrint('# --------------------', 'yellow', 3);
867
                        $this->colourPrint('# ' . $obj->getTitle() . ' (' . $params['taskName'] . ')', 'yellow');
868
                        $this->colourPrint('# --------------------', 'yellow');
869
                        $this->colourPrint('# ' . $obj->getDescriptionNice(), 'dark_grey');
870
                        $this->colourPrint('# --------------------', 'dark_grey');
871
                        $obj->run();
872
                        if ($this->runInteractively) {
873
                            $this->setSessionValue('Completed', $class);
874
                        }
875
                    } else {
876
                        if (! $this->runInteractively) {
877
                            $this->colourPrint('# --------------------', 'yellow', 3);
878
                            $this->colourPrint('# ' . $obj->getTitle() . ' (' . $params['taskName'] . ')', 'yellow');
879
                            $this->colourPrint('# --------------------', 'yellow');
880
                            $this->colourPrint('# skipped', 'yellow');
881
                            $this->colourPrint('# --------------------', 'yellow');
882
                        }
883
                    }
884
                    $obj = $properClass::deleteTask($params);
0 ignored issues
show
Unused Code introduced by
The assignment to $obj is dead and can be removed.
Loading history...
885
                } else {
886
                    user_error($properClass . ' could not be found as class. You can add namespacing to include your own classes.', E_USER_ERROR);
887
                }
888
            }
889
        }
890
        $this->colourPrint(
891
            '===================== END =======================',
892
            'light_red',
893
            5
894
        );
895
        $this->endPHP2CommandLine();
896
    }
897
898
    /**
899
     * What is the index of given task within the sequence
900
     *
901
     * @param string $s name of the task to find
902
     *
903
     * @return mixed the key/index of task
904
     */
905
    protected function positionForTask($s)
906
    {
907
        if (isset($this->listOfTasks[$s])) {
908
            return $s;
909
        }
910
        return array_search($s, $this->listOfTasks, true);
911
    }
912
913
    protected function loadNextStepInstructions()
914
    {
915
        if (PHP_SAPI === 'cli') {
916
            $this->restartSession = isset($argv[1]) && $argv[1] === 'restart';
917
        } else {
918
            $this->restartSession = isset($_GET['restart']);
919
        }
920
        if (PHP_SAPI === 'cli') {
921
            $this->runLastOneAgain = isset($argv[1]) && $argv[1] === 'again';
922
        } else {
923
            $this->runLastOneAgain = isset($_GET['again']);
924
        }
925
        //todo next / previous / etc...
926
    }
927
928
    /**
929
     * Starts the logger. Extra checking may be put in here to see if you
930
     * want to start the logger or not in different scenarios.
931
     *
932
     * For now it defaults to always existing
933
     * @return [type] [description]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
934
     */
935
    protected function startPHP2CommandLine()
936
    {
937
        $this->commandLineExec = PHP2CommandLineSingleton::create();
938
    }
939
940
    /**
941
     * deconstructs Command Line
942
     * important as this outputs the whole thing
943
     */
944
    protected function endPHP2CommandLine()
945
    {
946
        if ($this->commandLineExec !== null) {
947
            $this->commandLineExec = PHP2CommandLineSingleton::delete();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $this->commandLineExec is correct as Sunnysideup\PHP2CommandL...LineSingleton::delete() targeting Sunnysideup\PHP2CommandL...LineSingleton::delete() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
948
        }
949
    }
950
951
    /**
952
     * Loads in and sets all the meta data for a module from the inputed array
953
     * @param array $moduleDetails
954
     */
955
    protected function loadVarsForModule($moduleDetails)
956
    {
957
958
        //Is Module Upgrade
959
        //do this first as a lot of other functions rely on it ...
960
        $this->isModuleUpgrade = isset($moduleDetails['IsModuleUpgrade']) ? $moduleDetails['IsModuleUpgrade'] : true;
961
962
        //VendorName
963
        $this->vendorName = $moduleDetails['VendorName'];
964
965
        //VendorNamespace
966
        if (isset($moduleDetails['VendorNamespace'])) {
967
            $this->vendorNamespace = $moduleDetails['VendorNamespace'];
968
        } else {
969
            $this->vendorNamespace = $this->camelCase($this->vendorName);
970
        }
971
972
        //PackageName
973
        $this->packageName = $moduleDetails['PackageName'];
974
975
        //PackageNamespace
976
        if (isset($moduleDetails['PackageNamespace'])) {
977
            $this->packageNamespace = $moduleDetails['PackageNamespace'];
978
        } else {
979
            $this->packageNamespace = $this->camelCase($this->packageName);
980
        }
981
982
        if (isset($moduleDetails['GitLink'])) {
983
            $this->gitLink = $moduleDetails['GitLink'];
984
        } else {
985
            $this->gitLink = '[email protected]:' . $this->vendorName . '/silverstripe-' . $this->packageName . '.git';
986
        }
987
        //see: https://stackoverflow.com/questions/5573334/remove-a-part-of-a-string-but-only-when-it-is-at-the-end-of-the-string
988
        $gitLinkWithoutExtension = preg_replace('/' . preg_quote('.git', '/') . '$/', '', $this->gitLink);
989
        $this->gitLinkAsHTTPS = str_replace('[email protected]:', 'https://github.com/', $gitLinkWithoutExtension);
990
        $this->gitLinkAsRawHTTPS = str_replace('[email protected]:', 'https://raw.githubusercontent.com/', $gitLinkWithoutExtension);
991
992
        //Origin Composer FileLocation
993
        $this->originComposerFileLocation = isset($moduleDetails['OriginComposerFileLocation']) ? $moduleDetails['OriginComposerFileLocation'] : '';
994
        if ($this->packageFolderNameForInstall) {
995
            //do nothing
996
        } else {
997
            if ($this->getSessionValue('PackageFolderNameForInstall')) {
998
                $this->packageFolderNameForInstall = $this->getSessionValue('PackageFolderNameForInstall');
999
            } else {
1000
                if (! $this->originComposerFileLocation) {
1001
                    $this->originComposerFileLocation = $this->gitLinkAsRawHTTPS . '/master/composer.json';
1002
                }
1003
                if ($this->URLExists($this->originComposerFileLocation)) {
1004
                    $json = file_get_contents($this->originComposerFileLocation);
1005
                    $array = json_decode($json, true);
1006
                    if (isset($array['extra']['installer-name'])) {
1007
                        $this->packageFolderNameForInstall = $array['extra']['installer-name'];
1008
                    } else {
1009
                        if ($this->isModuleUpgrade) {
1010
                            $this->packageFolderNameForInstall = $this->packageName;
1011
                        } else {
1012
                            $this->packageFolderNameForInstall = 'mysite';
1013
                        }
1014
                    }
1015
                    if (isset($moduleDetails['PackageFolderNameForInstall'])) {
1016
                        $this->packageFolderNameForInstall = $moduleDetails['PackageFolderNameForInstall'];
1017
                    }
1018
                }
1019
                //user_error('You need to set originComposerFileLocation using ->setOriginComposerFileLocation. Could not find: '.$this->originComposerFileLocation);
1020
            }
1021
            $this->setSessionValue('PackageFolderNameForInstall', $this->packageFolderNameForInstall);
1022
        }
1023
1024
        //moduleDirLocation
1025
        if ($this->isModuleUpgrade) {
1026
            $this->moduleDirLocations = [
1027
                $this->webRootDirLocation . '/' . $this->packageFolderNameForInstall,
1028
            ];
1029
            $this->themeDirLocation = null;
1030
        } else {
1031
            if (! count($this->moduleDirLocations)) {
1032
                $this->moduleDirLocations[] = $this->webRootDirLocation . '/mysite';
1033
                $this->moduleDirLocations[] = $this->webRootDirLocation . '/app';
1034
            } else {
1035
                foreach ($this->moduleDirLocations as $key => $location) {
1036
                    $this->moduleDirLocations[$key] = $this->webRootDirLocation . '/' . $location;
1037
                }
1038
            }
1039
        }
1040
1041
        //ss4 location
1042
        if (isset($moduleDetails['VendorAndPackageFolderNameForInstall'])) {
1043
            $this->vendorAndPackageFolderNameForInstall = $moduleDetails['VendorAndPackageFolderNameForInstall'];
1044
        } else {
1045
            $this->vendorAndPackageFolderNameForInstall = strtolower($this->vendorName . '/' . $this->packageName);
1046
        }
1047
1048
        //UpgradeAsFork
1049
        $this->upgradeAsFork = empty($moduleDetails['UpgradeAsFork']) ? false : true;
1050
1051
        //LogFileLocation
1052
        $this->logFileLocation = '';
1053
        if ($this->logFolderDirLocation) {
1054
            $this->logFileLocation = $this->logFolderDirLocation . '/' . $this->packageName . '-upgrade-log.' . time() . '.txt';
1055
            $this->commandLineExec->setLogFileLocation($this->logFileLocation);
1056
        } else {
1057
            $this->commandLineExec->setLogFileLocation('');
1058
        }
1059
1060
        if ($this->restartSession) {
1061
            $this->deleteSession();
1062
        }
1063
    }
1064
1065
    protected function printVarsForModule($moduleDetails)
0 ignored issues
show
Unused Code introduced by
The parameter $moduleDetails is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1065
    protected function printVarsForModule(/** @scrutinizer ignore-unused */ $moduleDetails)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1066
    {
1067
        //output the confirmation.
1068
        $this->colourPrint('---------------------', 'light_cyan');
1069
        $this->colourPrint('UPGRADE DETAILS', 'light_cyan');
1070
        $this->colourPrint('---------------------', 'light_cyan');
1071
        $this->colourPrint('- Type: ' . ($this->getIsModuleUpgrade() ? 'module' : 'project'), 'light_cyan');
1072
        $this->colourPrint('- ---', 'light_cyan');
1073
        $this->colourPrint('- Vendor Name: ' . $this->vendorName, 'light_cyan');
1074
        $this->colourPrint('- Package Name: ' . $this->packageName, 'light_cyan');
1075
        $this->colourPrint('- ---', 'light_cyan');
1076
        $this->colourPrint('- Upgrade as Fork: ' . ($this->upgradeAsFork ? 'yes' : 'no'), 'light_cyan');
1077
        $this->colourPrint('- Run Interactively: ' . ($this->runInteractively ? 'yes' : 'no'), 'light_cyan');
1078
        $this->colourPrint('- Run Irreversibly: ' . ($this->runIrreversibly ? 'yes' : 'no'), 'light_cyan');
1079
        $this->colourPrint('- Is Module Upgrade: ' . ($this->isModuleUpgrade ? 'yes' : 'no'), 'light_cyan');
1080
        $this->colourPrint('- ---', 'light_cyan');
1081
        $this->colourPrint('- Vendor Namespace: ' . $this->vendorNamespace, 'light_cyan');
1082
        $this->colourPrint('- Package Namespace: ' . $this->packageNamespace, 'light_cyan');
1083
        $this->colourPrint('- ---', 'light_cyan');
1084
        $this->colourPrint('- Upgrade Dir (root of install): ' . $this->getWebRootDirLocation(), 'light_cyan');
1085
        $this->colourPrint('- Package Folder Name For Install: ' . $this->packageFolderNameForInstall, 'light_cyan');
1086
        $this->colourPrint('- Module / Project Dir(s): ' . implode(', ', $this->moduleDirLocations), 'light_cyan');
1087
        $this->colourPrint('- Theme Dir: ' . $this->themeDirLocation, 'light_cyan');
1088
        $this->colourPrint('- Git and Composer Root Dir: ' . $this->getGitRootDir(), 'light_cyan');
1089
        $this->colourPrint('- ---', 'light_cyan');
1090
        $this->colourPrint('- Git Repository Link (SSH): ' . $this->gitLink, 'light_cyan');
1091
        $this->colourPrint('- Git Repository Link (HTTPS): ' . $this->gitLinkAsHTTPS, 'light_cyan');
1092
        $this->colourPrint('- Git Repository Link (RAW): ' . $this->gitLinkAsRawHTTPS, 'light_cyan');
1093
        $this->colourPrint('- Origin composer file location: ' . $this->originComposerFileLocation, 'light_cyan');
1094
        $this->colourPrint('- ---', 'light_cyan');
1095
        $this->colourPrint('- Session file: ' . $this->getSessionFileLocation(), 'light_cyan');
1096
        $this->colourPrint('- ---', 'light_cyan');
1097
        $this->colourPrint('- Last Step: ' . ($this->getSessionValue('Completed') ?: 'not set'), 'light_cyan');
1098
        $this->colourPrint('- ---', 'light_cyan');
1099
        $this->colourPrint('- Log File Location: ' . ($this->logFileLocation ?: 'not logged'), 'light_cyan');
1100
        $this->colourPrint('- ---', 'light_cyan');
1101
        $this->colourPrint('- List of Steps: ' . $this->newLine() . ' -' . implode($this->newLine() . '    -', array_keys($this->listOfTasks)), 'light_cyan');
1102
        $this->colourPrint('---------------------', 'light_cyan');
1103
    }
1104
1105
    /**
1106
     * work out the current one to run!
1107
     *
1108
     * @return string
1109
     */
1110
    protected function workOutMethodsToRun()
1111
    {
1112
        if ($this->runInteractively) {
1113
            if ($this->startFrom || $this->endWith) {
1114
                user_error('In interactive mode you can not set StartFrom / EndWith / OnlyRun.');
1115
            }
1116
            if ($this->onlyRun) {
1117
            } else {
1118
                $lastMethod = $this->getSessionValue('Completed');
1119
                if ($lastMethod) {
1120
                    $this->verbose = false;
1121
                    $arrayKeys = array_keys($this->listOfTasks);
1122
                    $found = false;
1123
                    foreach ($arrayKeys as $index => $key) {
1124
                        if ($key === $lastMethod) {
1125
                            $found = true;
1126
                            if ($this->runLastOneAgain) {
1127
                                $this->onlyRun = $arrayKeys[$index];
1128
                            } else {
1129
                                if (isset($arrayKeys[$index + 1])) {
1130
                                    if (isset($this->listOfTasks[$arrayKeys[$index + 1]])) {
1131
                                        $this->onlyRun = $arrayKeys[$index + 1];
1132
                                    } else {
1133
                                        user_error('Can not find next task: ' . $arrayKeys[$index + 1]);
1134
                                    }
1135
                                } else {
1136
                                    $this->deleteSession();
1137
                                    die('
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1138
==========================================
1139
Session has completed.
1140
==========================================
1141
                                    ');
1142
                                }
1143
                            }
1144
                        }
1145
                    }
1146
                    if (! $found) {
1147
                        user_error('Did not find next step.');
1148
                    }
1149
                } else {
1150
                    $this->verbose = true;
1151
                    reset($this->listOfTasks);
1152
                    $this->onlyRun = key($this->listOfTasks);
1153
                }
1154
            }
1155
        }
1156
    }
1157
1158
    protected function nextStep()
1159
    {
1160
    }
1161
1162
    /**
1163
     * start the method ...
1164
     * - should we run it?
1165
     *
1166
     * @param  string $name whatever is listed in the listOfTasks
1167
     * @return bool
1168
     */
1169
    protected function shouldWeRunIt($name): bool
1170
    {
1171
        $runMe = true;
1172
        if ($this->onlyRun) {
1173
            return $name === $this->onlyRun ? true : false;
1174
        }
1175
        if ($this->lastMethodHasBeenRun) {
1176
            $runMe = false;
1177
        } else {
1178
            if ($this->startFrom) {
1179
                $runMe = false;
1180
                if ($name === $this->startFrom) {
1181
                    $this->startFrom = '';
1182
                }
1183
            }
1184
            if ($this->endWith) {
1185
                if ($name === $this->endWith) {
1186
                    $this->lastMethodHasBeenRun = true;
1187
                }
1188
            }
1189
        }
1190
1191
        //here we call the PHP2CommandLine
1192
1193
        return $runMe;
1194
    }
1195
1196
    protected function getSessionFileLocation()
1197
    {
1198
        return trim(
1199
            $this->getAboveWebRootDirLocation() .
0 ignored issues
show
Bug introduced by
The method getAboveWebRootDirLocation() does not exist on Sunnysideup\UpgradeToSilverstripe4\ModuleUpgrader. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1199
            $this->/** @scrutinizer ignore-call */ 
1200
                   getAboveWebRootDirLocation() .
Loading history...
1200
            '/' .
1201
            $this->sessionFileName .
1202
            '_' .
1203
            $this->getVendorNamespace() .
1204
            '_' .
1205
            $this->getPackageNamespace() .
1206
            '.json'
1207
        );
1208
    }
1209
1210
    protected function initSession()
1211
    {
1212
        if (! file_exists($this->getSessionFileLocation())) {
1213
            $this->setSessionData(['Started' => date('Y-m-d h:i ')]);
1214
        }
1215
    }
1216
1217
    protected function deleteSession()
1218
    {
1219
        unlink($this->getSessionFileLocation());
1220
    }
1221
1222
    protected function getSessionValue($key)
1223
    {
1224
        $session = $this->getSessionData();
1225
        if (isset($session[$key])) {
1226
            return $session[$key];
1227
        }
1228
        return null;
1229
    }
1230
1231
    protected function getSessionData()
1232
    {
1233
        $this->initSession();
1234
        $data = file_get_contents($this->getSessionFileLocation());
1235
        if (! $data) {
1236
            user_error('Could not read from: ' . $this->getSessionFileLocation());
1237
        }
1238
        return json_decode($data, true);
1239
    }
1240
1241
    /**
1242
     * @param array $session
1243
     */
1244
    protected function setSessionData($session)
1245
    {
1246
        $data = json_encode($session, JSON_PRETTY_PRINT);
1247
        try {
1248
            $file = fopen($this->getSessionFileLocation(), 'w');
1249
            if ($file === false) {
1250
                throw new \RuntimeException('Failed to open file: ' . $this->getSessionFileLocation());
1251
            }
1252
            $writeOutcome = fwrite($file, $data);
1253
            if ($writeOutcome === false) {
1254
                throw new \RuntimeException('Failed to write file: ' . $this->getSessionFileLocation());
1255
            }
1256
            $closeOutcome = fclose($file);
1257
            if ($closeOutcome === false) {
1258
                throw new \RuntimeException('Failed to close file: ' . $this->getSessionFileLocation());
1259
            }
1260
        } catch (\Exception $e) {
1261
            // send error message if you can
1262
            $this->colourPrint(
1263
                'Caught exception: ' . $e->getMessage(),
1264
                'red',
1265
                2
1266
            );
1267
        }
1268
    }
1269
1270
    protected function setSessionValue($key, $value)
1271
    {
1272
        $session = $this->getSessionData();
1273
        $session[$key] = trim($value);
1274
        $this->setSessionData($session);
1275
    }
1276
1277
    protected function URLExists($url)
1278
    {
1279
        if ($url) {
1280
            $headers = get_headers($url);
1281
            if (is_array($headers) && count($headers)) {
1282
                foreach ($headers as $header) {
1283
                    if (substr($header, 9, 3) === '200') {
1284
                        return true;
1285
                    }
1286
                }
1287
            }
1288
        }
1289
        return false;
1290
    }
1291
1292
    protected function newLine()
1293
    {
1294
        if (PHP_SAPI === 'cli') {
1295
            return PHP_EOL;
1296
        }
1297
        return nl2br("\n");
1298
    }
1299
}
1300