示例#1
0
def compile_model_solution(sender, instance, **kwargs):
    # If source file was not changed no need to re-compile.
    if not hasattr(instance, 'source_changed'): 
        return

    if not kwargs.get('created'):
        print "Not created!"

    programFilePath = instance.program_files.name
    ModelSolutionPath = instance.model_solution.name
    
    # Model Solution was not provided hence do nothing.
    if os.path.isdir(ModelSolutionPath):
        return

    os.chdir(tmpDir)

    extractFile(os.path.join(MEDIA_ROOT, ModelSolutionPath), tmpDir)

    # Change directory if solution tar contains a directory.
    if os.path.isdir(os.listdir('./')[0]):
        os.chdir(os.listdir('./')[0])

    currentDir = os.getcwd()
    extractFile(os.path.join(MEDIA_ROOT, programFilePath), currentDir)

    # Setting up compilation and creating CommandExecutor
    executor = CommandExecutor(timeout=5)
    command = get_compilation_command(instance)
    ''' To Remove: COMPILER_FLAGS
    exeName = "exefile_" + str(instance.id)
    compilerFlags = instance.compiler_flags if instance.compiler_flags else ""
    command = instance.compiler_name + " " + compilerFlags\
                + " " + instance.file_names_to_compile + " " + " -o " + exeName
    '''
    compileResult = executor.executeCommand(command=command)

    # Update output files on success
    if compileResult.returnCode == 0: 
        instance.UpdateOutput()
    cleanUp()
示例#2
0
def compile_model_solution(sender, instance, **kwargs):
    # If source file was not changed no need to re-compile.
    if not hasattr(instance, 'source_changed'):
        return

    if not kwargs.get('created'):
        print "Not created!"

    programFilePath = instance.program_files.name
    ModelSolutionPath = instance.model_solution.name

    # Model Solution was not provided hence do nothing.
    if os.path.isdir(ModelSolutionPath):
        return

    os.chdir(tmpDir)

    extractFile(os.path.join(MEDIA_ROOT, ModelSolutionPath), tmpDir)

    # Change directory if solution tar contains a directory.
    if os.path.isdir(os.listdir('./')[0]):
        os.chdir(os.listdir('./')[0])

    currentDir = os.getcwd()
    extractFile(os.path.join(MEDIA_ROOT, programFilePath), currentDir)

    # Setting up compilation and creating CommandExecutor
    executor = CommandExecutor(timeout=5)
    command = get_compilation_command(instance)
    ''' To Remove: COMPILER_FLAGS
    exeName = "exefile_" + str(instance.id)
    compilerFlags = instance.compiler_flags if instance.compiler_flags else ""
    command = instance.compiler_name + " " + compilerFlags\
                + " " + instance.file_names_to_compile + " " + " -o " + exeName
    '''
    compileResult = executor.executeCommand(command=command)

    # Update output files on success
    if compileResult.returnCode == 0:
        instance.UpdateOutput()
    cleanUp()
