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