From 9c149b9b93948d3fc75284b34c9dc6cb6d5271a6 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Mon, 29 Jul 2024 15:57:29 +0200 Subject: [PATCH 1/2] Must specify --repl to enable debug server --- .../src/main/java/org/enso/runner/Main.java | 74 ++++++++++--------- .../java/org/enso/runner/EngineMainTest.java | 46 ++++++++++++ .../Base_Tests/src/Semantic/Runtime_Spec.enso | 4 + 3 files changed, 88 insertions(+), 36 deletions(-) create mode 100644 engine/runner/src/test/java/org/enso/runner/EngineMainTest.java diff --git a/engine/runner/src/main/java/org/enso/runner/Main.java b/engine/runner/src/main/java/org/enso/runner/Main.java index 98c882bfd8d1..7e9bc456c55f 100644 --- a/engine/runner/src/main/java/org/enso/runner/Main.java +++ b/engine/runner/src/main/java/org/enso/runner/Main.java @@ -56,7 +56,7 @@ import scala.runtime.BoxedUnit; /** The main CLI entry point class. */ -public final class Main { +public class Main { private static final String JVM_OPTION = "jvm"; private static final String RUN_OPTION = "run"; private static final String INSPECT_OPTION = "inspect"; @@ -98,6 +98,8 @@ public final class Main { private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Main.class); + Main() {} + private static boolean isDevBuild() { return Info.ensoVersion().matches(".+-SNAPSHOT$"); } @@ -106,11 +108,8 @@ private static Option.Builder cliOptionBuilder() { return Option.builder(); } - /** - * Builds the [[Options]] object representing the CLI syntax. - * - * @return an [[Options]] object representing the CLI syntax - */ + private static final Options CLI_OPTIONS = buildOptions(); + private static Options buildOptions() { var help = cliOptionBuilder().option("h").longOpt(HELP_OPTION).desc("Displays this message.").build(); @@ -512,22 +511,22 @@ private static Options buildOptions() { * * @param options object representing the CLI syntax */ - private static void printHelp(Options options) { - new HelpFormatter().printHelp(LanguageInfo.ID, options); + private static void printHelp() { + new HelpFormatter().printHelp(LanguageInfo.ID, CLI_OPTIONS); } /** Terminates the process with a failure exit code. */ - private static RuntimeException exitFail() { + private RuntimeException exitFail() { return doExit(1); } /** Terminates the process with a success exit code. */ - private static RuntimeException exitSuccess() { + private final RuntimeException exitSuccess() { return doExit(0); } /** Shuts down the logging service and terminates the process. */ - private static RuntimeException doExit(int exitCode) { + RuntimeException doExit(int exitCode) { RunnerLogging.tearDown(); System.exit(exitCode); return null; @@ -665,7 +664,7 @@ private void compile( * @param executionEnvironment name of the execution environment to use during execution or {@code * null} */ - private void run( + private void handleRun( String path, java.util.List additionalArgs, String projectPath, @@ -675,6 +674,7 @@ private void run( boolean disablePrivateCheck, boolean enableAutoParallelism, boolean enableStaticAnalysis, + boolean enableDebugServer, boolean inspect, boolean dump, String executionEnvironment, @@ -708,9 +708,13 @@ private void run( .options(options); if (inspect) { + if (enableDebugServer) { + println("Cannot use --inspect and --repl and --run at once"); + throw exitFail(); + } options.put("inspect", ""); - } else { - // by default running with debug server enabled + } + if (enableDebugServer) { factory.messageTransport(replTransport()); options.put(DebugServerInfo.ENABLE_OPTION, "true"); } @@ -960,7 +964,7 @@ private void displayVersion(boolean useJson) { } /** Parses the log level option. */ - private static Level parseLogLevel(String levelOption) { + private Level parseLogLevel(String levelOption) { var name = levelOption.toLowerCase(); var found = Stream.of(Level.values()).filter(x -> name.equals(x.name().toLowerCase())).findFirst(); @@ -977,7 +981,7 @@ private static Level parseLogLevel(String levelOption) { } /** Parses an URI that specifies the logging service connection. */ - private static URI parseUri(String string) { + private URI parseUri(String string) { try { return new URI(string); } catch (URISyntaxException ex) { @@ -1001,15 +1005,13 @@ public static void main(String[] args) throws Exception { /** * Main entry point for the CLI program. * - * @param options the command line options * @param line the provided command line arguments * @param logLevel the provided log level * @param logMasking the flag indicating if the log masking is enabled */ - private void runMain(Options options, CommandLine line, Level logLevel, boolean logMasking) - throws IOException { + final void mainEntry(CommandLine line, Level logLevel, boolean logMasking) throws IOException { if (line.hasOption(HELP_OPTION)) { - printHelp(options); + printHelp(); throw exitSuccess(); } if (line.hasOption(VERSION_OPTION)) { @@ -1089,7 +1091,7 @@ private void runMain(Options options, CommandLine line, Level logLevel, boolean } if (line.hasOption(RUN_OPTION)) { - run( + handleRun( line.getOptionValue(RUN_OPTION), Arrays.asList(line.getArgs()), line.getOptionValue(IN_PROJECT_OPTION), @@ -1099,6 +1101,7 @@ private void runMain(Options options, CommandLine line, Level logLevel, boolean line.hasOption(DISABLE_PRIVATE_CHECK_OPTION), line.hasOption(AUTO_PARALLELISM_OPTION), line.hasOption(ENABLE_STATIC_ANALYSIS_OPTION), + line.hasOption(REPL_OPTION), line.hasOption(INSPECT_OPTION), line.hasOption(DUMP_GRAPHS_OPTION), line.getOptionValue(EXECUTION_ENVIRONMENT_OPTION), @@ -1106,7 +1109,7 @@ private void runMain(Options options, CommandLine line, Level logLevel, boolean .map(Integer::parseInt) .getOrElse(() -> 100)); } - if (line.hasOption(REPL_OPTION)) { + if (line.hasOption(REPL_OPTION) && !line.hasOption(RUN_OPTION)) { runRepl( line.getOptionValue(IN_PROJECT_OPTION), logLevel, @@ -1122,7 +1125,7 @@ private void runMain(Options options, CommandLine line, Level logLevel, boolean preinstallDependencies(line.getOptionValue(IN_PROJECT_OPTION), logLevel); } if (line.getOptions().length == 0) { - printHelp(options); + printHelp(); throw exitFail(); } } @@ -1240,16 +1243,15 @@ private static final scala.collection.immutable.List join( return scala.collection.immutable.$colon$colon$.MODULE$.apply(head, tail); } - private void println(String msg) { + void println(String msg) { System.out.println(msg); } private void launch(String[] args) throws IOException, InterruptedException, URISyntaxException { - var options = buildOptions(); - var line = preprocessArguments(options, args); + var line = preprocessArguments(args); var logMasking = new boolean[1]; - var logLevel = setupLogging(options, line, logMasking); + var logLevel = setupLogging(line, logMasking); if (line.hasOption(JVM_OPTION)) { var jvm = line.getOptionValue(JVM_OPTION); @@ -1332,36 +1334,36 @@ private void launch(String[] args) throws IOException, InterruptedException, URI } } - launch(options, line, logLevel, logMasking[0]); + launch(line, logLevel, logMasking[0]); } - protected CommandLine preprocessArguments(Options options, String[] args) { + final CommandLine preprocessArguments(String... args) { var parser = new DefaultParser(); try { var startParsing = System.currentTimeMillis(); - var line = parser.parse(options, args); + var line = parser.parse(CLI_OPTIONS, args); logger.trace( "Parsing Language Server arguments took {0}ms", System.currentTimeMillis() - startParsing); return line; } catch (Exception e) { - printHelp(options); + printHelp(); throw exitFail(); } } - private static Level setupLogging(Options options, CommandLine line, boolean[] logMasking) { + private Level setupLogging(CommandLine line, boolean[] logMasking) { var logLevel = scala.Option.apply(line.getOptionValue(LOG_LEVEL)) - .map(Main::parseLogLevel) + .map(this::parseLogLevel) .getOrElse(() -> defaultLogLevel); - var connectionUri = scala.Option.apply(line.getOptionValue(LOGGER_CONNECT)).map(Main::parseUri); + var connectionUri = scala.Option.apply(line.getOptionValue(LOGGER_CONNECT)).map(this::parseUri); logMasking[0] = !line.hasOption(NO_LOG_MASKING); RunnerLogging.setup(connectionUri, logLevel, logMasking[0]); return logLevel; } - private void launch(Options options, CommandLine line, Level logLevel, boolean logMasking) { + private void launch(CommandLine line, Level logLevel, boolean logMasking) { if (line.hasOption(LANGUAGE_SERVER_OPTION)) { try { var conf = parseProfilingConfig(line); @@ -1379,7 +1381,7 @@ private void launch(Options options, CommandLine line, Level logLevel, boolean l conf, ExecutionContext.global(), () -> { - runMain(options, line, logLevel, logMasking); + mainEntry(line, logLevel, logMasking); return BoxedUnit.UNIT; }); } catch (IOException ex) { diff --git a/engine/runner/src/test/java/org/enso/runner/EngineMainTest.java b/engine/runner/src/test/java/org/enso/runner/EngineMainTest.java new file mode 100644 index 000000000000..5b496f38ef32 --- /dev/null +++ b/engine/runner/src/test/java/org/enso/runner/EngineMainTest.java @@ -0,0 +1,46 @@ +package org.enso.runner; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import org.junit.Test; +import org.slf4j.event.Level; + +public class EngineMainTest { + private final List linesOut = new ArrayList<>(); + + @Test + public void cannotUseReplAndInspectAtOnce() throws Exception { + try { + var m = + new Main() { + @Override + RuntimeException doExit(int code) { + throw new ExitCode(code); + } + + void println(String line) { + linesOut.add(line); + } + }; + var file = File.createTempFile("some", ".enso"); + file.deleteOnExit(); + var line = m.preprocessArguments("--repl", "--inspect", "--run", file.getAbsolutePath()); + m.mainEntry(line, Level.INFO, false); + } catch (ExitCode ex) { + assertEquals("Execution fails", 1, ex.exitCode); + assertEquals("One line printed", 1, linesOut.size()); + assertEquals("Cannot use --inspect and --repl and --run at once", linesOut.get(0)); + } + } + + private static final class ExitCode extends RuntimeException { + final int exitCode; + + ExitCode(int exitCode) { + this.exitCode = exitCode; + } + } +} diff --git a/test/Base_Tests/src/Semantic/Runtime_Spec.enso b/test/Base_Tests/src/Semantic/Runtime_Spec.enso index 5c4ec3955915..3b0c4977e118 100644 --- a/test/Base_Tests/src/Semantic/Runtime_Spec.enso +++ b/test/Base_Tests/src/Semantic/Runtime_Spec.enso @@ -1,4 +1,5 @@ import Standard.Base.Runtime +import Standard.Base.Runtime.Debug import Standard.Base.Data.Numbers.Integer import Standard.Base.Any.Any import Standard.Base.Nothing.Nothing @@ -38,6 +39,9 @@ add_specs suite_builder = r2 = Panic.catch Any (Runtime.with_disabled_context Input environment=Runtime.current_execution_environment <| in_fn (out_fn 10)) p-> p.payload.to_text r2 . should_equal "(Forbidden_Operation.Error 'The Input context is disabled.')" + suite_builder.group "Debug" group_builder-> + group_builder.specify "Debug.breakpoint doesn't stop indefinitly" <| + Debug.breakpoint main filter=Nothing = suite = Test.build suite_builder-> From 76070ba54bfc57ce84a60b6215c1138df41fa8b9 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Mon, 29 Jul 2024 16:41:06 +0200 Subject: [PATCH 2/2] Use --repl to enable REPL changelog note --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a0ce5c320d0..af58be175a5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,12 @@ - [Enforce conversion method return type][10468] - [Renaming launcher executable to ensoup][10535] - [Space-precedence does not apply to value-level operators][10597] +- [Must specify `--repl` to enable debug server][10709] [10468]: https://github.com/enso-org/enso/pull/10468 [10535]: https://github.com/enso-org/enso/pull/10535 [10597]: https://github.com/enso-org/enso/pull/10597 +[10709]: https://github.com/enso-org/enso/pull/10709 #### Enso IDE