scala記述のプロジェクトをMavenで構築し，scalaコマンドで実行するまで．

# Maven -scala実行-

mavenを初めて使う機会があったので，引っかかったところを中心にまとめてみる．
maven自体がどんなものかはhttps://kengotoda.gitbooks.io/what-is-maven/primer/ を
読むことでおおまかなイメージをつけた．
本記事は以下の目的を達成するための手順を解説していく．

1. scalaコードを含むプロジェクト作成
1. mavenでscalaコードを実行するための設定
1. 依存関係を含むjarファイルの生成とその実行

環境は
ApacheMave:3.5.0 java:1.8.0 scala:2.11.6

## プロジェクト作成 ##
```bash
$ mvn archetype:generate
Choose a number or apply filter : scala
# 7: remote -> net.alchim31.maven:scala-archetype-simpleを確認して
Choose a number or apply filter : 7
Choose a number : 3
Define value for property 'groupId': project.test
Define value for property 'artifactId': mavenTest
Define value for property 'version' 1.0-SNAPSHOT: [Enter]
Define value for property 'package' project.test: [Enter]
Y: [Enter]
```
これでmavenTestフォルダが生成される．

```bash
$ tree mavenTest
mavenTest/
├── pom.xml
└── src
    ├── main
    │   └── scala
    │       └── project
    │           └── test
    │               └── App.scala
    └── test
        └── scala
            └── samples
                ├── junit.scala
                ├── scalatest.scala
                └── specs.scala
```

## 実行するための設定 ##
このままコンパイルを実行すると，

```bash
$ cd mavenTest
$ mvn compile
...
[ERROR] scalac error: bad option: '-make:transitive'
[INFO]   scalac -help  gives more information
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.446 s
[INFO] Finished at: 2017-08-11T21:39:24+09:00
[INFO] Final Memory: 11M/300M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal net.alchim31.maven:scala-maven-plugin:3.2.0:compi
...
```
というエラーが出てくる．そこでpom.xmlを次のように編集する．

```xml:pom.xml
<!-- この行を削除する -->
     <arg>-make:transitive</arg>
```

するとコンパイルは成功するので実行を行う．すると次のエラーが出る．

```bash
$ mvn scala:run
...
[ERROR] /home/yoshiki/xgboost/jvm-packages/project/mavenTest/src/test/scala/samples/specs.scala:18: error: not found: type JUnitRunner
[ERROR] @RunWith(classOf[JUnitRunner])
[ERROR]                  ^
[ERROR] one error found
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.391 s
[INFO] Finished at: 2017-08-11T21:43:41+09:00
[INFO] Final Memory: 11M/300M
[INFO] ------------------------------------------------------------------------
...
```
どうやらテストコードのビルドにコケたようである．
そこで次のようにpom.xmlを変更する．
＃ちなみに，mvn compileやmvn scala:runのcompile, scala:runは実行のゴールを指定するため，
mvn scala:runはmvn compileの操作を包含している．なので実際はmvn scala:runの実行だけで良い．

```xml:pom.xml
  <dependencies>
    ...
    <!-- JUnitRunner -->
    <dependency>
        <groupId>org.specs2</groupId>
        <artifactId>specs2-junit_${scala.compat.version}</artifactId>
        <!--versionは前後のspecs2-coreなどに合わせる-->
        <version>2.4.16</version>
        <scope>test</scope>
    </dependency>
    <!----------------->
    ...
  </dependencies>
```

実行

```bash
$ mvn scala:run

[WARNING] warning: there was one deprecation warning; re-run with -deprecation for details
[WARNING] one warning found
[INFO] prepare-compile in 0 s
[INFO] compile in 4 s
[INFO] 
[INFO] <<< scala-maven-plugin:3.2.0:run (default-cli) < test-compile @ mavenTest <<<
[INFO] 
[INFO] 
[INFO] --- scala-maven-plugin:3.2.0:run (default-cli) @ mavenTest ---
[WARNING] Not mainClass or valid launcher found/define
```
main class が無いということなのでscala-maven-pluginに指定する．(参考：http://qiita.com/motokazu/items/57540c80509d83c6a168 )

```xml:pom.xml
<!-- scala-maven-pluginのpluginのところに追加-->
      <plugin>
        <!-- see http://davidb.github.com/scala-maven-plugin -->
        <groupId>net.alchim31.maven</groupId>
        <artifactId>scala-maven-plugin</artifactId>
        <version>3.2.0</version>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
              <goal>testCompile</goal>
            </goals>
            <configuration>
              <args>
                <arg>-dependencyfile</arg>
                <arg>${project.build.directory}/.scala_dependencies</arg>
              </args>
            </configuration>
          </execution>
        </executions>
        <!-- ここから -->
        <configuration>
          <launchers>
            <launcher>
              <id>test</id>
              <mainClass>project.test.App</mainClass>
              <args>
                <arg>${basedir}</arg>
              </args>
            </launcher>
          </launchers>
        </configuration>
        <!-- ここまで追加 -->
      </plugin>
```
mvn scala:runすると，無事に'Hello world!'が出力される．
次に自由に使いたいライブラリをpom.xmlのdependenciesに追加していく．xgboostであれば，

```xml:pom.xml
<dependency>
  <groupId>ml.dmlc</groupId>
  <artifactId>xgboost4j</artifactId>
  <version>0.7</version>
</dependency>
```
と言った具合に追加する．（実際にxgboostを使うには，あらかじめ公式の手順でmvn installしなければならない）

## 実行だけを行いたい ##
mvn scala:runはアプリケーションをコンパイル＆実行してくれるが，勝手にコンパイルまでしてしまう．もし実行だけを行いたいならば，まず依存ライブラリを含むjarファイルを生成する必要がある．そのために
maven-assembly-pluginをpom.xmlに追加する．

```xml:pom.xml
<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <descriptorRefs>
      <descriptorRef>jar-with-dependencies</descriptorRef>
    </descriptorRefs>
  </configuration>
</plugin>
```
実行

```bash
$ ls target
archive-tmp                  maven-status                                      test-classes
classes                      mavenTest-1.0-SNAPSHOT.jar                        test-classes.-2096028797.timestamp
classes.936127338.timestamp  mavenTest-1.0-SNAPSHOT-jar-with-dependencies.jar
maven-archiver               specs2-reports

$ scala -cp target/mavenTest-1.0-SNAPSHOT-jar-with-dependencies.jar project.test.App
Hello World!
concat arguments = 
```

## repository のurlを追加 ##

```
<project>
  <repositories>
      <id>my-repo1</id>
      <name>central-repo</name>
      <url>https://repo.maven.apache.org/maven2/</url>
    </repository>
    <repository>
      <id>my-repo2</id>
      <name>maven2-repo</name>
      <url>https://dl.bintray.com/spark-packages/maven/</url>
    </repository>
  </repositories>
</project>
```

おわり．