How to define SBT Release task in Build.scala? - sbt

I'm defining my build/release process in build.sbt. I also have a project/Build.scala that has some definitions which are used in build.sbt. Doing this to keep build.sbt readable.
I'm trying to add a few new tasks to the releaseProcess. I'm defining these tasks in Build.scala as
object StartService {
val myNewTask = taskKey[Unit]("Execute a CLI command")
myNewTask := {
streams.value.log.info(s"Executing command")
s"cmd $arg1 $arg2" !
}
}
build.sbt has
releaseProcess := Seq[ReleaseStep](
...
releaseStepTask(StartService.myNewTask)
...
)
When executing release command I keep getting an exception that myNewTask is undefined. What is the right way to import tasks defined in Build.scala?
java.lang.RuntimeException: /:myNewTask is undefined.
at scala.sys.package$.error(package.scala:27)
at sbt.Extracted$$anonfun$getOrError$1.apply(Extracted.scala:94)
at sbt.Extracted$$anonfun$getOrError$1.apply(Extracted.scala:94)
at scala.Option.getOrElse(Option.scala:120)

You need to add the task definition to your project. Just by being in an object, that doesn't happen. The simplest way is to add the setting directly into build.sbt.
To automatically add it to several projects, you could define it as a plugin in your project directory:
object SbtScaryPlugin extends AutoPlugin {
override def trigger = allRequirements
override def requires = JvmPlugin
object autoImport {
val myNewTask = taskKey[Unit]("Execute a CLI command")
}
import autoImport._
override lazy val projectSettings = Seq(
myNewTask := {
streams.value.log.info(s"Executing command")
s"cmd $arg1 $arg2" !
}
)
}

Related

Getting an error unresolved refrence in corda contract?

My use case is similar to that of IOU use case. While writing contract for that i am getting the following error.
> Task :contracts:compileKotlin FAILED
e: D:\Capstone_Tryout\contracts\src\main\kotlin\com\template\contracts\TradeContract.kt: (45, 34): Unresolved reference: signers
My code is are
package com.template.contracts
import com.template.states.TradeState
import net.corda.core.contracts.CommandData
import net.corda.core.contracts.Contract
import net.corda.core.contracts.requireSingleCommand
import net.corda.core.contracts.requireThat
import net.corda.core.transactions.LedgerTransaction
// ************
// * Contract *
// ************
class TradeContract :Contract {
companion object {
// Used to identify our contract when building a transaction.
const val ID = "com.template.contracts.TradeContract"
}
// A transaction is valid if the verify() function of the contract of all the transaction's input and output states
// does not throw an exception.
override fun verify(tx: LedgerTransaction) {
val command = tx.commands.requireSingleCommand<Commands>().value
when(command) {
is Commands.Issue -> requireThat {
"There should be no input state" using (tx.inputs.isEmpty())
"There should be one output state" using (tx.outputs.size == 1)
"The output state should be of type TradeState" using (tx.outputs.get(0).data is TradeState)
val outputState = tx.outputs.get(0).data as TradeState
"TradeId should be 10 character long" using (outputState.TradeId.length == 10)
val trade = tx.outputsOfType<TradeState>().single()
"All of the participants must be signers." using (command.signers.toSet() == trade.participants.map { it.owningKey }.toSet())
"A newly issued TradeState must have a positive amount." using (trade.Amount > 0)
"The FromParty and ToParty cannot have the same identity." using (trade.FromParty != trade.ToParty)
}
}
// Verification logic goes here.
}
// Used to indicate the transaction's intent.
interface Commands : CommandData {
class Issue : Commands
}
}
While the similar code is working in corda example.
val iou = tx.outputsOfType<IOUState>().single()
"Both Parties together only may sign Trade issue transaction." using
(command.signers.toSet() == iou.participants.map { it.owningKey }.toSet())
I am not able to figure out why i am getting this error.
Please confirm that you did the following:
Define the command inside your contract:
public interface Commands extends CommandData {
class Create implements Commands {}
}
Extract the command from the transaction inside your verify() method:
final CommandWithParties<Commands.Create> command =
requireSingleCommand(tx.getCommands(), Commands.Create.class);
Command wraps value and signers.
Value is the type of the command
Signers are the public keys of the required signers of the command.
The issue in the code above is :
val command = tx.commands.requireSingleCommand<Commands>().value
Replace the above with:
val command = tx.commands.requireSingleCommand<Commands>()

How to use the GlideApp generated api in the library module?

Building library module. And in the sample application which is using the library module it has
#GlideModule
class DPAppGlideModule : AppGlideModule() {
override fun isManifestParsingEnabled(): Boolean {
return false
}
}
and in the library module has:
#GlideModule
public final class LibGlideModule extends LibraryGlideModule {
}
and in the library module it is using the GlideApp the generated api
fun ImageView.loadImg(imageUrl: String) {
var requestOptions : RequestOptions = RequestOptions()
requestOptions.diskCacheStrategy(DiskCacheStrategy.ALL)
if (!TextUtils.isEmpty(imageUrl)) {
GlideApp.with(this.context)
.setDefaultRequestOptions(requestOptions)
.load(imageUrl)
.into(this)
}
}
But since this is the library module and cannot have decency on the application module, so it cannot compile
How to use the GlideApp generated api in the library module?
ref — https://bumptech.github.io/glide/doc/configuration.html
Just add
annotationProcessor com.github.bumptech.glide:compiler:4.8.0
dependency in your module gradle file. sync project then clean and rebuild it.
If your module using kotlin. change "annotationProcessor" to "kapt".
Be careful if you have others module dependency,make sure you use the right GlideApp Object. Maybe others module have it own GlideApp object