示例#3
0
class CustomTestcase(object):
    def __init__(self, inputFile, program, submission):
        # Setting section of the testcase, submission to use, the input file given by the student and the command executor that runs the commands.
        self.program = program
        self.submission = submission
        self.inputFile = inputFile
        self.commandExecutor = CommandExecutor()
        self.eval_dir = os.path.join(PROJECT_ROOT, '../evaluate/safeexec')

    def get_resource_limit(self):
        # Return default values because there is no setting for custom testcase.
        return {'cpu_time':10, 'clock_time':10,
                'memory': 32768, 'stack_size': 8192, 'child_processes': 0,
                'open_files': 512, 'file_size': 1024,
            }

    # Store the input file that student uploaded  
    def store_input_file(self, inputFile, dest):
        file_path = os.path.join(dest, inputFile.name.split('/')[-1])
        destination = open(file_path, 'wb+')

        # Work-around to support file and InMemoeryUploadedFile objects
        if hasattr(inputFile, 'chunks'):
            all_file = inputFile.chunks()
        else:
            all_file = inputFile

        # Write everything to the input file represented by destination object. Then return the full path of file name.
        for chunk in all_file:
            destination.write(chunk)
        destination.close()
        return file_path

    # Function to setup the environment (input file, solution files and submission files) before running the code.
    def setup(self):
        # This is the directory where the student program is copied to.
        self.temp_dir = tempfile.mkdtemp(prefix="grader", dir=self.eval_dir)
        os.chdir(self.temp_dir)

        # Copy student solution files to tmp directory.
        extract_or_copy(src=self.submission.filePath.file.name, dest=self.temp_dir)

        # Another temp directory for running solution program. This is the directory where the solution program is copied to.
        self.solution_temp_dir = tempfile.mkdtemp(prefix="solution", dir=self.eval_dir)
        
        directories = [a for a in os.listdir('./') if os.path.isdir(a)]
        if directories:
            os.chdir(directories[0])
        currentDir = os.getcwd()

        # Extract the program file and the input file to the student directory, and the input file to the program directory as well.
        extract_or_copy(src=self.program.program_files.file.name, dest=currentDir)
        self.submittedFiles = get_file_name_list(name=self.submission.filePath.file.name)
        input_file = self.store_input_file(self.inputFile, currentDir)
        shutil.copy(src=input_file, dst=self.solution_temp_dir)

    # Function to compile the student program.
    def compile(self):
        self.exe_file = str(self.program.id)
        compiler_command = " ".join(pickle.loads(self.program.compiler_command)) + " -o " + self.exe_file
        self.compileResult = self.commandExecutor.executeCommand(command=compiler_command)

    # Function to run the student and model solution on the input file.
    def run(self):
        # Run student exe file.
        _, self.actual_stdout = tempfile.mkstemp(dir='./')
        os.chmod(self.actual_stdout, 0777)

        runStudentProgram = "./" + self.exe_file + " < " + self.inputFile.name
        self.actualOutput = self.commandExecutor.safe_execute(
                                                        command=runStudentProgram,
                                                        limits=self.get_resource_limit()
                                                    )

        # Run solution exe file.
        shutil.copy(src=self.program.exe_file_name.file.name, dst=self.solution_temp_dir)
        os.chdir(self.solution_temp_dir)
        _, self.expected_stdout = tempfile.mkstemp(dir='./')
        os.chmod(self.expected_stdout, 0777)
        exe = self.program.exe_file_name.name.split('/')[-1]
        runSolutionProgram = "./" + exe + " < " + self.inputFile.name

        self.expectedOutput = self.commandExecutor.safe_execute(
                                                        command=runSolutionProgram,
                                                        limits=self.get_resource_limit()
                                                    )
        self.passed = self.testPassed()

    # This function is called after run(), and checks the actual and the expected output.
    def testPassed(self):
        # At this point actual o/p is in self.actual_stdout and expected O/P is in self.expected_stdout.
        # compare them and display result on browser.

        if not (self.expectedOutput.returnCode == 0 and self.actualOutput.returnCode == 0):
            return False

        exp_op = iter(self.expectedOutput.get_stdout())
        act_op = iter(self.actualOutput.get_stdout())

        if len(self.expectedOutput.get_stdout()) > len(self.actualOutput.get_stdout()):
            return False

        for line1, line2 in zip(exp_op, act_op):
            if line1.strip() != line2.strip():
                return False
    
        for line2 in act_op:
            if line2.strip() != "":
                return False
        return True

    # This is the function called to get the result once the input file is uploaded.
    def getResult(self):
        # Setup the environment.
        self.setup()
        # Compile the program.
        self.compile()
        # If compilation is successful then run the program.
        if self.compileResult.returnCode == 0:
            self.run()
        # Clean up the temporary directories.
        self.cleanUp()
        return self

    # Function to clean up the temporary directories.
    def cleanUp(self):
        shutil.rmtree(self.temp_dir, ignore_errors=True)
