I want to get the project and configuration axis from within the task. For example, considering the following task:
myTask := {
val project = ?
val configuration = ?
val key = ?
println(s"project: $project")
println(s"configuration: $configuration")
println(s"key: $key")
}
If I run the task like this,
> myModule/myConfig:myTask
it should print
project: myModule
configuration: myConfig
key: myTask
My partial solution in build.sbt would be as follows:
lazy val myTask = taskKey[Unit]("Prints axes of its execution")
lazy val myTaskSetting = myTask := {
val project = thisProject.value.id
val cfg = configuration.?.value
val key = myTask.key.label
println(s"project: $project")
println(s"configuration: $cfg")
println(s"key: $key")
}
myTaskSetting
lazy val a, b = project settings (Seq(myTaskSetting): _*)
I've no idea how to access the current configuration the task is bound to upon execution.
> myTask
project: axes
configuration: None
key: myTask
project: b
configuration: None
key: myTask
project: a
configuration: None
key: myTask
Related
In Corda 3.2, when using the Cordform task, I might define a validating notary as follows:
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
directory "./build/nodes"
node {
name "O=Notary,L=London,C=GB"
notary = [validating : true]
p2pPort 10002
rpcSettings {
address("localhost:10003")
adminAddress("localhost:10043")
}
cordapps = [ ]
}
}
How do I define a validating notary when using the node driver?
When using the node driver, you use the notarySpecs parameter to define the notaries to create on the network:
fun main(args: Array<String>) {
val validatingNotarySpec = NotarySpec(CordaX500Name("ValidatingNotary", "London", "GB"), true)
val nonValidatingNotarySpec = NotarySpec(CordaX500Name("NonValidatingNotary", "London", "GB"), false)
val notarySpecs = listOf(validatingNotarySpec, nonValidatingNotarySpec)
driver(DriverParameters(notarySpecs = notarySpecs)) {
// Driver logic.
}
}
By default, you will get a single validating notary with the name CordaX500Name("Notary Service", "Zurich", "CH").
I'm deploying a corda network using two different machines: in the first I'm deploying a notary and an oracle service using the following configuration:
Notary
myLegalName="O=Notary,L=London,C=GB"
keyStorePassword : "cordacadevpass"
trustStorePassword : "trustpass"
p2pAddress="machine-ip1:10004"
notary : {
validating : false
}
devMode : true
Oracle
myLegalName="O=Oracle,L=London,C=GB"
keyStorePassword : "cordacadevpass"
trustStorePassword : "trustpass"
p2pAddress="machine-ip1:10001"
rpcSettings {
address="0.0.0.0:10002"
adminAddress="0.0.0.0:10003"
}
rpcUsers=[
{
password=test
permissions=[
ALL
]
user=user1
}
]
devMode : true
In the second I'm deploying the following party node:
Party
myLegalName="O=Party,L=London,C=GB"
keyStorePassword : "cordacadevpass"
trustStorePassword : "trustpass"
p2pAddress="machine-ip2:10001"
rpcSettings {
address="0.0.0.0:10002"
adminAddress="0.0.0.0:10003"
}
rpcUsers=[
{
password=test
permissions=[
ALL
]
user=user1
}
]
devMode : true
Once Party starts a flow building a transaction it fails raising this exception:
java.lang.IllegalStateException: Need to specify a notary for the state, or set a default one on TransactionBuilder
at net.corda.core.transactions.TransactionBuilder.addOutputState(TransactionBuilder.kt:172)
at net.corda.core.transactions.TransactionBuilder.addOutputState$default(TransactionBuilder.kt:171)
The call function is :
override fun call(): SignedTransaction {
val notary = serviceHub.networkMapCache.getNotary(CordaX500Name("Notary", "London", "GB"))!!
val issueState = CashOwningState(amount, ourIdentity)
val issueCommand = Command(
CashIssueContract.Commands.Issue(),
issueState.participants.map { it.owningKey })
val txBuilder = TransactionBuilder(notary).withItems(
StateAndContract(issueState, CashIssueContract.TEST_CONTRACT_ID),
issueCommand)
txBuilder.verify(serviceHub)
val fullySignedTx = serviceHub.signInitialTransaction(txBuilder)
return subFlow(FinalityFlow(fullySignedTx, FINALIZING_TX.childProgressTracker()))
}
It seems that the Notary is found in the network, but the CordApp doesn't recognize it as a notary.
This is not an issue of the CorDapp not recognising the notary. The only place this exception is thrown is here:
#JvmOverloads
fun addOutputState(state: ContractState, contract: ContractClassName, constraint: AttachmentConstraint = AutomaticHashConstraint): TransactionBuilder {
checkNotNull(notary) { "Need to specify a notary for the state, or set a default one on TransactionBuilder initialisation" }
addOutputState(state, contract, notary!!, constraint = constraint)
return this
}
When instantiating a TransactionBuilder by passing in a notary, no check is performed for whether the party being passed is in fact a notary.
You must be trying to add an output state to a TransactionBuilder without a notary somewhere else in your code.
mappings in Universal <++= (packageBin in Compile, sourceDirectory) map { (_, src) =>
val confFiles = (src / "main" / "resources") ** "*.conf"
confFiles.get.map(file => file -> ("conf/" + file.name))
},
Works but generates a compiler warning <++= has been deprecated. Changing the operator to ++= generates a compiler error
error: No implicit for Append.Values[Seq[(java.io.File, String)], sbt.Def.Initialize[sbt.Task[Seq[(java.io.File, String)]]]] found,
so sbt.Def.Initialize[sbt.Task[Seq[(java.io.File, String)]]] cannot be appended to Seq[(java.io.File, String)]
mappings in Universal ++= (packageBin in Compile, sourceDirectory) map { (_, src) =>
Here is how I solved it
mappings in Universal ++= { (packageBin in Compile, sourceDirectory) map { (_, src) =>
val confFiles = (src / "main" / "resources") ** "*.conf"
confFiles.get.map(file => file -> ("conf/" + file.name))
}
}.value,
Even better is
mappings in Universal ++= {
val src = sourceDirectory.value
val confFiles = (src / "main" / "resources") ** "*.conf"
confFiles.get.map(file => file -> ("conf/" + file.name))
}
This operator is very confusing. Try a simpler := which is functionally equivalent:
mappings.in(Universal) := {
// Dependency on packageBin (part of your previous definition).
packageBin.in(Compile).value
// Create the new mappings.
val confFiles = (sourceDirectory.value / "main" / "resources") ** "*.conf"
val newMappings = confFiles.get.map(file => file -> ("conf/" + file.name))
// Append them manually to the previous value.
mappings.in(Universal).value ++ newMappings
}
I am using sbt to build a multi-module project. One of the modules is a JavaScript application which builds with npm. I would like to simply execute npm via a shell script as part of the package task, and use the resulting output file as the artifact for that module. I am able to run a shell command as part of the package task, but for some reason this task is ignored when I run publish or publishLocal.
Attached is my Build.scala.
It is the accounts-ui project which should build using npm. Right now the actual npm build is represented by a simple script.
import sbt._
import Keys._
import play.Play.autoImport._
import PlayKeys._
import play.PlayScala
import sbtassembly._
import AssemblyKeys._
import net.virtualvoid.sbt.graph.Plugin.graphSettings
import ohnosequences.sbt.SbtS3Resolver.autoImport._
object Build extends Build {
lazy val commonSettings = Seq(
organization := "myorg",
scalaVersion := "2.11.5"
)
lazy val publishSettings = Seq(
publishTo := {
val prefix = if (isSnapshot.value) "snapshots" else "releases"
Some(s3resolver.value("MyOrg " + prefix + " S3 bucket", s3(prefix+".repo.myorg.com")))
}
)
lazy val root = Project(id = "root", base = file(".")).settings(commonSettings).settings(
name := "accounts-root"
).settings(publishSettings).aggregate(api, ui)
val _apiName = "accounts-api"
lazy val api = Project(id = "api", base = file("./api")).settings(commonSettings).settings(
name := "accounts-api",
libraryDependencies ++= Seq(
specs2
)
).settings(publishSettings).settings(graphSettings).settings(
mainClass in assembly := Some("play.core.server.NettyServer"),
fullClasspath in assembly += Attributed.blank(PlayKeys.playPackageAssets.value),
test in assembly := {},
assemblyExcludedJars in assembly := {
val cp = (fullClasspath in assembly).value
cp filter { (el) => {
val name = el.data.getName
name.contains("mockito") || name.contains("commons-logging") || name.contains("specs2")
}
}
}
).settings(addArtifact(Artifact(_apiName, "assembly"), assembly)
).enablePlugins(PlayScala)
val npmBuildTask = taskKey[Unit]("some custom task")
lazy val ui = Project(id = "ui", base = file("./ui")).settings(commonSettings).settings(
name := "accounts-ui",
npmBuildTask := {
val processBuilder = Process("npm-build.sh")
val process = processBuilder.run()
if(process.exitValue() != 0)
throw new Error(s"custom task failed with exit value ${process.exitValue()}")
},
Keys.`package` <<= (Keys.`package` in Compile) dependsOn npmBuildTask
).settings(publishSettings)
}
I was able to solve it as follows:
val npmPackageTask = taskKey[File]("npm package task")
lazy val ui = Project(id = "ui", base = file("./ui")).settings(commonSettings).settings(
name := "accounts-ui",
npmPackageTask := {
val processBuilder = Process("npm-build.sh")
val process = processBuilder.run()
if(process.exitValue() != 0)
throw new Error(s"custom task failed with exit value ${process.exitValue()}")
file(".")
},
packageBin in Compile <<= npmPackageTask
).settings(publishSettings)
The key was to create the key as taskKey[File], use the packageBin key, and replace the task with the <<= operator.
I have two task nativeJar and native64Jar, manifest and doLast closers are same for both the tasks except the file names. So is It possible to extract that code in a common method and pass two file names as a method parameter and call that common method from both tasks or call that method from dolast clouser.
task nativeJar( type: Jar ) {
doFirst {
delete fileTree(dir: "$releaseDir", include: "*.jar")
}
baseName = 'NativeLibs'
destinationDir = new File(releaseDir)
from files(releaseDir + 'jar_merge/signedNativeLibs')
manifest {
attributes 'Permissions' : 'all-permissions', 'Publisher' : 'abc', 'Application-Name' : 'WorkBench', 'Codebase' : '*.abc.com'
}
doLast {
ant.signjar( jar: "$releaseDir/NativeLibs.jar", alias:"WorkBench", keystore: "WorkBench.jks", signedjar: "$releaseDir/signedNativeLibs.jar", storepass: "freddie" )
}
}
// Create signedNativeLibs64.jar file
task native64Jar( type: Jar , dependsOn: 'nativeJar' ) {
baseName = 'NativeLibs64'
destinationDir = new File(releaseDir)
from files(releaseDir + 'jar_merge/signedNativeLibs64')
manifest {
attributes 'Permissions' : 'all-permissions', 'Publisher' : 'abc', 'Application-Name' : 'WorkBench', 'Codebase' : '*.abc.com'
}
doLast {
ant.signjar( jar: "$releaseDir/NativeLibs64.jar", alias:"WorkBench", keystore: "WorkBench.jks", signedjar: "$releaseDir/signedNativeLibs64.jar", storepass: "freddie" )
}
}
I would recommend splitting out the signing as a separate task so that you get proper up-to-date checks from Gradle. As you have it now, you'll always sign the jar every time you build. And if you delete the signed jar, it won't generate again until you clean the native jar too.
You can share configuration closures between tasks. E.g.,
[ task1, task2 ].each { task ->
task.configure {
// shared closure
}
}
There are a few other best practices I'd follow.
Don't use new File() since it makes your script dependent on the current working directory.
Refer to outputs via the task versus recreating the full path (e.g., what you're doing with $releaseDir/NativeLibs.jar). Gradle is able to infer dependencies that way.
Use a custom task class vs an ad-hoc task with doFirst()/doLast(). Since you're delegating all the work to the ant task, this should be really simple.
I'm not sure why you need your particular file names, but I left them as-is. If they're not important, removing them would make this even simpler.
I took a stab at your example (disclaimer: I didn't try it):
task nativeJar( type: Jar ) {
baseName = 'NativeLibs'
from files(releaseDir + 'jar_merge/signedNativeLibs')
}
task native64Jar( type: Jar ) {
baseName = 'NativeLibs64'
from files(releaseDir + 'jar_merge/signedNativeLibs64')
}
[ nativeJar, native64Jar ].each { task ->
task.configure {
destinationDir = file(releaseDir)
manifest {
attributes 'Permissions' : 'all-permissions', 'Publisher' : 'Financial Engineering', 'Application-Name' : 'WorkBench', 'Codebase' : '*.fhlmc.com'
}
}
}
// this class definition should go at the top of your build.gradle script else it will through an exception mentioned in comments
class SignJarTask extends DefaultTask {
#InputFile File inputFile
#OutputFile File outputFile
#TaskAction
void signJar() {
ant.signjar( jar: inputFile, alias:"WorkBench", keystore: "WorkBench.jks", signedjar: outputFile, storepass: "freddie" )
}
}
task signJar(type: SignJarTask) {
inputFile = file("$releaseDir/NativeLibs.jar")
outputFile = file("$releaseDir/signedNativeLibs.jar")
}
task sign64Jar(type: SignJarTask) {
inputFile = file("$releaseDir/NativeLibs64.jar")
outputFile = file("$releaseDir/signedNativeLibs64.jar")
}