summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZubin Duggal <zubin.duggal@gmail.com>2021-12-13 18:02:24 +0530
committerMarge Bot <ben+marge-bot@smart-cactus.org>2022-01-11 19:37:45 -0500
commita8fb4251cd4b12c792b0f94979b584364d80b434 (patch)
tree2c9cec1dd481d042454e04aa72e006603f4c7e03
parent2b6c217925a39624f425758ca680887b01db8efd (diff)
downloadhaskell-a8fb4251cd4b12c792b0f94979b584364d80b434.tar.gz
hadrian: allow offline bootstrapping
This patch adds the ability to fetch and store dependencies needed for boostrapping hadrian. By default the script will download the dependencies from the network but some package managers disallow network access so there are also options to build given a supplied tarball. The -s option allos you to provide the tarball bootstrap.py -d plan-bootstrap-8.10.5.json -w /path/to-ghc -s sources-tarball.tar.gz Which dependencies you need can be queried using the `list-sources` option. bootstrap.py list-sources -d plan-bootstrap-8.10.5.json This produces `fetch_plan.json` which tells you where to get each source from. You can instruct the script to create the tarball using the `fetch` option. bootstrap.py fetch -d plan-bootstrap-8.10.5.json -o sources-tarball.tar.gz Together these commands mean you can build GHC without needing cabal-install. Fixes #17103
-rw-r--r--hadrian/Setup.hs3
-rw-r--r--hadrian/bootstrap/README.md17
-rwxr-xr-xhadrian/bootstrap/bootstrap.py234
-rw-r--r--hadrian/bootstrap/plan-8_10_7.json1
-rw-r--r--hadrian/bootstrap/plan-bootstrap-8_10_7.json1
5 files changed, 192 insertions, 64 deletions
diff --git a/hadrian/Setup.hs b/hadrian/Setup.hs
new file mode 100644
index 0000000000..200a2e51d0
--- /dev/null
+++ b/hadrian/Setup.hs
@@ -0,0 +1,3 @@
+import Distribution.Simple
+main = defaultMain
+
diff --git a/hadrian/bootstrap/README.md b/hadrian/bootstrap/README.md
index c82ace0669..b20534dfe0 100644
--- a/hadrian/bootstrap/README.md
+++ b/hadrian/bootstrap/README.md
@@ -11,9 +11,26 @@ If you want to bootstrap with ghc-8.10.5 then run the ./bootstrap script with th
bootstrap.py -d plan-bootstrap-8.10.5.json -w /path/to-ghc
+This default option will download the dependencies using the network.
+
The result of the bootstrap script will be a hadrian binary in
`_build/bin/hadrian`.
+Alternatively, you can provide a tarball with the source of any dependencies.
+
+ bootstrap.py -d plan-bootstrap-8.10.5.json -w /path/to-ghc -s sources-tarball.tar.gz
+
+Which dependencies you need can be queried using the `list-sources` option.
+
+ bootstrap.py list-sources -d plan-bootstrap-8.10.5.json
+
+This produces `fetch_plan.json` which tells you where to get each source from.
+You can instruct the script to create the tarball using the `fetch` option.
+
+ bootstrap.py fetch -d plan-bootstrap-8.10.5.json -o sources-tarball.tar.gz
+
+## Generating the bootstrap plans
+
There is a script (using nix) which can be used to generate the bootstrap plans for the range
of supported GHC versions using nix.
diff --git a/hadrian/bootstrap/bootstrap.py b/hadrian/bootstrap/bootstrap.py
index 8ed4d5588c..d5580ab484 100755
--- a/hadrian/bootstrap/bootstrap.py
+++ b/hadrian/bootstrap/bootstrap.py
@@ -21,6 +21,8 @@ from pathlib import Path
import platform
import shutil
import subprocess
+import tempfile
+import sys
from textwrap import dedent
from typing import Set, Optional, Dict, List, Tuple, \
NewType, BinaryIO, NamedTuple, TypeVar
@@ -31,7 +33,7 @@ BUILDDIR = Path('_build')
BINDIR = BUILDDIR / 'bin' # binaries go there (--bindir)
DISTDIR = BUILDDIR / 'dists' # --builddir
-UNPACKED = BUILDDIR / 'unpacked' # where we unpack tarballs
+UNPACKED = BUILDDIR / 'unpacked' # where we unpack final package tarballs
TARBALLS = BUILDDIR / 'tarballs' # where we download tarballks
PSEUDOSTORE = BUILDDIR / 'pseudostore' # where we install packages
ARTIFACTS = BUILDDIR / 'artifacts' # Where we put the archive
@@ -46,6 +48,8 @@ class PackageSource(Enum):
HACKAGE = 'hackage'
LOCAL = 'local'
+url = str
+
BuiltinDep = NamedTuple('BuiltinDep', [
('package', PackageName),
('version', Version),
@@ -68,10 +72,18 @@ BootstrapInfo = NamedTuple('BootstrapInfo', [
('dependencies', List[BootstrapDep]),
])
+FetchInfo = NamedTuple('FetchInfo', [
+ ('url', url),
+ ('sha256', SHA256Hash)
+])
+
+FetchPlan = Dict[Path, FetchInfo]
+
class Compiler:
def __init__(self, ghc_path: Path):
if not ghc_path.is_file():
- raise TypeError(f'GHC {ghc_path} is not a file')
+ print(f'GHC {ghc_path} is not a file')
+ sys.exit(1)
self.ghc_path = ghc_path.resolve()
@@ -111,40 +123,11 @@ def package_cabal_url(package: PackageName, version: Version, revision: int) ->
return f'http://hackage.haskell.org/package/{package}-{version}/revision/{revision}.cabal'
def verify_sha256(expected_hash: SHA256Hash, f: Path):
+ print(f"Verifying {f}...")
h = hash_file(hashlib.sha256(), f.open('rb'))
if h != expected_hash:
raise BadTarball(f, expected_hash, h)
-def fetch_package(package: PackageName,
- version: Version,
- src_sha256: SHA256Hash,
- revision: Optional[int],
- cabal_sha256: Optional[SHA256Hash],
- ) -> (Path, Path):
- import urllib.request
-
- # Download source distribution
- tarball = TARBALLS / f'{package}-{version}.tar.gz'
- if not tarball.exists():
- print(f'Fetching {package}-{version}...')
- tarball.parent.mkdir(parents=True, exist_ok=True)
- url = package_url(package, version)
- with urllib.request.urlopen(url) as resp:
- shutil.copyfileobj(resp, tarball.open('wb'))
-
- verify_sha256(src_sha256, tarball)
-
- # Download revised cabal file
- cabal_file = TARBALLS / f'{package}.cabal'
- if revision is not None and not cabal_file.exists():
- assert cabal_sha256 is not None
- url = package_cabal_url(package, version, revision)
- with urllib.request.urlopen(url) as resp:
- shutil.copyfileobj(resp, cabal_file.open('wb'))
- verify_sha256(cabal_sha256, cabal_file)
-
- return (tarball, cabal_file)
-
def read_bootstrap_info(path: Path) -> BootstrapInfo:
obj = json.load(path.open())
@@ -166,15 +149,18 @@ def check_builtin(dep: BuiltinDep, ghc: Compiler) -> None:
print(f'Using {dep.package}-{dep.version} from GHC...')
return
-def install_dep(dep: BootstrapDep, ghc: Compiler) -> None:
- dist_dir = (DISTDIR / f'{dep.package}-{dep.version}').resolve()
-
+def resolve_dep(dep : BootstrapDep) -> Path:
if dep.source == PackageSource.HACKAGE:
- assert dep.src_sha256 is not None
- (tarball, cabal_file) = fetch_package(dep.package, dep.version, dep.src_sha256,
- dep.revision, dep.cabal_sha256)
+
+ tarball = TARBALLS / f'{dep.package}-{dep.version}.tar.gz'
+ verify_sha256(dep.src_sha256, tarball)
+
+ cabal_file = TARBALLS / f'{dep.package}.cabal'
+ verify_sha256(dep.cabal_sha256, cabal_file)
+
UNPACKED.mkdir(parents=True, exist_ok=True)
shutil.unpack_archive(tarball.resolve(), UNPACKED, 'gztar')
+
sdist_dir = UNPACKED / f'{dep.package}-{dep.version}'
# Update cabal file with revision
@@ -183,9 +169,16 @@ def install_dep(dep: BootstrapDep, ghc: Compiler) -> None:
elif dep.source == PackageSource.LOCAL:
if dep.package == 'hadrian':
- sdist_dir = Path('../').resolve()
+ sdist_dir = Path(sys.path[0]).parent.resolve()
else:
raise ValueError(f'Unknown local package {dep.package}')
+ return sdist_dir
+
+
+def install_dep(dep: BootstrapDep, ghc: Compiler) -> None:
+ dist_dir = (DISTDIR / f'{dep.package}-{dep.version}').resolve()
+
+ sdist_dir = resolve_dep(dep)
install_sdist(dist_dir, sdist_dir, ghc, dep.flags)
@@ -298,7 +291,6 @@ def archive_name(version):
return f'hadrian-{version}-{machine}-{version}'
def make_archive(hadrian_path):
- import tempfile
print(f'Creating distribution tarball')
@@ -324,28 +316,88 @@ def make_archive(hadrian_path):
return archivename
+def fetch_from_plan(plan : FetchPlan, output_dir : Path):
+ import urllib.request
+
+ output_dir.resolve()
+ output_dir.mkdir(parents=True, exist_ok=True)
+
+ for path in plan:
+ output_path = output_dir / path
+ url = plan[path].url
+ sha = plan[path].sha256
+ if not output_path.exists():
+ print(f'Fetching {url}...')
+ with urllib.request.urlopen(url) as resp:
+ shutil.copyfileobj(resp, output_path.open('wb'))
+ verify_sha256(sha, output_path)
+
+def gen_fetch_plan(info : BootstrapInfo) -> FetchPlan :
+ sources_dict = {}
+ for dep in info.dependencies:
+ if dep.package != 'hadrian':
+ sources_dict[f"{dep.package}-{dep.version}.tar.gz"] = FetchInfo(package_url(dep.package, dep.version), dep.src_sha256)
+ if dep.revision is not None:
+ sources_dict[f"{dep.package}.cabal"] = FetchInfo(package_cabal_url(dep.package, dep.version, dep.revision), dep.cabal_sha256)
+ return sources_dict
+
+def find_ghc(compiler) -> Compiler:
+ # Find compiler
+ if compiler is None:
+ path = shutil.which('ghc')
+ if path is None:
+ raise ValueError("Couldn't find ghc in PATH")
+ ghc = Compiler(Path(path))
+ else:
+ ghc = Compiler(compiler)
+ return ghc
+
+
def main() -> None:
import argparse
parser = argparse.ArgumentParser(
description="bootstrapping utility for hadrian.",
epilog = USAGE,
formatter_class = argparse.RawDescriptionHelpFormatter)
- parser.add_argument('-d', '--deps', type=Path, default='bootstrap-deps.json',
- help='bootstrap dependency file')
+ parser.add_argument('-d', '--deps', type=Path, help='bootstrap dependency file (plan-bootstrap.json)')
parser.add_argument('-w', '--with-compiler', type=Path,
help='path to GHC')
- args = parser.parse_args()
+ parser.add_argument('-s', '--bootstrap-sources', type=Path,
+ help='Path to prefetched bootstrap sources tarball')
- # Find compiler
- if args.with_compiler is None:
- path = shutil.which('ghc')
- if path is None:
- raise ValueError("Couldn't find ghc in PATH")
- ghc = Compiler(Path(path))
- else:
- ghc = Compiler(args.with_compiler)
+ subparsers = parser.add_subparsers(dest="command")
+
+ parser_list = subparsers.add_parser('list-sources', help='list all sources required to download')
+ parser_list.add_argument('-o','--output', type=Path, default='fetch_plan.json')
+
+ parser_fetch = subparsers.add_parser('fetch', help='fetch all required sources from hackage (for offline builds)')
+ parser_fetch.add_argument('-o','--output', type=Path, default='bootstrap-sources')
+ parser_fetch.add_argument('-p','--fetch-plan', type=Path, default=None, help="A json document that lists the urls required for download (optional)")
+
+ args = parser.parse_args()
- print(f'Bootstrapping hadrian with GHC {ghc.version} at {ghc.ghc_path}...')
+ ghc = None
+
+ if args.deps is None:
+ if args.bootstrap_sources is None:
+ # find appropriate plan in the same directory as the script
+ ghc = find_ghc(args.with_compiler)
+ args.deps = Path(sys.path[0]) / f"plan-bootstrap-{ghc.version.replace('.','_')}.json"
+ print(f"defaulting bootstrap plan to {args.deps}")
+ # We have a tarball with all the required information, unpack it and use for further
+ elif args.bootstrap_sources is not None and args.command != 'list-sources':
+ print(f'Unpacking {args.bootstrap_sources} to {TARBALLS}')
+ shutil.unpack_archive(args.bootstrap_sources.resolve(), TARBALLS, 'gztar')
+ args.deps = TARBALLS / 'plan-bootstrap.json'
+ print(f"using plan-bootstrap.json ({args.deps}) from {args.bootstrap_sources}")
+ else:
+ print("We need a bootstrap plan (plan-bootstrap.json) or a tarball containing bootstrap information")
+ print("Perhaps pick an appropriate one from: ")
+ for child in Path(sys.path[0]).iterdir:
+ if child.match('plan-bootstrap-*.json'):
+ print(child)
+ sys.exit(1)
+ info = read_bootstrap_info(args.deps)
print(dedent("""
DO NOT use this script if you have another recent cabal-install available.
@@ -353,25 +405,79 @@ def main() -> None:
architectures.
"""))
- info = read_bootstrap_info(args.deps)
- bootstrap(info, ghc)
- hadrian_path = (BINDIR / 'hadrian').resolve()
- archive = make_archive(hadrian_path)
+ if(args.command == 'fetch'):
+ if args.fetch_plan is not None:
+ plan = { path : FetchInfo(p["url"],p["sha256"]) for path, p in json.load(args.fetch_plan.open()).items() }
+ else:
+ plan = gen_fetch_plan(info)
+
+ # In temporary directory, create a directory which we will archive
+ tmpdir = TMPDIR.resolve()
+ tmpdir.mkdir(parents=True, exist_ok=True)
+
+ rootdir = Path(tempfile.mkdtemp(dir=tmpdir))
+
+ fetch_from_plan(plan, rootdir)
+
+ shutil.copyfile(args.deps, rootdir / 'plan-bootstrap.json')
- print(dedent(f'''
- Bootstrapping finished!
+ fmt = 'gztar'
+ if platform.system() == 'Windows': fmt = 'zip'
+
+ archivename = shutil.make_archive(args.output, fmt, root_dir=rootdir)
- The resulting hadrian executable can be found at
+ print(f'Bootstrap sources saved to {archivename}')
+ print(f'Use `bootstrap.py -d {args.deps} -s {archivename}` to continue')
- {hadrian_path}
+ elif(args.command == 'list-sources'):
+ plan = gen_fetch_plan(info)
+ with open(args.output, 'w') as out:
+ json.dump({path : val._asdict() for path,val in plan.items()}, out)
+ print(f"Required hackage sources saved to {args.output}")
+ tarfmt= "\n./"
+ print(f"""
+Download the files listed in {args.output} and save them to a tarball ($TARBALL), along with {args.deps}
+The contents of $TARBALL should look like:
- It have been archived for distribution in
+./
+./plan-bootstrap.json
+./{tarfmt.join(path for path in plan)}
- {archive}
+Then use `bootstrap.py -s $TARBALL` to continue
+Alternatively, you could use `bootstrap.py -d {args.deps} fetch -o $TARBALL` to download and generate the tarball, skipping this step
+""")
- You can use this executable to build GHC.
- '''))
+ elif(args.command == None):
+ if ghc is None:
+ ghc = find_ghc(args.with_compiler)
+
+ print(f'Bootstrapping hadrian with GHC {ghc.version} at {ghc.ghc_path}...')
+
+ if args.bootstrap_sources is None:
+ plan = gen_fetch_plan(info)
+ fetch_from_plan(plan, TARBALLS)
+
+ bootstrap(info, ghc)
+ hadrian_path = (BINDIR / 'hadrian').resolve()
+
+ archive = make_archive(hadrian_path)
+
+ print(dedent(f'''
+ Bootstrapping finished!
+
+ The resulting hadrian executable can be found at
+
+ {hadrian_path}
+
+ It have been archived for distribution in
+
+ {archive}
+
+ You can use this executable to build GHC.
+ '''))
+ else:
+ print(f"No such command: {args.command}")
def subprocess_run(args, **kwargs):
"Like subprocess.run, but also print what we run"
diff --git a/hadrian/bootstrap/plan-8_10_7.json b/hadrian/bootstrap/plan-8_10_7.json
new file mode 100644
index 0000000000..da1a970d1c
--- /dev/null
+++ b/hadrian/bootstrap/plan-8_10_7.json
@@ -0,0 +1 @@
+{"cabal-version":"3.6.0.0","cabal-lib-version":"3.6.1.0","compiler-id":"ghc-8.10.7","os":"linux","arch":"x86_64","install-plan":[{"type":"pre-existing","id":"Cabal-3.2.1.0","pkg-name":"Cabal","pkg-version":"3.2.1.0","depends":["array-0.5.4.0","base-4.14.3.0","binary-0.8.8.0","bytestring-0.10.12.0","containers-0.6.5.1","deepseq-1.4.4.0","directory-1.3.6.0","filepath-1.4.2.1","mtl-2.2.2","parsec-3.1.14.0","pretty-1.1.3.6","process-1.6.13.2","text-1.2.4.1","time-1.9.3","transformers-0.5.6.2","unix-2.7.2.2"]},{"type":"configured","id":"QuickCheck-2.14.2-1ab4fade23a39bdfa4bc08a060cf2ab9229069e612057481b6330cd9a452d0a7","pkg-name":"QuickCheck","pkg-version":"2.14.2","flags":{"old-random":false,"templatehaskell":true},"style":"global","pkg-src":{"type":"repo-tar","repo":{"type":"secure-repo","uri":"http://hackage.haskell.org/"}},"pkg-cabal-sha256":"4ce29211223d5e6620ebceba34a3ca9ccf1c10c0cf387d48aea45599222ee5aa","pkg-src-sha256":"d87b6c85696b601175274361fa62217894401e401e150c3c5d4013ac53cd36f3","depends":["base-4.14.3.0","containers-0.6.5.1","deepseq-1.4.4.0","random-1.2.0-2243011942dde842d48362369219b18eb7cc062f1688de6916b30e595e924a4f","splitmix-0.1.0.3-ea3085a505c71722909b9aaac572a309c1a1430c785391ad5df25c21334bd11f","template-haskell-2.16.0.0","transformers-0.5.6.2"],"exe-depends":[],"component-name":"lib"},{"type":"pre-existing","id":"array-0.5.4.0","pkg-name":"array","pkg-version":"0.5.4.0","depends":["base-4.14.3.0"]},{"type":"pre-existing","id":"base-4.14.3.0","pkg-name":"base","pkg-version":"4.14.3.0","depends":["ghc-prim-0.6.1","integer-gmp-1.0.3.0","rts"]},{"type":"pre-existing","id":"binary-0.8.8.0","pkg-name":"binary","pkg-version":"0.8.8.0","depends":["array-0.5.4.0","base-4.14.3.0","bytestring-0.10.12.0","containers-0.6.5.1"]},{"type":"pre-existing","id":"bytestring-0.10.12.0","pkg-name":"bytestring","pkg-version":"0.10.12.0","depends":["base-4.14.3.0","deepseq-1.4.4.0","ghc-prim-0.6.1","integer-gmp-1.0.3.0"]},{"type":"configured","id":"clock-0.8.2-d0dc2384503c95726509e70e7531bd527ee2a618757ad555267b66af6639fd46","pkg-name":"clock","pkg-version":"0.8.2","flags":{"llvm":false},"style":"global","pkg-src":{"type":"repo-tar","repo":{"type":"secure-repo","uri":"http://hackage.haskell.org/"}},"pkg-cabal-sha256":"473ffd59765cc67634bdc55b63c699a85addf3a024089073ec2a862881e83e2a","pkg-src-sha256":"0b5db110c703e68b251d5883253a934b012110b45393fc65df1b095eb9a4e461","depends":["base-4.14.3.0"],"exe-depends":[],"component-name":"lib"},{"type":"pre-existing","id":"containers-0.6.5.1","pkg-name":"containers","pkg-version":"0.6.5.1","depends":["array-0.5.4.0","base-4.14.3.0","deepseq-1.4.4.0"]},{"type":"pre-existing","id":"deepseq-1.4.4.0","pkg-name":"deepseq","pkg-version":"1.4.4.0","depends":["array-0.5.4.0","base-4.14.3.0"]},{"type":"pre-existing","id":"directory-1.3.6.0","pkg-name":"directory","pkg-version":"1.3.6.0","depends":["base-4.14.3.0","filepath-1.4.2.1","time-1.9.3","unix-2.7.2.2"]},{"type":"configured","id":"extra-1.7.9-d67225380b6532ca2bfa5e82183ab2c561dc7aa0a4c67e028fad508894aaab28","pkg-name":"extra","pkg-version":"1.7.9","flags":{},"style":"global","pkg-src":{"type":"repo-tar","repo":{"type":"secure-repo","uri":"http://hackage.haskell.org/"}},"pkg-cabal-sha256":"f1dec740f0f2025790c540732bfd52c556ec55bde4f5dfd7cf18e22bd44ff3d0","pkg-src-sha256":"f66e26a63b216f0ca33665a75c08eada0a96af192ace83a18d87839d79afdf9d","depends":["base-4.14.3.0","clock-0.8.2-d0dc2384503c95726509e70e7531bd527ee2a618757ad555267b66af6639fd46","directory-1.3.6.0","filepath-1.4.2.1","process-1.6.13.2","time-1.9.3","unix-2.7.2.2"],"exe-depends":[],"component-name":"lib"},{"type":"pre-existing","id":"filepath-1.4.2.1","pkg-name":"filepath","pkg-version":"1.4.2.1","depends":["base-4.14.3.0"]},{"type":"configured","id":"filepattern-0.1.2-6cea41cc4733b58a07fd91659973df5fe1833632c32faf1ff101197c1a17cdbf","pkg-name":"filepattern","pkg-version":"0.1.2","flags":{},"style":"global","pkg-src":{"type":"repo-tar","repo":{"type":"secure-repo","uri":"http://hackage.haskell.org/"}},"pkg-cabal-sha256":"aec816ff25418d1b03ba75189e568f490eb86efc47f586d43363fa338e422e81","pkg-src-sha256":"d92912ee0db0b8c50d6b2ffdc1ae91ee30e2704b47896aa325b42b58a2fcf65b","depends":["base-4.14.3.0","directory-1.3.6.0","extra-1.7.9-d67225380b6532ca2bfa5e82183ab2c561dc7aa0a4c67e028fad508894aaab28","filepath-1.4.2.1"],"exe-depends":[],"component-name":"lib"},{"type":"pre-existing","id":"ghc-boot-th-8.10.7","pkg-name":"ghc-boot-th","pkg-version":"8.10.7","depends":["base-4.14.3.0"]},{"type":"pre-existing","id":"ghc-prim-0.6.1","pkg-name":"ghc-prim","pkg-version":"0.6.1","depends":["rts"]},{"type":"configured","id":"hadrian-0.1.0.0-inplace-hadrian","pkg-name":"hadrian","pkg-version":"0.1.0.0","flags":{"threaded":true},"style":"local","pkg-src":{"type":"local","path":"/home/zubin/ghcs/hadrian/hadrian/."},"dist-dir":"/home/zubin/ghcs/hadrian/hadrian/dist-newstyle/build/x86_64-linux/ghc-8.10.7/hadrian-0.1.0.0/x/hadrian","depends":["Cabal-3.2.1.0","QuickCheck-2.14.2-1ab4fade23a39bdfa4bc08a060cf2ab9229069e612057481b6330cd9a452d0a7","base-4.14.3.0","bytestring-0.10.12.0","containers-0.6.5.1","directory-1.3.6.0","extra-1.7.9-d67225380b6532ca2bfa5e82183ab2c561dc7aa0a4c67e028fad508894aaab28","filepath-1.4.2.1","mtl-2.2.2","parsec-3.1.14.0","shake-0.19.4-1b5ee53f982f6a7a27ff48f4dd3394ec132b4a5f7bc220b8ff9a2f4c53696f15","transformers-0.5.6.2","unordered-containers-0.2.13.0-58e16f1c5409e3f5d3eeabf16aadb5657e6bc5a6faec0126c75e8e7cc74f3945"],"exe-depends":[],"component-name":"exe:hadrian","bin-file":"/home/zubin/ghcs/hadrian/hadrian/dist-newstyle/build/x86_64-linux/ghc-8.10.7/hadrian-0.1.0.0/x/hadrian/build/hadrian/hadrian"},{"type":"configured","id":"hashable-1.3.1.0-1a2b1a1b7cddf830807847c6367d9ae80ef1db199fe34b5ec14f4a758bbd6657","pkg-name":"hashable","pkg-version":"1.3.1.0","flags":{"integer-gmp":true},"style":"global","pkg-src":{"type":"repo-tar","repo":{"type":"secure-repo","uri":"http://hackage.haskell.org/"}},"pkg-cabal-sha256":"d965e098e06cc585b201da6137dcb31c40f35eb7a937b833903969447985c076","pkg-src-sha256":"8061823a4ac521b53912edcba36b956f3159cb885b07ec119af295a6568ca7c4","depends":["base-4.14.3.0","bytestring-0.10.12.0","deepseq-1.4.4.0","ghc-prim-0.6.1","integer-gmp-1.0.3.0","text-1.2.4.1"],"exe-depends":[],"component-name":"lib"},{"type":"configured","id":"heaps-0.4-7cd7f81fe8e434fb927c09a81c78e17029735eb735dadd2e0095eccad2f28315","pkg-name":"heaps","pkg-version":"0.4","flags":{},"style":"global","pkg-src":{"type":"repo-tar","repo":{"type":"secure-repo","uri":"http://hackage.haskell.org/"}},"pkg-cabal-sha256":"66b19fcd813b0e4db3e0bac541bd46606c3b13d3d081d9f9666f4be0f5ff14b8","pkg-src-sha256":"89329df8b95ae99ef272e41e7a2d0fe2f1bb7eacfcc34bc01664414b33067cfd","depends":["base-4.14.3.0"],"exe-depends":[],"component-name":"lib"},{"type":"pre-existing","id":"integer-gmp-1.0.3.0","pkg-name":"integer-gmp","pkg-version":"1.0.3.0","depends":["ghc-prim-0.6.1"]},{"type":"configured","id":"js-dgtable-0.5.2-611975c124efb7e3dff07d621d374704168c1a98c4cd9abc0371f555da021a8f","pkg-name":"js-dgtable","pkg-version":"0.5.2","flags":{},"style":"global","pkg-src":{"type":"repo-tar","repo":{"type":"secure-repo","uri":"http://hackage.haskell.org/"}},"pkg-cabal-sha256":"f75cb4fa53c88c65794becdd48eb0d3b2b8abd89a3d5c19e87af91f5225c15e4","pkg-src-sha256":"e28dd65bee8083b17210134e22e01c6349dc33c3b7bd17705973cd014e9f20ac","depends":["base-4.14.3.0"],"exe-depends":[],"component-name":"lib"},{"type":"configured","id":"js-flot-0.8.3-163b76cdce2eb5fca3a158e8cc58c1e0a0378fc57e814b8623da9effed6e9420","pkg-name":"js-flot","pkg-version":"0.8.3","flags":{},"style":"global","pkg-src":{"type":"repo-tar","repo":{"type":"secure-repo","uri":"http://hackage.haskell.org/"}},"pkg-cabal-sha256":"4c1c447a9a2fba0adba6d30678302a30c32b9dfde9e7aa9e9156483e1545096d","pkg-src-sha256":"1ba2f2a6b8d85da76c41f526c98903cbb107f8642e506c072c1e7e3c20fe5e7a","depends":["base-4.14.3.0"],"exe-depends":[],"component-name":"lib"},{"type":"configured","id":"js-jquery-3.3.1-4b07853b823d103c8e45e6bee9e6183531d323a3c9cb9656aae62acb0f43e44e","pkg-name":"js-jquery","pkg-version":"3.3.1","flags":{},"style":"global","pkg-src":{"type":"repo-tar","repo":{"type":"secure-repo","uri":"http://hackage.haskell.org/"}},"pkg-cabal-sha256":"59ab6c79159549ef94b584abce8e6d3b336014c2cce1337b59a8f637e2856df5","pkg-src-sha256":"e0e0681f0da1130ede4e03a051630ea439c458cb97216cdb01771ebdbe44069b","depends":["base-4.14.3.0"],"exe-depends":[],"component-name":"lib"},{"type":"pre-existing","id":"mtl-2.2.2","pkg-name":"mtl","pkg-version":"2.2.2","depends":["base-4.14.3.0","transformers-0.5.6.2"]},{"type":"pre-existing","id":"parsec-3.1.14.0","pkg-name":"parsec","pkg-version":"3.1.14.0","depends":["base-4.14.3.0","bytestring-0.10.12.0","mtl-2.2.2","text-1.2.4.1"]},{"type":"pre-existing","id":"pretty-1.1.3.6","pkg-name":"pretty","pkg-version":"1.1.3.6","depends":["base-4.14.3.0","deepseq-1.4.4.0","ghc-prim-0.6.1"]},{"type":"configured","id":"primitive-0.7.1.0-24e5fe46f21fa909242c62c01a9dc73651664fea156afd47a7a236612e5bff26","pkg-name":"primitive","pkg-version":"0.7.1.0","flags":{},"style":"global","pkg-src":{"type":"repo-tar","repo":{"type":"secure-repo","uri":"http://hackage.haskell.org/"}},"pkg-cabal-sha256":"f6357d5720c1c665096c3e011467daf443198b786a708d2ff926958a24d508d4","pkg-src-sha256":"6bebecfdf2a57787d9fd5231bfd612b65a92edd7b33a973b2a0f11312b89a3f0","depends":["base-4.14.3.0","deepseq-1.4.4.0","transformers-0.5.6.2"],"exe-depends":[],"component-name":"lib"},{"type":"pre-existing","id":"process-1.6.13.2","pkg-name":"process","pkg-version":"1.6.13.2","depends":["base-4.14.3.0","deepseq-1.4.4.0","directory-1.3.6.0","filepath-1.4.2.1","unix-2.7.2.2"]},{"type":"configured","id":"random-1.2.0-2243011942dde842d48362369219b18eb7cc062f1688de6916b30e595e924a4f","pkg-name":"random","pkg-version":"1.2.0","flags":{},"style":"global","pkg-src":{"type":"repo-tar","repo":{"type":"secure-repo","uri":"http://hackage.haskell.org/"}},"pkg-cabal-sha256":"30d72df4cc1d2fe2d445c88f0ee9d21965af7ce86660c43a6c32a6a1d90d51c9","pkg-src-sha256":"e4519cf7c058bfd5bdbe4acc782284acc9e25e74487208619ca83cbcd63fb9de","depends":["base-4.14.3.0","bytestring-0.10.12.0","deepseq-1.4.4.0","mtl-2.2.2","splitmix-0.1.0.3-ea3085a505c71722909b9aaac572a309c1a1430c785391ad5df25c21334bd11f"],"exe-depends":[],"component-name":"lib"},{"type":"pre-existing","id":"rts","pkg-name":"rts","pkg-version":"1.0.1","depends":[]},{"type":"configured","id":"shake-0.19.4-1b5ee53f982f6a7a27ff48f4dd3394ec132b4a5f7bc220b8ff9a2f4c53696f15","pkg-name":"shake","pkg-version":"0.19.4","flags":{"cloud":false,"embed-files":false,"portable":false},"style":"global","pkg-src":{"type":"repo-tar","repo":{"type":"secure-repo","uri":"http://hackage.haskell.org/"}},"pkg-cabal-sha256":"be81f7c69137e639812380047dfbbdd253ca536cc919504c3bc0f14517e80eb9","pkg-src-sha256":"5bae8873f628113604159f650802edb249dfbe5802c4612751f680ac987d73ee","depends":["base-4.14.3.0","binary-0.8.8.0","bytestring-0.10.12.0","deepseq-1.4.4.0","directory-1.3.6.0","extra-1.7.9-d67225380b6532ca2bfa5e82183ab2c561dc7aa0a4c67e028fad508894aaab28","filepath-1.4.2.1","filepattern-0.1.2-6cea41cc4733b58a07fd91659973df5fe1833632c32faf1ff101197c1a17cdbf","hashable-1.3.1.0-1a2b1a1b7cddf830807847c6367d9ae80ef1db199fe34b5ec14f4a758bbd6657","heaps-0.4-7cd7f81fe8e434fb927c09a81c78e17029735eb735dadd2e0095eccad2f28315","js-dgtable-0.5.2-611975c124efb7e3dff07d621d374704168c1a98c4cd9abc0371f555da021a8f","js-flot-0.8.3-163b76cdce2eb5fca3a158e8cc58c1e0a0378fc57e814b8623da9effed6e9420","js-jquery-3.3.1-4b07853b823d103c8e45e6bee9e6183531d323a3c9cb9656aae62acb0f43e44e","primitive-0.7.1.0-24e5fe46f21fa909242c62c01a9dc73651664fea156afd47a7a236612e5bff26","process-1.6.13.2","random-1.2.0-2243011942dde842d48362369219b18eb7cc062f1688de6916b30e595e924a4f","time-1.9.3","transformers-0.5.6.2","unix-2.7.2.2","unordered-containers-0.2.13.0-58e16f1c5409e3f5d3eeabf16aadb5657e6bc5a6faec0126c75e8e7cc74f3945","utf8-string-1.0.2-e0dec0cb269d870cf4ce7c7046b52e087c28eb892bd20000fda419f3259c0719"],"exe-depends":[],"component-name":"lib"},{"type":"configured","id":"shake-0.19.4-e-shake-bb8241813adf3bcaf65a8bb63b7d51a0c2b766952b74366c02ac48e6628adc8b","pkg-name":"shake","pkg-version":"0.19.4","flags":{"cloud":false,"embed-files":false,"portable":false},"style":"global","pkg-src":{"type":"repo-tar","repo":{"type":"secure-repo","uri":"http://hackage.haskell.org/"}},"pkg-cabal-sha256":"be81f7c69137e639812380047dfbbdd253ca536cc919504c3bc0f14517e80eb9","pkg-src-sha256":"5bae8873f628113604159f650802edb249dfbe5802c4612751f680ac987d73ee","depends":["base-4.14.3.0","binary-0.8.8.0","bytestring-0.10.12.0","deepseq-1.4.4.0","directory-1.3.6.0","extra-1.7.9-d67225380b6532ca2bfa5e82183ab2c561dc7aa0a4c67e028fad508894aaab28","filepath-1.4.2.1","filepattern-0.1.2-6cea41cc4733b58a07fd91659973df5fe1833632c32faf1ff101197c1a17cdbf","hashable-1.3.1.0-1a2b1a1b7cddf830807847c6367d9ae80ef1db199fe34b5ec14f4a758bbd6657","heaps-0.4-7cd7f81fe8e434fb927c09a81c78e17029735eb735dadd2e0095eccad2f28315","js-dgtable-0.5.2-611975c124efb7e3dff07d621d374704168c1a98c4cd9abc0371f555da021a8f","js-flot-0.8.3-163b76cdce2eb5fca3a158e8cc58c1e0a0378fc57e814b8623da9effed6e9420","js-jquery-3.3.1-4b07853b823d103c8e45e6bee9e6183531d323a3c9cb9656aae62acb0f43e44e","primitive-0.7.1.0-24e5fe46f21fa909242c62c01a9dc73651664fea156afd47a7a236612e5bff26","process-1.6.13.2","random-1.2.0-2243011942dde842d48362369219b18eb7cc062f1688de6916b30e595e924a4f","time-1.9.3","transformers-0.5.6.2","unix-2.7.2.2","unordered-containers-0.2.13.0-58e16f1c5409e3f5d3eeabf16aadb5657e6bc5a6faec0126c75e8e7cc74f3945","utf8-string-1.0.2-e0dec0cb269d870cf4ce7c7046b52e087c28eb892bd20000fda419f3259c0719"],"exe-depends":[],"component-name":"exe:shake","bin-file":"/home/zubin/.cabal/store/ghc-8.10.7/shake-0.19.4-e-shake-bb8241813adf3bcaf65a8bb63b7d51a0c2b766952b74366c02ac48e6628adc8b/bin/shake"},{"type":"configured","id":"splitmix-0.1.0.3-ea3085a505c71722909b9aaac572a309c1a1430c785391ad5df25c21334bd11f","pkg-name":"splitmix","pkg-version":"0.1.0.3","flags":{"optimised-mixer":false},"style":"global","pkg-src":{"type":"repo-tar","repo":{"type":"secure-repo","uri":"http://hackage.haskell.org/"}},"pkg-cabal-sha256":"fc3aae74c467f4b608050bef53aec17904a618731df9407e655d8f3bf8c32d5c","pkg-src-sha256":"46009f4b000c9e6613377767b8718bf38476469f2a8e2162d98cc246882d5a35","depends":["base-4.14.3.0","deepseq-1.4.4.0"],"exe-depends":[],"component-name":"lib"},{"type":"pre-existing","id":"template-haskell-2.16.0.0","pkg-name":"template-haskell","pkg-version":"2.16.0.0","depends":["base-4.14.3.0","ghc-boot-th-8.10.7","ghc-prim-0.6.1","pretty-1.1.3.6"]},{"type":"pre-existing","id":"text-1.2.4.1","pkg-name":"text","pkg-version":"1.2.4.1","depends":["array-0.5.4.0","base-4.14.3.0","binary-0.8.8.0","bytestring-0.10.12.0","deepseq-1.4.4.0","ghc-prim-0.6.1","integer-gmp-1.0.3.0","template-haskell-2.16.0.0"]},{"type":"pre-existing","id":"time-1.9.3","pkg-name":"time","pkg-version":"1.9.3","depends":["base-4.14.3.0","deepseq-1.4.4.0"]},{"type":"pre-existing","id":"transformers-0.5.6.2","pkg-name":"transformers","pkg-version":"0.5.6.2","depends":["base-4.14.3.0"]},{"type":"pre-existing","id":"unix-2.7.2.2","pkg-name":"unix","pkg-version":"2.7.2.2","depends":["base-4.14.3.0","bytestring-0.10.12.0","time-1.9.3"]},{"type":"configured","id":"unordered-containers-0.2.13.0-58e16f1c5409e3f5d3eeabf16aadb5657e6bc5a6faec0126c75e8e7cc74f3945","pkg-name":"unordered-containers","pkg-version":"0.2.13.0","flags":{"debug":false},"style":"global","pkg-src":{"type":"repo-tar","repo":{"type":"secure-repo","uri":"http://hackage.haskell.org/"}},"pkg-cabal-sha256":"6310c636f92ed4908fdd0de582b6be31c2851c7b5f2ec14e9f416eb94df7a078","pkg-src-sha256":"86b01369ab8eb311383a052d389337e2cd71a63088323f02932754df4aa37b55","depends":["base-4.14.3.0","deepseq-1.4.4.0","hashable-1.3.1.0-1a2b1a1b7cddf830807847c6367d9ae80ef1db199fe34b5ec14f4a758bbd6657"],"exe-depends":[],"component-name":"lib"},{"type":"configured","id":"utf8-string-1.0.2-e0dec0cb269d870cf4ce7c7046b52e087c28eb892bd20000fda419f3259c0719","pkg-name":"utf8-string","pkg-version":"1.0.2","flags":{},"style":"global","pkg-src":{"type":"repo-tar","repo":{"type":"secure-repo","uri":"http://hackage.haskell.org/"}},"pkg-cabal-sha256":"79416292186feeaf1f60e49ac5a1ffae9bf1b120e040a74bf0e81ca7f1d31d3f","pkg-src-sha256":"ee48deada7600370728c4156cb002441de770d0121ae33a68139a9ed9c19b09a","depends":["base-4.14.3.0","bytestring-0.10.12.0"],"exe-depends":[],"component-name":"lib"}]} \ No newline at end of file
diff --git a/hadrian/bootstrap/plan-bootstrap-8_10_7.json b/hadrian/bootstrap/plan-bootstrap-8_10_7.json
new file mode 100644
index 0000000000..6715c4dcfd
--- /dev/null
+++ b/hadrian/bootstrap/plan-bootstrap-8_10_7.json
@@ -0,0 +1 @@
+{"dependencies":[{"source":"hackage","cabal_sha256":"fc3aae74c467f4b608050bef53aec17904a618731df9407e655d8f3bf8c32d5c","revision":0,"src_sha256":"46009f4b000c9e6613377767b8718bf38476469f2a8e2162d98cc246882d5a35","flags":["-optimised-mixer"],"package":"splitmix","version":"0.1.0.3"},{"source":"hackage","cabal_sha256":"195506fedaa7c31c1fa2a747e9b49b4a5d1f0b09dd8f1291f23a771656faeec3","revision":6,"src_sha256":"e4519cf7c058bfd5bdbe4acc782284acc9e25e74487208619ca83cbcd63fb9de","flags":[],"package":"random","version":"1.2.0"},{"source":"hackage","cabal_sha256":"4ce29211223d5e6620ebceba34a3ca9ccf1c10c0cf387d48aea45599222ee5aa","revision":0,"src_sha256":"d87b6c85696b601175274361fa62217894401e401e150c3c5d4013ac53cd36f3","flags":["-old-random","+templatehaskell"],"package":"QuickCheck","version":"2.14.2"},{"source":"hackage","cabal_sha256":"473ffd59765cc67634bdc55b63c699a85addf3a024089073ec2a862881e83e2a","revision":0,"src_sha256":"0b5db110c703e68b251d5883253a934b012110b45393fc65df1b095eb9a4e461","flags":["-llvm"],"package":"clock","version":"0.8.2"},{"source":"hackage","cabal_sha256":"f1dec740f0f2025790c540732bfd52c556ec55bde4f5dfd7cf18e22bd44ff3d0","revision":0,"src_sha256":"f66e26a63b216f0ca33665a75c08eada0a96af192ace83a18d87839d79afdf9d","flags":[],"package":"extra","version":"1.7.9"},{"source":"hackage","cabal_sha256":"aec816ff25418d1b03ba75189e568f490eb86efc47f586d43363fa338e422e81","revision":0,"src_sha256":"d92912ee0db0b8c50d6b2ffdc1ae91ee30e2704b47896aa325b42b58a2fcf65b","flags":[],"package":"filepattern","version":"0.1.2"},{"source":"hackage","cabal_sha256":"d965e098e06cc585b201da6137dcb31c40f35eb7a937b833903969447985c076","revision":0,"src_sha256":"8061823a4ac521b53912edcba36b956f3159cb885b07ec119af295a6568ca7c4","flags":["+integer-gmp"],"package":"hashable","version":"1.3.1.0"},{"source":"hackage","cabal_sha256":"66b19fcd813b0e4db3e0bac541bd46606c3b13d3d081d9f9666f4be0f5ff14b8","revision":0,"src_sha256":"89329df8b95ae99ef272e41e7a2d0fe2f1bb7eacfcc34bc01664414b33067cfd","flags":[],"package":"heaps","version":"0.4"},{"source":"hackage","cabal_sha256":"f75cb4fa53c88c65794becdd48eb0d3b2b8abd89a3d5c19e87af91f5225c15e4","revision":0,"src_sha256":"e28dd65bee8083b17210134e22e01c6349dc33c3b7bd17705973cd014e9f20ac","flags":[],"package":"js-dgtable","version":"0.5.2"},{"source":"hackage","cabal_sha256":"4c1c447a9a2fba0adba6d30678302a30c32b9dfde9e7aa9e9156483e1545096d","revision":0,"src_sha256":"1ba2f2a6b8d85da76c41f526c98903cbb107f8642e506c072c1e7e3c20fe5e7a","flags":[],"package":"js-flot","version":"0.8.3"},{"source":"hackage","cabal_sha256":"59ab6c79159549ef94b584abce8e6d3b336014c2cce1337b59a8f637e2856df5","revision":0,"src_sha256":"e0e0681f0da1130ede4e03a051630ea439c458cb97216cdb01771ebdbe44069b","flags":[],"package":"js-jquery","version":"3.3.1"},{"source":"hackage","cabal_sha256":"29de6bfd0cf8ba023ceb806203dfbec0e51e3524e75ffe41056f70b4229c6f0f","revision":3,"src_sha256":"6bebecfdf2a57787d9fd5231bfd612b65a92edd7b33a973b2a0f11312b89a3f0","flags":[],"package":"primitive","version":"0.7.1.0"},{"source":"hackage","cabal_sha256":"6310c636f92ed4908fdd0de582b6be31c2851c7b5f2ec14e9f416eb94df7a078","revision":0,"src_sha256":"86b01369ab8eb311383a052d389337e2cd71a63088323f02932754df4aa37b55","flags":["-debug"],"package":"unordered-containers","version":"0.2.13.0"},{"source":"hackage","cabal_sha256":"79416292186feeaf1f60e49ac5a1ffae9bf1b120e040a74bf0e81ca7f1d31d3f","revision":0,"src_sha256":"ee48deada7600370728c4156cb002441de770d0121ae33a68139a9ed9c19b09a","flags":[],"package":"utf8-string","version":"1.0.2"},{"source":"hackage","cabal_sha256":"be81f7c69137e639812380047dfbbdd253ca536cc919504c3bc0f14517e80eb9","revision":0,"src_sha256":"5bae8873f628113604159f650802edb249dfbe5802c4612751f680ac987d73ee","flags":["-cloud","-embed-files","-portable"],"package":"shake","version":"0.19.4"},{"source":"local","cabal_sha256":null,"revision":null,"src_sha256":null,"flags":["+threaded"],"package":"hadrian","version":"0.1.0.0"}],"builtin":[{"package":"rts","version":"1.0.1"},{"package":"ghc-prim","version":"0.6.1"},{"package":"integer-gmp","version":"1.0.3.0"},{"package":"base","version":"4.14.3.0"},{"package":"array","version":"0.5.4.0"},{"package":"deepseq","version":"1.4.4.0"},{"package":"bytestring","version":"0.10.12.0"},{"package":"containers","version":"0.6.5.1"},{"package":"binary","version":"0.8.8.0"},{"package":"filepath","version":"1.4.2.1"},{"package":"time","version":"1.9.3"},{"package":"unix","version":"2.7.2.2"},{"package":"directory","version":"1.3.6.0"},{"package":"transformers","version":"0.5.6.2"},{"package":"mtl","version":"2.2.2"},{"package":"ghc-boot-th","version":"8.10.7"},{"package":"pretty","version":"1.1.3.6"},{"package":"template-haskell","version":"2.16.0.0"},{"package":"text","version":"1.2.4.1"},{"package":"parsec","version":"3.1.14.0"},{"package":"process","version":"1.6.13.2"},{"package":"Cabal","version":"3.2.1.0"}]}