示例#4
0
def compile_solution(sender, instance, **kwargs):

    # If the program language is an interpreted language, then we dont do anything
    if not compile_required(instance.assignment.program_language) and not getattr(instance, 'execute_now', False):
        instance.set_sane()
        instance.delete_error_message()
        return

    if not compile_required(instance.assignment.program_language) :
        old_pwd = os.getcwd()
        instance.set_sane()
        instance.UpdateOutput()
        instance.delete_error_message()
        os.chdir(old_pwd)
        return

    # instance.id would indicate that record was not created.
    if not getattr(instance, 'compile_now', False) or instance.id is None: 
        return

    # If solution is given then set the path, else do nothing
    programFilePath = instance.program_files.name
    if hasattr(instance.assignment.model_solution, 'file'):
        ModelSolutionPath = instance.assignment.model_solution.file.name
    else:
        instance.set_sane()
        instance.delete_error_message()
        return 

    # Model Solution was not provided hence do nothing.
    if not os.path.isfile(ModelSolutionPath):
        return

    # Copying module solution to a temp directory for compilation
    tmp_dir = tempfile.mkdtemp(prefix='grader')
    old_pwd = os.getcwd()
    os.chdir(tmp_dir)
    currentDir = os.getcwd()
    try:
        # Copy model solution to temp directory.
        with Archive(fileobj=instance.assignment.model_solution.file) as archive:
            if archive.is_archive():
                archive.extract(dest=currentDir)
            else:
                shutil.copy(src=os.path.join(MEDIA_ROOT, ModelSolutionPath), dst=currentDir)

        # Change directory if solution tar contains a directory.
        directories = [a for a in os.listdir('./') if os.path.isdir(a)]
        if directories:
            os.chdir(directories[0])
            currentDir = os.getcwd()

        # Copying the program files to the current directory
        if instance.program_files:
            with Archive(name=instance.program_files.file.name) as archive:
                if archive.is_archive():
                    archive.extract(dest=currentDir)
                else:
                    shutil.copy(src=os.path.join(MEDIA_ROOT, programFilePath), dst=currentDir)

        # Setting up compilation process and calling the CommandExecutor with appropriate command
        executor = CommandExecutor(timeout=100)
        compiler_command = get_compilation_command(instance)
        compileResult = executor.executeCommand(command=compiler_command)

        # Compilation successful => Set the program to sane and delete errors, else report the errors.
        if compileResult.returnCode == 0: # save exe file on success.
            instance.is_sane = True
            instance.UpdateOutput()
            instance.delete_error_message()
        else:
            message = "Compilation failed.\nReturn code = {0}.\nError message={1}".format(compileResult.returnCode, "".join(compileResult.stderr))
            print "Instructor solution not sane - " + message
            instance.save_error(message)
        shutil.rmtree(tmp_dir)
    finally:
        os.chdir(old_pwd)
示例#5
0
class Program(object):
    def __init__(self, program, assignment_result):
        self.assignment_result = assignment_result
        self.program = program

        # Extracting the list of files relevant to only this section.
        if program.program_files:
            prgrm_files = get_file_name_list(name=program.program_files.file.name)
            prgrm_files = " ".join(prgrm_files)
        else:
            prgrm_files = ""

        # Adding the list of files in the assignment model solution to the above list.
        self.programFiles = program.assignment.student_program_files + " " + prgrm_files
        self.language = program.assignment.program_language
        self.compiler_command = get_compilation_command(program)
        self.execution_command = get_execution_command(program)
        self.commandExecutor = CommandExecutor()

    # Function to check if any files are missing.
    def fileExist(self):
        self.missingFiles = []

        # Checking if each file in the self.programFiles variable is valid. If not add to the missing files array.
        for aFile in self.programFiles.split():
            if not os.path.isfile(aFile):
                self.missingFiles.append(aFile)

        # If there are any missing files, then either retrieve existing program result object or create one with the assignment result, section
        # and the missing files. If the object was not created, then update the missing files attribute of the program result.
        # Save the new or existing program result object after this, and return if there were any files missing.
        if self.missingFiles:
            self.programResult, created = ProgramResults.objects.get_or_create(
                                            assignment_result = self.assignment_result,
                                            program = self.program,
                                            defaults = {'missing_file_names': "\n".join(self.missingFiles)}
                                        )
            if not created:
                self.programResult.missing_file_names = "\n".join(self.missingFiles)

            self.programResult.save()
        return bool(self.missingFiles)
            
    # Function to handle compilation of the section.
    def compile(self):

        # If any files are missing then return failure of compilation. Appropriate program result is created.
        if self.fileExist():
            return False

        # If the language of the section/assignment needs compilation, then go ahead and compile. Set program result attributes accordingly.
        # If compilation is not needed then proceed.
        if compile_required(self.language):
            compilation_command = self.compiler_command
            self.compileResult = self.commandExecutor.executeCommand(command=compilation_command)
            attrs = {'missing_file_names': "\n".join(self.missingFiles),
                 'compiler_errors': "".join(self.compileResult.stderr),
                 'compiler_output': "\n".join(self.compileResult.get_stdout()),
                 'compiler_return_code': int(self.compileResult.returnCode)}
        else:
            attrs = {'missing_file_names': "\n".join(self.missingFiles),
                 'compiler_errors': "",
                 'compiler_output': "",
                 'compiler_return_code': 0}
        filter_attrs = {'assignment_result': self.assignment_result, 'program': self.program}

        # Create or update program result object with the result of compilation process for the section. The attributes of the program result object
        # are the same as the result of the compilation process.
        try: # create_or_update equivalent.
            obj = ProgramResults.objects.filter(**filter_attrs)
            obj.update(**attrs)
            self.programResult = obj[0:1].get()
        except ProgramResults.DoesNotExist:
            attrs.update(filter_attrs)
            self.programResult = ProgramResults.objects.create(**attrs)

        # If compilation is successful or if compilation is not needed then return true. Else return false.
        if compile_required(self.language) == False or self.compileResult.returnCode == 0:
            return True
        else:
            return False

    # Function to run the student solution on all the testcases of the section.
    def run(self):
        # Filter out the testcases of the section.
        testcases = Testcase.objects.filter(program=self.program)

        # Run the execution command on each of the testcases. Compilation (if needed) is already taken care of.
        for test in testcases:
            testcase = TestCase(test, self.programResult)
            testcase.run(self.execution_command)
