]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/arcanist_util/cpp_linter/FacebookHowtoevenLinter.php
bump version to 12.2.12-pve1
[ceph.git] / ceph / src / rocksdb / arcanist_util / cpp_linter / FacebookHowtoevenLinter.php
1 <?php
2 // Copyright 2015-present Facebook. All Rights Reserved.
3 // This source code is licensed under the BSD-style license found in the
4 // LICENSE file in the root directory of this source tree. An additional grant
5 // of patent rights can be found in the PATENTS file in the same directory.
6
7 final class FacebookHowtoevenLinter extends ArcanistLinter {
8
9 const VERSION = 'fd9192f324c36d28136d14380f0b552a1385b59b';
10
11 private $parsedTargets = array();
12
13 public function getLinterName() {
14 return 'Howtoeven';
15 }
16
17 protected function getSeverity($code) {
18 $severities = array(
19 ArcanistLintSeverity::SEVERITY_DISABLED,
20 ArcanistLintSeverity::SEVERITY_ADVICE,
21 ArcanistLintSeverity::SEVERITY_WARNING,
22 ArcanistLintSeverity::SEVERITY_ERROR,
23 );
24 return idx($severities, $code, ArcanistLintSeverity::SEVERITY_WARNING);
25 }
26
27 public function willLintPaths(array $paths) {
28 // Cleanup previous runs.
29 $this->localExecx("rm -rf _build/_lint");
30
31 // Build compilation database.
32 $lintable_paths = $this->getLintablePaths($paths);
33 $interesting_paths = $this->getInterestingPaths($lintable_paths);
34
35 if (!$lintable_paths) {
36 return;
37 }
38
39 // Run lint.
40 try {
41 $this->localExecx(
42 "%C %C -p _build/dev/ %Ls",
43 $this->getBinaryPath(),
44 $this->getFilteredIssues(),
45 $lintable_paths);
46 } catch (CommandException $exception) {
47 PhutilConsole::getConsole()->writeErr($exception->getMessage());
48 }
49
50 // Load results.
51 $result = id(
52 new SQLite3(
53 $this->getProjectRoot().'/_build/_lint/lint.db',
54 SQLITE3_OPEN_READONLY))
55 ->query("SELECT * FROM raised_issues");
56
57 while ($issue = $result->fetchArray(SQLITE3_ASSOC)) {
58 // Skip issues not part of the linted file.
59 if (in_array($issue['file'], $interesting_paths)) {
60 $this->addLintMessage(id(new ArcanistLintMessage())
61 ->setPath($issue['file'])
62 ->setLine($issue['line'])
63 ->setChar($issue['column'])
64 ->setCode('Howtoeven')
65 ->setSeverity($this->getSeverity($issue['severity']))
66 ->setName('Hte-'.$issue['name'])
67 ->setDescription(
68 sprintf(
69 "%s\n\n%s",
70 ($issue['message']) ? $issue['message'] : $issue['description'],
71 $issue['explanation']))
72 ->setOriginalText(idx($issue, 'original', ''))
73 ->setReplacementText(idx($issue, 'replacement', '')));
74 }
75 }
76 }
77
78 public function lintPath($path) {
79 }
80
81 /**
82 * Get the paths that we know how to lint.
83 *
84 * The strategy is to first look whether there's an existing compilation
85 * database and use that if it's exhaustive. We generate our own only if
86 * necessary.
87 */
88 private function getLintablePaths($paths) {
89 // Replace headers with existing sources.
90 for ($i = 0; $i < count($paths); $i++) {
91 if (preg_match("/\.h$/", $paths[$i])) {
92 $header = preg_replace("/\.h$/", ".cpp", $paths[$i]);
93 if (file_exists($header)) {
94 $paths[$i] = $header;
95 }
96 }
97 }
98
99 // Check if database exists and is exhaustive.
100 $available_paths = $this->getAvailablePaths();
101 $lintable_paths = array_intersect($paths, $available_paths);
102 if ($paths === $lintable_paths) {
103 return $lintable_paths;
104 }
105
106 // Generate our own database.
107 $targets = $this->getTargetsFor($paths);
108 if (!$targets) {
109 PhutilConsole::getConsole()->writeErr(
110 "No build targets found for %s\n",
111 implode(', ', $paths));
112 return array();
113 }
114
115 $this->localExecx("./tools/build/bin/fbconfig.par -r %Ls", $targets);
116 $this->localExecx("./tools/build/bin/fbmake.par gen_cdb");
117
118 $available_paths = $this->getAvailablePaths();
119 $lintable_paths = array_intersect($paths, $available_paths);
120 if ($paths != $lintable_paths) {
121 PhutilConsole::getConsole()->writeErr(
122 "Can't lint %s\n",
123 implode(', ', array_diff($paths, $available_paths)));
124 }
125
126 // Return what we know how to lint.
127 return $lintable_paths;
128 }
129
130 /**
131 * Get the available paths in the current compilation database.
132 */
133 private function getAvailablePaths() {
134 $database_path = $this->getProjectRoot()
135 .'/_build/dev/compile_commands.json';
136 if (!file_exists($database_path)) {
137 return array();
138 }
139
140 $entries = json_decode(file_get_contents($database_path), true);
141 $paths = array();
142 foreach ($entries as $entry) {
143 $paths[] = $entry['file'];
144 }
145 return $paths;
146 }
147
148 /**
149 * Search for the targets directories for the given files.
150 */
151 private static function getTargetsFor($paths) {
152 $targets = array();
153 foreach ($paths as $path) {
154 while (($path = dirname($path)) !== '.') {
155 if (in_array('TARGETS', scandir($path))) {
156 $contents = file_get_contents($path.'/TARGETS');
157 if (strpos($contents, 'cpp_binary') !== false) {
158 $targets[] = $path;
159 break;
160 }
161 }
162 }
163 }
164 return array_unique($targets);
165 }
166
167 /**
168 * The paths that we actually want to report on.
169 */
170 private function getInterestingPaths($paths) {
171 $headers = array();
172 foreach ($paths as $path) {
173 $headers[] = preg_replace("/\.cpp$/", ".h", $path);
174 }
175 return array_merge($paths, $headers);
176 }
177
178 /**
179 * The path where the binary is located. Will return the current dewey binary
180 * unless the `HOWTOEVEN_BUILD` environment variable is set.
181 */
182 private function getBinaryPath() {
183 $path = sprintf(
184 "/mnt/dewey/fbcode/.commits/%s/builds/howtoeven/client",
185 self::VERSION);
186
187 $build = getenv('HOWTOEVEN_BUILD');
188 if ($build) {
189 $path = sprintf(
190 "./_build/%s/tools/howtoeven/client",
191 $build);
192 if (!file_exists($path)) {
193 PhutilConsole::getConsole()->writeErr(">> %s does not exist\n", $path);
194 exit(1);
195 }
196 }
197
198 return $path;
199 }
200
201 /**
202 * Execute the command in the root directory.
203 */
204 private function localExecx($command /* , ... */) {
205 $arguments = func_get_args();
206 return newv('ExecFuture', $arguments)
207 ->setCWD($this->getProjectRoot())
208 ->resolvex();
209 }
210
211 /**
212 * The root of the project.
213 */
214 private function getProjectRoot() {
215 return $this->getEngine()->getWorkingCopy()->getProjectRoot();
216 }
217
218 private function getFilteredIssues() {
219 $issues = getenv('HOWTOEVEN_ISSUES');
220 return ($issues) ? csprintf('-issues %s', $issues) : '';
221 }
222
223 }