Chris@17
|
1 <?php
|
Chris@17
|
2 /**
|
Chris@17
|
3 * A local file represents a chunk of text has a file system location.
|
Chris@17
|
4 *
|
Chris@17
|
5 * @author Greg Sherwood <gsherwood@squiz.net>
|
Chris@17
|
6 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
|
Chris@17
|
7 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
Chris@17
|
8 */
|
Chris@17
|
9
|
Chris@17
|
10 namespace PHP_CodeSniffer\Files;
|
Chris@17
|
11
|
Chris@17
|
12 use PHP_CodeSniffer\Ruleset;
|
Chris@17
|
13 use PHP_CodeSniffer\Config;
|
Chris@17
|
14 use PHP_CodeSniffer\Util\Cache;
|
Chris@17
|
15
|
Chris@17
|
16 class LocalFile extends File
|
Chris@17
|
17 {
|
Chris@17
|
18
|
Chris@17
|
19
|
Chris@17
|
20 /**
|
Chris@17
|
21 * Creates a LocalFile object and sets the content.
|
Chris@17
|
22 *
|
Chris@17
|
23 * @param string $path The absolute path to the file.
|
Chris@17
|
24 * @param \PHP_CodeSniffer\Ruleset $ruleset The ruleset used for the run.
|
Chris@17
|
25 * @param \PHP_CodeSniffer\Config $config The config data for the run.
|
Chris@17
|
26 *
|
Chris@17
|
27 * @return void
|
Chris@17
|
28 */
|
Chris@17
|
29 public function __construct($path, Ruleset $ruleset, Config $config)
|
Chris@17
|
30 {
|
Chris@17
|
31 $this->path = trim($path);
|
Chris@17
|
32 if (is_readable($this->path) === false) {
|
Chris@17
|
33 parent::__construct($this->path, $ruleset, $config);
|
Chris@17
|
34 $error = 'Error opening file; file no longer exists or you do not have access to read the file';
|
Chris@17
|
35 $this->addMessage(true, $error, 1, 1, 'Internal.LocalFile', [], 5, false);
|
Chris@17
|
36 $this->ignored = true;
|
Chris@17
|
37 return;
|
Chris@17
|
38 }
|
Chris@17
|
39
|
Chris@17
|
40 // Before we go and spend time tokenizing this file, just check
|
Chris@17
|
41 // to see if there is a tag up top to indicate that the whole
|
Chris@17
|
42 // file should be ignored. It must be on one of the first two lines.
|
Chris@17
|
43 if ($config->annotations === true) {
|
Chris@17
|
44 $handle = fopen($this->path, 'r');
|
Chris@17
|
45 if ($handle !== false) {
|
Chris@17
|
46 $firstContent = fgets($handle);
|
Chris@17
|
47 $firstContent .= fgets($handle);
|
Chris@17
|
48 fclose($handle);
|
Chris@17
|
49
|
Chris@17
|
50 if (strpos($firstContent, '@codingStandardsIgnoreFile') !== false
|
Chris@17
|
51 || stripos($firstContent, 'phpcs:ignorefile') !== false
|
Chris@17
|
52 ) {
|
Chris@17
|
53 // We are ignoring the whole file.
|
Chris@17
|
54 $this->ignored = true;
|
Chris@17
|
55 return;
|
Chris@17
|
56 }
|
Chris@17
|
57 }
|
Chris@17
|
58 }
|
Chris@17
|
59
|
Chris@17
|
60 $this->reloadContent();
|
Chris@17
|
61
|
Chris@17
|
62 return parent::__construct($this->path, $ruleset, $config);
|
Chris@17
|
63
|
Chris@17
|
64 }//end __construct()
|
Chris@17
|
65
|
Chris@17
|
66
|
Chris@17
|
67 /**
|
Chris@17
|
68 * Loads the latest version of the file's content from the file system.
|
Chris@17
|
69 *
|
Chris@17
|
70 * @return void
|
Chris@17
|
71 */
|
Chris@17
|
72 public function reloadContent()
|
Chris@17
|
73 {
|
Chris@17
|
74 $this->setContent(file_get_contents($this->path));
|
Chris@17
|
75
|
Chris@17
|
76 }//end reloadContent()
|
Chris@17
|
77
|
Chris@17
|
78
|
Chris@17
|
79 /**
|
Chris@17
|
80 * Processes the file.
|
Chris@17
|
81 *
|
Chris@17
|
82 * @return void
|
Chris@17
|
83 */
|
Chris@17
|
84 public function process()
|
Chris@17
|
85 {
|
Chris@17
|
86 if ($this->ignored === true) {
|
Chris@17
|
87 return;
|
Chris@17
|
88 }
|
Chris@17
|
89
|
Chris@17
|
90 if ($this->configCache['cache'] === false) {
|
Chris@17
|
91 return parent::process();
|
Chris@17
|
92 }
|
Chris@17
|
93
|
Chris@17
|
94 $hash = md5_file($this->path);
|
Chris@17
|
95 $cache = Cache::get($this->path);
|
Chris@17
|
96 if ($cache !== false && $cache['hash'] === $hash) {
|
Chris@17
|
97 // We can't filter metrics, so just load all of them.
|
Chris@17
|
98 $this->metrics = $cache['metrics'];
|
Chris@17
|
99
|
Chris@17
|
100 if ($this->configCache['recordErrors'] === true) {
|
Chris@17
|
101 // Replay the cached errors and warnings to filter out the ones
|
Chris@17
|
102 // we don't need for this specific run.
|
Chris@17
|
103 $this->configCache['cache'] = false;
|
Chris@17
|
104 $this->replayErrors($cache['errors'], $cache['warnings']);
|
Chris@17
|
105 $this->configCache['cache'] = true;
|
Chris@17
|
106 } else {
|
Chris@17
|
107 $this->errorCount = $cache['errorCount'];
|
Chris@17
|
108 $this->warningCount = $cache['warningCount'];
|
Chris@17
|
109 $this->fixableCount = $cache['fixableCount'];
|
Chris@17
|
110 }
|
Chris@17
|
111
|
Chris@17
|
112 if (PHP_CODESNIFFER_VERBOSITY > 0
|
Chris@17
|
113 || (PHP_CODESNIFFER_CBF === true && empty($this->config->files) === false)
|
Chris@17
|
114 ) {
|
Chris@17
|
115 echo "[loaded from cache]... ";
|
Chris@17
|
116 }
|
Chris@17
|
117
|
Chris@17
|
118 $this->numTokens = $cache['numTokens'];
|
Chris@17
|
119 $this->fromCache = true;
|
Chris@17
|
120 return;
|
Chris@17
|
121 }//end if
|
Chris@17
|
122
|
Chris@17
|
123 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@17
|
124 echo PHP_EOL;
|
Chris@17
|
125 }
|
Chris@17
|
126
|
Chris@17
|
127 parent::process();
|
Chris@17
|
128
|
Chris@17
|
129 $cache = [
|
Chris@17
|
130 'hash' => $hash,
|
Chris@17
|
131 'errors' => $this->errors,
|
Chris@17
|
132 'warnings' => $this->warnings,
|
Chris@17
|
133 'metrics' => $this->metrics,
|
Chris@17
|
134 'errorCount' => $this->errorCount,
|
Chris@17
|
135 'warningCount' => $this->warningCount,
|
Chris@17
|
136 'fixableCount' => $this->fixableCount,
|
Chris@17
|
137 'numTokens' => $this->numTokens,
|
Chris@17
|
138 ];
|
Chris@17
|
139
|
Chris@17
|
140 Cache::set($this->path, $cache);
|
Chris@17
|
141
|
Chris@17
|
142 // During caching, we don't filter out errors in any way, so
|
Chris@17
|
143 // we need to do that manually now by replaying them.
|
Chris@17
|
144 if ($this->configCache['recordErrors'] === true) {
|
Chris@17
|
145 $this->configCache['cache'] = false;
|
Chris@17
|
146 $this->replayErrors($this->errors, $this->warnings);
|
Chris@17
|
147 $this->configCache['cache'] = true;
|
Chris@17
|
148 }
|
Chris@17
|
149
|
Chris@17
|
150 }//end process()
|
Chris@17
|
151
|
Chris@17
|
152
|
Chris@17
|
153 /**
|
Chris@17
|
154 * Clears and replays error and warnings for the file.
|
Chris@17
|
155 *
|
Chris@17
|
156 * Replaying errors and warnings allows for filtering rules to be changed
|
Chris@17
|
157 * and then errors and warnings to be reapplied with the new rules. This is
|
Chris@17
|
158 * particularly useful while caching.
|
Chris@17
|
159 *
|
Chris@17
|
160 * @param array $errors The list of errors to replay.
|
Chris@17
|
161 * @param array $warnings The list of warnings to replay.
|
Chris@17
|
162 *
|
Chris@17
|
163 * @return void
|
Chris@17
|
164 */
|
Chris@17
|
165 private function replayErrors($errors, $warnings)
|
Chris@17
|
166 {
|
Chris@17
|
167 $this->errors = [];
|
Chris@17
|
168 $this->warnings = [];
|
Chris@17
|
169 $this->errorCount = 0;
|
Chris@17
|
170 $this->warningCount = 0;
|
Chris@17
|
171 $this->fixableCount = 0;
|
Chris@17
|
172
|
Chris@17
|
173 foreach ($errors as $line => $lineErrors) {
|
Chris@17
|
174 foreach ($lineErrors as $column => $colErrors) {
|
Chris@17
|
175 foreach ($colErrors as $error) {
|
Chris@17
|
176 $this->activeListener = $error['listener'];
|
Chris@17
|
177 $this->addMessage(
|
Chris@17
|
178 true,
|
Chris@17
|
179 $error['message'],
|
Chris@17
|
180 $line,
|
Chris@17
|
181 $column,
|
Chris@17
|
182 $error['source'],
|
Chris@17
|
183 [],
|
Chris@17
|
184 $error['severity'],
|
Chris@17
|
185 $error['fixable']
|
Chris@17
|
186 );
|
Chris@17
|
187 }
|
Chris@17
|
188 }
|
Chris@17
|
189 }
|
Chris@17
|
190
|
Chris@17
|
191 foreach ($warnings as $line => $lineErrors) {
|
Chris@17
|
192 foreach ($lineErrors as $column => $colErrors) {
|
Chris@17
|
193 foreach ($colErrors as $error) {
|
Chris@17
|
194 $this->activeListener = $error['listener'];
|
Chris@17
|
195 $this->addMessage(
|
Chris@17
|
196 false,
|
Chris@17
|
197 $error['message'],
|
Chris@17
|
198 $line,
|
Chris@17
|
199 $column,
|
Chris@17
|
200 $error['source'],
|
Chris@17
|
201 [],
|
Chris@17
|
202 $error['severity'],
|
Chris@17
|
203 $error['fixable']
|
Chris@17
|
204 );
|
Chris@17
|
205 }
|
Chris@17
|
206 }
|
Chris@17
|
207 }
|
Chris@17
|
208
|
Chris@17
|
209 }//end replayErrors()
|
Chris@17
|
210
|
Chris@17
|
211
|
Chris@17
|
212 }//end class
|