【问题标题】:In the startup scripts generated by gradle's application plugin, how can I have the program name passed in to the application?在 gradle 的应用插件生成的启动脚本中,如何将程序名传入到应用中?
【发布时间】:2018-01-17 17:44:02
【问题描述】:

执行 gradle 应用程序插件的 installDist 任务会创建一个目录 build/install/<em>my-application-name</em>/bin,其中包含包装脚本 my-application-name<em>my-application-name</em>.bat。运行这些脚本中的任何一个都会运行应用程序,并且传递给这些脚本的参数会传递给底层应用程序。

在 UNIX shell 脚本中,您可以访问用于执行程序的名称 $0。其实 UNIX 版本的 gradle 生成的启动脚本多次使用$0

如何配置 gradle 应用程序插件,以便这些脚本将 $0 的值(以及 Windows 上的任何 Windows 等效项)传递到底层应用程序,也许作为 Java 系统属性?

【问题讨论】:

    标签: java gradle


    【解决方案1】:

    由于获取正在运行的脚本名称的参数在 Linux($0) 和 Windows(%0) 中的引用方式不同,因此生成自定义脚本的最直接方法是为各自start script generators:

    startScripts {
      unixStartScriptGenerator.template = resources.text.fromFile('unixStartScript.txt')
      windowsStartScriptGenerator.template = resources.text.fromFile('windowsStartScript.txt')
    }
    

    默认模板很容易获得调用,例如unixStartScriptGenerator.template.asString()

    关于自定义启动脚本的文档可以在here找到。

    【讨论】:

    • 作为一个对 Groovy 知之甚少的人,我如何将-Dprogname="$0" 插入到 unix 脚本的正确位置(作为 JVM 的参数之一)?我不想更改整个模板,只需将这一参数添加到 JVM(并且我希望 $0 由 shell 评估 - 我不希望将文字美元符号和零传递给JVM)。
    • @LaurenceGonsalves 您可以就地更改模板:def gen = unixStartScriptGenerator; gen.template = resources.text.fromString(gen.template.asString().replace('DEFAULT_JVM_OPTS=${defaultJvmOpts}', 'DEFAULT_JVM_OPTS=${defaultJvmOpts}; JAVA_OPTS="\\$JAVA_OPTS -Dprogname=\\$0"'))
    • @LaurenceGonsalves 在不修改脚本的情况下,您可以尝试使用startScripts 任务的defaultJvmOpts 参数传递值,但是值会被转义,因此插入$ 符号会出现问题.
    • 谢谢。我对此做了一些调整,但像这样转换模板是关键因素。
    • 如何防止生成.bat文件?我试图用空的generateScript() 分配一个带有ScriptGenerator 实例的匿名类,但这仍然会在那里创建.bat 文件。唯一不同的是它是空的。
    【解决方案2】:

    我采取了另一种方法。根据文档,从Gradle 2.4 一直到Gradle 4.8,我们应该能够在startScripts 任务中设置以下属性:

    • applicationName
    • optsEnvironmentVar
    • exitEnvironmentVar
    • mainClassName
    • executableDir
    • defaultJvmOpts
    • appNameSystemProperty
    • appHomeRelativePath
    • classpath

    不幸的是,以下属性并非如此,它们似乎从未公开过:

    • appNameSystemProperty
    • appHomeRelativePath

    如果appNameSystemProperty 如文档所述被暴露,那么我们应该能够简单地执行以下操作:

    startScripts {
        applicationName = 'foo'
        appNameSystemProperty = 'appName'
    }
    

    这将导致将-DappName=foo 添加到在两个启动脚本中构造的 Java 命令中。

    由于情况并非如此,我采用了以下方法,这比该问题的早期解决方案更冗长,但可能不那么脆弱,因为它不依赖于调整开箱即用的模板。相反,它会导致记录在案的行为。

    startScripts {
        mainClassName = '...'
        applicationName = 'foo'
        unixStartScriptGenerator =
            new CustomStartScriptGenerator(generator: unixStartScriptGenerator)
        windowsStartScriptGenerator =
            new CustomStartScriptGenerator(generator: windowsStartScriptGenerator)
    }
    
    class CustomStartScriptGenerator implements ScriptGenerator {
        @Delegate
        ScriptGenerator generator
    
        void generateScript(JavaAppStartScriptGenerationDetails details,
                            Writer destination) {
            details = new CustomDetails(details: details)
            this.generator.generateScript(details, destination)
        }
    
        static class CustomDetails implements JavaAppStartScriptGenerationDetails {
            @Delegate
            JavaAppStartScriptGenerationDetails details
    
            @Override
            String getAppNameSystemProperty() { 'appName' }
        }
    }
    

    【讨论】:

      【解决方案3】:

      根据 jihor 的回答,这就是我最终要做的。我在这里发布它只是为了给其他感兴趣的人提供一个可行的答案:

      startScripts {
          def gen = unixStartScriptGenerator
          gen.template = resources.text.fromString(
              gen.template.asString().replaceFirst('(?=\nDEFAULT_JVM_OPTS=.*?\n)') {
                  '\nJAVA_OPTS="\\$JAVA_OPTS "\'"-Dprogname=\\$0"\''
              })
      
          // TODO: do something similar for windowsStartScriptGenerator
      }
      

      这使用replaceFirst 代替replace,所以我们可以匹配一个模式。这有点不那么脆弱,也让我们可以使用前瞻,所以我们不必实际替换我们正在寻找的东西。 (顺便说一下,这是 replaceFirst 的 groovy 变体,它采用闭包。与在这种情况下采用替换字符串的版本相比,这需要的转义要少得多。)

      还有,而不是:

      JAVA_OPTS="$JAVA_OPTS -Dprogname=$0"
      

      我们实际上需要这样的东西:

      JAVA_OPTS="$JAVA_OPTS "'"-Dprogname=$0"'
      

      这是因为$0 可能包含特殊字符(如空格),并且启动脚本使用eval set -- 删除了$JAVA_OPTS 值中的一级引号。

      (如果有人知道如何在 Windows 上进行此操作,请随时更新此答案。)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-09-06
        • 1970-01-01
        • 2020-05-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多