示例#6
0
class Program(object):
    def __init__(self, program, assignment_result):
        self.assignment_result = assignment_result
        self.program = program

        # Extracting the list of files relevant to only this section.
        if program.program_files:
            prgrm_files = get_file_name_list(
                name=program.program_files.file.name)
            prgrm_files = " ".join(prgrm_files)
        else:
            prgrm_files = ""

        # Adding the list of files in the assignment model solution to the above list.
        self.programFiles = program.assignment.student_program_files + " " + prgrm_files
        self.language = program.assignment.program_language
        self.compiler_command = get_compilation_command(program)
        self.execution_command = get_execution_command(program)
        self.commandExecutor = CommandExecutor()

    # Function to check if any files are missing.
    def fileExist(self):
        self.missingFiles = []

        # Checking if each file in the self.programFiles variable is valid. If not add to the missing files array.
        for aFile in self.programFiles.split():
            if not os.path.isfile(aFile):
                self.missingFiles.append(aFile)

        # If there are any missing files, then either retrieve existing program result object or create one with the assignment result, section
        # and the missing files. If the object was not created, then update the missing files attribute of the program result.
        # Save the new or existing program result object after this, and return if there were any files missing.
        if self.missingFiles:
            self.programResult, created = ProgramResults.objects.get_or_create(
                assignment_result=self.assignment_result,
                program=self.program,
                defaults={'missing_file_names': "\n".join(self.missingFiles)})
            if not created:
                self.programResult.missing_file_names = "\n".join(
                    self.missingFiles)

            self.programResult.save()
        return bool(self.missingFiles)

    # Function to handle compilation of the section.
    def compile(self):

        # If any files are missing then return failure of compilation. Appropriate program result is created.
        if self.fileExist():
            return False

        # If the language of the section/assignment needs compilation, then go ahead and compile. Set program result attributes accordingly.
        # If compilation is not needed then proceed.
        if compile_required(self.language):
            compilation_command = self.compiler_command
            self.compileResult = self.commandExecutor.executeCommand(
                command=compilation_command)
            attrs = {
                'missing_file_names': "\n".join(self.missingFiles),
                'compiler_errors': "".join(self.compileResult.stderr),
                'compiler_output': "\n".join(self.compileResult.get_stdout()),
                'compiler_return_code': int(self.compileResult.returnCode)
            }
        else:
            attrs = {
                'missing_file_names': "\n".join(self.missingFiles),
                'compiler_errors': "",
                'compiler_output': "",
                'compiler_return_code': 0
            }
        filter_attrs = {
            'assignment_result': self.assignment_result,
            'program': self.program
        }

        # Create or update program result object with the result of compilation process for the section. The attributes of the program result object
        # are the same as the result of the compilation process.
        try:  # create_or_update equivalent.
            obj = ProgramResults.objects.filter(**filter_attrs)
            obj.update(**attrs)
            self.programResult = obj[0:1].get()
        except ProgramResults.DoesNotExist:
            attrs.update(filter_attrs)
            self.programResult = ProgramResults.objects.create(**attrs)

        # If compilation is successful or if compilation is not needed then return true. Else return false.
        if compile_required(
                self.language) == False or self.compileResult.returnCode == 0:
            return True
        else:
            return False

    # Function to run the student solution on all the testcases of the section.
    def run(self):
        # Filter out the testcases of the section.
        testcases = Testcase.objects.filter(program=self.program)

        # Run the execution command on each of the testcases. Compilation (if needed) is already taken care of.
        for test in testcases:
            testcase = TestCase(test, self.programResult)
            testcase.run(self.execution_command)
