[#dependencies]
== Project dependencies

Eldev picks up project dependencies from package declaration,
i.e. usually from `Package-Requires` header in the project’s main
`.el` file.  If you have several files with package headers in the the
root directory, you need to set variable `eldev-project-main-file`,
else function `package-dir-info` can pick a wrong one.  In any case,
you don’t need to declare these dependencies second time in `Eldev`
and keep track that they remain in sync.

However, you do need to tell Eldev how to _find_ these dependencies.
There are three ways of locating packages: <<package-archives,using
Elisp package archives>>, <<vc-repositories,using VC (Git)
repositories>> and <<local-sources,on your local file system>>.

[#package-archives]
=== From Elisp package archives

By default Eldev doesn’t use any package archives.  To instruct it to
use an archive to locate packages, call function
`eldev-use-package-archive` in file `Eldev` (you have such forms
already in place if you have used `eldev init`).  For example:

[source]
----
(eldev-use-package-archive 'melpa)
----

Eldev knows about three “standard” archives, which should cover most
of your needs: `gnu-elpa`, `nongnu-elpa` and `melpa`.

You can also explicitly choose stable (a.k.a. release: `gnu`, `nongnu`
and `melpa-stable`) or unstable (a.k.a. snapshot or development:
`gnu-devel`, `nongnu-devel` and `melpa-unstable`) variants instead.
There are some naming inconsistencies here, because for GNU and NonGNU
only the stable variants had been added at first (`nongnu` only in
0.10), nonstable (development) were added later, in 1.1.

{since-0-5} A better way is provided by two global options: `--stable`
(the default) and `--unstable`.  Normally, Eldev will try to install
everything from stable archive variants (you wouldn’t want your tests
fail only because a dependency in an unstable version has a bug).
However, if a package is not available (at all or in the required
version) from the stable archive, unstable will be used automatically.
If you specify `--unstable` on the command line, Eldev will behave in
the opposite way: prefer the unstable archive and use the stable only
as a fallback.

Emacs 25 and up supports package archive priorities.  Eldev backports
this to Emacs 24 and utilizes the feature to assign the standard
archives it knows about priorities 300/190 (GNU ELPA, stable/unstable
variants), 250/150 (NonGNU ELPA), and 200/100 (MELPA).  A dependency
from a package with a lower priority is installed only if there are no
other options.

If dependencies for your project are only available from some other
archive, you can still use the same function.  Just substite the
symbolic archive name with a cons cell of name and URL as strings:

[source]
----
(eldev-use-package-archive '("myarchive" . "http://my.archive.com/packages/"))
----

You don’t need to perform any additional steps to have Eldev actually
install the dependencies: any command that needs them will make sure
they are installed first.  However, if you want to check if package
archives have been specified correctly and all dependencies can be
looked up without problems, you can explicitly use command `prepare`.

[#vc-repositories]
=== From VC (Git) repositories

{since-1-11} If a package you depend on isn’t available from a package
archive (e.g. MELPA), this is still not a problem as long as there is
a Git repository for it.  Simply add to file `Eldev` a form like this:

[source]
----
(eldev-use-vc-repository 'dep-name :git "FULL-URL")
----

If the package is available on GitHub, you can avoid specifying the
full URL by using the shortened form:

[source]
----
(eldev-use-vc-repository 'dep-name :github "USER/REPOSITORY")
----

Now, whenever a package called `dep-name` is needed, Eldev will first
fetch given Git repository, build an Elisp package from it and provide
it to the standard Emacs package manager for use.

Like <<package-archives,with package archives>>, function
`eldev-use-vc-repository` itself doesn’t describe _how_ you intend to
use given package.  It merely tells Eldev where to find it.  Only if
the package is listed as a <<dependencies,regular dependency>> of your
project or you register it as <<additional-dependencies,an additional
dependency>>, will the repository actually get fetched.

If the project fetched from a repository doesn’t use Eldev itself, the
tool might have problems building a package from it.  In this case you
can pass a <<setup-procedure,setup form>> to it:

[source]
----
(eldev-use-vc-repository ... :setup FORM)
----

This form will be given to child Eldev processes whenever a package
needs to be created out of the VC-fetched project.  Most likely you
will need to tell child Eldev how to locate dependencies of _that_
project.  The best way to figure it out is to check out the repository
and create file `Eldev` in it with required contents
(<<initializing,`eldev init`>> might help).  Instead of committing the
created file, convert its contents into an Elisp form (use `progn` if
needed) and pass it as a value of `:setup` in your _main_ project.

By default, Eldev will check out the repository at the latest stable
tagged release.  If there are none, however, it will just use the HEAD
commit.  Eldev respects the options `--stable`/`--unstable` described
in the previous section also for VC repositories.  For example, the
latter makes it ignore the releases and always use the latest commit.
Finally, if you _always_ want to build from a specific commit, e.g. to
make build process more stable, you can pass optional argument
`:commit` to `eldev-use-vc-repository`.  Its value must be a string:
either a tag name or a _full_ (not shortened) Git commit hash.

[#local-sources]
=== From your file system (local sources)

Imagine you are developing more than one project at once and they
depend on each other.  You’d typically want to test the changes you
make in one of them from another right away.  If you are familiar with
Cask, this is solved by linking projects in it.

Eldev provides a more flexible approach to this problem called _local
sources_.  Let’s assume you develop project `foo` in directory `~/foo`
and also a library called `barlib` in `~/barlib`.  And `foo` uses the
library.  To have Eldev use your local copy of `barlib` instead of
downloading it e.g. from MELPA, add the following form in file
`~/foo/Eldev-local`:

[source]
----
(eldev-use-local-sources "~/barlib")
----

NOTE: Before 1.11 the function was named `eldev-use-local-dependency`.
This name is still available for backward compatibility.

Note that the form _must not_ be added to `Eldev`: other developers
who check out your project probably don’t even have a local copy of
`barlib` or maybe have it in some other place.  In other words, this
should really remain your own private setting and go to `Eldev-local`.

Local sources have _loading modes_, just as the project’s package
itself.  Those will be discussed <<loading-modes,later>>.

Eldev correctly handles situations with adding, removing or otherwise
changing local source definitions.  I.e. by simply commenting out or
uncommenting `eldev-use-local-sources` call, you can quickly test your
project both with a MELPA-provided package and with local (and
presumably just changed) copy of its dependency sources — Eldev will
adapt without any additional work from you.

[#additional-dependencies]
=== Additional dependencies

It is possible to register additional dependencies for use only by
certain Eldev commands.  Perhaps the most useful is to make certain
packages available for testing purposes.  For example, if your project
doesn’t depend on package `foo` on its own, but your test files do,
add the following form to `Eldev` file:

[source]
----
(eldev-add-extra-dependencies 'test 'foo)
----

Additional dependencies are looked up in the same way as normal ones.
So, you need to make sure that all of them are available from the
package archives you instructed Eldev to use.

The following commands make use of additional dependencies: `build`,
`emacs`, `eval`, `exec` and `test`.  Commands you define yourself can
also take advantage of this mechanism, see function
`eldev-load-project-dependencies`.

[#extended-dependency-format]
==== Extended dependency format

{since-0-2} Normally to specify an additional dependency you just need
to provide its package name as a symbol.  However, Eldev also supports
“extended” format, that lets you specify other details.  In this
format, dependency is specified as a property list (plist):

[source]
----
(:package  DEPENDENCY-NAME
 :version  REQUIRED-VERSION
 :archive  PACKAGE-ARCHIVE
 :archives (PACKAGE-ARCHIVE...)
 :optional OPTIONAL)
----

All keywords except `:package` can be omitted.  In the extended format
you can specify which version of the dependency is required (normally,
any version will do) and which package archive(s) to use (by default,
the same archives as for normal dependencies are used).  In values
associated with `:archive`/`:archives` standard shortcuts `gnu` (for
GNU ELPA) and `melpa` (for MELPA; also `melpa-stable` and
`melpa-unstable`) can be used.  Dependencies can also be marked as
optional, see the next subsection.

{since-0-9} There is also a special format for referring to certain
tools like <<buttercup,Buttercup>>: `(:tool TOOL-NAME)`.  For details,
refer to section <<development-tool-sources,Development tool
sources>>.

==== Optional additional dependencies

{since-0-9} Suppose you want to test your project’s integration with a
third-party package, but don’t strictly _need_ it.  And, additionally,
relevant tests are written in such a way as to simply be skipped if
said package is not available, e.g. using `ert-skip` or
`buttercup-skip`.  In this case you may want to declare the package as
an _optional additional dependency_, so that you don't need to care if
it can be installed during continuous integration or not:

[source]
----
(eldev-add-extra-dependencies 'test '(:package helm :optional t))
----

In this example, we declare that we want Helm for testing, but don't
care much if it cannot be installed, e.g. because of too old Emacs
version.

=== Examining dependencies

Sometimes it is useful to check what a project depends on, especially
if it is not your project, just something you have checked out.  There
are two commands for this in Eldev.

First is `dependencies` (can be shortened to `deps`).  It lists
_direct_ dependencies of the project being built.  By default, it
omits any built-in packages, most importantly `emacs`.  If you want to
check those too, add option `-b` (`--list-built-ins`).

Second is `dependecy-tree` (short alias: `dtree`).  It prints a tree
of project direct dependencies, direct dependencies of those, and so
on — recursively.  Like with the first command, use option `-b` if you
want to see built-ins in the tree.

Both commands can also list additional dependencies if instructed:
just specify set name(s) on the command line, e.g.:

    $ eldev dependencies test

You can also check which archives Eldev uses to look up dependencies
for this particular project with the following command:

    $ eldev archives

=== Upgrading dependencies

Eldev will install project dependencies automatically, but it will
never upgrade them, at least if you don’t change your project to
require a newer version.  However, you can always explicitly ask Eldev
to upgrade the installed dependencies:

    $ eldev upgrade

First, package archive contents will be refetched, so that Eldev knows
about newly available versions.  Next, this command upgrades (or
installs, if necessary) all project dependencies and all additional
dependencies you might have registered (see
<<additional-dependencies,above>>).  If you don’t want to upgrade
everything, you can explicitly list names of the packages that should
be upgraded:

    $ eldev upgrade dash ht

You can also check what Eldev would upgrade without actually upgrading
anything:

    $ eldev upgrade --dry-run

{since-0-5} If you use MELPA for looking up dependencies, you can
switch between Stable and Unstable using global options with the same
name, i.e.:

    $ eldev --unstable upgrade

Because of the incompatible version numbers that MELPA Unstable
supplies, you cannot directly “upgrade” from an unstable version back
to a stable one.  But you can specify option `-d` (`--downgrade`) to
the command:

    $ eldev --stable upgrade -d

In this case Eldev will downgrade dependencies if this allows it to
use more preferable package archive.  (Since `--stable` is the
default, specifying it in the command above is not really needed, it’s
only mentioned for clarity.)

To install unstable version of only a specific dependency, while
leaving all others at stable versions, combine `--unstable` with
listing package names after the command, e.g.:

    $ eldev --unstable upgrade dash

==== Upgrading development tools

{since-0-6} Command `upgrade` works not only with package
dependencies, but also with common development tools used by the
project during development, for example <<buttercup,Buttercup>> or
<<linting,various linters>>.  This works exactly the same as for
project dependencies, with the only exception that the tool must be
installed first.  E.g., for Buttercup you need to <<testing,test>>
your project at least once, so that Eldev knows about the need for
this tool.

Development tools are installed from package archives hardcoded inside
Eldev (but see <<development-tool-sources,the next section>>),
regardless of which archives you have configured for your project.
For example, even if you use `melpa-unstable` archive, Buttercup will
still be installed from MELPA Stable (unless, of course, you use
`--unstable` global option).  If you need, you can switch to unstable
version of the tool later:

    $ eldev --unstable upgrade buttercup

[#development-tool-sources]
=== Development tool sources

Eldev knows how to install certain development tools and also uses
predefined package archives for this, not the ones you specify in
project’s configuration.  This means you don’t need to list archives
for tools like <<buttercup,Buttercup>>: only list them if they are
needed to look up real dependencies.

{since-0-9} There is a simple way to customize where exactly Eldev
finds the tools: use variable `eldev-known-tool-packages` for this.
The value of the variable is an alist keyed by tool names and
containing <<extended-dependency-format,package descriptor plists>> as
values.  By default it already contains information about the tools
Eldev knows about.  You can add more or replace existing ones if you
need: just `push` more entries at the beginning of the list, there is
no need to actually remove anything.

You can also use the tools as e.g. runtime dependencies if needed
(though in most cases you should leave this to Eldev).  Just specify
package plist as `(:tool TOOL-NAME)` for this.  Both tools with
built-in support and any new you add to `eldev-known-tool-packages`
can be referred this way.

Current list of the known tools:

* `buttercup`
* `ecukes`
* `package-lint`
* `relint`
* `elisp-lint`
* `undercover`

[#disabling-dependencies]
=== Disabling dependency management

CAUTION: This operation mode is *not recommended*.  It exists only to
support special usecases that “insist” on setting Emacs’ `load-path`
directly and cannot be customized (with reasonable effort).

{since-1-9} Eldev has limited support for operating _without
dependency management_.  This mode can be activated using global
option `--disable-dependencies` (there is no short version to
emphasize that _it is not recommended_).  It exists to support certain
environments that themselves provide a suitable value for Emacs
variable `load-path` via environment variable `EMACSLOADPATH`.  An
example of such an environment is {uri-guix}[GUIX] package building.

Unlike in <<preinstalled-dependencies,preinstalled-dependency mode>>
described earlier, here Eldev doesn’t work with dependencies (and
<<development-tool-sources,tools>>) as standard Emacs packages at all.
Instead, everything is expected to be loadable using `require` form
without any further setup.  For this, variable `load-path` must be set
appropriately, most likely using `EMACSLOADPATH` (though you could, in
principle, set its value in e.g. `Eldev-local`).

One consequence of this mode is that Emacs package system won’t
consider dependency packages installed at all, see
`package-installed-p`.  <<autoloads,Autoloads>> are not supported in
this mode (neither for dependencies nor for the project itself), so
you must explicitly require all features before using them.  There
might be other, unexpected, limitations as well, as this mode is not
thoroughly tested.

Unless you need to build packages for GUIX or have some comparable
environment that computes `load-path` on its own and doesn’t let Eldev
manage dependencies normally by accessing standard package archives,
you shouldn’t use this mode.

[#global-cache]
=== Global package archive cache

{since-0-4} To avoid downloading the same packages repeatedly, Eldev
employs a package archive cache.  This cache is shared between all
projects and <<different-emacs-versions,all Emacs versions>> on your
machine.  It can significantly speed up package preparation if you use
a new project, test it on another Emacs version or delete
project-specific cache (subdirectory `.eldev`) for whatever reason.

By default, downloaded packages stay cached indefinitely, while
archive contents expires in one hour.  However, if you use command
`upgrade` or `upgrade-self`, package archive contents is always
refreshed.

Cache usage is not controllable from command line.  However, you can
customize it somewhat in `~/.config/eldev/config`.  Variable
`eldev-enable-global-package-archive-cache` lets you disable the
global cache outright.  Using
`eldev-global-cache-archive-contents-max-age` you can adjust how long
cached copies of `archive-contents` stay valid.
