# Python imports
import os
import sys
import shutil
import subprocess
import json
import uuid
import collections
import hashlib
# local imports
# These must be relative imports for flmake reproduce
from .. import FLASH_SRC_DIR, MPIRUN_CMD, _metadata
from ..utils import warning
from ..dsl import runtime_parameters
from . import logger
from . import setup_parse
from . import setup_globals
from .setup_globals import gvars
from .utils import desc_cmd_metadata, vc_checkout, vc_patch
def _checkout_and_patch(src, info, diff, cmd):
targ = vc_checkout(src, info, cmd=cmd)
if 0 < len(diff):
vc_patch(targ, diff, info[0])
return targ
def _run_prev_cmd(cmd, desc, srcdirs, prjdirs):
# setup source dir
src_diff = desc[cmd]['source_diff'] if 'source_diff' in desc[cmd] else ""
srcdir = _checkout_and_patch(FLASH_SRC_DIR, desc[cmd]['source_version'], src_diff, cmd)
srcdirs.append(srcdir)
md = dict(_metadata)
md["FLASH_SRC_DIR"] = srcdir
md["FLASH_CLEAN_SRC_DIR"] = os.path.join(srcdir, '.clean')
md["MPIRUN_CMD"] = MPIRUN_CMD
md["version"] = desc[cmd]['source_version']
srctools = os.path.join(srcdir, 'tools')
with open(os.path.join(srctools, 'python', 'metadata.json'), 'w') as f:
json.dump(md, f, indent=2)
sys.path.insert(0, srctools)
# setup project dir
prj_diff = desc[cmd]['project_diff'] if 'project_diff' in desc[cmd] else ""
prjdir = _checkout_and_patch(os.getcwd(), desc[cmd]['project_version'], prj_diff, cmd)
prjdirs.append(prjdir)
from python.flmake.setup_globals import gvars as prev_gvars
_defs = prev_gvars._defaults
prev_gvars.project_setup_dir = gvars.project_setup_dir
prev_gvars.project_build_dir = gvars.project_build_dir
prev_gvars.project_source_dir = os.path.join(prjdir, _defs['project_source_dir'])
prev_gvars.project_simulations_dir = os.path.join(prjdir, _defs['project_simulations_dir'])
rcfile = os.path.join(prjdir, 'flashrc.py')
if 0 < len(desc[cmd]['rcfile']):
with open(rcfile, 'w') as f:
f.write(desc[cmd]['rcfile'])
# run the command
_mod_cmd(cmd, desc, srcdirs, prjdirs)
from python.flmake.main import main as prev_main
if cmd == "setup":
# FIXME hack until setup_parse is refactored.
sys.argv = desc[cmd]['command']
prev_main(rcfile, desc[cmd]['command'][1:])
# clear modules
sys.path.remove(srctools)
for mod in sys.modules.keys():
if mod.startswith('python'):
del sys.modules[mod]
return srcdirs, prjdirs
[docs]def main(opts, rc, msg):
"""Reproduces a FLASH run from a description."""
gvars.init(FLASH_SRC_DIR)
desc_filename = opts[0]
# reporduce previous commands
with open(desc_filename) as desc_file:
desc = json.load(desc_file)
srcdirs, prjdirs = [], []
for cmd in ['setup', 'build', 'run']:
if cmd in desc:
srcdirs, prjdirs = _run_prev_cmd(cmd, desc, srcdirs, prjdirs)
return 0
[docs]def usage():
"""Constructs usage info and exits."""
msg = ("usage: flmake reproduce [options] <flash_descr>\n\n"
"Reproduces a flash history by checking out previous\n"
"versions of the code and re-executing them with the\n"
"original values. Note: it is highly advised to run\n"
"'flmake clean 3' prior to reproduce.")
return msg
#
# Modifications specific to commands
#
def _mod_cmd(cmd, desc, srcdirs, prjdirs):
modfuncs = {'build': _mod_build, 'run': _mod_run}
modfunc = modfuncs.get(cmd, lambda *a: None)
modfunc(cmd, desc, srcdirs, prjdirs)
def _mod_build(cmd, desc, srcdirs, prjdirs):
_relink_setup(gvars.project_setup_dir, srcdirs, prjdirs)
def _mod_run(cmd, desc, srcdirs, prjdirs):
_relink_setup(gvars.project_setup_dir, srcdirs, prjdirs)
def _relink_setup(setupdir, srcdirs, prjdirs):
allfiles = [os.path.join(setupdir, f) for f in os.listdir(setupdir)]
symlinks = [f for f in allfiles if os.path.islink(f)]
srclinks = set([f for f in symlinks if os.readlink(f).startswith(srcdirs[-2])])
prjlinks = set([f for f in symlinks if os.readlink(f).startswith(prjdirs[-2])])
for f in symlinks:
thedirs = srcdirs if f in srclinks else (prjdirs if f in prjlinks else None)
oldtarg = os.readlink(f)
newtarg = oldtarg.replace(*thedirs[-2:])
os.remove(f)
os.symlink(newtarg, f)