Building Software with Dependencies not in Builder

It is possible to build Habitat packages locally, using dependencies that are not present in Builder; perhaps you’re experimenting with some private packages, or with local changes that aren’t yet pushed up to Builder. While this is doable, it takes a little extra work currently.

When you declare dependencies in a Habitat plan, the most common practice is to specify just the origin and package name, like core/ruby. When Habitat goes to build your package, it consults Builder to determine the latest fully-qualified identifier for the dependency you’ve specified, like core/ruby/2.4.3/20180310000655. Once Habitat has that information, it can begin the download process.

If Habitat sees that you already have core/ruby/2.4.3/20180310000655 installed (i.e., /hab/pkgs/core/ruby/2.4.3/20180310000655 exists) or, failing that, you have the corresponding artifact in your cache (i.e., /hab/cache/artifacts/core-ruby-2.4.3-20180310000655-x86_64-linux.hart exists), then it will not attempt to pull anything from Builder; after all, you already have it! If the artifact is neither installed nor cached, though, Habitat will download it from Builder.

Thus, in the usual case, Habitat will make up to two requests to Builder for each dependency; one to resolve the exact release it should download, and one to actually download that release.

Given this, we can effectively short-circuit all Builder interactions for a given dependency by placing a fully-qualified release in your plan’s dependencies, and having the corresponding artifact already present in your artifact cache.

Thus, to “trick” Habitat into using packages that aren’t yet in Builder, you should do two things:

  • First, specify the fully-qualified identifier for each package you want to use that is not in Builder.
  • Second, place the corresponding *.hart file in your artifact cache for the build program to find.

An alternative you could try is to set the NO_INSTALL_DEPS environment variable in your studio. This stops all Builder interactions for the entire build, and thus assumes that all dependencies are already available locally. Habitat will use the most recent artifact that satisfies the given dependency identifier; if your artifact happens to be the most recent one, then it will be used. Note, however, that this is a coarser solution than the one given above, since it will apply to every dependency; please use care if you use this approach. This environment variable is intended for shortening the local development cycle on a package, and also comes in handy if you’re on an airplane.

If this is a pattern you find yourself reaching for frequently, you may want to follow, which tracks work on an “offline” mode of building.