misc: add new minimal thydeps script for Isabelle2018

This commit is contained in:
Japheth Lim 2018-08-27 12:50:54 +10:00
parent b61e91921c
commit 1bb071e703
1 changed files with 145 additions and 0 deletions

145
misc/scripts/thydeps Executable file
View File

@ -0,0 +1,145 @@
#!/usr/bin/env python3
#
# Copyright 2018, Data61
# Commonwealth Scientific and Industrial Research Organisation (CSIRO)
# ABN 41 687 119 230.
#
# This software may be distributed and modified according to the terms of
# the BSD 2-Clause license. Note that NO WARRANTY is provided.
# See "LICENSE_BSD2.txt" for details.
#
# @TAG(DATA61_BSD)
#
'''
Find the set of theory files that the given theories depend on.
Basically a thin wrapper around 'isabelle build -l'.
The main use for this script is to extract dependent theory files
for stand-alone releases of the C parser and AutoCorres.
'''
import argparse
import os
import re
import subprocess
def run_isabelle_tool(isabelle_dir, cmdline, ignore_exit_code=False):
'''Run Isabelle with given command (e.g. ['build', '-l', 'HOL']).
The first argument should be the Isabelle directory.
If the command succeeded, return its standard output.'''
isabelle_exe = os.path.join(isabelle_dir, 'bin', 'isabelle')
try:
return subprocess.check_output([isabelle_exe] + cmdline)
except subprocess.CalledProcessError as e:
if ignore_exit_code:
return e.output
else:
raise
def session_theory_deps(isabelle_dir, ROOT_dirs, sessions):
'''For the given sessions, retrieve the dependent sessions
and theory files (including the given sessions).
Returns a dict keyed by session name, containing lists of
theory file paths.'''
cmdline = ['build', '-l', '-n']
for d in ROOT_dirs:
cmdline += ['-d', d]
cmdline += sessions
deps = {}
this_session = None
session_name_re = r'[a-zA-Z0-9-_]+'
# `isabelle build` returns 1 if the session hasn't been built,
# even for a dry-run, so ignore the exit code
for l in run_isabelle_tool(
isabelle_dir, cmdline, ignore_exit_code=True).splitlines():
l = l.decode('utf-8')
# 'Session HOL/HOL-Word (main timing)'
m = re.match(r'Session (' + session_name_re + ')/(' + session_name_re + ')(?: \(.*\))?', l)
if m:
# start processing next session
_, session = m.groups()
this_session = session
assert session not in deps
deps[session] = []
continue
# ' /path/to/proof.thy'
if l.startswith(' '):
# another file in session
deps[this_session].append(l[2:])
continue
# There are some other junk lines, like '... elapsed time',
# which we ignore
return deps
def theory_deps_in_dirs(isabelle_dir, ROOT_dirs, sessions, base_dirs):
'''Get dependent sessions and theories like session_theory_deps,
but only report theory files and sessions that involve one of
the given directories.'''
full_deps = session_theory_deps(isabelle_dir, ROOT_dirs, sessions)
if not base_dirs:
# no filtering
return full_deps
deps = {}
# remove unwanted theories
for session in full_deps:
session_trimmed_deps = []
for f in full_deps[session]:
keep = False
for base in base_dirs:
relpath = os.path.relpath(f, base)
if not relpath.startswith('../'):
keep = True
break
if keep:
session_trimmed_deps.append(f)
# if session has no wanted theories, also drop it
if session_trimmed_deps:
deps[session] = session_trimmed_deps
return deps
def main():
parser = argparse.ArgumentParser(
description='Extract theory file dependencies of Isabelle sessions')
parser.add_argument('-d', metavar='DIR', action='append', default=[],
help='Directories containing ROOT or ROOTS files (default: .)')
parser.add_argument('-b', metavar='DIR', action='append', default=[],
help='Show theory files from these directories (default: all)')
parser.add_argument('-I', metavar='DIR', required=True,
help='Path to Isabelle system')
parser.add_argument('-r', action='store_true',
help='Print relative paths to -b directory (only one dir allowed)')
parser.add_argument('sessions', metavar='SESSIONS', nargs='+',
help='Isabelle session names')
opts = parser.parse_args()
if not opts.d:
opts.d = ['.']
# use absolute paths and resolve symlinks, to match `isabelle build -l`
opts.b = [os.path.realpath(d) for d in opts.b]
if opts.r and len(opts.b) != 1:
parser.error('must have exactly one directory for -b to use -r')
if not os.path.isdir(opts.I):
parser.error('expected a directory for -I option')
expected_isabelle = os.path.join(opts.I, 'bin', 'isabelle')
if not os.path.exists(expected_isabelle):
parser.error('Isabelle executable not found: %r' % expected_isabelle)
deps = theory_deps_in_dirs(opts.I, opts.d, opts.sessions, opts.b)
for session in deps:
for theory in deps[session]:
if opts.r:
theory = os.path.relpath(theory, opts.b[0])
print(theory)
if __name__ == '__main__':
main()