mirror of https://github.com/sbt/sbt.git
Merge pull request #781 from coursier/topic/less-scalaz
Use less things from scalaz
This commit is contained in:
commit
834fbd598a
12
README.md
12
README.md
|
|
@ -131,6 +131,8 @@ libraryDependencies ++= Seq(
|
|||
)
|
||||
```
|
||||
|
||||
Note that the examples below are validated against the current sources of coursier. You may want to read the [documentation of the latest release](https://github.com/coursier/coursier/blob/v1.0.2/README.md#api) of coursier instead.
|
||||
|
||||
Add an import for coursier,
|
||||
```scala
|
||||
import coursier._
|
||||
|
|
@ -181,10 +183,9 @@ These would mean that the resolution wasn't able to get metadata about some depe
|
|||
Then fetch and get local copies of the artifacts themselves (the JARs) with
|
||||
```scala
|
||||
import java.io.File
|
||||
import scalaz.\/
|
||||
import scalaz.concurrent.Task
|
||||
|
||||
val localArtifacts: Seq[FileError \/ File] = Task.gatherUnordered(
|
||||
val localArtifacts: Seq[Either[FileError, File]] = Task.gatherUnordered(
|
||||
resolution.artifacts.map(Cache.file(_).run)
|
||||
).unsafePerformSync
|
||||
```
|
||||
|
|
@ -422,6 +423,8 @@ libraryDependencies ++= Seq(
|
|||
)
|
||||
```
|
||||
|
||||
Note that the examples below are validated against the current sources of coursier. You may want to read the [documentation of the latest release](https://github.com/coursier/coursier/blob/v1.0.2/README.md#api-1) of coursier instead.
|
||||
|
||||
The first module, `"io.get-coursier" %% "coursier" % "1.0.1"`, mainly depends on
|
||||
`scalaz-core` (and only it, *not* `scalaz-concurrent` for example). It contains among others,
|
||||
definitions,
|
||||
|
|
@ -509,7 +512,7 @@ res6: coursier.maven.MavenRepository = MavenRepository(https://nexus.corp.com/co
|
|||
|
||||
Now that we have repositories, we're going to mix these with things from the `coursier-cache` module,
|
||||
for resolution to happen via the cache. We'll create a function
|
||||
of type `Seq[(Module, String)] => F[Seq[((Module, String), Seq[String] \/ (Artifact.Source, Project))]]`.
|
||||
of type `Seq[(Module, String)] => F[Seq[((Module, String), Either[Seq[String], (Artifact.Source, Project)])]]`.
|
||||
Given a sequence of dependencies, designated by their `Module` (organisation and name in most cases)
|
||||
and version (just a `String`), it gives either errors (`Seq[String]`) or metadata (`(Artifact.Source, Project)`),
|
||||
wrapping the whole in a monad `F`.
|
||||
|
|
@ -564,10 +567,9 @@ which are dependencies whose versions could not be unified.
|
|||
Then, if all went well, we can fetch and get local copies of the artifacts themselves (the JARs) with
|
||||
```scala
|
||||
import java.io.File
|
||||
import scalaz.\/
|
||||
import scalaz.concurrent.Task
|
||||
|
||||
val localArtifacts: Seq[FileError \/ File] = Task.gatherUnordered(
|
||||
val localArtifacts: Seq[Either[FileError, File]] = Task.gatherUnordered(
|
||||
resolution.artifacts.map(Cache.file(_).run)
|
||||
).unsafePerformSync
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
package coursier
|
||||
|
||||
import java.math.BigInteger
|
||||
import java.net.{ HttpURLConnection, URL, URLConnection, URLStreamHandler, URLStreamHandlerFactory }
|
||||
import java.nio.channels.{ OverlappingFileLockException, FileLock }
|
||||
import java.net.{HttpURLConnection, URL, URLConnection, URLStreamHandler, URLStreamHandlerFactory}
|
||||
import java.nio.channels.{FileLock, OverlappingFileLockException}
|
||||
import java.security.MessageDigest
|
||||
import java.util.concurrent.{ Callable, ConcurrentHashMap, Executors, ExecutorService }
|
||||
import java.util.concurrent.{Callable, ConcurrentHashMap, ExecutorService, Executors}
|
||||
import java.util.regex.Pattern
|
||||
|
||||
import coursier.core.Authentication
|
||||
|
|
@ -13,15 +13,14 @@ import coursier.internal.FileUtil
|
|||
import coursier.util.Base64.Encoder
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
||||
import scalaz._
|
||||
import scalaz.Scalaz.ToEitherOps
|
||||
import scalaz.concurrent.{ Task, Strategy }
|
||||
|
||||
import java.io.{ Serializable => _, _ }
|
||||
import scalaz.Nondeterminism
|
||||
import scalaz.concurrent.{Strategy, Task}
|
||||
import java.io.{Serializable => _, _}
|
||||
import java.nio.charset.Charset
|
||||
|
||||
import scala.concurrent.duration.{ Duration, DurationInt }
|
||||
import coursier.util.EitherT
|
||||
|
||||
import scala.concurrent.duration.{Duration, DurationInt}
|
||||
import scala.util.Try
|
||||
import scala.util.control.NonFatal
|
||||
|
||||
|
|
@ -83,9 +82,9 @@ object Cache {
|
|||
cache: File,
|
||||
file: File
|
||||
)(
|
||||
f: => FileError \/ T,
|
||||
ifLocked: => Option[FileError \/ T]
|
||||
): FileError \/ T = {
|
||||
f: => Either[FileError, T],
|
||||
ifLocked: => Option[Either[FileError, T]]
|
||||
): Either[FileError, T] = {
|
||||
|
||||
val lockFile = CachePath.lockFile(file)
|
||||
|
||||
|
|
@ -97,7 +96,7 @@ object Cache {
|
|||
}
|
||||
|
||||
@tailrec
|
||||
def loop(): FileError \/ T = {
|
||||
def loop(): Either[FileError, T] = {
|
||||
|
||||
val resOpt = {
|
||||
var lock: FileLock = null
|
||||
|
|
@ -133,8 +132,8 @@ object Cache {
|
|||
finally if (out != null) out.close()
|
||||
}
|
||||
|
||||
def withLockFor[T](cache: File, file: File)(f: => FileError \/ T): FileError \/ T =
|
||||
withLockOr(cache, file)(f, Some(-\/(FileError.Locked(file))))
|
||||
def withLockFor[T](cache: File, file: File)(f: => Either[FileError, T]): Either[FileError, T] =
|
||||
withLockOr(cache, file)(f, Some(Left(FileError.Locked(file))))
|
||||
|
||||
|
||||
private def defaultRetryCount = 3
|
||||
|
|
@ -152,11 +151,11 @@ object Cache {
|
|||
logger: Option[Logger],
|
||||
retry: Int = retryCount
|
||||
)(
|
||||
f: => FileError \/ T
|
||||
): FileError \/ T = {
|
||||
f: => Either[FileError, T]
|
||||
): Either[FileError, T] = {
|
||||
|
||||
@tailrec
|
||||
def helper(retry: Int): FileError \/ T = {
|
||||
def helper(retry: Int): Either[FileError, T] = {
|
||||
|
||||
val resOpt =
|
||||
try {
|
||||
|
|
@ -164,20 +163,17 @@ object Cache {
|
|||
val prev = urlLocks.putIfAbsent(url, o)
|
||||
|
||||
val res =
|
||||
if (prev == null) {
|
||||
val res =
|
||||
try \/-(f)
|
||||
catch {
|
||||
case nfe: FileNotFoundException if nfe.getMessage != null =>
|
||||
-\/(-\/(FileError.NotFound(nfe.getMessage)))
|
||||
}
|
||||
finally {
|
||||
urlLocks.remove(url)
|
||||
}
|
||||
|
||||
res.merge[FileError \/ T]
|
||||
} else
|
||||
-\/(FileError.ConcurrentDownload(url))
|
||||
if (prev == null)
|
||||
try f
|
||||
catch {
|
||||
case nfe: FileNotFoundException if nfe.getMessage != null =>
|
||||
Left(FileError.NotFound(nfe.getMessage))
|
||||
}
|
||||
finally {
|
||||
urlLocks.remove(url)
|
||||
}
|
||||
else
|
||||
Left(FileError.ConcurrentDownload(url))
|
||||
|
||||
Some(res)
|
||||
}
|
||||
|
|
@ -186,7 +182,7 @@ object Cache {
|
|||
// TODO If Cache is made an (instantiated) class at some point, allow to log that exception.
|
||||
None
|
||||
case NonFatal(e) =>
|
||||
Some(-\/(
|
||||
Some(Left(
|
||||
FileError.DownloadError(
|
||||
s"Caught $e${Option(e.getMessage).fold("")(" (" + _ + ")")} while downloading $url"
|
||||
)
|
||||
|
|
@ -325,7 +321,7 @@ object Cache {
|
|||
url: String,
|
||||
authentication: Option[Authentication],
|
||||
logger0: Option[Logger]
|
||||
): FileError \/ Option[Long] = {
|
||||
): Either[FileError, Option[Long]] = {
|
||||
|
||||
val logger = logger0.map(Logger.Extended(_))
|
||||
|
||||
|
|
@ -350,14 +346,14 @@ object Cache {
|
|||
success = true
|
||||
logger.foreach(_.gettingLengthResult(url, len))
|
||||
|
||||
len.right
|
||||
Right(len)
|
||||
} finally {
|
||||
if (!success)
|
||||
logger.foreach(_.gettingLengthResult(url, None))
|
||||
}
|
||||
|
||||
case other =>
|
||||
-\/(FileError.DownloadError(s"Cannot do HEAD request with connection $other ($url)"))
|
||||
Left(FileError.DownloadError(s"Cannot do HEAD request with connection $other ($url)"))
|
||||
}
|
||||
} finally {
|
||||
if (conn != null)
|
||||
|
|
@ -373,7 +369,7 @@ object Cache {
|
|||
pool: ExecutorService,
|
||||
logger0: Option[Logger] = None,
|
||||
ttl: Option[Duration] = defaultTtl
|
||||
): Task[Seq[((File, String), FileError \/ Unit)]] = {
|
||||
): Task[Seq[((File, String), Either[FileError, Unit])]] = {
|
||||
|
||||
implicit val pool0 = pool
|
||||
|
||||
|
|
@ -391,13 +387,13 @@ object Cache {
|
|||
def fileLastModified(file: File): EitherT[Task, FileError, Option[Long]] =
|
||||
EitherT {
|
||||
Task {
|
||||
\/- {
|
||||
Right {
|
||||
val lastModified = file.lastModified()
|
||||
if (lastModified > 0L)
|
||||
Some(lastModified)
|
||||
else
|
||||
None
|
||||
} : FileError \/ Option[Long]
|
||||
} : Either[FileError, Option[Long]]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -433,14 +429,14 @@ object Cache {
|
|||
success = true
|
||||
logger.foreach(_.checkingUpdatesResult(url, currentLastModifiedOpt, res))
|
||||
|
||||
res.right
|
||||
Right(res)
|
||||
} finally {
|
||||
if (!success)
|
||||
logger.foreach(_.checkingUpdatesResult(url, currentLastModifiedOpt, None))
|
||||
}
|
||||
|
||||
case other =>
|
||||
-\/(FileError.DownloadError(s"Cannot do HEAD request with connection $other ($url)"))
|
||||
Left(FileError.DownloadError(s"Cannot do HEAD request with connection $other ($url)"))
|
||||
}
|
||||
} finally {
|
||||
if (conn != null)
|
||||
|
|
@ -510,17 +506,17 @@ object Cache {
|
|||
EitherT {
|
||||
fileExists(file).flatMap {
|
||||
case false =>
|
||||
Task.now(true.right)
|
||||
Task.now(Right(true))
|
||||
case true =>
|
||||
checkNeeded.flatMap {
|
||||
case false =>
|
||||
Task.now(false.right)
|
||||
Task.now(Right(false))
|
||||
case true =>
|
||||
check.run.flatMap {
|
||||
case \/-(false) =>
|
||||
case Right(false) =>
|
||||
Task {
|
||||
doTouchCheckFile(file)
|
||||
\/-(false)
|
||||
Right(false)
|
||||
}
|
||||
case other =>
|
||||
Task.now(other)
|
||||
|
|
@ -559,7 +555,7 @@ object Cache {
|
|||
|
||||
var lenOpt = Option.empty[Option[Long]]
|
||||
|
||||
def doDownload(): FileError \/ Unit =
|
||||
def doDownload(): Either[FileError, Unit] =
|
||||
downloading(url, file, logger) {
|
||||
|
||||
val alreadyDownloaded = tmp.length()
|
||||
|
|
@ -587,9 +583,9 @@ object Cache {
|
|||
}
|
||||
|
||||
if (responseCode(conn) == Some(404))
|
||||
FileError.NotFound(url, permanent = Some(true)).left
|
||||
Left(FileError.NotFound(url, permanent = Some(true)))
|
||||
else if (responseCode(conn) == Some(401))
|
||||
FileError.Unauthorized(url, realm = realm(conn)).left
|
||||
Left(FileError.Unauthorized(url, realm = realm(conn)))
|
||||
else {
|
||||
// TODO Use the safer getContentLengthLong when switching back to Java >= 7
|
||||
for (len0 <- Option(conn.getContentLength) if len0 >= 0L) {
|
||||
|
|
@ -619,7 +615,7 @@ object Cache {
|
|||
|
||||
doTouchCheckFile(file)
|
||||
|
||||
result.right
|
||||
Right(result)
|
||||
}
|
||||
} finally {
|
||||
if (conn != null)
|
||||
|
|
@ -627,11 +623,11 @@ object Cache {
|
|||
}
|
||||
}
|
||||
|
||||
def checkDownload(): Option[FileError \/ Unit] = {
|
||||
def checkDownload(): Option[Either[FileError, Unit]] = {
|
||||
|
||||
def progress(currentLen: Long): Unit =
|
||||
if (lenOpt.isEmpty) {
|
||||
lenOpt = Some(contentLength(url, artifact.authentication, logger).toOption.flatten)
|
||||
lenOpt = Some(contentLength(url, artifact.authentication, logger).right.toOption.flatten)
|
||||
for (o <- lenOpt; len <- o)
|
||||
logger.foreach(_.downloadLength(url, len, currentLen, watching = true))
|
||||
} else
|
||||
|
|
@ -639,7 +635,7 @@ object Cache {
|
|||
|
||||
def done(): Unit =
|
||||
if (lenOpt.isEmpty) {
|
||||
lenOpt = Some(contentLength(url, artifact.authentication, logger).toOption.flatten)
|
||||
lenOpt = Some(contentLength(url, artifact.authentication, logger).right.toOption.flatten)
|
||||
for (o <- lenOpt; len <- o)
|
||||
logger.foreach(_.downloadLength(url, len, len, watching = true))
|
||||
} else
|
||||
|
|
@ -648,7 +644,7 @@ object Cache {
|
|||
|
||||
if (file.exists()) {
|
||||
done()
|
||||
Some(().right)
|
||||
Some(Right(()))
|
||||
} else {
|
||||
// yes, Thread.sleep. 'tis our thread pool anyway.
|
||||
// (And the various resources make it not straightforward to switch to a more Task-based internal API here.)
|
||||
|
|
@ -658,7 +654,7 @@ object Cache {
|
|||
|
||||
if (currentLen == 0L && file.exists()) { // check again if file exists in case it was created in the mean time
|
||||
done()
|
||||
Some(().right)
|
||||
Some(Right(()))
|
||||
} else {
|
||||
progress(currentLen)
|
||||
None
|
||||
|
|
@ -668,7 +664,7 @@ object Cache {
|
|||
|
||||
logger.foreach(_.downloadingArtifact(url, file))
|
||||
|
||||
var res: FileError \/ Unit = null
|
||||
var res: Either[FileError, Unit] = null
|
||||
|
||||
try {
|
||||
res = withLockOr(cache, file)(
|
||||
|
|
@ -691,37 +687,37 @@ object Cache {
|
|||
|
||||
def validErrFileExists =
|
||||
EitherT {
|
||||
Task {
|
||||
(referenceFileExists && errFile0.exists()).right[FileError]
|
||||
Task[Either[FileError, Boolean]] {
|
||||
Right(referenceFileExists && errFile0.exists())
|
||||
}
|
||||
}
|
||||
|
||||
def createErrFile =
|
||||
EitherT {
|
||||
Task {
|
||||
Task[Either[FileError, Unit]] {
|
||||
if (referenceFileExists) {
|
||||
if (!errFile0.exists())
|
||||
FileUtil.write(errFile0, "".getBytes(UTF_8))
|
||||
}
|
||||
|
||||
().right[FileError]
|
||||
Right(())
|
||||
}
|
||||
}
|
||||
|
||||
def deleteErrFile =
|
||||
EitherT {
|
||||
Task {
|
||||
Task[Either[FileError, Unit]] {
|
||||
if (errFile0.exists())
|
||||
errFile0.delete()
|
||||
|
||||
().right[FileError]
|
||||
Right(())
|
||||
}
|
||||
}
|
||||
|
||||
def retainError =
|
||||
EitherT {
|
||||
remote(file, url).run.flatMap {
|
||||
case err @ -\/(FileError.NotFound(_, Some(true))) =>
|
||||
case err @ Left(FileError.NotFound(_, Some(true))) =>
|
||||
createErrFile.run.map(_ => err)
|
||||
case other =>
|
||||
deleteErrFile.run.map(_ => other)
|
||||
|
|
@ -732,7 +728,7 @@ object Cache {
|
|||
case CachePolicy.FetchMissing | CachePolicy.LocalOnly | CachePolicy.LocalUpdate | CachePolicy.LocalUpdateChanging =>
|
||||
validErrFileExists.flatMap { exists =>
|
||||
if (exists)
|
||||
EitherT(Task.now(FileError.NotFound(url, Some(true)).left[Unit]))
|
||||
EitherT(Task.now[Either[FileError, Unit]](Left(FileError.NotFound(url, Some(true)))))
|
||||
else
|
||||
retainError
|
||||
}
|
||||
|
|
@ -748,13 +744,13 @@ object Cache {
|
|||
|
||||
// memo-ized
|
||||
|
||||
lazy val res =
|
||||
lazy val res: Either[FileError, Boolean] =
|
||||
if (file.exists())
|
||||
true.right[FileError]
|
||||
Right(true)
|
||||
else if (referenceFileExists && errFile0.exists())
|
||||
FileError.NotFound(url, Some(true)).left[Boolean]
|
||||
Left(FileError.NotFound(url, Some(true)): FileError)
|
||||
else
|
||||
false.right[FileError]
|
||||
Right(false)
|
||||
|
||||
EitherT(Task(res))
|
||||
}
|
||||
|
|
@ -764,9 +760,9 @@ object Cache {
|
|||
Task {
|
||||
if (file.exists()) {
|
||||
logger.foreach(_.foundLocally(url, file))
|
||||
\/-(())
|
||||
Right(())
|
||||
} else
|
||||
-\/(FileError.NotFound(file.toString))
|
||||
Left(FileError.NotFound(file.toString))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -788,19 +784,19 @@ object Cache {
|
|||
|
||||
val requiredArtifactCheck = artifact.extra.get("required") match {
|
||||
case None =>
|
||||
EitherT(Task.now(().right[FileError]))
|
||||
EitherT(Task.now[Either[FileError, Unit]](Right(())))
|
||||
case Some(required) =>
|
||||
cachePolicy0 match {
|
||||
case CachePolicy.LocalOnly | CachePolicy.LocalUpdateChanging | CachePolicy.LocalUpdate =>
|
||||
val file = localFile(required.url, cache, artifact.authentication.map(_.user))
|
||||
localInfo(file, required.url).flatMap {
|
||||
case true =>
|
||||
EitherT(Task.now(().right[FileError]))
|
||||
EitherT(Task.now[Either[FileError, Unit]](Right(())))
|
||||
case false =>
|
||||
EitherT(Task.now(FileError.NotFound(file.toString).left[Unit]))
|
||||
EitherT(Task.now[Either[FileError, Unit]](Left(FileError.NotFound(file.toString))))
|
||||
}
|
||||
case _ =>
|
||||
EitherT(Task.now(().right[FileError]))
|
||||
EitherT(Task.now[Either[FileError, Unit]](Right(())))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -823,7 +819,7 @@ object Cache {
|
|||
case true =>
|
||||
remoteKeepErrors(file, url)
|
||||
case false =>
|
||||
EitherT(Task.now[FileError \/ Unit](().right))
|
||||
EitherT(Task.now[Either[FileError, Unit]](Right(())))
|
||||
}
|
||||
|
||||
cachePolicy0 match {
|
||||
|
|
@ -912,7 +908,7 @@ object Cache {
|
|||
|
||||
sumOpt match {
|
||||
case None =>
|
||||
FileError.ChecksumFormatError(sumType, sumFile.getPath).left
|
||||
Left(FileError.ChecksumFormatError(sumType, sumFile.getPath))
|
||||
|
||||
case Some(sum) =>
|
||||
val md = MessageDigest.getInstance(sumType)
|
||||
|
|
@ -925,20 +921,20 @@ object Cache {
|
|||
val calculatedSum = new BigInteger(1, digest)
|
||||
|
||||
if (sum == calculatedSum)
|
||||
().right
|
||||
Right(())
|
||||
else
|
||||
FileError.WrongChecksum(
|
||||
Left(FileError.WrongChecksum(
|
||||
sumType,
|
||||
calculatedSum.toString(16),
|
||||
sum.toString(16),
|
||||
localFile0.getPath,
|
||||
sumFile.getPath
|
||||
).left
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
case None =>
|
||||
Task.now(FileError.ChecksumNotFound(sumType, localFile0.getPath).left)
|
||||
Task.now(Left(FileError.ChecksumNotFound(sumType, localFile0.getPath)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -978,20 +974,20 @@ object Cache {
|
|||
}
|
||||
|
||||
val ((f, _), res) = results.head
|
||||
res.flatMap { _ =>
|
||||
res.right.flatMap { _ =>
|
||||
checksum match {
|
||||
case None =>
|
||||
// FIXME All the checksums should be in the error, possibly with their URLs
|
||||
// from artifact.checksumUrls
|
||||
-\/(FileError.ChecksumNotFound(checksums0.last.get, ""))
|
||||
case Some(c) => \/-((f, c))
|
||||
Left(FileError.ChecksumNotFound(checksums0.last.get, ""))
|
||||
case Some(c) => Right((f, c))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res.flatMap {
|
||||
case (f, None) => EitherT(Task.now[FileError \/ File](\/-(f)))
|
||||
case (f, None) => EitherT(Task.now[Either[FileError, File]](Right(f)))
|
||||
case (f, Some(c)) =>
|
||||
validateChecksum(artifact, c, cache, pool).map(_ => f)
|
||||
}
|
||||
|
|
@ -1068,7 +1064,7 @@ object Cache {
|
|||
} else
|
||||
notFound(f)
|
||||
|
||||
EitherT.fromEither(Task.now[Either[String, String]](res))
|
||||
EitherT(Task.now[Either[String, String]](res))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1102,7 +1098,7 @@ object Cache {
|
|||
withChecksums = false,
|
||||
withSignatures = false,
|
||||
dropInfoAttributes = true
|
||||
).getOrElse(
|
||||
).right.getOrElse(
|
||||
throw new Exception("Cannot happen")
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ import coursier.core.Authentication
|
|||
import coursier.ivy.IvyRepository
|
||||
import coursier.util.Parse
|
||||
|
||||
import scalaz._, Scalaz._
|
||||
import scalaz.{Validation, ValidationNel}
|
||||
import scalaz.Scalaz.vectorInstance
|
||||
import scalaz.Scalaz.{ToEitherOpsFromEither, ToNelOps, ToTraverseOps, ToValidationOps}
|
||||
|
||||
object CacheParse {
|
||||
|
||||
|
|
@ -18,7 +20,7 @@ object CacheParse {
|
|||
else {
|
||||
val repo = Parse.repository(s)
|
||||
|
||||
val url = repo.map {
|
||||
val url = repo.right.map {
|
||||
case m: MavenRepository =>
|
||||
m.root
|
||||
case i: IvyRepository =>
|
||||
|
|
@ -32,13 +34,13 @@ object CacheParse {
|
|||
}
|
||||
|
||||
val validatedUrl = try {
|
||||
url.map(Cache.url)
|
||||
url.right.map(Cache.url)
|
||||
} catch {
|
||||
case e: MalformedURLException =>
|
||||
("Error parsing URL " + url + Option(e.getMessage).fold("")(" (" + _ + ")")).left
|
||||
Left("Error parsing URL " + url + Option(e.getMessage).fold("")(" (" + _ + ")"))
|
||||
}
|
||||
|
||||
validatedUrl.flatMap { url =>
|
||||
validatedUrl.right.flatMap { url =>
|
||||
Option(url.getUserInfo) match {
|
||||
case None =>
|
||||
repo
|
||||
|
|
@ -52,7 +54,7 @@ object CacheParse {
|
|||
url.getFile
|
||||
).toString
|
||||
|
||||
repo.map {
|
||||
repo.right.map {
|
||||
case m: MavenRepository =>
|
||||
m.copy(
|
||||
root = baseUrl,
|
||||
|
|
@ -73,7 +75,7 @@ object CacheParse {
|
|||
}
|
||||
|
||||
case _ =>
|
||||
s"No password found in user info of URL $url".left
|
||||
Left(s"No password found in user info of URL $url")
|
||||
}
|
||||
}
|
||||
}.validation
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package coursier
|
||||
|
||||
import scalaz.{Failure, Success}
|
||||
|
||||
sealed abstract class CachePolicy extends Product with Serializable
|
||||
|
||||
object CachePolicy {
|
||||
|
|
@ -80,14 +82,14 @@ object CachePolicy {
|
|||
value.filter(_.nonEmpty).flatMap {
|
||||
str =>
|
||||
CacheParse.cachePolicies(str) match {
|
||||
case scalaz.Success(Seq()) =>
|
||||
case Success(Seq()) =>
|
||||
Console.err.println(
|
||||
s"Warning: no mode found in $description, ignoring it."
|
||||
)
|
||||
None
|
||||
case scalaz.Success(policies) =>
|
||||
case Success(policies) =>
|
||||
Some(policies)
|
||||
case scalaz.Failure(errors) =>
|
||||
case Failure(errors) =>
|
||||
Console.err.println(
|
||||
s"Warning: unrecognized mode in $description, ignoring it."
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@ package coursier
|
|||
import java.io._
|
||||
import java.nio.charset.Charset
|
||||
|
||||
import scala.language.implicitConversions
|
||||
import coursier.util.EitherT
|
||||
|
||||
import scalaz._
|
||||
import scala.language.implicitConversions
|
||||
import scala.util.{Failure, Success, Try}
|
||||
import scalaz.concurrent.Task
|
||||
|
||||
object Platform {
|
||||
|
|
@ -26,27 +27,30 @@ object Platform {
|
|||
|
||||
private lazy val UTF_8 = Charset.forName("UTF-8")
|
||||
|
||||
def readFully(is: => InputStream) =
|
||||
def readFully(is: => InputStream): Task[Either[String, String]] =
|
||||
Task {
|
||||
\/.fromTryCatchNonFatal {
|
||||
val t = Try {
|
||||
val is0 = is
|
||||
val b =
|
||||
try readFullySync(is0)
|
||||
finally is0.close()
|
||||
|
||||
new String(b, UTF_8)
|
||||
} .leftMap{
|
||||
case e: java.io.FileNotFoundException if e.getMessage != null =>
|
||||
s"Not found: ${e.getMessage}"
|
||||
case e =>
|
||||
s"$e${Option(e.getMessage).fold("")(" (" + _ + ")")}"
|
||||
}
|
||||
|
||||
t match {
|
||||
case Success(r) => Right(r)
|
||||
case Failure(e: java.io.FileNotFoundException) if e.getMessage != null =>
|
||||
Left(s"Not found: ${e.getMessage}")
|
||||
case Failure(e) =>
|
||||
Left(s"$e${Option(e.getMessage).fold("")(" (" + _ + ")")}")
|
||||
}
|
||||
}
|
||||
|
||||
val artifact: Fetch.Content[Task] = { artifact =>
|
||||
EitherT {
|
||||
val conn = Cache.urlConnection(artifact.url, artifact.authentication)
|
||||
readFully(conn.getInputStream())
|
||||
readFully(conn.getInputStream)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import coursier.util.{Parse, Print}
|
|||
import scala.annotation.tailrec
|
||||
import scala.concurrent.duration.Duration
|
||||
import scalaz.concurrent.{Strategy, Task}
|
||||
import scalaz.{-\/, Failure, Nondeterminism, Success, \/-}
|
||||
import scalaz.{Failure, Nondeterminism, Success}
|
||||
|
||||
|
||||
object Helper {
|
||||
|
|
@ -182,14 +182,14 @@ class Helper(
|
|||
|
||||
logger.foreach(_.stop())
|
||||
|
||||
val errors = res.collect { case -\/(err) => err }
|
||||
val errors = res.collect { case Left(err) => err }
|
||||
|
||||
prematureExitIf(errors.nonEmpty) {
|
||||
s"Error getting scaladex infos:\n" + errors.map(" " + _).mkString("\n")
|
||||
}
|
||||
|
||||
res
|
||||
.collect { case \/-(l) => l }
|
||||
.collect { case Right(l) => l }
|
||||
.flatten
|
||||
.map { case (mod, ver) => (Dependency(mod, ver), Map[String, String]()) }
|
||||
}
|
||||
|
|
@ -644,7 +644,7 @@ class Helper(
|
|||
|
||||
val (ignoredErrors, errors) = results
|
||||
.collect {
|
||||
case (artifact, -\/(err)) =>
|
||||
case (artifact, Left(err)) =>
|
||||
artifact -> err
|
||||
}
|
||||
.partition {
|
||||
|
|
@ -657,7 +657,7 @@ class Helper(
|
|||
}
|
||||
|
||||
val artifactToFile = results.collect {
|
||||
case (artifact: Artifact, \/-(f)) =>
|
||||
case (artifact: Artifact, Right(f)) =>
|
||||
(artifact.url, f)
|
||||
}.toMap
|
||||
|
||||
|
|
|
|||
|
|
@ -5,15 +5,13 @@ import java.nio.charset.StandardCharsets
|
|||
import java.util.concurrent.ExecutorService
|
||||
|
||||
import argonaut._, Argonaut._, ArgonautShapeless._
|
||||
import coursier.core.{ Artifact, Attributes }
|
||||
import coursier.{ Fetch, Module }
|
||||
import coursier.core.{Artifact, Attributes}
|
||||
import coursier.util.EitherT
|
||||
import coursier.{Fetch, Module}
|
||||
|
||||
import scala.language.higherKinds
|
||||
import scalaz.{ -\/, EitherT, Monad, Nondeterminism, \/, \/- }
|
||||
import scalaz.Scalaz.ToEitherOps
|
||||
import scalaz.Scalaz.ToEitherOpsFromEither
|
||||
import scalaz.Nondeterminism
|
||||
import scalaz.concurrent.Task
|
||||
import scalaz.std.list._
|
||||
|
||||
object Scaladex {
|
||||
|
||||
|
|
@ -37,7 +35,7 @@ object Scaladex {
|
|||
|
||||
def apply(pool: ExecutorService): Scaladex[Task] =
|
||||
Scaladex({ url =>
|
||||
EitherT(Task({
|
||||
EitherT(Task[Either[String, String]]({
|
||||
var conn: HttpURLConnection = null
|
||||
|
||||
val b = try {
|
||||
|
|
@ -48,7 +46,7 @@ object Scaladex {
|
|||
coursier.Cache.closeConn(conn)
|
||||
}
|
||||
|
||||
new String(b, StandardCharsets.UTF_8).right[String]
|
||||
Right(new String(b, StandardCharsets.UTF_8))
|
||||
})(pool))
|
||||
}, Nondeterminism[Task])
|
||||
|
||||
|
|
@ -78,7 +76,7 @@ case class Scaladex[F[_]](fetch: String => EitherT[F, String, String], F: Nondet
|
|||
s"https://index.scala-lang.org/api/search?q=$name&target=$target&scalaVersion=$scalaVersion"
|
||||
)
|
||||
|
||||
s.flatMap(s => EitherT.fromDisjunction[F](s.decodeEither[List[Scaladex.SearchResult]].disjunction))
|
||||
s.flatMap(s => EitherT.fromEither(s.decodeEither[List[Scaladex.SearchResult]]))
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -95,7 +93,7 @@ case class Scaladex[F[_]](fetch: String => EitherT[F, String, String], F: Nondet
|
|||
s"https://index.scala-lang.org/api/project?organization=$organization&repository=$repository&artifact=$artifactName"
|
||||
)
|
||||
|
||||
s.flatMap(s => EitherT.fromDisjunction[F](s.decodeEither[Scaladex.ArtifactInfos].disjunction))
|
||||
s.flatMap(s => EitherT.fromEither(s.decodeEither[Scaladex.ArtifactInfos]))
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -113,7 +111,7 @@ case class Scaladex[F[_]](fetch: String => EitherT[F, String, String], F: Nondet
|
|||
|
||||
case class Result(artifacts: List[String])
|
||||
|
||||
s.flatMap(s => EitherT.fromDisjunction[F](s.decodeEither[Result].disjunction.map(_.artifacts)))
|
||||
s.flatMap(s => EitherT.fromEither(s.decodeEither[Result].map(_.artifacts)))
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -135,9 +133,9 @@ case class Scaladex[F[_]](fetch: String => EitherT[F, String, String], F: Nondet
|
|||
.flatMap {
|
||||
case Seq(first, _*) =>
|
||||
logger(s"Using ${first.organization}/${first.repository} for $name")
|
||||
EitherT.fromDisjunction[F]((first.organization, first.repository, first.artifacts).right): EitherT[F, String, (String, String, Seq[String])]
|
||||
EitherT.fromEither[F](Right((first.organization, first.repository, first.artifacts)): Either[String, (String, String, Seq[String])])
|
||||
case Seq() =>
|
||||
EitherT.fromDisjunction[F](s"No project found for $name".left): EitherT[F, String, (String, String, Seq[String])]
|
||||
EitherT.fromEither[F](Left(s"No project found for $name"): Either[String, (String, String, Seq[String])])
|
||||
}
|
||||
|
||||
orgNameOrError.flatMap {
|
||||
|
|
@ -145,10 +143,10 @@ case class Scaladex[F[_]](fetch: String => EitherT[F, String, String], F: Nondet
|
|||
|
||||
val moduleVersions = F.map(F.gather(artifactNames.map { artifactName =>
|
||||
F.map(artifactInfos(ghOrg, ghRepo, artifactName).run) {
|
||||
case -\/(err) =>
|
||||
case Left(err) =>
|
||||
logger(s"Cannot get infos about artifact $artifactName from $ghOrg/$ghRepo: $err, ignoring it")
|
||||
Nil
|
||||
case \/-(infos) =>
|
||||
case Right(infos) =>
|
||||
logger(s"Found module ${infos.groupId}:${infos.artifactId}:${infos.version}")
|
||||
Seq(Module(infos.groupId, infos.artifactId) -> infos.version)
|
||||
}
|
||||
|
|
@ -156,9 +154,9 @@ case class Scaladex[F[_]](fetch: String => EitherT[F, String, String], F: Nondet
|
|||
|
||||
EitherT(F.map(moduleVersions) { l =>
|
||||
if (l.isEmpty)
|
||||
s"No module found for $ghOrg/$ghRepo".left
|
||||
Left(s"No module found for $ghOrg/$ghRepo")
|
||||
else
|
||||
l.right
|
||||
Right(l)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import coursier.cli.util.Zip
|
|||
import coursier.internal.FileUtil
|
||||
|
||||
import scala.collection.mutable
|
||||
import scalaz.\/-
|
||||
|
||||
object Assembly {
|
||||
|
||||
|
|
@ -273,8 +272,8 @@ object Assembly {
|
|||
// FIXME Acquire lock on tmpDest
|
||||
Assembly.make(jars, tmpDest, assemblyRules)
|
||||
FileUtil.atomicMove(tmpDest, dest)
|
||||
\/-((dest, jars))
|
||||
}.leftMap(_.describe).toEither
|
||||
Right((dest, jars))
|
||||
}.left.map(_.describe)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
package coursier
|
||||
|
||||
import scala.language.higherKinds
|
||||
import coursier.util.EitherT
|
||||
|
||||
import scalaz._
|
||||
import scala.language.higherKinds
|
||||
import scalaz.{Monad, Nondeterminism}
|
||||
|
||||
object Fetch {
|
||||
|
||||
|
|
@ -11,7 +12,7 @@ object Fetch {
|
|||
|
||||
type MD = Seq[(
|
||||
(Module, String),
|
||||
Seq[String] \/ (Artifact.Source, Project)
|
||||
Either[Seq[String], (Artifact.Source, Project)]
|
||||
)]
|
||||
|
||||
type Metadata[F[_]] = Seq[(Module, String)] => F[MD]
|
||||
|
|
@ -39,17 +40,18 @@ object Fetch {
|
|||
val lookups = repositories
|
||||
.map(repo => repo -> repo.find(module, version, fetch).run)
|
||||
|
||||
val task = lookups.foldLeft[F[Seq[String] \/ (Artifact.Source, Project)]](F.point(-\/(Nil))) {
|
||||
case (acc, (repo, eitherProjTask)) =>
|
||||
val task0 = lookups.foldLeft[F[Either[Seq[String], (Artifact.Source, Project)]]](F.point(Left(Nil))) {
|
||||
case (acc, (_, eitherProjTask)) =>
|
||||
F.bind(acc) {
|
||||
case -\/(errors) =>
|
||||
F.map(eitherProjTask)(_.leftMap(error => error +: errors))
|
||||
case res @ \/-(_) =>
|
||||
case Left(errors) =>
|
||||
F.map(eitherProjTask)(_.left.map(error => error +: errors))
|
||||
case res @ Right(_) =>
|
||||
F.point(res)
|
||||
}
|
||||
}
|
||||
|
||||
EitherT(F.map(task)(_.leftMap(_.reverse)))
|
||||
val task = F.map(task0)(e => e.left.map(_.reverse): Either[Seq[String], (Artifact.Source, Project)])
|
||||
EitherT(task)
|
||||
}
|
||||
|
||||
def from[F[_]](
|
||||
|
|
@ -62,14 +64,13 @@ object Fetch {
|
|||
|
||||
modVers =>
|
||||
F.map(
|
||||
F.gatherUnordered(
|
||||
modVers.map { case (module, version) =>
|
||||
def get(fetch: Content[F]) =
|
||||
find(repositories, module, version, fetch)
|
||||
F.map((get(fetch) /: extra)(_ orElse get(_))
|
||||
.run)((module, version) -> _)
|
||||
F.gatherUnordered {
|
||||
modVers.map {
|
||||
case (module, version) =>
|
||||
def get(fetch: Content[F]) = find(repositories, module, version, fetch)
|
||||
F.map((get(fetch) /: extra)(_ orElse get(_)).run)(d => (module, version) -> d)
|
||||
}
|
||||
)
|
||||
}
|
||||
)(_.toSeq)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
package coursier.core
|
||||
|
||||
import scalaz.{-\/, \/, \/-}
|
||||
|
||||
// Maven-specific
|
||||
final case class Activation(
|
||||
properties: Seq[(String, Option[String])],
|
||||
os: Activation.Os,
|
||||
jdk: Option[VersionInterval \/ Seq[Version]]
|
||||
jdk: Option[Either[VersionInterval, Seq[Version]]]
|
||||
) {
|
||||
|
||||
def isEmpty: Boolean = properties.isEmpty && os.isEmpty && jdk.isEmpty
|
||||
|
|
@ -35,9 +33,9 @@ final case class Activation(
|
|||
def fromOs = os.isActive(osInfo)
|
||||
|
||||
def fromJdk = jdk.forall {
|
||||
case -\/(itv) =>
|
||||
case Left(itv) =>
|
||||
jdkVersion.exists(itv.contains)
|
||||
case \/-(versions) =>
|
||||
case Right(versions) =>
|
||||
jdkVersion.exists(versions.contains)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@ package coursier.core
|
|||
import coursier.Fetch
|
||||
|
||||
import scala.language.higherKinds
|
||||
|
||||
import scalaz._
|
||||
|
||||
import scalaz.Monad
|
||||
import coursier.core.compatibility.encodeURIComponent
|
||||
import coursier.util.EitherT
|
||||
|
||||
trait Repository extends Product with Serializable {
|
||||
def find[F[_]](
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import java.util.regex.Pattern.quote
|
|||
|
||||
import scala.annotation.tailrec
|
||||
import scala.collection.JavaConverters._
|
||||
import scalaz.{ \/-, -\/ }
|
||||
|
||||
object Resolution {
|
||||
|
||||
|
|
@ -201,7 +200,7 @@ object Resolution {
|
|||
module -> {
|
||||
val (versionOpt, updatedDeps) = forceVersions.get(module) match {
|
||||
case None =>
|
||||
if (deps.lengthCompare(1) == 0) (Some(deps.head.version), \/-(deps))
|
||||
if (deps.lengthCompare(1) == 0) (Some(deps.head.version), Right(deps))
|
||||
else {
|
||||
val versions = deps
|
||||
.map(_.version)
|
||||
|
|
@ -210,14 +209,14 @@ object Resolution {
|
|||
|
||||
(versionOpt, versionOpt match {
|
||||
case Some(version) =>
|
||||
\/-(deps.map(dep => dep.copy(version = version)))
|
||||
Right(deps.map(dep => dep.copy(version = version)))
|
||||
case None =>
|
||||
-\/(deps)
|
||||
Left(deps)
|
||||
})
|
||||
}
|
||||
|
||||
case Some(forcedVersion) =>
|
||||
(Some(forcedVersion), \/-(deps.map(dep => dep.copy(version = forcedVersion))))
|
||||
(Some(forcedVersion), Right(deps.map(dep => dep.copy(version = forcedVersion))))
|
||||
}
|
||||
|
||||
(updatedDeps, versionOpt)
|
||||
|
|
@ -230,10 +229,10 @@ object Resolution {
|
|||
|
||||
(
|
||||
merged
|
||||
.collect { case (-\/(dep), _) => dep }
|
||||
.collect { case (Left(dep), _) => dep }
|
||||
.flatten,
|
||||
merged
|
||||
.collect { case (\/-(dep), _) => dep }
|
||||
.collect { case (Right(dep), _) => dep }
|
||||
.flatten,
|
||||
mergedByModVer
|
||||
.collect { case (mod, (_, Some(ver))) => mod -> ver }
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ package core
|
|||
|
||||
import scala.annotation.tailrec
|
||||
import scala.language.higherKinds
|
||||
import scalaz.{-\/, Monad, \/, \/-}
|
||||
import scalaz.Scalaz.{ToFunctorOps, ToBindOps, ToTraverseOps, vectorInstance}
|
||||
import scalaz.Monad
|
||||
import scalaz.Scalaz.{ToFunctorOps, ToBindOps}
|
||||
|
||||
|
||||
sealed abstract class ResolutionProcess {
|
||||
|
|
@ -64,11 +64,11 @@ final case class Missing(
|
|||
def next(results: Fetch.MD): ResolutionProcess = {
|
||||
|
||||
val errors = results.collect {
|
||||
case (modVer, -\/(errs)) =>
|
||||
case (modVer, Left(errs)) =>
|
||||
modVer -> errs
|
||||
}
|
||||
val successes = results.collect {
|
||||
case (modVer, \/-(repoProj)) =>
|
||||
case (modVer, Right(repoProj)) =>
|
||||
modVer -> repoProj
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +168,7 @@ object ResolutionProcess {
|
|||
private[coursier] def fetchAll[F[_]](
|
||||
modVers: Seq[(Module, String)],
|
||||
fetch: Fetch.Metadata[F]
|
||||
)(implicit F: Monad[F]): F[Vector[((Module, String), Seq[String] \/ (Artifact.Source, Project))]] = {
|
||||
)(implicit F: Monad[F]): F[Vector[((Module, String), Either[Seq[String], (Artifact.Source, Project)])]] = {
|
||||
|
||||
def uniqueModules(modVers: Seq[(Module, String)]): Stream[Seq[(Module, String)]] = {
|
||||
|
||||
|
|
@ -193,7 +193,7 @@ object ResolutionProcess {
|
|||
|
||||
uniqueModules(modVers)
|
||||
.toVector
|
||||
.foldLeft(F.point(Vector.empty[((Module, String), Seq[String] \/ (Artifact.Source, Project))])) {
|
||||
.foldLeft(F.point(Vector.empty[((Module, String), Either[Seq[String], (Artifact.Source, Project)])])) {
|
||||
(acc, l) =>
|
||||
for (v <- acc; e <- fetch(l))
|
||||
yield v ++ e
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
package coursier.core
|
||||
|
||||
import scalaz.{ -\/, \/, \/- }
|
||||
import scalaz.Scalaz.ToEitherOps
|
||||
|
||||
final case class VersionInterval(
|
||||
from: Option[Version],
|
||||
to: Option[Version],
|
||||
|
|
@ -91,25 +88,25 @@ final case class VersionConstraint(
|
|||
interval: VersionInterval,
|
||||
preferred: Seq[Version]
|
||||
) {
|
||||
def blend: Option[VersionInterval \/ Version] =
|
||||
def blend: Option[Either[VersionInterval, Version]] =
|
||||
if (interval.isValid) {
|
||||
val preferredInInterval = preferred.filter(interval.contains)
|
||||
|
||||
if (preferredInInterval.isEmpty)
|
||||
Some(interval.left)
|
||||
Some(Left(interval))
|
||||
else
|
||||
Some(preferredInInterval.max.right)
|
||||
Some(Right(preferredInInterval.max))
|
||||
} else
|
||||
None
|
||||
|
||||
def repr: Option[String] =
|
||||
blend.map {
|
||||
case -\/(itv) =>
|
||||
case Left(itv) =>
|
||||
if (itv == VersionInterval.zero)
|
||||
""
|
||||
else
|
||||
itv.repr
|
||||
case \/-(v) => v.repr
|
||||
case Right(v) => v.repr
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,10 @@ package coursier.ivy
|
|||
|
||||
import coursier.Fetch
|
||||
import coursier.core._
|
||||
import coursier.util.WebPage
|
||||
import coursier.util.{EitherT, WebPage}
|
||||
|
||||
import scala.language.higherKinds
|
||||
|
||||
import scalaz._
|
||||
import scalaz.Scalaz._
|
||||
import scalaz.Monad
|
||||
|
||||
final case class IvyRepository(
|
||||
pattern: Pattern,
|
||||
|
|
@ -115,7 +113,7 @@ final case class IvyRepository(
|
|||
p.name,
|
||||
p.ext,
|
||||
Some(p.classifier).filter(_.nonEmpty)
|
||||
)).toList.map(p -> _) // FIXME Validation errors are ignored
|
||||
)).right.toSeq.toList.map(p -> _) // FIXME Validation errors are ignored
|
||||
}
|
||||
|
||||
retainedWithUrl.map { case (p, url) =>
|
||||
|
|
@ -160,22 +158,26 @@ final case class IvyRepository(
|
|||
case None =>
|
||||
findNoInverval(module, version, fetch)
|
||||
case Some(itv) =>
|
||||
val listingUrl = revisionListingPattern.substituteVariables(
|
||||
variables(module, None, "ivy", "ivy", "xml", None)
|
||||
).flatMap { s =>
|
||||
if (s.endsWith("/"))
|
||||
s.right
|
||||
else
|
||||
s"Don't know how to list revisions of ${metadataPattern.string}".left
|
||||
}
|
||||
val listingUrl = revisionListingPattern
|
||||
.substituteVariables(variables(module, None, "ivy", "ivy", "xml", None))
|
||||
.right
|
||||
.flatMap { s =>
|
||||
if (s.endsWith("/"))
|
||||
Right(s)
|
||||
else
|
||||
Left(s"Don't know how to list revisions of ${metadataPattern.string}")
|
||||
}
|
||||
|
||||
def fromWebPage(url: String, s: String) = {
|
||||
|
||||
val subDirs = WebPage.listDirectories(url, s)
|
||||
val versions = subDirs.map(Parse.version).collect { case Some(v) => v }
|
||||
val versionsInItv = versions.filter(itv.contains)
|
||||
|
||||
if (versionsInItv.isEmpty)
|
||||
EitherT(F.point(s"No version found for $version".left[(Artifact.Source, Project)]))
|
||||
EitherT(
|
||||
F.point[Either[String, (Artifact.Source, Project)]](Left(s"No version found for $version"))
|
||||
)
|
||||
else {
|
||||
val version0 = versionsInItv.max
|
||||
findNoInverval(module, version0.repr, fetch)
|
||||
|
|
@ -209,11 +211,11 @@ final case class IvyRepository(
|
|||
F: Monad[F]
|
||||
): EitherT[F, String, (Artifact.Source, Project)] = {
|
||||
|
||||
val eitherArtifact: String \/ Artifact =
|
||||
val eitherArtifact: Either[String, Artifact] =
|
||||
for {
|
||||
url <- metadataPattern.substituteVariables(
|
||||
variables(module, Some(version), "ivy", "ivy", "xml", None)
|
||||
)
|
||||
).right
|
||||
} yield {
|
||||
var artifact = Artifact(
|
||||
url,
|
||||
|
|
@ -235,13 +237,15 @@ final case class IvyRepository(
|
|||
for {
|
||||
artifact <- EitherT(F.point(eitherArtifact))
|
||||
ivy <- fetch(artifact)
|
||||
proj0 <- EitherT(F.point {
|
||||
for {
|
||||
xml <- \/.fromEither(compatibility.xmlParse(ivy))
|
||||
_ <- if (xml.label == "ivy-module") \/-(()) else -\/("Module definition not found")
|
||||
proj <- IvyXml.project(xml)
|
||||
} yield proj
|
||||
})
|
||||
proj0 <- EitherT(
|
||||
F.point {
|
||||
for {
|
||||
xml <- compatibility.xmlParse(ivy).right
|
||||
_ <- (if (xml.label == "ivy-module") Right(()) else Left("Module definition not found")).right
|
||||
proj <- IvyXml.project(xml).right
|
||||
} yield proj
|
||||
}
|
||||
)
|
||||
} yield {
|
||||
val proj =
|
||||
if (dropInfoAttributes)
|
||||
|
|
@ -287,16 +291,18 @@ object IvyRepository {
|
|||
// hack for SBT putting infos in properties
|
||||
dropInfoAttributes: Boolean = false,
|
||||
authentication: Option[Authentication] = None
|
||||
): String \/ IvyRepository =
|
||||
): Either[String, IvyRepository] =
|
||||
|
||||
for {
|
||||
propertiesPattern <- PropertiesPattern.parse(pattern)
|
||||
propertiesPattern <- PropertiesPattern.parse(pattern).right
|
||||
metadataPropertiesPatternOpt <- metadataPatternOpt
|
||||
.fold(Option.empty[PropertiesPattern].right[String])(PropertiesPattern.parse(_)
|
||||
.map(Some(_)))
|
||||
.fold[Either[String, Option[PropertiesPattern]]](Right(None))(PropertiesPattern.parse(_).right.map(Some(_)))
|
||||
.right
|
||||
|
||||
pattern <- propertiesPattern.substituteProperties(properties)
|
||||
metadataPatternOpt <- metadataPropertiesPatternOpt.fold(Option.empty[Pattern].right[String])(_.substituteProperties(properties).map(Some(_)))
|
||||
pattern <- propertiesPattern.substituteProperties(properties).right
|
||||
metadataPatternOpt <- metadataPropertiesPatternOpt
|
||||
.fold[Either[String, Option[Pattern]]](Right(None))(_.substituteProperties(properties).right.map(Some(_)))
|
||||
.right
|
||||
|
||||
} yield
|
||||
IvyRepository(
|
||||
|
|
@ -359,8 +365,8 @@ object IvyRepository {
|
|||
dropInfoAttributes,
|
||||
authentication
|
||||
) match {
|
||||
case \/-(repo) => repo
|
||||
case -\/(msg) =>
|
||||
case Right(repo) => repo
|
||||
case Left(msg) =>
|
||||
throw new IllegalArgumentException(s"Error while parsing Ivy patterns: $msg")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,29 +3,29 @@ package coursier.ivy
|
|||
import coursier.core._
|
||||
import coursier.util.Xml._
|
||||
|
||||
import scalaz.{ Node => _, _ }, Scalaz._
|
||||
|
||||
object IvyXml {
|
||||
|
||||
val attributesNamespace = "http://ant.apache.org/ivy/extra"
|
||||
|
||||
private def info(node: Node): String \/ (Module, String) =
|
||||
private def info(node: Node): Either[String, (Module, String)] =
|
||||
for {
|
||||
org <- node.attribute("organisation")
|
||||
name <- node.attribute("module")
|
||||
version <- node.attribute("revision")
|
||||
attr = node.attributesFromNamespace(attributesNamespace)
|
||||
} yield (Module(org, name, attr.toMap), version)
|
||||
org <- node.attribute("organisation").right
|
||||
name <- node.attribute("module").right
|
||||
version <- node.attribute("revision").right
|
||||
} yield {
|
||||
val attr = node.attributesFromNamespace(attributesNamespace)
|
||||
(Module(org, name, attr.toMap), version)
|
||||
}
|
||||
|
||||
// FIXME Errors are ignored here
|
||||
private def configurations(node: Node): Seq[(String, Seq[String])] =
|
||||
node.children
|
||||
.filter(_.label == "conf")
|
||||
.flatMap { node =>
|
||||
node.attribute("name").toOption.toSeq.map(_ -> node)
|
||||
node.attribute("name").right.toOption.toSeq.map(_ -> node)
|
||||
}
|
||||
.map { case (name, node) =>
|
||||
name -> node.attribute("extends").toOption.toSeq.flatMap(_.split(','))
|
||||
name -> node.attribute("extends").right.toSeq.flatMap(_.split(','))
|
||||
}
|
||||
|
||||
// FIXME "default(compile)" likely not to be always the default
|
||||
|
|
@ -52,9 +52,11 @@ object IvyXml {
|
|||
val excludes = node.children
|
||||
.filter(_.label == "exclude")
|
||||
.flatMap { node0 =>
|
||||
val org = node0.attribute("org").getOrElse("*")
|
||||
val name = node0.attribute("module").orElse(node0.attribute("name")).getOrElse("*")
|
||||
val confs = node0.attribute("conf").toOption.filter(_.nonEmpty).fold(Seq("*"))(_.split(','))
|
||||
val org = node0.attribute("org").right.getOrElse("*")
|
||||
val name = node0.attribute("module").right.toOption
|
||||
.orElse(node0.attribute("name").right.toOption)
|
||||
.getOrElse("*")
|
||||
val confs = node0.attribute("conf").right.toOption.filter(_.nonEmpty).fold(Seq("*"))(_.split(','))
|
||||
confs.map(_ -> (org, name))
|
||||
}
|
||||
.groupBy { case (conf, _) => conf }
|
||||
|
|
@ -63,15 +65,15 @@ object IvyXml {
|
|||
val allConfsExcludes = excludes.getOrElse("*", Set.empty)
|
||||
|
||||
for {
|
||||
org <- node.attribute("org").toOption.toSeq
|
||||
name <- node.attribute("name").toOption.toSeq
|
||||
version <- node.attribute("rev").toOption.toSeq
|
||||
rawConf <- node.attribute("conf").toOption.toSeq
|
||||
org <- node.attribute("org").right.toOption.toSeq
|
||||
name <- node.attribute("name").right.toOption.toSeq
|
||||
version <- node.attribute("rev").right.toOption.toSeq
|
||||
rawConf <- node.attribute("conf").right.toOption.toSeq
|
||||
(fromConf, toConf) <- mappings(rawConf)
|
||||
attr = node.attributesFromNamespace(attributesNamespace)
|
||||
} yield {
|
||||
val transitive = node.attribute("transitive").toOption match {
|
||||
case Some("false") => false
|
||||
val attr = node.attributesFromNamespace(attributesNamespace)
|
||||
val transitive = node.attribute("transitive") match {
|
||||
case Right("false") => false
|
||||
case _ => true
|
||||
}
|
||||
|
||||
|
|
@ -91,23 +93,24 @@ object IvyXml {
|
|||
node.children
|
||||
.filter(_.label == "artifact")
|
||||
.flatMap { node =>
|
||||
val name = node.attribute("name").getOrElse("")
|
||||
val type0 = node.attribute("type").getOrElse("jar")
|
||||
val ext = node.attribute("ext").getOrElse(type0)
|
||||
val confs = node.attribute("conf").toOption.fold(Seq("*"))(_.split(','))
|
||||
val classifier = node.attribute("classifier").toOption.getOrElse("")
|
||||
val name = node.attribute("name").right.getOrElse("")
|
||||
val type0 = node.attribute("type").right.getOrElse("jar")
|
||||
val ext = node.attribute("ext").right.getOrElse(type0)
|
||||
val confs = node.attribute("conf").fold(_ => Seq("*"), _.split(',').toSeq)
|
||||
val classifier = node.attribute("classifier").right.getOrElse("")
|
||||
confs.map(_ -> Publication(name, type0, ext, classifier))
|
||||
}
|
||||
.groupBy { case (conf, _) => conf }
|
||||
.map { case (conf, l) => conf -> l.map { case (_, p) => p } }
|
||||
|
||||
def project(node: Node): String \/ Project =
|
||||
def project(node: Node): Either[String, Project] =
|
||||
for {
|
||||
infoNode <- node.children
|
||||
.find(_.label == "info")
|
||||
.toRightDisjunction("Info not found")
|
||||
.toRight("Info not found")
|
||||
.right
|
||||
|
||||
modVer <- info(infoNode)
|
||||
modVer <- info(infoNode).right
|
||||
} yield {
|
||||
|
||||
val (module, version) = modVer
|
||||
|
|
@ -137,12 +140,13 @@ object IvyXml {
|
|||
val licenses = infoNode.children
|
||||
.filter(_.label == "license")
|
||||
.flatMap { n =>
|
||||
n.attribute("name").toOption.map { name =>
|
||||
(name, n.attribute("url").toOption)
|
||||
}.toSeq
|
||||
n.attribute("name").right.toSeq.map { name =>
|
||||
(name, n.attribute("url").right.toOption)
|
||||
}
|
||||
}
|
||||
|
||||
val publicationDate = infoNode.attribute("publication")
|
||||
.right
|
||||
.toOption
|
||||
.flatMap(parseDateTime)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ package coursier.ivy
|
|||
|
||||
import scala.language.implicitConversions
|
||||
|
||||
import scalaz._, Scalaz._
|
||||
import scalaz.{Failure, Success, ValidationNel}
|
||||
import scalaz.Scalaz.{ToEitherOpsFromEither, ToFoldableOps, ToTraverseOps, ToValidationOps, vectorInstance}
|
||||
|
||||
import fastparse.all._
|
||||
|
||||
|
|
@ -12,7 +13,7 @@ final case class PropertiesPattern(chunks: Seq[PropertiesPattern.ChunkOrProperty
|
|||
|
||||
import PropertiesPattern.ChunkOrProperty
|
||||
|
||||
def substituteProperties(properties: Map[String, String]): String \/ Pattern = {
|
||||
def substituteProperties(properties: Map[String, String]): Either[String, Pattern] = {
|
||||
|
||||
val validation = chunks.toVector.traverseM[({ type L[X] = ValidationNel[String, X] })#L, Pattern.Chunk] {
|
||||
case ChunkOrProperty.Prop(name, alternativesOpt) =>
|
||||
|
|
@ -24,6 +25,7 @@ final case class PropertiesPattern(chunks: Seq[PropertiesPattern.ChunkOrProperty
|
|||
case Some(alt) =>
|
||||
PropertiesPattern(alt)
|
||||
.substituteProperties(properties)
|
||||
.right
|
||||
.map(_.chunks.toVector)
|
||||
.validation
|
||||
.toValidationNel
|
||||
|
|
@ -35,6 +37,7 @@ final case class PropertiesPattern(chunks: Seq[PropertiesPattern.ChunkOrProperty
|
|||
case ChunkOrProperty.Opt(l @ _*) =>
|
||||
PropertiesPattern(l)
|
||||
.substituteProperties(properties)
|
||||
.right
|
||||
.map(l => Vector(Pattern.Chunk.Opt(l.chunks: _*)))
|
||||
.validation
|
||||
.toValidationNel
|
||||
|
|
@ -47,7 +50,7 @@ final case class PropertiesPattern(chunks: Seq[PropertiesPattern.ChunkOrProperty
|
|||
|
||||
}.map(Pattern(_))
|
||||
|
||||
validation.disjunction.leftMap { notFoundProps =>
|
||||
validation.toEither.left.map { notFoundProps =>
|
||||
s"Property(ies) not found: ${notFoundProps.toList.mkString(", ")}"
|
||||
}
|
||||
}
|
||||
|
|
@ -62,7 +65,7 @@ final case class Pattern(chunks: Seq[Pattern.Chunk]) {
|
|||
|
||||
def string: String = chunks.map(_.string).mkString
|
||||
|
||||
def substituteVariables(variables: Map[String, String]): String \/ String = {
|
||||
def substituteVariables(variables: Map[String, String]): Either[String, String] = {
|
||||
|
||||
def helper(chunks: Seq[Chunk]): ValidationNel[String, Seq[Chunk.Const]] =
|
||||
chunks.toVector.traverseU[ValidationNel[String, Seq[Chunk.Const]]] {
|
||||
|
|
@ -87,11 +90,11 @@ final case class Pattern(chunks: Seq[Pattern.Chunk]) {
|
|||
|
||||
validation match {
|
||||
case Failure(notFoundVariables) =>
|
||||
s"Variables not found: ${notFoundVariables.toList.mkString(", ")}".left
|
||||
Left(s"Variables not found: ${notFoundVariables.toList.mkString(", ")}")
|
||||
case Success(constants) =>
|
||||
val b = new StringBuilder
|
||||
constants.foreach(b ++= _.value)
|
||||
b.result().right
|
||||
Right(b.result())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -144,12 +147,12 @@ object PropertiesPattern {
|
|||
}
|
||||
|
||||
|
||||
def parse(pattern: String): String \/ PropertiesPattern =
|
||||
def parse(pattern: String): Either[String, PropertiesPattern] =
|
||||
parser.parse(pattern) match {
|
||||
case f: Parsed.Failure =>
|
||||
f.msg.left
|
||||
Left(f.msg)
|
||||
case Parsed.Success(v, _) =>
|
||||
PropertiesPattern(v).right
|
||||
Right(PropertiesPattern(v))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ package coursier.maven
|
|||
import coursier.Fetch
|
||||
import coursier.core._
|
||||
import coursier.core.compatibility.encodeURIComponent
|
||||
import coursier.util.WebPage
|
||||
import coursier.util.{EitherT, WebPage}
|
||||
|
||||
import scala.language.higherKinds
|
||||
import scalaz._
|
||||
import scalaz.Monad
|
||||
|
||||
object MavenRepository {
|
||||
val SnapshotTimestamp = "(.*-)?[0-9]{8}\\.[0-9]{6}-[0-9]+".r
|
||||
|
|
@ -179,9 +179,9 @@ final case class MavenRepository(
|
|||
|
||||
val res =
|
||||
if (files.contains("maven-metadata.xml"))
|
||||
-\/("maven-metadata.xml found, not listing version from directory listing")
|
||||
Left("maven-metadata.xml found, not listing version from directory listing")
|
||||
else if (rawVersions.isEmpty)
|
||||
-\/(s"No versions found at $listingUrl")
|
||||
Left(s"No versions found at $listingUrl")
|
||||
else {
|
||||
val parsedVersions = rawVersions.map(Version(_))
|
||||
val nonPreVersions = parsedVersions.filter(_.items.forall {
|
||||
|
|
@ -190,10 +190,10 @@ final case class MavenRepository(
|
|||
})
|
||||
|
||||
if (nonPreVersions.isEmpty)
|
||||
-\/(s"Found only pre-versions at $listingUrl")
|
||||
Left(s"Found only pre-versions at $listingUrl")
|
||||
else {
|
||||
val latest = nonPreVersions.max
|
||||
\/-(Versions(
|
||||
Right(Versions(
|
||||
latest.repr,
|
||||
latest.repr,
|
||||
nonPreVersions.map(_.repr).toList,
|
||||
|
|
@ -214,16 +214,16 @@ final case class MavenRepository(
|
|||
): EitherT[F, String, Versions] =
|
||||
EitherT(
|
||||
versionsArtifact(module) match {
|
||||
case None => F.point(-\/("Not supported"))
|
||||
case None => F.point(Left("Not supported"))
|
||||
case Some(artifact) =>
|
||||
F.map(fetch(artifact).run)(eitherStr =>
|
||||
F.map(fetch(artifact).run) { eitherStr =>
|
||||
for {
|
||||
str <- eitherStr
|
||||
xml <- \/.fromEither(compatibility.xmlParse(str))
|
||||
_ <- if (xml.label == "metadata") \/-(()) else -\/("Metadata not found")
|
||||
versions <- Pom.versions(xml)
|
||||
str <- eitherStr.right
|
||||
xml <- compatibility.xmlParse(str).right
|
||||
_ <- (if (xml.label == "metadata") Right(()) else Left("Metadata not found")).right
|
||||
versions <- Pom.versions(xml).right
|
||||
} yield versions
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -237,16 +237,16 @@ final case class MavenRepository(
|
|||
|
||||
EitherT(
|
||||
snapshotVersioningArtifact(module, version) match {
|
||||
case None => F.point(-\/("Not supported"))
|
||||
case None => F.point(Left("Not supported"))
|
||||
case Some(artifact) =>
|
||||
F.map(fetch(artifact).run)(eitherStr =>
|
||||
F.map(fetch(artifact).run) { eitherStr =>
|
||||
for {
|
||||
str <- eitherStr
|
||||
xml <- \/.fromEither(compatibility.xmlParse(str))
|
||||
_ <- if (xml.label == "metadata") \/-(()) else -\/("Metadata not found")
|
||||
snapshotVersioning <- Pom.snapshotVersioning(xml)
|
||||
str <- eitherStr.right
|
||||
xml <- compatibility.xmlParse(str).right
|
||||
_ <- (if (xml.label == "metadata") Right(()) else Left("Metadata not found")).right
|
||||
snapshotVersioning <- Pom.snapshotVersioning(xml).right
|
||||
} yield snapshotVersioning
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
@ -269,7 +269,7 @@ final case class MavenRepository(
|
|||
versioningOption match {
|
||||
case None =>
|
||||
EitherT[F, String, Project](
|
||||
F.point(-\/("No snapshot versioning value found"))
|
||||
F.point(Left("No snapshot versioning value found"))
|
||||
)
|
||||
case versioning @ Some(_) =>
|
||||
findVersioning(module, version, versioning, fetch)
|
||||
|
|
@ -290,7 +290,7 @@ final case class MavenRepository(
|
|||
}
|
||||
|
||||
// keep exact version used to get metadata, in case the one inside the metadata is wrong
|
||||
F.map(res)(_.map(proj => proj.copy(actualVersionOpt = Some(version))))
|
||||
F.map(res)(_.right.map(proj => proj.copy(actualVersionOpt = Some(version))))
|
||||
}
|
||||
|
||||
private def artifactFor(url: String, changing: Boolean) =
|
||||
|
|
@ -314,9 +314,9 @@ final case class MavenRepository(
|
|||
|
||||
def parseRawPom(str: String) =
|
||||
for {
|
||||
xml <- \/.fromEither(compatibility.xmlParse(str))
|
||||
_ <- if (xml.label == "project") \/-(()) else -\/("Project definition not found")
|
||||
proj <- Pom.project(xml, relocationAsDependency = true)
|
||||
xml <- compatibility.xmlParse(str).right
|
||||
_ <- (if (xml.label == "project") Right(()) else Left("Project definition not found")).right
|
||||
proj <- Pom.project(xml, relocationAsDependency = true).right
|
||||
} yield proj
|
||||
|
||||
def isArtifact(fileName: String, prefix: String): Option[(String, String)] =
|
||||
|
|
@ -370,9 +370,9 @@ final case class MavenRepository(
|
|||
for {
|
||||
str <- fetch(requiringDirListingProjectArtifact)
|
||||
rawListFilesPageOpt <- EitherT(F.map(fetch(artifactFor(listFilesUrl, changing0)).run) {
|
||||
e => \/-(e.toOption): String \/ Option[String]
|
||||
e => Right(e.right.toOption): Either[String, Option[String]]
|
||||
})
|
||||
proj0 <- EitherT(F.point[String \/ Project](parseRawPom(str)))
|
||||
proj0 <- EitherT(F.point[Either[String, Project]](parseRawPom(str)))
|
||||
} yield {
|
||||
|
||||
val foundPublications =
|
||||
|
|
@ -451,20 +451,20 @@ final case class MavenRepository(
|
|||
val eitherVersion = {
|
||||
val release = Version(versions0.release)
|
||||
|
||||
if (itv.contains(release)) \/-(versions0.release)
|
||||
if (itv.contains(release)) Right(versions0.release)
|
||||
else {
|
||||
val inInterval = versions0.available
|
||||
.map(Version(_))
|
||||
.filter(itv.contains)
|
||||
|
||||
if (inInterval.isEmpty) -\/(s"No version found for $version")
|
||||
else \/-(inInterval.max.repr)
|
||||
if (inInterval.isEmpty) Left(s"No version found for $version")
|
||||
else Right(inInterval.max.repr)
|
||||
}
|
||||
}
|
||||
|
||||
eitherVersion match {
|
||||
case -\/(reason) => EitherT[F, String, (Artifact.Source, Project)](F.point(-\/(reason)))
|
||||
case \/-(version0) =>
|
||||
case Left(reason) => EitherT[F, String, (Artifact.Source, Project)](F.point(Left(reason)))
|
||||
case Right(version0) =>
|
||||
findNoInterval(module, version0, fetch)
|
||||
.map(_.copy(versions = Some(versions0)))
|
||||
.map((source, _))
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
package coursier.maven
|
||||
|
||||
import coursier.core._
|
||||
|
||||
import scalaz._
|
||||
import scalaz.Scalaz.{eitherMonad, listInstance, ToTraverseOps}
|
||||
|
||||
object Pom {
|
||||
import coursier.util.Xml._
|
||||
|
||||
private def point[T](t: T) =
|
||||
Right(t).right
|
||||
|
||||
/**
|
||||
* Returns either a property's key-value pair or an error if the elem is not an element.
|
||||
*
|
||||
|
|
@ -16,10 +18,10 @@ object Pom {
|
|||
* @return the key and the value of the property
|
||||
* @see [[https://issues.apache.org/jira/browse/MNG-5380]]
|
||||
*/
|
||||
def property(elem: Node): String \/ (String, String) = {
|
||||
def property(elem: Node): Either[String, (String, String)] = {
|
||||
// Not matching with Text, which fails on scala-js if the property value has xml comments
|
||||
if (elem.isElement) \/-(elem.label -> elem.textContent.trim)
|
||||
else -\/(s"Can't parse property $elem")
|
||||
if (elem.isElement) Right(elem.label -> elem.textContent.trim)
|
||||
else Left(s"Can't parse property $elem")
|
||||
}
|
||||
|
||||
// TODO Allow no version in some contexts
|
||||
|
|
@ -27,52 +29,53 @@ object Pom {
|
|||
node: Node,
|
||||
defaultGroupId: Option[String] = None,
|
||||
defaultArtifactId: Option[String] = None
|
||||
): String \/ Module = {
|
||||
): Either[String, Module] = {
|
||||
for {
|
||||
organization <- {
|
||||
val e = text(node, "groupId", "Organization")
|
||||
defaultGroupId.fold(e)(g => e.orElse(\/-(g)))
|
||||
defaultGroupId.fold(e)(g => Right(e.right.getOrElse(g))).right
|
||||
}
|
||||
name <- {
|
||||
val n = text(node, "artifactId", "Name")
|
||||
defaultArtifactId.fold(n)(n0 => n.orElse(\/-(n0)))
|
||||
defaultArtifactId.fold(n)(n0 => Right(n.right.getOrElse(n0))).right
|
||||
}
|
||||
} yield Module(organization, name, Map.empty).trim
|
||||
}
|
||||
|
||||
private def readVersion(node: Node) =
|
||||
text(node, "version", "Version").getOrElse("").trim
|
||||
text(node, "version", "Version").right.getOrElse("").trim
|
||||
|
||||
def dependency(node: Node): String \/ (String, Dependency) = {
|
||||
for {
|
||||
mod <- module(node)
|
||||
version0 = readVersion(node)
|
||||
scopeOpt = text(node, "scope", "").toOption
|
||||
typeOpt = text(node, "type", "").toOption
|
||||
classifierOpt = text(node, "classifier", "").toOption
|
||||
xmlExclusions = node.children
|
||||
def dependency(node: Node): Either[String, (String, Dependency)] =
|
||||
module(node).right.flatMap { mod =>
|
||||
|
||||
val version0 = readVersion(node)
|
||||
val scopeOpt = text(node, "scope", "").right.toOption
|
||||
val typeOpt = text(node, "type", "").right.toOption
|
||||
val classifierOpt = text(node, "classifier", "").right.toOption
|
||||
val xmlExclusions = node.children
|
||||
.find(_.label == "exclusions")
|
||||
.map(_.children.filter(_.label == "exclusion"))
|
||||
.getOrElse(Seq.empty)
|
||||
exclusions <- {
|
||||
import Scalaz._
|
||||
xmlExclusions.toList.traverseU(module(_, defaultArtifactId = Some("*")))
|
||||
|
||||
xmlExclusions.toList.traverseU(module(_, defaultArtifactId = Some("*"))).right.map { exclusions =>
|
||||
|
||||
val optional = text(node, "optional", "").right.toSeq.contains("true")
|
||||
|
||||
scopeOpt.getOrElse("") -> Dependency(
|
||||
mod,
|
||||
version0,
|
||||
"",
|
||||
exclusions.map(mod => (mod.organization, mod.name)).toSet,
|
||||
Attributes(typeOpt.getOrElse(""), classifierOpt.getOrElse("")),
|
||||
optional,
|
||||
transitive = true
|
||||
)
|
||||
}
|
||||
optional = text(node, "optional", "").toOption.toSeq.contains("true")
|
||||
} yield scopeOpt.getOrElse("") -> Dependency(
|
||||
mod,
|
||||
version0,
|
||||
"",
|
||||
exclusions.map(mod => (mod.organization, mod.name)).toSet,
|
||||
Attributes(typeOpt.getOrElse(""), classifierOpt.getOrElse("")),
|
||||
optional,
|
||||
transitive = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private def profileActivation(node: Node): (Option[Boolean], Activation) = {
|
||||
val byDefault =
|
||||
text(node, "activeByDefault", "").toOption.flatMap{
|
||||
text(node, "activeByDefault", "").right.toOption.flatMap {
|
||||
case "true" => Some(true)
|
||||
case "false" => Some(false)
|
||||
case _ => None
|
||||
|
|
@ -80,27 +83,27 @@ object Pom {
|
|||
|
||||
val properties = node.children
|
||||
.filter(_.label == "property")
|
||||
.flatMap{ p =>
|
||||
.flatMap { p =>
|
||||
for{
|
||||
name <- text(p, "name", "").toOption
|
||||
valueOpt = text(p, "value", "").toOption
|
||||
name <- text(p, "name", "").right.toOption
|
||||
valueOpt = text(p, "value", "").right.toOption
|
||||
} yield (name, valueOpt)
|
||||
}
|
||||
|
||||
val osNodeOpt = node.children.collectFirst { case n if n.label == "os" => n }
|
||||
|
||||
val os = Activation.Os(
|
||||
osNodeOpt.flatMap(n => text(n, "arch", "").toOption),
|
||||
osNodeOpt.flatMap(n => text(n, "family", "").toOption).toSet,
|
||||
osNodeOpt.flatMap(n => text(n, "name", "").toOption),
|
||||
osNodeOpt.flatMap(n => text(n, "version", "").toOption)
|
||||
osNodeOpt.flatMap(n => text(n, "arch", "").right.toOption),
|
||||
osNodeOpt.flatMap(n => text(n, "family", "").right.toOption).toSet,
|
||||
osNodeOpt.flatMap(n => text(n, "name", "").right.toOption),
|
||||
osNodeOpt.flatMap(n => text(n, "version", "").right.toOption)
|
||||
)
|
||||
|
||||
val jdk = text(node, "jdk", "").toOption.flatMap { s =>
|
||||
val jdk = text(node, "jdk", "").right.toOption.flatMap { s =>
|
||||
Parse.versionInterval(s)
|
||||
.orElse(Parse.multiVersionInterval(s))
|
||||
.map(-\/(_))
|
||||
.orElse(Parse.version(s).map(v => \/-(Seq(v))))
|
||||
.map(Left(_))
|
||||
.orElse(Parse.version(s).map(v => Right(Seq(v))))
|
||||
}
|
||||
|
||||
val activation = Activation(properties, os, jdk)
|
||||
|
|
@ -108,10 +111,9 @@ object Pom {
|
|||
(byDefault, activation)
|
||||
}
|
||||
|
||||
def profile(node: Node): String \/ Profile = {
|
||||
import Scalaz._
|
||||
def profile(node: Node): Either[String, Profile] = {
|
||||
|
||||
val id = text(node, "id", "Profile ID").getOrElse("")
|
||||
val id = text(node, "id", "Profile ID").right.getOrElse("")
|
||||
|
||||
val xmlActivationOpt = node.children
|
||||
.find(_.label == "activation")
|
||||
|
|
@ -123,102 +125,117 @@ object Pom {
|
|||
.getOrElse(Seq.empty)
|
||||
|
||||
for {
|
||||
deps <- xmlDeps.toList.traverseU(dependency)
|
||||
deps <- xmlDeps.toList.traverseU(dependency).right
|
||||
|
||||
xmlDepMgmts = node.children
|
||||
depMgmts <- node
|
||||
.children
|
||||
.find(_.label == "dependencyManagement")
|
||||
.flatMap(_.children.find(_.label == "dependencies"))
|
||||
.map(_.children.filter(_.label == "dependency"))
|
||||
.getOrElse(Seq.empty)
|
||||
depMgmts <- xmlDepMgmts.toList.traverseU(dependency)
|
||||
.toList
|
||||
.traverseU(dependency)
|
||||
.right
|
||||
|
||||
xmlProperties = node.children
|
||||
properties <- node
|
||||
.children
|
||||
.find(_.label == "properties")
|
||||
.map(_.children.collect{case elem if elem.isElement => elem})
|
||||
.map(_.children.collect { case elem if elem.isElement => elem })
|
||||
.getOrElse(Seq.empty)
|
||||
|
||||
properties <- {
|
||||
import Scalaz._
|
||||
xmlProperties.toList.traverseU(property)
|
||||
}
|
||||
.toList
|
||||
.traverseU(property)
|
||||
.right
|
||||
|
||||
} yield Profile(id, activeByDefault, activation, deps, depMgmts, properties.toMap)
|
||||
}
|
||||
|
||||
def packagingOpt(pom: Node): Option[String] =
|
||||
text(pom, "packaging", "").toOption
|
||||
text(pom, "packaging", "").right.toOption
|
||||
|
||||
def project(pom: Node): String \/ Project =
|
||||
def project(pom: Node): Either[String, Project] =
|
||||
project(pom, relocationAsDependency = false)
|
||||
|
||||
def project(
|
||||
pom: Node,
|
||||
relocationAsDependency: Boolean
|
||||
): String \/ Project = {
|
||||
import Scalaz._
|
||||
): Either[String, Project] = {
|
||||
|
||||
for {
|
||||
projModule <- module(pom, defaultGroupId = Some(""))
|
||||
projVersion = readVersion(pom)
|
||||
projModule <- module(pom, defaultGroupId = Some("")).right
|
||||
|
||||
parentOpt = pom.children
|
||||
.find(_.label == "parent")
|
||||
parentOpt <- point(pom.children.find(_.label == "parent"))
|
||||
parentModuleOpt <- parentOpt
|
||||
.map(module(_).map(Some(_)))
|
||||
.getOrElse(\/-(None))
|
||||
parentVersionOpt = parentOpt
|
||||
.map(readVersion)
|
||||
.map(module(_).right.map(Some(_)))
|
||||
.getOrElse(Right(None))
|
||||
.right
|
||||
parentVersionOpt <- point(parentOpt.map(readVersion))
|
||||
|
||||
xmlDeps = pom.children
|
||||
.find(_.label == "dependencies")
|
||||
.map(_.children.filter(_.label == "dependency"))
|
||||
.getOrElse(Seq.empty)
|
||||
deps <- xmlDeps.toList.traverseU(dependency)
|
||||
xmlDeps <- point(
|
||||
pom.children
|
||||
.find(_.label == "dependencies")
|
||||
.map(_.children.filter(_.label == "dependency"))
|
||||
.getOrElse(Seq.empty)
|
||||
)
|
||||
deps <- xmlDeps.toList.traverseU(dependency).right
|
||||
|
||||
xmlDepMgmts = pom.children
|
||||
.find(_.label == "dependencyManagement")
|
||||
.flatMap(_.children.find(_.label == "dependencies"))
|
||||
.map(_.children.filter(_.label == "dependency"))
|
||||
.getOrElse(Seq.empty)
|
||||
depMgmts <- xmlDepMgmts.toList.traverseU(dependency)
|
||||
xmlDepMgmts <- point(
|
||||
pom.children
|
||||
.find(_.label == "dependencyManagement")
|
||||
.flatMap(_.children.find(_.label == "dependencies"))
|
||||
.map(_.children.filter(_.label == "dependency"))
|
||||
.getOrElse(Seq.empty)
|
||||
)
|
||||
depMgmts <- xmlDepMgmts.toList.traverseU(dependency).right
|
||||
|
||||
groupId <- Some(projModule.organization).filter(_.nonEmpty)
|
||||
.orElse(parentModuleOpt.map(_.organization).filter(_.nonEmpty))
|
||||
.toRightDisjunction("No organization found")
|
||||
version <- Some(projVersion).filter(_.nonEmpty)
|
||||
.toRight("No organization found")
|
||||
.right
|
||||
version <- Some(readVersion(pom)).filter(_.nonEmpty)
|
||||
.orElse(parentVersionOpt.filter(_.nonEmpty))
|
||||
.toRightDisjunction("No version found")
|
||||
.toRight("No version found")
|
||||
.right
|
||||
|
||||
_ <- parentVersionOpt
|
||||
.map(v => if (v.isEmpty) -\/("Parent version missing") else \/-(()))
|
||||
.getOrElse(\/-(()))
|
||||
.map(v => if (v.isEmpty) Left("Parent version missing") else Right(()))
|
||||
.getOrElse(Right(()))
|
||||
.right
|
||||
_ <- parentModuleOpt
|
||||
.map(mod => if (mod.organization.isEmpty) -\/("Parent organization missing") else \/-(()))
|
||||
.getOrElse(\/-(()))
|
||||
.map(mod => if (mod.organization.isEmpty) Left("Parent organization missing") else Right(()))
|
||||
.getOrElse(Right(()))
|
||||
.right
|
||||
|
||||
xmlProperties = pom.children
|
||||
.find(_.label == "properties")
|
||||
.map(_.children.collect{case elem if elem.isElement => elem})
|
||||
.getOrElse(Seq.empty)
|
||||
properties <- xmlProperties.toList.traverseU(property)
|
||||
xmlProperties <- point(
|
||||
pom.children
|
||||
.find(_.label == "properties")
|
||||
.map(_.children.collect{case elem if elem.isElement => elem})
|
||||
.getOrElse(Seq.empty)
|
||||
)
|
||||
properties <- xmlProperties.toList.traverseU(property).right
|
||||
|
||||
xmlProfiles = pom.children
|
||||
.find(_.label == "profiles")
|
||||
.map(_.children.filter(_.label == "profile"))
|
||||
.getOrElse(Seq.empty)
|
||||
profiles <- xmlProfiles.toList.traverseU(profile)
|
||||
xmlProfiles <- point(
|
||||
pom
|
||||
.children
|
||||
.find(_.label == "profiles")
|
||||
.map(_.children.filter(_.label == "profile"))
|
||||
.getOrElse(Seq.empty)
|
||||
)
|
||||
profiles <- xmlProfiles.toList.traverseU(profile).right
|
||||
|
||||
extraAttrs <- properties
|
||||
.collectFirst { case ("extraDependencyAttributes", s) => extraAttributes(s) }
|
||||
.getOrElse(\/-(Map.empty))
|
||||
|
||||
extraAttrsMap = extraAttrs.map {
|
||||
case (mod, ver) =>
|
||||
(mod.copy(attributes = Map.empty), ver) -> mod.attributes
|
||||
}.toMap
|
||||
.getOrElse(Right(Map.empty))
|
||||
.right
|
||||
|
||||
} yield {
|
||||
|
||||
val extraAttrsMap = extraAttrs
|
||||
.map {
|
||||
case (mod, ver) =>
|
||||
(mod.copy(attributes = Map.empty), ver) -> mod.attributes
|
||||
}
|
||||
.toMap
|
||||
|
||||
val description = pom.children
|
||||
.find(_.label == "description")
|
||||
.map(_.textContent)
|
||||
|
|
@ -235,8 +252,8 @@ object Pom {
|
|||
.flatMap(_.children)
|
||||
.filter(_.label == "license")
|
||||
.flatMap { n =>
|
||||
text(n, "name", "License name").toOption.map { name =>
|
||||
(name, text(n, "url", "License URL").toOption)
|
||||
text(n, "name", "License name").right.toOption.map { name =>
|
||||
(name, text(n, "url", "License URL").right.toOption)
|
||||
}.toSeq
|
||||
}
|
||||
|
||||
|
|
@ -247,13 +264,13 @@ object Pom {
|
|||
.filter(_.label == "developer")
|
||||
.map { n =>
|
||||
for {
|
||||
id <- text(n, "id", "Developer ID")
|
||||
name <- text(n, "name", "Developer name")
|
||||
url <- text(n, "url", "Developer URL")
|
||||
id <- text(n, "id", "Developer ID").right
|
||||
name <- text(n, "name", "Developer name").right
|
||||
url <- text(n, "url", "Developer URL").right
|
||||
} yield Info.Developer(id, name, url)
|
||||
}
|
||||
.collect {
|
||||
case \/-(d) => d
|
||||
case Right(d) => d
|
||||
}
|
||||
|
||||
val finalProjModule = projModule.copy(organization = groupId)
|
||||
|
|
@ -267,9 +284,9 @@ object Pom {
|
|||
|
||||
// see https://maven.apache.org/guides/mini/guide-relocation.html
|
||||
|
||||
val relocatedGroupId = text(n, "groupId", "").getOrElse(finalProjModule.organization)
|
||||
val relocatedArtifactId = text(n, "artifactId", "").getOrElse(finalProjModule.name)
|
||||
val relocatedVersion = text(n, "version", "").getOrElse(version)
|
||||
val relocatedGroupId = text(n, "groupId", "").right.getOrElse(finalProjModule.organization)
|
||||
val relocatedArtifactId = text(n, "artifactId", "").right.getOrElse(finalProjModule.name)
|
||||
val relocatedVersion = text(n, "version", "").right.getOrElse(version)
|
||||
|
||||
"" -> Dependency(
|
||||
finalProjModule.copy(
|
||||
|
|
@ -318,37 +335,44 @@ object Pom {
|
|||
}
|
||||
}
|
||||
|
||||
def versions(node: Node): String \/ Versions = {
|
||||
import Scalaz._
|
||||
def versions(node: Node): Either[String, Versions] = {
|
||||
|
||||
for {
|
||||
organization <- text(node, "groupId", "Organization") // Ignored
|
||||
name <- text(node, "artifactId", "Name") // Ignored
|
||||
organization <- text(node, "groupId", "Organization").right // Ignored
|
||||
name <- text(node, "artifactId", "Name").right // Ignored
|
||||
|
||||
xmlVersioning <- node.children
|
||||
.find(_.label == "versioning")
|
||||
.toRightDisjunction("Versioning info not found in metadata")
|
||||
.toRight("Versioning info not found in metadata")
|
||||
.right
|
||||
|
||||
latest = text(xmlVersioning, "latest", "Latest version")
|
||||
} yield {
|
||||
|
||||
val latest = text(xmlVersioning, "latest", "Latest version")
|
||||
.right
|
||||
.getOrElse("")
|
||||
release = text(xmlVersioning, "release", "Release version")
|
||||
val release = text(xmlVersioning, "release", "Release version")
|
||||
.right
|
||||
.getOrElse("")
|
||||
|
||||
versionsOpt = xmlVersioning.children
|
||||
val versionsOpt = xmlVersioning.children
|
||||
.find(_.label == "versions")
|
||||
.map(_.children.filter(_.label == "version").flatMap(_.children.collectFirst{case Text(t) => t}))
|
||||
.map(_.children.filter(_.label == "version").flatMap(_.children.collectFirst { case Text(t) => t }))
|
||||
|
||||
lastUpdatedOpt = text(xmlVersioning, "lastUpdated", "Last update date and time")
|
||||
val lastUpdatedOpt = text(xmlVersioning, "lastUpdated", "Last update date and time")
|
||||
.right
|
||||
.toOption
|
||||
.flatMap(parseDateTime)
|
||||
|
||||
} yield Versions(latest, release, versionsOpt.map(_.toList).getOrElse(Nil), lastUpdatedOpt)
|
||||
Versions(latest, release, versionsOpt.map(_.toList).getOrElse(Nil), lastUpdatedOpt)
|
||||
}
|
||||
}
|
||||
|
||||
def snapshotVersion(node: Node): String \/ SnapshotVersion = {
|
||||
def textOrEmpty(name: String, desc: String) =
|
||||
def snapshotVersion(node: Node): Either[String, SnapshotVersion] = {
|
||||
|
||||
def textOrEmpty(name: String, desc: String): String =
|
||||
text(node, name, desc)
|
||||
.toOption
|
||||
.right
|
||||
.getOrElse("")
|
||||
|
||||
val classifier = textOrEmpty("classifier", "Classifier")
|
||||
|
|
@ -356,10 +380,11 @@ object Pom {
|
|||
val value = textOrEmpty("value", "Value")
|
||||
|
||||
val updatedOpt = text(node, "updated", "Updated")
|
||||
.right
|
||||
.toOption
|
||||
.flatMap(parseDateTime)
|
||||
|
||||
\/-(SnapshotVersion(
|
||||
Right(SnapshotVersion(
|
||||
classifier,
|
||||
ext,
|
||||
value,
|
||||
|
|
@ -380,49 +405,72 @@ object Pom {
|
|||
SnapshotVersion("*", "*", value, None)
|
||||
}
|
||||
|
||||
def snapshotVersioning(node: Node): String \/ SnapshotVersioning = {
|
||||
import Scalaz._
|
||||
|
||||
def snapshotVersioning(node: Node): Either[String, SnapshotVersioning] =
|
||||
// FIXME Quite similar to Versions above
|
||||
for {
|
||||
organization <- text(node, "groupId", "Organization")
|
||||
name <- text(node, "artifactId", "Name")
|
||||
version = readVersion(node)
|
||||
organization <- text(node, "groupId", "Organization").right
|
||||
name <- text(node, "artifactId", "Name").right
|
||||
|
||||
xmlVersioning <- node.children
|
||||
xmlVersioning <- node
|
||||
.children
|
||||
.find(_.label == "versioning")
|
||||
.toRightDisjunction("Versioning info not found in metadata")
|
||||
.toRight("Versioning info not found in metadata")
|
||||
.right
|
||||
|
||||
latest = text(xmlVersioning, "latest", "Latest version")
|
||||
snapshotVersions <- {
|
||||
|
||||
val xmlSnapshotVersions = xmlVersioning
|
||||
.children
|
||||
.find(_.label == "snapshotVersions")
|
||||
.map(_.children.filter(_.label == "snapshotVersion"))
|
||||
.getOrElse(Seq.empty)
|
||||
|
||||
xmlSnapshotVersions
|
||||
.toList
|
||||
.traverseU(snapshotVersion)
|
||||
.right
|
||||
}
|
||||
} yield {
|
||||
|
||||
val version = readVersion(node)
|
||||
|
||||
val latest = text(xmlVersioning, "latest", "Latest version")
|
||||
.right
|
||||
.getOrElse("")
|
||||
release = text(xmlVersioning, "release", "Release version")
|
||||
val release = text(xmlVersioning, "release", "Release version")
|
||||
.right
|
||||
.getOrElse("")
|
||||
|
||||
lastUpdatedOpt = text(xmlVersioning, "lastUpdated", "Last update date and time")
|
||||
val lastUpdatedOpt = text(xmlVersioning, "lastUpdated", "Last update date and time")
|
||||
.right
|
||||
.toOption
|
||||
.flatMap(parseDateTime)
|
||||
|
||||
xmlSnapshotOpt = xmlVersioning.children
|
||||
val xmlSnapshotOpt = xmlVersioning
|
||||
.children
|
||||
.find(_.label == "snapshot")
|
||||
|
||||
timestamp = xmlSnapshotOpt
|
||||
val timestamp = xmlSnapshotOpt
|
||||
.flatMap(
|
||||
text(_, "timestamp", "Snapshot timestamp")
|
||||
.right
|
||||
.toOption
|
||||
)
|
||||
.getOrElse("")
|
||||
|
||||
buildNumber = xmlSnapshotOpt
|
||||
val buildNumber = xmlSnapshotOpt
|
||||
.flatMap(
|
||||
text(_, "buildNumber", "Snapshot build number")
|
||||
.right
|
||||
.toOption
|
||||
)
|
||||
.filter(s => s.nonEmpty && s.forall(_.isDigit))
|
||||
.map(_.toInt)
|
||||
|
||||
localCopy = xmlSnapshotOpt
|
||||
val localCopy = xmlSnapshotOpt
|
||||
.flatMap(
|
||||
text(_, "localCopy", "Snapshot local copy")
|
||||
.right
|
||||
.toOption
|
||||
)
|
||||
.collect {
|
||||
|
|
@ -430,28 +478,21 @@ object Pom {
|
|||
case "false" => false
|
||||
}
|
||||
|
||||
xmlSnapshotVersions = xmlVersioning.children
|
||||
.find(_.label == "snapshotVersions")
|
||||
.map(_.children.filter(_.label == "snapshotVersion"))
|
||||
.getOrElse(Seq.empty)
|
||||
snapshotVersions <- xmlSnapshotVersions
|
||||
.toList
|
||||
.traverseU(snapshotVersion)
|
||||
} yield SnapshotVersioning(
|
||||
Module(organization, name, Map.empty),
|
||||
version,
|
||||
latest,
|
||||
release,
|
||||
timestamp,
|
||||
buildNumber,
|
||||
localCopy,
|
||||
lastUpdatedOpt,
|
||||
if (!snapshotVersions.isEmpty)
|
||||
snapshotVersions
|
||||
else
|
||||
buildNumber.map(bn => guessedSnapshotVersion(version, timestamp, bn)).toList
|
||||
)
|
||||
}
|
||||
SnapshotVersioning(
|
||||
Module(organization, name, Map.empty),
|
||||
version,
|
||||
latest,
|
||||
release,
|
||||
timestamp,
|
||||
buildNumber,
|
||||
localCopy,
|
||||
lastUpdatedOpt,
|
||||
if (!snapshotVersions.isEmpty)
|
||||
snapshotVersions
|
||||
else
|
||||
buildNumber.map(bn => guessedSnapshotVersion(version, timestamp, bn)).toList
|
||||
)
|
||||
}
|
||||
|
||||
val relocatedPackaging = s"$$relocated"
|
||||
|
||||
|
|
@ -471,7 +512,7 @@ object Pom {
|
|||
|
||||
val extraAttributeDropPrefix = "e:"
|
||||
|
||||
def extraAttribute(s: String): String \/ (Module, String) = {
|
||||
def extraAttribute(s: String): Either[String, (Module, String)] = {
|
||||
// vaguely does the same as:
|
||||
// https://github.com/apache/ant-ivy/blob/2.2.0/src/java/org/apache/ivy/core/module/id/ModuleRevisionId.java#L291
|
||||
|
||||
|
|
@ -483,39 +524,46 @@ object Pom {
|
|||
if (rawParts.length % 2 == 0) {
|
||||
val malformed = rawParts.filter(!_.startsWith(extraAttributePrefix))
|
||||
if (malformed.isEmpty)
|
||||
\/-(rawParts.map(_.drop(extraAttributePrefix.length)))
|
||||
Right(rawParts.map(_.drop(extraAttributePrefix.length)))
|
||||
else
|
||||
-\/(s"Malformed attributes ${malformed.map("'"+_+"'").mkString(", ")} in extra attributes '$s'")
|
||||
Left(s"Malformed attributes ${malformed.map("'"+_+"'").mkString(", ")} in extra attributes '$s'")
|
||||
} else
|
||||
-\/(s"Malformed extra attributes '$s'")
|
||||
Left(s"Malformed extra attributes '$s'")
|
||||
|
||||
def attrFrom(attrs: Map[String, String], name: String): String \/ String =
|
||||
\/.fromEither(
|
||||
attrs.get(name)
|
||||
.toRight(s"$name not found in extra attributes '$s'")
|
||||
)
|
||||
def attrFrom(attrs: Map[String, String], name: String): Either[String, String] =
|
||||
attrs
|
||||
.get(name)
|
||||
.toRight(s"$name not found in extra attributes '$s'")
|
||||
|
||||
for {
|
||||
parts <- partsOrError
|
||||
attrs = parts.grouped(2).collect {
|
||||
case Seq(k, v) if v != "NULL" =>
|
||||
k.stripPrefix(extraAttributeDropPrefix) -> v
|
||||
}.toMap
|
||||
org <- attrFrom(attrs, extraAttributeOrg)
|
||||
name <- attrFrom(attrs, extraAttributeName)
|
||||
version <- attrFrom(attrs, extraAttributeVersion)
|
||||
remainingAttrs = attrs.filterKeys(!extraAttributeBase(_))
|
||||
} yield (Module(org, name, remainingAttrs.toVector.toMap), version)
|
||||
parts <- partsOrError.right
|
||||
attrs <- point(
|
||||
parts
|
||||
.grouped(2)
|
||||
.collect {
|
||||
case Seq(k, v) if v != "NULL" =>
|
||||
k.stripPrefix(extraAttributeDropPrefix) -> v
|
||||
}
|
||||
.toMap
|
||||
)
|
||||
org <- attrFrom(attrs, extraAttributeOrg).right
|
||||
name <- attrFrom(attrs, extraAttributeName).right
|
||||
version <- attrFrom(attrs, extraAttributeVersion).right
|
||||
} yield {
|
||||
val remainingAttrs = attrs.filterKeys(!extraAttributeBase(_))
|
||||
(Module(org, name, remainingAttrs.toVector.toMap), version)
|
||||
}
|
||||
}
|
||||
|
||||
def extraAttributes(s: String): String \/ Seq[(Module, String)] = {
|
||||
def extraAttributes(s: String): Either[String, Seq[(Module, String)]] = {
|
||||
|
||||
val lines = s.split('\n').toSeq.map(_.trim).filter(_.nonEmpty)
|
||||
|
||||
lines.foldLeft[String \/ Seq[(Module, String)]](\/-(Vector.empty)) {
|
||||
lines.foldLeft[Either[String, Seq[(Module, String)]]](Right(Vector.empty)) {
|
||||
case (acc, line) =>
|
||||
for {
|
||||
modVers <- acc
|
||||
modVer <- extraAttribute(line)
|
||||
modVers <- acc.right
|
||||
modVer <- extraAttribute(line).right
|
||||
} yield modVers :+ modVer
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
package coursier.util
|
||||
|
||||
import scala.language.higherKinds
|
||||
import scalaz.Monad
|
||||
|
||||
final case class EitherT[F[_], L, R](run: F[Either[L, R]]) {
|
||||
|
||||
def map[S](f: R => S)(implicit M: Monad[F]): EitherT[F, L, S] =
|
||||
EitherT(
|
||||
M.map(run)(e => e.right.map(f))
|
||||
)
|
||||
|
||||
def flatMap[S](f: R => EitherT[F, L, S])(implicit M: Monad[F]): EitherT[F, L, S] =
|
||||
EitherT(
|
||||
M.bind(run) {
|
||||
case Left(l) =>
|
||||
M.point(Left(l))
|
||||
case Right(r) =>
|
||||
f(r).run
|
||||
}
|
||||
)
|
||||
|
||||
def leftMap[M](f: L => M)(implicit M: Monad[F]): EitherT[F, M, R] =
|
||||
EitherT(
|
||||
M.map(run)(e => e.left.map(f))
|
||||
)
|
||||
|
||||
def orElse(other: => EitherT[F, L, R])(implicit M: Monad[F]): EitherT[F, L, R] =
|
||||
EitherT(
|
||||
M.bind(run) {
|
||||
case Left(_) =>
|
||||
other.run
|
||||
case Right(r) =>
|
||||
M.point(Right(r))
|
||||
}
|
||||
)
|
||||
|
||||
def scalaz(implicit M: Monad[F]): _root_.scalaz.EitherT[F, L, R] =
|
||||
_root_.scalaz.EitherT(
|
||||
M.map(run)(_root_.scalaz.\/.fromEither)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
object EitherT {
|
||||
|
||||
def point[F[_], L, R](r: R)(implicit M: Monad[F]): EitherT[F, L, R] =
|
||||
EitherT(M.point(Right(r)))
|
||||
|
||||
def fromEither[F[_]]: FromEither[F] =
|
||||
new FromEither[F]
|
||||
|
||||
final class FromEither[F[_]] {
|
||||
def apply[L, R](either: Either[L, R])(implicit M: Monad[F]): EitherT[F, L, R] =
|
||||
EitherT(M.point(either))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -6,8 +6,6 @@ import coursier.ivy.IvyRepository
|
|||
import coursier.maven.MavenRepository
|
||||
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
import scalaz.\/
|
||||
import scalaz.Scalaz.ToEitherOps
|
||||
|
||||
object Parse {
|
||||
|
||||
|
|
@ -354,35 +352,35 @@ object Parse {
|
|||
defaultScalaVersion: String): (Seq[String], Seq[(Dependency, Map[String, String])]) =
|
||||
valuesAndErrors(moduleVersionConfig(_, req, transitive, defaultScalaVersion), l)
|
||||
|
||||
def repository(s: String): String \/ Repository =
|
||||
def repository(s: String): Either[String, Repository] =
|
||||
if (s == "central")
|
||||
MavenRepository("https://repo1.maven.org/maven2").right
|
||||
Right(MavenRepository("https://repo1.maven.org/maven2"))
|
||||
else if (s.startsWith("sonatype:"))
|
||||
MavenRepository(s"https://oss.sonatype.org/content/repositories/${s.stripPrefix("sonatype:")}").right
|
||||
Right(MavenRepository(s"https://oss.sonatype.org/content/repositories/${s.stripPrefix("sonatype:")}"))
|
||||
else if (s.startsWith("bintray:"))
|
||||
MavenRepository(s"https://dl.bintray.com/${s.stripPrefix("bintray:")}").right
|
||||
Right(MavenRepository(s"https://dl.bintray.com/${s.stripPrefix("bintray:")}"))
|
||||
else if (s.startsWith("bintray-ivy:"))
|
||||
IvyRepository.fromPattern(
|
||||
Right(IvyRepository.fromPattern(
|
||||
s"https://dl.bintray.com/${s.stripPrefix("bintray-ivy:").stripSuffix("/")}/" +:
|
||||
coursier.ivy.Pattern.default
|
||||
).right
|
||||
))
|
||||
else if (s.startsWith("typesafe:ivy-"))
|
||||
IvyRepository.fromPattern(
|
||||
Right(IvyRepository.fromPattern(
|
||||
s"https://repo.typesafe.com/typesafe/ivy-${s.stripPrefix("typesafe:ivy-")}/" +:
|
||||
coursier.ivy.Pattern.default
|
||||
).right
|
||||
))
|
||||
else if (s.startsWith("typesafe:"))
|
||||
MavenRepository(s"https://repo.typesafe.com/typesafe/${s.stripPrefix("typesafe:")}").right
|
||||
Right(MavenRepository(s"https://repo.typesafe.com/typesafe/${s.stripPrefix("typesafe:")}"))
|
||||
else if (s.startsWith("sbt-plugin:"))
|
||||
IvyRepository.fromPattern(
|
||||
Right(IvyRepository.fromPattern(
|
||||
s"https://repo.scala-sbt.org/scalasbt/sbt-plugin-${s.stripPrefix("sbt-plugin:")}/" +:
|
||||
coursier.ivy.Pattern.default
|
||||
).right
|
||||
))
|
||||
else if (s.startsWith("ivy:"))
|
||||
IvyRepository.parse(s.stripPrefix("ivy:"))
|
||||
else if (s == "jitpack")
|
||||
MavenRepository("https://jitpack.io").right
|
||||
Right(MavenRepository("https://jitpack.io"))
|
||||
else
|
||||
MavenRepository(s).right
|
||||
Right(MavenRepository(s))
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ package coursier.util
|
|||
|
||||
import coursier.core.Versions
|
||||
|
||||
import scalaz.{\/-, -\/, \/, Scalaz}
|
||||
|
||||
object Xml {
|
||||
|
||||
/** A representation of an XML node/document, with different implementations on JVM and JS */
|
||||
|
|
@ -23,10 +21,10 @@ object Xml {
|
|||
}
|
||||
|
||||
lazy val attributesMap = attributes.map { case (_, k, v) => k -> v }.toMap
|
||||
def attribute(name: String): String \/ String =
|
||||
def attribute(name: String): Either[String, String] =
|
||||
attributesMap.get(name) match {
|
||||
case None => -\/(s"Missing attribute $name")
|
||||
case Some(value) => \/-(value)
|
||||
case None => Left(s"Missing attribute $name")
|
||||
case Some(value) => Right(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -48,14 +46,11 @@ object Xml {
|
|||
else None
|
||||
}
|
||||
|
||||
def text(elem: Node, label: String, description: String) = {
|
||||
import Scalaz.ToOptionOpsFromOption
|
||||
|
||||
def text(elem: Node, label: String, description: String): Either[String, String] =
|
||||
elem.children
|
||||
.find(_.label == label)
|
||||
.flatMap(_.children.collectFirst{case Text(t) => t})
|
||||
.toRightDisjunction(s"$description not found")
|
||||
}
|
||||
.toRight(s"$description not found")
|
||||
|
||||
def parseDateTime(s: String): Option[Versions.DateTime] =
|
||||
if (s.length == 14 && s.forall(_.isDigit))
|
||||
|
|
|
|||
|
|
@ -131,6 +131,8 @@ libraryDependencies ++= Seq(
|
|||
)
|
||||
```
|
||||
|
||||
Note that the examples below are validated against the current sources of coursier. You may want to read the [documentation of the latest release](https://github.com/coursier/coursier/blob/v1.0.2/README.md#api) of coursier instead.
|
||||
|
||||
Add an import for coursier,
|
||||
```scala
|
||||
import coursier._
|
||||
|
|
@ -208,10 +210,9 @@ These would mean that the resolution wasn't able to get metadata about some depe
|
|||
Then fetch and get local copies of the artifacts themselves (the JARs) with
|
||||
```tut:silent
|
||||
import java.io.File
|
||||
import scalaz.\/
|
||||
import scalaz.concurrent.Task
|
||||
|
||||
val localArtifacts: Seq[FileError \/ File] = Task.gatherUnordered(
|
||||
val localArtifacts: Seq[Either[FileError, File]] = Task.gatherUnordered(
|
||||
resolution.artifacts.map(Cache.file(_).run)
|
||||
).unsafePerformSync
|
||||
```
|
||||
|
|
@ -451,6 +452,8 @@ libraryDependencies ++= Seq(
|
|||
)
|
||||
```
|
||||
|
||||
Note that the examples below are validated against the current sources of coursier. You may want to read the [documentation of the latest release](https://github.com/coursier/coursier/blob/v1.0.2/README.md#api-1) of coursier instead.
|
||||
|
||||
The first module, `"io.get-coursier" %% "coursier" % "1.0.1"`, mainly depends on
|
||||
`scalaz-core` (and only it, *not* `scalaz-concurrent` for example). It contains among others,
|
||||
definitions,
|
||||
|
|
@ -536,7 +539,7 @@ MavenRepository(
|
|||
|
||||
Now that we have repositories, we're going to mix these with things from the `coursier-cache` module,
|
||||
for resolution to happen via the cache. We'll create a function
|
||||
of type `Seq[(Module, String)] => F[Seq[((Module, String), Seq[String] \/ (Artifact.Source, Project))]]`.
|
||||
of type `Seq[(Module, String)] => F[Seq[((Module, String), Either[Seq[String], (Artifact.Source, Project)])]]`.
|
||||
Given a sequence of dependencies, designated by their `Module` (organisation and name in most cases)
|
||||
and version (just a `String`), it gives either errors (`Seq[String]`) or metadata (`(Artifact.Source, Project)`),
|
||||
wrapping the whole in a monad `F`.
|
||||
|
|
@ -591,10 +594,9 @@ which are dependencies whose versions could not be unified.
|
|||
Then, if all went well, we can fetch and get local copies of the artifacts themselves (the JARs) with
|
||||
```tut:silent
|
||||
import java.io.File
|
||||
import scalaz.\/
|
||||
import scalaz.concurrent.Task
|
||||
|
||||
val localArtifacts: Seq[FileError \/ File] = Task.gatherUnordered(
|
||||
val localArtifacts: Seq[Either[FileError, File]] = Task.gatherUnordered(
|
||||
resolution.artifacts.map(Cache.file(_).run)
|
||||
).unsafePerformSync
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
package coursier
|
||||
|
||||
import java.io.{ File, FileNotFoundException, IOException }
|
||||
import java.net.{ HttpURLConnection, URL, URLConnection }
|
||||
import java.io.{File, FileNotFoundException, IOException}
|
||||
import java.net.{HttpURLConnection, URL, URLConnection}
|
||||
|
||||
import coursier.util.EitherT
|
||||
|
||||
import scala.language.higherKinds
|
||||
|
||||
import scalaz.{ EitherT, Monad }
|
||||
import scalaz.syntax.monad._
|
||||
import scalaz.Scalaz.ToEitherOps
|
||||
import scalaz.Monad
|
||||
|
||||
object FallbackDependenciesRepository {
|
||||
|
||||
|
|
@ -106,14 +105,14 @@ final case class FallbackDependenciesRepository(
|
|||
|
||||
val res = fallbacks
|
||||
.get((module, version))
|
||||
.fold("No fallback URL found".left[(Artifact.Source, Project)]) {
|
||||
.fold[Either[String, (Artifact.Source, Project)]](Left("No fallback URL found")) {
|
||||
case (url, _) =>
|
||||
|
||||
val urlStr = url.toExternalForm
|
||||
val idx = urlStr.lastIndexOf('/')
|
||||
|
||||
if (idx < 0 || urlStr.endsWith("/"))
|
||||
s"$url doesn't point to a file".left
|
||||
Left(s"$url doesn't point to a file")
|
||||
else {
|
||||
val (dirUrlStr, fileName) = urlStr.splitAt(idx + 1)
|
||||
|
||||
|
|
@ -135,12 +134,12 @@ final case class FallbackDependenciesRepository(
|
|||
Info.empty
|
||||
)
|
||||
|
||||
(source, proj).right
|
||||
Right((source, proj))
|
||||
} else
|
||||
s"$fileName not found under $dirUrlStr".left
|
||||
Left(s"$fileName not found under $dirUrlStr")
|
||||
}
|
||||
}
|
||||
|
||||
EitherT(res.point)
|
||||
EitherT(F.point(res))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,13 @@
|
|||
package coursier
|
||||
|
||||
import org.scalajs.dom.raw.{ Event, XMLHttpRequest }
|
||||
|
||||
import scala.concurrent.{ ExecutionContext, Promise, Future }
|
||||
import coursier.util.EitherT
|
||||
import org.scalajs.dom.raw.{Event, XMLHttpRequest}
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future, Promise}
|
||||
import scala.language.implicitConversions
|
||||
|
||||
import scala.scalajs.js
|
||||
import js.Dynamic.{ global => g }
|
||||
|
||||
import js.Dynamic.{global => g}
|
||||
import scala.scalajs.js.timers._
|
||||
import scalaz.{ -\/, \/-, EitherT }
|
||||
|
||||
object Platform {
|
||||
|
||||
|
|
@ -80,9 +77,9 @@ object Platform {
|
|||
EitherT(
|
||||
Task { implicit ec =>
|
||||
get(artifact.url)
|
||||
.map(\/-(_))
|
||||
.map(Right(_))
|
||||
.recover { case e: Exception =>
|
||||
-\/(e.toString + Option(e.getMessage).fold("")(" (" + _ + ")"))
|
||||
Left(e.toString + Option(e.getMessage).fold("")(" (" + _ + ")"))
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
@ -104,11 +101,11 @@ object Platform {
|
|||
Task { implicit ec =>
|
||||
Future(logger.fetching(artifact.url))
|
||||
.flatMap(_ => get(artifact.url))
|
||||
.map { s => logger.fetched(artifact.url); \/-(s) }
|
||||
.map { s => logger.fetched(artifact.url); Right(s) }
|
||||
.recover { case e: Exception =>
|
||||
val msg = e.toString + Option(e.getMessage).fold("")(" (" + _ + ")")
|
||||
logger.other(artifact.url, msg)
|
||||
-\/(msg)
|
||||
Left(msg)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -10,25 +10,6 @@ object Mima {
|
|||
|
||||
// Important: the line with the "binary compatibility versions" comment below is matched during releases
|
||||
def binaryCompatibilityVersions = Set(
|
||||
"1.0.0-RC1",
|
||||
"1.0.0-RC2",
|
||||
"1.0.0-RC3",
|
||||
"1.0.0-RC4",
|
||||
"1.0.0-RC5",
|
||||
"1.0.0-RC6",
|
||||
"1.0.0-RC7",
|
||||
"1.0.0-RC8",
|
||||
"1.0.0-RC9",
|
||||
"1.0.0-RC10",
|
||||
"1.0.0-RC11",
|
||||
"1.0.0-RC12",
|
||||
"1.0.0-RC12-1",
|
||||
"1.0.0-RC13",
|
||||
"1.0.0-RC14",
|
||||
"1.0.0",
|
||||
"1.0.1-M1",
|
||||
"1.0.1",
|
||||
"1.0.2",
|
||||
"" // binary compatibility versions
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
package coursier
|
||||
|
||||
import scala.language.higherKinds
|
||||
import coursier.util.EitherT
|
||||
|
||||
import scalaz.{EitherT, Monad}
|
||||
import scalaz.syntax.monad._
|
||||
import scalaz.syntax.std.option._
|
||||
import scala.language.higherKinds
|
||||
import scalaz.Monad
|
||||
|
||||
final case class InterProjectRepository(projects: Seq[Project]) extends Repository {
|
||||
|
||||
|
|
@ -12,17 +11,19 @@ final case class InterProjectRepository(projects: Seq[Project]) extends Reposito
|
|||
.map(proj => proj.moduleVersion -> proj)
|
||||
.toMap
|
||||
|
||||
def find[F[_]: Monad](
|
||||
def find[F[_]](
|
||||
module: Module,
|
||||
version: String,
|
||||
fetch: Fetch.Content[F]
|
||||
)(implicit
|
||||
F: Monad[F]
|
||||
): EitherT[F, String, (Artifact.Source, Project)] = {
|
||||
|
||||
val res = map
|
||||
.get((module, version))
|
||||
.toRightDisjunction("Not found")
|
||||
.map((Artifact.Source.empty, _))
|
||||
.toRight("Not found")
|
||||
|
||||
EitherT(res.point)
|
||||
EitherT(F.point(res))
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ import sbt.librarymanagement.GetClassifiersModule
|
|||
import sbt.{Resolver, SettingKey, TaskKey}
|
||||
|
||||
import scala.concurrent.duration.Duration
|
||||
import scalaz.\/
|
||||
|
||||
object Keys {
|
||||
val coursierParallelDownloads = SettingKey[Int]("coursier-parallel-downloads")
|
||||
|
|
@ -65,8 +64,8 @@ object Keys {
|
|||
"Prints dependencies and transitive dependencies as an inverted tree (dependees as children)"
|
||||
)
|
||||
|
||||
val coursierArtifacts = TaskKey[Map[Artifact, FileError \/ File]]("coursier-artifacts")
|
||||
val coursierSignedArtifacts = TaskKey[Map[Artifact, FileError \/ File]]("coursier-signed-artifacts")
|
||||
val coursierClassifiersArtifacts = TaskKey[Map[Artifact, FileError \/ File]]("coursier-classifiers-artifacts")
|
||||
val coursierSbtClassifiersArtifacts = TaskKey[Map[Artifact, FileError \/ File]]("coursier-sbt-classifiers-artifacts")
|
||||
val coursierArtifacts = TaskKey[Map[Artifact, Either[FileError, File]]]("coursier-artifacts")
|
||||
val coursierSignedArtifacts = TaskKey[Map[Artifact, Either[FileError, File]]]("coursier-signed-artifacts")
|
||||
val coursierClassifiersArtifacts = TaskKey[Map[Artifact, Either[FileError, File]]]("coursier-classifiers-artifacts")
|
||||
val coursierSbtClassifiersArtifacts = TaskKey[Map[Artifact, Either[FileError, File]]]("coursier-sbt-classifiers-artifacts")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import sbt.Keys._
|
|||
import scala.collection.mutable
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
import scala.util.Try
|
||||
import scalaz.{-\/, \/-}
|
||||
import scalaz.concurrent.{Strategy, Task}
|
||||
|
||||
object Tasks {
|
||||
|
|
@ -450,16 +449,16 @@ object Tasks {
|
|||
{
|
||||
s =>
|
||||
val p = PropertiesPattern.parse(s) match {
|
||||
case -\/(err) =>
|
||||
case Left(err) =>
|
||||
throw new Exception(s"Cannot parse pattern $s: $err")
|
||||
case \/-(p) =>
|
||||
case Right(p) =>
|
||||
p
|
||||
}
|
||||
|
||||
p.substituteProperties(props ++ extraProps) match {
|
||||
case -\/(err) =>
|
||||
case Left(err) =>
|
||||
throw new Exception(err)
|
||||
case \/-(p) =>
|
||||
case Right(p) =>
|
||||
p
|
||||
}
|
||||
}
|
||||
|
|
@ -754,7 +753,9 @@ object Tasks {
|
|||
.process
|
||||
.run(fetch, maxIterations)
|
||||
.unsafePerformSyncAttempt
|
||||
.leftMap(ex =>
|
||||
.toEither
|
||||
.left
|
||||
.map(ex =>
|
||||
ResolutionError.UnknownException(ex)
|
||||
.throwException()
|
||||
)
|
||||
|
|
@ -1042,11 +1043,11 @@ object Tasks {
|
|||
|
||||
artifactsLogger.init(if (printOptionalMessage) log.info(artifactInitialMessage))
|
||||
|
||||
Task.gatherUnordered(artifactFileOrErrorTasks).unsafePerformSyncAttempt match {
|
||||
case -\/(ex) =>
|
||||
Task.gatherUnordered(artifactFileOrErrorTasks).unsafePerformSyncAttempt.toEither match {
|
||||
case Left(ex) =>
|
||||
ResolutionError.UnknownDownloadException(ex)
|
||||
.throwException()
|
||||
case \/-(l) =>
|
||||
case Right(l) =>
|
||||
l.toMap
|
||||
}
|
||||
} finally {
|
||||
|
|
@ -1270,14 +1271,14 @@ object Tasks {
|
|||
}
|
||||
|
||||
val artifactFiles = artifactFilesOrErrors0.collect {
|
||||
case (artifact, \/-(file)) =>
|
||||
case (artifact, Right(file)) =>
|
||||
artifact -> file
|
||||
}
|
||||
|
||||
val artifactErrors = artifactFilesOrErrors0
|
||||
.toVector
|
||||
.collect {
|
||||
case (a, -\/(err)) if !a.isOptional || !err.notFound =>
|
||||
case (a, Left(err)) if !a.isOptional || !err.notFound =>
|
||||
a -> err
|
||||
}
|
||||
|
||||
|
|
@ -1292,7 +1293,7 @@ object Tasks {
|
|||
|
||||
// can be non empty only if ignoreArtifactErrors is true or some optional artifacts are not found
|
||||
val erroredArtifacts = artifactFilesOrErrors0.collect {
|
||||
case (artifact, -\/(_)) =>
|
||||
case (artifact, Left(_)) =>
|
||||
artifact
|
||||
}.toSet
|
||||
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@ import com.tonicsystems.jarjar.transform.jar.DefaultJarProcessor
|
|||
import coursier.core.Orders
|
||||
import sbt.file
|
||||
|
||||
import scalaz.{\/, \/-}
|
||||
|
||||
object Shading {
|
||||
|
||||
// FIXME Also vaguely in cli
|
||||
|
|
@ -58,7 +56,7 @@ object Shading {
|
|||
currentProject: Project,
|
||||
res: Resolution,
|
||||
configs: Map[String, Set[String]],
|
||||
artifactFilesOrErrors: Map[Artifact, FileError \/ File],
|
||||
artifactFilesOrErrors: Map[Artifact, Either[FileError, File]],
|
||||
classpathTypes: Set[String],
|
||||
baseConfig: String,
|
||||
shadedConf: String,
|
||||
|
|
@ -101,7 +99,7 @@ object Shading {
|
|||
|
||||
val artifactFilesOrErrors0 = artifactFilesOrErrors
|
||||
.collect {
|
||||
case (a, \/-(f)) => a.url -> f
|
||||
case (a, Right(f)) => a.url -> f
|
||||
}
|
||||
|
||||
val compileDeps = configDependencies(baseConfig)
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ import sbt.librarymanagement._
|
|||
import sbt.librarymanagement.Resolver
|
||||
import sbt.util.Logger
|
||||
|
||||
import scalaz.{-\/, \/-}
|
||||
|
||||
object FromSbt {
|
||||
|
||||
def sbtModuleIdName(
|
||||
|
|
@ -227,11 +225,11 @@ object FromSbt {
|
|||
dropInfoAttributes = true,
|
||||
authentication = authentication
|
||||
) match {
|
||||
case -\/(err) =>
|
||||
case Left(err) =>
|
||||
sys.error(
|
||||
s"Cannot parse Ivy patterns ${r.patterns.artifactPatterns.head} and ${r.patterns.ivyPatterns.head}: $err"
|
||||
)
|
||||
case \/-(repo) =>
|
||||
case Right(repo) =>
|
||||
repo
|
||||
}
|
||||
|
||||
|
|
@ -258,11 +256,11 @@ object FromSbt {
|
|||
dropInfoAttributes = true,
|
||||
authentication = authentication
|
||||
) match {
|
||||
case -\/(err) =>
|
||||
case Left(err) =>
|
||||
sys.error(
|
||||
s"Cannot parse Ivy patterns ${r.patterns.artifactPatterns.head} and ${r.patterns.ivyPatterns.head}: $err"
|
||||
)
|
||||
case \/-(repo) =>
|
||||
case Right(repo) =>
|
||||
repo
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
package coursier.test
|
||||
|
||||
import coursier.util.TestEscape
|
||||
import coursier.util.{EitherT, TestEscape}
|
||||
import coursier.{Fetch, Task}
|
||||
|
||||
import scala.concurrent.{Promise, ExecutionContext, Future}
|
||||
import scala.concurrent.{ExecutionContext, Future, Promise}
|
||||
import scala.scalajs.js
|
||||
import js.Dynamic.{global => g}
|
||||
import scalaz.{-\/, EitherT, \/-}
|
||||
|
||||
package object compatibility {
|
||||
|
||||
|
|
@ -40,10 +39,10 @@ package object compatibility {
|
|||
|
||||
Task { implicit ec =>
|
||||
textResource0(path)
|
||||
.map(\/-(_))
|
||||
.map(Right(_))
|
||||
.recoverWith {
|
||||
case e: Exception =>
|
||||
Future.successful(-\/(e.getMessage))
|
||||
Future.successful(Left(e.getMessage))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ object IvyTests extends TestSuite {
|
|||
"[organisation]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)" +
|
||||
"[revision]/[type]s/[artifact](-[classifier]).[ext]",
|
||||
dropInfoAttributes = true
|
||||
).getOrElse(
|
||||
).right.getOrElse(
|
||||
throw new Exception("Cannot happen")
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import utest._
|
|||
|
||||
import scala.collection.JavaConverters._
|
||||
import scala.concurrent.duration.DurationInt
|
||||
import scalaz.{-\/, \/-}
|
||||
import scalaz.concurrent.Task
|
||||
|
||||
object ResolutionProcessTests extends TestSuite {
|
||||
|
|
@ -40,7 +39,7 @@ object ResolutionProcessTests extends TestSuite {
|
|||
case Seq(mv @ (`mod`, v)) =>
|
||||
Task.async { cb =>
|
||||
called.put(v, ())
|
||||
cb(\/-(Seq((mv, -\/(Seq("w/e"))))))
|
||||
cb(scalaz.\/-(Seq((mv, Left(Seq("w/e"))))))
|
||||
}
|
||||
|
||||
case _ => sys.error(s"Cannot happen ($modVers)")
|
||||
|
|
|
|||
|
|
@ -3,11 +3,10 @@ package coursier.test
|
|||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.{Files, Paths}
|
||||
|
||||
import coursier.util.TestEscape
|
||||
import coursier.util.{EitherT, TestEscape}
|
||||
import coursier.{Cache, Fetch, Platform}
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
import scalaz.{-\/, EitherT, \/, \/-}
|
||||
import scalaz.concurrent.Task
|
||||
|
||||
package object compatibility {
|
||||
|
|
@ -49,20 +48,20 @@ package object compatibility {
|
|||
|
||||
val init = EitherT[Task, String, Unit] {
|
||||
if (Files.exists(path))
|
||||
Task.now(\/-(()))
|
||||
Task.now(Right(()))
|
||||
else if (fillChunks)
|
||||
Task[String \/ Unit] {
|
||||
Task[Either[String, Unit]] {
|
||||
Files.createDirectories(path.getParent)
|
||||
def is() = Cache.urlConnection(artifact.url, artifact.authentication).getInputStream
|
||||
val b = Platform.readFullySync(is())
|
||||
Files.write(path, b)
|
||||
\/-(())
|
||||
Right(())
|
||||
}.handle {
|
||||
case e: Exception =>
|
||||
-\/(e.toString)
|
||||
Left(e.toString)
|
||||
}
|
||||
else
|
||||
Task.now(-\/(s"not found: $path"))
|
||||
Task.now(Left(s"not found: $path"))
|
||||
}
|
||||
|
||||
init.flatMap { _ =>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
io.get-coursier:coursier_2.11:1.0.3-SNAPSHOT:compile
|
||||
io.get-coursier:coursier_2.11:1.1.0-SNAPSHOT:compile
|
||||
org.scala-lang:scala-library:2.11.12:default
|
||||
org.scala-lang.modules:scala-xml_2.11:1.0.6:default
|
||||
org.scalaz:scalaz-core_2.11:7.2.16:default
|
||||
|
|
@ -4,8 +4,6 @@ import coursier.core.{Activation, Parse}
|
|||
import coursier.core.Activation.Os
|
||||
import utest._
|
||||
|
||||
import scalaz.{-\/, \/-}
|
||||
|
||||
object ActivationTests extends TestSuite {
|
||||
|
||||
def parseVersion(s: String) = Parse.version(s).getOrElse(???)
|
||||
|
|
@ -210,7 +208,7 @@ object ActivationTests extends TestSuite {
|
|||
val activation = Activation(
|
||||
Nil,
|
||||
Os.empty,
|
||||
Some(\/-(Seq(parseVersion("1.8.0_112"))))
|
||||
Some(Right(Seq(parseVersion("1.8.0_112"))))
|
||||
)
|
||||
|
||||
val isActive = activation.isActive(Map(), Os.empty, Some(jdkVersion))
|
||||
|
|
@ -222,7 +220,7 @@ object ActivationTests extends TestSuite {
|
|||
val activation = Activation(
|
||||
Nil,
|
||||
Os.empty,
|
||||
Some(\/-(Seq(parseVersion("1.8.0_102"), parseVersion("1.8.0_112"))))
|
||||
Some(Right(Seq(parseVersion("1.8.0_102"), parseVersion("1.8.0_112"))))
|
||||
)
|
||||
|
||||
val isActive = activation.isActive(Map(), Os.empty, Some(jdkVersion))
|
||||
|
|
@ -235,7 +233,7 @@ object ActivationTests extends TestSuite {
|
|||
val activation = Activation(
|
||||
Nil,
|
||||
Os.empty,
|
||||
Some(\/-(Seq(parseVersion("1.8.0_102"))))
|
||||
Some(Right(Seq(parseVersion("1.8.0_102"))))
|
||||
)
|
||||
|
||||
val isActive = activation.isActive(Map(), Os.empty, Some(jdkVersion))
|
||||
|
|
@ -248,7 +246,7 @@ object ActivationTests extends TestSuite {
|
|||
val activation = Activation(
|
||||
Nil,
|
||||
Os.empty,
|
||||
Some(\/-(Seq(parseVersion("1.8.0_92"), parseVersion("1.8.0_102"))))
|
||||
Some(Right(Seq(parseVersion("1.8.0_92"), parseVersion("1.8.0_102"))))
|
||||
)
|
||||
|
||||
val isActive = activation.isActive(Map(), Os.empty, Some(jdkVersion))
|
||||
|
|
@ -260,7 +258,7 @@ object ActivationTests extends TestSuite {
|
|||
val activation = Activation(
|
||||
Nil,
|
||||
Os.empty,
|
||||
Some(-\/(parseVersionInterval("[1.8,)")))
|
||||
Some(Left(parseVersionInterval("[1.8,)")))
|
||||
)
|
||||
|
||||
val isActive = activation.isActive(Map(), Os.empty, Some(jdkVersion))
|
||||
|
|
@ -272,7 +270,7 @@ object ActivationTests extends TestSuite {
|
|||
val activation = Activation(
|
||||
Nil,
|
||||
Os.empty,
|
||||
Some(-\/(parseVersionInterval("[1.7,1.8)")))
|
||||
Some(Left(parseVersionInterval("[1.7,1.8)")))
|
||||
)
|
||||
|
||||
val isActive = activation.isActive(Map(), Os.empty, Some(jdkVersion))
|
||||
|
|
@ -290,7 +288,7 @@ object ActivationTests extends TestSuite {
|
|||
"requiredWithNegValue" -> Some("!bar")
|
||||
),
|
||||
Os(None, Set("mac"), None, None),
|
||||
Some(-\/(parseVersionInterval("[1.8,)")))
|
||||
Some(Left(parseVersionInterval("[1.8,)")))
|
||||
)
|
||||
|
||||
'match - {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@ import coursier.ivy.PropertiesPattern.ChunkOrProperty._
|
|||
|
||||
import utest._
|
||||
|
||||
import scalaz.Scalaz.ToEitherOps
|
||||
|
||||
object IvyPatternParserTests extends TestSuite {
|
||||
|
||||
val tests = TestSuite {
|
||||
|
|
@ -23,7 +21,7 @@ object IvyPatternParserTests extends TestSuite {
|
|||
"/resolved.xml.", Var("ext")
|
||||
)
|
||||
|
||||
assert(PropertiesPattern.parse(strPattern).map(_.chunks) == expectedChunks.right)
|
||||
assert(PropertiesPattern.parse(strPattern).right.map(_.chunks) == Right(expectedChunks))
|
||||
}
|
||||
|
||||
'activatorLaunchLocal - {
|
||||
|
|
@ -50,48 +48,48 @@ object IvyPatternParserTests extends TestSuite {
|
|||
)
|
||||
|
||||
val pattern0 = PropertiesPattern.parse(strPattern)
|
||||
assert(pattern0.map(_.chunks) == expectedChunks.right)
|
||||
assert(pattern0.right.map(_.chunks) == Right(expectedChunks))
|
||||
|
||||
val pattern = pattern0.toOption.get
|
||||
val pattern = pattern0.right.get
|
||||
|
||||
* - {
|
||||
val varPattern = pattern.substituteProperties(Map(
|
||||
"activator.local.repository" -> "xyz"
|
||||
)).map(_.string)
|
||||
)).right.map(_.string)
|
||||
|
||||
val expectedVarPattern =
|
||||
"file://xyz" +
|
||||
"/[organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)" +
|
||||
"[revision]/[type]s/[artifact](-[classifier]).[ext]"
|
||||
|
||||
assert(varPattern == expectedVarPattern.right)
|
||||
assert(varPattern == Right(expectedVarPattern))
|
||||
}
|
||||
|
||||
* - {
|
||||
val varPattern = pattern.substituteProperties(Map(
|
||||
"activator.local.repository" -> "xyz",
|
||||
"activator.home" -> "aaaa"
|
||||
)).map(_.string)
|
||||
)).right.map(_.string)
|
||||
|
||||
val expectedVarPattern =
|
||||
"file://xyz" +
|
||||
"/[organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)" +
|
||||
"[revision]/[type]s/[artifact](-[classifier]).[ext]"
|
||||
|
||||
assert(varPattern == expectedVarPattern.right)
|
||||
assert(varPattern == Right(expectedVarPattern))
|
||||
}
|
||||
|
||||
* - {
|
||||
val varPattern = pattern.substituteProperties(Map(
|
||||
"activator.home" -> "aaaa"
|
||||
)).map(_.string)
|
||||
)).right.map(_.string)
|
||||
|
||||
val expectedVarPattern =
|
||||
"file://aaaa/repository" +
|
||||
"/[organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)" +
|
||||
"[revision]/[type]s/[artifact](-[classifier]).[ext]"
|
||||
|
||||
assert(varPattern == expectedVarPattern.right)
|
||||
assert(varPattern == Right(expectedVarPattern))
|
||||
}
|
||||
|
||||
* - {
|
||||
|
|
@ -104,9 +102,9 @@ object IvyPatternParserTests extends TestSuite {
|
|||
"/[organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)" +
|
||||
"[revision]/[type]s/[artifact](-[classifier]).[ext]"
|
||||
|
||||
assert(varPattern0.map(_.string) == expectedVarPattern.right)
|
||||
assert(varPattern0.right.map(_.string) == Right(expectedVarPattern))
|
||||
|
||||
val varPattern = varPattern0.toOption.get
|
||||
val varPattern = varPattern0.right.toOption.get
|
||||
|
||||
* - {
|
||||
val res = varPattern.substituteVariables(Map(
|
||||
|
|
@ -117,10 +115,10 @@ object IvyPatternParserTests extends TestSuite {
|
|||
"artifact" -> "art",
|
||||
"classifier" -> "docc",
|
||||
"ext" -> "jrr"
|
||||
)).map(_.string)
|
||||
)).right.map(_.string)
|
||||
val expectedRes = "file://homez/.activator/repository/org/mod/1.1.x/jarrs/art-docc.jrr"
|
||||
|
||||
assert(res == expectedRes.right)
|
||||
assert(res == Right(expectedRes))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,30 +25,30 @@ object ParseTests extends TestSuite {
|
|||
val tests = TestSuite {
|
||||
"bintray-ivy:" - {
|
||||
val obtained = Parse.repository("bintray-ivy:scalameta/maven")
|
||||
assert(obtained.exists(isIvyRepo))
|
||||
assert(obtained.right.exists(isIvyRepo))
|
||||
}
|
||||
"bintray:" - {
|
||||
val obtained = Parse.repository("bintray:scalameta/maven")
|
||||
assert(obtained.exists(isMavenRepo))
|
||||
assert(obtained.right.exists(isMavenRepo))
|
||||
}
|
||||
|
||||
"sbt-plugin:" - {
|
||||
val res = Parse.repository("sbt-plugin:releases")
|
||||
assert(res.exists(isIvyRepo))
|
||||
assert(res.right.exists(isIvyRepo))
|
||||
}
|
||||
|
||||
"typesafe:ivy-" - {
|
||||
val res = Parse.repository("typesafe:ivy-releases")
|
||||
assert(res.exists(isIvyRepo))
|
||||
assert(res.right.exists(isIvyRepo))
|
||||
}
|
||||
"typesafe:" - {
|
||||
val res = Parse.repository("typesafe:releases")
|
||||
assert(res.exists(isMavenRepo))
|
||||
assert(res.right.exists(isMavenRepo))
|
||||
}
|
||||
|
||||
"jitpack" - {
|
||||
val res = Parse.repository("jitpack")
|
||||
assert(res.exists(isMavenRepo))
|
||||
assert(res.right.exists(isMavenRepo))
|
||||
}
|
||||
|
||||
// Module parsing tests
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package coursier
|
|||
package test
|
||||
|
||||
import utest._
|
||||
import scalaz._
|
||||
|
||||
import coursier.maven.Pom
|
||||
|
||||
|
|
@ -21,7 +20,7 @@ object PomParsingTests extends TestSuite {
|
|||
</dependency>
|
||||
"""
|
||||
|
||||
val expected = \/-(
|
||||
val expected = Right(
|
||||
"" -> Dependency(
|
||||
Module("comp", "lib"),
|
||||
"2.1",
|
||||
|
|
@ -40,7 +39,7 @@ object PomParsingTests extends TestSuite {
|
|||
</profile>
|
||||
"""
|
||||
|
||||
val expected = \/-(Profile("profile1", None, Profile.Activation(Nil), Nil, Nil, Map.empty))
|
||||
val expected = Right(Profile("profile1", None, Profile.Activation(Nil), Nil, Nil, Map.empty))
|
||||
|
||||
val result = Pom.profile(xmlParse(profileNode).right.get)
|
||||
|
||||
|
|
@ -55,7 +54,7 @@ object PomParsingTests extends TestSuite {
|
|||
</profile>
|
||||
"""
|
||||
|
||||
val expected = \/-(Profile("", Some(true), Profile.Activation(Nil), Nil, Nil, Map.empty))
|
||||
val expected = Right(Profile("", Some(true), Profile.Activation(Nil), Nil, Nil, Map.empty))
|
||||
|
||||
val result = Pom.profile(xmlParse(profileNode).right.get)
|
||||
|
||||
|
|
@ -71,7 +70,7 @@ object PomParsingTests extends TestSuite {
|
|||
</profile>
|
||||
"""
|
||||
|
||||
val expected = \/-(Profile("profile1", Some(true), Profile.Activation(Nil), Nil, Nil, Map.empty))
|
||||
val expected = Right(Profile("profile1", Some(true), Profile.Activation(Nil), Nil, Nil, Map.empty))
|
||||
|
||||
val result = Pom.profile(xmlParse(profileNode).right.get)
|
||||
|
||||
|
|
@ -88,7 +87,7 @@ object PomParsingTests extends TestSuite {
|
|||
</activation>
|
||||
</profile>
|
||||
"""
|
||||
val expected = \/-(Profile("profile1", None, Profile.Activation(List("hadoop.profile" -> None)), Nil, Nil, Map.empty))
|
||||
val expected = Right(Profile("profile1", None, Profile.Activation(List("hadoop.profile" -> None)), Nil, Nil, Map.empty))
|
||||
val result = Pom.profile(xmlParse(profileNode).right.get)
|
||||
|
||||
assert(result == expected)
|
||||
|
|
@ -106,7 +105,7 @@ object PomParsingTests extends TestSuite {
|
|||
</activation>
|
||||
</profile>
|
||||
"""
|
||||
val expected = \/-(Profile("profile1", None, Profile.Activation(List("hadoop.profile" -> Some("yes"))), Nil, Nil, Map.empty))
|
||||
val expected = Right(Profile("profile1", None, Profile.Activation(List("hadoop.profile" -> Some("yes"))), Nil, Nil, Map.empty))
|
||||
val result = Pom.profile(xmlParse(profileNode).right.get)
|
||||
|
||||
assert(result == expected)
|
||||
|
|
@ -126,7 +125,7 @@ object PomParsingTests extends TestSuite {
|
|||
</profile>
|
||||
"""
|
||||
|
||||
val expected = \/-(Profile(
|
||||
val expected = Right(Profile(
|
||||
"profile1",
|
||||
None,
|
||||
Profile.Activation(Nil),
|
||||
|
|
@ -157,7 +156,7 @@ object PomParsingTests extends TestSuite {
|
|||
</profile>
|
||||
"""
|
||||
|
||||
val expected = \/-(Profile(
|
||||
val expected = Right(Profile(
|
||||
"profile1",
|
||||
None,
|
||||
Profile.Activation(Nil),
|
||||
|
|
@ -181,7 +180,7 @@ object PomParsingTests extends TestSuite {
|
|||
</profile>
|
||||
"""
|
||||
|
||||
val expected = \/-(Profile(
|
||||
val expected = Right(Profile(
|
||||
"profile1",
|
||||
None,
|
||||
Profile.Activation(Nil),
|
||||
|
|
@ -204,7 +203,7 @@ object PomParsingTests extends TestSuite {
|
|||
</profile>
|
||||
"""
|
||||
|
||||
val expected = \/-(Profile(
|
||||
val expected = Right(Profile(
|
||||
"profile1",
|
||||
None,
|
||||
Profile.Activation(Nil),
|
||||
|
|
@ -218,7 +217,7 @@ object PomParsingTests extends TestSuite {
|
|||
assert(result == expected)
|
||||
}
|
||||
'beFineWithCommentsInProperties{
|
||||
import scalaz._, Scalaz._
|
||||
import scalaz.Scalaz.{eitherMonad, listInstance, ToTraverseOps}
|
||||
|
||||
val properties =
|
||||
"""
|
||||
|
|
@ -258,12 +257,12 @@ object PomParsingTests extends TestSuite {
|
|||
val node = parsed.right.get
|
||||
assert(node.label == "properties")
|
||||
|
||||
val children = node.children.collect{case elem if elem.isElement => elem}
|
||||
val children = node.children.collect { case elem if elem.isElement => elem }
|
||||
val props0 = children.toList.traverseU(Pom.property)
|
||||
|
||||
assert(props0.isRight)
|
||||
|
||||
val props = props0.getOrElse(???).toMap
|
||||
val props = props0.right.getOrElse(???).toMap
|
||||
|
||||
assert(props.contains("commons.release.2.desc"))
|
||||
assert(props.contains("commons.osgi.export"))
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@ package coursier
|
|||
package test
|
||||
|
||||
import coursier.core._
|
||||
import coursier.util.EitherT
|
||||
|
||||
import scala.language.higherKinds
|
||||
|
||||
import scalaz.{ Monad, EitherT }
|
||||
import scalaz.Scalaz._
|
||||
import scalaz.Monad
|
||||
|
||||
final case class TestRepository(projects: Map[(Module, String), Project]) extends Repository {
|
||||
val source = new core.Artifact.Source {
|
||||
|
|
@ -23,7 +22,9 @@ final case class TestRepository(projects: Map[(Module, String), Project]) extend
|
|||
)(implicit
|
||||
F: Monad[F]
|
||||
) =
|
||||
EitherT(F.point(
|
||||
projects.get((module, version)).map((source, _)).toRightDisjunction("Not found")
|
||||
))
|
||||
EitherT(
|
||||
F.point(
|
||||
projects.get((module, version)).map((source, _)).toRight("Not found")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
version in ThisBuild := "1.0.3-SNAPSHOT"
|
||||
version in ThisBuild := "1.1.0-SNAPSHOT"
|
||||
|
|
|
|||
Loading…
Reference in New Issue