Gradle:使用项目类路径执行Groovy交互式shell

我有一个由几个子项目组成的Gradle项目。 我刚刚创建了一个新的,以添加对我想要运行的交互式Groovy shell的支持:

gradle console 

要么

 gradle console:run 

所以我的新console模块的build.gradle文件如下:

 apply plugin: 'groovy' apply plugin:'application' mainClassName = 'org.codehaus.groovy.tools.shell.Main' dependencies { compile 'org.codehaus.groovy:groovy-all:2.2.2' compile 'org.fusesource.jansi:jansi:1.11' compile 'commons-cli:commons-cli:1.2' compile 'jline:jline:2.11' compile project(':my-module') } task(console, dependsOn: 'classes', type: JavaExec) { main = 'org.codehaus.groovy.tools.shell.Main' classpath = sourceSets.main.runtimeClasspath } 

但是,当我运行gradle :console:rungradle console我得到类似的东西:

 :console:run Groovy Shell (2.2.2, JVM: 1.6.0_45) Type 'help' or '\h' for help. -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- groovy:000> BUILD SUCCESSFUL Total time: 4.529 secs giovanni@mylaptop:~/Projects/my-project$ 

因此,交互式shell似乎已经开始,但它会立即退出。

难道我做错了什么?

编辑 :在build.gradle文件中添加以下内容:

 run.standardInput = System.in 

现在,从输入流中读取标准输入(由于注释)。

但是,Gradle似乎陷入了困境:

 Groovy Shell (2.2.2, JVM: 1.6.0_45) Type 'help' or '\h' for help. -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- groovy:000> > Building 88% > :console:run 

并且没有接受任何输入。 即使这样也会导致同样的事情:

 gradle --no-daemon console:run 

2018年更新:

Dylons接受的答案似乎不再起作用了./gradlew console立即退出:

 $ ./gradlew console 

配置项目:不推荐使用Task.leftShift(Closure)方法,并计划在Gradle 5.0中删除它。 请改用Task.doLast(Action)。 在build_8qb2gvs00xed46ejq1p63fo92.run(/home/jhe052/eclipse-workspace/QuinCe/build.gradle:118)(使用–stacktrace运行以获取此弃用警告的完整堆栈跟踪。)

在3个3个可操作的任务中建立成功:1个执行,2个最新

用doLast替换leftShift(<<)会删除不推荐使用的消息,但结果相同。 版本信息:

 $ ./gradlew --version 

Gradle 4.4.1

制作时间:2017-12-20 15:45:23 UTC修订:10ed9dc355dc39f6307cc98fbd8cea314bdd381c

Groovy:2.4.12 Ant:2017年2月2日编译的Apache Ant(TM)版本1.9.9 JVM:1.8.0_151(Oracle Corporation 25.151-b12)操作系统:Linux 4.13.0-32-generic amd64

