Completed
Push — master ( 99175c...aac9a1 )
by Morris
26:23 queued 09:51
created
lib/private/Template/CSSResourceLocator.php 2 patches
Indentation   +114 added lines, -114 removed lines patch added patch discarded remove patch
@@ -34,118 +34,118 @@
 block discarded – undo
34 34
 
35 35
 class CSSResourceLocator extends ResourceLocator {
36 36
 
37
-	/** @var SCSSCacher */
38
-	protected $scssCacher;
39
-
40
-	/**
41
-	 * @param ILogger $logger
42
-	 * @param string $theme
43
-	 * @param array $core_map
44
-	 * @param array $party_map
45
-	 * @param SCSSCacher $scssCacher
46
-	 */
47
-	public function __construct(ILogger $logger, $theme, $core_map, $party_map, $scssCacher) {
48
-		$this->scssCacher = $scssCacher;
49
-
50
-		parent::__construct($logger, $theme, $core_map, $party_map);
51
-	}
52
-
53
-	/**
54
-	 * @param string $style
55
-	 */
56
-	public function doFind($style) {
57
-		$app = substr($style, 0, strpos($style, '/'));
58
-		if (strpos($style, '3rdparty') === 0
59
-			&& $this->appendIfExist($this->thirdpartyroot, $style.'.css')
60
-			|| $this->cacheAndAppendScssIfExist($this->serverroot, $style.'.scss', $app)
61
-			|| $this->cacheAndAppendScssIfExist($this->serverroot, 'core/'.$style.'.scss')
62
-			|| $this->appendIfExist($this->serverroot, $style.'.css')
63
-			|| $this->appendIfExist($this->serverroot, 'core/'.$style.'.css')
64
-		) {
65
-			return;
66
-		}
67
-		$style = substr($style, strpos($style, '/')+1);
68
-		$app_path = \OC_App::getAppPath($app);
69
-		$app_url = \OC_App::getAppWebPath($app);
70
-
71
-		if ($app_path === false && $app_url === false) {
72
-			$this->logger->error('Could not find resource {resource} to load', [
73
-				'resource' => $app . '/' . $style . '.css',
74
-				'app' => 'cssresourceloader',
75
-			]);
76
-			return;
77
-		}
78
-
79
-		// Account for the possibility of having symlinks in app path. Doing
80
-		// this here instead of above as an empty argument to realpath gets
81
-		// turned into cwd.
82
-		$app_path = realpath($app_path);
83
-
84
-		if(!$this->cacheAndAppendScssIfExist($app_path, $style.'.scss', $app)) {
85
-			$this->append($app_path, $style.'.css', $app_url);
86
-		}
87
-	}
88
-
89
-	/**
90
-	 * @param string $style
91
-	 */
92
-	public function doFindTheme($style) {
93
-		$theme_dir = 'themes/'.$this->theme.'/';
94
-		$this->appendIfExist($this->serverroot, $theme_dir.'apps/'.$style.'.css')
95
-			|| $this->appendIfExist($this->serverroot, $theme_dir.$style.'.css')
96
-			|| $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$style.'.css');
97
-	}
98
-
99
-	/**
100
-	 * cache and append the scss $file if exist at $root
101
-	 *
102
-	 * @param string $root path to check
103
-	 * @param string $file the filename
104
-	 * @return bool True if the resource was found and cached, false otherwise
105
-	 */
106
-	protected function cacheAndAppendScssIfExist($root, $file, $app = 'core') {
107
-		if (is_file($root.'/'.$file)) {
108
-			if($this->scssCacher !== null) {
109
-				if($this->scssCacher->process($root, $file, $app)) {
110
-
111
-					$this->append($root, $this->scssCacher->getCachedSCSS($app, $file), \OC::$WEBROOT, true, true);
112
-					return true;
113
-				} else {
114
-					$this->logger->warning('Failed to compile and/or save '.$root.'/'.$file, ['app' => 'core']);
115
-					return false;
116
-				}
117
-			} else {
118
-				$this->logger->debug('Scss is disabled for '.$root.'/'.$file.', ignoring', ['app' => 'core']);
119
-				return true;
120
-			}
121
-		}
122
-		return false;
123
-	}
124
-
125
-	public function append($root, $file, $webRoot = null, $throw = true, $scss = false) {
126
-		if (!$scss) {
127
-			parent::append($root, $file, $webRoot, $throw);
128
-		} else {
129
-			if (!$webRoot) {
130
-				$webRoot = $this->findWebRoot($root);
131
-
132
-				if ($webRoot === null) {
133
-					$webRoot = '';
134
-					$this->logger->error('ResourceLocator can not find a web root (root: {root}, file: {file}, webRoot: {webRoot}, throw: {throw})', [
135
-						'app' => 'lib',
136
-						'root' => $root,
137
-						'file' => $file,
138
-						'webRoot' => $webRoot,
139
-						'throw' => $throw ? 'true' : 'false'
140
-					]);
141
-
142
-					if ($throw && $root === '/') {
143
-						throw new ResourceNotFoundException($file, $webRoot);
144
-					}
145
-				}
146
-			}
147
-
148
-			$this->resources[] = array($webRoot? : \OC::$WEBROOT, $webRoot, $file);
149
-		}
150
-	}
37
+    /** @var SCSSCacher */
38
+    protected $scssCacher;
39
+
40
+    /**
41
+     * @param ILogger $logger
42
+     * @param string $theme
43
+     * @param array $core_map
44
+     * @param array $party_map
45
+     * @param SCSSCacher $scssCacher
46
+     */
47
+    public function __construct(ILogger $logger, $theme, $core_map, $party_map, $scssCacher) {
48
+        $this->scssCacher = $scssCacher;
49
+
50
+        parent::__construct($logger, $theme, $core_map, $party_map);
51
+    }
52
+
53
+    /**
54
+     * @param string $style
55
+     */
56
+    public function doFind($style) {
57
+        $app = substr($style, 0, strpos($style, '/'));
58
+        if (strpos($style, '3rdparty') === 0
59
+            && $this->appendIfExist($this->thirdpartyroot, $style.'.css')
60
+            || $this->cacheAndAppendScssIfExist($this->serverroot, $style.'.scss', $app)
61
+            || $this->cacheAndAppendScssIfExist($this->serverroot, 'core/'.$style.'.scss')
62
+            || $this->appendIfExist($this->serverroot, $style.'.css')
63
+            || $this->appendIfExist($this->serverroot, 'core/'.$style.'.css')
64
+        ) {
65
+            return;
66
+        }
67
+        $style = substr($style, strpos($style, '/')+1);
68
+        $app_path = \OC_App::getAppPath($app);
69
+        $app_url = \OC_App::getAppWebPath($app);
70
+
71
+        if ($app_path === false && $app_url === false) {
72
+            $this->logger->error('Could not find resource {resource} to load', [
73
+                'resource' => $app . '/' . $style . '.css',
74
+                'app' => 'cssresourceloader',
75
+            ]);
76
+            return;
77
+        }
78
+
79
+        // Account for the possibility of having symlinks in app path. Doing
80
+        // this here instead of above as an empty argument to realpath gets
81
+        // turned into cwd.
82
+        $app_path = realpath($app_path);
83
+
84
+        if(!$this->cacheAndAppendScssIfExist($app_path, $style.'.scss', $app)) {
85
+            $this->append($app_path, $style.'.css', $app_url);
86
+        }
87
+    }
88
+
89
+    /**
90
+     * @param string $style
91
+     */
92
+    public function doFindTheme($style) {
93
+        $theme_dir = 'themes/'.$this->theme.'/';
94
+        $this->appendIfExist($this->serverroot, $theme_dir.'apps/'.$style.'.css')
95
+            || $this->appendIfExist($this->serverroot, $theme_dir.$style.'.css')
96
+            || $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$style.'.css');
97
+    }
98
+
99
+    /**
100
+     * cache and append the scss $file if exist at $root
101
+     *
102
+     * @param string $root path to check
103
+     * @param string $file the filename
104
+     * @return bool True if the resource was found and cached, false otherwise
105
+     */
106
+    protected function cacheAndAppendScssIfExist($root, $file, $app = 'core') {
107
+        if (is_file($root.'/'.$file)) {
108
+            if($this->scssCacher !== null) {
109
+                if($this->scssCacher->process($root, $file, $app)) {
110
+
111
+                    $this->append($root, $this->scssCacher->getCachedSCSS($app, $file), \OC::$WEBROOT, true, true);
112
+                    return true;
113
+                } else {
114
+                    $this->logger->warning('Failed to compile and/or save '.$root.'/'.$file, ['app' => 'core']);
115
+                    return false;
116
+                }
117
+            } else {
118
+                $this->logger->debug('Scss is disabled for '.$root.'/'.$file.', ignoring', ['app' => 'core']);
119
+                return true;
120
+            }
121
+        }
122
+        return false;
123
+    }
124
+
125
+    public function append($root, $file, $webRoot = null, $throw = true, $scss = false) {
126
+        if (!$scss) {
127
+            parent::append($root, $file, $webRoot, $throw);
128
+        } else {
129
+            if (!$webRoot) {
130
+                $webRoot = $this->findWebRoot($root);
131
+
132
+                if ($webRoot === null) {
133
+                    $webRoot = '';
134
+                    $this->logger->error('ResourceLocator can not find a web root (root: {root}, file: {file}, webRoot: {webRoot}, throw: {throw})', [
135
+                        'app' => 'lib',
136
+                        'root' => $root,
137
+                        'file' => $file,
138
+                        'webRoot' => $webRoot,
139
+                        'throw' => $throw ? 'true' : 'false'
140
+                    ]);
141
+
142
+                    if ($throw && $root === '/') {
143
+                        throw new ResourceNotFoundException($file, $webRoot);
144
+                    }
145
+                }
146
+            }
147
+
148
+            $this->resources[] = array($webRoot? : \OC::$WEBROOT, $webRoot, $file);
149
+        }
150
+    }
151 151
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -64,13 +64,13 @@  discard block
 block discarded – undo
