Brian O'Connor
Committed by Gerrit Code Review

Adding Checkstyle daemon

Lazily instaniate a checkstyle daemon for the first checkstyle job.
Then, each subsequent checkstyle target uses the daemon.

The daemon is terminated when the parent buck or buckd exits.

Change-Id: I4dbea957f20a3f77048dd25d960b7faa1eafef37
...@@ -110,39 +110,29 @@ def osgi_jar( ...@@ -110,39 +110,29 @@ def osgi_jar(
110 110
111 ### Checkstyle 111 ### Checkstyle
112 if srcs: 112 if srcs:
113 - chk_cmd = '#!/bin/bash\n'
114 base = get_base_path() 113 base = get_base_path()
115 - chk_cmd += 'OUT=$3\n' 114 + files = base + '\n' + '\n'.join(['%s/%s' % (base, s) for s in srcs])
116 - chk_cmd += ' '.join(( 'java -jar $1',
117 - '-c $2',
118 - ' '.join(['%s/%s' % (base, s) for s in srcs]) ))
119 - chk_cmd += ' | tee $OUT'
120 - chk_cmd += ' | grep -E "^.*[0-9]+:[0-9]+: error:"'
121 - chk_cmd += ' | sed "s#^.*%s/#%s:#g"\n' % (base, name)
122 - chk_cmd += 'RESULT=(${PIPESTATUS[*]})\n' # RESULT[0] is checkstyle result, RESULT[2] is grep
123 - chk_cmd += 'test ${RESULT[2]} -eq 0 || cat $OUT\n'
124 - chk_cmd += 'rm $OUT\n'
125 - chk_cmd += 'exit ${RESULT[0]}'
126 115
127 genrule( 116 genrule(
128 - name = name + '-checkstyle-sh', 117 + name = name + '-checkstyle-files',
129 - bash = "echo '%s' > $OUT && chmod +x $OUT" % chk_cmd, 118 + bash = "echo '%s' > $OUT" % files,
130 srcs = srcs, 119 srcs = srcs,
131 - out = 'checkstyle.sh', 120 + out = 'checkstyle-files.txt',
132 ) 121 )
133 122
134 sh_test( 123 sh_test(
135 name = name + '-checkstyle', 124 name = name + '-checkstyle',
136 - test = ':' + name + '-checkstyle-sh', 125 + test = '//tools/build/conf:start-checkstyle',
137 - args = [
138 - '$(location //lib:checkstyle)',
139 - '$(location //tools/build/conf:checkstyle-xml)',
140 - '`mktemp /tmp/%s-checkstyle-XXXXXX`' % name,
141 - ],
142 deps = [ 126 deps = [
143 ':'+ bare_jar_name, 127 ':'+ bare_jar_name,
144 - '//tools/build/conf:suppressions-xml',
145 ], 128 ],
129 + args = [
130 + '$(location //tools/build/conf:checkstyle-jar)',
131 + '$(location :' + name + '-checkstyle-files)',
132 + '$(location //tools/build/conf:checkstyle-xml)',
133 + '$(location //tools/build/conf:suppressions-xml)',
134 + ],
135 + test_rule_timeout_ms = 20000,
146 labels = [ 'checkstyle' ], 136 labels = [ 'checkstyle' ],
147 ) 137 )
148 else: 138 else:
...@@ -219,4 +209,6 @@ def osgi_jar_with_tests( ...@@ -219,4 +209,6 @@ def osgi_jar_with_tests(
219 resources = test_resources, 209 resources = test_resources,
220 resources_root = test_resources_root, 210 resources_root = test_resources_root,
221 visibility = visibility 211 visibility = visibility
222 - ) 212 + )
213 +
214 + #FIXME need to run checkstyle on test sources
...\ No newline at end of file ...\ No newline at end of file
......
1 -# ***** This file was auto-generated at Wed May 18 14:26:50 PDT 2016. Do not edit this file manually. ***** 1 +# ***** This file was auto-generated at Wed May 18 17:55:44 PDT 2016. Do not edit this file manually. *****
2 osgi_feature_group( 2 osgi_feature_group(
3 name = 'COMPILE', 3 name = 'COMPILE',
4 visibility = ['PUBLIC'], 4 visibility = ['PUBLIC'],
...@@ -321,6 +321,15 @@ remote_jar ( ...@@ -321,6 +321,15 @@ remote_jar (
321 ) 321 )
322 322
323 remote_jar ( 323 remote_jar (
324 + name = 'commons-beanutils',
325 + out = 'commons-beanutils-1.9.2.jar',
326 + url = 'mvn:commons-beanutils:commons-beanutils:jar:1.9.2',
327 + sha1 = '7a87d845ad3a155297e8f67d9008f4c1e5656b71',
328 + maven_coords = 'commons-beanutils:commons-beanutils:1.9.2',
329 + visibility = [ 'PUBLIC' ],
330 +)
331 +
332 +remote_jar (
324 name = 'concurrent-trees', 333 name = 'concurrent-trees',
325 out = 'concurrent-trees-2.4.0.jar', 334 out = 'concurrent-trees-2.4.0.jar',
326 url = 'mvn:com.googlecode.concurrent-trees:concurrent-trees:jar:2.4.0', 335 url = 'mvn:com.googlecode.concurrent-trees:concurrent-trees:jar:2.4.0',
...@@ -420,6 +429,15 @@ remote_jar ( ...@@ -420,6 +429,15 @@ remote_jar (
420 ) 429 )
421 430
422 remote_jar ( 431 remote_jar (
432 + name = 'antlr',
433 + out = 'antlr-2.7.7.jar',
434 + url = 'mvn:antlr:antlr:jar:2.7.7',
435 + sha1 = '83cd2cd674a217ade95a4bb83a8a14f351f48bd0',
436 + maven_coords = 'antlr:antlr:jar:NON-OSGI:2.7.7',
437 + visibility = [ 'PUBLIC' ],
438 +)
439 +
440 +remote_jar (
423 name = 'error_prone_annotations', 441 name = 'error_prone_annotations',
424 out = 'error_prone_annotations-2.0.2.jar', 442 out = 'error_prone_annotations-2.0.2.jar',
425 url = 'mvn:com.google.errorprone:error_prone_annotations:jar:2.0.2', 443 url = 'mvn:com.google.errorprone:error_prone_annotations:jar:2.0.2',
...@@ -1114,9 +1132,10 @@ remote_jar ( ...@@ -1114,9 +1132,10 @@ remote_jar (
1114 1132
1115 remote_jar ( 1133 remote_jar (
1116 name = 'checkstyle', 1134 name = 'checkstyle',
1117 - out = 'checkstyle-6.11.2-all.jar', 1135 + out = 'checkstyle-6.11.2.jar',
1118 - url = 'http://onlab.vicci.org/onos/third-party/checkstyle-6.11.2-all.jar', 1136 + url = 'mvn:com.puppycrawl.tools:checkstyle:jar:6.11.2',
1119 - sha1 = 'f504187b1743e73ffe72c2eede0ff57d45536b7d', 1137 + sha1 = '2705f014697ac0219de0bb2bfc33afb7ec6d22c6',
1138 + maven_coords = 'com.puppycrawl.tools:checkstyle:jar:NON-OSGI:6.11.2',
1120 visibility = [ 'PUBLIC' ], 1139 visibility = [ 'PUBLIC' ],
1121 ) 1140 )
1122 1141
......
...@@ -98,6 +98,7 @@ ...@@ -98,6 +98,7 @@
98 "catalyst-local": "mvn:io.atomix.catalyst:catalyst-local:1.0.4", 98 "catalyst-local": "mvn:io.atomix.catalyst:catalyst-local:1.0.4",
99 "catalyst-serializer": "mvn:io.atomix.catalyst:catalyst-serializer:1.0.4", 99 "catalyst-serializer": "mvn:io.atomix.catalyst:catalyst-serializer:1.0.4",
100 "catalyst-transport": "mvn:io.atomix.catalyst:catalyst-transport:1.0.4", 100 "catalyst-transport": "mvn:io.atomix.catalyst:catalyst-transport:1.0.4",
101 + "catalyst-transport": "mvn:io.atomix.catalyst:catalyst-transport:1.0.4",
101 "commons-codec": "mvn:commons-codec:commons-codec:1.10", 102 "commons-codec": "mvn:commons-codec:commons-codec:1.10",
102 "commons-collections": "mvn:commons-collections:commons-collections:3.2.2", 103 "commons-collections": "mvn:commons-collections:commons-collections:3.2.2",
103 "commons-configuration": "mvn:commons-configuration:commons-configuration:1.10", 104 "commons-configuration": "mvn:commons-configuration:commons-configuration:1.10",
...@@ -107,6 +108,7 @@ ...@@ -107,6 +108,7 @@
107 "commons-logging": "mvn:commons-logging:commons-logging:1.1.1", 108 "commons-logging": "mvn:commons-logging:commons-logging:1.1.1",
108 "commons-math3": "mvn:org.apache.commons:commons-math3:3.6.1", 109 "commons-math3": "mvn:org.apache.commons:commons-math3:3.6.1",
109 "commons-pool": "mvn:commons-pool:commons-pool:1.6", 110 "commons-pool": "mvn:commons-pool:commons-pool:1.6",
111 + "commons-beanutils": "mvn:commons-beanutils:commons-beanutils:1.9.2",
110 "concurrent-trees": "mvn:com.googlecode.concurrent-trees:concurrent-trees:2.4.0", 112 "concurrent-trees": "mvn:com.googlecode.concurrent-trees:concurrent-trees:2.4.0",
111 "copycat-api": "mvn:org.onosproject:copycat-api:0.5.1.onos", 113 "copycat-api": "mvn:org.onosproject:copycat-api:0.5.1.onos",
112 "copycat-client": "mvn:io.atomix.copycat:copycat-client:1.0.0-rc4", 114 "copycat-client": "mvn:io.atomix.copycat:copycat-client:1.0.0-rc4",
...@@ -118,6 +120,7 @@ ...@@ -118,6 +120,7 @@
118 "copycat-state-log": "mvn:org.onosproject:copycat-state-log:0.5.1.onos", 120 "copycat-state-log": "mvn:org.onosproject:copycat-state-log:0.5.1.onos",
119 "copycat-state-machine": "mvn:org.onosproject:copycat-state-machine:0.5.1.onos", 121 "copycat-state-machine": "mvn:org.onosproject:copycat-state-machine:0.5.1.onos",
120 "easymock": "mvn:org.easymock:easymock:3.4", 122 "easymock": "mvn:org.easymock:easymock:3.4",
123 + "antlr": "mvn:antlr:antlr:2.7.7",
121 "error_prone_annotations": "mvn:com.google.errorprone:error_prone_annotations:2.0.2", 124 "error_prone_annotations": "mvn:com.google.errorprone:error_prone_annotations:2.0.2",
122 "ganymed-ssh2": "mvn:ch.ethz.ganymed:ganymed-ssh2:262", 125 "ganymed-ssh2": "mvn:ch.ethz.ganymed:ganymed-ssh2:262",
123 "jersey-container-jetty-http": "mvn:org.glassfish.jersey.containers:jersey-container-jetty-http:2.22.2", 126 "jersey-container-jetty-http": "mvn:org.glassfish.jersey.containers:jersey-container-jetty-http:2.22.2",
...@@ -198,7 +201,7 @@ ...@@ -198,7 +201,7 @@
198 "slf4j-jdk14": "mvn:org.slf4j:slf4j-jdk14:1.7.21", 201 "slf4j-jdk14": "mvn:org.slf4j:slf4j-jdk14:1.7.21",
199 "typesafe-config": "mvn:com.typesafe:config:1.2.1", 202 "typesafe-config": "mvn:com.typesafe:config:1.2.1",
200 "validation-api": "mvn:javax.validation:validation-api:1.1.0.Final", 203 "validation-api": "mvn:javax.validation:validation-api:1.1.0.Final",
201 - "checkstyle": "http://onlab.vicci.org/onos/third-party/checkstyle-6.11.2-all.jar", 204 + "checkstyle": "mvn:com.puppycrawl.tools:checkstyle:6.11.2",
202 "apache-karaf": "http://onlab.vicci.org/onos/third-party/apache-karaf-3.0.5.tar.gz", 205 "apache-karaf": "http://onlab.vicci.org/onos/third-party/apache-karaf-3.0.5.tar.gz",
203 "bndlib": "mvn:biz.aQute.bnd:biz.aQute.bndlib:jar:3.1.0", 206 "bndlib": "mvn:biz.aQute.bnd:biz.aQute.bndlib:jar:3.1.0",
204 "org.apache.felix.scr.bnd": { 207 "org.apache.felix.scr.bnd": {
......
1 checkstyle_source = 'src/main/resources/onos/checkstyle.xml' 1 checkstyle_source = 'src/main/resources/onos/checkstyle.xml'
2 suppression_source = 'src/main/resources/onos/suppressions.xml' 2 suppression_source = 'src/main/resources/onos/suppressions.xml'
3 3
4 -xml = ('<module name="SuppressionFilter">' 4 +export_file (
5 - '<property name="file" value="$(location :suppressions-xml)"/>'
6 - '</module>' )
7 -cmd = "sed 's#<module name=\"Checker\">#<module name=\"Checker\">%s#' %s > $OUT" % ( xml, checkstyle_source )
8 -
9 -genrule(
10 name = 'checkstyle-xml', 5 name = 'checkstyle-xml',
11 - srcs = [ checkstyle_source ], 6 + src = checkstyle_source,
12 - out = 'checkstyle.xml', 7 + visibility = [ 'PUBLIC' ],
13 - bash = cmd,
14 - visibility = [ 'PUBLIC' ]
15 ) 8 )
16 9
17 -#FIXME location suppression.xml does not trigger this rule 10 +export_file (
18 -export_file(
19 name = 'suppressions-xml', 11 name = 'suppressions-xml',
20 src = suppression_source, 12 src = suppression_source,
21 - visibility = [ 'PUBLIC' ] 13 + visibility = [ 'PUBLIC' ],
14 +)
15 +
16 +export_file (
17 + name = 'start-checkstyle',
18 + visibility = [ 'PUBLIC' ],
19 +)
20 +
21 +COMPILE = [
22 + '//lib:guava',
23 + '//lib:checkstyle',
24 +]
25 +
26 +RUN = [
27 + '//lib:commons-logging',
28 + '//lib:commons-beanutils',
29 + '//lib:commons-lang3',
30 + '//lib:commons-collections',
31 + '//lib:antlr',
32 +]
33 +
34 +java_library (
35 + name = 'checkstyle',
36 + srcs = glob([ 'src/main/java/**/*.java' ]),
37 + deps = COMPILE,
22 ) 38 )
39 +
40 +java_binary (
41 + name = 'checkstyle-jar',
42 + deps = [ ':checkstyle' ] + RUN,
43 + main_class = 'org.onosproject.checkstyle.Main',
44 + blacklist = [ 'META-INF/.*' ],
45 + visibility = [ 'PUBLIC' ],
46 +)
47 +
48 +# cmd = '#!/bin/bash\n'
49 +# cmd += '$1 &>/dev/null < /dev/null &'
50 +#
51 +# genrule(
52 +# name = 'checkstyle-sh',
53 +# bash = "echo '%s' > $OUT && chmod +x $OUT" % cmd,
54 +# out = 'checkstyle.sh',
55 +# )
56 +#
57 +# sh_test(
58 +# name = 'checkstyle-runner',
59 +# test = ':checkstyle-sh',
60 +# args = [
61 +# '$(exe :checkstyle-jar)',
62 +# '$(location //lib:checkstyle)',
63 +# '$(location //tools/build/conf:checkstyle-xml)',
64 +# '`mktemp /tmp/%s-checkstyle-XXXXXX`',
65 +# ],
66 +# labels = [ 'checkstyle' ],
67 +# visibility = [ 'PUBLIC' ],
68 +# )
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -34,5 +34,29 @@ ...@@ -34,5 +34,29 @@
34 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 34 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
35 </properties> 35 </properties>
36 36
37 + <dependencies>
38 + <dependency>
39 + <groupId>com.puppycrawl.tools</groupId>
40 + <artifactId>checkstyle</artifactId>
41 + <version>6.11.2</version>
42 + </dependency>
43 + </dependencies>
44 +
45 + <build>
46 + <plugins>
47 + <plugin>
48 + <groupId>org.apache.maven.plugins</groupId>
49 + <artifactId>maven-compiler-plugin</artifactId>
50 + <!-- TODO: update once following issue is fixed. -->
51 + <!-- https://jira.codehaus.org/browse/MCOMPILER-205 -->
52 + <version>2.5.1</version>
53 + <configuration>
54 + <source>1.8</source>
55 + <target>1.8</target>
56 + </configuration>
57 + </plugin>
58 + </plugins>
59 + </build>
60 +
37 </project> 61 </project>
38 62
......
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.checkstyle;
17 +
18 +import com.google.common.io.ByteStreams;
19 +import com.puppycrawl.tools.checkstyle.Checker;
20 +import com.puppycrawl.tools.checkstyle.ConfigurationLoader;
21 +import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
22 +import com.puppycrawl.tools.checkstyle.PropertiesExpander;
23 +import com.puppycrawl.tools.checkstyle.api.AuditEvent;
24 +import com.puppycrawl.tools.checkstyle.api.AuditListener;
25 +import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
26 +import com.puppycrawl.tools.checkstyle.api.Configuration;
27 +
28 +import java.io.File;
29 +import java.io.IOException;
30 +import java.net.Socket;
31 +import java.util.List;
32 +import java.util.concurrent.CountDownLatch;
33 +import java.util.stream.Collectors;
34 +import java.util.stream.Stream;
35 +
36 +public class CheckstyleRunner {
37 +
38 + private final Configuration config;
39 +
40 + public CheckstyleRunner(String configLocation, String suppressionLocation)
41 + throws CheckstyleException {
42 + // create a configuration
43 + DefaultConfiguration config = (DefaultConfiguration) ConfigurationLoader.loadConfiguration(
44 + configLocation, new PropertiesExpander(System.getProperties()));
45 +
46 + // add the suppression file to the configuration
47 + DefaultConfiguration suppressions = new DefaultConfiguration("SuppressionFilter");
48 + suppressions.addAttribute("file", suppressionLocation);
49 + config.addChild(suppressions);
50 +
51 + this.config = config;
52 + }
53 +
54 + public Runnable checkClass(Socket socket) {
55 + return () -> {
56 + try {
57 + String input = new String(ByteStreams.toByteArray(socket.getInputStream()));
58 + String output = checkClass(input);
59 + socket.getOutputStream().write(output.getBytes());
60 + socket.getOutputStream().flush();
61 + socket.close();
62 + } catch (IOException e) {
63 + e.printStackTrace();
64 + } catch (CheckstyleException e) {
65 + e.printStackTrace();
66 + } catch (InterruptedException e) {
67 + e.printStackTrace();
68 + }
69 + };
70 + }
71 +
72 + public String checkClass(String input) throws CheckstyleException, InterruptedException {
73 + String[] split = input.split("\n", 2);
74 + if (split.length < 2 || split[1].length() == 0) {
75 + return "";
76 + }
77 + String base = split[0];
78 + String files = split[1];
79 +
80 + // create a listener for output
81 + StringAuditor listener = new StringAuditor();
82 + listener.setBase(base);
83 +
84 + // create Checker object and run it
85 + final Checker checker = new Checker();
86 + final ClassLoader moduleClassLoader = Checker.class.getClassLoader();
87 + checker.setModuleClassLoader(moduleClassLoader);
88 +
89 + try {
90 +
91 + checker.configure(config);
92 + checker.addListener(listener);
93 +
94 + // run Checker
95 + List<File> fileList = Stream.of(files.split("\n"))
96 + .map(File::new)
97 + .collect(Collectors.toList());
98 + int errorCounter = checker.process(fileList);
99 + if (errorCounter > 0) {
100 + listener.append("CHECKSTYLE ERROR\n");
101 + }
102 + } finally {
103 + checker.destroy();
104 + }
105 +
106 + return listener.getAudit();
107 + }
108 +}
109 +
110 +class StringAuditor implements AuditListener {
111 +
112 + private CountDownLatch finishedLatch = new CountDownLatch(1);
113 + private StringBuilder output = new StringBuilder();
114 + private String base = "";
115 +
116 + public void setBase(String base) {
117 + this.base = base;
118 + }
119 +
120 + public void append(String s) {
121 + output.append(s);
122 + }
123 +
124 + public String getAudit() throws InterruptedException {
125 + finishedLatch.await();
126 + return output.toString();
127 + }
128 +
129 + @Override
130 + public void auditStarted(AuditEvent evt) {
131 +
132 + }
133 +
134 + @Override
135 + public void auditFinished(AuditEvent evt) {
136 + finishedLatch.countDown();
137 + }
138 +
139 + @Override
140 + public void fileStarted(AuditEvent evt) {
141 +
142 + }
143 +
144 + @Override
145 + public void fileFinished(AuditEvent evt) {
146 +
147 + }
148 +
149 + @Override
150 + public void addError(AuditEvent evt) {
151 + switch (evt.getSeverityLevel()) {
152 + case ERROR:
153 + String fileName = evt.getFileName();
154 + int index = fileName.indexOf(base);
155 + if (index >= 0) {
156 + fileName = fileName.substring(index + base.length() + 1);
157 + }
158 + output.append(fileName).append(':').append(evt.getLine());
159 + if (evt.getColumn() > 0) {
160 + output.append(':').append(evt.getColumn());
161 + }
162 + output.append(": ").append(evt.getMessage());
163 + output.append('\n');
164 + break;
165 + case IGNORE:
166 + case INFO:
167 + case WARNING:
168 + default:
169 + break;
170 + }
171 + }
172 +
173 + @Override
174 + public void addException(AuditEvent evt, Throwable throwable) {
175 + addError(evt);
176 + output.append(throwable.getMessage());
177 + }
178 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.checkstyle;
18 +
19 +import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
20 +
21 +import java.io.IOException;
22 +import java.net.ServerSocket;
23 +import java.nio.ByteBuffer;
24 +import java.nio.channels.FileChannel;
25 +import java.nio.channels.FileLock;
26 +import java.nio.file.Files;
27 +import java.nio.file.Path;
28 +import java.nio.file.Paths;
29 +import java.util.Timer;
30 +import java.util.TimerTask;
31 +import java.util.concurrent.ExecutorService;
32 +import java.util.concurrent.Executors;
33 +
34 +import static java.nio.file.StandardOpenOption.*;
35 +
36 +/**
37 + * Main program for executing scenario test warden.
38 + */
39 +public final class Main {
40 +
41 + private static long POLLING_INTERVAL = 1000; //ms
42 +
43 + // Public construction forbidden
44 + private Main(String[] args) {
45 + }
46 +
47 + /**
48 + * Main entry point for the cell warden.
49 + *
50 + * @param args command-line arguments
51 + */
52 + public static void main(String[] args)
53 + throws CheckstyleException, IOException {
54 + startServer(args);
55 + }
56 +
57 + // Monitors another PID and exit when that process exits
58 + private static void watchProcess(String pid) {
59 + if (pid == null || pid.equals("0")) {
60 + return;
61 + }
62 + Timer timer = new Timer(true); // start as a daemon, so we don't hang shutdown
63 + timer.scheduleAtFixedRate(new TimerTask() {
64 + private String cmd = "kill -s 0 " + pid;
65 + @Override
66 + public void run() {
67 + try {
68 + Process p = Runtime.getRuntime().exec(cmd);
69 + p.waitFor();
70 + if (p.exitValue() != 0) {
71 + System.err.println("shutting down...");
72 + System.exit(0);
73 + }
74 + } catch (IOException | InterruptedException e) {
75 + //no-op
76 + e.printStackTrace();
77 + }
78 + }
79 + }, POLLING_INTERVAL, POLLING_INTERVAL);
80 + }
81 +
82 + // Initiates a server.
83 + private static void startServer(String[] args) throws IOException, CheckstyleException {
84 + String portLock = args[0];
85 + String buckPid = args[1];
86 + String checkstyleFile = args[2];
87 + String suppressionsFile = args[3];
88 +
89 + // Use a file lock to ensure only one copy of the daemon runs
90 + Path portLockPath = Paths.get(portLock);
91 + FileChannel channel = FileChannel.open(portLockPath, WRITE, CREATE);
92 + FileLock lock = channel.tryLock();
93 + if (lock == null) {
94 + System.out.println("Server is already running");
95 + System.exit(1);
96 + } //else, hold the lock until the JVM exits
97 +
98 + // Start the server and bind it to a random port
99 + ServerSocket server = new ServerSocket(0);
100 +
101 + // Monitor the parent buck process
102 + watchProcess(buckPid);
103 +
104 + // Set up hook to clean up after ourselves
105 + Runtime.getRuntime().addShutdownHook(new Thread(() -> {
106 + try {
107 + if (channel != null) {
108 + channel.truncate(0);
109 + channel.close();
110 + }
111 + System.err.println("tear down...");
112 + Files.delete(portLockPath);
113 + } catch (IOException e) {
114 + //no-op: shutting down
115 + e.printStackTrace();
116 + }
117 + }));
118 +
119 + // Write the bound port to the port file
120 + int port = server.getLocalPort();
121 + channel.truncate(0);
122 + channel.write(ByteBuffer.wrap(Integer.toString(port).getBytes()));
123 +
124 + // Instantiate a Checkstyle runner and executor; serve until exit...
125 + CheckstyleRunner runner = new CheckstyleRunner(checkstyleFile, suppressionsFile);
126 + ExecutorService executor = Executors.newCachedThreadPool();
127 + while (true) {
128 + try {
129 + executor.submit(runner.checkClass(server.accept()));
130 + } catch (Exception e) {
131 + e.printStackTrace();
132 + //no-op
133 + }
134 + }
135 + }
136 +}
1 +#!/bin/bash
2 +CHECKSTYLE=$1
3 +FILES=$2
4 +CONFIG=$3
5 +SUPPRESSIONS=$4
6 +
7 +PORT_FILE="$1.port"
8 +
9 +function ppid() {
10 + ps -p ${1:-$$} -o ppid= -o pid= -o comm=
11 +}
12 +
13 +function buck_pid() {
14 + BUCK_PID=($(ppid))
15 + while [ ${BUCK_PID[0]} -ne 0 ]; do
16 + BUCK_PID=($(ppid $BUCK_PID))
17 + if [ "${BUCK_PID[2]}" == "buck" ]; then
18 + # use parent PID of buck
19 + echo ${BUCK_PID[0]}
20 + return
21 + fi
22 + if [ "${BUCK_PID[2]}" == "buckd" ] ||
23 + [[ "${BUCK_PID[2]}" == *"python"* ]]; then
24 + # use PID of buckd or python
25 + echo ${BUCK_PID[1]}
26 + return
27 + fi
28 + done
29 + # fallback last read PID
30 + echo ${BUCK_PID[1]}
31 +}
32 +
33 +function port() {
34 + cat $PORT_FILE 2>/dev/null || echo 0
35 +}
36 +
37 +function check_socket() {
38 + nc localhost $(port) < /dev/null 2>/dev/null
39 + return $?
40 +}
41 +
42 +# check to see if checkstyle daemon is running; if not, start it
43 +if ! check_socket; then
44 + # Starting checkstyle server...
45 + #FIXME change to /dev/null if/when we are confident
46 + nohup java -jar $CHECKSTYLE $PORT_FILE $(buck_pid) $3 $4 >>/tmp/checkstyle.daemon 2>&1 &
47 +
48 + TRIES=20
49 + i=0
50 + # Wait for checkstyle server to start for 2 seconds
51 + while [ $i -lt $TRIES ]; do
52 + if check_socket; then
53 + CONNECTED=true
54 + break
55 + fi
56 + let i=i+1
57 + sleep 0.1
58 + done
59 + if [ -z "$CONNECTED" ]; then
60 + echo "Failed to start checkstyle server"
61 + exit 3
62 + fi
63 +fi
64 +
65 +# run the actual checkstyle client
66 +OUT=$(cat $FILES | nc localhost $(port))
67 +if [ $? -ne 0 ]; then
68 + echo "Error connecting to checkstyle server"
69 + exit 2
70 +fi
71 +if [ -n "$OUT" ]; then
72 + printf "$OUT"
73 + exit 1
74 +fi
...\ No newline at end of file ...\ No newline at end of file