-
Notifications
You must be signed in to change notification settings - Fork 83
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
Library management API #124
Conversation
Note: I've already started to port sbt/zinc and sbt/sbt to the new LM API described in this PR: |
I've created a gist that shows how to resolve a given module ID with this API: I think that there's still room for improvement. Here are some notes that I took while writing that:
That would be great if we could get this example to become shorter.) |
I guess we should move everything that's specific to the Ivy implementation to the |
We need logger during the setup. Task logging needs to be split for
IvyPaths is used throughout testing, and I actually think it's a good idea to change them both at the same time, so I am keeping this one. I did move baseDirectory to external, so there are not duplicates.
I don't think
See Keys.scala.
We should use Vector.
Not sure what you mean by this. You pass in the list of configurations to InlineConfigurations.
I think this fine. The module descriptor has the authoritative list of configurations that it defines. ModuleID can have complex expressions like |
Rebased and squashed. Here's demo a code: scala> import java.io.File
import java.io.File
scala> import sbt.librarymanagement._, syntax._
import sbt.librarymanagement._
import syntax._
scala> val log = sbt.util.LogExchange.logger("test")
log: sbt.internal.util.ManagedLogger = sbt.internal.util.ManagedLogger@c439b0f
scala> val lm = {
import sbt.librarymanagement.ivy._
val ivyConfig = InlineIvyConfiguration().withLog(log)
IvyLibraryManagement(ivyConfig)
}
lm: sbt.librarymanagement.LibraryManagement = sbt.librarymanagement.ivy.IvyLibraryManagement@11c07acb
scala> val module = "commons-io" % "commons-io" % "2.5"
module: sbt.librarymanagement.ModuleID = commons-io:commons-io:2.5
scala> lm.retrieve(module, scalaModuleInfo = None, new File("target"), log)
res0: Either[sbt.librarymanagement.UnresolvedWarning,Vector[java.io.File]] =
Right(Vector(target/jars/commons-io/commons-io/commons-io-2.5.jar,
target/jars/commons-io/commons-io/commons-io-2.5.jar,
target/jars/commons-io/commons-io/commons-io-2.5.jar)) |
Very nice. I think that we now have a much better story in terms of user API. If you think the change is worth it, this commit: Duhemm@460d4d7 changes the configurations in I'll update my WIP PR to port Zinc to this new API, this will give us a new datapoint to assess the quality of this API. |
@Duhemm I like what you've done - I've always been in favour of a more typed way to define module configurations. But I think in addition to splitting the string into a seq we should type the elements, i.e not have them as strings such as "compile" and "test->test". Also, what's the thinking behind using a |
@Duhemm This PR should be refactoring, so the fact that the expected value on the specs are changing makes me a bit suspicious. Also |
organizationArtifact(name, CrossVersion.binary) | ||
|
||
private def organizationArtifact(name: String, cross: CrossVersion) = { | ||
nonEmpty(name, "Artifact ID") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Name"
/** | ||
* Helper mixin to provide methods for library management | ||
*/ | ||
abstract class LibraryManagement extends LibraryManagementInterface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Forwarding my review of #123) Please could we define two different entities and use composition over inheritance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Sorry about that.
@@ -0,0 +1,24 @@ | |||
package sbt.librarymanagement | |||
|
|||
abstract class LibraryManagementSyntax extends DependencyBuilders { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this stay as a trait please? So it can be a mixin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it really worth it? The trait-to-interface is still somewhat fragile (e.g. val
must be final without return types), and I don't know who would ever need to mix this in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok. I guess I'll turn them into traits and put comments to remind future developers to use final val.
@@ -6,10 +6,10 @@ package sbt.librarymanagement | |||
import java.io.{ IOException, File } | |||
import java.net.URL | |||
import scala.xml.XML | |||
import org.apache.ivy.plugins.resolver.DependencyResolver | |||
// import org.apache.ivy.plugins.resolver.DependencyResolver |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
commented code
@@ -259,7 +260,7 @@ class MakePom(val log: Logger) { | |||
types match { | |||
case Nil => Artifact.PomType | |||
case xs if xs.contains(Artifact.DefaultType) => Artifact.DefaultType | |||
case x :: xs => x | |||
case x :: (xs @ _) => x |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's going on here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's to silent the huge number of warnings. If I'm right, I would prefer case x :: _ => ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoiding the compiler warning. Could also be _
, but I grew up writing x :: xs
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL. Thank you.
@@ -145,7 +145,8 @@ object VersionNumber { | |||
case (v1, v2) | |||
if (v1.size >= 3) && (v2.size >= 3) => // A normal version number MUST take the form X.Y.Z | |||
(v1._1.get, v1._2.get, v1._3.get, v1.tags, v2._1.get, v2._2.get, v2._3.get, v2.tags) match { | |||
case (x1, y1, 0, ts1, x2, y2, 0, ts2) if ts1.nonEmpty || ts2.nonEmpty => | |||
case (x1 @ _, y1 @ _, 0, ts1, x2 @ _, y2 @ _, 0, ts2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what with all the @ _
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoiding compiler warnings.
|
||
// Todo. Fix publish ordering https://github.com/sbt/sbt/issues/2088#issuecomment-246208872 | ||
val ivyFile: Option[File] = | ||
if (configuration.publishMavenStyle) None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this a blocker for this PR? Does this (with the todo above) mean we no longer publish POM files?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the first step towards folding deliver
into publish
.
I haven't changed anything with POM. I think it's handled as an artifact in Defaults.scala:
publishArtifact in makePom := publishMavenStyle.value && publishArtifact.value,
artifact in makePom := Artifact.pom(moduleName.value),
case a: IArtifact => applyFilter(f, a) | ||
} | ||
|
||
def applyFilter(f: ArtifactTypeFilter, a: IArtifact): Boolean = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The f is redundant.
@@ -209,7 +209,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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
commented code
@dwijnand I'm not super familiar with this code, but my understanding is that when there is no configuration that is explicitly set ( @eed3si9n I agree, this is just a POC. I changed the tests to compensate for the |
|
Yes. There's a weird coupling between |
/** | ||
* Interface for library management intended for library management engine authors. | ||
*/ | ||
abstract class LibraryManagementInterface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could the interfaces in this file be interfaces?
Also can we call this RetrieverInterface (or similar)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
retrieve is a specific feature so a generic sounding name would be DependencyResolutionInterface
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WFM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
LGTM, pending sbt/zinc and sbt/sbt ripple PRs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment
* if any. | ||
*/ | ||
def scalaModuleInfo: Option[ScalaModuleInfo] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please split this in 3 files (DependencyResolutionInterface.scala
, PublisherInterface.scala
and ModuleDescriptor.scala
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually thought it would be a good idea to keep all the open-ended interfaces so we can link to the file and talk about it.
I forgot about |
This splits the core of LM and Ivy-based implementation. - InlineConfiguration is renamed to ModuleConfiguration - IvyScala is renamed to ScalaModuleInfo - UpdateConfiguration, RetrieveConfiguration, PublishConfiguration are refactored to use builder pattern. - Adds ConfigRef for referencing Configuration - Moves syntax related things into `sbt.librarymagement.syntax`
This is used only by sbt, and we are not sure if it needs to be part of the API
Tests passing and |
This is continuation of #113 and #123 on a shared branch.
Ref sbt/sbt#2294
The goal of Library Management API is to create an Ivy-free interface that can abstract different dependency resolution implementations such as Ivy, cached resolution, and Coursier.
Note this PR is intended to be Refactoring, in the sense that this should not introduce any change to the observable behavior.
DependencyResolution
DependencyResolution
is the user-facing API that contains useful helper functions.The intended audience is build users and plugin authors.
DependencyResolutionInterface
DependencyResolutionInterface
is the interface dependency resolution engine authors will implement to provide the resolution feature:These methods define the most general forms of performing
update
.If the implementation already integrates with sbt, it should be easy to implement them.
IvyLibraryManagement
Here's the reference implementation using Ivy.
https://github.com/eed3si9n/librarymanagement/blob/7b21353a06aab419de7892fd13cee2f4da8f26da/ivy/src/main/scala/sbt/librarymanagement/IvyLibraryManagement.scala
Credits
This PR is co-authored by Eugene Yokota (@eed3si9n, Lightbend) and Martin Duhem (@Duhemm, Scala Center). I've squash a bunch of commits by Martin from #125 and #127.