这适用于JDK 7+(对于JDK 6,请看下图):

 configurations { console } dependencies { // ... compile dependencies, runtime dependencies, etc. console 'commons-cli:commons-cli:1.2' console('jline:jline:2.11') { exclude(group: 'junit', module: 'junit') } console 'org.codehaus.groovy:groovy-groovysh:2.2.+' } task(console, dependsOn: 'classes') << { def classpath = sourceSets.main.runtimeClasspath + configurations.console def command = [ 'java', '-cp', classpath.collect().join(System.getProperty('path.separator')), 'org.codehaus.groovy.tools.shell.Main', '--color' ] def proc = new ProcessBuilder(command) .redirectOutput(ProcessBuilder.Redirect.INHERIT) .redirectInput(ProcessBuilder.Redirect.INHERIT) .redirectError(ProcessBuilder.Redirect.INHERIT) .start() proc.waitFor() if (0 != proc.exitValue()) { throw new RuntimeException("console exited with status: ${proc.exitValue()}") } } 

为了使这项工作适用于JDK 6,我从https://stackoverflow.com/a/4274535/206543修改了该解决方案。 我的解决方案是针对标准Linux终端量身定制的,因此如果您运行的shell使用除了'\ n'之外的字符序列用于换行或将退格编码为其他127的值,则可能需要对其进行一些修改。 我没有确定如何正确打印颜色,因此它的输出相当单调,但它将完成工作:

 configurations { console } dependencies { // ... compile dependencies, runtime dependencies, etc. console 'commons-cli:commons-cli:1.2' console('jline:jline:2.11') { exclude(group: 'junit', module: 'junit') } console 'org.codehaus.groovy:groovy-groovysh:2.2.+' } class StreamCopier implements Runnable { def istream def ostream StreamCopier(istream, ostream) { this.istream = istream this.ostream = ostream } void run() { int n def buffer = new byte[4096] while ((n = istream.read(buffer)) != -1) { ostream.write(buffer, 0, n) ostream.flush() } } } class InputCopier implements Runnable { def istream def ostream def stdout InputCopier(istream, ostream, stdout) { this.istream = istream this.ostream = ostream this.stdout = stdout } void run() { try { int n def buffer = java.nio.ByteBuffer.allocate(4096) while ((n = istream.read(buffer)) != -1) { ostream.write(buffer.array(), 0, n) ostream.flush() buffer.clear() if (127 == buffer.get(0)) { stdout.print("\b \b") stdout.flush() } } } catch (final java.nio.channels.AsynchronousCloseException exception) { // Ctrl+D pressed } finally { ostream.close() } } } def getChannel(istream) { def f = java.io.FilterInputStream.class.getDeclaredField("in") f.setAccessible(true) while (istream instanceof java.io.FilterInputStream) { istream = f.get(istream) } istream.getChannel() } task(console, dependsOn: 'classes') << { def classpath = sourceSets.main.runtimeClasspath + configurations.console def command = [ 'java', '-cp', classpath.collect().join(System.getProperty('path.separator')), 'org.codehaus.groovy.tools.shell.Main' ] def proc = new ProcessBuilder(command).start() def stdout = new Thread(new StreamCopier(proc.getInputStream(), System.out)) stdout.start() def stderr = new Thread(new StreamCopier(proc.getErrorStream(), System.err)) stderr.start() def stdin = new Thread(new InputCopier( getChannel(System.in), proc.getOutputStream(), System.out)) stdin.start() proc.waitFor() System.in.close() stdout.join() stderr.join() stdin.join() if (0 != proc.exitValue()) { throw new RuntimeException("console exited with status: ${proc.exitValue()}") } } 

然后,通过以下方式执行:

 gradle console 

或者,如果你从gradle那里得到很多噪音:

 gradle console -q 

我创建了一个允许这个的gradle插件( https://github.com/tkruse/gradle-groovysh-plugin )。 遗憾的是,Gradle没有为支持REPL的IO提供有用的API /合约,因此该插件不适用于较新版本的Gradle。

但是,在github上的文档中,您可以找到没有插件的手动解决方案 。

该解决方案的大纲是:

 package shell; import org.codehaus.groovy.tools.shell.Main; import org.fusesource.jansi.AnsiConsole; class ShellMain { public static void main(String[] args) { // workaround for jAnsi problems, (backspace and arrow keys not working) AnsiConsole.systemUninstall(); Main.main(args); } } 

然后使用JavaExec任务运行它

 apply plugin: 'java' dependencies { compile('commons-cli:commons-cli:1.2') compile('org.codehaus.groovy:groovy-all:2.4.4') { force = true } // when using groovy < 2.2 above: "jline:jline:1.0" compile("jline:jline:2.11") { exclude(group: 'junit', module: 'junit') } } task shell(dependsOn: 'testClasses', type: JavaExec) { doFirst { if (getProperty('org.gradle.daemon') == 'true') { throw new IllegalStateException('Do not run shell with gradle daemon, it will eat your arrow keys.') } } standardInput = System.in main = 'shell.ShellMain' classpath = sourceSets.main.runtimeClasspath jvmArgs = [] } 

Gradle目前不能很好地处理ncurses样式的控制台应用程序。 在单独的控制台中运行groovysh ,或者运行groovyConsole