# -*- coding: utf-8 -*-
# $Id: ProgrammingBackend.py 1634 2013-04-12 15:36:36Z amelung $
#
# Copyright (c) 2007-2011 Otto-von-Guericke-Universität Magdeburg
#
# This file is part of ECSpooler.
#import sys, os, re, popen2, tempfile, threading, signal, traceback
import shutil
import logging
import config
try:
except AttributeError:
try:
except AttributeError:
"""
ProgrammingBackend is the basic class of all backends for
programming exercises.
Backend implementations *should* be derived from this class and must
implement the following methods:
process_checkSyntax(self) -> (code, message)
... test the student solution for syntactical correctness.
process_checkSemantics(self) -> (code, message)
... test the student solution for semantical correctness using input data.
"""
# set in subclasses
# resourcestring
# set default time (in seconds) before killing a test job's execution
"""
This constructor is needed to reset the logging environment.
"""
"""
Executes a check job.
@param: job: a BackendJob with all relevant test data
@return: a BackendResult
@see: BackendJob, BackendResult
@see: Backend.execute, Backend._process_execute
"""
try:
# invoke syntax check
# FIXME: If the returned value is always of typ
# BackendResult we could use isFailure!
#if not result.hasFailed:
if result:
# invoke semantic check
# end if
# end if
except Exception, e:
# delete all files and folders used in this test
return result
# -- check syntax ---------------------------------------------------------
"""
Manages the syntax check for a given job depending on the
selected test scenarios. The syntax check itself will be
done in process_checkSyntax.
@param: job: a BackendJob
@return: a BackendResult
"""
# test for available test specs
# test for available test specs
msg = 'No test specification selected.'
# get the names of all test enrironments selected in this job
# process syntax check for each test environment
job.getSubmission())
# if there is an result probably an error occoured
"""
Tests the syntax of a programm. Override this method if you need to
do some special things during syntax check.
@param: jobId: ID for this test job
@param: test: name of the selected test environment (cf. self.testSchema)
@return: a BackendResult or None if test succeeded
"""
# get the compiler or if not available the interpreter
#LOG.debug("testSpec.compiler: %s" % repr(testSpec.compiler))
#LOG.debug("testSpec.interpreter: %s" % repr(testSpec.interpreter))
#LOG.debug("compiler: %s" % repr(compiler))
if compiler:
try:
# test term (e.g., student's source code)
try:
except AssertionError, ae:
#LOG.debug(repr(module))
#LOG.debug('exitcode: %s' % repr(exitcode))
#LOG.debug('result: %s' % repr(result))
except Exception, e:
msg = 'Internal error during syntax check: %s: %s' % \
# consider exit code
#return BackendResult(-exitcode, result or repr(-exitcode))
else:
msg = 'No compiler/interpreter defined (test spec: %s).' \
# everything seems to be ok
return None
"""
Pre process student's submissions and syntax check wrapper code.
Override this method if you need to reformat the wrapper code or
the student's submission.
@param: test
@param: src
@return: source and module name if needed
"""
result = ''
#result = re.sub('\$\{SOURCE\}', src, test.syntax)
else:
return result, None
"""
Post process interpreter messages. Override this method if you need
to remove or reformat messages.
@param: message
"""
return message
# -- check semantics ------------------------------------------------------
"""
"""
"""
"""
# overwrite this method
raise NotImplementedError("Method _process_checkSemantics must be "
"implemented by a subclass")
"""
Pre process student's submissions and semantic check wrapper code.
Override this method if you need to reformat the wrapper code or
the student's submission.
@param: test
@param: src
@return: source and module name if needed
"""
return src, None
"""
Post process interpreter messages. Override this method if you need
to remove or reformat messages.
@param: message
"""
return message
# -- helper methods -------------------------------------------------------
"""
Creates a new module. Returns the module's name and
absolute path in a tuple object.
@return: a dictonary with keys module and file
"""
if not name:
#LOG.debug('%s' % tempfile.gettempdir())
#LOG.debug('%s' % dir)
#LOG.debug('%s' % name)
#LOG.debug('%s' % suffix)
# get file name
# write file
#os.chmod(os.path.dirname(fName), 01777)
# get modul name
#mName = os.path.basename(fName).replace(suffix, '')
#def _execute(self, command, options, dir, fName)
"""
Change the current working directory to dir and runs the given
interpreter with the given file. Availability: Unix.
@param: command command which will be executed
@param: options options for command including flags as list
@param: dir path to which we will change the current working directory
@param: fName name of the file which will be called with the interpreter
@param: args command line arguments that fName will be called with
@return: exitcode and result message, normally something like os.EX_OK
"""
# change dir to current job dir
args_encoded = []
options_encoded = []
#LOG.debug('args: %s' % repr(args))
#LOG.debug('options: %s' % repr(options))
else:
else:
#LOG.debug('args_encoded: %s' % repr(args_encoded))
#LOG.debug('options_encoded: %s' % repr(options_encoded))
# create a list of alle command line elements
commandLine = [command]
else:
# we use subprocess
dir,
# This method will be called in a timer thread to ensure that
# handle will be killed after PROCESS_WAIT_TIME
def interruptProcess():
try:
except AttributeError:
# we will do nothing in this case
pass
# end interruptProcess
# read stdout while communicating with process
# cancel time; process has been finished normaly before PROCESS_WAIT_TIME
# check exitcode
# process has been interrupted by timer
#os.remove(fName)
return exitcode, 'Function call cancelled after %i seconds. ' \
'Check for infinite loops.' \
% (self.PROCESS_WAIT_TIME,)
#LOG.debug('exitcode: %s' % repr(exitcode))
#LOG.debug('stdout: %s' % repr(stdout))
# removing files will be done in _cleanup
# concat result message
if (stderr == None):
else:
"""
Delete the entire directory tree for path.
@directory a directory in temporary path
"""
return
try:
# change directory
# delete the entire directory tree
except Exception, e: