Commit 29d297b5 authored by Ben Gamari's avatar Ben Gamari 🐢

Initial commit of dump-interfaces

This is the initial commit of a utility that I have been using to
compare the user-facing interfaces exposed by GHC across releases
parent cc2f96d2
#!/usr/bin/env python
"""
This is a handy utility for comparing the interfaces exposed by the core
library included in GHC's global package database. Given a compiler and a set
of packages it will produce a directory containing dumps of the :browse output
from each of the packages' exposed modules. These directories can be compared
with, e.g., meld with a reasonable number of false differences.
"""
from pathlib import Path
import subprocess
from typing import TextIO, Set
import re
CORE_PACKAGES = [
"base",
"ghc-prim",
"template-haskell",
"ghc-boot",
"ghc-boot-th"
]
exposed_modules_re = re.compile('exposed-modules:\s*((?:(?:[A-Z][A-Za-z0-9_]*\.)*(?:[A-Z][A-Za-z0-9_]*)\s*)*)')
def dump_module(out: TextIO, ghc: Path, mod: str):
print(f' Dumping {mod}...')
subprocess.run([ghc, '--interactive', '-dppr-cols=9999', '-v0'],
input=f':bro {mod}',
stdout=out,
encoding='UTF-8',
check=True)
def dump_package(out_dir: Path, ghc: Path, pkg: str):
pkg_out = out_dir / pkg
pkg_out.mkdir(exist_ok=True, parents=True)
modules = get_modules(ghc, pkg)
print(f'Dumping {len(modules)} exposed modules from {pkg}...')
for mod in modules:
mod_out = pkg_out / f"{mod}.txt"
dump_module(mod_out.open('w'), ghc, mod)
def get_modules(ghc: Path, pkg: str) -> Set[str]:
ghc_pkg = ghc.parent / "ghc-pkg"
out = subprocess.check_output([ghc_pkg, 'describe', pkg], encoding='UTF-8')
m = exposed_modules_re.search(out)
return set(m.group(1).split())
def main() -> None:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-c', '--compiler', type=Path, required=True,
help='GHC executable')
parser.add_argument('-o', '--output', type=Path, default=Path('interfaces'),
help='Output directory')
parser.add_argument('package', nargs='*', help='Packages to dump')
args = parser.parse_args()
packages = args.package
if packages == []:
packages = CORE_PACKAGES
for pkg in packages:
dump_package(args.output, args.compiler, pkg)
if __name__ == "__main__":
main()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment