scala - how to deal with a sbt multi project with non-standard artifacts? -
what trying do:
first, let me present (very) simplified version of i'm trying achieve. consider following multi-project:
root |___backend | |___frontend | |___deployer
the backend packaged onejar, , performs standalone process background work. frontend web-service play project (packaged zip file dist
). deployer yet self executable jar packaged onejar, packaging modified include other projects artifacts. deployer job initialize system. deploys other artifacts specified machines, , initializes distributed system.
what problem:
basically, i'm trying (unsuccessfully) play's dist zip artifact & backend onejar self executable artifact packaged inside deployer jar (with other resources files)
the deployer jar should like:
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 logback.xml) , onejar files....
what have far:
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) ...
backend/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) ...
frontend/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 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) ...
deployer/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 "src/main/resources" inner jar, fat one-jar. classpathtypes := classpathtypes.value + "zip" //don't ommit dist zip file 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 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 commented out because it's not working, shows i'm trying do. //(types wrong. need file 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) ...
notice in root build.sbt, have per-configuration classpath dependencies "optional->compile"
. iv'e put there after looking @ ivy.xml
file:
... <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> ...
and seeing dist.zip
artifact found in optional
scope, thought artifact dependency way (not seem working though...). also, when tried out commented out lines, got error saying it's wrong type.
==================================================
as i'm writing question, figured out i've done wrong...
update:
there's few things missed (to snippets copy & pasted...). first, deployer should not dependon(backend,frontend)
@ all. aggregate
. moreover, these artifacts (backend & frontend) should not visible on deployer's classpath @ all. line:
classpathtypes := classpathtypes.value + "zip"
is unneeded. also, code transform mappings in onejar
in deployer/build.sbt
file, more simple. need take care of resources. , finally, commented out lines, should be:
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"}
that's pretty it.
Comments
Post a Comment