Running a scala script

Running a Script Inlined in the pom

This goal allows you to execute a scala script defined in the pom.

  <plugin>
    <groupId>net.alchim31.maven</groupId>
    <artifactId>scala-maven-plugin</artifactId>
    <version>4.8.1</version>
    <executions>
      <execution>
        <phase>package</phase>
        <goals>
          <goal>script</goal>
        </goals>
      </execution>
    </executions>
    <configuration>
      <script>
        println ("Hello from pom script :-)")
     </script>
    </configuration>
  </plugin>

Running from a Script File

This goal allows you to run a scala script by defining the "script" property:

mvn scala:script -DscriptFile=scripts/PrintHello.scala

Running a script as part of a build

Executing a script as part of the build process.

  <plugin>
    <groupId>net.alchim31.maven</groupId>
    <artifactId>scala-maven-plugin</artifactId>
    <version>4.8.1</version>
    <executions>
      <execution>
        <phase>package</phase>
        <goals>
          <goal>script</goal>
        </goals>
      </execution>
    </executions>
    <configuration>
      <scriptFile>package.scala</scriptFile>
    </configuration>
  </plugin>

Predefining a script file

Adding the script configuration to your plugin definition.

  <plugin>
    <groupId>net.alchim31.maven</groupId>
    <artifactId>scala-maven-plugin</artifactId>
    <version>4.8.1</version>
    <configuration>
      <scriptFile>pathToScript/MyScript</scriptFile>
    </configuration>
  </plugin>

Now you can run the following command to run your scala app.

mvn scala:script

Classpath for running and compiling script

The classpath is define by configuration 'includeScopes', 'excludeScopes', 'addToClasspath'. The possible scopes are : test, compile, system, runtime, plugin. The default rules (since 2.14) is :
  • embedded script into pom.xml run with 'plugin' scope
  • script read from scriptFile run with 'compile, test, runtime'

Using the Maven Project from within a script

If the script run within the 'PLUGIN' scope then a scala.maven.model.MavenProjectAdapter object and a org.apache.maven.plugin.logging.Log object will be passed to the script. The Log will have the name "log" and the MavenProjectAdapter will have the name "project"

The class MavenProjectAdapter is a decorator for the MavenProject class that adds typing to the java.util.Collection and adds apply and update methods for accessing the properties of the project.

Note: In this scenario the scala.collection.jcl.Conversions._ is imported so that the java.util collections can be treated as Scala collections.

Here is an example script using the project

        <executions>
          <execution>
            <id>generate-hello</id>
            <phase>generate-sources</phase>
            <goals>
              <goal>script</goal>
            </goals>
            <configuration>
              <scalaVersion>2.7.7</scalaVersion>
              <keepGeneratedScript>true</keepGeneratedScript>
              <script>
              &lt;![CDATA[
                println("hello from scala script constructor")

                def run() {
                  import java.io.PrintWriter
                  import scala.collection.jcl.Conversions._

                  println("hello from scala script run method")
                  log.info( project("scala.version") )
                  val fo = new PrintWriter("target/hello.txt")
                  try {
                    fo.println(project.getArtifactId())
                    for( d <- project.getDependencies() ) {
                      fo.println (d.getArtifactId)
                    }
                  } finally {
                    fo.close()
                  }
                }
              ]]&gt;
              </script>
            </configuration>
          </execution>
        </executions>
      </plugin>

Technical details

This mojo operates by adding a class definition to the start of the script. As a result the script is essentially the initialization of the class.

The reason for this is that it allows one to define classes and functions in any order and not worry about 'forward reference extends over definition of value _' compile errors.

However there is a danger in putting complex code in the constructor of a class and that has to do poor performance because of certain precautions the JVM takes when constructing a class. In order to offer a solution to this this Mojo will look for a run() method after the 'virtual' class has been constructed and invokes that method.

If this mojo detects that the MavenProjectAdapter class is on the classpath (in otherwords this plugin is a dependency in the scope that the script runs) then the MavenProjectAdapter that decorates the current MavenProject will be passed to the script's construct. The variable name is 'project'. The project variable can be used to inspect parameters of the maven project like the properties and dependencies of the project.

Here is an example using the run method with the MavenProjectAdapter

<script>
  println ("Hi I shouldn't do any heavy work here...")
  def run(){
    println(project.getName+" is the current project")
    println("Now lets do some serious work!  Even multi-threaded programming is allowed.")
  }
</script>