1 | <?php |
||
2 | |||
3 | // Set the directory to monitor |
||
4 | |||
5 | namespace Lepton; |
||
6 | |||
7 | use ScssPhp\ScssPhp\{Compiler, OutputStyle}; |
||
8 | |||
9 | class LeptonServer |
||
10 | { |
||
11 | private array $fileHashes = array(); |
||
12 | private array $dependancyTree = array(); |
||
13 | private bool $compile_sass = false; |
||
14 | private $webServerProcess; |
||
15 | |||
16 | public function __construct(public readonly string $sass_directory, public readonly string $css_directory, private readonly string $application) |
||
17 | { |
||
18 | |||
19 | echo "Running...".PHP_EOL; |
||
20 | |||
21 | if(is_dir($this->sass_directory)) { |
||
22 | // Clean output folder |
||
23 | array_map('unlink', array_filter((array) glob($this->css_directory."*"))); |
||
24 | |||
25 | $this->compile_sass = true; |
||
26 | echo "\e[32mCompiling assets...\e[39m".PHP_EOL; |
||
27 | |||
28 | $this->updateMainFiles(); |
||
29 | |||
30 | // Compile the files |
||
31 | foreach($this->fileHashes as $file => $hash) { |
||
32 | |||
33 | $file = realpath($file); |
||
34 | $fileDependancies = $this->compileFile($file); |
||
35 | $this->fileHashes[$file] = filemtime($file); |
||
36 | $this->dependancyTree[$file] = $fileDependancies; |
||
37 | foreach($fileDependancies as $dep) { |
||
38 | $this->fileHashes[realpath($dep)] = filemtime($dep); |
||
39 | } |
||
40 | } |
||
41 | |||
42 | |||
43 | echo "Dependancies tree built.".PHP_EOL.PHP_EOL; |
||
44 | |||
45 | // Compute md5 hash for files |
||
46 | foreach($this->dependancyTree as $file => $where) { |
||
47 | $fileHashes[$file] = filemtime($file); |
||
48 | } |
||
49 | |||
50 | } else { |
||
51 | echo "\e[32mNo _sass directory found\e[39m".PHP_EOL; |
||
52 | } |
||
53 | } |
||
54 | |||
55 | |||
56 | public function run() |
||
57 | { |
||
58 | |||
59 | |||
60 | declare(ticks=1); // Enable tick processing for signal handling |
||
61 | |||
62 | pcntl_signal(SIGINT, array($this, "terminate")); |
||
63 | |||
64 | echo "\e[32mWatching in ".$this->sass_directory."\e[39m".PHP_EOL.PHP_EOL; |
||
65 | |||
66 | echo "\e[33mStarting PHP WebServer (ONLY FOR DEVELOPMENT) at http://127.0.0.1:5555\e[39m".PHP_EOL.PHP_EOL; |
||
67 | |||
68 | //Start the PHP built-in web server |
||
69 | $command = sprintf('php -S localhost:5555 -t %s %s/webserver.php', $this->application, $this->application); |
||
70 | $this->webServerProcess = proc_open($command, [STDIN, STDOUT, STDERR], $pipes); |
||
71 | while(true) { |
||
72 | if($this->compile_sass) { |
||
73 | $this->cleanDeletedFiles(); |
||
74 | $this->updateMainFiles(); |
||
75 | foreach($this->fileHashes as $file => $hash) { |
||
76 | $file = realpath($file); |
||
77 | if(file_exists($file)) { |
||
78 | $newHash = filemtime($file); |
||
79 | if($newHash != $hash) { |
||
80 | echo "\e[93mFile $file modified!\e[39m".PHP_EOL; |
||
81 | $this->fileHashes[$file] = $newHash; |
||
82 | |||
83 | // if it's a main file |
||
84 | if(key_exists($file, $this->dependancyTree)) { |
||
85 | $this->dependancyTree[$file] = $this->compileFile($file); |
||
86 | } else { // if it's an included file |
||
87 | foreach($this->dependancyTree as $main => $dependancies) { |
||
88 | if(in_array($file, $dependancies)) { |
||
89 | $this->dependancyTree[$main] = $this->compileFile($main); |
||
90 | } |
||
91 | } |
||
92 | } |
||
93 | |||
94 | } |
||
95 | } else { |
||
96 | unset($this->fileHashes[$file]); |
||
97 | } |
||
98 | } |
||
99 | } |
||
100 | sleep(1); |
||
101 | } |
||
102 | |||
103 | } |
||
104 | |||
105 | public function terminate() |
||
106 | { |
||
107 | echo "\n\n\e[31mTERMINATING...\e[39m\n"; |
||
108 | proc_terminate($this->webServerProcess); |
||
109 | exit(130); |
||
0 ignored issues
–
show
|
|||
110 | } |
||
111 | |||
112 | |||
113 | public function cleanDeletedFiles() |
||
114 | { |
||
115 | |||
116 | foreach($this->fileHashes as $file => $hash) { |
||
117 | if(!file_exists($file)) { |
||
118 | unset($fileHashes[$file]); |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
119 | foreach($this->dependancyTree as $main => $dependancies) { |
||
120 | if($main == $file) { |
||
121 | unset($this->dependancyTree[$main]); |
||
122 | } |
||
123 | if(in_array($file, $dependancies)) { |
||
124 | $key = array_search($file, $dependancies); |
||
125 | unset($this->dependancyTree[$main][$key]); |
||
126 | } |
||
127 | } |
||
128 | } |
||
129 | } |
||
130 | } |
||
131 | |||
132 | |||
133 | public function compileScss($inputFile) |
||
134 | { |
||
135 | |||
136 | $compiler = new Compiler(); |
||
137 | $compiler->setImportPaths($this->sass_directory); |
||
138 | $compiler->setOutputStyle(OutputStyle::COMPRESSED); |
||
139 | |||
140 | if (is_file($inputFile)) { |
||
141 | // Set the path to the output CSS file |
||
142 | $outputFile = preg_replace('/(.*)\.(sass|scss)$/', '$1.css', basename($inputFile)); |
||
143 | $outputFile = $this->css_directory.$outputFile; |
||
144 | // Compile the SCSS code into CSS |
||
145 | try { |
||
146 | $result = $compiler->compileString(file_get_contents($inputFile)); |
||
147 | |||
148 | $outputdir = dirname($outputFile); |
||
149 | |||
150 | // Create the directories recursively |
||
151 | if (!is_dir($outputdir)) { |
||
152 | mkdir($outputdir, 0755, true); |
||
153 | } |
||
154 | file_put_contents($outputFile, $result->getCss()); |
||
155 | return $result->getIncludedFiles(); |
||
156 | } catch (\Exception $e) { |
||
157 | print_r($e); |
||
158 | syslog(LOG_ERR, 'scssphp: Unable to compile content'); |
||
159 | } |
||
160 | |||
161 | } else { |
||
162 | echo "Invalid file".PHP_EOL; |
||
163 | } |
||
164 | } |
||
165 | |||
166 | public function compileFile($file) |
||
167 | { |
||
168 | $fileNameArray = explode("/", $file); |
||
169 | $fileName = end($fileNameArray); |
||
170 | echo "\e[39m\t==> Compiling $fileName... \e[39m"; |
||
171 | $included = $this->compileScss($file); |
||
172 | echo "\e[32mDone!\e[39m".PHP_EOL; |
||
173 | return $included; |
||
174 | } |
||
175 | |||
176 | public function updateMainFiles() |
||
177 | { |
||
178 | $files = glob($this->sass_directory . '/*'); // Get all files in the directory |
||
179 | |||
180 | |||
181 | foreach ($files as $file) { |
||
182 | $file = realpath($file); |
||
183 | $pattern = '/^\/.+\/[^_]*[.](scss|sass)/'; // Specify the regex pattern for file names |
||
184 | if(preg_match($pattern, $file)) { |
||
185 | if(! array_key_exists($file, $this->fileHashes)) { |
||
186 | $this->fileHashes[$file] = 0; |
||
187 | } |
||
188 | } |
||
189 | } |
||
190 | |||
191 | } |
||
192 | |||
193 | } |
||
194 |
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.