How to set system properties for runMain on command line?
Asked Answered
H

3

45

How can I set a system property for runMain upon executing it from command line on Windows?

I'd like to be able to run the following command:

sbt -Dconfig.resource=../application.conf "runMain akka.Main com.my.main.Actor"

Regardless of whether fork is true, whether I put it in SBT_OPTS, or how I pass it in I cannot accomplish this. I am familiar with both Setting value of setting on command line when no default value defined in build? and Setting system properties with "sbt run" but neither answer my question.

Other questions seem to indicate you can't even easily view the Java invocation arguments easily in SBT. Any help is appreciated.

Haemolysin answered 27/1, 2014 at 19:2 Comment(2)
BTW, this works at least with sbt 1.x sbt run -J-Dconfig.resource="../application.conf"Marianmariana
This doesn't work, at least not in sbt 1.1.1. Adding enVars in run := Map("config.resources" -> "blabla") works thoughFig
T
50

This works:

sbt '; set javaOptions += "-Dconfig.resource=../application.conf" ; runMain akka.Main com.my.main.Actor'

If this isn't a "friendly" enough syntax, wrap it in a little shell script.

(Note this assumes you have fork set to true for running. If you don't, see akauppi's comment.)

Tomasatomasina answered 29/1, 2014 at 14:13 Comment(7)
Thanks, I'm afraid that is about the best I can do.Haemolysin
No, that's not friendly enough. Is there a better way now?Grazing
I think this needs 'fork' to be enabled. Got it to work without fork (which was my need) by: sbt '; eval System.setProperty("config.file","fn.conf") ; test'Howenstein
@Howenstein this works great for calling something in main - but i can't get it working with any of my tests or integration testsCabal
Replace with javaOptions ++= Seq(...) for brevity when overriding multiple options.Skimp
if you want to combine forking VMs with set javaOpts, use this in addition: javaOptions in ThisBuild ++= sys.props.get("config.resource") .map(value => s"-Dconfig.resource=$value").toSeqSemivitreous
If you use subproject/runMain then it's subproject/javaOptions. Easy to forget.Canso
H
18

You could use envVars setting. I'm unsure how idiomatic it is in SBT, though.

> help envVars
Environment variables used when forking a new JVM

The following (very minimalistic) build.sbt worked fine.

fork := true

envVars := Map("msg" -> "hello")

Once you get it running, setting envVars to any value with set does the trick.

> help set
set [every] <setting-expression>

        Applies the given setting to the current project:
          1) Constructs the expression provided as an argument by compiling and loading it.
          2) Appends the new setting to the current project's settings.
          3) Re-evaluates the build's settings.

        This command does not rebuild the build definitions, plugins, or configurations.
        It does not automatically persist the setting(s) either.
        To persist the setting(s), run 'session save' or 'session save-all'.

        If 'every' is specified, the setting is evaluated in the current context
        and the resulting value is used in every scope.  This overrides the value
        bound to the key everywhere.

I've got a simple app to run.

$ sbt run
[info] Set current project to fork-testing (in build file:/C:/dev/sandbox/fork-testing/)
[info] Running Hello
[info] hello

With the envVars setting changed on the command line the output would change as follows:

$ sbt 'set envVars := Map("msg" -> "Hello, Chad")' run
[info] Set current project to fork-testing (in build file:/C:/dev/sandbox/fork-testing/)
[info] Defining *:envVars
[info] The new value will be used by *:runner, compile:run::runner and 1 others.
[info]  Run `last` for details.
[info] Reapplying settings...
[info] Set current project to fork-testing (in build file:/C:/dev/sandbox/fork-testing/)
[info] Running Hello
[info] Hello, Chad

runMain is no different from run in this case.

$ sbt 'set envVars := Map("msg" -> "Hello, Chad")' 'runMain Hello'
[info] Set current project to fork-testing (in build file:/C:/dev/sandbox/fork-testing/)
[info] Defining *:envVars
[info] The new value will be used by *:runner, compile:run::runner and 1 others.
[info]  Run `last` for details.
[info] Reapplying settings...
[info] Set current project to fork-testing (in build file:/C:/dev/sandbox/fork-testing/)
[info] Running Hello
[info] Hello, Chad
Hydromagnetics answered 28/1, 2014 at 15:30 Comment(4)
Thanks for the answer. I was hoping for Java system properties, but I suppose I could set javaOptions via the "set". I was hoping for a more friendly way for my administrator to provide the path to his configuration, but it appears I just have to create a custom task or something.Haemolysin
BTW, Why do you want to run an app using SBT instead of leveraging sbt-native-packager at the very least?! All configuration would then be in a code repo and you'd also could automate deployments.Hydromagnetics
I want my administrator to provide this system property at his own leisure.Haemolysin
The following #37214252 answers my question.Mcmath
R
6

If you're trying to set SBT properties, like plugin settings, then the above won't work (AFAICT) as of 0.13+ in my experience. The following however did work, when trying to pass in Liquibase settings, like password, from our CI frameworks.

In your build.sbt

Ugly, but supplies defaults, and optionally grabs from System.properties. This way you've got your default and override cases covered.

def sysPropOrDefault(propName:String,default:String):String = Option(System.getProperty(propName)).getOrElse(default)

liquibaseUsername := sysPropOrDefault("liquibase.username","change_me")
liquibasePassword := sysPropOrDefault("liquibase.password","chuck(\)orris")

From the commandline

Now just override via -Dprop=value like you would with Maven or other JVM programs. Note props appear before SBT task.

sbt -Dliquibase.password="shh" -Dliquibase.username="bob" liquibase:liquibase-update

Razor answered 2/6, 2016 at 16:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.