@Stephen and @stefanobaghino-da pointed me to the DAML LF API Type Signature package.
I want to use the package from Scala 3, so I added the package as a dependency like this:
libraryDependencies += ("com.daml" %% "daml-lf-api-type-signature" % "2.6.3").cross(CrossVersion.for3Use2_13)
I can import every component from the package, but I couldn’t figure out how to read the type signatures.
My guess is that the entry point may be the SignatureReaderMain
object:
package com.daml.lf.typesig.reader
import java.io.BufferedInputStream
import java.nio.file.Files
import com.daml.daml_lf_dev.DamlLf
object SignatureReaderMain extends App {
val lfFile = new java.io.File(args.apply(0))
val is = Files.newInputStream(lfFile.toPath)
try {
val bis = new BufferedInputStream(is)
val archive = DamlLf.Archive.parser().parseFrom(bis)
val out = SignatureReader.readPackageSignature(archive)
println(s"out: $out")
} finally {
is.close()
}
}
The problem seems to be that the command line functionality of the App class is not available in Scala 3: " The previous functionality of App
, which relied on the “magic” DelayedInit
trait, is no longer available. App
still exists in limited form for now, but it doesn’t support command line arguments and will be deprecated in the future." (See the “Backwards Compatibility with Scala 2” on this page.)
The real reason of me being stuck is, of course, that I am a very beginner wannabe Scala user, so I would be grateful for any guidance on this.
You may want to have a look here.
As a further note, you might want to also use Using
to safely consume resources.
1 Like
I don’t know if using Using would help, but if I try to run this with the compiled dar of the skeleton project:
package main
import java.io.BufferedInputStream
import java.nio.file.Files
import com.daml.daml_lf_dev.DamlLf
import com.daml.lf.typesig.reader.SignatureReader
import com.daml.lf.typesig.reader.SignatureReaderMain.args
object readTypeSignatures {
private def readTypeSignatures(path: String) = {
val lfFile = new java.io.File(path)
val is = Files.newInputStream(lfFile.toPath)
try {
val bis = new BufferedInputStream(is)
val archive = DamlLf.Archive.parser().parseFrom(bis)
val out = SignatureReader.readPackageSignature(archive)
println(s"out: $out")
} finally {
is.close()
}
}
def main(args: Array[String]): Unit =
readTypeSignatures(args(0))
}
I get the following error:
[IJ]run "/Users/gyorgybalazsi/_tmp/signature-reader-daml/.daml/dist/signature-reader-daml-0.0.1.dar"
[info] compiling 1 Scala source to /Users/gyorgybalazsi/_tmp/signature-reader-test/target/scala-3.3.0/classes ...
[info] done compiling
[info] running main.readTypeSignatures /Users/gyorgybalazsi/_tmp/signature-reader-daml/.daml/dist/signature-reader-daml-0.0.1.dar
[error] com.google.protobuf.InvalidProtocolBufferException: Protocol message contained an invalid tag (zero).
[error] at com.google.protobuf.InvalidProtocolBufferException.invalidTag(InvalidProtocolBufferException.java:125)
[error] at com.google.protobuf.CodedInputStream$StreamDecoder.readTag(CodedInputStream.java:2116)
[error] at com.daml.daml_lf_dev.DamlLf$Archive$Builder.mergeFrom(DamlLf.java:1538)
[error] at com.daml.daml_lf_dev.DamlLf$Archive$1.parsePartialFrom(DamlLf.java:1857)
[error] at com.daml.daml_lf_dev.DamlLf$Archive$1.parsePartialFrom(DamlLf.java:1849)
[error] at com.google.protobuf.AbstractParser.parsePartialFrom(AbstractParser.java:215)
[error] at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:232)
[error] at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:237)
[error] at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:48)
[error] at main.readTypeSignatures$.readTypeSignatures(Main.scala:15)
[error] at main.readTypeSignatures$.main(Main.scala:23)
[error] at main.readTypeSignatures.main(Main.scala)
[error] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[error] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
[error] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error] at java.base/java.lang.reflect.Method.invoke(Method.java:568)
[error] stack trace is suppressed; run last Compile / run for the full output
[error] (Compile / run) com.google.protobuf.InvalidProtocolBufferException: Protocol message contained an invalid tag (zero).
[error] Total time: 1 s, completed May 25, 2023, 2:07:20 PM
[IJ]
The library works on individual Daml-LF files, not DARs. You are probably aware of this, but as a reference for other readers, the DAR is (just like a JAR) a zipped archive. You need to unzip that file and feed the library with the Daml-LF files stored therein. IIRC the DAR also includes a manifest under the META-INF
directory listing the Daml-LF files in the archive.
1 Like
Thank you, Stefano, in this way it prints out as expected:
out: (Errors(\/-(Tip)),PackageSignature(c3c5461898d9ab637071f8b2c7f1007306753a5afe7ed0df444c902171aca199,Some(PackageMetadata(signature-reader-daml,0.0.1)),Map(Main:Give -> Normal(DefDataType(IndexedSeq(),Record(IndexedSeq((newOwner,TypePrim(PrimTypeParty,IndexedSeq())))))), Main:Asset -> Template(Record(IndexedSeq((issuer,TypePrim(PrimTypeParty,IndexedSeq())), (owner,TypePrim(PrimTypeParty,IndexedSeq())), (name,TypePrim(PrimTypeText,IndexedSeq())))),DefTemplate(Resolved(Map(Archive -> Map(None -> TemplateChoice(TypeCon(TypeConName(d14e08374fc7197d6a0de468c968ae8ba3aadbf9315476fd39071831f5923662:DA.Internal.Template:Archive),IndexedSeq()),true,TypePrim(PrimTypeUnit,IndexedSeq()))), Give -> Map(None -> TemplateChoice(TypeCon(TypeConName(c3c5461898d9ab637071f8b2c7f1007306753a5afe7ed0df444c902171aca199:Main:Give),IndexedSeq()),true,TypePrim(PrimTypeContractId,IndexedSeq(TypeCon(TypeConName(c3c5461898d9ab637071f8b2c7f1007306753a5afe7ed0df444c902171aca199:Main:Asset),IndexedSeq()))))))),None,Vector()))),Map()))
1 Like
Since it’s an internal library, the best way to figure out how to use it is to grab the digital-asset/daml
repo and see how it’s used there. You probably know that the Java and Scala codegens do work on dars, and these are both based on api-type-signature; if you look into the source code for these codegens, you can figure out how they handle dars.
The "a real dar"
tests in SignatureReaderSpec
also demonstrate how to interact with a whole dar, albeit with somewhat elided error handling.
You should look into these source files anyway because, as an internal library, you will not find documentation about how to work with api-type-signature correctly; the easiest way to discover details you might be missing (like what the heck all this resolve*
stuff is) is to see what its clients in the daml
repo do with it.
1 Like
Thank you, Stephen, I will check these out.