Unable to load CordaService

I have a CordaService that looks like this:
#CordaService
class MyService(private val services: AppServiceHub) : SingletonSerializeAsToken() {
private companion object {
private val log = loggerFor<MyService>()
init {
BraidCordaJacksonInit.init()
}
}
init {
println("***** MyService Initializing ****")
}
}
The service has been behaving fine for quite some time. For an unknown reason, it’s no longer being initialised by the runtime.
The node's logs show that the cordapp has been successfully identified and loaded:
I 12:13:58+0100 [main] Main.printBasicNodeInfo - Loaded CorDapps : my-cordapp-0.1, corda-core-3.1-corda {}
If I run the node using NodeDriver:
fun main(args: Array<String>) {
driver(DriverParameters(
isDebug = true,
waitForAllNodesToFinish = true,
startNodesInProcess = true) {
listOf(
startNode(providedName = CordaX500Name("PartyA", "London", "GB"))
).map { it.getOrThrow() }
}
}
... the corda service is correctly initialised:
***** MyService Initializing ****
[INFO ] 12:17:09,934 [driver-pool-thread-0] (AbstractNode.kt:487) internal.Node.installCordaService - Installed io.bluebank.MyService Corda service {}
Is there something specific I need to add to encourage the scanner to locate the class?
Thanks,
Fuzz
This was our fault. Someone had removed the cordapp from ./build.gradle deployNodes configuration!

Importing an external module in a global type definition file

I'm trying to write a definition file for meteor-files, which is a Meteor Atmosphere package that exposes a global class FilesCollection. The start of my definition, I think, should look like this:
declare class FilesCollection extends Mongo.Collection<any> {
constructor(config?: FilesCollectionConfig)
}
However, I'm not sure of the best way to reference Mongo.Collection. Here's an excerpt from the Meteor definition file:
declare module Mongo {
var Collection: CollectionStatic;
interface CollectionStatic {
new < T > (name: string, options ? : {
connection ? : Object;
idGeneration ? : string;
transform ? : Function;
}): Collection < T > ;
}
interface Collection < T > {
...
}
...
}
declare module "meteor/mongo" {
module Mongo {
var Collection: CollectionStatic;
interface CollectionStatic {
new < T > (name: string, options ? : {
connection ? : Object;
idGeneration ? : string;
transform ? : Function;
}): Collection < T > ;
}
interface Collection < T > {
...
}
...
}
}
So, when referencing Mongo.Collection elsewhere in my app, I start the file with import { Mongo } from 'meteor/mongo';. However, I'm not sure how to do the same within a definition file, as I can't add an import statement in a global definition.
If I add Meteor as a global dependency in typings.json, the above appears to work in my definitions repository typed-meteor-files. However, when I use typed-meteor-files in my app, the additional properties from Mongo.Collection aren't pulled in, and I get the error Cannot find Mongo on the imported definition file. I'm a little lost, and not sure what the right way to do this is. Thanks!

How can a default task be overridden from an AutoPlugin?

Let's say that I wan to override (replace) the default setting for the packageBin task. So I naively wrote an AutoPlugin like this:
object TestPlugin extends AutoPlugin {
override def trigger = allRequirements
override val projectSettings: Seq[Def.Setting[_]] = Seq(
packageBin in Compile <<= (packageBin in Compile).map { a =>
println("project/compile::packageBin")
a
}
)
}
But this does not work (at least not with SBT 0.13.5 and 0.13.6-M1), my version of packageBin gets never called. If I put the the following line in my project's build.sbt file, then it works.
packageBin in Compile <<= (packageBin in Compile).map { a => println("project/compile::packageBin"); a }
Is it possible at all to achieve this from an AutoPlugin or a classical plugin, and if so how?
I found the solution to the problem here.
In order to make sure that the settings of the AutoPlugin are not overwritten by the default settings, the settings from the AutoPlugin must be applied after the default settings. The default settings are set by the AutoPlugins in package sbt.plugins (CorePlugin, IvyPlugin, JvmPlugin).
So all I had to do, is to make my AutoPlugin dependent on the JvmPlugin by adding the following override to my AutoPlugin:
override def requires: Plugins = JvmPlugin
The complete autoplugin with the overriden packageBin is as follows:
import sbt._
import Keys._
import plugins.JvmPlugin
object TestPlugin extends AutoPlugin {
override def requires = JvmPlugin
override def trigger = allRequirements
override val projectSettings: Seq[Def.Setting[_]] = Seq(
packageBin in Compile <<= (packageBin in Compile).map { a =>
println("project/compile::packageBin")
a
}
)
}
Just to complete the answer from #user1752169, here's a shorter (not necessarily simpler to comprehend) solution with the to-be-forgotten operator ~=:
import sbt._
import Keys._
import plugins.JvmPlugin
object TestPlugin extends AutoPlugin {
override def requires = JvmPlugin
override def trigger = allRequirements
override val projectSettings: Seq[Def.Setting[_]] = Seq(
packageBin in Compile ~= { a =>
println("project/compile::packageBin")
a
}
)
}
Or to have a side-effecting post-processing with andFinally:
import sbt._
import Keys._
import plugins.JvmPlugin
object TestPlugin extends AutoPlugin {
override def requires = JvmPlugin
override def trigger = allRequirements
override val projectSettings: Seq[Def.Setting[_]] = Seq(
packageBin in Compile <<= (packageBin in Compile) andFinally {
println("project/compile::packageBin")
}
)
}
As a nice addition, one may save the autoplugin code to project/src/main/scala in any project and gets the plugin activated without much work (and constantly updated when changed).

Resources