This is an automated email from the ASF dual-hosted git repository. paulk pushed a commit to branch GROOVY_5_0_X in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 6b00ab80bd90107c3f16c1b70999910fddd219bd Author: Mattias Reichel <[email protected]> AuthorDate: Tue Jan 13 16:56:59 2026 +0100 GROOVY-11839: feat(groovysh): entry point with binding injection --- .../groovy/org/apache/groovy/groovysh/Main.groovy | 32 +++++++++++++++++---- .../groovy/groovysh/ProgrammaticStartTest.groovy | 33 ++++++++++++++++++++++ 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Main.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Main.groovy index 1aa8308cc2..0ef1b23eed 100644 --- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Main.groovy +++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Main.groovy @@ -290,7 +290,14 @@ class Main { } } - static void main(String[] args) { + /** + * Programmatic entry point for embedding groovysh. + * + * @param args CLI-like arguments (same as {@link #main(String[])}). + * @param initialBindings binding variables for the GroovyEngine + * @return process exit code (0 for success) + */ + static int start(String[] args = new String[0], Map<String, ?> initialBindings = Collections.emptyMap()) { def cli = new CliBuilderInternal(usage: 'groovysh [options] [...]', stopAtNonOption: false, header: messages['cli.option.header']) cli.with { @@ -311,18 +318,18 @@ class Main { OptionAccessor options = cli.parse(args) if (options == null) { - // CliBuilder prints error, but does not exit - System.exit(22) // Invalid Args + // CliBuilder prints error + return 22 // Invalid Args } if (options.h) { cli.usage() - System.exit(0) + return 0 } if (options.V) { println render(messages.format('cli.info.version', GroovySystem.version)) - System.exit(0) + return 0 } String evaluate = options.e ?: null @@ -359,6 +366,15 @@ class Main { // ScriptEngine and command registries GroovyEngine scriptEngine = new GroovyEngine() + + if (initialBindings) { + initialBindings.each { k, v -> + if (k != null) { + scriptEngine.put(k, v) + } + } + } + scriptEngine.put('ROOT', rootURL.toString()) if (!scriptEngine.hasVariable('CONSOLE_OPTIONS')) { scriptEngine.put('CONSOLE_OPTIONS', [:]) @@ -506,6 +522,12 @@ class Main { } } catch (Throwable t) { t.printStackTrace() + return 1 } + return 0 + } + + static void main(String[] args) { + System.exit(start(args)) } } diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/apache/groovy/groovysh/ProgrammaticStartTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/apache/groovy/groovysh/ProgrammaticStartTest.groovy new file mode 100644 index 0000000000..e2542f0463 --- /dev/null +++ b/subprojects/groovy-groovysh/src/test/groovy/org/apache/groovy/groovysh/ProgrammaticStartTest.groovy @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.groovy.groovysh + +import groovy.test.GroovyTestCase + +/** + * Verifies the programmatic API surface exists and is callable. + */ +class ProgrammaticStartTest extends GroovyTestCase { + + void testStartMethodIsPresentAndCallable() { + // We just verify it accepts parameters and doesn't throw on trivial help/version paths. + int rc = Main.start(['--help'] as String[], [foo: 1]) + assert rc == 0 + } +}
