[2.x] perf: Memoize the artifact content hash in LibraryManagementCodec (#9563)

**Problem**
Serializing an UpdateReport re-reads every artifact through sjson-new's
File iso to recompute its sha256, so every ActionCache key computation
and Tracked write-back re-reads the whole dependency classpath on every
invocation, including no-ops.

**Solution**
Override the iso with a hash memoized by (path, size, lastModified),
with the same invalidation semantics as the digest cache in sbt/sbt#8363,
and mix it into the generated codec via contrabandCodecParents.

Generated-by: Claude Fable 5
This commit is contained in:
tanaka takaya 2026-08-07 09:46:13 +09:00 committed by GitHub
parent b0c840105b
commit 1038618246
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
52 changed files with 259 additions and 48 deletions

View File

@ -1236,6 +1236,7 @@ lazy val lmCore = (project in file("lm-core"))
lmTestSettings,
name := "librarymanagement-core",
contrabandSjsonNewVersion := sjsonNewVersion,
Compile / generateContrabands / contrabandCodecParents += "sbt.librarymanagement.MemoizedFileFormats",
libraryDependencies ++= Seq(
jsch,
// scalaReflect,

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait ArtifactFormats { self: sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol =>
trait ArtifactFormats { self: sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given ArtifactFormat: JsonFormat[sbt.librarymanagement.Artifact] = new JsonFormat[sbt.librarymanagement.Artifact] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.Artifact = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait ArtifactTypeFilterFormats { self: sjsonnew.BasicJsonProtocol =>
trait ArtifactTypeFilterFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given ArtifactTypeFilterFormat: JsonFormat[sbt.librarymanagement.ArtifactTypeFilter] = new JsonFormat[sbt.librarymanagement.ArtifactTypeFilter] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.ArtifactTypeFilter = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait CallerFormats { self: sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats =>
trait CallerFormats { self: sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats =>
given CallerFormat: JsonFormat[sbt.librarymanagement.Caller] = new JsonFormat[sbt.librarymanagement.Caller] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.Caller = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait ChainedResolverFormats { self: sbt.librarymanagement.ResolverFormats & sjsonnew.BasicJsonProtocol =>
trait ChainedResolverFormats { self: sbt.librarymanagement.ResolverFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given ChainedResolverFormat: JsonFormat[sbt.librarymanagement.ChainedResolver] = new JsonFormat[sbt.librarymanagement.ChainedResolver] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.ChainedResolver = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait ChecksumFormats { self: sjsonnew.BasicJsonProtocol =>
trait ChecksumFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given ChecksumFormat: JsonFormat[sbt.librarymanagement.Checksum] = new JsonFormat[sbt.librarymanagement.Checksum] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.Checksum = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait ConfigurationReportFormats { self: sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ModuleReportFormats & sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.CallerFormats & sbt.librarymanagement.OrganizationArtifactReportFormats =>
trait ConfigurationReportFormats { self: sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ModuleReportFormats & sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.CallerFormats & sbt.librarymanagement.OrganizationArtifactReportFormats =>
given ConfigurationReportFormat: JsonFormat[sbt.librarymanagement.ConfigurationReport] = new JsonFormat[sbt.librarymanagement.ConfigurationReport] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.ConfigurationReport = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait ConfigurationReportLiteFormats { self: sbt.librarymanagement.OrganizationArtifactReportFormats & sbt.librarymanagement.ModuleReportFormats & sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.CallerFormats =>
trait ConfigurationReportLiteFormats { self: sbt.librarymanagement.OrganizationArtifactReportFormats & sbt.librarymanagement.ModuleReportFormats & sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.CallerFormats =>
given ConfigurationReportLiteFormat: JsonFormat[sbt.internal.librarymanagement.ConfigurationReportLite] = new JsonFormat[sbt.internal.librarymanagement.ConfigurationReportLite] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.librarymanagement.ConfigurationReportLite = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait ConflictManagerFormats { self: sjsonnew.BasicJsonProtocol =>
trait ConflictManagerFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given ConflictManagerFormat: JsonFormat[sbt.librarymanagement.ConflictManager] = new JsonFormat[sbt.librarymanagement.ConflictManager] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.ConflictManager = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait DeveloperFormats { self: sjsonnew.BasicJsonProtocol =>
trait DeveloperFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given DeveloperFormat: JsonFormat[sbt.librarymanagement.Developer] = new JsonFormat[sbt.librarymanagement.Developer] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.Developer = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait FileConfigurationFormats { self: sjsonnew.BasicJsonProtocol =>
trait FileConfigurationFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given FileConfigurationFormat: JsonFormat[sbt.librarymanagement.FileConfiguration] = new JsonFormat[sbt.librarymanagement.FileConfiguration] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.FileConfiguration = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait FileRepositoryFormats { self: sbt.librarymanagement.PatternsFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.FileConfigurationFormats =>
trait FileRepositoryFormats { self: sbt.librarymanagement.PatternsFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.FileConfigurationFormats =>
given FileRepositoryFormat: JsonFormat[sbt.librarymanagement.FileRepository] = new JsonFormat[sbt.librarymanagement.FileRepository] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.FileRepository = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait GetClassifiersConfigurationFormats { self: sbt.librarymanagement.GetClassifiersModuleFormats & sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.ScalaModuleInfoFormats & sbt.librarymanagement.ConfigurationFormats & sbt.librarymanagement.UpdateConfigurationFormats & sbt.librarymanagement.RetrieveConfigurationFormats & sbt.librarymanagement.UpdateLoggingFormats & sbt.internal.librarymanagement.formats.LogicalClockFormats & sbt.librarymanagement.ArtifactTypeFilterFormats =>
trait GetClassifiersConfigurationFormats { self: sbt.librarymanagement.GetClassifiersModuleFormats & sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.ScalaModuleInfoFormats & sbt.librarymanagement.ConfigurationFormats & sbt.librarymanagement.UpdateConfigurationFormats & sbt.librarymanagement.RetrieveConfigurationFormats & sbt.librarymanagement.UpdateLoggingFormats & sbt.internal.librarymanagement.formats.LogicalClockFormats & sbt.librarymanagement.ArtifactTypeFilterFormats =>
given GetClassifiersConfigurationFormat: JsonFormat[sbt.librarymanagement.GetClassifiersConfiguration] = new JsonFormat[sbt.librarymanagement.GetClassifiersConfiguration] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.GetClassifiersConfiguration = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait GetClassifiersModuleFormats { self: sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.ScalaModuleInfoFormats & sbt.librarymanagement.ConfigurationFormats =>
trait GetClassifiersModuleFormats { self: sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.ScalaModuleInfoFormats & sbt.librarymanagement.ConfigurationFormats =>
given GetClassifiersModuleFormat: JsonFormat[sbt.librarymanagement.GetClassifiersModule] = new JsonFormat[sbt.librarymanagement.GetClassifiersModule] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.GetClassifiersModule = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait InclExclRuleFormats { self: sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sjsonnew.BasicJsonProtocol =>
trait InclExclRuleFormats { self: sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given InclExclRuleFormat: JsonFormat[sbt.librarymanagement.InclExclRule] = new JsonFormat[sbt.librarymanagement.InclExclRule] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.InclExclRule = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait IvyFileConfigurationFormats { self: sbt.librarymanagement.ScalaModuleInfoFormats & sbt.librarymanagement.ConfigurationFormats & sjsonnew.BasicJsonProtocol =>
trait IvyFileConfigurationFormats { self: sbt.librarymanagement.ScalaModuleInfoFormats & sbt.librarymanagement.ConfigurationFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given IvyFileConfigurationFormat: JsonFormat[sbt.librarymanagement.IvyFileConfiguration] = new JsonFormat[sbt.librarymanagement.IvyFileConfiguration] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.IvyFileConfiguration = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait IvyPathsFormats { self: sjsonnew.BasicJsonProtocol =>
trait IvyPathsFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given IvyPathsFormat: JsonFormat[sbt.librarymanagement.IvyPaths] = new JsonFormat[sbt.librarymanagement.IvyPaths] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.IvyPaths = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait KeyFileAuthenticationFormats { self: sjsonnew.BasicJsonProtocol =>
trait KeyFileAuthenticationFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given KeyFileAuthenticationFormat: JsonFormat[sbt.librarymanagement.KeyFileAuthentication] = new JsonFormat[sbt.librarymanagement.KeyFileAuthentication] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.KeyFileAuthentication = {
__jsOpt match {

View File

@ -6,6 +6,7 @@
package sbt.librarymanagement
trait LibraryManagementCodec extends sbt.librarymanagement.ConfigRefFormats
with sjsonnew.BasicJsonProtocol
with sbt.librarymanagement.MemoizedFileFormats
with sbt.librarymanagement.RetrieveConfigurationFormats
with sbt.librarymanagement.UpdateLoggingFormats
with sbt.internal.librarymanagement.formats.LogicalClockFormats

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait LicenseFormats { self: sjsonnew.BasicJsonProtocol =>
trait LicenseFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given LicenseFormat: JsonFormat[sbt.librarymanagement.License] = new JsonFormat[sbt.librarymanagement.License] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.License = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait MavenCacheFormats { self: sjsonnew.BasicJsonProtocol =>
trait MavenCacheFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given MavenCacheFormat: JsonFormat[sbt.librarymanagement.MavenCache] = new JsonFormat[sbt.librarymanagement.MavenCache] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.MavenCache = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait MavenRepoFormats { self: sjsonnew.BasicJsonProtocol =>
trait MavenRepoFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given MavenRepoFormat: JsonFormat[sbt.librarymanagement.MavenRepo] = new JsonFormat[sbt.librarymanagement.MavenRepo] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.MavenRepo = {
__jsOpt match {

View File

@ -6,6 +6,6 @@
package sbt.librarymanagement
import _root_.sjsonnew.JsonFormat
trait MavenRepositoryFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MavenRepoFormats & sbt.librarymanagement.MavenCacheFormats =>
trait MavenRepositoryFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.MavenRepoFormats & sbt.librarymanagement.MavenCacheFormats =>
given MavenRepositoryFormat: JsonFormat[sbt.librarymanagement.MavenRepository] = flatUnionFormat2[sbt.librarymanagement.MavenRepository, sbt.librarymanagement.MavenRepo, sbt.librarymanagement.MavenCache]("type")
}

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait ModuleConfigurationFormats { self: sbt.librarymanagement.ResolverFormats & sjsonnew.BasicJsonProtocol =>
trait ModuleConfigurationFormats { self: sbt.librarymanagement.ResolverFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given ModuleConfigurationFormat: JsonFormat[sbt.librarymanagement.ModuleConfiguration] = new JsonFormat[sbt.librarymanagement.ModuleConfiguration] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.ModuleConfiguration = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait ModuleDescriptorConfigurationFormats { self: sbt.librarymanagement.ScalaModuleInfoFormats & sbt.librarymanagement.ConfigurationFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.ModuleInfoFormats & sbt.librarymanagement.LicenseFormats & sbt.librarymanagement.ScmInfoFormats & sbt.librarymanagement.DeveloperFormats & sbt.internal.librarymanagement.formats.NodeSeqFormat & sbt.librarymanagement.ConflictManagerFormats =>
trait ModuleDescriptorConfigurationFormats { self: sbt.librarymanagement.ScalaModuleInfoFormats & sbt.librarymanagement.ConfigurationFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.ModuleInfoFormats & sbt.librarymanagement.LicenseFormats & sbt.librarymanagement.ScmInfoFormats & sbt.librarymanagement.DeveloperFormats & sbt.internal.librarymanagement.formats.NodeSeqFormat & sbt.librarymanagement.ConflictManagerFormats =>
given ModuleDescriptorConfigurationFormat: JsonFormat[sbt.librarymanagement.ModuleDescriptorConfiguration] = new JsonFormat[sbt.librarymanagement.ModuleDescriptorConfiguration] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.ModuleDescriptorConfiguration = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait ModuleIDFormats { self: sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats =>
trait ModuleIDFormats { self: sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats =>
given ModuleIDFormat: JsonFormat[sbt.librarymanagement.ModuleID] = new JsonFormat[sbt.librarymanagement.ModuleID] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.ModuleID = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait ModuleInfoFormats { self: sbt.librarymanagement.LicenseFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.ScmInfoFormats & sbt.librarymanagement.DeveloperFormats =>
trait ModuleInfoFormats { self: sbt.librarymanagement.LicenseFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.ScmInfoFormats & sbt.librarymanagement.DeveloperFormats =>
given ModuleInfoFormat: JsonFormat[sbt.librarymanagement.ModuleInfo] = new JsonFormat[sbt.librarymanagement.ModuleInfo] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.ModuleInfo = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait ModuleReportFormats { self: sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.CallerFormats =>
trait ModuleReportFormats { self: sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.CallerFormats =>
given ModuleReportFormat: JsonFormat[sbt.librarymanagement.ModuleReport] = new JsonFormat[sbt.librarymanagement.ModuleReport] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.ModuleReport = {
__jsOpt match {

View File

@ -6,6 +6,6 @@
package sbt.librarymanagement
import _root_.sjsonnew.JsonFormat
trait ModuleSettingsFormats { self: sbt.librarymanagement.ScalaModuleInfoFormats & sbt.librarymanagement.ConfigurationFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.IvyFileConfigurationFormats & sbt.librarymanagement.PomConfigurationFormats & sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.ModuleInfoFormats & sbt.librarymanagement.LicenseFormats & sbt.librarymanagement.ScmInfoFormats & sbt.librarymanagement.DeveloperFormats & sbt.internal.librarymanagement.formats.NodeSeqFormat & sbt.librarymanagement.ConflictManagerFormats & sbt.librarymanagement.ModuleDescriptorConfigurationFormats =>
trait ModuleSettingsFormats { self: sbt.librarymanagement.ScalaModuleInfoFormats & sbt.librarymanagement.ConfigurationFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.IvyFileConfigurationFormats & sbt.librarymanagement.PomConfigurationFormats & sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.ModuleInfoFormats & sbt.librarymanagement.LicenseFormats & sbt.librarymanagement.ScmInfoFormats & sbt.librarymanagement.DeveloperFormats & sbt.internal.librarymanagement.formats.NodeSeqFormat & sbt.librarymanagement.ConflictManagerFormats & sbt.librarymanagement.ModuleDescriptorConfigurationFormats =>
given ModuleSettingsFormat: JsonFormat[sbt.librarymanagement.ModuleSettings] = flatUnionFormat3[sbt.librarymanagement.ModuleSettings, sbt.librarymanagement.IvyFileConfiguration, sbt.librarymanagement.PomConfiguration, sbt.librarymanagement.ModuleDescriptorConfiguration]("type")
}

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait OrganizationArtifactReportFormats { self: sbt.librarymanagement.ModuleReportFormats & sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.CallerFormats =>
trait OrganizationArtifactReportFormats { self: sbt.librarymanagement.ModuleReportFormats & sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.CallerFormats =>
given OrganizationArtifactReportFormat: JsonFormat[sbt.librarymanagement.OrganizationArtifactReport] = new JsonFormat[sbt.librarymanagement.OrganizationArtifactReport] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.OrganizationArtifactReport = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait PasswordAuthenticationFormats { self: sjsonnew.BasicJsonProtocol =>
trait PasswordAuthenticationFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given PasswordAuthenticationFormat: JsonFormat[sbt.librarymanagement.PasswordAuthentication] = new JsonFormat[sbt.librarymanagement.PasswordAuthentication] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.PasswordAuthentication = {
__jsOpt match {

View File

@ -6,6 +6,6 @@
package sbt.librarymanagement
import _root_.sjsonnew.JsonFormat
trait PatternsBasedRepositoryFormats { self: sbt.librarymanagement.PatternsFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.FileConfigurationFormats & sbt.librarymanagement.FileRepositoryFormats & sbt.librarymanagement.URLRepositoryFormats & sbt.librarymanagement.SshConnectionFormats & sbt.librarymanagement.SshAuthenticationFormats & sbt.librarymanagement.SshRepositoryFormats & sbt.librarymanagement.SftpRepositoryFormats =>
trait PatternsBasedRepositoryFormats { self: sbt.librarymanagement.PatternsFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.FileConfigurationFormats & sbt.librarymanagement.FileRepositoryFormats & sbt.librarymanagement.URLRepositoryFormats & sbt.librarymanagement.SshConnectionFormats & sbt.librarymanagement.SshAuthenticationFormats & sbt.librarymanagement.SshRepositoryFormats & sbt.librarymanagement.SftpRepositoryFormats =>
given PatternsBasedRepositoryFormat: JsonFormat[sbt.librarymanagement.PatternsBasedRepository] = flatUnionFormat4[sbt.librarymanagement.PatternsBasedRepository, sbt.librarymanagement.FileRepository, sbt.librarymanagement.URLRepository, sbt.librarymanagement.SshRepository, sbt.librarymanagement.SftpRepository]("type")
}

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait PatternsFormats { self: sjsonnew.BasicJsonProtocol =>
trait PatternsFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given PatternsFormat: JsonFormat[sbt.librarymanagement.Patterns] = new JsonFormat[sbt.librarymanagement.Patterns] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.Patterns = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait PomConfigurationFormats { self: sbt.librarymanagement.ScalaModuleInfoFormats & sbt.librarymanagement.ConfigurationFormats & sjsonnew.BasicJsonProtocol =>
trait PomConfigurationFormats { self: sbt.librarymanagement.ScalaModuleInfoFormats & sbt.librarymanagement.ConfigurationFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given PomConfigurationFormat: JsonFormat[sbt.librarymanagement.PomConfiguration] = new JsonFormat[sbt.librarymanagement.PomConfiguration] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.PomConfiguration = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait PublishConfigurationFormats { self: sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.UpdateLoggingFormats & sjsonnew.BasicJsonProtocol =>
trait PublishConfigurationFormats { self: sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.UpdateLoggingFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given PublishConfigurationFormat: JsonFormat[sbt.librarymanagement.PublishConfiguration] = new JsonFormat[sbt.librarymanagement.PublishConfiguration] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.PublishConfiguration = {
__jsOpt match {

View File

@ -6,6 +6,6 @@
package sbt.librarymanagement
import _root_.sjsonnew.JsonFormat
trait ResolverFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.ChainedResolverFormats & sbt.librarymanagement.MavenRepoFormats & sbt.librarymanagement.MavenCacheFormats & sbt.librarymanagement.PatternsFormats & sbt.librarymanagement.FileConfigurationFormats & sbt.librarymanagement.FileRepositoryFormats & sbt.librarymanagement.URLRepositoryFormats & sbt.librarymanagement.SshConnectionFormats & sbt.librarymanagement.SshAuthenticationFormats & sbt.librarymanagement.SshRepositoryFormats & sbt.librarymanagement.SftpRepositoryFormats =>
trait ResolverFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.ChainedResolverFormats & sbt.librarymanagement.MavenRepoFormats & sbt.librarymanagement.MavenCacheFormats & sbt.librarymanagement.PatternsFormats & sbt.librarymanagement.FileConfigurationFormats & sbt.librarymanagement.FileRepositoryFormats & sbt.librarymanagement.URLRepositoryFormats & sbt.librarymanagement.SshConnectionFormats & sbt.librarymanagement.SshAuthenticationFormats & sbt.librarymanagement.SshRepositoryFormats & sbt.librarymanagement.SftpRepositoryFormats =>
given ResolverFormat: JsonFormat[sbt.librarymanagement.Resolver] = flatUnionFormat7[sbt.librarymanagement.Resolver, sbt.librarymanagement.ChainedResolver, sbt.librarymanagement.MavenRepo, sbt.librarymanagement.MavenCache, sbt.librarymanagement.FileRepository, sbt.librarymanagement.URLRepository, sbt.librarymanagement.SshRepository, sbt.librarymanagement.SftpRepository]("type")
}

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait RetrieveConfigurationFormats { self: sbt.librarymanagement.ConfigRefFormats & sjsonnew.BasicJsonProtocol =>
trait RetrieveConfigurationFormats { self: sbt.librarymanagement.ConfigRefFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given RetrieveConfigurationFormat: JsonFormat[sbt.librarymanagement.RetrieveConfiguration] = new JsonFormat[sbt.librarymanagement.RetrieveConfiguration] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.RetrieveConfiguration = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait ScalaModuleInfoFormats { self: sbt.librarymanagement.ConfigurationFormats & sjsonnew.BasicJsonProtocol =>
trait ScalaModuleInfoFormats { self: sbt.librarymanagement.ConfigurationFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given ScalaModuleInfoFormat: JsonFormat[sbt.librarymanagement.ScalaModuleInfo] = new JsonFormat[sbt.librarymanagement.ScalaModuleInfo] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.ScalaModuleInfo = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait ScmInfoFormats { self: sjsonnew.BasicJsonProtocol =>
trait ScmInfoFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given ScmInfoFormat: JsonFormat[sbt.librarymanagement.ScmInfo] = new JsonFormat[sbt.librarymanagement.ScmInfo] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.ScmInfo = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait SftpRepositoryFormats { self: sbt.librarymanagement.PatternsFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.SshConnectionFormats & sbt.librarymanagement.SshAuthenticationFormats =>
trait SftpRepositoryFormats { self: sbt.librarymanagement.PatternsFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.SshConnectionFormats & sbt.librarymanagement.SshAuthenticationFormats =>
given SftpRepositoryFormat: JsonFormat[sbt.librarymanagement.SftpRepository] = new JsonFormat[sbt.librarymanagement.SftpRepository] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.SftpRepository = {
__jsOpt match {

View File

@ -6,6 +6,6 @@
package sbt.librarymanagement
import _root_.sjsonnew.JsonFormat
trait SshAuthenticationFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.PasswordAuthenticationFormats & sbt.librarymanagement.KeyFileAuthenticationFormats =>
trait SshAuthenticationFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.PasswordAuthenticationFormats & sbt.librarymanagement.KeyFileAuthenticationFormats =>
given SshAuthenticationFormat: JsonFormat[sbt.librarymanagement.SshAuthentication] = flatUnionFormat2[sbt.librarymanagement.SshAuthentication, sbt.librarymanagement.PasswordAuthentication, sbt.librarymanagement.KeyFileAuthentication]("type")
}

View File

@ -6,6 +6,6 @@
package sbt.librarymanagement
import _root_.sjsonnew.JsonFormat
trait SshBasedRepositoryFormats { self: sbt.librarymanagement.PatternsFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.SshConnectionFormats & sbt.librarymanagement.SshAuthenticationFormats & sbt.librarymanagement.SshRepositoryFormats & sbt.librarymanagement.SftpRepositoryFormats =>
trait SshBasedRepositoryFormats { self: sbt.librarymanagement.PatternsFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.SshConnectionFormats & sbt.librarymanagement.SshAuthenticationFormats & sbt.librarymanagement.SshRepositoryFormats & sbt.librarymanagement.SftpRepositoryFormats =>
given SshBasedRepositoryFormat: JsonFormat[sbt.librarymanagement.SshBasedRepository] = flatUnionFormat2[sbt.librarymanagement.SshBasedRepository, sbt.librarymanagement.SshRepository, sbt.librarymanagement.SftpRepository]("type")
}

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait SshConnectionFormats { self: sbt.librarymanagement.SshAuthenticationFormats & sjsonnew.BasicJsonProtocol =>
trait SshConnectionFormats { self: sbt.librarymanagement.SshAuthenticationFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given SshConnectionFormat: JsonFormat[sbt.librarymanagement.SshConnection] = new JsonFormat[sbt.librarymanagement.SshConnection] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.SshConnection = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait SshRepositoryFormats { self: sbt.librarymanagement.PatternsFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.SshConnectionFormats & sbt.librarymanagement.SshAuthenticationFormats =>
trait SshRepositoryFormats { self: sbt.librarymanagement.PatternsFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.SshConnectionFormats & sbt.librarymanagement.SshAuthenticationFormats =>
given SshRepositoryFormat: JsonFormat[sbt.librarymanagement.SshRepository] = new JsonFormat[sbt.librarymanagement.SshRepository] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.SshRepository = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait URLRepositoryFormats { self: sbt.librarymanagement.PatternsFormats & sjsonnew.BasicJsonProtocol =>
trait URLRepositoryFormats { self: sbt.librarymanagement.PatternsFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given URLRepositoryFormat: JsonFormat[sbt.librarymanagement.URLRepository] = new JsonFormat[sbt.librarymanagement.URLRepository] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.URLRepository = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait UpdateConfigurationFormats { self: sbt.librarymanagement.RetrieveConfigurationFormats & sbt.librarymanagement.ConfigRefFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.UpdateLoggingFormats & sbt.internal.librarymanagement.formats.LogicalClockFormats & sbt.librarymanagement.ArtifactTypeFilterFormats =>
trait UpdateConfigurationFormats { self: sbt.librarymanagement.RetrieveConfigurationFormats & sbt.librarymanagement.ConfigRefFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.UpdateLoggingFormats & sbt.internal.librarymanagement.formats.LogicalClockFormats & sbt.librarymanagement.ArtifactTypeFilterFormats =>
given UpdateConfigurationFormat: JsonFormat[sbt.librarymanagement.UpdateConfiguration] = new JsonFormat[sbt.librarymanagement.UpdateConfiguration] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.UpdateConfiguration = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait UpdateLoggingFormats { self: sjsonnew.BasicJsonProtocol =>
trait UpdateLoggingFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given UpdateLoggingFormat: JsonFormat[sbt.librarymanagement.UpdateLogging] = new JsonFormat[sbt.librarymanagement.UpdateLogging] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.UpdateLogging = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait UpdateReportFormats { self: sbt.librarymanagement.ConfigurationReportFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ModuleReportFormats & sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.CallerFormats & sbt.librarymanagement.OrganizationArtifactReportFormats & sbt.librarymanagement.UpdateStatsFormats =>
trait UpdateReportFormats { self: sbt.librarymanagement.ConfigurationReportFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ModuleReportFormats & sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.CallerFormats & sbt.librarymanagement.OrganizationArtifactReportFormats & sbt.librarymanagement.UpdateStatsFormats =>
given UpdateReportFormat: JsonFormat[sbt.librarymanagement.UpdateReport] = new JsonFormat[sbt.librarymanagement.UpdateReport] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.UpdateReport = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait UpdateReportLiteFormats { self: sbt.librarymanagement.ConfigurationReportLiteFormats & sbt.librarymanagement.OrganizationArtifactReportFormats & sbt.librarymanagement.ModuleReportFormats & sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.CallerFormats =>
trait UpdateReportLiteFormats { self: sbt.librarymanagement.ConfigurationReportLiteFormats & sbt.librarymanagement.OrganizationArtifactReportFormats & sbt.librarymanagement.ModuleReportFormats & sbt.librarymanagement.ModuleIDFormats & sbt.librarymanagement.ArtifactFormats & sbt.librarymanagement.ConfigRefFormats & sbt.librarymanagement.ChecksumFormats & sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats & sbt.librarymanagement.InclExclRuleFormats & sbt.librarymanagement.CrossVersionFormats & sbt.librarymanagement.DisabledFormats & sbt.librarymanagement.BinaryFormats & sbt.librarymanagement.ConstantFormats & sbt.librarymanagement.PatchFormats & sbt.librarymanagement.FullFormats & sbt.librarymanagement.For3Use2_13Formats & sbt.librarymanagement.For2_13Use3Formats & sbt.librarymanagement.CallerFormats =>
given UpdateReportLiteFormat: JsonFormat[sbt.internal.librarymanagement.UpdateReportLite] = new JsonFormat[sbt.internal.librarymanagement.UpdateReportLite] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.librarymanagement.UpdateReportLite = {
__jsOpt match {

View File

@ -5,7 +5,7 @@
// DO NOT EDIT MANUALLY
package sbt.librarymanagement
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait UpdateStatsFormats { self: sjsonnew.BasicJsonProtocol =>
trait UpdateStatsFormats { self: sjsonnew.BasicJsonProtocol & sbt.librarymanagement.MemoizedFileFormats =>
given UpdateStatsFormat: JsonFormat[sbt.librarymanagement.UpdateStats] = new JsonFormat[sbt.librarymanagement.UpdateStats] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.UpdateStats = {
__jsOpt match {

View File

@ -0,0 +1,76 @@
/*
* sbt
* Copyright 2023, Scala center
* Copyright 2011 - 2022, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* Licensed under Apache License 2.0 (see LICENSE)
*/
package sbt.librarymanagement
import java.io.File
import java.net.URI
import java.nio.file.{ Files, Path, Paths }
import java.nio.file.attribute.BasicFileAttributes
import java.nio.ByteBuffer
import scala.util.Try
import com.github.benmanes.caffeine.cache.{ Cache, Caffeine }
import sbt.io.IO
import sjsonnew.{ FileIsoStringLongs, HashUtil, IsoStringLong }
/**
* Overrides sjson-new's `File`/`Path` isos so the sha256 content hash they embed is memoized by
* (path, size, lastModified) instead of re-read from disk on every serialization. Same
* invalidation as the digest cache in sbt.util.CacheImplicits (sbt/sbt#8363): a changed file
* changes its size or timestamp and is re-hashed.
*
* Mix in after `BasicJsonProtocol` (via `contrabandCodecParents`) so these overrides win in
* linearization.
*/
trait MemoizedFileFormats extends FileIsoStringLongs {
import MemoizedFileFormats.{ Entry, hashCache }
// sjsonnew.HashUtil.sha256ToLong is private[sjsonnew]; same semantics via the public sha256
private def hashFile(path: Path): Long = {
val buf = HashUtil.sha256(path.toFile())
if buf.length < 8 then 0L else ByteBuffer.wrap(buf).getLong()
}
private def memoizedHash(path: Path): Long =
Try(Files.readAttributes(path, classOf[BasicFileAttributes])).toOption match {
case None =>
// no size/mtime to validate a cache entry against, so hash uncached
if Files.isRegularFile(path) then hashFile(path) else 0L
case Some(attrs) =>
val key = path.toString
val mtime = attrs.lastModifiedTime.toMillis
val cached = hashCache.getIfPresent(key)
if (cached != null && cached.size == attrs.size && cached.mtime == mtime) cached.hash
else {
val h = if (attrs.isDirectory) 0L else hashFile(path)
// 0L is the sentinel for directories and files that vanish mid-hash, not a
// content hash; caching it would keep serving 0 for the key
if (h != 0L) hashCache.put(key, new Entry(attrs.size, mtime, h))
h
}
}
override implicit lazy val fileStringLongIso: IsoStringLong[File] = IsoStringLong.iso[File](
file => (IO.toURI(file).toASCIIString, memoizedHash(file.toPath())),
p => IO.toFile(new URI(p._1))
)
override implicit lazy val pathStringLongIso: IsoStringLong[Path] = IsoStringLong.iso[Path](
path => (path.toString, memoizedHash(path)),
p => Paths.get(p._1)
)
}
private[librarymanagement] object MemoizedFileFormats {
private final class Entry(val size: Long, val mtime: Long, val hash: Long)
// shared by every mix-in of the trait; a per-instance cache would re-hash the same
// files for each codec object that extends MemoizedFileFormats
private val hashCache: Cache[String, Entry] =
Caffeine.newBuilder().maximumSize(65536).build[String, Entry]()
}

View File

@ -0,0 +1,133 @@
package sbt.librarymanagement
import java.io.{ File, PrintWriter, StringWriter }
import java.nio.ByteBuffer
import java.nio.file.{ Files, Path }
import java.nio.file.attribute.FileTime
import sbt.io.IO
import sjsonnew.HashUtil
import sjsonnew.support.scalajson.unsafe.{ CompactPrinter, Converter }
import verify.BasicTestSuite
object MemoizedFileFormatsSpec extends BasicTestSuite:
private object Codec extends MemoizedFileFormats
import Codec.{ fileStringLongIso, pathStringLongIso }
// sjsonnew.HashUtil.sha256ToLong is private[sjsonnew]; reproduce its semantics via the
// public sha256 so the tests can compare against the stock (non-memoized) hash.
private def stockHash(path: Path): Long =
val buf = HashUtil.sha256(path.toFile())
if buf.length < 8 then 0L else ByteBuffer.wrap(buf).getLong()
private def withTempFile[A](content: String)(f: Path => A): A =
IO.withTemporaryFile("memoized-file-formats", ".txt") { file =>
IO.write(file, content)
f(file.toPath())
}
test("fileStringLongIso computes the same hash as the stock sha256"):
withTempFile("hello, world") { path =>
val (_, hash) = fileStringLongIso.to(path.toFile())
assert(hash == stockHash(path))
}
test("pathStringLongIso computes the same hash as the stock sha256"):
withTempFile("hello, world") { path =>
val (_, hash) = pathStringLongIso.to(path)
assert(hash == stockHash(path))
}
test("hash is served from the cache while (path, size, mtime) is unchanged"):
withTempFile("aaaa") { path =>
val mtime = Files.getLastModifiedTime(path)
val (_, first) = fileStringLongIso.to(path.toFile())
// Same-length content plus a restored mtime keeps the (path, size, mtime) cache key
// identical, so a recomputation would be observable as a hash change.
Files.write(path, "bbbb".getBytes("UTF-8"))
Files.setLastModifiedTime(path, mtime)
val (_, second) = fileStringLongIso.to(path.toFile())
assert(second == first)
assert(second != stockHash(path))
}
test("hash is recomputed when the mtime changes"):
withTempFile("aaaa") { path =>
val mtime = Files.getLastModifiedTime(path)
val (_, first) = fileStringLongIso.to(path.toFile())
Files.write(path, "bbbb".getBytes("UTF-8"))
// A full second ahead so the change survives filesystems with coarse mtime granularity.
Files.setLastModifiedTime(path, FileTime.fromMillis(mtime.toMillis + 1000))
val (_, second) = fileStringLongIso.to(path.toFile())
assert(second != first)
assert(second == stockHash(path))
}
test("hash is recomputed when the size changes"):
withTempFile("aaaa") { path =>
val mtime = Files.getLastModifiedTime(path)
val (_, first) = fileStringLongIso.to(path.toFile())
Files.write(path, "bbbbbb".getBytes("UTF-8"))
Files.setLastModifiedTime(path, mtime)
val (_, second) = fileStringLongIso.to(path.toFile())
assert(second != first)
assert(second == stockHash(path))
}
test("a missing file hashes to 0"):
IO.withTemporaryDirectory { dir =>
val missing = new File(dir, "does-not-exist.txt")
val (_, hash) = fileStringLongIso.to(missing)
assert(hash == 0L)
}
test("a directory hashes to 0"):
IO.withTemporaryDirectory { dir =>
val (_, hash) = fileStringLongIso.to(dir)
assert(hash == 0L)
}
test("round-trips a File through the iso"):
withTempFile("hello") { path =>
val file = path.toFile()
val pair = fileStringLongIso.to(file)
assert(fileStringLongIso.from(pair).getCanonicalFile == file.getCanonicalFile)
}
test("the memoized iso is wired into the generated LibraryManagementCodec"):
IO.withTemporaryDirectory { dir =>
val jar = new File(dir, "lib.jar")
IO.write(jar, "aaaa")
val mtime = Files.getLastModifiedTime(jar.toPath())
val ur = report(dir, jar)
val before = render(ur)
// 0 is the missing-file/directory sentinel; a real hash proves the artifact was
// actually hashed, so the unchanged-render assertion below is meaningful.
assert(before.contains("\"second\":"))
assert(!before.contains("\"second\":0,"))
// Same-size rewrite plus a restored mtime keeps the cache key identical; an unchanged
// render then proves the generated codec goes through the memoized iso (the wiring).
IO.write(jar, "bbbb")
Files.setLastModifiedTime(jar.toPath(), mtime)
val after = render(ur)
assert(after == before)
}
private def render(ur: UpdateReport): String =
val js = Converter.toJson(ur)(using LibraryManagementCodec.UpdateReportFormat).get
val out = new StringWriter
CompactPrinter.print(js, new PrintWriter(out))
out.toString
private def report(dir: File, jar: File): UpdateReport =
val modId = ModuleID("org.example", "lib", "1.0.0")
val artifact = Artifact("lib", "jar", "jar", None, Vector.empty, None, Map.empty, None)
val mr = ModuleReport(modId, Vector((artifact, jar)), Vector.empty)
val descriptor = new File(dir, "ivy.xml")
IO.touch(descriptor)
UpdateReport(
descriptor,
Vector(ConfigurationReport(ConfigRef("compile"), Vector(mr), Vector.empty)),
UpdateStats(0L, 0L, 0L, false),
Map.empty
)