如何处理带有非标准工件的sbt多项目?

时间:2014-03-10 09:17:02

标签: scala sbt onejar

我想做什么:

首先,让我提出一个(非常)简化的版本,我想要实现的目标。 考虑以下多项目:

root
|___backend
|   
|___frontend
|
|___deployer

后端与oneJar一起打包,并作为执行后台工作的独立进程执行。前端是一个Web服务play项目(打包为带dist的zip文件)。部署者是另一个与oneJar一起打包的自执行jar,但是包装被修改为包含其他项目工件。部署工作是初始化系统。它将其他工件部署到指定的计算机,并初始化分布式系统。

我的问题是什么:

基本上,我正在尝试(不成功)获得该游戏的dist zip artifact&后端oneJar自我可执行工件打包在deployer jar(与其他资源文件)中

部署者应该看起来像:

deployer-executable.jar
|___0/
|   |___backend-selfexec.jar
|   |___frontenf-dist.zip
|
|___1/
|   |___other resources (mostly configuration files)
|   |___ ...
|
|___META-INF/ ...
|___com/simontuffs/onejar/ ...
|___doc/ ...
|___lib/ ...
|___main/deployer-VERSION.jar
|___other resources (such as logback.xml) and oneJar files....

到目前为止我有什么:

build.sbt

...

lazy val backend = project in file("backend") 

lazy val frontend = project in file("frontend") 

lazy val deployer = project in file("deployer") dependsOn(backend % "optional->compile", frontend % "optional->compile")    aggregate(backend, frontend)

...

后端/ build.sbt

...

seq(com.github.retronym.SbtOneJar.oneJarSettings: _*)

exportJars := true

mainClass in oneJar := Some("org.product.backend.Main")

artifact in oneJar <<= moduleName(Artifact(_, "selfexec"))

addArtifact(artifact in (Compile, oneJar), oneJar)

...

前端/ build.sbt

import play.Project._

...

play.Project.playScalaSettings

lazy val dist = com.typesafe.sbt.SbtNativePackager.NativePackagerKeys.dist

lazy val publishDist = TaskKey[sbt.File]("publish-dist", "publish the dist artifact")

publish <<= (publish) dependsOn dist

publishLocal <<= (publishLocal) dependsOn dist

artifact in publishDist ~= {
  (art: Artifact) => art.copy(`type` = "zip", extension = "zip", classifier = Some("dist"))
}

publishDist <<= (target in Universal, normalizedName, version) map { (targetDir, id, version) =>
  val packageName = s"$id-$version"
  targetDir / (packageName + ".zip")
}

addArtifact(artifact in publishDist, publishDist)

...

部署/ build.sbt

...

seq(com.github.retronym.SbtOneJar.oneJarSettings: _*)

exportJars := true

mainClass in oneJar := Some("org.product.deployer.Main")

unmanagedResources in Compile := Seq() //don't add resources from "src/main/resources" to inner jar, only to the fat one-jar.

classpathTypes :=  classpathTypes.value + "zip" //don't ommit the dist zip file from classpath

mappings in oneJar := {
    def isNeedToBeInDir0(f: File) = f.getName == "frontend-VERSION-dist.zip" || f.getName == "backend-VERSION-selfexec.jar"
    def nameForPackaging(name: String): String = if(name.contains("frontend")) "frontend.zip" else "backend.jar"
    //following method could be replaced with: http://www.scala-sbt.org/release/docs/Detailed-Topics/Mapping-Files.html#relative-to-a-directory
    def files2TupleRec(pathPrefix: String, dir: File): Seq[Tuple2[File,String]] = {
        sbt.IO.listFiles(dir) flatMap {
            f => {
                if(f.isFile) Seq((f,s"${pathPrefix}${f.getName}"))
                else files2TupleRec(s"${pathPrefix}${f.getName}/",f)
            }
        }
    }
    val oldSeq = (mappings in oneJar).value
    oldSeq.filterNot(t => isNeedToBeInDir0(t._1)) ++ 
    oldSeq.filter(t => isNeedToBeInDir0(t._1)).map{
        case (f,_) => (f,s"/0/${nameForPackaging(f.getName)}") //NOT WORKING
    } ++ 
    files2TupleRec("",file("deployer/src/main/resources"))
}

//following lines is commented out because it's also not working, but it shows very clearly what i'm trying to do.
//(types are wrong. i need File but have sbt.Artifact):

//mappings in oneJar <+= (artifact in LocalProject("backend") in oneJar) map {_ -> "/0/backend.jar"} 

//mappings in oneJar <+= (artifact in LocalProject("frontend") in oneJar) map {_ -> "/0/frontend.zip"} 

artifact in oneJar <<= moduleName(Artifact(_, "executable"))

addArtifact(artifact in (Compile, oneJar), oneJar)

...

请注意,在root build.sbt中,我有per-configuration classpath dependencies "optional->compile"。看完ivy.xml文件后,我把它放在那里:

...
 <configurations>
         <conf name="compile" visibility="public" description=""/>
         <conf name="runtime" visibility="public" description="" extends="compile"/>
         <conf name="test" visibility="public" description="" extends="runtime"/>
         <conf name="provided" visibility="public" description=""/>
         <conf name="optional" visibility="public" description=""/>
         <conf name="sources" visibility="public" description=""/>
         <conf name="pom" visibility="public" description=""/>
 </configurations>
 <publications>
         <artifact name="frontend_2.10" type="zip" ext="zip" conf="compile,runtime,test,provided,optional,sources,pom" e:classifier="dist"/>
         <artifact name="frontend_2.10" type="pom" ext="pom" conf="pom"/>
         <artifact name="frontend_2.10" type="jar" ext="jar" conf="compile"/>
         <artifact name="frontend_2.10" type="src" ext="jar" conf="sources" e:classifier="sources"/>
 </publications>
...

并且看到dist.zip工件只在optional范围内找到,我想我可以通过这种方式将这个工件作为依赖(虽然似乎没有工作......)。另外,当我试用注释掉的行时,我得到一个错误,说它是错误的类型。

=============================================== ===

因为我在写这个问题,我想出了我做错了什么......

UPDATE:

我错过了一些东西(很多片段都是复制和粘贴的......)。首先,部署者不应该dependOn(backend,frontend)。只是aggregate。而且,这些工件(后端和前端)根本不应该在部署者的类路径中可见。所以这一行:

classpathTypes :=  classpathTypes.value + "zip"

是不需要的。另外,转换mappings in oneJar文件中deployer/build.sbt的代码可能要简单得多。只需要照顾资源。最后,注释掉的行应该是:

mappings in oneJar <+= (artifactPath in LocalProject("backend") in oneJar) map {_ -> "0/backend.jar"} 

mappings in oneJar <+= (packageBin in LocalProject("frontend") in Universal) map {_ -> "0/frontend.zip"}

几乎就是这样。

0 个答案:

没有答案