From ea08f865203292a52648454d47d36559886457a6 Mon Sep 17 00:00:00 2001 From: Indrajit Raychaudhuri Date: Tue, 28 Feb 2012 15:18:46 +0530 Subject: [PATCH] Added support for providing basic SCM info Sonatype OSS repo (where many libraries are expected to migrate) requires populating SCM info in additional to what is already provisioned for populating in SBT. We now support populating the basic SCM info as thus: ``` // Usual scmInfo := Some(ScmInfo(url("https://github.com/foo/project"), "scm:git:https://github.com/foo/project.git")) // Also add scmInfo := Some(ScmInfo(url("https://github.com/foo/project"), "scm:git:https://github.com/foo/project.git", Some("dev_connection"))) ``` For anything more esoteric than the basic info, there is always `pomPostProcess` :) --- ivy/IvyInterface.scala | 10 ++++++---- ivy/MakePom.scala | 16 ++++++++++++++++ main/Defaults.scala | 3 ++- main/Keys.scala | 9 +++++---- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/ivy/IvyInterface.scala b/ivy/IvyInterface.scala index 5b90fd141..be3d2cd3d 100644 --- a/ivy/IvyInterface.scala +++ b/ivy/IvyInterface.scala @@ -17,9 +17,9 @@ final case class ModuleID(organization: String, name: String, revision: String, (if(extraAttributes.isEmpty) "" else " " + extraString) def extraString = extraAttributes.map { case (k,v) => k + "=" + v } mkString("(",", ",")") - @deprecated("Use the variant accepting a CrossVersion value constructed by a member of the CrossVersion object.", "0.12.0") + @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 the variant accepting a CrossVersion value constructed by a member of the CrossVersion object.", "0.12.0") + @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: CrossVersion): ModuleID = copy(crossVersion = v) @@ -49,13 +49,15 @@ object ModuleID if(key.startsWith("e:")) (key, value) else ("e:" + key, value) } /** Additional information about a project module */ -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) +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) { 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) } +/** Basic SCM information for a project module */ +case class ScmInfo(browseUrl: URL, connection: String, devConnection: Option[String] = None) /** Rule to exclude unwanted dependencies pulled in transitively by a module. */ case class ExclusionRule(organization: String = "*", name: String = "*", artifact: String = "*", configurations: Seq[String] = Nil) sealed trait Resolver @@ -428,7 +430,7 @@ object Artifact } def artifactName(scalaVersion: ScalaVersion, module: ModuleID, artifact: Artifact): String = { - import artifact._ + import artifact._ val classifierStr = classifier match { case None => ""; case Some(c) => "-" + c } val cross = CrossVersion(module.crossVersion, scalaVersion.full, scalaVersion.binary) val base = CrossVersion.applyCross(artifact.name, cross) diff --git a/ivy/MakePom.scala b/ivy/MakePom.scala index e2b5f1778..31a83a705 100644 --- a/ivy/MakePom.scala +++ b/ivy/MakePom.scala @@ -44,6 +44,7 @@ class MakePom(val log: Logger) {moduleInfo.nameFormal} { makeStartYear(moduleInfo) } { makeOrganization(moduleInfo) } + { makeScmInfo(moduleInfo) } { extra } { val deps = depsInConfs(module, configurations) @@ -83,6 +84,21 @@ class MakePom(val log: Logger) }} } + def makeScmInfo(moduleInfo: ModuleInfo): NodeSeq = + { + moduleInfo.scmInfo match { + case Some(s) => + + {s.browseUrl} + {s.connection} + {s.devConnection match { + case Some(d) => {d} + case _ => NodeSeq.Empty + }} + + case _ => NodeSeq.Empty + } + } def makeProperties(module: ModuleDescriptor, dependencies: Seq[DependencyDescriptor]): NodeSeq = { val extra = IvySbt.getExtraAttributes(module) diff --git a/main/Defaults.scala b/main/Defaults.scala index 6e07ed6e9..656bfd0b3 100644 --- a/main/Defaults.scala +++ b/main/Defaults.scala @@ -715,7 +715,8 @@ object Classpaths organization <<= organization or normalizedName, organizationName <<= organizationName or organization, organizationHomepage <<= organizationHomepage or homepage, - projectInfo <<= (name, description, homepage, startYear, licenses, organizationName, organizationHomepage) apply ModuleInfo, + scmInfo in GlobalScope :== None, + projectInfo <<= (name, description, homepage, startYear, licenses, organizationName, organizationHomepage, scmInfo) apply ModuleInfo, externalResolvers <<= (externalResolvers.task.?, resolvers) { case (Some(delegated), Seq()) => delegated case (_, rs) => task { Resolver.withDefaultResolvers(rs) } diff --git a/main/Keys.scala b/main/Keys.scala index a0fe26a11..eeed6e3a9 100644 --- a/main/Keys.scala +++ b/main/Keys.scala @@ -197,10 +197,10 @@ object Keys val testListeners = TaskKey[Seq[TestReportListener]]("test-listeners", "Defines test listeners.") val testExecution = TaskKey[Tests.Execution]("test-execution", "Settings controlling test execution") val isModule = AttributeKey[Boolean]("is-module", "True if the target is a module.") - + // Classpath/Dependency Management Keys type Classpath = Seq[Attributed[File]] - + val name = SettingKey[String]("name", "Project name.") val normalizedName = SettingKey[String]("normalized-name", "Project name transformed from mixed case and spaces to lowercase and dash-separated.") val description = SettingKey[String]("description", "Project description.") @@ -210,6 +210,7 @@ object Keys val organization = SettingKey[String]("organization", "Organization/group ID.") val organizationName = SettingKey[String]("organization-name", "Organization full/formal name.") val organizationHomepage = SettingKey[Option[URL]]("organization-homepage", "Organization homepage.") + val scmInfo = SettingKey[Option[ScmInfo]]("scm-info", "Basic SCM information for the project.") val projectInfo = SettingKey[ModuleInfo]("project-info", "Addition project information like formal name, homepage, licenses etc.") val defaultConfiguration = SettingKey[Option[Configuration]]("default-configuration", "Defines the configuration used when none is specified for a dependency.") val defaultConfigurationMapping = SettingKey[String]("default-configuration-mapping", "Defines the mapping used for a simple, unmapped configuration definition.") @@ -225,7 +226,7 @@ object Keys val externalDependencyClasspath = TaskKey[Classpath]("external-dependency-classpath", "The classpath consisting of library dependencies, both managed and unmanaged.") val dependencyClasspath = TaskKey[Classpath]("dependency-classpath", "The classpath consisting of internal and external, managed and unmanaged dependencies.") val fullClasspath = TaskKey[Classpath]("full-classpath", "The exported classpath, consisting of build products and unmanaged and managed, internal and external dependencies.") - + val internalConfigurationMap = SettingKey[Configuration => Configuration]("internal-configuration-map", "Maps configurations to the actual configuration used to define the classpath.") val classpathConfiguration = TaskKey[Configuration]("classpath-configuration", "The configuration used to define the classpath.") val ivyConfiguration = TaskKey[IvyConfiguration]("ivy-configuration", "General dependency management (Ivy) settings, such as the resolvers and paths to use.") @@ -240,7 +241,7 @@ object Keys val updateClassifiers = TaskKey[UpdateReport]("update-classifiers", "Resolves and optionally retrieves classified artifacts, such as javadocs and sources, for dependency definitions, transitively.", update) val transitiveClassifiers = SettingKey[Seq[String]]("transitive-classifiers", "List of classifiers used for transitively obtaining extra artifacts for sbt or declared dependencies.") val updateSbtClassifiers = TaskKey[UpdateReport]("update-sbt-classifiers", "Resolves and optionally retrieves classifiers, such as javadocs and sources, for sbt, transitively.", updateClassifiers) - + val publishConfiguration = TaskKey[PublishConfiguration]("publish-configuration", "Configuration for publishing to a repository.") val publishLocalConfiguration = TaskKey[PublishConfiguration]("publish-local-configuration", "Configuration for publishing to the local repository.") val deliverConfiguration = TaskKey[DeliverConfiguration]("deliver-configuration", "Configuration for generating the finished Ivy file for publishing.")