[](https://ci.appveyor.com/project/alexarchambault/coursier)
[](https://gitter.im/alexarchambault/coursier?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Compared to the default dependency resolution of SBT, it adds:
* downloading of artifacts in parallel,
* better offline mode - one can safely work with snapshot dependencies if these are in cache (SBT tends to try to fail if it cannot check for updates),
Repositories starting with `ivy:` are assumed to be Ivy repositories, specified with an Ivy pattern, like `ivy:https://repo.typesafe.com/typesafe/ivy-releases/[organisation]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext]`.
The `bootstrap` generates tiny bootstrap launchers, able to pull their dependencies from
repositories on first launch. For example, the launcher of coursier is [generated](https://github.com/alexarchambault/coursier/blob/master/project/generate-launcher.sh) with a command like
`scalaz-core` (and only it, *not*`scalaz-concurrent` for example). It contains among others,
definitions,
mainly in [`Definitions.scala`](https://github.com/alexarchambault/coursier/blob/master/core/shared/src/main/scala/coursier/core/Definitions.scala),
[`Resolution`](https://github.com/alexarchambault/coursier/blob/master/core/shared/src/main/scala/coursier/core/Resolution.scala), representing a particular state of the resolution,
and [`ResolutionProcess`](https://github.com/alexarchambault/coursier/blob/master/core/shared/src/main/scala/coursier/core/ResolutionProcess.scala),
that expects to be given metadata, wrapped in any `Monad`, then feeds these to `Resolution`, and at the end gives
you the final `Resolution`, wrapped in the same `Monad` it was given input. This final `Resolution` has all the dependencies,
In order for the resolution to go on, we'll need things from a few repositories,
```tut
val repositories = Seq(
Cache.ivy2Local,
MavenRepository("https://repo1.maven.org/maven2")
)
```
The first one, `Cache.ivy2Local`, is defined in `coursier.Cache`, itself from the `coursier-cache` module that
we added above. As we can see, it is an `IvyRepository`, picking things under `~/.ivy2/local`. An `IvyRepository`
is related to the [Ivy](http://ant.apache.org/ivy/) build tool. This kind of repository involves a so-called [pattern](http://ant.apache.org/ivy/history/2.4.0/concept.html#patterns), with
various properties. These are not of very common use in Scala, although SBT uses them a bit.
The second repository in a `MavenRepository`. These are simpler than the Ivy repositories. They're the ones
we're the most used to in Scala. Common ones like [Central](https://repo1.maven.org/maven2) like here, or the repositories
from [Sonatype](https://oss.sonatype.org/content/repositories/), are Maven repositories. These originate
from the [Maven](https://maven.apache.org/) build tool. Unlike the Ivy repositories which involve customisable patterns to point
to the underlying metadata and artifacts, the paths of these for Maven repositories all look alike,
like for any particular version of the standard library, under paths like
that drives the resolution. It is loosely inspired by the `Process` of scalaz-stream.
It is an immutable structure, that represents the various states the resolution process can be in.
Its method `current` gives the current `Resolution`. Calling `isDone` on the latter says whether the
resolution is done or not.
The `next` method, that expects a `fetch` method like the one above, gives
the "next" state of the resolution process, wrapped in the monad of the `fetch` method. It allows to do
one resolution step.
Lastly, the `run` method runs the whole resolution until its end. It expects a `fetch` method too,
and will make at most `maxIterations` steps (50 by default), and return the "final" resolution state,
wrapped in the monad of `fetch`. One should check that the `Resolution` it returns is done (`isDone`) -
the contrary means that `maxIterations` were reached, likely signaling an issue, unless the underlying
resolution is particularly complex, in which case `maxIterations` could be increased.
Let's run the whole resolution,
```tut:silent
val resolution = start.process.run(fetch).run
```
To get additional feedback during the resolution, we can give the `Cache.default` method above
a [`Cache.Logger`](https://github.com/alexarchambault/coursier/blob/cf269c6895e19f2d590f08811406724304332950/cache/src/main/scala/coursier/Cache.scala#L484-L490).
By default, downloads happen in a global fixed thread pool (with 6 threads, allowing for 6 parallel downloads), but
you can supply your own thread pool to `Cache.default`.
Now that the resolution is done, we can check for errors in
```tut:silent
val errors: Seq[(Dependency, Seq[String])] = resolution.errors
```
These would mean that the resolution wasn't able to get metadata about some dependencies.
We can also check for version conflicts, in
```tut:silent
val conflicts: Set[Dependency] = resolution.conflicts
```
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(
resolution.artifacts.map(Cache.file(_).run)
).run
```
We're using the `Cache.file` method, that can also be given a `Logger` (for more feedback) and a custom thread pool.
### Scala JS demo
*coursier* is also compiled to Scala JS, and can be tested in the browser via its
#### Inter-project repository in the SBT plugin is a bit naive
The inter-project repository is the pseudo-repository, nesting the metadata
of sub-projects. It gets confused in at least these two cases:
- two sub-projects have the same organization and module name,
- a sub-project depends on a released version of another sub-project, possibly transitively.
The problem with it is that it doesn't look at the real sub-projects graph. It
just trusts SBT to put dependencies between projects in the library
dependencies.
So if a link appears transitively, with a sub-project depending on
a released version of a sub-project (second point above), the coursier SBT plugin will
think there's a dependency between the sub-projects. Thus it will trust
SBT to put the second project build products on the classpath.
But SBT knows there's no such link, so it just doesn't put them.
The second point happens for the `readme` sub-project of Ammonite, for example,
which transitively depends on a released version of `ammonite-ops`, itself also
built by the `ops` sub-project.
#### Ivy support is poorly tested
The minimum was made for SBT plugins to be resolved fine (including dependencies
between plugins, the possibility that some of them come from Maven repositories,
with a pecularities, classifiers - sources, javadoc - should be fine too).
So it is likely that projects relying more heavily
on Ivy features could run into the limitations of the current implementation.
Any issue report related to that, illustrated with public Ivy repositories
if possible, would be greatly appreciated.
#### *Important*: SBT plugin might mess with published artifacts
SBT seems to require the `update` command to generate a few metadata files
later used by `publish`. If ever there's an issue with these, this might
add discrepencies in the artifacts published with `publish` or `publishLocal`.
Should you want to use the coursier SBT plugin while publishing artifacts at the
same time, I'd recommend an extreme caution at first, like manually inspecting
the metadata files and compare with previous ones, to ensure everything's fine.
coursier publishes its artifacts with its own plugin enabled since version
`1.0.0-M2` though, without any apparent problem.
#### No wait on locked file
If ever resolution or artifact downloading stumbles upon a locked metadata or
artifact in the cache, it will just fail, instead of waiting for the lock to be freed.
#### Also
Plus the inherent amount of bugs arising in a young project :-)
## Roadmap
The first releases were milestones like `0.1.0-M?`. As a launcher, basic Ivy
repositories support, and an SBT plugin, were added in the mean time,
coursier is now aiming directly at `1.0.0`.
The last features I'd like to add until a feature freeze are mainly a
better / nicer output, for both the command-line tools and the SBT plugin.
These are tracked via Github [issues](https://github.com/alexarchambault/coursier/issues?q=is%3Aopen+is%3Aissue+milestone%3A1.0.0), along with other points.
Milestones will keep being released until then.
Then coursier should undergo `RC` releases, with no new features added, and
only fixes and minor refactorings between them.
Once RCs will be considered stable enough, `1.0.0` should be released.