This document contains documentation for wit
developers.`
Requirements for linting and type checking can be installed with pip3
:
$ pip3 install -r requirements.txt
You can run all tests with the included Makefile:
$ make test-all
The regression tests for wit are in the t/
directory. Each test is a bash script ending with .t
as the filename extension. You can run individual tests:
$ ./t/wit_init.t
You can also run all of the regression tests via the Makefile:
$ make test-regress
By default, the regression tests use the wit
executable in the base directory of this repository. This can be overwritten by setting the WIT
environment variable to point to either the directory containing the wit
executable, or setting it to the wit
executable itself.
For example, if you wish to test whatever wit
is on your PATH
, you can type:
$ WIT=`which wit` make test-regress
Alternatively, you can point to a wit
installation:
$ WIT=/path/to/wit/installation make test-regress
Note that this only affects test-regress
, linting and type checking are run on the repository itself.
This projects uses Flake8 for linting. The rules are in .flake8
and linting can be run with:
$ make test-lint
We also use mypy for (limited) static type checking. The rules are specified in mypy.ini
and can be run with:
$ make test-typecheck
Much of wit
terminology is derived directly from git
, upon which wit
relies.
package: A git repository that is incorporated into a wit
workspace, either explicitly by being added to the workspace by the workspace owner, or implicitly by being included from aanother package.
workspace: A workspace is a work area that contains zero or more packages, along with meta-data about those packages.
These files are generated and maintained by wit
. Wit uses json for its meta-data. Note that the purpose and thus the format of these files are all very similar; they explicitly identify packages.
wit-workspace.json
: This file lists the packages explicitly added to the workspace, along with their specific git hash.
[
{
"commit": "d575fab969bee591e115f6e5f836b4bbc810883f",
"name": "chisel3-wake",
"source": "git@github.com:sifive/chisel3-wake.git"
}
]
wit-manifest.json
: Packages specify their dependencies in the wit-manifest.json
file. These packages are implicitly added to the workspace during wit
's resolution phase.
[
{
"commit": "2272044c6ab46b5148c39c124e66e1a8e9073a24",
"name": "firrtl",
"source": "git@github.com:freechipsproject/firrtl.git"
}
]
wit-lock.json
: When wit traverses the packages in your workspace its resolution algorithm deterministically generates a list of explicit and implicit packages along with git hashes. wit-lock.json
contains this list, which is a full specification of your workspace's state.
{
"firrtl": {
"commit": "2272044c6ab46b5148c39c124e66e1a8e9073a24",
"name": "firrtl",
"source": "git@github.com:freechipsproject/firrtl.git"
},
...
}
Wit's purpose is to assist development by deterministically generating a workspace of packages that ensures all dependencies are met. Its algorithm is straightforward:
- Initialize an empty repo -> package map (
MAP
). - Create a queue of all packages present in the
wit-workspace.json
file ordered by commit time. Remember, a package is a specific commit of a git repo. - Pop the package (
P
) with the youngest (newest) commit time. Determine the source repo (R
). - If
R
has already been seen and the package (P'
) specified inMAP[R]
is not a descendent ofP
(i.e.P
's commit is not present inP'
's history) then fail. - If
R
has already been seen andP'
is a descendent ofP
then go to step 2 - If
R
has not been seen then setMAP[R]
toP
. - Determine
P
'swit
dependencies fromP/wit-manifest.json
. Append these to the ordered list from step 2 based on commit time. - Go to step 3.
Wit has three main responsibilities:
- Generate a reproducible dependency tree from a
wit-workspace.json
- Deduplicate packages in that dependency tree into a flat list of packages
- Make the workspace filesystem match the aforementioned flat list of packages as close as possible without overwriting the users' uncommitted changes
As of 5670099b
, Wit is increasingly built with assumption that we might encounter problems while fulfilling Responsibilities 1 & 2.
Responsibilities 1 & 2 are fulfilled by the same algorithm in Wit to reduce unnecessary cloning of Git repos.
In Wit, the process of exploring & deduplicating packages is called "package resolution."
The following objects are used to store data:
Dependency
: what's requested by thewit-workspace.json
andwit-manifest.json
filesPackage
: the outcome of deduplicating a list ofDependency
objects with the sameGitRepo
: the repo on disk used to analyzePackage
andDependency
objects
During package resolution, Wit does the following:
- Explore
wit-workspace.json
andwit-manifest.json
files, generatingDependency
objects - Bind each
Dependency
object toPackage
object of the same name. AllDependency
objects of the same name should point to the same Package object. - Bind that
Package
object toGitRepo
on disk, used to find the commit times and git ancestry of each Dependency - Use the
GitRepo
to find the commit time of each Dependency - Add the
Dependency
objects to the queue in tuples of (Dependency, commit time). - Pop the
Dependency
with the newest commit time from the queue - The newest
Dependency
out of all of theDependency
objects of the same name is the one we want to cloned to disk. Therefore, theDependency
we just popped is the "winner" of the deduplication algorithm - So far, the
Package
object was used to groupDependency
objects of the same name together. Now that we know whichDependency
is the winner, we can populate thesource
andrevision
fields of thePackage
. - Does the popped
Package
object have awit-manifest.json
?- Yes: Skip to Step 1, using its
wit-manifest.json
- No: Are there more items in the queue?
- Yes: Skip to step 6
- No: Package resolution complete!
- Yes: Skip to Step 1, using its
add-pkg
add-dep
update-pkg
update-dep
status
: compareresolve(workspace.json)
to the filetreeresolve()
inspect
: analyze the output ofresolve(lock.json)
update
: update filetree to match the model ofresolve(workspace.json)