sbt-idea icon indicating copy to clipboard operation
sbt-idea copied to clipboard

Attaching sources to dependencies

Open symfrog opened this issue 13 years ago • 3 comments

Hi

What is the best way to attach sources to the Intellij dependencies? After I run the "idea" command there does seem to be a source path attached for each dependency, e.g.: /Users/dev/scala/proj/lib_managed/scala_2.8.1/test/servlet-api-2.5.0.jar

Has source location:

/Users/dev/scala/proj/lib_managed/scala_2.8.1/test/servlet-api-2.5.0-sources.jar

Is it possible to tell sbt-idea to use a specific path format when it generates source attachment paths?

Alternatively is it possible to configure my sbt ivy retrieve pattern in such a way as to match the source locations generated by sbt-idea?

I am automatically retrieving the sources of my ivy.xml dependencies using sbt-sources(https://github.com/OlegYch/sbt-sources-plugin), so I would prefer to avoid copying source jars manually into the sbt-idea expected locations.

Thanks

symfrog avatar May 04 '11 14:05 symfrog

Unfortunately I don't have an immediate answer for you. I haven't used sbt-sources-plugin, and have only used withSources() declarations in project definition which just work with sbt-idea, but obviously miss transitive dependencies.

So I would be interested in the answer to this too!

mpeltonen avatar May 05 '11 14:05 mpeltonen

I have found a setup that I am happy with, sbt update is retrieving all my dependencies' sources transitively.

I have patched sbt-idea to be able to use a regular expression to distinguish between sources, jars, and javadocs and the relation between them. Using the patch I can now do the following in my project definition:

import java.io.File
import sbt._
import Process._
import FileUtilities._
import java.util.jar.Manifest
import scala.util.matching.Regex

class CustomProject(info: ProjectInfo) extends DefaultProject(info) with IdeaProject{
   override val outputPattern = "[conf]/[type]s/[artifact](-[revision])(-[classifier]).[ext]"
   override val JarsPattern:Regex = """.*/jars/(.*)\.jar""".r
   override val SourcesPattern:Regex = """.*/sources/(.*)\.jar""".r
}

I ran the sbt-idea tests after the modifications and it seems the tests for issue-50 and issue-52 are failing. The failure seems to be that the "scope" attribute is no longer being added to order entries. I would be happy to track down the reason/fix if you think the changes are acceptable.

Here is the git patch:

---
 .../src/main/scala/IdeaModuleDescriptor.scala      |   40 ++++++++++++++------
 sbt-idea-plugin/src/main/scala/IdeaProject.scala   |   11 ++++-
 .../src/main/scala/IdeaProcessor.scala             |    8 +++-
 3 files changed, 43 insertions(+), 16 deletions(-)

diff --git a/sbt-idea-core/src/main/scala/IdeaModuleDescriptor.scala b/sbt-idea-core/src/main/scala/IdeaModuleDescriptor.scala
index d17abe6..870748e 100644
--- a/sbt-idea-core/src/main/scala/IdeaModuleDescriptor.scala
+++ b/sbt-idea-core/src/main/scala/IdeaModuleDescriptor.scala
@@ -7,8 +7,23 @@
 import sbt._
 import java.io.File
 import xml.{UnprefixedAttribute, NodeSeq, Node, NodeBuffer}
+import scala.util.matching.Regex
+
+class IdeaModuleDescriptor(val project: BasicDependencyProject,val JarsPattern:Regex,val SourcesPattern:Regex, val JavadocsPattern:Regex,val log: Logger) extends SaveableXml with ProjectPaths {
+
+ 
+  class RegexFilter(val Pattern:Regex) extends FileFilter{
+    override def accept(file:File):Boolean={
+      (Pattern findFirstIn file.getAbsolutePath) match{
+        case Some(_) => true
+        case None => false
+      }
+    }
+  }
+  val Jars = new RegexFilter(JarsPattern)
+  val Sources = new RegexFilter(SourcesPattern)
+  val JavaDocs = new RegexFilter(JavadocsPattern)

-class IdeaModuleDescriptor(val project: BasicDependencyProject, val log: Logger) extends SaveableXml with ProjectPaths {
   val path = String.format("%s/%s.iml", projectPath, project.name)
   val env = new IdeaProjectEnvironment(project.rootProject)
   val userEnv = new IdeaUserEnvironment(project.rootProject)
@@ -95,13 +110,6 @@ class IdeaModuleDescriptor(val project: BasicDependencyProject, val log: Logger)
         }
         {
           val Jar = ".jar"
-          val Jars = GlobFilter("*" + Jar)
-
-          val SourcesJar = "-sources" + Jar
-          val Sources = GlobFilter("*" + SourcesJar)
-
-          val JavaDocJar = "-javadoc" + Jar
-          val JavaDocs = GlobFilter("*" + JavaDocJar)

           val classpathJars = ideClasspath ** Jars

@@ -118,7 +126,7 @@ class IdeaModuleDescriptor(val project: BasicDependencyProject, val log: Logger)
             case _ => List()
           }.foldLeft(Set.empty[(String, Long)])(_++_)

-          val sources = allJars ** Sources
+          val sources = ((project.unmanagedClasspath +++ project.managedDependencyPath) ** Sources)
           val javadoc = allJars ** JavaDocs
           val allClasses = classpathJars --- sources --- javadoc
           val classes = allClasses.filter(p => !alreadyDeclared((nameWithScope(p.asFile), p.asFile.length)))
@@ -127,9 +135,17 @@ class IdeaModuleDescriptor(val project: BasicDependencyProject, val log: Logger)
           def named(pf: PathFinder, suffix: String) = Map() ++ pf.getFiles.toList.sort(_.getAbsolutePath > _.getAbsolutePath).map(file =>
             cut(file.getName, suffix) -> relativePath(file))

-          val namedSources = named(sources, SourcesJar)
-          val namedJavadoc = named(javadoc, JavaDocJar)
-          val namedClasses = named(classes, Jar)
+          def namedRegex(pf: PathFinder, Pattern:Regex)={
+            Map() ++ pf.getFiles.toList.sort(_.getAbsolutePath > _.getAbsolutePath).map(file =>{ val name = file.getAbsolutePath match {
+              case Pattern(a) => a
+              case _ => throw new RuntimeException("Pattern %s did not match file path %s".format(Pattern,file.getAbsolutePath))
+            }
+            name -> relativePath(file)})
+          }
+
+          val namedSources = namedRegex(sources, SourcesPattern)
+          val namedJavadoc = namedRegex(javadoc, JavadocsPattern)
+          val namedClasses = namedRegex(classes, JarsPattern)

           val defaultJars = defaultClasspath ** Jars
           val defaultJarNames = defaultJars.get.map(_.name).toList
diff --git a/sbt-idea-plugin/src/main/scala/IdeaProject.scala b/sbt-idea-plugin/src/main/scala/IdeaProject.scala
index 6057732..ec95cfe 100644
--- a/sbt-idea-plugin/src/main/scala/IdeaProject.scala
+++ b/sbt-idea-plugin/src/main/scala/IdeaProject.scala
@@ -6,22 +6,27 @@

 import sbt._

+import scala.util.matching.Regex
 trait IdeaProject extends BasicDependencyProject {

   lazy val env = new IdeaProjectEnvironment(this)

+  val JarsPattern:Regex = """(.*)\.jar""".r
+  val SourcesPattern:Regex = """(.*)-sources\.jar""".r
+  val JavadocsPattern:Regex = """(.*)-javadoc\.jar""".r
+
   lazy val idea = task {  createIdeaProject; None  } describedAs("Creates IntelliJ IDEA project files.")

   def createIdeaProject: Unit = {
     if (this eq rootProject) {
-      new IdeaProjectDescriptor(this, log).save
+      new IdeaProjectDescriptor(this,log).save
       if (env.includeSbtProjectDefinitionModule.value) {
         new SbtProjectDefinitionIdeaModuleDescriptor(this, log).save
       }
     }
     this match {
       case pp: ParentProject => new ParentProjectIdeaModuleDescriptor(pp, log).save
-      case bdp: BasicDependencyProject => new IdeaModuleDescriptor(bdp, log).save
+      case bdp: BasicDependencyProject => new IdeaModuleDescriptor(bdp, JarsPattern, SourcesPattern, JavadocsPattern,log).save
     }
   }
-}
\ No newline at end of file
+}
diff --git a/sbt-idea-processor/src/main/scala/IdeaProcessor.scala b/sbt-idea-processor/src/main/scala/IdeaProcessor.scala
index 4512119..60bf94b 100644
--- a/sbt-idea-processor/src/main/scala/IdeaProcessor.scala
+++ b/sbt-idea-processor/src/main/scala/IdeaProcessor.scala
@@ -6,8 +6,14 @@

 import sbt._
 import processor._
+import scala.util.matching.Regex

 class IdeaProcessor extends BasicProcessor {
+
+  val JarsPattern:Regex = """(.*)\.jar""".r
+  val SourcesPattern:Regex = """(.*)-sources\.jar""".r
+  val JavadocsPattern:Regex = """(.*)-javadoc\.jar""".r
+
   def apply(project:Project, args:String){
     attemptIdeaProject(project)
   }
@@ -33,7 +39,7 @@ class IdeaProcessor extends BasicProcessor {
     }
     project match {
       case pp: ParentProject => new ParentProjectIdeaModuleDescriptor(pp, project.log).save
-      case bdp: BasicDependencyProject => new IdeaModuleDescriptor(bdp, project.log).save
+      case bdp: BasicDependencyProject => new IdeaModuleDescriptor(bdp,JarsPattern, SourcesPattern, JavadocsPattern, project.log).save
     }
   }

-- 
1.7.5

symfrog avatar May 06 '11 11:05 symfrog

Note that this should work correctly with the sbt-0.10 branch.

ijuma avatar Jul 15 '11 14:07 ijuma