64 64
 		) {
65 65
 			return;
66 66
 		}
67
-		$style = substr($style, strpos($style, '/')+1);
67
+		$style = substr($style, strpos($style, '/') + 1);
68 68
 		$app_path = \OC_App::getAppPath($app);
69 69
 		$app_url = \OC_App::getAppWebPath($app);
70 70
 
71 71
 		if ($app_path === false && $app_url === false) {
72 72
 			$this->logger->error('Could not find resource {resource} to load', [
73
-				'resource' => $app . '/' . $style . '.css',
73
+				'resource' => $app.'/'.$style.'.css',
74 74
 				'app' => 'cssresourceloader',
75 75
 			]);
76 76
 			return;
@@ -81,7 +81,7 @@  discard block
 block discarded – undo
81 81
 		// turned into cwd.
82 82
 		$app_path = realpath($app_path);
83 83
 
84
-		if(!$this->cacheAndAppendScssIfExist($app_path, $style.'.scss', $app)) {
84
+		if (!$this->cacheAndAppendScssIfExist($app_path, $style.'.scss', $app)) {
85 85
 			$this->append($app_path, $style.'.css', $app_url);
86 86
 		}
87 87
 	}
@@ -105,8 +105,8 @@  discard block
 block discarded – undo
105 105
 	 */
106 106
 	protected function cacheAndAppendScssIfExist($root, $file, $app = 'core') {
107 107
 		if (is_file($root.'/'.$file)) {
108
-			if($this->scssCacher !== null) {
109
-				if($this->scssCacher->process($root, $file, $app)) {
108
+			if ($this->scssCacher !== null) {
109
+				if ($this->scssCacher->process($root, $file, $app)) {
110 110
 
111 111
 					$this->append($root, $this->scssCacher->getCachedSCSS($app, $file), \OC::$WEBROOT, true, true);
112 112
 					return true;
@@ -145,7 +145,7 @@  discard block
 block discarded – undo
145 145
 				}
146 146
 			}
147 147
 
148
-			$this->resources[] = array($webRoot? : \OC::$WEBROOT, $webRoot, $file);
148
+			$this->resources[] = array($webRoot ?: \OC::$WEBROOT, $webRoot, $file);
149 149
 		}
150 150
 	}
151 151
 }
Please login to merge, or discard this patch.
lib/private/Template/SCSSCacher.php 2 patches
Indentation   +283 added lines, -283 removed lines patch added patch discarded remove patch
@@ -45,287 +45,287 @@
 block discarded – undo
45 45
 
46 46
 class SCSSCacher {
47 47
 
48
-	/** @var ILogger */
49
-	protected $logger;
50
-
51
-	/** @var IAppData */
52
-	protected $appData;
53
-
54
-	/** @var IURLGenerator */
55
-	protected $urlGenerator;
56
-
57
-	/** @var IConfig */
58
-	protected $config;
59
-
60
-	/** @var string */
61
-	protected $serverRoot;
62
-
63
-	/** @var ICache */
64
-	protected $depsCache;
65
-
66
-	/**
67
-	 * @param ILogger $logger
68
-	 * @param Factory $appDataFactory
69
-	 * @param IURLGenerator $urlGenerator
70
-	 * @param IConfig $config
71
-	 * @param \OC_Defaults $defaults
72
-	 * @param string $serverRoot
73
-	 * @param ICache $depsCache
74
-	 */
75
-	public function __construct(ILogger $logger,
76
-								Factory $appDataFactory,
77
-								IURLGenerator $urlGenerator,
78
-								IConfig $config,
79
-								\OC_Defaults $defaults,
80
-								$serverRoot,
81
-								ICache $depsCache) {
82
-		$this->logger = $logger;
83
-		$this->appData = $appDataFactory->get('css');
84
-		$this->urlGenerator = $urlGenerator;
85
-		$this->config = $config;
86
-		$this->defaults = $defaults;
87
-		$this->serverRoot = $serverRoot;
88
-		$this->depsCache = $depsCache;
89
-	}
90
-
91
-	/**
92
-	 * Process the caching process if needed
93
-	 * @param string $root Root path to the nextcloud installation
94
-	 * @param string $file
95
-	 * @param string $app The app name
96
-	 * @return boolean
97
-	 */
98
-	public function process($root, $file, $app) {
99
-		$path = explode('/', $root . '/' . $file);
100
-
101
-		$fileNameSCSS = array_pop($path);
102
-		$fileNameCSS = $this->prependBaseurlPrefix(str_replace('.scss', '.css', $fileNameSCSS));
103
-
104
-		$path = implode('/', $path);
105
-		$webDir = $this->getWebDir($path, $app, $this->serverRoot, \OC::$WEBROOT);
106
-
107
-		try {
108
-			$folder = $this->appData->getFolder($app);
109
-		} catch(NotFoundException $e) {
110
-			// creating css appdata folder
111
-			$folder = $this->appData->newFolder($app);
112
-		}
113
-
114
-
115
-		if(!$this->variablesChanged() && $this->isCached($fileNameCSS, $folder)) {
116
-			return true;
117
-		}
118
-		return $this->cache($path, $fileNameCSS, $fileNameSCSS, $folder, $webDir);
119
-	}
120
-
121
-	/**
122
-	 * @param $appName
123
-	 * @param $fileName
124
-	 * @return ISimpleFile
125
-	 */
126
-	public function getCachedCSS($appName, $fileName) {
127
-		$folder = $this->appData->getFolder($appName);
128
-		return $folder->getFile($this->prependBaseurlPrefix($fileName));
129
-	}
130
-
131
-	/**
132
-	 * Check if the file is cached or not
133
-	 * @param string $fileNameCSS
134
-	 * @param ISimpleFolder $folder
135
-	 * @return boolean
136
-	 */
137
-	private function isCached($fileNameCSS, ISimpleFolder $folder) {
138
-		try {
139
-			$cachedFile = $folder->getFile($fileNameCSS);
140
-			if ($cachedFile->getSize() > 0) {
141
-				$depFileName = $fileNameCSS . '.deps';
142
-				$deps = $this->depsCache->get($folder->getName() . '-' . $depFileName);
143
-				if ($deps === null) {
144
-					$depFile = $folder->getFile($depFileName);
145
-					$deps = $depFile->getContent();
146
-					//Set to memcache for next run
147
-					$this->depsCache->set($folder->getName() . '-' . $depFileName, $deps);
148
-				}
149
-				$deps = json_decode($deps, true);
150
-
151
-				foreach ($deps as $file=>$mtime) {
152
-					if (!file_exists($file) || filemtime($file) > $mtime) {
153
-						return false;
154
-					}
155
-				}
156
-			}
157
-			return true;
158
-		} catch(NotFoundException $e) {
159
-			return false;
160
-		}
161
-	}
162
-
163
-	/**
164
-	 * Check if the variables file has changed
165
-	 * @return bool
166
-	 */
167
-	private function variablesChanged() {
168
-		$injectedVariables = $this->getInjectedVariables();
169
-		if($this->config->getAppValue('core', 'scss.variables') !== md5($injectedVariables)) {
170
-			$this->resetCache();
171
-			$this->config->setAppValue('core', 'scss.variables', md5($injectedVariables));
172
-			return true;
173
-		}
174
-		return false;
175
-	}
176
-
177
-	/**
178
-	 * Cache the file with AppData
179
-	 * @param string $path
180
-	 * @param string $fileNameCSS
181
-	 * @param string $fileNameSCSS
182
-	 * @param ISimpleFolder $folder
183
-	 * @param string $webDir
184
-	 * @return boolean
185
-	 */
186
-	private function cache($path, $fileNameCSS, $fileNameSCSS, ISimpleFolder $folder, $webDir) {
187
-		$scss = new Compiler();
188
-		$scss->setImportPaths([
189
-			$path,
190
-			$this->serverRoot . '/core/css/',
191
-		]);
192
-		// Continue after throw
193
-		$scss->setIgnoreErrors(true);
194
-		if($this->config->getSystemValue('debug')) {
195
-			// Debug mode
196
-			$scss->setFormatter(Expanded::class);
197
-			$scss->setLineNumberStyle(Compiler::LINE_COMMENTS);
198
-		} else {
199
-			// Compression
200
-			$scss->setFormatter(Crunched::class);
201
-		}
202
-
203
-		try {
204
-			$cachedfile = $folder->getFile($fileNameCSS);
205
-		} catch(NotFoundException $e) {
206
-			$cachedfile = $folder->newFile($fileNameCSS);
207
-		}
208
-
209
-		$depFileName = $fileNameCSS . '.deps';
210
-		try {
211
-			$depFile = $folder->getFile($depFileName);
212
-		} catch (NotFoundException $e) {
213
-			$depFile = $folder->newFile($depFileName);
214
-		}
215
-
216
-		// Compile
217
-		try {
218
-			$compiledScss = $scss->compile(
219
-				'@import "variables.scss";' .
220
-				$this->getInjectedVariables() .
221
-				'@import "'.$fileNameSCSS.'";');
222
-		} catch(ParserException $e) {
223
-			$this->logger->error($e, ['app' => 'core']);
224
-			return false;
225
-		}
226
-
227
-		// Gzip file
228
-		try {
229
-			$gzipFile = $folder->getFile($fileNameCSS . '.gzip'); # Safari doesn't like .gz
230
-		} catch (NotFoundException $e) {
231
-			$gzipFile = $folder->newFile($fileNameCSS . '.gzip'); # Safari doesn't like .gz
232
-		}
233
-
234
-		try {
235
-			$data = $this->rebaseUrls($compiledScss, $webDir);
236
-			$cachedfile->putContent($data);
237
-			$deps = json_encode($scss->getParsedFiles());
238
-			$depFile->putContent($deps);
239
-			$this->depsCache->set($folder->getName() . '-' . $depFileName, $deps);
240
-			$gzipFile->putContent(gzencode($data, 9));
241
-			$this->logger->debug($webDir.'/'.$fileNameSCSS.' compiled and successfully cached', ['app' => 'core']);
242
-			return true;
243
-		} catch(NotPermittedException $e) {
244
-			return false;
245
-		}
246
-	}
247
-
248
-	/**
249
-	 * Reset scss cache by deleting all generated css files
250
-	 * We need to regenerate all files when variables change
251
-	 */
252
-	private function resetCache() {
253
-		$appDirectory = $this->appData->getDirectoryListing();
254
-		if(empty($appDirectory)){
255
-			return;
256
-		}
257
-		foreach ($appDirectory as $folder) {
258
-			foreach ($folder->getDirectoryListing() as $file) {
259
-				if (substr($file->getName(), -3) === "css" || substr($file->getName(), -4) === "deps") {
260
-					$file->delete();
261
-				}
262
-			}
263
-		}
264
-	}
265
-
266
-	/**
267
-	 * @return string SCSS code for variables from OC_Defaults
268
-	 */
269
-	private function getInjectedVariables() {
270
-		$variables = '';
271
-		foreach ($this->defaults->getScssVariables() as $key => $value) {
272
-			$variables .= '$' . $key . ': ' . $value . ';';
273
-		}
274
-		return $variables;
275
-	}
276
-
277
-	/**
278
-	 * Add the correct uri prefix to make uri valid again
279
-	 * @param string $css
280
-	 * @param string $webDir
281
-	 * @return string
282
-	 */
283
-	private function rebaseUrls($css, $webDir) {
284
-		$re = '/url\([\'"]([\.\w?=\/-]*)[\'"]\)/x';
285
-		$subst = 'url(\''.$webDir.'/$1\')';
286
-		return preg_replace($re, $subst, $css);
287
-	}
288
-
289
-	/**
290
-	 * Return the cached css file uri
291
-	 * @param string $appName the app name
292
-	 * @param string $fileName
293
-	 * @return string
294
-	 */
295
-	public function getCachedSCSS($appName, $fileName) {
296
-		$tmpfileLoc = explode('/', $fileName);
297
-		$fileName = array_pop($tmpfileLoc);
298
-		$fileName = $this->prependBaseurlPrefix(str_replace('.scss', '.css', $fileName));
299
-
300
-		return substr($this->urlGenerator->linkToRoute('core.Css.getCss', array('fileName' => $fileName, 'appName' => $appName)), strlen(\OC::$WEBROOT) + 1);
301
-	}
302
-
303
-	/**
304
-	 * Prepend hashed base url to the css file
305
-	 * @param $cssFile
306
-	 * @return string
307
-	 */
308
-	private function prependBaseurlPrefix($cssFile) {
309
-		$frontendController = ($this->config->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true');
310
-		return substr(md5($this->urlGenerator->getBaseUrl() . $frontendController), 0, 8) . '-' . $cssFile;
311
-	}
312
-
313
-	/**
314
-	 * Get WebDir root
315
-	 * @param string $path the css file path
316
-	 * @param string $appName the app name
317
-	 * @param string $serverRoot the server root path
318
-	 * @param string $webRoot the nextcloud installation root path
319
-	 * @return string the webDir
320
-	 */
321
-	private function getWebDir($path, $appName, $serverRoot, $webRoot) {
322
-		// Detect if path is within server root AND if path is within an app path
323
-		if ( strpos($path, $serverRoot) === false && $appWebPath = \OC_App::getAppWebPath($appName)) {
324
-			// Get the file path within the app directory
325
-			$appDirectoryPath = explode($appName, $path)[1];
326
-			// Remove the webroot
327
-			return str_replace($webRoot, '', $appWebPath.$appDirectoryPath);
328
-		}
329
-		return $webRoot.substr($path, strlen($serverRoot));
330
-	}
48
+    /** @var ILogger */
49
+    protected $logger;
50
+
51
+    /** @var IAppData */
52
+    protected $appData;
53
+
54
+    /** @var IURLGenerator */
55
+    protected $urlGenerator;
56
+
57
+    /** @var IConfig */
58
+    protected $config;
59
+
60
+    /** @var string */
61
+    protected $serverRoot;
62
+
63
+    /** @var ICache */
64
+    protected $depsCache;
65
+
66
+    /**
67
+     * @param ILogger $logger
68
+     * @param Factory $appDataFactory
69
+     * @param IURLGenerator $urlGenerator
70
+     * @param IConfig $config
71
+     * @param \OC_Defaults $defaults
72
+     * @param string $serverRoot
73
+     * @param ICache $depsCache
74
+     */
75
+    public function __construct(ILogger $logger,
76
+                                Factory $appDataFactory,
77
+                                IURLGenerator $urlGenerator,
78
+                                IConfig $config,
79
+                                \OC_Defaults $defaults,
80
+                                $serverRoot,
81
+                                ICache $depsCache) {
82
+        $this->logger = $logger;
83
+        $this->appData = $appDataFactory->get('css');
84
+        $this->urlGenerator = $urlGenerator;
85
+        $this->config = $config;
86
+        $this->defaults = $defaults;
87
+        $this->serverRoot = $serverRoot;
88
+        $this->depsCache = $depsCache;
89
+    }
90
+
91
+    /**
92
+     * Process the caching process if needed
93
+     * @param string $root Root path to the nextcloud installation
94
+     * @param string $file
95
+     * @param string $app The app name
96
+     * @return boolean
97
+     */
98
+    public function process($root, $file, $app) {
99
+        $path = explode('/', $root . '/' . $file);
100
+
101
+        $fileNameSCSS = array_pop($path);
102
+        $fileNameCSS = $this->prependBaseurlPrefix(str_replace('.scss', '.css', $fileNameSCSS));
103
+
104
+        $path = implode('/', $path);
105
+        $webDir = $this->getWebDir($path, $app, $this->serverRoot, \OC::$WEBROOT);
106
+
107
+        try {
108
+            $folder = $this->appData->getFolder($app);
109
+        } catch(NotFoundException $e) {
110
+            // creating css appdata folder
111
+            $folder = $this->appData->newFolder($app);
112
+        }
113
+
114
+
115
+        if(!$this->variablesChanged() && $this->isCached($fileNameCSS, $folder)) {
116
+            return true;
117
+        }
118
+        return $this->cache($path, $fileNameCSS, $fileNameSCSS, $folder, $webDir);
119
+    }
120
+
121
+    /**
122
+     * @param $appName
123
+     * @param $fileName
124
+     * @return ISimpleFile
125
+     */
126
+    public function getCachedCSS($appName, $fileName) {
127
+        $folder = $this->appData->getFolder($appName);
128
+        return $folder->getFile($this->prependBaseurlPrefix($fileName));
129
+    }
130
+
131
+    /**
132
+     * Check if the file is cached or not
133
+     * @param string $fileNameCSS
134
+     * @param ISimpleFolder $folder
135
+     * @return boolean
136
+     */
137
+    private function isCached($fileNameCSS, ISimpleFolder $folder) {
138
+        try {
139
+            $cachedFile = $folder->getFile($fileNameCSS);
140
+            if ($cachedFile->getSize() > 0) {
141
+                $depFileName = $fileNameCSS . '.deps';
142
+                $deps = $this->depsCache->get($folder->getName() . '-' . $depFileName);
143
+                if ($deps === null) {
144
+                    $depFile = $folder->getFile($depFileName);
145
+                    $deps = $depFile->getContent();
146
+                    //Set to memcache for next run
147
+                    $this->depsCache->set($folder->getName() . '-' . $depFileName, $deps);
148
+                }
149
+                $deps = json_decode($deps, true);
150
+
151
+                foreach ($deps as $file=>$mtime) {
152
+                    if (!file_exists($file) || filemtime($file) > $mtime) {
153
+                        return false;
154
+                    }
155
+                }
156
+            }
157
+            return true;
158
+        } catch(NotFoundException $e) {
159
+            return false;
160
+        }
161
+    }
162
+
163
+    /**
164
+     * Check if the variables file has changed
165
+     * @return bool
166
+     */
167
+    private function variablesChanged() {
168
+        $injectedVariables = $this->getInjectedVariables();
169
+        if($this->config->getAppValue('core', 'scss.variables') !== md5($injectedVariables)) {
170
+            $this->resetCache();
171
+            $this->config->setAppValue('core', 'scss.variables', md5($injectedVariables));
172
+            return true;
173
+        }
174
+        return false;
175
+    }
176
+
177
+    /**
178
+     * Cache the file with AppData
179
+     * @param string $path
180
+     * @param string $fileNameCSS
181
+     * @param string $fileNameSCSS
182
+     * @param ISimpleFolder $folder
183
+     * @param string $webDir
184
+     * @return boolean
185
+     */
186
+    private function cache($path, $fileNameCSS, $fileNameSCSS, ISimpleFolder $folder, $webDir) {
187
+        $scss = new Compiler();
188
+        $scss->setImportPaths([
189
+            $path,
190
+            $this->serverRoot . '/core/css/',
191
+        ]);
192
+        // Continue after throw
193
+        $scss->setIgnoreErrors(true);
194
+        if($this->config->getSystemValue('debug')) {
195
+            // Debug mode
196
+            $scss->setFormatter(Expanded::class);
197
+            $scss->setLineNumberStyle(Compiler::LINE_COMMENTS);
198
+        } else {
199
+            // Compression
200
+            $scss->setFormatter(Crunched::class);
201
+        }
202
+
203
+        try {
204
+            $cachedfile = $folder->getFile($fileNameCSS);
205
+        } catch(NotFoundException $e) {
206
+            $cachedfile = $folder->newFile($fileNameCSS);
207
+        }
208
+
209
+        $depFileName = $fileNameCSS . '.deps';
210
+        try {
211
+            $depFile = $folder->getFile($depFileName);
212
+        } catch (NotFoundException $e) {
213
+            $depFile = $folder->newFile($depFileName);
214
+        }
215
+
216
+        // Compile
217
+        try {
218
+            $compiledScss = $scss->compile(
219
+                '@import "variables.scss";' .
220
+                $this->getInjectedVariables() .
221
+                '@import "'.$fileNameSCSS.'";');
222
+        } catch(ParserException $e) {
223
+            $this->logger->error($e, ['app' => 'core']);
224
+            return false;
225
+        }
226
+
227
+        // Gzip file
228
+        try {
229
+            $gzipFile = $folder->getFile($fileNameCSS . '.gzip'); # Safari doesn't like .gz
230
+        } catch (NotFoundException $e) {
231
+            $gzipFile = $folder->newFile($fileNameCSS . '.gzip'); # Safari doesn't like .gz
232
+        }
233
+
234
+        try {
235
+            $data = $this->rebaseUrls($compiledScss, $webDir);
236
+            $cachedfile->putContent($data);
237
+            $deps = json_encode($scss->getParsedFiles());
238
+            $depFile->putContent($deps);
239
+            $this->depsCache->set($folder->getName() . '-' . $depFileName, $deps);
240
+            $gzipFile->putContent(gzencode($data, 9));
241
+            $this->logger->debug($webDir.'/'.$fileNameSCSS.' compiled and successfully cached', ['app' => 'core']);
242
+            return true;
243
+        } catch(NotPermittedException $e) {
244
+            return false;
245
+        }
246
+    }
247
+
248
+    /**
249
+     * Reset scss cache by deleting all generated css files
250
+     * We need to regenerate all files when variables change
251
+     */
252
+    private function resetCache() {
253
+        $appDirectory = $this->appData->getDirectoryListing();
254
+        if(empty($appDirectory)){
255
+            return;
256
+        }
257
+        foreach ($appDirectory as $folder) {
258
+            foreach ($folder->getDirectoryListing() as $file) {
259
+                if (substr($file->getName(), -3) === "css" || substr($file->getName(), -4) === "deps") {
260
+                    $file->delete();
261
+                }
262
+            }
263
+        }
264
+    }
265
+
266
+    /**
267
+     * @return string SCSS code for variables from OC_Defaults
268
+     */
269
+    private function getInjectedVariables() {
270
+        $variables = '';
271
+        foreach ($this->defaults->getScssVariables() as $key => $value) {
272
+            $variables .= '$' . $key . ': ' . $value . ';';
273
+        }
274
+        return $variables;
275
+    }
276
+
277
+    /**
278
+     * Add the correct uri prefix to make uri valid again
279
+     * @param string $css
280
+     * @param string $webDir
281
+     * @return string
282
+     */
283
+    private function rebaseUrls($css, $webDir) {
284
+        $re = '/url\([\'"]([\.\w?=\/-]*)[\'"]\)/x';
285
+        $subst = 'url(\''.$webDir.'/$1\')';
286
+        return preg_replace($re, $subst, $css);
287
+    }
288
+
289
+    /**
290
+     * Return the cached css file uri
291
+     * @param string $appName the app name
292
+     * @param string $fileName
293
+     * @return string
294
+     */
295
+    public function getCachedSCSS($appName, $fileName) {
296
+        $tmpfileLoc = explode('/', $fileName);
297
+        $fileName = array_pop($tmpfileLoc);
298
+        $fileName = $this->prependBaseurlPrefix(str_replace('.scss', '.css', $fileName));
299
+
300
+        return substr($this->urlGenerator->linkToRoute('core.Css.getCss', array('fileName' => $fileName, 'appName' => $appName)), strlen(\OC::$WEBROOT) + 1);
301
+    }
302
+
303
+    /**
304
+     * Prepend hashed base url to the css file
305
+     * @param $cssFile
306
+     * @return string
307
+     */
308
+    private function prependBaseurlPrefix($cssFile) {
309
+        $frontendController = ($this->config->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true');
310
+        return substr(md5($this->urlGenerator->getBaseUrl() . $frontendController), 0, 8) . '-' . $cssFile;
311
+    }
312
+
313
+    /**
314
+     * Get WebDir root
315
+     * @param string $path the css file path
316
+     * @param string $appName the app name
317
+     * @param string $serverRoot the server root path
318
+     * @param string $webRoot the nextcloud installation root path
319
+     * @return string the webDir
320
+     */
321
+    private function getWebDir($path, $appName, $serverRoot, $webRoot) {
322
+        // Detect if path is within server root AND if path is within an app path
323
+        if ( strpos($path, $serverRoot) === false && $appWebPath = \OC_App::getAppWebPath($appName)) {
324
+            // Get the file path within the app directory
325
+            $appDirectoryPath = explode($appName, $path)[1];
326
+            // Remove the webroot
327
+            return str_replace($webRoot, '', $appWebPath.$appDirectoryPath);
328
+        }
329
+        return $webRoot.substr($path, strlen($serverRoot));
330
+    }
331 331
 }
Please login to merge, or discard this patch.
Spacing   +23 added lines, -23 removed lines patch added patch discarded remove patch
@@ -96,7 +96,7 @@  discard block
 block discarded – undo
96 96
 	 * @return boolean
97 97
 	 */
98 98
 	public function process($root, $file, $app) {
99
-		$path = explode('/', $root . '/' . $file);
99
+		$path = explode('/', $root.'/'.$file);
100 100
 
101 101
 		$fileNameSCSS = array_pop($path);
102 102
 		$fileNameCSS = $this->prependBaseurlPrefix(str_replace('.scss', '.css', $fileNameSCSS));
@@ -106,13 +106,13 @@  discard block
 block discarded – undo
106 106
 
107 107
 		try {
108 108
 			$folder = $this->appData->getFolder($app);
109
-		} catch(NotFoundException $e) {
109
+		} catch (NotFoundException $e) {
110 110
 			// creating css appdata folder
111 111
 			$folder = $this->appData->newFolder($app);
112 112
 		}
113 113
 
114 114
 
115
-		if(!$this->variablesChanged() && $this->isCached($fileNameCSS, $folder)) {
115
+		if (!$this->variablesChanged() && $this->isCached($fileNameCSS, $folder)) {
116 116
 			return true;
117 117
 		}
118 118
 		return $this->cache($path, $fileNameCSS, $fileNameSCSS, $folder, $webDir);
@@ -138,13 +138,13 @@  discard block
 block discarded – undo
138 138
 		try {
139 139
 			$cachedFile = $folder->getFile($fileNameCSS);
140 140
 			if ($cachedFile->getSize() > 0) {
141
-				$depFileName = $fileNameCSS . '.deps';
142
-				$deps = $this->depsCache->get($folder->getName() . '-' . $depFileName);
141
+				$depFileName = $fileNameCSS.'.deps';
142
+				$deps = $this->depsCache->get($folder->getName().'-'.$depFileName);
143 143
 				if ($deps === null) {
144 144
 					$depFile = $folder->getFile($depFileName);
145 145
 					$deps = $depFile->getContent();
146 146
 					//Set to memcache for next run
147
-					$this->depsCache->set($folder->getName() . '-' . $depFileName, $deps);
147
+					$this->depsCache->set($folder->getName().'-'.$depFileName, $deps);
148 148
 				}
149 149
 				$deps = json_decode($deps, true);
150 150
 
@@ -155,7 +155,7 @@  discard block
 block discarded – undo
155 155
 				}
156 156
 			}
157 157
 			return true;
158
-		} catch(NotFoundException $e) {
158
+		} catch (NotFoundException $e) {
159 159
 			return false;
160 160
 		}
161 161
 	}
@@ -166,7 +166,7 @@  discard block
 block discarded – undo
166 166
 	 */
167 167
 	private function variablesChanged() {
168 168
 		$injectedVariables = $this->getInjectedVariables();
169
-		if($this->config->getAppValue('core', 'scss.variables') !== md5($injectedVariables)) {
169
+		if ($this->config->getAppValue('core', 'scss.variables') !== md5($injectedVariables)) {
170 170
 			$this->resetCache();
171 171
 			$this->config->setAppValue('core', 'scss.variables', md5($injectedVariables));
172 172
 			return true;
@@ -187,11 +187,11 @@  discard block
 block discarded – undo
187 187
 		$scss = new Compiler();
188 188
 		$scss->setImportPaths([
189 189
 			$path,
190
-			$this->serverRoot . '/core/css/',
190
+			$this->serverRoot.'/core/css/',
191 191
 		]);
192 192
 		// Continue after throw
193 193
 		$scss->setIgnoreErrors(true);
194
-		if($this->config->getSystemValue('debug')) {
194
+		if ($this->config->getSystemValue('debug')) {
195 195
 			// Debug mode
196 196
 			$scss->setFormatter(Expanded::class);
197 197
 			$scss->setLineNumberStyle(Compiler::LINE_COMMENTS);
@@ -202,11 +202,11 @@  discard block
 block discarded – undo
202 202
 
203 203
 		try {
204 204
 			$cachedfile = $folder->getFile($fileNameCSS);
205
-		} catch(NotFoundException $e) {
205
+		} catch (NotFoundException $e) {
206 206
 			$cachedfile = $folder->newFile($fileNameCSS);
207 207
 		}
208 208
 
209
-		$depFileName = $fileNameCSS . '.deps';
209
+		$depFileName = $fileNameCSS.'.deps';
210 210
 		try {
211 211
 			$depFile = $folder->getFile($depFileName);
212 212
 		} catch (NotFoundException $e) {
@@ -216,19 +216,19 @@  discard block
 block discarded – undo
216 216
 		// Compile
217 217
 		try {
218 218
 			$compiledScss = $scss->compile(
219
-				'@import "variables.scss";' .
220
-				$this->getInjectedVariables() .
219
+				'@import "variables.scss";'.
220
+				$this->getInjectedVariables().
221 221
 				'@import "'.$fileNameSCSS.'";');
222
-		} catch(ParserException $e) {
222
+		} catch (ParserException $e) {
223 223
 			$this->logger->error($e, ['app' => 'core']);
224 224
 			return false;
225 225
 		}
226 226
 
227 227
 		// Gzip file
228 228
 		try {
229
-			$gzipFile = $folder->getFile($fileNameCSS . '.gzip'); # Safari doesn't like .gz
229
+			$gzipFile = $folder->getFile($fileNameCSS.'.gzip'); # Safari doesn't like .gz
230 230
 		} catch (NotFoundException $e) {
231
-			$gzipFile = $folder->newFile($fileNameCSS . '.gzip'); # Safari doesn't like .gz
231
+			$gzipFile = $folder->newFile($fileNameCSS.'.gzip'); # Safari doesn't like .gz
232 232
 		}
233 233
 
234 234
 		try {
@@ -236,11 +236,11 @@  discard block
 block discarded – undo
236 236
 			$cachedfile->putContent($data);
237 237
 			$deps = json_encode($scss->getParsedFiles());
238 238
 			$depFile->putContent($deps);
239
-			$this->depsCache->set($folder->getName() . '-' . $depFileName, $deps);
239
+			$this->depsCache->set($folder->getName().'-'.$depFileName, $deps);
240 240
 			$gzipFile->putContent(gzencode($data, 9));
241 241
 			$this->logger->debug($webDir.'/'.$fileNameSCSS.' compiled and successfully cached', ['app' => 'core']);
242 242
 			return true;
243
-		} catch(NotPermittedException $e) {
243
+		} catch (NotPermittedException $e) {
244 244
 			return false;
245 245
 		}
246 246
 	}
@@ -251,7 +251,7 @@  discard block
 block discarded – undo
251 251
 	 */
252 252
 	private function resetCache() {
253 253
 		$appDirectory = $this->appData->getDirectoryListing();
254
-		if(empty($appDirectory)){
254
+		if (empty($appDirectory)) {
255 255
 			return;
256 256
 		}
257 257
 		foreach ($appDirectory as $folder) {
@@ -269,7 +269,7 @@  discard block
 block discarded – undo
269 269
 	private function getInjectedVariables() {
270 270
 		$variables = '';
271 271
 		foreach ($this->defaults->getScssVariables() as $key => $value) {
272
-			$variables .= '$' . $key . ': ' . $value . ';';
272
+			$variables .= '$'.$key.': '.$value.';';
273 273
 		}
274 274
 		return $variables;
275 275
 	}
@@ -307,7 +307,7 @@  discard block
 block discarded – undo
307 307
 	 */
308 308
 	private function prependBaseurlPrefix($cssFile) {
309 309
 		$frontendController = ($this->config->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true');
310
-		return substr(md5($this->urlGenerator->getBaseUrl() . $frontendController), 0, 8) . '-' . $cssFile;
310
+		return substr(md5($this->urlGenerator->getBaseUrl().$frontendController), 0, 8).'-'.$cssFile;
311 311
 	}
312 312
 
313 313
 	/**
@@ -320,7 +320,7 @@  discard block
 block discarded – undo
320 320
 	 */
321 321
 	private function getWebDir($path, $appName, $serverRoot, $webRoot) {
322 322
 		// Detect if path is within server root AND if path is within an app path
323
-		if ( strpos($path, $serverRoot) === false && $appWebPath = \OC_App::getAppWebPath($appName)) {
323
+		if (strpos($path, $serverRoot) === false && $appWebPath = \OC_App::getAppWebPath($appName)) {
324 324
 			// Get the file path within the app directory
325 325
 			$appDirectoryPath = explode($appName, $path)[1];
326 326
 			// Remove the webroot
Please login to merge, or discard this patch.