diff --git a/build.sbt b/build.sbt index 0f38b6bde..9f0c79fb4 100644 --- a/build.sbt +++ b/build.sbt @@ -17,7 +17,6 @@ def commonSettings: Seq[Setting[_]] = Seq( crossScalaVersions := Seq(scala211), resolvers += Resolver.sonatypeRepo("public"), scalacOptions += "-Ywarn-unused", - scalacOptions += "-Ywarn-unused-import", previousArtifact := None, // Some(organization.value %% moduleName.value % "1.0.0"), publishArtifact in Compile := true, publishArtifact in Test := false @@ -47,11 +46,14 @@ lazy val lm = (project in file("librarymanagement")). commonSettings, name := "librarymanagement", libraryDependencies ++= Seq( - ivy, jsch, sbtSerialization, scalaReflect.value, launcherInterface), - resourceGenerators in Compile <+= (version, resourceManaged, streams, compile in Compile) map Util.generateVersionFile, - binaryIssueFilters ++= Seq() + ivy, jsch, scalaReflect.value, launcherInterface, sjsonnewScalaJson % Optional), + libraryDependencies ++= scalaXml.value, + resourceGenerators in Compile += Def.task(Util.generateVersionFile(version.value, resourceManaged.value, streams.value, (compile in Compile).value)).taskValue, + binaryIssueFilters ++= Seq(), + datatypeFormatsForType in generateDatatypes in Compile := DatatypeConfig.getFormats ). - configure(addSbtIO, addSbtUtilLogging, addSbtUtilTesting, addSbtUtilCollection, addSbtUtilCompletion) + configure(addSbtIO, addSbtUtilLogging, addSbtUtilTesting, addSbtUtilCollection, addSbtUtilCompletion, addSbtUtilCache). + enablePlugins(DatatypePlugin, JsonCodecPlugin) def customCommands: Seq[Setting[_]] = Seq( commands += Command.command("release") { state => diff --git a/librarymanagement/src/main/datatype/librarymanagement.json b/librarymanagement/src/main/datatype/librarymanagement.json new file mode 100644 index 000000000..994dba15e --- /dev/null +++ b/librarymanagement/src/main/datatype/librarymanagement.json @@ -0,0 +1,775 @@ +{ + "codecNamespace": "sbt.librarymanagement", + "fullCodec": "LibraryManagementCodec", + "types": [ + { + "name": "Artifact", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "parents": "sbt.librarymanagement.ArtifactExtra", + "fields": [ + { "name": "name", "type": "String" }, + { "name": "type", "type": "String", "default": "Artifact.DefaultType", "since": "0.0.1" }, + { "name": "extension", "type": "String", "default": "Artifact.DefaultExtension", "since": "0.0.1" }, + { "name": "classifier", "type": "String?", "default": "None", "since": "0.0.1" }, + { "name": "configurations", "type": "sbt.librarymanagement.Configuration*", "default": "Vector.empty", "since": "0.0.1" }, + { "name": "url", "type": "java.net.URL?", "default": "None", "since": "0.0.1" }, + { "name": "extraAttributes", "type": "Map[String, String]", "default": "Map.empty", "since": "0.0.1" } + ], + "parentsCompanion": "sbt.librarymanagement.ArtifactFunctions" + }, + { + "name": "ArtifactTypeFilter", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "doc": "Work around the inadequacy of Ivy's ArtifactTypeFilter (that it cannot reverse a filter)", + "parents": "sbt.librarymanagement.ArtifactTypeFilterExtra", + "fields": [ + { + "name": "types", + "doc": [ + "Represents the artifact types that we should try to resolve for (as in the allowed values of", + "`artifact[type]` from a dependency `` section). One can use this to filter", + "source / doc artifacts." + ], + "type": "Set[String]" + }, + { + "name": "inverted", + "doc": [ "Whether to invert the types filter (i.e. allow only types NOT in the set)" ], + "type": "boolean" + } + ], + "parentsCompanion": "sbt.librarymanagement.ArtifactTypeFilterFunctions" + }, + { + "name": "Caller", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "caller", "type": "sbt.librarymanagement.ModuleID" }, + { "name": "callerConfigurations", "type": "String*" }, + { "name": "callerExtraAttributes", "type": "Map[String, String]" }, + { "name": "isForceDependency", "type": "boolean" }, + { "name": "isChangingDependency", "type": "boolean" }, + { "name": "isTransitiveDependency", "type": "boolean" }, + { "name": "isDirectlyForceDependency", "type": "boolean" } + ], + "toString": "s\"$caller\"" + }, + { + "name": "Configuration", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "doc": "Represents an Ivy configuration.", + "parents": "sbt.librarymanagement.ConfigurationExtra", + "fields": [ + { "name": "name", "type": "String" }, + { "name": "description", "type": "String", "default": "\"\"", "since": "0.0.1" }, + { "name": "isPublic", "type": "boolean", "default": "true", "since": "0.0.1" }, + { "name": "extendsConfigs", "type": "sbt.librarymanagement.Configuration*", "default": "Vector.empty", "since": "0.0.1" }, + { "name": "transitive", "type": "boolean", "default": "true", "since": "0.0.1" } + ], + "toString": "name" + }, + { + "name": "ConfigurationReport", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "doc": [ + "Provides information about resolution of a single configuration." + ], + "parents": "sbt.librarymanagement.ConfigurationReportExtra", + "fields": [ + { "name": "configuration", "type": "String", "doc": [ "the configuration this report is for." ] }, + { + "name": "modules", + "type": "sbt.librarymanagement.ModuleReport*", + "doc": [ + "a sequence containing one report for each module resolved for this configuration." + ] + }, + { + "name": "details", + "type": "sbt.librarymanagement.OrganizationArtifactReport*", + "doc": [ "a sequence containing one report for each org/name, which may or may not be part of the final resolution." ] + } + ] + }, + { + "name": "ConflictManager", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "doc": "See http://ant.apache.org/ivy/history/latest-milestone/settings/conflict-managers.html for details of the different conflict managers.", + "fields": [ + { "name": "name", "type": "String" }, + { "name": "organization", "type": "String", "default": "\"*\"", "since": "0.0.1" }, + { "name": "module", "type": "String", "default": "\"*\"", "since": "0.0.1" } + ], + "parentsCompanion": "sbt.librarymanagement.ConflictManagerFunctions" + }, + { + "name": "CrossVersion", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "interface", + "doc": "Configures how a module will be cross-versioned.", + "types": [ + { + "name": "Disabled", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "doc": "Disables cross versioning for a module.", + "type": "record" + }, + { + "name": "Binary", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "doc": [ + "Cross-versions a module using the result of applying `remapVersion` to the binary version.", + "For example, if `remapVersion = v => \"2.10\"` and the binary version is \"2.9.2\" or \"2.10\",", + "the module is cross-versioned with \"2.10\"." + ], + "type": "record" + }, + { + "name": "Full", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "doc": [ + "Cross-versions a module with the result of applying `remapVersion` to the full version.", + "For example, if `remapVersion = v => \"2.10\"` and the full version is \"2.9.2\" or \"2.10.3\",", + "the module is cross-versioned with \"2.10\"." + ] + } + ], + "parentsCompanion": "sbt.librarymanagement.CrossVersionFunctions" + }, + { + "name": "Developer", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "id", "type": "String" }, + { "name": "name", "type": "String" }, + { "name": "email", "type": "String" }, + { "name": "url", "type": "java.net.URL" } + ] + }, + { + "name": "FileConfiguration", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "doc": "Configuration specific to an Ivy filesystem resolver.", + "fields": [ + { "name": "isLocal", "type": "boolean" }, + { "name": "isTransactional", "type": "boolean?" } + ] + }, + { + "name": "InclExclRule", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "doc": [ + "Rule to either:", + "", + "Which one depends on the parameter name which it is passed to, but the filter has the same fields in both cases." + ], + "fields": [ + { "name": "organization", "type": "String", "default": "\"*\"", "since": "0.0.1" }, + { "name": "name", "type": "String", "default": "\"*\"", "since": "0.0.1" }, + { "name": "artifact", "type": "String", "default": "\"*\"", "since": "0.0.1" }, + { "name": "configurations", "type": "String*", "default": "Vector.empty", "since": "0.0.1" } + ], + "parentsCompanion": "sbt.librarymanagement.InclExclRuleFunctions" + }, + { + "name": "IvyScala", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "scalaFullVersion", "type": "String" }, + { "name": "scalaBinaryVersion", "type": "String" }, + { "name": "configurations", "type": "sbt.librarymanagement.Configuration*" }, + { "name": "checkExplicit", "type": "boolean" }, + { "name": "filterImplicit", "type": "boolean" }, + { "name": "overrideScalaVersion", "type": "boolean" }, + { "name": "scalaOrganization", "type": "String", "default": "sbt.librarymanagement.ScalaArtifacts.Organization", "since": "0.0.1" }, + { "name": "scalaArtifacts", "type": "String*", "default": "sbt.librarymanagement.ScalaArtifacts.Artifacts", "since": "0.0.1" } + ], + "parentsCompanion": "sbt.librarymanagement.IvyScalaFunctions" + }, + { + "name": "ModuleConfiguration", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "organization", "type": "String" }, + { "name": "name", "type": "String" }, + { "name": "revision", "type": "String" }, + { "name": "resolver", "type": "sbt.librarymanagement.Resolver" } + ], + "extraCompanion": [ + "def apply(org: String, resolver: sbt.librarymanagement.Resolver): ModuleConfiguration = apply(org, \"*\", \"*\", resolver)", + "def apply(org: String, name: String, resolver: sbt.librarymanagement.Resolver): ModuleConfiguration = ModuleConfiguration(org, name, \"*\", resolver)" + ] + }, + { + "name": "ModuleID", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "parents": "sbt.librarymanagement.ModuleIDExtra", + "fields": [ + { "name": "organization", "type": "String" }, + { "name": "name", "type": "String" }, + { "name": "revision", "type": "String" }, + { "name": "configurations", "type": "String?", "default": "None", "since": "0.0.1" }, + { "name": "isChanging", "type": "boolean", "default": "false", "since": "0.0.1" }, + { "name": "isTransitive", "type": "boolean", "default": "true", "since": "0.0.1" }, + { "name": "isForce", "type": "boolean", "default": "false", "since": "0.0.1" }, + { "name": "explicitArtifacts", "type": "sbt.librarymanagement.Artifact*", "default": "Vector.empty", "since": "0.0.1" }, + { "name": "inclusions", "type": "sbt.librarymanagement.InclExclRule*", "default": "Vector.empty", "since": "0.0.1" }, + { "name": "exclusions", "type": "sbt.librarymanagement.InclExclRule*", "default": "Vector.empty", "since": "0.0.1" }, + { "name": "extraAttributes", "type": "Map[String, String]", "default": "Map.empty", "since": "0.0.1" }, + { "name": "crossVersion", "type": "sbt.librarymanagement.CrossVersion", "default": "sbt.librarymanagement.Disabled()", "since": "0.0.1" }, + { "name": "branchName", "type": "String?", "default": "None", "since": "0.0.1" } + ], + "toString": [ + "organization + \":\" + name + \":\" + revision +", + " (configurations match { case Some(s) => \":\" + s; case None => \"\" }) +", + " (if (extraAttributes.isEmpty) \"\" else \" \" + extraString)" + ], + "parentsCompanion": "sbt.librarymanagement.ModuleIDFunctions" + }, + { + "name": "ModuleInfo", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "doc": "Additional information about a project module", + "fields": [ + { "name": "nameFormal", "type": "String" }, + { "name": "description", "type": "String", "default": "\"\"", "since": "0.0.1" }, + { "name": "homepage", "type": "java.net.URL?", "default": "None", "since": "0.0.1" }, + { "name": "startYear", "type": "int?", "default": "None", "since": "0.0.1" }, + { "name": "licenses", "type": "scala.Tuple2[String, java.net.URL]*", "default": "Vector.empty", "since": "0.0.1" }, + { "name": "organizationName", "type": "String", "default": "\"\"", "since": "0.0.1" }, + { "name": "organizationHomepage", "type": "java.net.URL?", "default": "None", "since": "0.0.1" }, + { "name": "scmInfo", "type": "sbt.librarymanagement.ScmInfo?", "default": "None", "since": "0.0.1" }, + { "name": "developers", "type": "sbt.librarymanagement.Developer*", "default": "Vector.empty", "since": "0.0.1" } + ] + }, + { + "name": "ModuleReport", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "doc": [ + "Provides information about the resolution of a module.", + "This information is in the context of a specific configuration." + ], + "parents": "sbt.librarymanagement.ModuleReportExtra", + "fields": [ + { "name": "module", "type": "sbt.librarymanagement.ModuleID" }, + { "name": "artifacts", "type": "scala.Tuple2[sbt.librarymanagement.Artifact, java.io.File]*" }, + { "name": "missingArtifacts", "type": "sbt.librarymanagement.Artifact*" }, + { "name": "status", "type": "String?", "default": "None", "since": "0.0.1" }, + { "name": "publicationDate", "type": "java.util.Date?", "default": "None", "since": "0.0.1" }, + { "name": "resolver", "type": "String?", "default": "None", "since": "0.0.1" }, + { "name": "artifactResolver", "type": "String?", "default": "None", "since": "0.0.1" }, + { "name": "evicted", "type": "boolean", "default": "false", "since": "0.0.1" }, + { "name": "evictedData", "type": "String?", "default": "None", "since": "0.0.1" }, + { "name": "evictedReason", "type": "String?", "default": "None", "since": "0.0.1" }, + { "name": "problem", "type": "String?", "default": "None", "since": "0.0.1" }, + { "name": "homepage", "type": "String?", "default": "None", "since": "0.0.1" }, + { "name": "extraAttributes", "type": "Map[String, String]", "default": "Map.empty", "since": "0.0.1" }, + { "name": "isDefault", "type": "boolean?", "default": "None", "since": "0.0.1" }, + { "name": "branch", "type": "String?", "default": "None", "since": "0.0.1" }, + { "name": "configurations", "type": "String*", "default": "Vector.empty", "since": "0.0.1" }, + { "name": "licenses", "type": "scala.Tuple2[String, Option[String]]*", "default": "Vector.empty", "since": "0.0.1" }, + { "name": "callers", "type": "sbt.librarymanagement.Caller*", "default": "Vector.empty", "since": "0.0.1" } + ], + "toString": [ + "s\"\\t\\t$module: \" +", + "(if (arts.size <= 1) \"\" else \"\\n\\t\\t\\t\") + arts.mkString(\"\\n\\t\\t\\t\") + \"\\n\"" + ] + }, + { + "name": "ModuleSettings", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "interface", + "fields": [ + { "name": "validate", "type": "boolean" }, + { "name": "ivyScala", "type": "sbt.librarymanagement.IvyScala?" } + ], + "types": [ + { + "name": "IvyFileConfiguration", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "file", "type": "java.io.File" }, + { "name": "autoScalaTools", "type": "boolean" } + ] + }, + { + "name": "PomConfiguration", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "file", "type": "java.io.File" }, + { "name": "autoScalaTools", "type": "boolean" } + ] + }, + { + "name": "InlineConfiguration", + "namespace": "sbt.internal.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "module", "type": "sbt.librarymanagement.ModuleID" }, + { "name": "moduleInfo", "type": "sbt.librarymanagement.ModuleInfo" }, + { "name": "dependencies", "type": "sbt.librarymanagement.ModuleID*" }, + { "name": "overrides", "type": "Set[sbt.librarymanagement.ModuleID]", "default": "Set.empty", "since": "0.0.1" }, + { "name": "excludes", "type": "sbt.internal.librarymanagement.SbtExclusionRule*", "default": "Vector.empty", "since": "0.0.1" }, + { "name": "ivyXML", "type": "scala.xml.NodeSeq", "default": "scala.xml.NodeSeq.Empty", "since": "0.0.1" }, + { "name": "configurations", "type": "sbt.librarymanagement.Configuration*", "default": "Vector.empty", "since": "0.0.1" }, + { "name": "defaultConfiguration", "type": "sbt.librarymanagement.Configuration?", "default": "None", "since": "0.0.1" }, + { "name": "conflictManager", "type": "sbt.librarymanagement.ConflictManager", "default": "sbt.librarymanagement.ConflictManager.default", "since": "0.0.1" } + ], + "parentsCompanion": "sbt.internal.librarymanagement.InlineConfigurationFunctions" + } + ] + }, + { + "name": "OrganizationArtifactReport", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "doc": [ + "OrganizationArtifactReport represents an organization+name entry in Ivy resolution report.", + "In sbt's terminology, \"module\" consists of organization, name, and version.", + "In Ivy's, \"module\" means just organization and name, and the one including version numbers", + "are called revisions.", + "", + "A sequence of OrganizationArtifactReport called details is newly added to ConfigurationReport, replacing evicted.", + "(Note old evicted was just a seq of ModuleIDs).", + "OrganizationArtifactReport groups the ModuleReport of both winners and evicted reports by their organization and name,", + "which can be used to calculate detailed eviction warning etc." + ], + "fields": [ + { "name": "organization", "type": "String" }, + { "name": "name", "type": "String" }, + { "name": "modules", "type": "sbt.librarymanagement.ModuleReport*" } + ] + }, + { + "name": "Patterns", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "ivyPatterns", "type": "String*", "default": "Vector.empty", "since": "0.0.1" }, + { "name": "artifactPatterns", "type": "String*", "default": "Vector.empty", "since": "0.0.1" }, + { "name": "isMavenCompatible", "type": "boolean", "default": "true", "since": "0.0.1" }, + { "name": "descriptorOptional", "type": "boolean", "default": "false", "since": "0.0.1" }, + { "name": "skipConsistencyCheck", "type": "boolean", "default": "false", "since": "0.0.1" } + ], + "toString": [ + "\"Patterns(ivyPatterns=%s, artifactPatterns=%s, isMavenCompatible=%s, descriptorOptional=%s, skipConsistencyCheck=%s)\".format(", + " ivyPatterns, artifactPatterns, isMavenCompatible, descriptorOptional, skipConsistencyCheck)" + ], + "parentsCompanion": "sbt.librarymanagement.PatternsFunctions" + }, + { + "name": "Resolver", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "interface", + "fields": [ + { "name": "name", "type": "String" } + ], + "types": [ + { + "name": "ChainedResolver", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "resolvers", "type": "sbt.librarymanagement.Resolver*" } + ] + }, + { + "name": "IMavenRepository", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "interface", + "doc": "An instance of a remote maven repository. Note: This will use Aether/Maven to resolve artifacts.", + "fields": [ + { "name": "root", "type": "String" }, + { "name": "localIfFile", "type": "boolean", "default": "true", "since": "0.0.1" } + ], + "types": [ + { + "name": "MavenRepository", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "toString": "s\"$name: $root\"" + }, + { + "name": "MavenCache", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "doc": [ + "An instance of maven CACHE directory. You cannot treat a cache directory the same as a a remote repository because", + "the metadata is different (see Aether ML discussion)." + ], + "fields": [ + { "name": "rootFile", "type": "java.io.File" } + ], + "extra": "def this(name: String, rootFile: java.io.File) = this(name, rootFile.toURI.toURL.toString, true, rootFile)", + "toString": "s\"cache:$name: ${rootFile.getAbsolutePath}\"", + "extraCompanion": "def apply(name: String, rootFile: java.io.File): MavenCache = new MavenCache(name, rootFile)" + } + ] + }, + { + "name": "PatternsBasedRepository", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "interface", + "fields": [ + { "name": "patterns", "type": "sbt.librarymanagement.Patterns" } + ], + "doc": "sbt interface to an Ivy repository based on patterns, which is most Ivy repositories.", + "types": [ + { + "name": "FileRepository", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "doc": "sbt interface for an Ivy filesystem repository. More convenient construction is done using Resolver.file.", + "fields": [ + { "name": "configuration", "type": "sbt.librarymanagement.FileConfiguration" } + ], + "extra": [ + "def this(name: String, configuration: sbt.librarymanagement.FileConfiguration, patterns: sbt.librarymanagement.Patterns) = ", + " this(name, patterns, configuration)" + ], + "extraCompanion": [ + "def apply(name: String, configuration: sbt.librarymanagement.FileConfiguration, patterns: sbt.librarymanagement.Patterns) = ", + " new FileRepository(name, patterns, configuration)" + ] + }, + { + "name": "URLRepository", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record" + }, + { + "name": "SshBasedRepository", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "interface", + "doc": "sbt interface for an Ivy ssh-based repository (ssh and sftp). Requires the Jsch library..", + "fields": [ + { "name": "connection", "type": "sbt.librarymanagement.SshConnection" } + ], + "types": [ + { + "name": "SshRepository", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "doc": "sbt interface for an Ivy repository over ssh. More convenient construction is done using Resolver.ssh.", + "fields": [ + { "name": "publishPermissions", "type": "String?" } + ], + "extra": [ + "def this(name: String, connection: sbt.librarymanagement.SshConnection, patterns: sbt.librarymanagement.Patterns, publishPermissions: Option[String]) = ", + " this(name, patterns, connection, publishPermissions)" + ], + "extraCompanion": [ + "def apply(name: String, connection: sbt.librarymanagement.SshConnection, patterns: sbt.librarymanagement.Patterns, publishPermissions: Option[String]) = ", + " new SshRepository(name, patterns, connection, publishPermissions)" + ] + }, + { + "name": "SftpRepository", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "doc": "sbt interface for an Ivy repository over sftp. More convenient construction is done using Resolver.sftp.", + "extra": [ + "def this(name: String, connection: sbt.librarymanagement.SshConnection, patterns: sbt.librarymanagement.Patterns) = ", + " this(name, patterns, connection)" + ], + "extraCompanion": [ + "def apply(name: String, connection: sbt.librarymanagement.SshConnection, patterns: sbt.librarymanagement.Patterns) = ", + " new SftpRepository(name, patterns, connection)" + ] + } + ] + } + ] + } + ], + "parentsCompanion": "sbt.librarymanagement.ResolverFunctions" + }, + { + "name": "ScmInfo", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "doc": "Basic SCM information for a project module", + "fields": [ + { "name": "browseUrl", "type": "java.net.URL" }, + { "name": "connection", "type": "String" }, + { "name": "devConnection", "type": "String?" } + ] + }, + { + "name": "SshAuthentication", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "interface", + "types": [ + { + "name": "PasswordAuthentication", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "user", "type": "String" }, + { "name": "password", "type": "String?" } + ] + }, + { + "name": "KeyFileAuthentication", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "user", "type": "String" }, + { "name": "keyfile", "type": "java.io.File" }, + { "name": "password", "type": "String?" } + ] + } + ] + }, + { + "name": "SshConnection", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "authentication", "type": "sbt.librarymanagement.SshAuthentication?" }, + { "name": "hostname", "type": "String?" }, + { "name": "port", "type": "int?" } + ] + }, + { + "name": "UpdateConfiguration", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "retrieve", "type": "sbt.internal.librarymanagement.RetrieveConfiguration?" }, + { "name": "missingOk", "type": "boolean" }, + { "name": "logging", "type": "sbt.librarymanagement.UpdateLogging" }, + { "name": "artifactFilter", "type": "sbt.librarymanagement.ArtifactTypeFilter" } + ] + }, + { + "name": "UpdateLogging", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "enumeration", + "doc": [ + "Configures logging during an 'update'. `level` determines the amount of other information logged.", + "`Full` is the default and logs the most.", + "`DownloadOnly` only logs what is downloaded.", + "`Quiet` only displays errors.", + "`Default` uses the current log level of `update` task." + ], + "symbols": [ "Full", "DownloadOnly", "Quiet", "Default" ] + }, + { + "name": "UpdateReport", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "doc": [ + "Provides information about dependency resolution.", + "It does not include information about evicted modules, only about the modules ultimately selected by the conflict manager.", + "This means that for a given configuration, there should only be one revision for a given organization and module name." + ], + "parents": "sbt.librarymanagement.UpdateReportExtra", + "fields": [ + { + "name": "cachedDescriptor", + "type": "java.io.File", + "doc": [ "the location of the resolved module descriptor in the cache" ] + }, + { + "name": "configurations", + "type": "sbt.librarymanagement.ConfigurationReport*", + "doc": [ "a sequence containing one report for each configuration resolved." ] + }, + { + "name": "stats", + "type": "sbt.librarymanagement.UpdateStats", + "doc": [ "stats information about the update that produced this report" ] + }, + { "name": "stamps", "type": "Map[java.io.File, Long]" } + ], + "toString": "\"Update report:\\n\\t\" + stats + \"\\n\" + configurations.mkString" + }, + { + "name": "UpdateStats", + "namespace": "sbt.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "resolveTime", "type": "long" }, + { "name": "downloadTime", "type": "long" }, + { "name": "downloadSize", "type": "long" }, + { "name": "cached", "type": "boolean" } + ], + "toString": "Seq(\"Resolve time: \" + resolveTime + \" ms\", \"Download time: \" + downloadTime + \" ms\", \"Download size: \" + downloadSize + \" bytes\").mkString(\", \")" + }, + + { + "name": "ConfigurationReportLite", + "namespace": "sbt.internal.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "configuration", "type": "String" }, + { "name": "details", "type": "sbt.librarymanagement.OrganizationArtifactReport*" } + ] + }, + { + "name": "IvyConfiguration", + "namespace": "sbt.internal.librarymanagement", + "target": "Scala", + "type": "interface", + "fields": [ + { "name": "lock", "type": "xsbti.GlobalLock?" }, + { "name": "baseDirectory", "type": "java.io.File" }, + { "name": "log", "type": "xsbti.Logger" }, + { "name": "updateOptions", "type": "sbt.librarymanagement.UpdateOptions" } + ], + "types": [ + { + "name": "InlineIvyConfiguration", + "namespace": "sbt.internal.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "paths", "type": "sbt.internal.librarymanagement.IvyPaths" }, + { "name": "resolvers", "type": "sbt.librarymanagement.Resolver*" }, + { "name": "otherResolvers", "type": "sbt.librarymanagement.Resolver*" }, + { "name": "moduleConfigurations", "type": "sbt.librarymanagement.ModuleConfiguration*" }, + { "name": "localOnly", "type": "boolean" }, + { "name": "checksums", "type": "String*" }, + { "name": "resolutionCacheDir", "type": "java.io.File?" } + ], + "extra": [ + "def this(", + " paths: sbt.internal.librarymanagement.IvyPaths,", + " resolvers: Vector[sbt.librarymanagement.Resolver],", + " otherResolvers: Vector[sbt.librarymanagement.Resolver],", + " moduleConfigurations: Vector[sbt.librarymanagement.ModuleConfiguration],", + " localOnly: Boolean,", + " lock: Option[xsbti.GlobalLock],", + " checksums: Vector[String],", + " resolutionCacheDir: Option[java.io.File],", + " updateOptions: sbt.librarymanagement.UpdateOptions,", + " log: xsbti.Logger", + ") =", + " this(lock, paths.baseDirectory, log, updateOptions, paths, resolvers, otherResolvers,", + " moduleConfigurations, localOnly, checksums, resolutionCacheDir)" + ] + }, + { + "name": "ExternalIvyConfiguration", + "namespace": "sbt.internal.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "uri", "type": "java.net.URI" }, + { "name": "extraResolvers", "type": "sbt.librarymanagement.Resolver*" } + ] + } + ] + }, + { + "name": "IvyPaths", + "namespace": "sbt.internal.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "baseDirectory", "type": "java.io.File" }, + { "name": "ivyHome", "type": "java.io.File?" } + ] + }, + { + "name": "RetrieveConfiguration", + "namespace": "sbt.internal.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "retrieveDirectory", "type": "java.io.File" }, + { "name": "outputPattern", "type": "String" }, + { "name": "sync", "type": "boolean", "default": "false", "since": "0.0.1" }, + { "name": "configurationsToRetrieve", "type": "Set[sbt.librarymanagement.Configuration]?", "default": "None", "since": "0.0.1" } + ] + }, + { + "name": "SbtExclusionRule", + "namespace": "sbt.internal.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "organization", "type": "String" }, + { "name": "name", "type": "String" }, + { "name": "artifact", "type": "String" }, + { "name": "configurations", "type": "String*" }, + { "name": "crossVersion", "type": "sbt.librarymanagement.CrossVersion" } + ] + }, + { + "name": "UpdateReportLite", + "namespace": "sbt.internal.librarymanagement", + "target": "Scala", + "type": "record", + "fields": [ + { "name": "configurations", "type": "sbt.internal.librarymanagement.ConfigurationReportLite*" } + ] + } + ] +} diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala index 1d0a6a470..a1d67b99c 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala @@ -195,20 +195,20 @@ private[sbt] object ConvertResolver { initializePatterns(resolver, repo.patterns, settings) initializeConnection(resolver, repo.connection) } - private def initializeConnection(resolver: AbstractSshBasedResolver, connection: RepositoryHelpers.SshConnection): Unit = { + private def initializeConnection(resolver: AbstractSshBasedResolver, connection: SshConnection): Unit = { import resolver._ import connection._ hostname.foreach(setHost) port.foreach(setPort) authentication foreach { - case RepositoryHelpers.PasswordAuthentication(user, password) => - setUser(user) - password.foreach(setUserPassword) - case RepositoryHelpers.KeyFileAuthentication(user, file, password) => - setKeyFile(file) - password.foreach(setKeyFilePassword) - setUser(user) + case pa: PasswordAuthentication => + setUser(pa.user) + pa.password.foreach(setUserPassword) + case kfa: KeyFileAuthentication => + setKeyFile(kfa.keyfile) + kfa.password.foreach(setKeyFilePassword) + setUser(kfa.user) } } private def initializePatterns(resolver: AbstractPatternsBasedResolver, patterns: Patterns, settings: IvySettings): Unit = { diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/Ivy.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/Ivy.scala index 29e8b0b42..320f549a0 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/Ivy.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/Ivy.scala @@ -30,8 +30,9 @@ import sbt.util.Logger import sbt.librarymanagement._ import Resolver.PluginPattern import ivyint.{ CachedResolutionResolveEngine, CachedResolutionResolveCache, SbtDefaultDependencyDescriptor } +import sbt.internal.util.CacheStore -final class IvySbt(val configuration: IvyConfiguration) { +final class IvySbt(val configuration: IvyConfiguration, fileToStore: File => CacheStore) { self => import configuration.baseDirectory /* @@ -92,7 +93,8 @@ final class IvySbt(val configuration: IvyConfiguration) { setEventManager(new EventManager()) if (configuration.updateOptions.cachedResolution) { setResolveEngine(new ResolveEngine(getSettings, getEventManager, getSortEngine) with CachedResolutionResolveEngine { - val cachedResolutionResolveCache = IvySbt.cachedResolutionResolveCache + override private[sbt] val fileToStore: File => CacheStore = self.fileToStore + val cachedResolutionResolveCache = IvySbt.cachedResolutionResolveCache(fileToStore) val projectResolver = prOpt def makeInstance = mkIvy }) @@ -139,7 +141,7 @@ final class IvySbt(val configuration: IvyConfiguration) { withIvy(log) { i => val prOpt = Option(i.getSettings.getResolver(ProjectResolver.InterProject)) map { case pr: ProjectResolver => pr } if (configuration.updateOptions.cachedResolution) { - IvySbt.cachedResolutionResolveCache.clean(md, prOpt) + IvySbt.cachedResolutionResolveCache(fileToStore).clean(md, prOpt) } } @@ -236,8 +238,8 @@ private[sbt] object IvySbt { val DefaultIvyConfigFilename = "ivysettings.xml" val DefaultIvyFilename = "ivy.xml" val DefaultMavenFilename = "pom.xml" - val DefaultChecksums = Seq("sha1", "md5") - private[sbt] val cachedResolutionResolveCache: CachedResolutionResolveCache = new CachedResolutionResolveCache() + val DefaultChecksums = Vector("sha1", "md5") + private[sbt] def cachedResolutionResolveCache(fileToStore: File => CacheStore): CachedResolutionResolveCache = new CachedResolutionResolveCache(fileToStore) def defaultIvyFile(project: File) = new File(project, DefaultIvyFilename) def defaultIvyConfiguration(project: File) = new File(project, DefaultIvyConfigFilename) @@ -305,8 +307,8 @@ private[sbt] object IvySbt { */ def hasImplicitClassifier(artifact: IArtifact): Boolean = { - import collection.JavaConversions._ - artifact.getQualifiedExtraAttributes.keys.exists(_.asInstanceOf[String] startsWith "m:") + import scala.collection.JavaConverters._ + artifact.getQualifiedExtraAttributes.asScala.keys.exists(_.asInstanceOf[String] startsWith "m:") } private def setModuleConfigurations(settings: IvySettings, moduleConfigurations: Seq[ModuleConfiguration], log: Logger): Unit = { val existing = settings.getResolverNames @@ -426,7 +428,7 @@ private[sbt] object IvySbt { { val sub = CrossVersion(scalaFullVersion, scalaBinaryVersion) m match { - case ic: InlineConfiguration => ic.copy(module = sub(ic.module), dependencies = ic.dependencies map sub, overrides = ic.overrides map sub) + case ic: InlineConfiguration => ic.withModule(sub(ic.module)).withDependencies(ic.dependencies map sub).withOverrides(ic.overrides map sub) case _ => m } } @@ -439,7 +441,7 @@ private[sbt] object IvySbt { } def getExtraAttributes(revID: ExtendableItem): Map[String, String] = { - import collection.JavaConverters._ + import scala.collection.JavaConverters._ revID.getExtraAttributes.asInstanceOf[java.util.Map[String, String]].asScala.toMap } private[sbt] def extra(artifact: Artifact, unqualify: Boolean = false): java.util.Map[String, String] = @@ -449,8 +451,9 @@ private[sbt] object IvySbt { } private[sbt] def javaMap(m: Map[String, String], unqualify: Boolean = false) = { + import scala.collection.JavaConverters._ val map = if (unqualify) m map { case (k, v) => (k.stripPrefix("e:"), v) } else m - if (map.isEmpty) null else scala.collection.JavaConversions.mapAsJavaMap(map) + if (map.isEmpty) null else map.asJava } /** Creates a full ivy file for 'module' using the 'dependencies' XML as the part after the <info>...</info> section. */ @@ -514,7 +517,7 @@ private[sbt] object IvySbt { val dds = moduleID.getDependencies val deps = dds flatMap { dd => val module = toModuleID(dd.getDependencyRevisionId) - dd.getModuleConfigurations map (c => module.copy(configurations = Some(c))) + dd.getModuleConfigurations map (c => module.withConfigurations(Some(c))) } inconsistentDuplicateWarning(deps) } @@ -571,7 +574,7 @@ private[sbt] object IvySbt { deps.put(id, updated) } - import collection.JavaConverters._ + import scala.collection.JavaConverters._ deps.values.asScala.toSeq.flatMap { dds => val mergeable = (dds, dds.tail).zipped.forall(ivyint.MergeDescriptors.mergeable _) if (mergeable) dds.reverse.reduceLeft(ivyint.MergeDescriptors.apply _) :: Nil else dds @@ -652,7 +655,7 @@ private[sbt] object IvySbt { val overridden = overrides.map(id => (key(id), id.revision)).toMap dependencies map { dep => overridden get key(dep) match { - case Some(rev) => dep.copy(revision = rev) + case Some(rev) => dep.withRevision(rev) case None => dep } } diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyActions.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyActions.scala index d87001653..13a5d040b 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyActions.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyActions.scala @@ -21,36 +21,19 @@ import sbt.util.Logger import sbt.internal.util.{ ShowLines, SourcePosition, LinePosition, RangePosition, LineRange } import sbt.librarymanagement._ import sbt.internal.librarymanagement.syntax._ +import sbt.internal.librarymanagement._ -final class DeliverConfiguration(val deliverIvyPattern: String, val status: String, val configurations: Option[Seq[Configuration]], val logging: UpdateLogging.Value) -final class PublishConfiguration(val ivyFile: Option[File], val resolverName: String, val artifacts: Map[Artifact, File], val checksums: Seq[String], val logging: UpdateLogging.Value, +final class DeliverConfiguration(val deliverIvyPattern: String, val status: String, val configurations: Option[Vector[Configuration]], val logging: UpdateLogging) +final class PublishConfiguration(val ivyFile: Option[File], val resolverName: String, val artifacts: Map[Artifact, File], val checksums: Vector[String], val logging: UpdateLogging, val overwrite: Boolean) { - def this(ivyFile: Option[File], resolverName: String, artifacts: Map[Artifact, File], checksums: Seq[String], logging: UpdateLogging.Value) = + def this(ivyFile: Option[File], resolverName: String, artifacts: Map[Artifact, File], checksums: Vector[String], logging: UpdateLogging) = this(ivyFile, resolverName, artifacts, checksums, logging, false) } -final class UpdateConfiguration(val retrieve: Option[RetrieveConfiguration], val missingOk: Boolean, val logging: UpdateLogging.Value, val artifactFilter: ArtifactTypeFilter) { - @deprecated("You should use the constructor that provides an artifactFilter", "1.0.x") - def this(retrieve: Option[RetrieveConfiguration], missingOk: Boolean, logging: UpdateLogging.Value) { - this(retrieve, missingOk, logging, ArtifactTypeFilter.forbid(Set("src", "doc"))) // allow everything but "src", "doc" by default - } - - private[sbt] def copy( - retrieve: Option[RetrieveConfiguration] = this.retrieve, - missingOk: Boolean = this.missingOk, - logging: UpdateLogging.Value = this.logging, - artifactFilter: ArtifactTypeFilter = this.artifactFilter - ): UpdateConfiguration = - new UpdateConfiguration(retrieve, missingOk, logging, artifactFilter) -} -final class RetrieveConfiguration(val retrieveDirectory: File, val outputPattern: String, val sync: Boolean, val configurationsToRetrieve: Option[Set[Configuration]]) { - def this(retrieveDirectory: File, outputPattern: String) = this(retrieveDirectory, outputPattern, false, None) - def this(retrieveDirectory: File, outputPattern: String, sync: Boolean) = this(retrieveDirectory, outputPattern, sync, None) -} -final case class MakePomConfiguration(file: File, moduleInfo: ModuleInfo, configurations: Option[Seq[Configuration]] = None, extra: NodeSeq = NodeSeq.Empty, process: XNode => XNode = n => n, filterRepositories: MavenRepository => Boolean = _ => true, allRepositories: Boolean, includeTypes: Set[String] = Set(Artifact.DefaultType, Artifact.PomType)) +final case class MakePomConfiguration(file: File, moduleInfo: ModuleInfo, configurations: Option[Vector[Configuration]] = None, extra: NodeSeq = NodeSeq.Empty, process: XNode => XNode = n => n, filterRepositories: MavenRepository => Boolean = _ => true, allRepositories: Boolean, includeTypes: Set[String] = Set(Artifact.DefaultType, Artifact.PomType)) /** @param exclude is a map from ModuleID to classifiers that were previously tried and failed, so should now be excluded */ final case class GetClassifiersConfiguration(module: GetClassifiersModule, exclude: Map[ModuleID, Set[String]], configuration: UpdateConfiguration, ivyScala: Option[IvyScala], sourceArtifactTypes: Set[String], docArtifactTypes: Set[String]) -final case class GetClassifiersModule(id: ModuleID, modules: Seq[ModuleID], configurations: Seq[Configuration], classifiers: Seq[String]) +final case class GetClassifiersModule(id: ModuleID, modules: Vector[ModuleID], configurations: Vector[Configuration], classifiers: Vector[String]) final class UnresolvedWarningConfiguration private[sbt] ( val modulePositions: Map[ModuleID, SourcePosition] @@ -61,17 +44,6 @@ object UnresolvedWarningConfiguration { new UnresolvedWarningConfiguration(modulePositions) } -/** - * Configures logging during an 'update'. `level` determines the amount of other information logged. - * `Full` is the default and logs the most. - * `DownloadOnly` only logs what is downloaded. - * `Quiet` only displays errors. - * `Default` uses the current log level of `update` task. - */ -object UpdateLogging extends Enumeration { - val Full, DownloadOnly, Quiet, Default = Value -} - object IvyActions { /** Installs the dependencies of the given 'module' from the resolver named 'from' to the resolver named 'to'.*/ def install(module: IvySbt#Module, from: String, to: String, log: Logger): Unit = { @@ -133,13 +105,13 @@ object IvyActions { if (resolver eq null) sys.error("Undefined resolver '" + resolverName + "'") val ivyArtifact = ivyFile map { file => (MDArtifact.newIvyArtifact(md), file) } val cross = crossVersionMap(module.moduleSettings) - val as = mapArtifacts(md, cross, artifacts) ++ ivyArtifact.toSeq + val as = mapArtifacts(md, cross, artifacts) ++ ivyArtifact.toList withChecksums(resolver, checksums) { publish(md, as, resolver, overwrite = overwrite) } } } - private[this] def withChecksums[T](resolver: DependencyResolver, checksums: Seq[String])(act: => T): T = + private[this] def withChecksums[T](resolver: DependencyResolver, checksums: Vector[String])(act: => T): T = resolver match { case br: BasicResolver => withChecksums(br, checksums)(act); case _ => act } - private[this] def withChecksums[T](resolver: BasicResolver, checksums: Seq[String])(act: => T): T = + private[this] def withChecksums[T](resolver: BasicResolver, checksums: Vector[String])(act: => T): T = { val previous = resolver.getChecksumAlgorithms resolver.setChecksums(checksums mkString ",") @@ -151,9 +123,9 @@ object IvyActions { case i: InlineConfiguration => CrossVersion(i.module, i.ivyScala) case _ => None } - def mapArtifacts(module: ModuleDescriptor, cross: Option[String => String], artifacts: Map[Artifact, File]): Seq[(IArtifact, File)] = + def mapArtifacts(module: ModuleDescriptor, cross: Option[String => String], artifacts: Map[Artifact, File]): Vector[(IArtifact, File)] = { - val rawa = artifacts.keys.toSeq + val rawa = artifacts.keys.toVector val seqa = CrossVersion.substituteCross(rawa, cross) val zipped = rawa zip IvySbt.mapArtifacts(module, seqa) zipped map { case (a, ivyA) => (ivyA, artifacts(a)) } @@ -235,8 +207,8 @@ object IvyActions { { import config.{ configuration => c, ivyScala, module => mod } import mod.{ id, modules => deps } - val base = restrictedCopy(id, true).copy(name = id.name + "$" + label) - val module = new ivySbt.Module(InlineConfiguration(base, ModuleInfo(base.name), deps).copy(ivyScala = ivyScala)) + val base = restrictedCopy(id, true).withName(id.name + "$" + label) + val module = new ivySbt.Module(InlineConfiguration(false, ivyScala, base, ModuleInfo(base.name), deps)) val report = updateEither(module, c, uwconfig, logicalClock, depDir, log) match { case Right(r) => r case Left(w) => @@ -270,10 +242,10 @@ object IvyActions { val baseModules = modules map { m => restrictedCopy(m, true) } // Adding list of explicit artifacts here. val deps = baseModules.distinct flatMap classifiedArtifacts(classifiers, exclude, artifacts) - val base = restrictedCopy(id, true).copy(name = id.name + classifiers.mkString("$", "_", "")) - val module = new ivySbt.Module(InlineConfiguration(base, ModuleInfo(base.name), deps).copy(ivyScala = ivyScala, configurations = confs)) + val base = restrictedCopy(id, true).withName(id.name + classifiers.mkString("$", "_", "")) + val module = new ivySbt.Module(InlineConfiguration(false, ivyScala, base, ModuleInfo(base.name), deps).withConfigurations(confs)) // c.copy ensures c.types is preserved too - val upConf = c.copy(missingOk = true) + val upConf = c.withMissingOk(true) updateEither(module, upConf, uwconfig, logicalClock, depDir, log) match { case Right(r) => // The artifacts that came from Ivy don't have their classifier set, let's set it according to @@ -285,7 +257,7 @@ object IvyActions { artFileSeq map { case (art, f) => // Deduce the classifier from the type if no classifier is present already - art.copy(classifier = art.classifier orElse typeClassifierMap.get(art.`type`)) -> f + art.withClassifier(art.classifier orElse typeClassifierMap.get(art.`type`)) -> f } } case Left(w) => @@ -294,7 +266,7 @@ object IvyActions { } // This version adds explicit artifact private[sbt] def classifiedArtifacts( - classifiers: Seq[String], + classifiers: Vector[String], exclude: Map[ModuleID, Set[String]], artifacts: Vector[(String, ModuleID, Artifact, File)] )(m: ModuleID): Option[ModuleID] = { @@ -308,7 +280,7 @@ object IvyActions { def hardcodedArtifacts = classifiedArtifacts(classifiers, exclude)(m) explicitArtifacts orElse hardcodedArtifacts } - private def classifiedArtifacts(classifiers: Seq[String], exclude: Map[ModuleID, Set[String]])(m: ModuleID): Option[ModuleID] = + private def classifiedArtifacts(classifiers: Vector[String], exclude: Map[ModuleID, Set[String]])(m: ModuleID): Option[ModuleID] = { val excluded = exclude getOrElse (restrictedCopy(m, false), Set.empty) val included = classifiers filterNot excluded @@ -330,12 +302,12 @@ object IvyActions { * }}} * `usage.getDependencyIncludesSet` returns null if there are no (explicit) include rules. */ - private def intransitiveModuleWithExplicitArts(module: ModuleID, arts: Seq[Artifact]): ModuleID = - module.copy(isTransitive = false, explicitArtifacts = arts, inclusions = InclExclRule.everything :: Nil) + private def intransitiveModuleWithExplicitArts(module: ModuleID, arts: Vector[Artifact]): ModuleID = + module.withIsTransitive(false).withExplicitArtifacts(arts).withInclusions(Vector(InclExclRule.everything)) - def addExcluded(report: UpdateReport, classifiers: Seq[String], exclude: Map[ModuleID, Set[String]]): UpdateReport = + def addExcluded(report: UpdateReport, classifiers: Vector[String], exclude: Map[ModuleID, Set[String]]): UpdateReport = report.addMissing { id => classifiedArtifacts(id.name, classifiers filter getExcluded(id, exclude)) } - def classifiedArtifacts(name: String, classifiers: Seq[String]): Seq[Artifact] = + def classifiedArtifacts(name: String, classifiers: Vector[String]): Vector[Artifact] = classifiers map { c => Artifact.classified(name, c) } private[this] def getExcluded(id: ModuleID, exclude: Map[ModuleID, Set[String]]): Set[String] = exclude.getOrElse(restrictedCopy(id, false), Set.empty[String]) @@ -344,10 +316,10 @@ object IvyActions { report.allMissing flatMap { case (_, mod, art) => art.classifier.map { c => (restrictedCopy(mod, false), c) } } groupBy (_._1) map { case (mod, pairs) => (mod, pairs.map(_._2).toSet) } private[this] def restrictedCopy(m: ModuleID, confs: Boolean) = - ModuleID(m.organization, m.name, m.revision, crossVersion = m.crossVersion, extraAttributes = m.extraAttributes, configurations = if (confs) m.configurations else None) + ModuleID(m.organization, m.name, m.revision).withCrossVersion(m.crossVersion).withExtraAttributes(m.extraAttributes).withConfigurations(if (confs) m.configurations else None) .branch(m.branchName) - private[this] def resolve(logging: UpdateLogging.Value)(ivy: Ivy, module: DefaultModuleDescriptor, defaultConf: String, filter: ArtifactTypeFilter): (ResolveReport, Option[ResolveException]) = + private[this] def resolve(logging: UpdateLogging)(ivy: Ivy, module: DefaultModuleDescriptor, defaultConf: String, filter: ArtifactTypeFilter): (ResolveReport, Option[ResolveException]) = { val resolveOptions = new ResolveOptions val resolveId = ResolveOptions.getDefaultResolveId(module) @@ -420,7 +392,7 @@ object IvyActions { import UpdateLogging.{ Quiet, Full, DownloadOnly, Default } import LogOptions.{ LOG_QUIET, LOG_DEFAULT, LOG_DOWNLOAD_ONLY } - private def ivyLogLevel(level: UpdateLogging.Value) = + private def ivyLogLevel(level: UpdateLogging) = level match { case Quiet => LOG_QUIET case DownloadOnly => LOG_DOWNLOAD_ONLY diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyCache.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyCache.scala index ba3d97912..0c1c1f969 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyCache.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyCache.scala @@ -15,6 +15,14 @@ import sbt.io.Path import sbt.util.Logger import sbt.librarymanagement._ +import sbt.internal.util.{ CacheStore, FileBasedStore } + +import scala.json.ast.unsafe._ +import scala.collection.mutable +import jawn.{ SupportParser, MutableFacade } +import sjsonnew.IsoString +import sjsonnew.support.scalajson.unsafe.{ CompactPrinter, Converter } + class NotInCache(val id: ModuleID, cause: Throwable) extends RuntimeException(NotInCache(id, cause), cause) { def this(id: ModuleID) = this(id, null) @@ -27,7 +35,9 @@ private object NotInCache { } } /** Provides methods for working at the level of a single jar file with the default Ivy cache.*/ -class IvyCache(val ivyHome: Option[File]) { +class IvyCache(val ivyHome: Option[File], fileToStore: File => CacheStore) { + def this(ivyHome: Option[File]) = this(ivyHome, DefaultFileToStore) + def lockFile = new File(ivyHome getOrElse Path.userHome, ".sbt.cache.lock") /** Caches the given 'file' with the given ID. It may be retrieved or cleared using this ID.*/ def cacheJar(moduleID: ModuleID, file: File, lock: Option[xsbti.GlobalLock], log: Logger): Unit = { @@ -81,8 +91,8 @@ class IvyCache(val ivyHome: Option[File]) { { val local = Resolver.defaultLocal val paths = new IvyPaths(new File("."), ivyHome) - val conf = new InlineIvyConfiguration(paths, Seq(local), Nil, Nil, false, lock, IvySbt.DefaultChecksums, None, UpdateOptions(), log) - (new IvySbt(conf), local) + val conf = new InlineIvyConfiguration(paths, Vector(local), Vector.empty, Vector.empty, false, lock, IvySbt.DefaultChecksums, None, UpdateOptions(), log) + (new IvySbt(conf, fileToStore), local) } /** Creates a default jar artifact based on the given ID.*/ private def defaultArtifact(moduleID: ModuleID): IvyArtifact = @@ -98,3 +108,31 @@ private class FileDownloader extends ResourceDownloader { sys.error("Could not move temporary file " + part + " to final location " + dest) } } + +object FixedParser extends SupportParser[JValue] { + implicit val facade: MutableFacade[JValue] = + new MutableFacade[JValue] { + def jnull() = JNull + def jfalse() = JFalse + def jtrue() = JTrue + def jnum(s: String) = JNumber(s) + def jint(s: String) = JNumber(s) + def jstring(s: String) = JString(s) + def jarray(vs: mutable.ArrayBuffer[JValue]) = JArray(vs.toArray) + def jobject(vs: mutable.Map[String, JValue]) = { + val array = new Array[JField](vs.size) + var i = 0 + vs.foreach { + case (key, value) => + array(i) = JField(key, value) + i += 1 + } + JObject(array) + } + } +} + +object DefaultFileToStore extends (File => CacheStore) { + private implicit lazy val isoString: IsoString[JValue] = IsoString.iso(CompactPrinter.apply _, FixedParser.parseUnsafe _) + override def apply(f: File): CacheStore = new FileBasedStore(f, Converter) +} diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyConfigurations.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyConfigurations.scala index 7602f0de9..74bdde758 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyConfigurations.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyConfigurations.scala @@ -3,206 +3,9 @@ */ package sbt.internal.librarymanagement -import java.io.File -import java.net.URI -import scala.xml.NodeSeq -import sbt.util.Logger import sbt.librarymanagement._ -final class IvyPaths(val baseDirectory: File, val ivyHome: Option[File]) { - def withBase(newBaseDirectory: File) = new IvyPaths(newBaseDirectory, ivyHome) - override def toString = s"IvyPaths($baseDirectory, $ivyHome)" -} -sealed trait IvyConfiguration { - type This <: IvyConfiguration - def lock: Option[xsbti.GlobalLock] - def baseDirectory: File - def log: Logger - def withBase(newBaseDirectory: File): This - def updateOptions: UpdateOptions -} -final class InlineIvyConfiguration(val paths: IvyPaths, val resolvers: Seq[Resolver], val otherResolvers: Seq[Resolver], - val moduleConfigurations: Seq[ModuleConfiguration], val localOnly: Boolean, val lock: Option[xsbti.GlobalLock], - val checksums: Seq[String], val resolutionCacheDir: Option[File], val updateOptions: UpdateOptions, - val log: Logger) extends IvyConfiguration { - @deprecated("Use the variant that accepts resolutionCacheDir and updateOptions.", "0.13.0") - def this(paths: IvyPaths, resolvers: Seq[Resolver], otherResolvers: Seq[Resolver], - moduleConfigurations: Seq[ModuleConfiguration], localOnly: Boolean, lock: Option[xsbti.GlobalLock], - checksums: Seq[String], log: Logger) = - this(paths, resolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums, None, UpdateOptions(), log) - - @deprecated("Use the variant that accepts updateOptions.", "0.13.6") - def this(paths: IvyPaths, resolvers: Seq[Resolver], otherResolvers: Seq[Resolver], - moduleConfigurations: Seq[ModuleConfiguration], localOnly: Boolean, lock: Option[xsbti.GlobalLock], - checksums: Seq[String], resolutionCacheDir: Option[File], log: Logger) = - this(paths, resolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums, resolutionCacheDir, UpdateOptions(), log) - - override def toString: String = s"InlineIvyConfiguration($paths, $resolvers, $otherResolvers, " + - s"$moduleConfigurations, $localOnly, $checksums, $resolutionCacheDir, $updateOptions)" - - type This = InlineIvyConfiguration - def baseDirectory = paths.baseDirectory - def withBase(newBase: File) = new InlineIvyConfiguration(paths.withBase(newBase), resolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums, - resolutionCacheDir, updateOptions, log) - def changeResolvers(newResolvers: Seq[Resolver]) = new InlineIvyConfiguration(paths, newResolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums, - resolutionCacheDir, updateOptions, log) - - override def equals(o: Any): Boolean = o match { - case o: InlineIvyConfiguration => - this.paths == o.paths && - this.resolvers == o.resolvers && - this.otherResolvers == o.otherResolvers && - this.moduleConfigurations == o.moduleConfigurations && - this.localOnly == o.localOnly && - this.checksums == o.checksums && - this.resolutionCacheDir == o.resolutionCacheDir && - this.updateOptions == o.updateOptions - case _ => false - } - - override def hashCode: Int = - { - var hash = 1 - hash = hash * 31 + this.paths.## - hash = hash * 31 + this.resolvers.## - hash = hash * 31 + this.otherResolvers.## - hash = hash * 31 + this.moduleConfigurations.## - hash = hash * 31 + this.localOnly.## - hash = hash * 31 + this.checksums.## - hash = hash * 31 + this.resolutionCacheDir.## - hash = hash * 31 + this.updateOptions.## - hash - } -} -final class ExternalIvyConfiguration(val baseDirectory: File, val uri: URI, val lock: Option[xsbti.GlobalLock], - val extraResolvers: Seq[Resolver], val updateOptions: UpdateOptions, val log: Logger) extends IvyConfiguration { - @deprecated("Use the variant that accepts updateOptions.", "0.13.6") - def this(baseDirectory: File, uri: URI, lock: Option[xsbti.GlobalLock], extraResolvers: Seq[Resolver], log: Logger) = - this(baseDirectory, uri, lock, extraResolvers, UpdateOptions(), log) - - type This = ExternalIvyConfiguration - def withBase(newBase: File) = new ExternalIvyConfiguration(newBase, uri, lock, extraResolvers, UpdateOptions(), log) -} -object ExternalIvyConfiguration { - def apply(baseDirectory: File, file: File, lock: Option[xsbti.GlobalLock], log: Logger) = new ExternalIvyConfiguration(baseDirectory, file.toURI, lock, Nil, UpdateOptions(), log) -} - -object IvyConfiguration { - /** - * Called to configure Ivy when inline resolvers are not specified. - * This will configure Ivy with an 'ivy-settings.xml' file if there is one or else use default resolvers. - */ - @deprecated("Explicitly use either external or inline configuration.", "0.12.0") - def apply(paths: IvyPaths, lock: Option[xsbti.GlobalLock], localOnly: Boolean, checksums: Seq[String], log: Logger): IvyConfiguration = - { - log.debug("Autodetecting configuration.") - val defaultIvyConfigFile = IvySbt.defaultIvyConfiguration(paths.baseDirectory) - if (defaultIvyConfigFile.canRead) - ExternalIvyConfiguration(paths.baseDirectory, defaultIvyConfigFile, lock, log) - else - new InlineIvyConfiguration(paths, Resolver.withDefaultResolvers(Nil), Nil, Nil, localOnly, lock, checksums, None, log) - } -} - -sealed trait ModuleSettings { - def validate: Boolean - def ivyScala: Option[IvyScala] - def noScala: ModuleSettings -} -final case class IvyFileConfiguration(file: File, ivyScala: Option[IvyScala], validate: Boolean, autoScalaTools: Boolean = true) extends ModuleSettings { - def noScala = copy(ivyScala = None) -} -final case class PomConfiguration(file: File, ivyScala: Option[IvyScala], validate: Boolean, autoScalaTools: Boolean = true) extends ModuleSettings { - def noScala = copy(ivyScala = None) -} - -final class InlineConfiguration private[sbt] ( - val module: ModuleID, - val moduleInfo: ModuleInfo, - val dependencies: Seq[ModuleID], - val overrides: Set[ModuleID], - val excludes: Seq[SbtExclusionRule], - val ivyXML: NodeSeq, - val configurations: Seq[Configuration], - val defaultConfiguration: Option[Configuration], - val ivyScala: Option[IvyScala], - val validate: Boolean, - val conflictManager: ConflictManager -) extends ModuleSettings { - def withConfigurations(configurations: Seq[Configuration]) = copy(configurations = configurations) - def noScala = copy(ivyScala = None) - def withOverrides(overrides: Set[ModuleID]): ModuleSettings = - copy(overrides = overrides) - - private[sbt] def copy( - module: ModuleID = this.module, - moduleInfo: ModuleInfo = this.moduleInfo, - dependencies: Seq[ModuleID] = this.dependencies, - overrides: Set[ModuleID] = this.overrides, - excludes: Seq[SbtExclusionRule] = this.excludes, - ivyXML: NodeSeq = this.ivyXML, - configurations: Seq[Configuration] = this.configurations, - defaultConfiguration: Option[Configuration] = this.defaultConfiguration, - ivyScala: Option[IvyScala] = this.ivyScala, - validate: Boolean = this.validate, - conflictManager: ConflictManager = this.conflictManager - ): InlineConfiguration = - InlineConfiguration(module, moduleInfo, dependencies, overrides, excludes, ivyXML, - configurations, defaultConfiguration, ivyScala, validate, conflictManager) - - override def toString: String = - s"InlineConfiguration($module, $moduleInfo, $dependencies, $overrides, $excludes, " + - s"$ivyXML, $configurations, $defaultConfiguration, $ivyScala, $validate, $conflictManager)" - - override def equals(o: Any): Boolean = o match { - case o: InlineConfiguration => - this.module == o.module && - this.moduleInfo == o.moduleInfo && - this.dependencies == o.dependencies && - this.overrides == o.overrides && - this.excludes == o.excludes && - this.ivyXML == o.ivyXML && - this.configurations == o.configurations && - this.defaultConfiguration == o.defaultConfiguration && - this.ivyScala == o.ivyScala && - this.validate == o.validate && - this.conflictManager == o.conflictManager - case _ => false - } - - override def hashCode: Int = - { - var hash = 1 - hash = hash * 31 + this.module.## - hash = hash * 31 + this.dependencies.## - hash = hash * 31 + this.overrides.## - hash = hash * 31 + this.excludes.## - hash = hash * 31 + this.ivyXML.## - hash = hash * 31 + this.configurations.## - hash = hash * 31 + this.defaultConfiguration.## - hash = hash * 31 + this.ivyScala.## - hash = hash * 31 + this.validate.## - hash = hash * 31 + this.conflictManager.## - hash - } -} -object InlineConfiguration { - def apply( - module: ModuleID, - moduleInfo: ModuleInfo, - dependencies: Seq[ModuleID], - overrides: Set[ModuleID] = Set.empty, - excludes: Seq[SbtExclusionRule] = Nil, - ivyXML: NodeSeq = NodeSeq.Empty, - configurations: Seq[Configuration] = Nil, - defaultConfiguration: Option[Configuration] = None, - ivyScala: Option[IvyScala] = None, - validate: Boolean = false, - conflictManager: ConflictManager = ConflictManager.default - ): InlineConfiguration = - new InlineConfiguration(module, moduleInfo, dependencies, overrides, excludes, ivyXML, - configurations, defaultConfiguration, ivyScala, validate, conflictManager) - +abstract class InlineConfigurationFunctions { def configurations(explicitConfigurations: Iterable[Configuration], defaultConfiguration: Option[Configuration]) = if (explicitConfigurations.isEmpty) { defaultConfiguration match { diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyRetrieve.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyRetrieve.scala index b9917e1ad..6f0a7d42e 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyRetrieve.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyRetrieve.scala @@ -17,10 +17,10 @@ import sbt.librarymanagement._ import sbt.internal.librarymanagement.syntax._ object IvyRetrieve { - def reports(report: ResolveReport): Seq[ConfigurationResolveReport] = - report.getConfigurations map report.getConfigurationReport + def reports(report: ResolveReport): Vector[ConfigurationResolveReport] = + report.getConfigurations.toVector map report.getConfigurationReport - def moduleReports(confReport: ConfigurationResolveReport): Seq[ModuleReport] = + def moduleReports(confReport: ConfigurationResolveReport): Vector[ModuleReport] = for { revId <- confReport.getModuleRevisionIds.toArray.toVector collect { case revId: ModuleRevisionId => revId } } yield moduleRevisionDetail(confReport, confReport.getDependency(revId)) @@ -32,7 +32,7 @@ object IvyRetrieve { ModuleReport(mid, resolved, missing) } - private[sbt] def artifacts(mid: ModuleID, artReport: Seq[ArtifactDownloadReport]): (Seq[(Artifact, File)], Seq[Artifact]) = + private[sbt] def artifacts(mid: ModuleID, artReport: Seq[ArtifactDownloadReport]): (Vector[(Artifact, File)], Vector[Artifact]) = { val missing = new mutable.ListBuffer[Artifact] val resolved = new mutable.ListBuffer[(Artifact, File)] @@ -44,13 +44,13 @@ object IvyRetrieve { case None => missing += art } } - (resolved.toSeq, missing.toSeq) + (resolved.toVector, missing.toVector) } // We need this because current module report used as part of UpdateReport/ConfigurationReport contains // only the revolved modules. // Sometimes the entire module can be excluded via rules etc. - private[sbt] def organizationArtifactReports(confReport: ConfigurationResolveReport): Seq[OrganizationArtifactReport] = { + private[sbt] def organizationArtifactReports(confReport: ConfigurationResolveReport): Vector[OrganizationArtifactReport] = { val moduleIds = confReport.getModuleIds.toArray.toVector collect { case mId: IvyModuleId => mId } def organizationArtifact(mid: IvyModuleId): OrganizationArtifactReport = { val deps = confReport.getNodes(mid).toArray.toVector collect { case node: IvyNode => node } @@ -130,14 +130,14 @@ object IvyRetrieve { case _ => dep.getResolvedId.getExtraAttributes }) val isDefault = Option(dep.getDescriptor) map { _.isDefault } - val configurations = dep.getConfigurations(confReport.getConfiguration).toList - val licenses: Seq[(String, Option[String])] = mdOpt match { + val configurations = dep.getConfigurations(confReport.getConfiguration).toVector + val licenses: Vector[(String, Option[String])] = mdOpt match { case Some(md) => md.getLicenses.toVector collect { case lic: IvyLicense if Option(lic.getName).isDefined => val temporaryURL = "http://localhost" (lic.getName, nonEmptyString(lic.getUrl) orElse { Some(temporaryURL) }) } - case _ => Nil + case _ => Vector.empty } val callers = dep.getCallers(confReport.getConfiguration).toVector map { toCaller } val (resolved, missing) = artifacts(moduleId, confReport getDownloadReports revId) @@ -151,13 +151,13 @@ object IvyRetrieve { confReport.getEvictedNodes.map(node => toModuleID(node.getId)) def toModuleID(revID: ModuleRevisionId): ModuleID = - ModuleID(revID.getOrganisation, revID.getName, revID.getRevision, extraAttributes = IvySbt.getExtraAttributes(revID)) + ModuleID(revID.getOrganisation, revID.getName, revID.getRevision).withExtraAttributes(IvySbt.getExtraAttributes(revID)) .branch(nonEmptyString(revID.getBranch)) def toArtifact(art: IvyArtifact): Artifact = { import art._ - Artifact(getName, getType, getExt, Option(getExtraAttribute("classifier")), getConfigurations map Configurations.config, Option(getUrl)) + Artifact(getName, getType, getExt, Option(getExtraAttribute("classifier")), getConfigurations.toVector map Configurations.config, Option(getUrl)) } def updateReport(report: ResolveReport, cachedDescriptor: File): UpdateReport = diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/JsonUtil.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/JsonUtil.scala index 69a6fa282..7be87317a 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/JsonUtil.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/JsonUtil.scala @@ -3,18 +3,22 @@ package sbt.internal.librarymanagement import java.io.File import org.apache.ivy.core import core.module.descriptor.ModuleDescriptor -import sbt.serialization._ import sbt.util.Logger +import sbt.internal.util.CacheStore import sbt.librarymanagement._ +import sbt.librarymanagement.LibraryManagementCodec._ +import JsonUtil._ private[sbt] object JsonUtil { def sbtOrgTemp = "org.scala-sbt.temp" def fakeCallerOrganization = "org.scala-sbt.temp-callers" +} +private[sbt] class JsonUtil(fileToStore: File => CacheStore) { def parseUpdateReport(md: ModuleDescriptor, path: File, cachedDescriptor: File, log: Logger): UpdateReport = { try { - val lite = fromJsonFile[UpdateReportLite](path).get + val lite = fileToStore(path).read[UpdateReportLite] fromLite(lite, cachedDescriptor) } catch { case e: Throwable => @@ -25,7 +29,7 @@ private[sbt] object JsonUtil { def writeUpdateReport(ur: UpdateReport, graphPath: File): Unit = { sbt.io.IO.createDirectory(graphPath.getParentFile) - toJsonFile(toLite(ur), graphPath) + fileToStore(graphPath).write(toLite(ur)) } def toLite(ur: UpdateReport): UpdateReportLite = UpdateReportLite(ur.configurations map { cr => @@ -44,7 +48,7 @@ private[sbt] object JsonUtil { }) // #1763/#2030. Caller takes up 97% of space, so we need to shrink it down, // but there are semantics associated with some of them. - def filterOutArtificialCallers(callers: Seq[Caller]): Seq[Caller] = + def filterOutArtificialCallers(callers: Vector[Caller]): Vector[Caller] = if (callers.isEmpty) callers else { val nonArtificial = callers filter { c => @@ -53,8 +57,8 @@ private[sbt] object JsonUtil { } val interProj = (callers find { c => c.caller.organization == sbtOrgTemp - }).toList - interProj ::: nonArtificial.toList + }).toVector + interProj ++ nonArtificial } def fromLite(lite: UpdateReportLite, cachedDescriptor: File): UpdateReport = @@ -72,13 +76,3 @@ private[sbt] object JsonUtil { new UpdateReport(cachedDescriptor, configReports, stats, Map.empty) } } - -private[sbt] case class UpdateReportLite(configurations: Seq[ConfigurationReportLite]) -private[sbt] object UpdateReportLite { - implicit val pickler: Pickler[UpdateReportLite] with Unpickler[UpdateReportLite] = PicklerUnpickler.generate[UpdateReportLite] -} - -private[sbt] case class ConfigurationReportLite(configuration: String, details: Seq[OrganizationArtifactReport]) -private[sbt] object ConfigurationReportLite { - implicit val pickler: Pickler[ConfigurationReportLite] with Unpickler[ConfigurationReportLite] = PicklerUnpickler.generate[ConfigurationReportLite] -} diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/RichUpdateReport.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/RichUpdateReport.scala index db283b6c7..8b9f82922 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/RichUpdateReport.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/RichUpdateReport.scala @@ -35,18 +35,16 @@ final class RichUpdateReport(report: UpdateReport) { /** Constructs a new report that only contains files matching the specified filter.*/ private[sbt] def filter(f: DependencyFilter): UpdateReport = moduleReportMap { (configuration, modReport) => - modReport.copy( - artifacts = modReport.artifacts filter { case (art, file) => f(configuration, modReport.module, art) }, - missingArtifacts = modReport.missingArtifacts filter { art => f(configuration, modReport.module, art) } - ) + modReport + .withArtifacts(modReport.artifacts filter { case (art, file) => f(configuration, modReport.module, art) }) + .withMissingArtifacts(modReport.missingArtifacts filter { art => f(configuration, modReport.module, art) }) } - def substitute(f: (String, ModuleID, Seq[(Artifact, File)]) => Seq[(Artifact, File)]): UpdateReport = + def substitute(f: (String, ModuleID, Vector[(Artifact, File)]) => Vector[(Artifact, File)]): UpdateReport = moduleReportMap { (configuration, modReport) => val newArtifacts = f(configuration, modReport.module, modReport.artifacts) - modReport.copy( - artifacts = newArtifacts, - missingArtifacts = modReport.missingArtifacts - ) + modReport + .withArtifacts(newArtifacts) + .withMissingArtifacts(modReport.missingArtifacts) } def toSeq: Seq[(String, ModuleID, Artifact, File)] = @@ -57,9 +55,8 @@ final class RichUpdateReport(report: UpdateReport) { def addMissing(f: ModuleID => Seq[Artifact]): UpdateReport = moduleReportMap { (configuration, modReport) => - modReport.copy( - missingArtifacts = (modReport.missingArtifacts ++ f(modReport.module)).distinct - ) + modReport + .withMissingArtifacts((modReport.missingArtifacts ++ f(modReport.module)).distinct) } def moduleReportMap(f: (String, ModuleReport) => ModuleReport): UpdateReport = diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/SbtExclusionRule.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/SbtExclusionRule.scala deleted file mode 100644 index 76e74dcd4..000000000 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/SbtExclusionRule.scala +++ /dev/null @@ -1,52 +0,0 @@ -package sbt.internal.librarymanagement - -import impl.{ GroupID, GroupArtifactID } -import sbt.librarymanagement._ - -final class SbtExclusionRule( - val organization: String, - val name: String, - val artifact: String, - val configurations: Seq[String], - val crossVersion: CrossVersion -) { - - def copy( - organization: String = this.organization, - name: String = this.name, - artifact: String = this.artifact, - configurations: Seq[String] = this.configurations, - crossVersion: CrossVersion = this.crossVersion - ): SbtExclusionRule = - SbtExclusionRule( - organization = organization, - name = name, - artifact = artifact, - configurations = configurations, - crossVersion = crossVersion - ) -} - -object SbtExclusionRule { - def apply(organization: String): SbtExclusionRule = - new SbtExclusionRule(organization, "*", "*", Nil, CrossVersion.Disabled) - - def apply(organization: String, name: String): SbtExclusionRule = - new SbtExclusionRule(organization, name, "*", Nil, CrossVersion.Disabled) - - def apply( - organization: String, - name: String, - artifact: String, - configurations: Seq[String], - crossVersion: CrossVersion - ): SbtExclusionRule = - new SbtExclusionRule(organization, name, artifact, configurations, crossVersion) - - implicit def groupIdToExclusionRule(organization: GroupID): SbtExclusionRule = - SbtExclusionRule(organization.groupID) - implicit def stringToExclusionRule(organization: String): SbtExclusionRule = - SbtExclusionRule(organization) - implicit def groupArtifactIDToExcludsionRule(gaid: GroupArtifactID): SbtExclusionRule = - SbtExclusionRule(gaid.groupID, gaid.artifactID, "*", Nil, gaid.crossVersion) -} diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/DateFormat.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/DateFormat.scala new file mode 100644 index 000000000..337ff3bd8 --- /dev/null +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/DateFormat.scala @@ -0,0 +1,11 @@ +package sbt.internal.librarymanagement.formats + +import sjsonnew._ +import java.util._ +import java.text._ + +trait DateFormat { self: BasicJsonProtocol => + private val format = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy") + + implicit lazy val DateFormat: JsonFormat[Date] = project(_.toString, format.parse _) +} diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/DependencyResolverFormat.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/DependencyResolverFormat.scala new file mode 100644 index 000000000..e365b961b --- /dev/null +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/DependencyResolverFormat.scala @@ -0,0 +1,8 @@ +package sbt.internal.librarymanagement.formats + +import sjsonnew._ +import org.apache.ivy.plugins.resolver.DependencyResolver + +trait DependencyResolverFormat { self: BasicJsonProtocol => + implicit lazy val DependencyResolverFormat: JsonFormat[DependencyResolver] = ??? +} diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/GlobalLockFormat.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/GlobalLockFormat.scala new file mode 100644 index 000000000..2f4342d24 --- /dev/null +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/GlobalLockFormat.scala @@ -0,0 +1,8 @@ +package sbt.internal.librarymanagement.formats + +import sjsonnew._ +import xsbti._ + +trait GlobalLockFormat { self: BasicJsonProtocol => + implicit lazy val GlobalLockFormat: JsonFormat[GlobalLock] = ??? +} diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/LoggerFormat.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/LoggerFormat.scala new file mode 100644 index 000000000..b751672bd --- /dev/null +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/LoggerFormat.scala @@ -0,0 +1,8 @@ +package sbt.internal.librarymanagement.formats + +import sjsonnew._ +import xsbti._ + +trait LoggerFormat { self: BasicJsonProtocol => + implicit lazy val LoggerFormat: JsonFormat[Logger] = ??? +} diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/NodeSeqFormat.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/NodeSeqFormat.scala new file mode 100644 index 000000000..ad527c35d --- /dev/null +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/NodeSeqFormat.scala @@ -0,0 +1,8 @@ +package sbt.internal.librarymanagement.formats + +import sjsonnew._ +import scala.xml._ + +trait NodeSeqFormat { self: BasicJsonProtocol => + implicit lazy val NodeSeqFormat: JsonFormat[NodeSeq] = ??? +} diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/UpdateOptionsFormat.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/UpdateOptionsFormat.scala new file mode 100644 index 000000000..e5e8b6e63 --- /dev/null +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/UpdateOptionsFormat.scala @@ -0,0 +1,27 @@ +package sbt.internal.librarymanagement +package formats + +import sjsonnew._ +import sbt.librarymanagement._ + +trait UpdateOptionsFormat { self: BasicJsonProtocol => + + implicit lazy val UpdateOptionsFormat: JsonFormat[UpdateOptions] = + project( + (uo: UpdateOptions) => ( + uo.circularDependencyLevel.name, + uo.interProjectFirst, + uo.latestSnapshots, + uo.consolidatedResolution, + uo.cachedResolution + ), + (xs: (String, Boolean, Boolean, Boolean, Boolean)) => + new UpdateOptions(levels(xs._1), xs._2, xs._3, xs._4, xs._5, ConvertResolver.defaultConvert) + ) + + private val levels: Map[String, CircularDependencyLevel] = Map( + "warn" -> CircularDependencyLevel.Warn, + "ignore" -> CircularDependencyLevel.Ignore, + "error" -> CircularDependencyLevel.Error + ) +} diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/impl/DependencyBuilders.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/impl/DependencyBuilders.scala index 9ceac2da6..6260f5ad6 100755 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/impl/DependencyBuilders.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/impl/DependencyBuilders.scala @@ -26,7 +26,7 @@ trait DependencyBuilders { } final class GroupID private[sbt] (private[sbt] val groupID: String) { - def %(artifactID: String) = groupArtifact(artifactID, CrossVersion.Disabled) + def %(artifactID: String) = groupArtifact(artifactID, Disabled()) def %%(artifactID: String): GroupArtifactID = groupArtifact(artifactID, CrossVersion.binary) private def groupArtifact(artifactID: String, cross: CrossVersion) = @@ -53,7 +53,7 @@ final class ModuleIDConfigurable private[sbt] (moduleID: ModuleID) { { nonEmpty(configurations, "Configurations") val c = configurations - moduleID.copy(configurations = Some(c)) + moduleID.withConfigurations(configurations = Some(c)) } } final class RepositoryName private[sbt] (name: String) { diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/CachedResolutionResolveEngine.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/CachedResolutionResolveEngine.scala index ef9d20209..8c94be6f6 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/CachedResolutionResolveEngine.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/CachedResolutionResolveEngine.scala @@ -24,6 +24,7 @@ import sbt.io.{ DirectoryFilter, Hash, IO } import sbt.util.Logger import sbt.librarymanagement._ import sbt.internal.librarymanagement.syntax._ +import sbt.internal.util.CacheStore private[sbt] object CachedResolutionResolveCache { def createID(organization: String, name: String, revision: String) = @@ -38,8 +39,9 @@ private[sbt] object CachedResolutionResolveCache { lazy val yyyymmdd: SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd") } -private[sbt] class CachedResolutionResolveCache() { +private[sbt] class CachedResolutionResolveCache(fileToStore: File => CacheStore) { import CachedResolutionResolveCache._ + val jsonUtil = new JsonUtil(fileToStore) val updateReportCache: concurrent.Map[ModuleRevisionId, Either[ResolveException, UpdateReport]] = concurrent.TrieMap() // Used for subproject val projectReportCache: concurrent.Map[(ModuleRevisionId, LogicalClock), Either[ResolveException, UpdateReport]] = concurrent.TrieMap() @@ -164,7 +166,7 @@ private[sbt] class CachedResolutionResolveCache() { else None) match { case Some(path) => log.debug(s"parsing ${path.getAbsolutePath.toString}") - val ur = JsonUtil.parseUpdateReport(md, path, cachedDescriptor, log) + val ur = jsonUtil.parseUpdateReport(md, path, cachedDescriptor, log) if (ur.allFiles forall { _.exists }) { updateReportCache(md.getModuleRevisionId) = Right(ur) Some(Right(ur)) @@ -198,7 +200,7 @@ private[sbt] class CachedResolutionResolveCache() { if (changing) { cleanDynamicGraph() } - JsonUtil.writeUpdateReport(ur, gp) + jsonUtil.writeUpdateReport(ur, gp) // limit the update cache size if (updateReportCache.size > maxUpdateReportCacheSize) { updateReportCache.remove(updateReportCache.head._1) @@ -221,7 +223,7 @@ private[sbt] class CachedResolutionResolveCache() { { def reconstructReports(surviving: Vector[ModuleID], evicted: Vector[ModuleID], mgr: String): (Vector[ModuleReport], Vector[ModuleReport]) = { val moduleIdMap = Map(conflicts map { x => x.module -> x }: _*) - (surviving map moduleIdMap, evicted map moduleIdMap map { _.copy(evicted = true, evictedReason = Some(mgr.toString)) }) + (surviving map moduleIdMap, evicted map moduleIdMap map { _.withEvicted(true).withEvictedReason(Some(mgr.toString)) }) } (conflictCache get ((cf0, cf1))) match { case Some((surviving, evicted, mgr)) => reconstructReports(surviving, evicted, mgr) @@ -257,6 +259,9 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { private[sbt] def makeInstance: Ivy private[sbt] val ignoreTransitiveForce: Boolean = true + private[sbt] val fileToStore: File => CacheStore + private val jsonUtil = new JsonUtil(fileToStore) + def withIvy[A](log: Logger)(f: Ivy => A): A = withIvy(new IvyLoggerInterface(log))(f) def withIvy[A](log: MessageLogger)(f: Ivy => A): A = @@ -428,7 +433,7 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { if (mr.evicted || mr.problem.nonEmpty) None else // https://github.com/sbt/sbt/issues/1763 - Some(mr.copy(callers = JsonUtil.filterOutArtificialCallers(mr.callers))) + Some(mr.withCallers(jsonUtil.filterOutArtificialCallers(mr.callers))) } match { case Vector() => None case ms => Some(OrganizationArtifactReport(report0.organization, report0.name, ms)) @@ -504,7 +509,7 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { if (callers.size == callers0.size) mr else { log.debug(s":: $rootModuleConf: removing caller $moduleWithMostCallers -> $next for sorting") - mr.copy(callers = callers) + mr.withCallers(callers) } } OrganizationArtifactReport(oar.organization, oar.name, mrs) @@ -591,18 +596,18 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { * Merges ModuleReports, which represents orgnization, name, and version. * Returns a touple of (surviving modules ++ non-conflicting modules, newly evicted modules). */ - def mergeModuleReports(rootModuleConf: String, modules: Seq[ModuleReport], os: Vector[IvyOverride], log: Logger): (Vector[ModuleReport], Vector[ModuleReport]) = + def mergeModuleReports(rootModuleConf: String, modules: Vector[ModuleReport], os: Vector[IvyOverride], log: Logger): (Vector[ModuleReport], Vector[ModuleReport]) = { if (modules.nonEmpty) { log.debug(s":: merging module reports for $rootModuleConf: ${modules.head.module.organization}:${modules.head.module.name}") } - def mergeModuleReports(org: String, name: String, version: String, xs: Seq[ModuleReport]): ModuleReport = { + def mergeModuleReports(org: String, name: String, version: String, xs: Vector[ModuleReport]): ModuleReport = { val completelyEvicted = xs forall { _.evicted } val allCallers = xs flatMap { _.callers } // Caller info is often repeated across the subprojects. We only need ModuleID info for later, so xs.head is ok. - val distinctByModuleId = allCallers.groupBy({ _.caller }).toList map { case (k, xs) => xs.head } + val distinctByModuleId = allCallers.groupBy({ _.caller }).toVector map { case (k, xs) => xs.head } val allArtifacts = (xs flatMap { _.artifacts }).distinct - xs.head.copy(artifacts = allArtifacts, evicted = completelyEvicted, callers = distinctByModuleId) + xs.head.withArtifacts(allArtifacts).withEvicted(completelyEvicted).withCallers(distinctByModuleId) } val merged = (modules groupBy { m => (m.module.organization, m.module.name, m.module.revision) }).toSeq.toVector flatMap { case ((org, name, version), xs) => @@ -637,7 +642,7 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { } x } - val newlyEvicted = affected map { _.copy(evicted = true, evictedReason = Some("transitive-evict")) } + val newlyEvicted = affected map { _.withEvicted(true).withEvictedReason(Some("transitive-evict")) } if (affected.isEmpty) oar else new OrganizationArtifactReport(organization, name, unaffected ++ newlyEvicted) } @@ -669,7 +674,7 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { }) match { case Some(m) => log.debug(s"- directly forced dependency: $m ${m.callers}") - (Vector(m), conflicts filterNot { _ == m } map { _.copy(evicted = true, evictedReason = Some("direct-force")) }, "direct-force") + (Vector(m), conflicts filterNot { _ == m } map { _.withEvicted(true).withEvictedReason(Some("direct-force")) }, "direct-force") case None => (conflicts find { m => m.callers.exists { _.isForceDependency } @@ -677,13 +682,13 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { // Ivy translates pom.xml dependencies to forced="true", so transitive force is broken. case Some(m) if !ignoreTransitiveForce => log.debug(s"- transitively forced dependency: $m ${m.callers}") - (Vector(m), conflicts filterNot { _ == m } map { _.copy(evicted = true, evictedReason = Some("transitive-force")) }, "transitive-force") + (Vector(m), conflicts filterNot { _ == m } map { _.withEvicted(true).withEvictedReason(Some("transitive-force")) }, "transitive-force") case _ => val strategy = lcm.getStrategy val infos = conflicts map { ModuleReportArtifactInfo(_) } Option(strategy.findLatest(infos.toArray, None.orNull)) match { case Some(ModuleReportArtifactInfo(m)) => - (Vector(m), conflicts filterNot { _ == m } map { _.copy(evicted = true, evictedReason = Some(lcm.toString)) }, lcm.toString) + (Vector(m), conflicts filterNot { _ == m } map { _.withEvicted(true).withEvictedReason(Some(lcm.toString)) }, lcm.toString) case _ => (conflicts, Vector(), lcm.toString) } } @@ -696,7 +701,7 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { mr.module.revision == ovrVersion } match { case Some(m) => - (Vector(m), conflicts filterNot { _ == m } map { _.copy(evicted = true, evictedReason = Some("override")) }, "override") + (Vector(m), conflicts filterNot { _ == m } map { _.withEvicted(true).withEvictedReason(Some("override")) }, "override") case None => sys.error(s"override dependency specifies $ovrVersion but no candidates were found: " + (conflicts map { _.module }).mkString("(", ", ", ")")) } diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/Artifact.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/Artifact.scala index fd9e33bef..e3a2d2793 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/Artifact.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/Artifact.scala @@ -5,22 +5,39 @@ package sbt.librarymanagement import java.io.File import java.net.URL -import sbt.serialization._ -final case class Artifact(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Iterable[Configuration], url: Option[URL], extraAttributes: Map[String, String]) { +abstract class ArtifactExtra { + def name: String + def `type`: String + def extension: String + def classifier: Option[String] + def configurations: Vector[Configuration] + def url: Option[URL] + def extraAttributes: Map[String, String] + + protected[this] def copy( + name: String = name, + `type`: String = `type`, + extension: String = extension, + classifier: Option[String] = classifier, + configurations: Vector[Configuration] = configurations, + url: Option[URL] = url, + extraAttributes: Map[String, String] = extraAttributes + ): Artifact + def extra(attributes: (String, String)*) = copy(extraAttributes = extraAttributes ++ ModuleID.checkE(attributes)) } import Configurations.{ Optional, Pom, Test } -object Artifact { - def apply(name: String): Artifact = Artifact(name, DefaultType, DefaultExtension, None, Nil, None) - def apply(name: String, extra: Map[String, String]): Artifact = Artifact(name, DefaultType, DefaultExtension, None, Nil, None, extra) - def apply(name: String, classifier: String): Artifact = Artifact(name, DefaultType, DefaultExtension, Some(classifier), Nil, None) - def apply(name: String, `type`: String, extension: String): Artifact = Artifact(name, `type`, extension, None, Nil, None) - def apply(name: String, `type`: String, extension: String, classifier: String): Artifact = Artifact(name, `type`, extension, Some(classifier), Nil, None) - def apply(name: String, url: URL): Artifact = Artifact(name, extract(url, DefaultType), extract(url, DefaultExtension), None, Nil, Some(url)) - def apply(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Iterable[Configuration], url: Option[URL]): Artifact = +abstract class ArtifactFunctions { + def apply(name: String, extra: Map[String, String]): Artifact = Artifact(name, DefaultType, DefaultExtension, None, Vector.empty, None, extra) + def apply(name: String, classifier: String): Artifact = Artifact(name, DefaultType, DefaultExtension, Some(classifier), Vector.empty, None) + def apply(name: String, `type`: String, extension: String): Artifact = Artifact(name, `type`, extension, None, Vector.empty, None) + def apply(name: String, `type`: String, extension: String, classifier: String): Artifact = Artifact(name, `type`, extension, Some(classifier), Vector.empty, None) + def apply(name: String, url: URL): Artifact = Artifact(name, extract(url, DefaultType), extract(url, DefaultExtension), None, Vector.empty, Some(url)) + + def apply(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Vector[Configuration], url: Option[URL]): Artifact = Artifact(name, `type`, extension, classifier, configurations, url, Map.empty) val DefaultExtension = "jar" @@ -28,7 +45,7 @@ object Artifact { def sources(name: String) = classified(name, SourceClassifier) def javadoc(name: String) = classified(name, DocClassifier) - def pom(name: String) = Artifact(name, PomType, PomType, None, Pom :: Nil, None) + def pom(name: String) = Artifact(name, PomType, PomType, None, Vector(Pom), None) // Possible ivy artifact types such that sbt will treat those artifacts at sources / docs val DefaultSourceTypes = Set("src", "source", "sources") @@ -62,7 +79,7 @@ object Artifact { val name = file.getName val i = name.lastIndexOf('.') val base = if (i >= 0) name.substring(0, i) else name - Artifact(base, extract(name, DefaultType), extract(name, DefaultExtension), None, Nil, Some(file.toURI.toURL)) + Artifact(base, extract(name, DefaultType), extract(name, DefaultExtension), None, Vector.empty, Some(file.toURI.toURL)) } def artifactName(scalaVersion: ScalaVersion, module: ModuleID, artifact: Artifact): String = { @@ -88,75 +105,5 @@ object Artifact { * The artifact is created under the default configuration. */ def classified(name: String, classifier: String): Artifact = - Artifact(name, classifierType(classifier), DefaultExtension, Some(classifier), Nil, None) - - private val optStringPickler = implicitly[Pickler[Option[String]]] - private val optStringUnpickler = implicitly[Unpickler[Option[String]]] - private val vectorConfigurationPickler = implicitly[Pickler[Vector[Configuration]]] - private val vectorConfigurationUnpickler = implicitly[Unpickler[Vector[Configuration]]] - private val stringStringMapPickler = implicitly[Pickler[Map[String, String]]] - private val stringStringMapUnpickler = implicitly[Unpickler[Map[String, String]]] - - implicit val pickler: Pickler[Artifact] = new Pickler[Artifact] { - val tag = implicitly[FastTypeTag[Artifact]] - val stringTag = implicitly[FastTypeTag[String]] - val optionStringTag = implicitly[FastTypeTag[Option[String]]] - val vectorConfigurationTag = implicitly[FastTypeTag[Vector[Configuration]]] - val stringStringMapTag = implicitly[FastTypeTag[Map[String, String]]] - def pickle(a: Artifact, builder: PBuilder): Unit = { - builder.pushHints() - builder.hintTag(tag) - builder.beginEntry(a) - builder.putField("name", { b => - b.hintTag(stringTag) - stringPickler.pickle(a.name, b) - }) - builder.putField("type", { b => - b.hintTag(stringTag) - stringPickler.pickle(a.`type`, b) - }) - builder.putField("extension", { b => - b.hintTag(stringTag) - stringPickler.pickle(a.extension, b) - }) - builder.putField("classifier", { b => - b.hintTag(optionStringTag) - optStringPickler.pickle(a.classifier, b) - }) - builder.putField("configurations", { b => - b.hintTag(vectorConfigurationTag) - vectorConfigurationPickler.pickle(a.configurations.toVector, b) - }) - builder.putField("url", { b => - b.hintTag(optionStringTag) - optStringPickler.pickle(a.url map { _.toString }, b) - }) - builder.putField("extraAttributes", { b => - b.hintTag(stringStringMapTag) - stringStringMapPickler.pickle(a.extraAttributes, b) - }) - builder.endEntry() - builder.popHints() - () - } - } - implicit val unpickler: Unpickler[Artifact] = new Unpickler[Artifact] { - val tag = implicitly[FastTypeTag[Artifact]] - def unpickle(tpe: String, reader: PReader): Any = { - reader.pushHints() - // reader.hintTag(tag) - reader.beginEntry() - val name = stringPickler.unpickleEntry(reader.readField("name")).asInstanceOf[String] - val tp = stringPickler.unpickleEntry(reader.readField("type")).asInstanceOf[String] - val extension = stringPickler.unpickleEntry(reader.readField("extension")).asInstanceOf[String] - val classifier = optStringUnpickler.unpickleEntry(reader.readField("classifier")).asInstanceOf[Option[String]] - val configurations = vectorConfigurationUnpickler.unpickleEntry(reader.readField("configurations")).asInstanceOf[Vector[Configuration]] - val u = optStringUnpickler.unpickleEntry(reader.readField("url")).asInstanceOf[Option[String]] map { new URL(_) } - val extraAttributes = stringStringMapUnpickler.unpickleEntry(reader.readField("extraAttributes")).asInstanceOf[Map[String, String]] - val result = Artifact(name, tp, extension, classifier, configurations, u, extraAttributes) - reader.endEntry() - reader.popHints() - result - } - } + Artifact(name, classifierType(classifier), DefaultExtension, Some(classifier), Vector.empty, None) } diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/Configuration.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/Configuration.scala index f860d4abc..f0d0fff7f 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/Configuration.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/Configuration.scala @@ -3,8 +3,6 @@ */ package sbt.librarymanagement -import sbt.serialization._ - object Configurations { def config(name: String) = new Configuration(name) def default: Seq[Configuration] = defaultMavenConfigurations @@ -50,18 +48,20 @@ object Configurations { private[sbt] def defaultConfiguration(mavenStyle: Boolean) = if (mavenStyle) Configurations.Compile else Configurations.Default private[sbt] def removeDuplicates(configs: Iterable[Configuration]) = Set(scala.collection.mutable.Map(configs.map(config => (config.name, config)).toSeq: _*).values.toList: _*) } -/** Represents an Ivy configuration. */ -final case class Configuration(name: String, description: String, isPublic: Boolean, extendsConfigs: List[Configuration], transitive: Boolean) { + +abstract class ConfigurationExtra { + def name: String + def description: String + def isPublic: Boolean + def extendsConfigs: Vector[Configuration] + def transitive: Boolean + require(name != null && !name.isEmpty) require(description != null) - def this(name: String) = this(name, "", true, Nil, true) + def describedAs(newDescription: String) = Configuration(name, newDescription, isPublic, extendsConfigs, transitive) - def extend(configs: Configuration*) = Configuration(name, description, isPublic, configs.toList ::: extendsConfigs, transitive) + def extend(configs: Configuration*) = Configuration(name, description, isPublic, configs.toVector ++ extendsConfigs, transitive) def notTransitive = intransitive def intransitive = Configuration(name, description, isPublic, extendsConfigs, false) def hide = Configuration(name, description, false, extendsConfigs, transitive) - override def toString = name -} -object Configuration { - implicit val pickler: Pickler[Configuration] with Unpickler[Configuration] = PicklerUnpickler.generate[Configuration] } diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/CrossVersion.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/CrossVersion.scala index d9869e030..d212e0e0a 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/CrossVersion.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/CrossVersion.scala @@ -1,109 +1,22 @@ package sbt.librarymanagement -import sbt.serialization._ import sbt.internal.librarymanagement.SbtExclusionRule import sbt.internal.librarymanagement.cross.CrossVersionUtil final case class ScalaVersion(full: String, binary: String) -/** Configures how a module will be cross-versioned. */ -sealed trait CrossVersion - -object CrossVersion { +abstract class CrossVersionFunctions { /** The first `major.minor` Scala version that the Scala binary version should be used for cross-versioning instead of the full version. */ val TransitionScalaVersion = CrossVersionUtil.TransitionScalaVersion /** The first `major.minor` sbt version that the sbt binary version should be used for cross-versioning instead of the full version. */ val TransitionSbtVersion = CrossVersionUtil.TransitionSbtVersion - /** Disables cross versioning for a module.*/ - object Disabled extends CrossVersion { override def toString = "disabled" } - - /** - * Cross-versions a module using the result of applying `remapVersion` to the binary version. - * For example, if `remapVersion = v => "2.10"` and the binary version is "2.9.2" or "2.10", - * the module is cross-versioned with "2.10". - */ - final class Binary(val remapVersion: String => String) extends CrossVersion { - override def toString = "Binary" - override def hashCode = remapVersion.## - override def equals(that: Any) = that match { - case that: Binary => this.remapVersion == that.remapVersion - case _ => false - } - } - - /** - * Cross-versions a module with the result of applying `remapVersion` to the full version. - * For example, if `remapVersion = v => "2.10"` and the full version is "2.9.2" or "2.10.3", - * the module is cross-versioned with "2.10". - */ - final class Full(val remapVersion: String => String) extends CrossVersion { - override def toString = "Full" - override def hashCode = remapVersion.## - override def equals(that: Any) = that match { - case that: Full => this.remapVersion == that.remapVersion - case _ => false - } - } - - private val disabledTag = implicitly[FastTypeTag[Disabled.type]] - private val binaryTag = implicitly[FastTypeTag[Binary]] - private val fullTag = implicitly[FastTypeTag[Full]] - implicit val pickler: Pickler[CrossVersion] = new Pickler[CrossVersion] { - val tag = implicitly[FastTypeTag[CrossVersion]] - def pickle(a: CrossVersion, builder: PBuilder): Unit = { - builder.pushHints() - builder.hintTag(a match { - case Disabled => disabledTag - case x: Binary => binaryTag - case x: Full => fullTag - }) - builder.beginEntry(a) - builder.endEntry() - builder.popHints() - () - } - } - implicit val unpickler: Unpickler[CrossVersion] = new Unpickler[CrossVersion] { - val tag = implicitly[FastTypeTag[CrossVersion]] - def unpickle(tpe: String, reader: PReader): Any = { - reader.pushHints() - reader.hintTag(tag) - val tpeStr = reader.beginEntry() - val tpe = scala.pickling.FastTypeTag(tpeStr) - // sys.error(tpe.toString) - val result = tpe match { - case t if t == disabledTag => Disabled - case t if t == binaryTag => binary - case t if t == fullTag => full - } - reader.endEntry() - reader.popHints() - result - } - } - /** Cross-versions a module with the full version (typically the full Scala version). */ - def full: CrossVersion = new Full(idStringFun) - - /** - * Cross-versions a module with the result of applying `remapVersion` to the full version - * (typically the full Scala version). See also [[sbt.librarymanagement.CrossVersion.Full]]. - */ - def fullMapped(remapVersion: String => String): CrossVersion = new Full(remapVersion) + def full: CrossVersion = new Full() /** Cross-versions a module with the binary version (typically the binary Scala version). */ - def binary: CrossVersion = new Binary(idStringFun) - - /** - * Cross-versions a module with the result of applying `remapVersion` to the binary version - * (typically the binary Scala version). See also [[sbt.librarymanagement.CrossVersion.Binary]]. - */ - def binaryMapped(remapVersion: String => String): CrossVersion = new Binary(remapVersion) - - private[this] def idFun[T]: T => T = x => x - private[this] val idStringFun = idFun[String] + def binary: CrossVersion = new Binary() private[sbt] def append(s: String): Option[String => String] = Some(x => crossName(x, s)) @@ -114,9 +27,9 @@ object CrossVersion { */ def apply(cross: CrossVersion, fullVersion: String, binaryVersion: String): Option[String => String] = cross match { - case Disabled => None - case b: Binary => append(b.remapVersion(binaryVersion)) - case f: Full => append(f.remapVersion(fullVersion)) + case _: Disabled => None + case _: Binary => append(binaryVersion) + case _: Full => append(fullVersion) } /** Constructs the cross-version function defined by `module` and `is`, if one is configured. */ @@ -128,7 +41,7 @@ object CrossVersion { is flatMap { i => apply(module, i) } /** Cross-version each `Artifact` in `artifacts` according to cross-version function `cross`. */ - def substituteCross(artifacts: Seq[Artifact], cross: Option[String => String]): Seq[Artifact] = + def substituteCross(artifacts: Vector[Artifact], cross: Option[String => String]): Vector[Artifact] = cross match { case None => artifacts case Some(is) => substituteCrossA(artifacts, cross) @@ -147,14 +60,14 @@ object CrossVersion { private[sbt] def substituteCross(exclude: SbtExclusionRule, is: Option[IvyScala]): SbtExclusionRule = { val fopt: Option[String => String] = is flatMap { i => CrossVersion(exclude.crossVersion, i.scalaFullVersion, i.scalaBinaryVersion) } - exclude.copy(name = applyCross(exclude.name, fopt)) + exclude.withName(applyCross(exclude.name, fopt)) } /** Cross-versions `a` according to cross-version function `cross`. */ def substituteCross(a: Artifact, cross: Option[String => String]): Artifact = - a.copy(name = applyCross(a.name, cross)) + a.withName(applyCross(a.name, cross)) - private[sbt] def substituteCrossA(as: Seq[Artifact], cross: Option[String => String]): Seq[Artifact] = + private[sbt] def substituteCrossA(as: Vector[Artifact], cross: Option[String => String]): Vector[Artifact] = as.map(art => substituteCross(art, cross)) /** @@ -166,7 +79,7 @@ object CrossVersion { { val cross = apply(m.crossVersion, scalaFullVersion, scalaBinaryVersion) if (cross.isDefined) - m.copy(name = applyCross(m.name, cross), explicitArtifacts = substituteCrossA(m.explicitArtifacts, cross)) + m.withName(applyCross(m.name, cross)).withExplicitArtifacts(substituteCrossA(m.explicitArtifacts, cross)) else m } diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/EvictionWarning.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/EvictionWarning.scala index 2c93719ec..dde946c1f 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/EvictionWarning.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/EvictionWarning.scala @@ -88,7 +88,7 @@ final class EvictionPair private[sbt] ( val organization: String, val name: String, val winner: Option[ModuleReport], - val evicteds: Seq[ModuleReport], + val evicteds: Vector[ModuleReport], val includesDirect: Boolean, val showCallers: Boolean ) { @@ -168,7 +168,7 @@ object EvictionWarning { private[sbt] def processEvictions(module: IvySbt#Module, options: EvictionWarningOptions, reports: Seq[OrganizationArtifactReport]): EvictionWarning = { val directDependencies = module.moduleSettings match { case x: InlineConfiguration => x.dependencies - case _ => Seq() + case _ => Vector.empty } val pairs = reports map { detail => val evicteds = detail.modules filter { _.evicted } diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/IvyInterface.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/IvyInterface.scala index 54531bae4..cded9dcb5 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/IvyInterface.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/IvyInterface.scala @@ -3,54 +3,24 @@ */ package sbt.librarymanagement -import java.net.URL import org.apache.ivy.core.module.descriptor import org.apache.ivy.util.filter.{ Filter => IvyFilter } -import sbt.serialization._ -/** Additional information about a project module */ -final case class ModuleInfo(nameFormal: String, description: String = "", homepage: Option[URL] = None, startYear: Option[Int] = None, licenses: Seq[(String, URL)] = Nil, organizationName: String = "", organizationHomepage: Option[URL] = None, scmInfo: Option[ScmInfo] = None, developers: Seq[Developer] = Seq()) { - def this(nameFormal: String, description: String, homepage: Option[URL], startYear: Option[Int], licenses: Seq[(String, URL)], organizationName: String, organizationHomepage: Option[URL], scmInfo: Option[ScmInfo]) = - this(nameFormal, description, homepage, startYear, licenses, organizationName, organizationHomepage, scmInfo, Seq()) - def formally(name: String) = copy(nameFormal = name) - def describing(desc: String, home: Option[URL]) = copy(description = desc, homepage = home) - def licensed(lics: (String, URL)*) = copy(licenses = lics) - def organization(name: String, home: Option[URL]) = copy(organizationName = name, organizationHomepage = home) +abstract class InclExclRuleFunctions { + def everything = new InclExclRule("*", "*", "*", Vector.empty) } -/** Basic SCM information for a project module */ -final case class ScmInfo(browseUrl: URL, connection: String, devConnection: Option[String] = None) +abstract class ArtifactTypeFilterExtra { + def types: Set[String] + def inverted: Boolean -final case class Developer(id: String, name: String, email: String, url: URL) + protected[this] def copy(types: Set[String] = types, inverted: Boolean = inverted): ArtifactTypeFilter -/** - * Rule to either: - * - * Which one depends on the parameter name which it is passed to, but the filter has the same fields in both cases. - */ -final case class InclExclRule(organization: String = "*", name: String = "*", artifact: String = "*", configurations: Seq[String] = Nil) -object InclExclRule { - def everything = InclExclRule("*", "*", "*", Nil) - - implicit val pickler: Pickler[InclExclRule] with Unpickler[InclExclRule] = PicklerUnpickler.generate[InclExclRule] -} - -/** - * Work around the inadequacy of Ivy's ArtifactTypeFilter (that it cannot reverse a filter) - * @param types represents the artifact types that we should try to resolve for (as in the allowed values of - * `artifact[type]` from a dependency `` section). One can use this to filter - * source / doc artifacts. - * @param inverted whether to invert the types filter (i.e. allow only types NOT in the set) - */ -case class ArtifactTypeFilter(types: Set[String], inverted: Boolean) { def invert = copy(inverted = !inverted) def apply(a: descriptor.Artifact): Boolean = (types contains a.getType) ^ inverted } -object ArtifactTypeFilter { +abstract class ArtifactTypeFilterFunctions { def allow(types: Set[String]) = ArtifactTypeFilter(types, false) def forbid(types: Set[String]) = ArtifactTypeFilter(types, true) @@ -59,16 +29,12 @@ object ArtifactTypeFilter { } } -final case class ModuleConfiguration(organization: String, name: String, revision: String, resolver: Resolver) -object ModuleConfiguration { - def apply(org: String, resolver: Resolver): ModuleConfiguration = apply(org, "*", "*", resolver) - def apply(org: String, name: String, resolver: Resolver): ModuleConfiguration = ModuleConfiguration(org, name, "*", resolver) -} +abstract class ConflictManagerFunctions { + // To avoid NPE (or making the val's below lazy) + // For case classes refchecks rewrites apply calls to constructor calls, we have to do it manually + def apply(name: String, organization: String = "*", module: String = "*"): ConflictManager + def ConflictManager(name: String) = apply(name) -final case class ConflictManager(name: String, organization: String = "*", module: String = "*") - -/** See http://ant.apache.org/ivy/history/latest-milestone/settings/conflict-managers.html for details of the different conflict managers.*/ -object ConflictManager { val all = ConflictManager("all") val latestTime = ConflictManager("latest-time") val latestRevision = ConflictManager("latest-revision") diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/IvyScala.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/IvyScala.scala index 8b004ef9d..39ecbace4 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/IvyScala.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/IvyScala.scala @@ -19,7 +19,7 @@ object ScalaArtifacts { val ReflectID = "scala-reflect" val ActorsID = "scala-actors" val ScalapID = "scalap" - val Artifacts = Seq(LibraryID, CompilerID, ReflectID, ActorsID, ScalapID) + val Artifacts = Vector(LibraryID, CompilerID, ReflectID, ActorsID, ScalapID) val DottyIDPrefix = "dotty" def dottyID(binaryVersion: String): String = s"${DottyIDPrefix}_${binaryVersion}" @@ -28,8 +28,8 @@ object ScalaArtifacts { private[sbt] def toolDependencies(org: String, version: String, isDotty: Boolean = false): Seq[ModuleID] = if (isDotty) - Seq(ModuleID(org, DottyIDPrefix, version, Some(Configurations.ScalaTool.name + "->compile"), - crossVersion = CrossVersion.binary)) + Seq(ModuleID(org, DottyIDPrefix, version).withConfigurations(Some(Configurations.ScalaTool.name + "->compile")) + .withCrossVersion(CrossVersion.binary)) else Seq( scalaToolDependency(org, ScalaArtifacts.CompilerID, version), @@ -37,7 +37,7 @@ object ScalaArtifacts { ) private[this] def scalaToolDependency(org: String, id: String, version: String): ModuleID = - ModuleID(org, id, version, Some(Configurations.ScalaTool.name + "->default,optional(default)")) + ModuleID(org, id, version).withConfigurations(Some(Configurations.ScalaTool.name + "->default,optional(default)")) } object SbtArtifacts { val Organization = "org.scala-sbt" @@ -45,9 +45,7 @@ object SbtArtifacts { import ScalaArtifacts._ -final case class IvyScala(scalaFullVersion: String, scalaBinaryVersion: String, configurations: Iterable[Configuration], checkExplicit: Boolean, filterImplicit: Boolean, overrideScalaVersion: Boolean, scalaOrganization: String = ScalaArtifacts.Organization, scalaArtifacts: Seq[String] = ScalaArtifacts.Artifacts) - -private[sbt] object IvyScala { +private[sbt] abstract class IvyScalaFunctions { /** Performs checks/adds filters on Scala dependencies (if enabled in IvyScala). */ def checkModule(module: DefaultModuleDescriptor, conf: String, log: Logger)(check: IvyScala): Unit = { if (check.checkExplicit) diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/ModuleID.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/ModuleID.scala index 2cbf37138..e4f12fd3d 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/ModuleID.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/ModuleID.scala @@ -6,13 +6,37 @@ package sbt.librarymanagement import java.net.URL import sbt.internal.librarymanagement.mavenint.SbtPomExtraProperties -import sbt.serialization._ -final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String] = None, isChanging: Boolean = false, isTransitive: Boolean = true, isForce: Boolean = false, explicitArtifacts: Seq[Artifact] = Nil, inclusions: Seq[InclusionRule] = Nil, exclusions: Seq[ExclusionRule] = Nil, extraAttributes: Map[String, String] = Map.empty, crossVersion: CrossVersion = CrossVersion.Disabled, branchName: Option[String] = None) { - override def toString: String = - organization + ":" + name + ":" + revision + - (configurations match { case Some(s) => ":" + s; case None => "" }) + - (if (extraAttributes.isEmpty) "" else " " + extraString) +abstract class ModuleIDExtra { + def organization: String + def name: String + def revision: String + def configurations: Option[String] + def isChanging: Boolean + def isTransitive: Boolean + def isForce: Boolean + def explicitArtifacts: Vector[Artifact] + def inclusions: Vector[InclusionRule] + def exclusions: Vector[ExclusionRule] + def extraAttributes: Map[String, String] + def crossVersion: CrossVersion + def branchName: Option[String] + + protected[this] def copy( + organization: String = organization, + name: String = name, + revision: String = revision, + configurations: Option[String] = configurations, + isChanging: Boolean = isChanging, + isTransitive: Boolean = isTransitive, + isForce: Boolean = isForce, + explicitArtifacts: Vector[Artifact] = explicitArtifacts, + inclusions: Vector[InclusionRule] = inclusions, + exclusions: Vector[ExclusionRule] = exclusions, + extraAttributes: Map[String, String] = extraAttributes, + crossVersion: CrossVersion = crossVersion, + branchName: Option[String] = branchName + ): ModuleID /** String representation of the extra attributes, excluding any information only attributes. */ def extraString: String = extraDependencyAttributes.map { case (k, v) => k + "=" + v } mkString ("(", ", ", ")") @@ -21,10 +45,7 @@ final case class ModuleID(organization: String, name: String, revision: String, def extraDependencyAttributes: Map[String, String] = extraAttributes.filterKeys(!_.startsWith(SbtPomExtraProperties.POM_INFO_KEY_PREFIX)) @deprecated("Use `cross(CrossVersion)`, the variant accepting a CrossVersion value constructed by a member of the CrossVersion object instead.", "0.12.0") - def cross(v: Boolean): ModuleID = cross(if (v) CrossVersion.binary else CrossVersion.Disabled) - - @deprecated("Use `cross(CrossVersion)`, the variant accepting a CrossVersion value constructed by a member of the CrossVersion object instead.", "0.12.0") - def cross(v: Boolean, verRemap: String => String): ModuleID = cross(if (v) CrossVersion.binaryMapped(verRemap) else CrossVersion.Disabled) + def cross(v: Boolean): ModuleID = cross(if (v) CrossVersion.binary else Disabled()) /** Specifies the cross-version behavior for this module. See [CrossVersion] for details.*/ def cross(v: CrossVersion): ModuleID = copy(crossVersion = v) @@ -64,7 +85,7 @@ final case class ModuleID(organization: String, name: String, revision: String, * Declares the explicit artifacts for this module. If this ModuleID represents a dependency, * these artifact definitions override the information in the dependency's published metadata. */ - def artifacts(newArtifacts: Artifact*) = copy(explicitArtifacts = newArtifacts ++ this.explicitArtifacts) + def artifacts(newArtifacts: Artifact*) = copy(explicitArtifacts = newArtifacts.toVector ++ explicitArtifacts) /** * Applies the provided exclusions to dependencies of this module. Note that only exclusions that specify @@ -73,7 +94,7 @@ final case class ModuleID(organization: String, name: String, revision: String, def excludeAll(rules: InclExclRule*) = copy(exclusions = this.exclusions ++ rules) /** Excludes the dependency with organization `org` and `name` from being introduced by this dependency during resolution. */ - def exclude(org: String, name: String) = excludeAll(InclExclRule(org, name)) + def exclude(org: String, name: String) = excludeAll(InclExclRule().withOrganization(org).withName(name)) /** * Adds extra attributes for this module. All keys are prefixed with `e:` if they are not already so prefixed. @@ -127,9 +148,7 @@ final case class ModuleID(organization: String, name: String, revision: String, def branch(branchName: Option[String]) = copy(branchName = branchName) } -object ModuleID { - implicit val pickler: Pickler[ModuleID] with Unpickler[ModuleID] = PicklerUnpickler.generate[ModuleID] - +abstract class ModuleIDFunctions { /** Prefixes all keys with `e:` if they are not already so prefixed. */ def checkE(attributes: Seq[(String, String)]) = for ((key, value) <- attributes) yield if (key.startsWith("e:")) (key, value) else ("e:" + key, value) diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/Resolver.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/Resolver.scala index 7f2c8779e..75be6d228 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/Resolver.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/Resolver.scala @@ -9,11 +9,7 @@ import scala.xml.XML import org.apache.ivy.plugins.resolver.DependencyResolver import org.xml.sax.SAXParseException -sealed trait Resolver { - def name: String -} -final class RawRepository(val resolver: DependencyResolver) extends Resolver { - def name = resolver.getName +final class RawRepository(val resolver: DependencyResolver) extends Resolver(resolver.getName) { override def toString = "Raw(" + resolver.toString + ")" override def equals(o: Any): Boolean = o match { @@ -29,148 +25,30 @@ final class RawRepository(val resolver: DependencyResolver) extends Resolver { hash } } -sealed case class ChainedResolver(name: String, resolvers: Seq[Resolver]) extends Resolver -/** An instance of a remote maven repository. Note: This will use Aether/Maven to resolve artifacts. */ -sealed case class MavenRepository(name: String, root: String, localIfFile: Boolean = true) extends Resolver { - override def toString = s"$name: $root" - def isCache: Boolean = false - def withLocalIfFile(value: Boolean) = MavenRepository(name, root, value) -} - -/** - * An instance of maven CACHE directory. You cannot treat a cache directory the same as a a remote repository because - * the metadata is different (see Aether ML discussion). - */ -final class MavenCache(name: String, val rootFile: File) extends MavenRepository(name, rootFile.toURI.toURL.toString) { - override val toString = s"cache:$name: ${rootFile.getAbsolutePath}" - override def isCache: Boolean = true -} -object MavenCache { - def apply(name: String, rootFile: File): MavenCache = new MavenCache(name, rootFile) -} - -final class Patterns(val ivyPatterns: Seq[String], val artifactPatterns: Seq[String], val isMavenCompatible: Boolean, val descriptorOptional: Boolean, val skipConsistencyCheck: Boolean) { - private[sbt] def mavenStyle(): Patterns = Patterns(ivyPatterns, artifactPatterns, true) - private[sbt] def withDescriptorOptional(): Patterns = Patterns(ivyPatterns, artifactPatterns, isMavenCompatible, true, skipConsistencyCheck) - private[sbt] def withoutConsistencyCheck(): Patterns = Patterns(ivyPatterns, artifactPatterns, isMavenCompatible, descriptorOptional, true) - private[sbt] def withIvys(patterns: Seq[String]): Patterns = Patterns(patterns ++ ivyPatterns, artifactPatterns, isMavenCompatible) - private[sbt] def withArtifacts(patterns: Seq[String]): Patterns = Patterns(ivyPatterns, patterns ++ artifactPatterns, isMavenCompatible) - override def toString = "Patterns(ivyPatterns=%s, artifactPatterns=%s, isMavenCompatible=%s, descriptorOptional=%s, skipConsistencyCheck=%s)".format(ivyPatterns, artifactPatterns, isMavenCompatible, descriptorOptional, skipConsistencyCheck) - override def equals(obj: Any): Boolean = { - obj match { - case other: Patterns => - ivyPatterns == other.ivyPatterns && artifactPatterns == other.artifactPatterns && isMavenCompatible == other.isMavenCompatible && descriptorOptional == other.descriptorOptional && skipConsistencyCheck == other.skipConsistencyCheck - case _ => false - } - } - override def hashCode: Int = (ivyPatterns, artifactPatterns, isMavenCompatible, descriptorOptional, skipConsistencyCheck).hashCode -} -object Patterns { +abstract class PatternsFunctions { implicit def defaultPatterns: Patterns = Resolver.defaultPatterns def apply(artifactPatterns: String*): Patterns = Patterns(true, artifactPatterns: _*) - def apply(isMavenCompatible: Boolean, artifactPatterns: String*): Patterns = Patterns(artifactPatterns, artifactPatterns, isMavenCompatible) - def apply(ivyPatterns: Seq[String], artifactPatterns: Seq[String], isMavenCompatible: Boolean): Patterns = apply(ivyPatterns: Seq[String], artifactPatterns: Seq[String], isMavenCompatible: Boolean, false, false) - def apply(ivyPatterns: Seq[String], artifactPatterns: Seq[String], isMavenCompatible: Boolean, descriptorOptional: Boolean, skipConsistencyCheck: Boolean): Patterns = new Patterns(ivyPatterns, artifactPatterns, isMavenCompatible, descriptorOptional, skipConsistencyCheck) -} -object RepositoryHelpers { - final case class SshConnection(authentication: Option[SshAuthentication], hostname: Option[String], port: Option[Int]) { - def copy(authentication: Option[SshAuthentication]) = SshConnection(authentication, hostname, port) + def apply(isMavenCompatible: Boolean, artifactPatterns: String*): Patterns = { + val patterns = artifactPatterns.toVector + Patterns().withIvyPatterns(patterns).withArtifactPatterns(patterns).withIsMavenCompatible(isMavenCompatible) } - /** Configuration specific to an Ivy filesystem resolver. */ - final case class FileConfiguration(isLocal: Boolean, isTransactional: Option[Boolean]) { - def transactional() = FileConfiguration(isLocal, Some(true)) - def nontransactional() = FileConfiguration(isLocal, Some(false)) - def nonlocal() = FileConfiguration(false, isTransactional) - } - sealed trait SshAuthentication - final case class PasswordAuthentication(user: String, password: Option[String]) extends SshAuthentication - final case class KeyFileAuthentication(user: String, keyfile: File, password: Option[String]) extends SshAuthentication } -import RepositoryHelpers.{ SshConnection, FileConfiguration } -import RepositoryHelpers.{ KeyFileAuthentication, PasswordAuthentication, SshAuthentication } -/** sbt interface to an Ivy repository based on patterns, which is most Ivy repositories.*/ -sealed abstract class PatternsBasedRepository extends Resolver { - type RepositoryType <: PatternsBasedRepository - /** Should be implemented to create a new copy of this repository but with `patterns` as given.*/ - protected def copy(patterns: Patterns): RepositoryType - - /** The object representing the configured patterns for this repository. */ - def patterns: Patterns - - /** Enables maven 2 compatibility for this repository. */ - def mavenStyle() = copy(patterns.mavenStyle()) - - /** Makes descriptor metadata optional for this repository. */ - def descriptorOptional() = copy(patterns.withDescriptorOptional()) - - /** Disables consistency checking for this repository. */ - def skipConsistencyCheck() = copy(patterns.withoutConsistencyCheck()) - - /** Adds the given patterns for resolving/publishing Ivy files.*/ - def ivys(ivyPatterns: String*): RepositoryType = copy(patterns.withIvys(ivyPatterns)) - /** Adds the given patterns for resolving/publishing artifacts.*/ - def artifacts(artifactPatterns: String*): RepositoryType = copy(patterns.withArtifacts(artifactPatterns)) -} -/** sbt interface for an Ivy filesystem repository. More convenient construction is done using Resolver.file. */ -final case class FileRepository(name: String, configuration: FileConfiguration, patterns: Patterns) extends PatternsBasedRepository { - type RepositoryType = FileRepository - protected def copy(patterns: Patterns): FileRepository = FileRepository(name, configuration, patterns) - private def copy(configuration: FileConfiguration) = FileRepository(name, configuration, patterns) - def transactional() = copy(configuration.transactional()) - def nonlocal() = copy(configuration.nonlocal()) -} -final case class URLRepository(name: String, patterns: Patterns) extends PatternsBasedRepository { - type RepositoryType = URLRepository - protected def copy(patterns: Patterns): URLRepository = URLRepository(name, patterns) -} -/** sbt interface for an Ivy ssh-based repository (ssh and sftp). Requires the Jsch library.. */ -sealed abstract class SshBasedRepository extends PatternsBasedRepository { - type RepositoryType <: SshBasedRepository - protected def copy(connection: SshConnection): RepositoryType - private def copy(authentication: SshAuthentication): RepositoryType = copy(connection.copy(Some(authentication))) - - /** The object representing the configured ssh connection for this repository. */ - def connection: SshConnection - - /** Configures this to use the specified user name and password when connecting to the remote repository. */ - def as(user: String, password: String): RepositoryType = as(user, Some(password)) - def as(user: String): RepositoryType = as(user, None) - def as(user: String, password: Option[String]) = copy(new PasswordAuthentication(user, password)) - /** Configures this to use the specified keyfile and password for the keyfile when connecting to the remote repository. */ - def as(user: String, keyfile: File): RepositoryType = as(user, keyfile, None) - def as(user: String, keyfile: File, password: String): RepositoryType = as(user, keyfile, Some(password)) - def as(user: String, keyfile: File, password: Option[String]): RepositoryType = copy(new KeyFileAuthentication(user, keyfile, password)) -} -/** sbt interface for an Ivy repository over ssh. More convenient construction is done using Resolver.ssh. */ -final case class SshRepository(name: String, connection: SshConnection, patterns: Patterns, publishPermissions: Option[String]) extends SshBasedRepository { - type RepositoryType = SshRepository - protected def copy(patterns: Patterns): SshRepository = SshRepository(name, connection, patterns, publishPermissions) - protected def copy(connection: SshConnection): SshRepository = SshRepository(name, connection, patterns, publishPermissions) - /** Defines the permissions to set when publishing to this repository. */ - def withPermissions(publishPermissions: String): SshRepository = withPermissions(Some(publishPermissions)) - def withPermissions(publishPermissions: Option[String]): SshRepository = SshRepository(name, connection, patterns, publishPermissions) -} -/** sbt interface for an Ivy repository over sftp. More convenient construction is done using Resolver.sftp. */ -final case class SftpRepository(name: String, connection: SshConnection, patterns: Patterns) extends SshBasedRepository { - type RepositoryType = SftpRepository - protected def copy(patterns: Patterns): SftpRepository = SftpRepository(name, connection, patterns) - protected def copy(connection: SshConnection): SftpRepository = SftpRepository(name, connection, patterns) -} /** A repository that conforms to sbt launcher's interface */ private[sbt] class FakeRepository(resolver: DependencyResolver) extends xsbti.Repository { def rawRepository = new RawRepository(resolver) } -import Resolver._ +trait ResolversSyntax { + import Resolver._ + val DefaultMavenRepository = new MavenRepository("public", centralRepositoryRoot(useSecureResolvers)) + val JavaNet2Repository = new MavenRepository(JavaNet2RepositoryName, JavaNet2RepositoryRoot) + val JCenterRepository = new MavenRepository(JCenterRepositoryName, JCenterRepositoryRoot) +} -object DefaultMavenRepository extends MavenRepository("public", centralRepositoryRoot(useSecureResolvers)) -object JavaNet2Repository extends MavenRepository(JavaNet2RepositoryName, JavaNet2RepositoryRoot) -object JCenterRepository extends MavenRepository(JCenterRepositoryName, JCenterRepositoryRoot) - -object Resolver { +abstract class ResolverFunctions { private[sbt] def useSecureResolvers = sys.props.get("sbt.repository.secure") map { _.toLowerCase == "true" } getOrElse true val TypesafeRepositoryRoot = typesafeRepositoryRoot(useSecureResolvers) @@ -342,7 +220,7 @@ object Resolver { /** Resolves the ivy file and artifact patterns in `patterns` against the given base. */ private def resolvePatterns(base: String, basePatterns: Patterns): Patterns = { - def resolveAll(patterns: Seq[String]) = patterns.map(p => resolvePattern(base, p)) + def resolveAll(patterns: Vector[String]) = patterns.map(p => resolvePattern(base, p)) Patterns(resolveAll(basePatterns.ivyPatterns), resolveAll(basePatterns.artifactPatterns), basePatterns.isMavenCompatible, basePatterns.descriptorOptional, basePatterns.skipConsistencyCheck) } private[sbt] def resolvePattern(base: String, pattern: String): String = @@ -351,7 +229,7 @@ object Resolver { if (normBase.endsWith("/") || pattern.startsWith("/")) normBase + pattern else normBase + "/" + pattern } def defaultFileConfiguration = FileConfiguration(true, None) - def mavenStylePatterns = Patterns(Nil, mavenStyleBasePattern :: Nil, true) + def mavenStylePatterns = Patterns().withArtifactPatterns(Vector(mavenStyleBasePattern)) def ivyStylePatterns = defaultIvyPatterns //Patterns(Nil, Nil, false) def defaultPatterns = mavenStylePatterns @@ -381,17 +259,17 @@ object Resolver { } // TODO - should this just be the *exact* same as mavenLocal? probably... def publishMavenLocal: MavenCache = new MavenCache("publish-m2-local", mavenLocalDir) - def mavenLocal: MavenRepository = new MavenCache("Maven2 Local", mavenLocalDir) + def mavenLocal: IMavenRepository = new MavenCache("Maven2 Local", mavenLocalDir) def defaultLocal = defaultUserFileRepository("local") def defaultShared = defaultUserFileRepository("shared") def defaultUserFileRepository(id: String) = { - val pList = s"$${ivy.home}/$id/$localBasePattern" :: Nil - FileRepository(id, defaultFileConfiguration, Patterns(pList, pList, false)) + val pList = Vector(s"$${ivy.home}/$id/$localBasePattern") + FileRepository(id, defaultFileConfiguration, Patterns().withIvyPatterns(pList).withArtifactPatterns(pList).withIsMavenCompatible(false)) } def defaultIvyPatterns = { - val pList = List(localBasePattern) - Patterns(pList, pList, false) + val pList = Vector(localBasePattern) + Patterns().withIvyPatterns(pList).withArtifactPatterns(pList).withIsMavenCompatible(false) } } diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/UpdateReport.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/UpdateReport.scala index 06974aa90..ecc81493b 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/UpdateReport.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/UpdateReport.scala @@ -5,21 +5,13 @@ package sbt.librarymanagement import java.io.File import java.{ util => ju } -import sbt.serialization._ -/** - * Provides information about resolution of a single configuration. - * @param configuration the configuration this report is for. - * @param modules a sequence containing one report for each module resolved for this configuration. - * @param details a sequence containing one report for each org/name, which may or may not be part of the final resolution. - * @param evicted a sequence of evicted modules - */ -final class ConfigurationReport( - val configuration: String, - val modules: Seq[ModuleReport], - val details: Seq[OrganizationArtifactReport] -) { +abstract class ConfigurationReportExtra { + def configuration: String + def modules: Vector[ModuleReport] + def details: Vector[OrganizationArtifactReport] + /** a sequence of evicted modules */ def evicted: Seq[ModuleID] = details flatMap (_.modules) filter (_.evicted) map (_.module) @@ -36,78 +28,36 @@ final class ConfigurationReport( val module = mr.module if (module.configurations.isEmpty) { val conf = mr.configurations map (c => s"$configuration->$c") mkString ";" - module.copy(configurations = Some(conf)) + module.withConfigurations(Some(conf)) } else module } def retrieve(f: (String, ModuleID, Artifact, File) => File): ConfigurationReport = new ConfigurationReport(configuration, modules map { _.retrieve((mid, art, file) => f(configuration, mid, art, file)) }, details) } -object ConfigurationReport { - implicit val pickler: Pickler[ConfigurationReport] with Unpickler[ConfigurationReport] = PicklerUnpickler.generate[ConfigurationReport] -} -/** - * OrganizationArtifactReport represents an organization+name entry in Ivy resolution report. - * In sbt's terminology, "module" consists of organization, name, and version. - * In Ivy's, "module" means just organization and name, and the one including version numbers - * are called revisions. - * - * A sequence of OrganizationArtifactReport called details is newly added to ConfigurationReport, replacing evicted. - * (Note old evicted was just a seq of ModuleIDs). - * OrganizationArtifactReport groups the ModuleReport of both winners and evicted reports by their organization and name, - * which can be used to calculate detailed evction warning etc. - */ -final class OrganizationArtifactReport private[sbt] ( - val organization: String, - val name: String, - val modules: Seq[ModuleReport] -) { - override def toString: String = { - val details = modules map { _.detailReport } - s"\t$organization:$name\n${details.mkString}\n" - } -} -object OrganizationArtifactReport { - implicit val pickler: Pickler[OrganizationArtifactReport] with Unpickler[OrganizationArtifactReport] = PicklerUnpickler.generate[OrganizationArtifactReport] +abstract class ModuleReportExtra { + def module: ModuleID + def artifacts: Vector[(Artifact, File)] + def missingArtifacts: Vector[Artifact] + def status: Option[String] + def publicationDate: Option[ju.Date] + def resolver: Option[String] + def artifactResolver: Option[String] + def evicted: Boolean + def evictedData: Option[String] + def evictedReason: Option[String] + def problem: Option[String] + def homepage: Option[String] + def extraAttributes: Map[String, String] + def isDefault: Option[Boolean] + def branch: Option[String] + def configurations: Vector[String] + def licenses: Vector[(String, Option[String])] + def callers: Vector[Caller] - def apply(organization: String, name: String, modules: Seq[ModuleReport]): OrganizationArtifactReport = - new OrganizationArtifactReport(organization, name, modules) -} + protected[this] def arts: Vector[String] = artifacts.map(_.toString) ++ missingArtifacts.map(art => "(MISSING) " + art) -/** - * Provides information about the resolution of a module. - * This information is in the context of a specific configuration. - * @param module the `ModuleID` this report is for. - * @param artifacts the resolved artifacts for this module, paired with the File the artifact was retrieved to. - * @param missingArtifacts the missing artifacts for this module. - */ -final class ModuleReport( - val module: ModuleID, - val artifacts: Seq[(Artifact, File)], - val missingArtifacts: Seq[Artifact], - val status: Option[String], - val publicationDate: Option[ju.Date], - val resolver: Option[String], - val artifactResolver: Option[String], - val evicted: Boolean, - val evictedData: Option[String], - val evictedReason: Option[String], - val problem: Option[String], - val homepage: Option[String], - val extraAttributes: Map[String, String], - val isDefault: Option[Boolean], - val branch: Option[String], - val configurations: Seq[String], - val licenses: Seq[(String, Option[String])], - val callers: Seq[Caller] -) { - - private[this] lazy val arts: Seq[String] = artifacts.map(_.toString) ++ missingArtifacts.map(art => "(MISSING) " + art) - override def toString: String = { - s"\t\t$module: " + - (if (arts.size <= 1) "" else "\n\t\t\t") + arts.mkString("\n\t\t\t") + "\n" - } def detailReport: String = s"\t\t- ${module.revision}\n" + (if (arts.size <= 1) "" else arts.mkString("\t\t\t", "\n\t\t\t", "\n")) + @@ -148,10 +98,10 @@ final class ModuleReport( def retrieve(f: (ModuleID, Artifact, File) => File): ModuleReport = copy(artifacts = artifacts.map { case (art, file) => (art, f(module, art, file)) }) - private[sbt] def copy( + protected[this] def copy( module: ModuleID = module, - artifacts: Seq[(Artifact, File)] = artifacts, - missingArtifacts: Seq[Artifact] = missingArtifacts, + artifacts: Vector[(Artifact, File)] = artifacts, + missingArtifacts: Vector[Artifact] = missingArtifacts, status: Option[String] = status, publicationDate: Option[ju.Date] = publicationDate, resolver: Option[String] = resolver, @@ -164,66 +114,31 @@ final class ModuleReport( extraAttributes: Map[String, String] = extraAttributes, isDefault: Option[Boolean] = isDefault, branch: Option[String] = branch, - configurations: Seq[String] = configurations, - licenses: Seq[(String, Option[String])] = licenses, - callers: Seq[Caller] = callers - ): ModuleReport = - new ModuleReport(module, artifacts, missingArtifacts, status, publicationDate, resolver, artifactResolver, - evicted, evictedData, evictedReason, problem, homepage, extraAttributes, isDefault, branch, configurations, licenses, callers) + configurations: Vector[String] = configurations, + licenses: Vector[(String, Option[String])] = licenses, + callers: Vector[Caller] = callers + ): ModuleReport } -object ModuleReport { - def apply(module: ModuleID, artifacts: Seq[(Artifact, File)], missingArtifacts: Seq[Artifact]): ModuleReport = - new ModuleReport(module, artifacts, missingArtifacts, None, None, None, None, - false, None, None, None, None, Map(), None, None, Nil, Nil, Nil) - implicit val pickler: Pickler[ModuleReport] with Unpickler[ModuleReport] = PicklerUnpickler.generate[ModuleReport] -} - -final class Caller( - val caller: ModuleID, - val callerConfigurations: Seq[String], - val callerExtraAttributes: Map[String, String], - val isForceDependency: Boolean, - val isChangingDependency: Boolean, - val isTransitiveDependency: Boolean, - val isDirectlyForceDependency: Boolean -) { - override def toString: String = - s"$caller" -} -object Caller { - implicit val pickler: Pickler[Caller] with Unpickler[Caller] = PicklerUnpickler.generate[Caller] -} - -/** - * Provides information about dependency resolution. - * It does not include information about evicted modules, only about the modules ultimately selected by the conflict manager. - * This means that for a given configuration, there should only be one revision for a given organization and module name. - * @param cachedDescriptor the location of the resolved module descriptor in the cache - * @param configurations a sequence containing one report for each configuration resolved. - * @param stats information about the update that produced this report - * @see sbt.RichUpdateReport - */ -final class UpdateReport(val cachedDescriptor: File, val configurations: Seq[ConfigurationReport], val stats: UpdateStats, private[sbt] val stamps: Map[File, Long]) { - @deprecated("Use the variant that provides timestamps of files.", "0.13.0") - def this(cachedDescriptor: File, configurations: Seq[ConfigurationReport], stats: UpdateStats) = - this(cachedDescriptor, configurations, stats, Map.empty) - - override def toString = "Update report:\n\t" + stats + "\n" + configurations.mkString +abstract class UpdateReportExtra { + def cachedDescriptor: File + def configurations: Vector[ConfigurationReport] + def stats: UpdateStats + private[sbt] def stamps: Map[File, Long] /** All resolved modules in all configurations. */ - def allModules: Seq[ModuleID] = + def allModules: Vector[ModuleID] = { val key = (m: ModuleID) => (m.organization, m.name, m.revision) - configurations.flatMap(_.allModules).groupBy(key).toSeq map { + configurations.flatMap(_.allModules).groupBy(key).toVector map { case (k, v) => v reduceLeft { (agg, x) => - agg.copy( - configurations = (agg.configurations, x.configurations) match { - case (None, _) => x.configurations - case (Some(ac), None) => Some(ac) - case (Some(ac), Some(xc)) => Some(s"$ac;$xc") - } + agg.withConfigurations( + (agg.configurations, x.configurations) match { + case (None, _) => x.configurations + case (Some(ac), None) => Some(ac) + case (Some(ac), Some(xc)) => Some(s"$ac;$xc") + } ) } } @@ -237,81 +152,4 @@ final class UpdateReport(val cachedDescriptor: File, val configurations: Seq[Con /** Gets the names of all resolved configurations. This `UpdateReport` contains one `ConfigurationReport` for each configuration in this list. */ def allConfigurations: Seq[String] = configurations.map(_.configuration) - - private[sbt] def withStats(us: UpdateStats): UpdateReport = - new UpdateReport( - this.cachedDescriptor, - this.configurations, - us, - this.stamps - ) -} - -object UpdateReport { - private val vectorConfigurationReportPickler = implicitly[Pickler[Vector[ConfigurationReport]]] - private val vectorConfigurationReportUnpickler = implicitly[Unpickler[Vector[ConfigurationReport]]] - private val updateStatsPickler = implicitly[Pickler[UpdateStats]] - private val updateStatsUnpickler = implicitly[Unpickler[UpdateStats]] - private val flMapPickler = implicitly[Pickler[Map[File, Long]]] - private val flMapUnpickler = implicitly[Unpickler[Map[File, Long]]] - - implicit val pickler: Pickler[UpdateReport] with Unpickler[UpdateReport] = new Pickler[UpdateReport] with Unpickler[UpdateReport] { - val tag = implicitly[FastTypeTag[UpdateReport]] - val fileTag = implicitly[FastTypeTag[File]] - val vectorConfigurationReportTag = implicitly[FastTypeTag[Vector[ConfigurationReport]]] - val updateStatsTag = implicitly[FastTypeTag[UpdateStats]] - val flMapTag = implicitly[FastTypeTag[Map[File, Long]]] - def pickle(a: UpdateReport, builder: PBuilder): Unit = { - builder.pushHints() - builder.hintTag(tag) - builder.beginEntry(a) - builder.putField("cachedDescriptor", { b => - b.hintTag(fileTag) - filePickler.pickle(a.cachedDescriptor, b) - }) - builder.putField("configurations", { b => - b.hintTag(vectorConfigurationReportTag) - vectorConfigurationReportPickler.pickle(a.configurations.toVector, b) - }) - builder.putField("stats", { b => - b.hintTag(updateStatsTag) - updateStatsPickler.pickle(a.stats, b) - }) - builder.putField("stamps", { b => - b.hintTag(flMapTag) - flMapPickler.pickle(a.stamps, b) - }) - builder.endEntry() - builder.popHints() - () - } - - def unpickle(tpe: String, reader: PReader): Any = { - reader.pushHints() - reader.hintTag(tag) - reader.beginEntry() - val cachedDescriptor = filePickler.unpickleEntry(reader.readField("cachedDescriptor")).asInstanceOf[File] - val configurations = vectorConfigurationReportUnpickler.unpickleEntry(reader.readField("configurations")).asInstanceOf[Vector[ConfigurationReport]] - val stats = updateStatsUnpickler.unpickleEntry(reader.readField("stats")).asInstanceOf[UpdateStats] - val stamps = flMapUnpickler.unpickleEntry(reader.readField("stamps")).asInstanceOf[Map[File, Long]] - val result = new UpdateReport(cachedDescriptor, configurations, stats, stamps) - reader.endEntry() - reader.popHints() - result - } - } -} - -final class UpdateStats(val resolveTime: Long, val downloadTime: Long, val downloadSize: Long, val cached: Boolean) { - override def toString = Seq("Resolve time: " + resolveTime + " ms", "Download time: " + downloadTime + " ms", "Download size: " + downloadSize + " bytes").mkString(", ") - private[sbt] def withCached(c: Boolean): UpdateStats = - new UpdateStats( - resolveTime = this.resolveTime, - downloadTime = this.downloadTime, - downloadSize = this.downloadSize, - cached = c - ) -} -object UpdateStats { - implicit val pickler: Pickler[UpdateStats] with Unpickler[UpdateStats] = PicklerUnpickler.generate[UpdateStats] } diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/package.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/package.scala index 24e6eee19..a1892b2f0 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/package.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/package.scala @@ -1,6 +1,6 @@ package sbt -package object librarymanagement { +package object librarymanagement extends ResolversSyntax { type ExclusionRule = InclExclRule val ExclusionRule = InclExclRule diff --git a/librarymanagement/src/test/scala/BaseIvySpecification.scala b/librarymanagement/src/test/scala/BaseIvySpecification.scala index 7e561640d..dc7f2a4bf 100644 --- a/librarymanagement/src/test/scala/BaseIvySpecification.scala +++ b/librarymanagement/src/test/scala/BaseIvySpecification.scala @@ -4,28 +4,36 @@ import sbt.io.IO import sbt.io.syntax._ import java.io.File import cross.CrossVersionUtil -import sbt.util.Logger import sbt.internal.util.ConsoleLogger import sbt.librarymanagement._ -import ivyint.SbtChainResolver import Configurations._ +import sbt.internal.util.FileBasedStore + +import sjsonnew.IsoString +import sjsonnew.support.scalajson.unsafe.{ CompactPrinter, Converter } + +import scala.json.ast.unsafe.JValue + trait BaseIvySpecification extends UnitSpec { def currentBase: File = new File(".") def currentTarget: File = currentBase / "target" / "ivyhome" def currentManaged: File = currentBase / "target" / "lib_managed" def currentDependency: File = currentBase / "target" / "dependency" - def defaultModuleId: ModuleID = ModuleID("com.example", "foo", "0.1.0", Some("compile")) + def defaultModuleId: ModuleID = ModuleID("com.example", "foo", "0.1.0").withConfigurations(Some("compile")) + + implicit val isoString: IsoString[JValue] = IsoString.iso(CompactPrinter.apply, FixedParser.parseUnsafe) + val fileToStore = (f: File) => new FileBasedStore(f, Converter) lazy val log = ConsoleLogger() - def configurations = Seq(Compile, Test, Runtime) - def module(moduleId: ModuleID, deps: Seq[ModuleID], scalaFullVersion: Option[String], + def configurations = Vector(Compile, Test, Runtime) + def module(moduleId: ModuleID, deps: Vector[ModuleID], scalaFullVersion: Option[String], uo: UpdateOptions = UpdateOptions(), overrideScalaVersion: Boolean = true): IvySbt#Module = { val ivyScala = scalaFullVersion map { fv => new IvyScala( scalaFullVersion = fv, scalaBinaryVersion = CrossVersionUtil.binaryScalaVersion(fv), - configurations = Nil, + configurations = Vector.empty, checkExplicit = true, filterImplicit = false, overrideScalaVersion = overrideScalaVersion @@ -33,32 +41,32 @@ trait BaseIvySpecification extends UnitSpec { } val moduleSetting: ModuleSettings = InlineConfiguration( + false, + ivyScala, module = moduleId, moduleInfo = ModuleInfo("foo"), - dependencies = deps, - configurations = configurations, - ivyScala = ivyScala - ) - val ivySbt = new IvySbt(mkIvyConfiguration(uo)) + dependencies = deps + ).withConfigurations(configurations) + val ivySbt = new IvySbt(mkIvyConfiguration(uo), fileToStore) new ivySbt.Module(moduleSetting) } - def resolvers: Seq[Resolver] = Seq(DefaultMavenRepository) + def resolvers: Vector[Resolver] = Vector(DefaultMavenRepository) def chainResolver = ChainedResolver("sbt-chain", resolvers) def mkIvyConfiguration(uo: UpdateOptions): IvyConfiguration = { val paths = new IvyPaths(currentBase, Some(currentTarget)) - val other = Nil - val moduleConfs = Seq(ModuleConfiguration("*", chainResolver)) + val other = Vector.empty + val moduleConfs = Vector(ModuleConfiguration("*", chainResolver)) val off = false - val check = Nil + val check = Vector.empty val resCacheDir = currentTarget / "resolution-cache" new InlineIvyConfiguration(paths, resolvers, other, moduleConfs, off, None, check, Some(resCacheDir), uo, log) } def makeUpdateConfiguration: UpdateConfiguration = { - val retrieveConfig = new RetrieveConfiguration(currentManaged, Resolver.defaultRetrievePattern, false) + val retrieveConfig = new RetrieveConfiguration(currentManaged, Resolver.defaultRetrievePattern).withSync(false) new UpdateConfiguration(Some(retrieveConfig), false, UpdateLogging.Full, ArtifactTypeFilter.forbid(Set("src", "doc"))) } @@ -84,7 +92,7 @@ trait BaseIvySpecification extends UnitSpec { ivyFile = None, resolverName = resolver.name, artifacts = artifacts, - checksums = Seq(), + checksums = Vector.empty, logging = UpdateLogging.Full, overwrite = true ) diff --git a/librarymanagement/src/test/scala/CachedResolutionSpec.scala b/librarymanagement/src/test/scala/CachedResolutionSpec.scala index 4fc6faa3e..182fa9521 100644 --- a/librarymanagement/src/test/scala/CachedResolutionSpec.scala +++ b/librarymanagement/src/test/scala/CachedResolutionSpec.scala @@ -9,12 +9,12 @@ class CachedResolutionSpec extends BaseIvySpecification { "Resolving the same module twice" should "work" in { cleanIvyCache() val m = module( - ModuleID("com.example", "foo", "0.1.0", Some("compile")), - Seq(commonsIo13), Some("2.10.2"), UpdateOptions().withCachedResolution(true) + ModuleID("com.example", "foo", "0.1.0").withConfigurations(Some("compile")), + Vector(commonsIo13), Some("2.10.2"), UpdateOptions().withCachedResolution(true) ) val report = ivyUpdate(m) cleanCachedResolutionCache(m) - val report2 = ivyUpdate(m) + val _ = ivyUpdate(m) // first resolution creates the minigraph println(report) // second resolution reads from the minigraph @@ -25,8 +25,8 @@ class CachedResolutionSpec extends BaseIvySpecification { "Resolving the unsolvable module should" should "not work" in { // log.setLevel(Level.Debug) val m = module( - ModuleID("com.example", "foo", "0.2.0", Some("compile")), - Seq(mavenCayennePlugin302), Some("2.10.2"), UpdateOptions().withCachedResolution(true) + ModuleID("com.example", "foo", "0.2.0").withConfigurations(Some("compile")), + Vector(mavenCayennePlugin302), Some("2.10.2"), UpdateOptions().withCachedResolution(true) ) ivyUpdateEither(m) match { case Right(_) => sys.error("this should've failed") @@ -52,12 +52,12 @@ class CachedResolutionSpec extends BaseIvySpecification { // log.setLevel(Level.Debug) cleanIvyCache() val m = module( - ModuleID("com.example", "foo", "0.3.0", Some("compile")), - Seq(avro177, dataAvro1940, netty320), + ModuleID("com.example", "foo", "0.3.0").withConfigurations(Some("compile")), + Vector(avro177, dataAvro1940, netty320), Some("2.10.2"), UpdateOptions().withCachedResolution(true) ) // first resolution creates the minigraph - val report0 = ivyUpdate(m) + val _ = ivyUpdate(m) cleanCachedResolutionCache(m) // second resolution reads from the minigraph val report = ivyUpdate(m) @@ -66,11 +66,11 @@ class CachedResolutionSpec extends BaseIvySpecification { assert(!(modules exists { x: String => x contains """org.jboss.netty:netty:3.2.1.Final""" })) } - def commonsIo13 = ModuleID("commons-io", "commons-io", "1.3", Some("compile")) - def mavenCayennePlugin302 = ModuleID("org.apache.cayenne.plugins", "maven-cayenne-plugin", "3.0.2", Some("compile")) - def avro177 = ModuleID("org.apache.avro", "avro", "1.7.7", Some("compile")) - def dataAvro1940 = ModuleID("com.linkedin.pegasus", "data-avro", "1.9.40", Some("compile")) - def netty320 = ModuleID("org.jboss.netty", "netty", "3.2.0.Final", Some("compile")) + def commonsIo13 = ModuleID("commons-io", "commons-io", "1.3").withConfigurations(Some("compile")) + def mavenCayennePlugin302 = ModuleID("org.apache.cayenne.plugins", "maven-cayenne-plugin", "3.0.2").withConfigurations(Some("compile")) + def avro177 = ModuleID("org.apache.avro", "avro", "1.7.7").withConfigurations(Some("compile")) + def dataAvro1940 = ModuleID("com.linkedin.pegasus", "data-avro", "1.9.40").withConfigurations(Some("compile")) + def netty320 = ModuleID("org.jboss.netty", "netty", "3.2.0.Final").withConfigurations(Some("compile")) def defaultOptions = EvictionWarningOptions.default } diff --git a/librarymanagement/src/test/scala/ComponentManagerTest.scala b/librarymanagement/src/test/scala/ComponentManagerTest.scala index 8f6bec88f..ff429aee1 100644 --- a/librarymanagement/src/test/scala/ComponentManagerTest.scala +++ b/librarymanagement/src/test/scala/ComponentManagerTest.scala @@ -2,12 +2,11 @@ package sbt.internal.librarymanagement import java.io.File import java.util.concurrent.Callable -import sbt.io.IO.{ createDirectory, delete, touch, withTemporaryDirectory } +import sbt.io.IO.withTemporaryDirectory import sbt.io.IO import org.apache.ivy.util.ChecksumHelper import IfMissing.Fail import xsbti.ComponentProvider -import sbt.util.Logger // TODO - We need to re-enable this test. Right now, we dont' have a "stub" launcher for this. // This is testing something which uses a launcher interface, but was grabbing the underlying class directly diff --git a/librarymanagement/src/test/scala/CrossVersionTest.scala b/librarymanagement/src/test/scala/CrossVersionTest.scala index f70343e73..c179623fb 100644 --- a/librarymanagement/src/test/scala/CrossVersionTest.scala +++ b/librarymanagement/src/test/scala/CrossVersionTest.scala @@ -1,6 +1,5 @@ package sbt.librarymanagement -import java.io.File import sbt.internal.util.UnitSpec class CrossVersionTest extends UnitSpec { @@ -116,7 +115,7 @@ class CrossVersionTest extends UnitSpec { CrossVersion.binaryScalaVersion("2.10.1") shouldBe "2.10" } it should "return disabled cross version as equal to a copy" in { - CrossVersion.Disabled shouldBe CrossVersion.Disabled + Disabled() shouldBe Disabled() } it should "return full cross version as equal to a copy" in { CrossVersion.full shouldBe CrossVersion.full diff --git a/librarymanagement/src/test/scala/CustomPomParserTest.scala b/librarymanagement/src/test/scala/CustomPomParserTest.scala index 16874c3d3..eceec0d93 100644 --- a/librarymanagement/src/test/scala/CustomPomParserTest.scala +++ b/librarymanagement/src/test/scala/CustomPomParserTest.scala @@ -6,7 +6,6 @@ import org.apache.ivy.core.module.id.ModuleRevisionId import org.apache.ivy.core.resolve.ResolveOptions import sbt.librarymanagement._ import sbt.io.IO.withTemporaryDirectory -import sbt.util.Logger import sbt.internal.util.ConsoleLogger class CustomPomParserTest extends UnitSpec { @@ -16,8 +15,8 @@ class CustomPomParserTest extends UnitSpec { val repoUrl = getClass.getResource("/test-maven-repo") val local = MavenRepository("Test Repo", repoUrl.toExternalForm) val paths = new IvyPaths(new File("."), Some(cacheDir)) - val conf = new InlineIvyConfiguration(paths, Seq(local), Nil, Nil, false, None, Seq("sha1", "md5"), None, UpdateOptions(), log) - val ivySbt = new IvySbt(conf) + val conf = new InlineIvyConfiguration(paths, Vector(local), Vector.empty, Vector.empty, false, None, Vector("sha1", "md5"), None, UpdateOptions(), log) + val ivySbt = new IvySbt(conf, DefaultFileToStore) val resolveOpts = new ResolveOptions().setConfs(Array("default")) val mrid = ModuleRevisionId.newInstance("com.test", "test-artifact", "1.0.0-SNAPSHOT") diff --git a/librarymanagement/src/test/scala/DMSerializationSpec.scala b/librarymanagement/src/test/scala/DMSerializationSpec.scala index ab4d9f78c..ab1bb457b 100644 --- a/librarymanagement/src/test/scala/DMSerializationSpec.scala +++ b/librarymanagement/src/test/scala/DMSerializationSpec.scala @@ -2,8 +2,12 @@ package sbt.librarymanagement import java.net.URL import java.io.File -import sbt.serialization._ -import sbt.internal.util.UnitSpec + +import sbt.internal._, librarymanagement._, util.UnitSpec +import scala.json.ast.unsafe._ +import sjsonnew._, support.scalajson.unsafe._ + +import LibraryManagementCodec._ class DMSerializationSpec extends UnitSpec { "CrossVersion.full" should "roundtrip" in { @@ -13,7 +17,7 @@ class DMSerializationSpec extends UnitSpec { roundtripStr(CrossVersion.binary: CrossVersion) } "CrossVersion.Disabled" should "roundtrip" in { - roundtrip(CrossVersion.Disabled: CrossVersion) + roundtrip(Disabled(): CrossVersion) } """Artifact("foo")""" should "roundtrip" in { roundtrip(Artifact("foo")) @@ -34,7 +38,7 @@ class DMSerializationSpec extends UnitSpec { roundtrip(ModuleID("org", "name", "1.0")) } """ModuleReport(ModuleID("org", "name", "1.0"), Nil, Nil)""" should "roundtrip" in { - roundtripStr(ModuleReport(ModuleID("org", "name", "1.0"), Nil, Nil)) + roundtripStr(ModuleReport(ModuleID("org", "name", "1.0"), Vector.empty, Vector.empty)) } "Organization artifact report" should "roundtrip" in { roundtripStr(organizationArtifactReportExample) @@ -55,17 +59,19 @@ class DMSerializationSpec extends UnitSpec { lazy val organizationArtifactReportExample = new OrganizationArtifactReport("org", "name", Vector(moduleReportExample)) lazy val moduleReportExample = - ModuleReport(ModuleID("org", "name", "1.0"), Nil, Nil) + ModuleReport(ModuleID("org", "name", "1.0"), Vector.empty, Vector.empty) - def roundtrip[A: Pickler: Unpickler](a: A): Unit = + def roundtrip[A: JsonReader: JsonWriter](a: A): Unit = roundtripBuilder(a) { _ shouldBe _ } - def roundtripStr[A: Pickler: Unpickler](a: A): Unit = + def roundtripStr[A: JsonReader: JsonWriter](a: A): Unit = roundtripBuilder(a) { _.toString shouldBe _.toString } - def roundtripBuilder[A: Pickler: Unpickler](a: A)(f: (A, A) => Unit): Unit = + def roundtripBuilder[A: JsonReader: JsonWriter](a: A)(f: (A, A) => Unit): Unit = { - val json = toJsonString(a) + val json = isoString to (Converter toJsonUnsafe a) println(json) - val obj = fromJsonString[A](json).get + val obj = Converter fromJsonUnsafe[A] (isoString from json) f(a, obj) } + + implicit val isoString: IsoString[JValue] = IsoString.iso(CompactPrinter.apply, FixedParser.parseUnsafe) } diff --git a/librarymanagement/src/test/scala/EvictionWarningSpec.scala b/librarymanagement/src/test/scala/EvictionWarningSpec.scala index c1a77bf31..21d59b10a 100644 --- a/librarymanagement/src/test/scala/EvictionWarningSpec.scala +++ b/librarymanagement/src/test/scala/EvictionWarningSpec.scala @@ -44,25 +44,25 @@ class EvictionWarningSpec extends BaseIvySpecification { it should "be detected if it's enabled" in scalaLibTransitiveWarn2() it should "print out message about the eviction if it's enabled" in scalaLibTransitiveWarn3() - def akkaActor214 = ModuleID("com.typesafe.akka", "akka-actor", "2.1.4", Some("compile")) cross CrossVersion.binary - def akkaActor230 = ModuleID("com.typesafe.akka", "akka-actor", "2.3.0", Some("compile")) cross CrossVersion.binary - def akkaActor234 = ModuleID("com.typesafe.akka", "akka-actor", "2.3.4", Some("compile")) cross CrossVersion.binary - def scala2102 = ModuleID("org.scala-lang", "scala-library", "2.10.2", Some("compile")) - def scala2103 = ModuleID("org.scala-lang", "scala-library", "2.10.3", Some("compile")) - def scala2104 = ModuleID("org.scala-lang", "scala-library", "2.10.4", Some("compile")) - def commonsIo13 = ModuleID("commons-io", "commons-io", "1.3", Some("compile")) - def commonsIo14 = ModuleID("commons-io", "commons-io", "1.4", Some("compile")) - def commonsIo24 = ModuleID("commons-io", "commons-io", "2.4", Some("compile")) - def bnfparser10 = ModuleID("ca.gobits.bnf", "bnfparser", "1.0", Some("compile")) // uses commons-io 2.4 - def unfilteredUploads080 = ModuleID("net.databinder", "unfiltered-uploads", "0.8.0", Some("compile")) cross CrossVersion.binary // uses commons-io 1.4 - def bananaSesame04 = ModuleID("org.w3", "banana-sesame", "0.4", Some("compile")) cross CrossVersion.binary // uses akka-actor 2.1.4 - def akkaRemote234 = ModuleID("com.typesafe.akka", "akka-remote", "2.3.4", Some("compile")) cross CrossVersion.binary // uses akka-actor 2.3.4 + def akkaActor214 = ModuleID("com.typesafe.akka", "akka-actor", "2.1.4").withConfigurations(Some("compile")) cross CrossVersion.binary + def akkaActor230 = ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations(Some("compile")) cross CrossVersion.binary + def akkaActor234 = ModuleID("com.typesafe.akka", "akka-actor", "2.3.4").withConfigurations(Some("compile")) cross CrossVersion.binary + def scala2102 = ModuleID("org.scala-lang", "scala-library", "2.10.2").withConfigurations(Some("compile")) + def scala2103 = ModuleID("org.scala-lang", "scala-library", "2.10.3").withConfigurations(Some("compile")) + def scala2104 = ModuleID("org.scala-lang", "scala-library", "2.10.4").withConfigurations(Some("compile")) + def commonsIo13 = ModuleID("commons-io", "commons-io", "1.3").withConfigurations(Some("compile")) + def commonsIo14 = ModuleID("commons-io", "commons-io", "1.4").withConfigurations(Some("compile")) + def commonsIo24 = ModuleID("commons-io", "commons-io", "2.4").withConfigurations(Some("compile")) + def bnfparser10 = ModuleID("ca.gobits.bnf", "bnfparser", "1.0").withConfigurations(Some("compile")) // uses commons-io 2.4 + def unfilteredUploads080 = ModuleID("net.databinder", "unfiltered-uploads", "0.8.0").withConfigurations(Some("compile")) cross CrossVersion.binary // uses commons-io 1.4 + def bananaSesame04 = ModuleID("org.w3", "banana-sesame", "0.4").withConfigurations(Some("compile")) cross CrossVersion.binary // uses akka-actor 2.1.4 + def akkaRemote234 = ModuleID("com.typesafe.akka", "akka-remote", "2.3.4").withConfigurations(Some("compile")) cross CrossVersion.binary // uses akka-actor 2.3.4 def defaultOptions = EvictionWarningOptions.default import sbt.internal.util.ShowLines._ - def scalaVersionDeps = Seq(scala2102, akkaActor230) + def scalaVersionDeps = Vector(scala2102, akkaActor230) def scalaVersionWarn1() = { val m = module(defaultModuleId, scalaVersionDeps, Some("2.10.2"), overrideScalaVersion = false) @@ -113,7 +113,7 @@ class EvictionWarningSpec extends BaseIvySpecification { EvictionWarning(m, defaultOptions.withWarnScalaVersionEviction(false), report, log).scalaEvictions should have size (0) } - def javaLibDirectDeps = Seq(commonsIo14, commonsIo24) + def javaLibDirectDeps = Vector(commonsIo14, commonsIo24) def javaLibWarn1() = { val m = module(defaultModuleId, javaLibDirectDeps, Some("2.10.3")) @@ -151,20 +151,20 @@ class EvictionWarningSpec extends BaseIvySpecification { } def javaLibNoWarn1() = { - val deps = Seq(commonsIo14, commonsIo13) + val deps = Vector(commonsIo14, commonsIo13) val m = module(defaultModuleId, deps, Some("2.10.3")) val report = ivyUpdate(m) EvictionWarning(m, defaultOptions, report, log).reportedEvictions should have size (0) } def javaLibNoWarn2() = { - val deps = Seq(commonsIo14, commonsIo13) + val deps = Vector(commonsIo14, commonsIo13) val m = module(defaultModuleId, deps, Some("2.10.3")) val report = ivyUpdate(m) EvictionWarning(m, defaultOptions, report, log).lines shouldBe Nil } - def javaLibTransitiveDeps = Seq(unfilteredUploads080, bnfparser10) + def javaLibTransitiveDeps = Vector(unfilteredUploads080, bnfparser10) def javaLibTransitiveWarn1() = { val m = module(defaultModuleId, javaLibTransitiveDeps, Some("2.10.3")) @@ -190,14 +190,14 @@ class EvictionWarningSpec extends BaseIvySpecification { } def scalaLibWarn1() = { - val deps = Seq(scala2104, akkaActor214, akkaActor234) + val deps = Vector(scala2104, akkaActor214, akkaActor234) val m = module(defaultModuleId, deps, Some("2.10.4")) val report = ivyUpdate(m) EvictionWarning(m, defaultOptions, report, log).reportedEvictions should have size (1) } def scalaLibWarn2() = { - val deps = Seq(scala2104, akkaActor214, akkaActor234) + val deps = Vector(scala2104, akkaActor214, akkaActor234) val m = module(defaultModuleId, deps, Some("2.10.4")) val report = ivyUpdate(m) EvictionWarning(m, defaultOptions, report, log).lines shouldBe @@ -210,20 +210,20 @@ class EvictionWarningSpec extends BaseIvySpecification { } def scalaLibNoWarn1() = { - val deps = Seq(scala2104, akkaActor230, akkaActor234) + val deps = Vector(scala2104, akkaActor230, akkaActor234) val m = module(defaultModuleId, deps, Some("2.10.4")) val report = ivyUpdate(m) EvictionWarning(m, defaultOptions, report, log).reportedEvictions should have size (0) } def scalaLibNoWarn2() = { - val deps = Seq(scala2104, akkaActor230, akkaActor234) + val deps = Vector(scala2104, akkaActor230, akkaActor234) val m = module(defaultModuleId, deps, Some("2.10.4")) val report = ivyUpdate(m) EvictionWarning(m, defaultOptions, report, log).lines shouldBe Nil } - def scalaLibTransitiveDeps = Seq(scala2104, bananaSesame04, akkaRemote234) + def scalaLibTransitiveDeps = Vector(scala2104, bananaSesame04, akkaRemote234) def scalaLibTransitiveWarn1() = { val m = module(defaultModuleId, scalaLibTransitiveDeps, Some("2.10.4")) diff --git a/librarymanagement/src/test/scala/InconsistentDuplicateSpec.scala b/librarymanagement/src/test/scala/InconsistentDuplicateSpec.scala index 1e94e1196..4e0866d6c 100644 --- a/librarymanagement/src/test/scala/InconsistentDuplicateSpec.scala +++ b/librarymanagement/src/test/scala/InconsistentDuplicateSpec.scala @@ -20,7 +20,7 @@ class InconsistentDuplicateSpec extends UnitSpec { IvySbt.inconsistentDuplicateWarning(Seq(akkaActor230Test, akkaActor230)) shouldBe Nil } - def akkaActor214 = ModuleID("com.typesafe.akka", "akka-actor", "2.1.4", Some("compile")) cross CrossVersion.binary - def akkaActor230 = ModuleID("com.typesafe.akka", "akka-actor", "2.3.0", Some("compile")) cross CrossVersion.binary - def akkaActor230Test = ModuleID("com.typesafe.akka", "akka-actor", "2.3.0", Some("test")) cross CrossVersion.binary + def akkaActor214 = ModuleID("com.typesafe.akka", "akka-actor", "2.1.4").withConfigurations(Some("compile")) cross CrossVersion.binary + def akkaActor230 = ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations(Some("compile")) cross CrossVersion.binary + def akkaActor230Test = ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations(Some("test")) cross CrossVersion.binary } diff --git a/librarymanagement/src/test/scala/MakePomSpec.scala b/librarymanagement/src/test/scala/MakePomSpec.scala index 1a910ca91..fb2c55001 100644 --- a/librarymanagement/src/test/scala/MakePomSpec.scala +++ b/librarymanagement/src/test/scala/MakePomSpec.scala @@ -1,7 +1,5 @@ package sbt.internal.librarymanagement -import java.io.File -import sbt.util.Logger import sbt.internal.util.ConsoleLogger // http://ant.apache.org/ivy/history/2.3.0/ivyfile/dependency.html diff --git a/librarymanagement/src/test/scala/ResolverTest.scala b/librarymanagement/src/test/scala/ResolverTest.scala index 499e86db4..d2090c502 100644 --- a/librarymanagement/src/test/scala/ResolverTest.scala +++ b/librarymanagement/src/test/scala/ResolverTest.scala @@ -2,14 +2,13 @@ package sbt.librarymanagement import java.net.URL -import sbt._ import sbt.internal.util.UnitSpec object ResolverTest extends UnitSpec { "Resolver url" should "propagate pattern descriptorOptional and skipConsistencyCheck." in { - val pats = Seq("[orgPath]") - val patsExpected = Seq("http://foo.com/test/[orgPath]") + val pats = Vector("[orgPath]") + val patsExpected = Vector("http://foo.com/test/[orgPath]") val patterns = Resolver.url("test", new URL("http://foo.com/test"))(Patterns(pats, pats, isMavenCompatible = false, descriptorOptional = true, skipConsistencyCheck = true)).patterns patterns.ivyPatterns shouldBe patsExpected diff --git a/librarymanagement/src/test/scala/ScalaOverrideTest.scala b/librarymanagement/src/test/scala/ScalaOverrideTest.scala index 6fd2425c4..bf0b82e3e 100644 --- a/librarymanagement/src/test/scala/ScalaOverrideTest.scala +++ b/librarymanagement/src/test/scala/ScalaOverrideTest.scala @@ -1,6 +1,6 @@ package sbt.librarymanagement -import org.apache.ivy.core.module.id.{ ModuleId, ModuleRevisionId } +import org.apache.ivy.core.module.id.ModuleRevisionId import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor import sbt.internal.util.UnitSpec diff --git a/librarymanagement/src/test/scala/sbt/internal/librarymanagement/FakeResolverSpecification.scala b/librarymanagement/src/test/scala/sbt/internal/librarymanagement/FakeResolverSpecification.scala index 60e9f2dd7..27936225f 100644 --- a/librarymanagement/src/test/scala/sbt/internal/librarymanagement/FakeResolverSpecification.scala +++ b/librarymanagement/src/test/scala/sbt/internal/librarymanagement/FakeResolverSpecification.scala @@ -9,10 +9,10 @@ import sbt.librarymanagement.{ ModuleID, RawRepository, Resolver, UpdateReport } class FakeResolverSpecification extends BaseIvySpecification { import FakeResolver._ - val myModule = ModuleID("org.example", "my-module", "0.0.1-SNAPSHOT", Some("compile")) - val example = ModuleID("com.example", "example", "1.0.0", Some("compile")) - val anotherExample = ModuleID("com.example", "another-example", "1.0.0", Some("compile")) - val nonExisting = ModuleID("com.example", "does-not-exist", "1.2.3", Some("compile")) + val myModule = ModuleID("org.example", "my-module", "0.0.1-SNAPSHOT").withConfigurations(Some("compile")) + val example = ModuleID("com.example", "example", "1.0.0").withConfigurations(Some("compile")) + val anotherExample = ModuleID("com.example", "another-example", "1.0.0").withConfigurations(Some("compile")) + val nonExisting = ModuleID("com.example", "does-not-exist", "1.2.3").withConfigurations(Some("compile")) "The FakeResolver" should "find modules with only one artifact" in { val m = getModule(myModule) @@ -66,8 +66,8 @@ class FakeResolverSpecification extends BaseIvySpecification { ) private def fakeResolver = new FakeResolver("FakeResolver", new File("tmp"), modules) - override def resolvers: Seq[Resolver] = Seq(new RawRepository(fakeResolver)) - private def getModule(myModule: ModuleID): IvySbt#Module = module(defaultModuleId, Seq(myModule), None) + override def resolvers: Vector[Resolver] = Vector(new RawRepository(fakeResolver)) + private def getModule(myModule: ModuleID): IvySbt#Module = module(defaultModuleId, Vector(myModule), None) private def getAllFiles(report: UpdateReport) = for { conf <- report.configurations @@ -75,4 +75,4 @@ class FakeResolverSpecification extends BaseIvySpecification { (_, f) <- m.artifacts } yield f -} \ No newline at end of file +} diff --git a/librarymanagement/src/test/scala/sbt/internal/librarymanagement/IvyRepoSpec.scala b/librarymanagement/src/test/scala/sbt/internal/librarymanagement/IvyRepoSpec.scala index 9e15fbc01..b6238b3d5 100644 --- a/librarymanagement/src/test/scala/sbt/internal/librarymanagement/IvyRepoSpec.scala +++ b/librarymanagement/src/test/scala/sbt/internal/librarymanagement/IvyRepoSpec.scala @@ -6,7 +6,7 @@ import sbt.librarymanagement._ class IvyRepoSpec extends BaseIvySpecification with DependencyBuilders { - val ourModuleID = ModuleID("com.example", "foo", "0.1.0", Some("compile")) + val ourModuleID = ModuleID("com.example", "foo", "0.1.0").withConfigurations(Some("compile")) def makeModuleForDepWithSources = { // By default a module seems to only have [compile, test, runtime], yet deps automatically map to @@ -15,7 +15,7 @@ class IvyRepoSpec extends BaseIvySpecification with DependencyBuilders { module( ourModuleID, - Seq(dep), None //, UpdateOptions().withCachedResolution(true) + Vector(dep), None //, UpdateOptions().withCachedResolution(true) ) } @@ -50,21 +50,19 @@ class IvyRepoSpec extends BaseIvySpecification with DependencyBuilders { val docTypes = Set("javadoc") // These will be the default classifiers that SBT should try, in case a dependency is Maven. // In this case though, they will be tried and should fail gracefully - only the - val attemptedClassifiers = Seq("sources", "javadoc") + val attemptedClassifiers = Vector("sources", "javadoc") // The dep that we want to get the "classifiers" (i.e. sources / docs) for. // We know it has only one source artifact in the "compile" configuration. val dep = "com.test" % "module-with-srcs" % "0.1.00" % "compile" val clMod = { - import language.implicitConversions - implicit val key = (m: ModuleID) => (m.organization, m.name, m.revision) - val externalModules = Seq(dep) + val externalModules = Vector(dep) // Note: need to extract ourModuleID so we can plug it in here, can't fish it back out of the IvySbt#Module (`m`) - GetClassifiersModule(ourModuleID, externalModules, Seq(Configurations.Compile), attemptedClassifiers) + GetClassifiersModule(ourModuleID, externalModules, Vector(Configurations.Compile), attemptedClassifiers) } - val gcm = GetClassifiersConfiguration(clMod, Map.empty, c.copy(artifactFilter = c.artifactFilter.invert), ivyScala, srcTypes, docTypes) + val gcm = GetClassifiersConfiguration(clMod, Map.empty, c.withArtifactFilter(c.artifactFilter.invert), ivyScala, srcTypes, docTypes) val report2 = IvyActions.updateClassifiers(m.owner, gcm, UnresolvedWarningConfiguration(), LogicalClock.unknown, None, Vector(), log) @@ -80,7 +78,7 @@ class IvyRepoSpec extends BaseIvySpecification with DependencyBuilders { } } - override lazy val resolvers: Seq[Resolver] = Seq(testIvy) + override lazy val resolvers: Vector[Resolver] = Vector(testIvy) lazy val testIvy = { val repoUrl = getClass.getResource("/test-ivy-repo") diff --git a/project/DatatypeConfig.scala b/project/DatatypeConfig.scala new file mode 100644 index 000000000..78159c476 --- /dev/null +++ b/project/DatatypeConfig.scala @@ -0,0 +1,58 @@ +import sbt.datatype.{ CodecCodeGen, TpeRef } + +object DatatypeConfig { + + /** Extract the only type parameter from a TpeRef */ + def oneArg(tpe: TpeRef): TpeRef = { + val pat = s"""${CodecCodeGen.removeTypeParameters(tpe.name)}[<\\[](.+?)[>\\]]""".r + val pat(arg0) = tpe.name + TpeRef(arg0, false, false, false) + } + + /** Extract the two type parameters from a TpeRef */ + def twoArgs(tpe: TpeRef): List[TpeRef] = { + val pat = s"""${CodecCodeGen.removeTypeParameters(tpe.name)}[<\\[](.+?), (.+?)[>\\]]""".r + val pat(arg0, arg1) = tpe.name + TpeRef(arg0, false, false, false) :: TpeRef(arg1, false, false, false) :: Nil + } + + /** Codecs that were manually written. */ + val myCodecs: PartialFunction[String, TpeRef => List[String]] = { + case "java.util.Date" => { _ => "sbt.internal.librarymanagement.formats.DateFormat" :: Nil } + + case "scala.xml.NodeSeq" => { _ => "sbt.internal.librarymanagement.formats.NodeSeqFormat" :: Nil } + + case "org.apache.ivy.plugins.resolver.DependencyResolver" => + { _ => "sbt.internal.librarymanagement.formats.DependencyResolverFormat" :: Nil } + + case "xsbti.GlobalLock" => { _ => "sbt.internal.librarymanagement.formats.GlobalLockFormat" :: Nil } + case "xsbti.Logger" => { _ => "sbt.internal.librarymanagement.formats.LoggerFormat" :: Nil } + + case "sbt.librarymanagement.UpdateOptions" => + { _ => "sbt.internal.librarymanagement.formats.UpdateOptionsFormat" :: Nil } + + // TODO: These are handled by BasicJsonProtocol, and sbt-datatype should handle them by default, imo + case "Option" | "Set" => { tpe => getFormats(oneArg(tpe)) } + case "Map" | "Tuple2" | "scala.Tuple2" => { tpe => twoArgs(tpe).flatMap(getFormats) } + case "Int" | "Long" => { _ => Nil } + } + + /** Types for which we don't include the format -- they're just aliases to InclExclRule */ + val excluded = Set( + "sbt.librarymanagement.InclusionRule", + "sbt.librarymanagement.ExclusionRule") + + /** Returns the list of formats required to encode the given `TpeRef`. */ + val getFormats: TpeRef => List[String] = + CodecCodeGen.extensibleFormatsForType { + case TpeRef("sbt.internal.librarymanagement.RetrieveConfiguration", false, false, false) => + "sbt.librarymanagement.RetrieveConfigurationFormats" :: Nil + case tpe @ TpeRef(name, _, _, _) if myCodecs isDefinedAt CodecCodeGen.removeTypeParameters(name) => + myCodecs(CodecCodeGen.removeTypeParameters(name))(tpe) + case TpeRef(name, _, _, _) if excluded contains CodecCodeGen.removeTypeParameters(name) => + Nil + case other => + CodecCodeGen.formatsForType(other) + } + +} diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 8232a3c7e..250adc2e2 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -5,7 +5,7 @@ object Dependencies { lazy val scala211 = "2.11.8" val ioVersion = "1.0.0-M6" - val utilVersion = "0.1.0-M13" + val utilVersion = "0.1.0-M15" private lazy val sbtIO = "org.scala-sbt" %% "io" % ioVersion @@ -43,6 +43,16 @@ object Dependencies { lazy val launcherInterface = "org.scala-sbt" % "launcher-interface" % "1.0.0" lazy val ivy = "org.scala-sbt.ivy" % "ivy" % "2.3.0-sbt-2cc8d2761242b072cedb0a04cb39435c4fa24f9a" lazy val jsch = "com.jcraft" % "jsch" % "0.1.46" intransitive () - lazy val sbtSerialization = "org.scala-sbt" %% "serialization" % "0.1.2" lazy val scalaReflect = Def.setting { "org.scala-lang" % "scala-reflect" % scalaVersion.value } + lazy val scalaXml = scala211Module("scala-xml", "1.0.5") + lazy val sjsonnewVersion = "0.4.1" + lazy val sjsonnewScalaJson = "com.eed3si9n" %% "sjson-new-scalajson" % sjsonnewVersion + + private def scala211Module(name: String, moduleVersion: String) = + Def.setting { + scalaVersion.value match { + case sv if (sv startsWith "2.9.") || (sv startsWith "2.10.") => Nil + case _ => ("org.scala-lang.modules" %% name % moduleVersion) :: Nil + } + } } diff --git a/project/build.properties b/project/build.properties index 817bc38df..27e88aa11 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.9 +sbt.version=0.13.13 diff --git a/project/sbt-datatype.sbt b/project/sbt-datatype.sbt new file mode 100644 index 000000000..c13a23ad7 --- /dev/null +++ b/project/sbt-datatype.sbt @@ -0,0 +1 @@ +addSbtPlugin("org.scala-sbt" % "sbt-datatype" % "0.2.8")