You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Main.java 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /*
  2. * SonarQube Runner - CLI - Distribution
  3. * Copyright (C) 2011 SonarSource
  4. * sonarqube@googlegroups.com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
  19. */
  20. package org.sonar.runner.cli;
  21. import java.io.BufferedReader;
  22. import java.io.IOException;
  23. import java.io.InputStreamReader;
  24. import java.nio.charset.StandardCharsets;
  25. import java.util.Properties;
  26. import org.sonar.runner.api.EmbeddedRunner;
  27. /**
  28. * Arguments :
  29. * <ul>
  30. * <li>runner.home: optional path to runner home (root directory with sub-directories bin, lib and conf)</li>
  31. * <li>runner.settings: optional path to runner global settings, usually ${runner.home}/conf/sonar-runner.properties.
  32. * This property is used only if ${runner.home} is not defined</li>
  33. * <li>project.home: path to project root directory. If not set, then it's supposed to be the directory where the runner is executed</li>
  34. * <li>project.settings: optional path to project settings. Default value is ${project.home}/sonar-project.properties.</li>
  35. * </ul>
  36. *
  37. * @since 1.0
  38. */
  39. public class Main {
  40. private final Shutdown shutdown;
  41. private final Cli cli;
  42. private final Conf conf;
  43. private EmbeddedRunner runner;
  44. private BufferedReader inputReader;
  45. private RunnerFactory runnerFactory;
  46. Main(Shutdown shutdown, Cli cli, Conf conf, RunnerFactory runnerFactory) {
  47. this.shutdown = shutdown;
  48. this.cli = cli;
  49. this.conf = conf;
  50. this.runnerFactory = runnerFactory;
  51. }
  52. public static void main(String[] args) {
  53. Exit exit = new Exit();
  54. Shutdown shutdown = new Shutdown(exit);
  55. Cli cli = new Cli(exit).parse(args);
  56. cli.verify();
  57. Main main = new Main(shutdown, cli, new Conf(cli), new RunnerFactory());
  58. main.execute();
  59. }
  60. void execute() {
  61. Stats stats = new Stats().start();
  62. try {
  63. Properties p = conf.properties();
  64. init(p);
  65. runner.start();
  66. if (cli.isInteractive()) {
  67. interactiveLoop(p);
  68. } else {
  69. runAnalysis(stats, p);
  70. }
  71. } catch (Exception e) {
  72. displayExecutionResult(stats, "FAILURE");
  73. showError("Error during Sonar runner execution", e, cli.isDisplayStackTrace());
  74. shutdown.exit(Exit.ERROR);
  75. }
  76. runner.stop();
  77. shutdown.exit(Exit.SUCCESS);
  78. }
  79. private void interactiveLoop(Properties p) throws IOException {
  80. do {
  81. Stats stats = new Stats().start();
  82. try {
  83. runAnalysis(stats, p);
  84. } catch (Exception e) {
  85. displayExecutionResult(stats, "FAILURE");
  86. showError("Error during Sonar runner execution", e, cli.isDisplayStackTrace());
  87. }
  88. } while (waitForUser());
  89. }
  90. private void init(Properties p) throws IOException {
  91. SystemInfo.print();
  92. if (cli.isDisplayVersionOnly()) {
  93. shutdown.exit(Exit.SUCCESS);
  94. }
  95. if (cli.isDisplayStackTrace()) {
  96. Logs.info("Error stacktraces are turned on.");
  97. }
  98. runner = runnerFactory.create(p);
  99. }
  100. private void runAnalysis(Stats stats, Properties p) {
  101. runner.runAnalysis(p);
  102. displayExecutionResult(stats, "SUCCESS");
  103. }
  104. private boolean waitForUser() throws IOException {
  105. if (inputReader == null) {
  106. inputReader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
  107. }
  108. shutdown.signalReady(true);
  109. if (shutdown.shouldExit()) {
  110. // exit before displaying message
  111. return false;
  112. }
  113. System.out.println("");
  114. System.out.println("<Press enter to restart analysis or Ctrl+C to exit the interactive mode>");
  115. String line = inputReader.readLine();
  116. shutdown.signalReady(false);
  117. return line != null;
  118. }
  119. // Visible for testing
  120. void setInputReader(BufferedReader inputReader) {
  121. this.inputReader = inputReader;
  122. }
  123. private static void displayExecutionResult(Stats stats, String resultMsg) {
  124. Logs.info("------------------------------------------------------------------------");
  125. Logs.info("EXECUTION " + resultMsg);
  126. Logs.info("------------------------------------------------------------------------");
  127. stats.stop();
  128. Logs.info("------------------------------------------------------------------------");
  129. }
  130. private void showError(String message, Throwable e, boolean showStackTrace) {
  131. if (showStackTrace) {
  132. Logs.error(message, e);
  133. if (!cli.isDebugMode()) {
  134. Logs.error("");
  135. suggestDebugMode();
  136. }
  137. } else {
  138. Logs.error(message);
  139. if (e != null) {
  140. Logs.error(e.getMessage());
  141. String previousMsg = "";
  142. for (Throwable cause = e.getCause(); cause != null
  143. && cause.getMessage() != null
  144. && !cause.getMessage().equals(previousMsg); cause = cause.getCause()) {
  145. Logs.error("Caused by: " + cause.getMessage());
  146. previousMsg = cause.getMessage();
  147. }
  148. }
  149. Logs.error("");
  150. Logs.error("To see the full stack trace of the errors, re-run SonarQube Runner with the -e switch.");
  151. if (!cli.isDebugMode()) {
  152. suggestDebugMode();
  153. }
  154. }
  155. }
  156. private static void suggestDebugMode() {
  157. Logs.error("Re-run SonarQube Runner using the -X switch to enable full debug logging.");
  158. }
  159. }