Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace library dependencies with module dependencies #169

Open
wants to merge 8 commits into
base: sbt-0.11
Choose a base branch
from
78 changes: 20 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,64 +1,26 @@
Requirements
------------
This is a clone of sbt-idea which replaces library dependencies within a project with module dependency
if artifact ids match. This is useful, for example, if you have a general purpose library A you depend
on in one of your more specific projects B, and you want to improve A as you develop B.
You can incorporate such a dependency in the B build file by using `dependsOn` between sbt projects,
but this then requires developers of B to get sources for the general purpose library A too, and place it in the file
system according to the build dependency.

* [sbt](https://github.com/harrah/xsbt/wiki) 0.11.2 or 0.11.3.
* For sbt 0.12.x version of the plugin, see [branch sbt-0.12](https://github.com/mpeltonen/sbt-idea/tree/sbt-0.12#requirements)
* For sbt 0.7.x version of the plugin, see [branch sbt-0.7](https://github.com/mpeltonen/sbt-idea/tree/sbt-0.7)
To use it set up a "workspace" sbt project that aggregates a couple of sbt projects on your local harddisk.
For example:

```scala
import sbt._

Installation
------------
object Workspace extends Build {
lazy val root = Project("root", file(".")) aggregate(p1,p2)
lazy val p1 = RootProject(file("../p1"))
lazy val p2 = RootProject(file("../p2"))
}
```

Add the following line to ~/.sbt/plugins/build.sbt or PROJECT_DIR/project/plugins.sbt
Running `sbt gen-idea` in this project will create an intellij project file, as before. However, if project
`p1` has a library dependency to the artifact of `p2` (as determined by their name, org, scala version and version
settings), then the Intellij project will have a module dependency in module p1 to module p2, as opposed to
a library dependency (to the library jar in the local ivy repo).

addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.1.0")

To use the latest snapshot version, add also Sonatype snapshots repository resolver into the same file:

resolvers += "Sonatype snapshots" at "http://oss.sonatype.org/content/repositories/snapshots/"

addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.2.0-SNAPSHOT")

Usage
-----

### Basic project

Use the `gen-idea` sbt task to create Idea project files.

### Project with dependencies

If you have two sbt projects A and B, and A depends on B, then use the `gen-idea` sbt task on Project A to create Idea project files for both projects.

The projects need to be set up in the following way:

*Project A:*

import sbt._

object A extends Build {
lazy val A = Project("A", file(".")) aggregate(B) dependsOn(B)
lazy val B = RootProject(file("../B"))
}

*Project B:*

import sbt._

object B extends Build {
lazy val B = Project("B", file("."))
}

### Sources and javadocs

By default, classifiers (i.e. sources and javadocs) of dependencies are loaded if found and references added to Idea project files. If you don't want to download/reference them, use command 'gen-idea no-classifiers'.

Configuration settings
----------------------

TODO...

License
-------

Licensed under the New BSD License. See the LICENSE file for details.
2 changes: 1 addition & 1 deletion project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ object SbtIdeaBuild extends Build {
lazy val mainSettings: Seq[Project.Setting[_]] = Defaults.defaultSettings ++ ScriptedPlugin.scriptedSettings ++ Seq(
sbtPlugin := true,
organization := "com.github.mpeltonen",
name := "sbt-idea",
name := "sbt-idea-rc",
version := "1.2.0-SNAPSHOT",
publishTo := Some(Resolver.file("Github Pages", Path.userHome / "git" / "mpeltonen.github.com" / "maven" asFile)(Patterns(true, Resolver.mavenStyleBasePattern))),
publishTo <<= version { (v: String) =>
Expand Down
7 changes: 6 additions & 1 deletion src/main/scala/org/sbtidea/IdeaProjectDomain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,16 @@ case class Directories(sources: Seq[File], resources: Seq[File], outDir: File) {
def addRes (moreResources: Seq[File]): Directories = Directories(sources, resources ++ moreResources, outDir)
}

case class ArtifactId(name:String, version:String, organization:String, scalaVersion:String) {
def toFullName = organization + "_" + name + "_" + scalaVersion + "_" + version
}

case class SubProjectInfo(baseDir: File, name: String, dependencyProjects: List[String], classpathDeps: Seq[(File, Seq[File])], compileDirs: Directories,
testDirs: Directories, libraries: Seq[IdeaModuleLibRef], scalaInstance: ScalaInstance,
ideaGroup: Option[String], webAppPath: Option[File], basePackage: Option[String],
packagePrefix: Option[String],
extraFacets: NodeSeq)
extraFacets: NodeSeq,
artifactId:ArtifactId)

case class IdeaProjectInfo(baseDir: File, name: String, childProjects: List[SubProjectInfo], ideaLibs: List[IdeaLibrary])

Expand Down
35 changes: 32 additions & 3 deletions src/main/scala/org/sbtidea/SbtIdeaPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ object SbtIdeaPlugin extends Plugin {

private val NoClassifiers = "no-classifiers"
private val SbtClassifiers = "sbt-classifiers"
private val ReplaceLibsByModules = "replace-libs"
private val NoFsc = "no-fsc"

private val args = (Space ~> NoClassifiers | Space ~> SbtClassifiers | Space ~> NoFsc).*
private val args = (Space ~> NoClassifiers | Space ~> SbtClassifiers | Space ~> NoFsc | Space ~> ReplaceLibsByModules).*

private lazy val ideaCommand = Command("gen-idea")(_ => args)(doCommand)

Expand Down Expand Up @@ -79,10 +80,15 @@ object SbtIdeaPlugin extends Plugin {
}

val allProjectIds = projectList.values.map(_.id).toSet
val subProjects = projectList.collect {
val subProjectsRaw = projectList.collect {
case (projRef, project) if (!ignoreModule(projRef)) => projectData(projRef, project, buildStruct, state, args, allProjectIds)
}.toList

val subProjects = if (args.contains(ReplaceLibsByModules))
replaceLibDependenciesWithModuleDependencies(state, subProjectsRaw)
else
subProjectsRaw

val scalaInstances = subProjects.map(_.scalaInstance).distinct
val scalaLibs = (sbtInstance :: scalaInstances).map(toIdeaLib(_))
val ideaLibs = subProjects.flatMap(_.libraries.map(modRef => modRef.library)).toList.distinct
Expand Down Expand Up @@ -139,6 +145,20 @@ object SbtIdeaPlugin extends Plugin {
state
}

def replaceLibDependenciesWithModuleDependencies(state:State, subprojects: List[SubProjectInfo]) = {
val name2project = subprojects.groupBy(_.artifactId.toFullName)
for (sub <- subprojects) yield {
val libs = sub.libraries
val (replaceable, nonreplacable) = libs.partition(l => name2project.isDefinedAt(l.library.name))
val subprojectsToUseInstead = replaceable.map(l => name2project(l.library.name).head.name).toList
val newSubProject = sub.copy(libraries = nonreplacable, dependencyProjects = sub.dependencyProjects ++ subprojectsToUseInstead)
for (lib <- replaceable) {
logger(state).info("Replacing library %s with module %s".format(lib.library.name,name2project(lib.library.name).head.name))
}
newSubProject
}
}

def projectData(projectRef: ProjectRef, project: ResolvedProject, buildStruct: BuildStructure,
state: State, args: Seq[String], allProjectIds: Set[String]): SubProjectInfo = {

Expand All @@ -163,6 +183,13 @@ object SbtIdeaPlugin extends Plugin {
// IDEA project name. It must be consistent with the value of SubProjectInfo#dependencyProjects.
val projectName = project.id

val artifactId = ArtifactId(
name = setting(Keys.artifact, "Artifact not defined").name,
version = setting(Keys.version, "Version not defined"),
organization = setting(Keys.organization, "Org not defined"),
scalaVersion = setting(Keys.scalaVersion, "Scala version not defined")
)

logger(state).info("Trying to create an Idea module " + projectName)

val ideaGroup = optionalSetting(ideaProjectGroup)
Expand Down Expand Up @@ -231,6 +258,8 @@ object SbtIdeaPlugin extends Plugin {
}
}
SubProjectInfo(baseDirectory, projectName, project.uses.map(_.project).filter(isAggregate).toList, classpathDeps, compileDirectories,
testDirectories, librariesExtractor.allLibraries, scalaInstance, ideaGroup, None, basePackage, packagePrefix, extraFacets)
testDirectories, librariesExtractor.allLibraries, scalaInstance, ideaGroup, None, basePackage, packagePrefix, extraFacets,
artifactId
)
}
}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.2.0-SNAPSHOT")
addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "")
Original file line number Diff line number Diff line change
@@ -1 +1 @@
addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.2.0-SNAPSHOT")
addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "")
Original file line number Diff line number Diff line change
@@ -1 +1 @@
addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.2.0-SNAPSHOT")
addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "")
2 changes: 1 addition & 1 deletion src/sbt-test/sbt-idea/simple-project/project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.2.0-SNAPSHOT")
addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "")
Original file line number Diff line number Diff line change
@@ -1 +1 @@
addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.2.0-SNAPSHOT")
addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "")