Example #1
0
def update(data: DataDirectory) -> None:
    backend = data.get_backend().client

    current = get_current_version()
    available = backend.get_current_version()

    if current < available:
        interface_print("Update available")

        if prompt("Do you want to view the changelog?", YesNoParser(True)):
            changelogs = backend.get_changelogs()

            for key in sorted(changelogs.keys()):
                interface_print("=== Changes in version %s ===" % str(key))
                interface_print(changelogs[key])
                interface_print()

        if prompt("Do you want to download the update now?",
                  YesNoParser(True)):
            with TemporaryDirectory() as temp_dir:
                path = Path(temp_dir) / "client.tgz"

                with path.open("wb") as f:
                    f.write(backend.get())

                with tarfile.open(str(path)) as f:
                    f.extractall(str(Path.cwd().parent))

                interface_print("Update complete. Restarting script.")
                execute_subprocess(["./main.sh"], capture_output=False)
                exit(0)
Example #2
0
def main():
    root_directory = Path.cwd().parent.parent
    data_directory = DataDirectory(Path.cwd().parent / "data")

    set_global_log_file(data_directory.create_logfile())

    bootstrap_log_path = Path("bootstrap.log")
    if bootstrap_log_path.is_file():
        global_log_file.log("Bootstrap log:\n%s" %
                            bootstrap_log_path.open().read())

    interface_print("=== Welcome ===")

    update(data_directory)

    check_for_new_results(data_directory)
    ensure_team_existence(data_directory)

    def start_submission():
        interface_print()
        success = submit(root_directory, data_directory)
        interface_print()

        if success:
            if prompt("Do you want to submit another solution?",
                      YesNoParser(True)):
                start_submission()
        else:
            if prompt("Do you want to try again?", YesNoParser(True)):
                start_submission()

    if prompt("Do you want to submit a solution now?", YesNoParser(True)):
        start_submission()
Example #3
0
def check_for_new_results(data_directory: DataDirectory):
    # Check every submission for new results
    try:
        for assignment in data_directory.get_assignments():
            for submission in assignment.get_submissions():
                if not submission.bookkeeping_data.get(
                ).status == SubmissionStatus.accepted:
                    continue

                if submission.check_for_evaluation_results():
                    submission.print_evaluation_results()
                    continue

                # Check if the submission still exists (may have been removed) and if it is eligible for result subscription
                if submission.bookkeeping_data.get(
                ).status == SubmissionStatus.accepted and submission.submission_response.get(
                ).immediate_evaluation:
                    if prompt(
                            "Do you want to subscribe to the results of submission %s?"
                            % submission.submission_data.get().submission_id,
                            YesNoParser(True)):
                        submission.wait_for_evaluation_results()
    except Exception as e:
        global_log_file.error("".join(
            traceback.format_exception(*sys.exc_info())))

        # Errors when checking for new results should never prevent students from submitting, so we are a fault tolerant.
        interface_print("Error while checking for new results: %s" % str(e))
        interface_print(
            "Please report this issue. You will still be able to submit a solution."
        )
Example #4
0
def prompt(description: str, input_parser: InputParser):
    while True:
        result = input_parser.parse(input("%s %s " % (description, input_parser.get_format_description())))

        if result is None:
            interface_print("Sorry, again.")
            continue

        return result
Example #5
0
def submit(root_directory: Path, data: DataDirectory) -> bool:
    """
    :returns Whether a solution was submitted.
    """
    interface_print("=== Submitting ===")

    submission = None
    try:
        selected_assignment = select_assignment(data.get_assignments())
        interface_print()
        if selected_assignment is None:
            return False

        selected_variant = select_variant(root_directory, data)
        interface_print()

        if selected_variant is None:
            return False

        interface_print(
            "Selected variant '%s' for assignment '%s'." %
            (selected_variant.name, selected_assignment.assignment_id))

        submission = selected_assignment.create_submission()

        submission.team.set(data.team.get())
        submission.variant.set(selected_variant.variant_data)

        # Create temporary directory to build submission.
        with tempfile.TemporaryDirectory() as tmpdir:
            tmp_solution_root = Path(tmpdir) / selected_variant.root
            shutil.copytree(root_directory / selected_variant.root,
                            tmp_solution_root)

            if not build_solution(tmp_solution_root, selected_variant):
                return False

            clean_directory(tmp_solution_root, selected_variant)

            with tempfile.TemporaryFile() as temp_file:
                with tarfile.open(fileobj=temp_file,
                                  mode='w:gz',
                                  format=tarfile.GNU_FORMAT) as tar:
                    tar.add(tmp_solution_root,
                            recursive=True,
                            arcname="/%s" % selected_variant.root)

                submission.set_upload_file(temp_file)

        return submission.submit()
    except KeyboardInterrupt:
        interface_print("=== Aborted Submitting ===")
        if submission is not None:
            submission.delete()
        return False
Example #6
0
    def start_submission():
        interface_print()
        success = submit(root_directory, data_directory)
        interface_print()

        if success:
            if prompt("Do you want to submit another solution?",
                      YesNoParser(True)):
                start_submission()
        else:
            if prompt("Do you want to try again?", YesNoParser(True)):
                start_submission()
Example #7
0
def create_team_json(data: DataDirectory) -> None:
    members = []
    interface_print("A new team.json will now be created.\n")

    while True:
        members.append(prompt_student(len(members) + 1))

        if len(members) >= data.config.get().max_team_size or not prompt(
                "Another?", YesNoParser(True)):
            break

    data.team.set(Team(members))

    interface_print("team.json successfully created.\n")
Example #8
0
    def check_for_evaluation_results(self) -> Optional[bool]:
        if not self.bookkeeping_data.has_value():
            interface_print(
                "Error: There appears to be a data corruption. Bookkeeping data for a submission are missing."
            )
            return None

        if self.bookkeeping_data.get().status != SubmissionStatus.accepted:
            interface_print(
                "Error: Can only check for results of accepted submissions. Please report this as a bug in the script."
            )
            return None

        evaluated = self.get_backend().is_evaluated()

        if evaluated is None:
            interface_print(
                "- Submission '%s' can no longer be found on the server and will be marked as [removed]."
                % self.submission_data.get().submission_id)
            self.set_status(SubmissionStatus.removed)
            return None
        elif evaluated:
            self.submission_data.set(self.get_backend().get(True))
            self.evaluation_log.set(
                self.submission_data.get().evaluation_result.log)

            self.set_status(SubmissionStatus.evaluated)

            interface_print(
                "\n=== Evaluation results for submission '%s' retrieved. ===" %
                self.submission_data.get().submission_id)

            return True

        return False
Example #9
0
def ensure_team_existence(data: DataDirectory,
                          can_be_skipped: bool = False) -> None:
    if not data.team.has_value():
        interface_print(
            "There is no team.json saved yet. You will need to provide information about your team before you can submit solutions."
        )
        if not can_be_skipped or prompt(
                "Do you want to create a team.json now?", YesNoParser(True)):
            create_team_json(data)
    else:
        interface_print(
            "Please review the currently saved information about your team:")

        i = 1
        for member in data.team.get().members:
            interface_print(
                " %d - First name: %s; Last name: %s; Matriculation number: %s"
                % (i, member.first_name, member.last_name,
                   member.matriculation_number))
            i += 1

        if not prompt("Is this information up to date?", YesNoParser(True)):
            create_team_json(data)

        interface_print()
Example #10
0
def clean_directory(directory: Path, selected_variant: SkeletonVariant):
    def clean_helper(path: Path):
        if path.is_file():
            str(path.relative_to(directory))

            if not selected_variant.is_filename_allowed(
                    str(path.relative_to(directory))):
                path.unlink()
        elif path.is_dir():
            for child in path.iterdir():
                clean_helper(child)
            if not any(path.iterdir()):
                path.rmdir()

    interface_print("=== Cleaning directory for submission ===")
    clean_helper(directory)
    interface_print("=== Cleaning directory finished ===")
Example #11
0
def select_variant(root_directory: Path,
                   data: DataDirectory) -> Optional[SkeletonVariant]:
    found_options = [
        v for v in data.config.get().skeleton_variants
        if (root_directory / v.root).is_dir()
    ]

    if len(found_options) == 0:
        interface_print(
            "No skeleton variant found! Did you delete all of them?")
        return None

    if len(found_options) == 1:
        return found_options[0]

    return prompt("Please choose the variant you want to submit.",
                  SelectionParser([(a.name, a) for a in found_options], None))
Example #12
0
def prompt_student(member_number: int) -> Student:
    while True:
        interface_print("Please enter details of team member %d." %
                        member_number)

        lastname = prompt("Last Name:", NameParser())
        firstname = prompt("First Name:", NameParser())
        matriculation_number = prompt("Matriculation number:",
                                      MatriculationNumberParser())

        member = Student(lastname, firstname, matriculation_number)

        interface_print()
        interface_print(
            "First name: %s; Last name: %s; Matriculation number: %s" %
            (member.first_name, member.last_name, member.matriculation_number))

        if prompt("Is this correct?", YesNoParser(False)):
            return member
Example #13
0
    def wait_for_evaluation_results(self) -> bool:
        interface_print("Polling for results (Press CTRL + C to abort).",
                        end="")

        try:
            import time

            while True:
                results_found = self.check_for_evaluation_results()

                if results_found:
                    self.print_evaluation_results()
                    break
                if results_found is None:
                    break

                interface_print(".", end="", flush=True)
                time.sleep(1)

        except KeyboardInterrupt:
            interface_print("\nResult polling aborted.")

        return True
Example #14
0
    def start_submission():
        interface_print()
        success = submit(root_directory, data_directory)
        interface_print()

        if success:
            if prompt("Do you want to submit another solution?",
                      YesNoParser(True)):
                start_submission()
        else:
            if prompt("Do you want to try again?", YesNoParser(True)):
                start_submission()

    if prompt("Do you want to submit a solution now?", YesNoParser(True)):
        start_submission()


if __name__ == '__main__':
    try:
        main()
    except requests.exceptions.ConnectionError as e:
        interface_print(
            "The server can not be reached. You may need to be logged in to the VPN."
        )
        interface_print("Aborting.")
        exit(1)
    except KeyboardInterrupt:
        interface_print(
        )  # Print a single linefeed to avoid having the new command prompt dangle in the same line as the last output line
        exit(0)
Example #15
0
    def submit(self) -> bool:
        interface_print("=== Starting Upload ===")
        self.submission_response.set(
            self.parent.get_backend().submissions.post(
                self.upload_tgz_path, self.variant.base_property.get(),
                self.team.base_property.get()))
        self.submission_data.set(self.submission_response.get().submission)
        self.submission_log.set(self.submission_response.get().log)

        interface_print("=== Upload finished ===")
        interface_print("=== BEGIN Upload Log")
        interface_print(self.submission_response.get().log)
        interface_print("=== END Upload Log")

        if not self.submission_response.get().accepted:
            interface_print(
                "Submitting your solution failed. Please see the upload log above for more details."
            )
            self.set_status(SubmissionStatus.rejected)
            return False
        else:
            interface_print(
                "Successfully submitted your solution. Please see the upload log above for more details."
            )
            self.set_status(
                SubmissionStatus.accepted,
                self.submission_response.get().submission.submission_id)

            if self.submission_response.get().immediate_evaluation:
                self.wait_for_evaluation_results()

            return True
Example #16
0
    def print_evaluation_results(self) -> None:
        score_percentage = \
            100 * self.submission_data.get().evaluation_result.score / self.submission_data.get().evaluation_result.max_score \
                if self.submission_data.get().evaluation_result.max_score != 0 \
                else 0

        interface_print(
            "You achieved the score %d/%d (%d%%)." %
            (self.submission_data.get().evaluation_result.score,
             self.submission_data.get().evaluation_result.max_score,
             score_percentage))

        if self.submission_data.get().evaluation_result.comment is not None:
            interface_print("The following comment was left by your teacher:")
            interface_print(
                self.submission_data.get().evaluation_result.comment)

        if self.submission_data.get().evaluation_result.passed:
            interface_print("You have PASSED this assignment.")
        else:
            interface_print("You have NOT PASSED this assignment.")

        if self.submission_data.get().evaluation_result.log is not None:
            if prompt("Do you want to view the evaluation log now?",
                      YesNoParser(True)):
                interface_print("=== BEGIN Evaluation Log")
                interface_print(
                    self.submission_data.get().evaluation_result.log)
                interface_print("=== END Evaluation Log")

        interface_print("NOTE: This evaluation log is also available at '%s'" %
                        self.evaluation_log.path.absolute())
Example #17
0
def build_solution(directory: Path, selected_variant: SkeletonVariant) -> bool:
    interface_print("=== Building submission ===")
    interface_print("Running '%s'." % selected_variant.build)
    interface_print("=== Building submission finished ===")

    build_result = execute_subprocess([selected_variant.build],
                                      cwd=directory,
                                      is_shell_command=True,
                                      merge_stdout_stderr=True)

    if not build_result.is_success():
        interface_print("Building your solution failed!")
        if prompt("Do you want to view the build log?", YesNoParser(True)):
            interface_print("=== BEGIN Build Log ===")
            interface_print(build_result.stdout, end='')
            interface_print("=== END Build Log ===")

        if not prompt(
                "Do you want to submit your solution anyway, despite the failing build?",
                YesNoParser(False)):
            interface_print("Aborting submission.")
            return False

    return True