Ejemplo n.º 1
0
def _set_correct(wizard, parameter, target):
    """Sets the current model output for the target and parameter as correct
    so that it will be used for future unit test comparisons.
    """
    casepath = _get_casepath(wizard)
    #We don't worry about updating the XML tag. That is done by a calling
    #procedure. The job here is to copy model output to the global output's
    #folder specified by the user for the current module, and then return the name
    #of the file in that folder.

    #As such, we need to choose a naming convention for the auto-assigned model
    #outputs. The safest thing to do is use the
    #module.executable.parameter.testid.caseid as the file name. But that is
    #*really* long and if the test folder is already buried pretty deep, it can
    #become unwieldly... On the other hand, if multiple unit tests want to compare
    #to the same model output, then we don't want to duplicate that, especially
    #considering the size of some of the files in scientific computing.
    from os import path
    varfile = path.join(casepath, target.varfile)
    newname = ""
    dst = path.join(wizard.folders[wizard.xauto.module], newname)
    if target.autoclass:
        if path.isdir(varfile):
            from fortpy.utility import copytree
            copytree(varfile, dst)
    else:
        if path.isfile(varfile):
            from fortpy.utility import copyfile
            copyfile(varfile, dst)

    return (newname, None)
Ejemplo n.º 2
0
def compile_general(folder, compiler=None, identifier=None, debug=False, profile=False,
                    quiet=False, moptions=None, inclfortpy=True, vupdates=None, strict=False):
    """Same as for compile() but the folder is assumed to be generic and a copy of it
    is made for the specific compiler that we are dealing with.
    """
    #Because we often run the tests for multiple compiler versions, we need
    #a copy of the execution directory that was setup for the testing.
    from fortpy.utility import copytree
    from os import path
    target = replace(folder + ".[c]", compiler)
    copytree(folder, target)
    
    code, success = compile(target, compiler, identifier, debug, profile, quiet, moptions, inclfortpy)
    return (code, success, target)
Ejemplo n.º 3
0
def compile_general(folder,
                    compiler=None,
                    identifier=None,
                    debug=False,
                    profile=False,
                    quiet=False,
                    moptions=None,
                    inclfortpy=True,
                    vupdates=None,
                    strict=False):
    """Same as for compile() but the folder is assumed to be generic and a copy of it
    is made for the specific compiler that we are dealing with.
    """
    #Because we often run the tests for multiple compiler versions, we need
    #a copy of the execution directory that was setup for the testing.
    from fortpy.utility import copytree
    from os import path
    target = replace(folder + ".[c]", compiler)
    copytree(folder, target)

    code, success = compile(target, compiler, identifier, debug, profile,
                            quiet, moptions, inclfortpy, vupdates, strict)
    return (code, success, target)
Ejemplo n.º 4
0
    def _run_compile(self, identifier, testid):
        """Compiles the executable that was created for the specified identifier,
        returns True if the compile was successful."""
        #Because we often run the tests for multiple compiler versions, we need
        #a copy of the execution directory that was setup for the testing.
        from fortpy.testing.compilers import replace, executor, family
        from fortpy.utility import copytree
        from os import path
        source = path.join(self.libraryroot(identifier), identifier)        
        target = replace(source + ".[c]", self.compiler)
        copytree(source, target)

        #Before we compile, we need to make sure we have the fortpy.o and fortpy.mod
        #files for the specific compiler.
        tversion = self.template_version("fortpy.f90")
        for sdfile in ["fortpy.o", "fortpy.mod"]:
            fdfile = replace(sdfile + ".[c]", self.compiler)
            ftarget = path.join(target, sdfile)
            dversion = self.get_fortpy_version(ftarget)
                
            if not path.isfile(ftarget) or dversion != tversion:
                from shutil import copy
                source = path.join(self.fortpy_templates, fdfile)
                sversion = self.get_fortpy_version(source)
                if not path.isfile(source) or sversion != tversion:
                    self._compile_fortpyf90(tversion)
                    
                msg.info("   COPY: {}".format(source))
                copy(source, ftarget)
                #If the file is a binary, we need to save a .v with version
                #information as well for the next time we want to copy it.
                pre, ext = path.splitext(ftarget)
                if ext in [".o", ".so", ".mod"]:
                    with open(ftarget + '.v', 'w') as f:
                        f.write("# <fortpy version=\"{}\" />".format('.'.join(map(str, tversion))))
        
        #Find the target folder that has the executables etc then run
        #make and check the exit code.
        msg.blank()
        options = ""
        if self.debug:
            options += " DEBUG=true"
        if self.profile:
            options += " GPROF=true"

        codestr = "cd {}; make -f 'Makefile.{}' F90='{}' FAM='{}'" + options
        #If we are running in quiet mode, we don't want the compile information
        #to post to stdout; only errors should be redirected. This means we need
        #to wrap the execution in a subprocess and redirect the std* to PIPE
        from os import waitpid
        from subprocess import Popen, PIPE
        command = codestr.format(target, testid, executor(self.compiler), family(self.compiler))
        pcompile = Popen(command, shell=True, executable="/bin/bash", stdout=PIPE, stderr=PIPE)
        waitpid(pcompile.pid, 0)
        
        if not self.quiet:
            output = [x.decode('utf8') for x in pcompile.stdout.readlines()]
            msg.std(''.join(output))
        #else: #We don't need to get these lines since we are purposefully redirecting them.
        error = pcompile.stderr.readlines()
        code = len(error)
        if code != 0:
            msg.err(''.join(error))

        #It turns out that the compiler still returns a code of zero, even if the compile
        #failed because the actual compiler didn't fail; it did its job properly. We need to
        #check for the existence of errors in the 'compile.log' file.
        lcount = 0
        errors = []
        log = path.join(target, "compile.log")
        with open(log) as f:
            for line in f:
                lcount += 1
                if lcount > 21 and lcount < 32:
                    errors.append(line)
                elif lcount > 21:
                    break

        if len(errors) > 0:
            #There are 21 lines in the compile.log file when everything runs correctly
            #Overwrite code with a bad exit value since we have some other problems.
            code = 1
            #We want to write the first couple of errors to the console and give them the
            #option to still execute if the compile only generated warnings.
            msg.warn("compile generated some errors or warnings:")
            msg.blank()
            msg.info(''.join(errors))

            #If the executable exists, we could still prompt them to run it (in case the
            #additional lines were just warnings).
            exe = path.join(target, "{}.x".format(testid))
            if path.isfile(exe):
                choice = input("\nWould you still like to run the executable? ").lower()
                code = 0 if "y" in choice else code
                if "n" in choice:
                    msg.err("Unit testing terminated by user.")
                    exit(0)
            else:
                msg.err("Could not compile executable {}.x".format(testid))
                exit(-1)

        return code == 0, target