示例#7
0
class CustomTestcase(object):
    def __init__(self, inputFile, program, submission):
        # Setting section of the testcase, submission to use, the input file given by the student and the command executor that runs the commands.
        self.program = program
        self.submission = submission
        self.inputFile = inputFile
        self.commandExecutor = CommandExecutor()
        self.eval_dir = os.path.join(PROJECT_ROOT, '../evaluate/safeexec')

    def get_resource_limit(self):
        # Return default values because there is no setting for custom testcase.
        return {
            'cpu_time': 10,
            'clock_time': 10,
            'memory': 32768,
            'stack_size': 8192,
            'child_processes': 0,
            'open_files': 512,
            'file_size': 1024,
        }

    # Store the input file that student uploaded
    def store_input_file(self, inputFile, dest):
        file_path = os.path.join(dest, inputFile.name.split('/')[-1])
        destination = open(file_path, 'wb+')

        # Work-around to support file and InMemoeryUploadedFile objects
        if hasattr(inputFile, 'chunks'):
            all_file = inputFile.chunks()
        else:
            all_file = inputFile

        # Write everything to the input file represented by destination object. Then return the full path of file name.
        for chunk in all_file:
            destination.write(chunk)
        destination.close()
        return file_path

    # Function to setup the environment (input file, solution files and submission files) before running the code.
    def setup(self):
        # This is the directory where the student program is copied to.
        self.temp_dir = tempfile.mkdtemp(prefix="grader", dir=self.eval_dir)
        os.chdir(self.temp_dir)

        # Copy student solution files to tmp directory.
        extract_or_copy(src=self.submission.filePath.file.name,
                        dest=self.temp_dir)

        # Another temp directory for running solution program. This is the directory where the solution program is copied to.
        self.solution_temp_dir = tempfile.mkdtemp(prefix="solution",
                                                  dir=self.eval_dir)

        directories = [a for a in os.listdir('./') if os.path.isdir(a)]
        if directories:
            os.chdir(directories[0])
        currentDir = os.getcwd()

        # Extract the program file and the input file to the student directory, and the input file to the program directory as well.
        extract_or_copy(src=self.program.program_files.file.name,
                        dest=currentDir)
        self.submittedFiles = get_file_name_list(
            name=self.submission.filePath.file.name)
        input_file = self.store_input_file(self.inputFile, currentDir)
        shutil.copy(src=input_file, dst=self.solution_temp_dir)

    # Function to compile the student program.
    def compile(self):
        self.exe_file = str(self.program.id)
        compiler_command = " ".join(pickle.loads(
            self.program.compiler_command)) + " -o " + self.exe_file
        self.compileResult = self.commandExecutor.executeCommand(
            command=compiler_command)

    # Function to run the student and model solution on the input file.
    def run(self):
        # Run student exe file.
        _, self.actual_stdout = tempfile.mkstemp(dir='./')
        os.chmod(self.actual_stdout, 0777)

        runStudentProgram = "./" + self.exe_file + " < " + self.inputFile.name
        self.actualOutput = self.commandExecutor.safe_execute(
            command=runStudentProgram, limits=self.get_resource_limit())

        # Run solution exe file.
        shutil.copy(src=self.program.exe_file_name.file.name,
                    dst=self.solution_temp_dir)
        os.chdir(self.solution_temp_dir)
        _, self.expected_stdout = tempfile.mkstemp(dir='./')
        os.chmod(self.expected_stdout, 0777)
        exe = self.program.exe_file_name.name.split('/')[-1]
        runSolutionProgram = "./" + exe + " < " + self.inputFile.name

        self.expectedOutput = self.commandExecutor.safe_execute(
            command=runSolutionProgram, limits=self.get_resource_limit())
        self.passed = self.testPassed()

    # This function is called after run(), and checks the actual and the expected output.
    def testPassed(self):
        # At this point actual o/p is in self.actual_stdout and expected O/P is in self.expected_stdout.
        # compare them and display result on browser.

        if not (self.expectedOutput.returnCode == 0
                and self.actualOutput.returnCode == 0):
            return False

        exp_op = iter(self.expectedOutput.get_stdout())
        act_op = iter(self.actualOutput.get_stdout())

        if len(self.expectedOutput.get_stdout()) > len(
                self.actualOutput.get_stdout()):
            return False

        for line1, line2 in zip(exp_op, act_op):
            if line1.strip() != line2.strip():
                return False

        for line2 in act_op:
            if line2.strip() != "":
                return False
        return True

    # This is the function called to get the result once the input file is uploaded.
    def getResult(self):
        # Setup the environment.
        self.setup()
        # Compile the program.
        self.compile()
        # If compilation is successful then run the program.
        if self.compileResult.returnCode == 0:
            self.run()
        # Clean up the temporary directories.
        self.cleanUp()
        return self

    # Function to clean up the temporary directories.
    def cleanUp(self):
        shutil.rmtree(self.temp_dir, ignore_errors=True)