1<?php
2
3declare(strict_types=1);
4
5namespace dokuwiki\plugin\dx\src;
6
7use LogicException;
8use RuntimeException;
9
10final class Standardize
11{
12    private const STANDARDIZE_VERSION = '0.1.0';
13
14    // TODO: add logger trait or something
15
16    public function standardizePlugin(string $pluginName): void
17    {
18        // figure out plugin standardize version
19
20        // check for no git changes in plugin directory
21        $this->ensurePluginDirPristine($pluginName);
22
23        // remove old files
24        $filesToDelete = [
25            '_test/general.test.php',
26            '.github/workflows/phpCS.yml', // old name of phpQuality.yml
27        ];
28        foreach ($filesToDelete as $fileName) {
29            $this->deleteFileFromPlugin($pluginName, $fileName);
30        }
31
32        // copy new files
33        $filesToCopy = [
34            '.versionrc.js',
35            'build/pluginInfoVersionUpdater.js',
36            '.github/workflows/testLinux.yml',
37            '.github/workflows/phpQuality.yml',
38            '.github/workflows/commit-lint.yml',
39            '_test/GeneralTest.php',
40        ];
41        foreach ($filesToCopy as $fileName) {
42            $this->copyFileToPlugin($pluginName, $fileName);
43        }
44        // write standardize version file?
45    }
46
47    private function ensurePluginDirPristine(string $pluginName): void
48    {
49        $pluginDir = DOKU_PLUGIN . $pluginName;
50        if (!file_exists($pluginDir) || !is_dir($pluginDir)) {
51            throw new RuntimeException("Plugin \"$pluginName\" does not exist in expected location \"$pluginDir\"!");
52        }
53
54        // TODO: check for git executable being available
55        //       and for .git directory being present in plugin dir
56
57        chdir($pluginDir);
58        $gitStatusOutput = shell_exec('git status --porcelain');
59        if ($gitStatusOutput !== null) {
60            throw new RuntimeException($pluginDir . ' has uncommited git changes or untracked files!');
61        }
62    }
63
64    private function deleteFileFromPlugin(string $pluginName, string $fileName): void
65    {
66        $targetFilePath = DOKU_PLUGIN . $pluginName . '/' . $fileName;
67        if (!file_exists($targetFilePath)) {
68            return;
69        }
70        if (!is_writable($targetFilePath)) {
71            throw new RuntimeException($targetFilePath . ' is not writable!');
72        }
73        unlink($targetFilePath);
74    }
75
76    private function copyFileToPlugin(string $pluginName, string $fileName): void
77    {
78        $filePath = DOKU_PLUGIN . 'dx/skel/' . $fileName . '.skel';
79        if (!file_exists($filePath)) {
80            throw new LogicException('file missing: ' . $filePath);
81        }
82        $fileContents = file_get_contents($filePath);
83        $fileContents = str_replace(
84            '@@PLUGIN_NAME@@',
85            $pluginName,
86            $fileContents
87        );
88        $targetFilePath = DOKU_PLUGIN . $pluginName . '/' . $fileName;
89
90        $this->makeFileDir($targetFilePath);
91        if (!is_writable(dirname($targetFilePath))) {
92            throw new RuntimeException($targetFilePath . ' is not writable!');
93        }
94        file_put_contents($targetFilePath, $fileContents);
95    }
96
97    private function makeFileDir(string $filePath): void
98    {
99        $dirPath = dirname($filePath);
100        if (file_exists($dirPath) && is_dir($dirPath)) {
101            // All good, directory already exists
102            return;
103        }
104        if (!mkdir($dirPath, 0755, true) && !is_dir($dirPath)) {
105            throw new RuntimeException(sprintf('Directory "%s" was not created', $dirPath));
106        }
107    }
108}
109