Esempio n. 1
0
    def make(self):
        # Unset stack size limit
        resource.setrlimit(resource.RLIMIT_STACK, (resource.RLIM_INFINITY,
                                                   resource.RLIM_INFINITY))

        if not os.path.exists(os.path.join(self.odir, "contest-config.py")):
            raise Exception("Directory doesn't contain contest-config.py")
        self.wdir = os.path.join(self.odir, "build")
        if self.clean:
            shutil.rmtree(self.wdir)
        if not os.path.exists(self.wdir):
            os.mkdir(self.wdir)
        # We have to avoid copying the folder contest/build
        # or contest/task/build into contest/build.
        # For this reason, we ignore all files and directories named "build"
        # when copying recursively.
        copyrecursivelyifnecessary(self.odir, self.wdir, set(["build"]))
        self.wdir = os.path.abspath(self.wdir)
        file_cacher = FileCacher(path=os.path.join(self.wdir, ".cache"))
        try:
            with chdir(self.wdir):
                contestconfig = ContestConfig(
                    os.path.join(self.wdir, ".rules"),
                    os.path.basename(self.odir),
                    ignore_latex=self.no_latex,
                    onlytask=self.task)
                contestconfig._readconfig("contest-config.py")
                if self.task is not None and len(contestconfig.tasks) == 0:
                    raise Exception("Task {} not found".format(self.task))
                cdb = contestconfig._makecontest()
                test_udb = contestconfig._makeuser(
                    contestconfig._mytestuser.username)
                test_gdb = contestconfig._makegroup(
                    contestconfig._mytestuser.group.name, cdb)
                # We're not putting the test user on any team for testing
                # (shouldn't be needed).
                test_pdb = contestconfig._makeparticipation(
                    contestconfig._mytestuser.username, cdb,
                    test_udb, test_gdb, None)
                for t in contestconfig.tasks.values():
                    tdb = t._makedbobject(cdb, file_cacher)
                    t._make_test_submissions(test_pdb, tdb, self.local_test)
        finally:
            file_cacher.destroy_cache()
Esempio n. 2
0
    def build(self):
        file_cacher = FileCacher(path=os.path.join(self.wdir, ".cache"))

        try:
            with chdir(self.wdir):
                contestconfig = \
                    ContestConfig(os.path.join(self.wdir, ".rules"),
                                  "hidden contest", minimal=self.minimal)
                copyifnecessary(os.path.join(contestconfig._get_ready_dir(),
                                             "contest-template.py"),
                                os.path.join(self.wdir, "c.py"))
                contestconfig._readconfig("c.py")
                contestconfig._task(
                    self.task, contestconfig.full_feedback, self.minimal)

                if not self.minimal:
                    cdb = contestconfig._makecontest()
                    test_udb = contestconfig._makeuser(
                        contestconfig._mytestuser.username)
                    test_gdb = contestconfig._makegroup(
                        contestconfig._mytestuser.group.name, cdb)
                    # We're not putting the test user on any team for testing
                    # (shouldn't be needed).
                    test_pdb = contestconfig._makeparticipation(
                        contestconfig._mytestuser.username, cdb,
                        test_udb, test_gdb, None)
                    for t in contestconfig.tasks.values():
                        tdb = t._makedbobject(cdb, file_cacher)
                        t._make_test_submissions(
                            test_pdb, tdb, self.local_test)

        finally:
            file_cacher.destroy_cache()

        primary_statements = [s for s in list(list(contestconfig.tasks.values())[
            0]._statements.values()) if s.primary]
        if len(primary_statements) == 0:
            return None
        elif len(primary_statements) == 1:
            return os.path.abspath(primary_statements[0].file_)
        else:
            raise Exception("More than one primary statement")
Esempio n. 3
0
class GerImport(Service):
    def __init__(self, odir, no_test, clean, force):
        self.odir = odir
        self.no_test = no_test
        self.clean = clean
        self.force = force

        Service.__init__(self)

    def make(self):
        self.file_cacher = FileCacher()
        try:
            self.make_helper()
        finally:
            self.file_cacher.destroy_cache()

    def make_helper(self):
        # Unset stack size limit
        resource.setrlimit(resource.RLIMIT_STACK, (resource.RLIM_INFINITY,
                                                   resource.RLIM_INFINITY))

        if not os.path.exists(os.path.join(self.odir, "contest-config.py")):
            raise Exception("Directory doesn't contain contest-config.py")
        self.wdir = os.path.join(self.odir, "build")
        if self.clean:
            shutil.rmtree(self.wdir)
        if not os.path.exists(self.wdir):
            os.mkdir(self.wdir)
        # We have to avoid copying the folder contest/build
        # or contest/task/build into contest/build.
        # For this reason, we ignore all files and directories named "build"
        # when copying recursively.
        copyrecursivelyifnecessary(self.odir, self.wdir, set(["build"]))

        self.wdir = os.path.abspath(self.wdir)
        with chdir(self.wdir):
            contestconfig = ContestConfig(
                os.path.join(self.wdir, ".rules"),
                os.path.basename(self.odir))

            # Read the configuration file and build.
            contestconfig._readconfig("contest-config.py")

            with SessionGen() as session:
                def session_add(k, v):
                    session.add(v)

                # Variables like udbs, teamdbs, cdb, ... contain objects before
                # they've been put into the database.
                # Their counterpars udb1s, teamdb1s, cdb1, ... contain the
                # objects that are actually in the database (which are copies
                # of the objects in udbs, ...).

                # Create users in the database.
                udbs = [contestconfig._makeuser(u) for u in contestconfig.users]
                udb1s = _update_list_with_key(session.query(User).all(),
                                              udbs,
                                              lambda u : u.username,
                                              preserve_old=True,
                                              update_value_fn=update_user,
                                              creator_fn=session_add)
                udbs = {u.username : u for u in udbs}

                # Create teams in the database.
                teamdbs = [contestconfig._maketeam(t) for t in contestconfig.teams]
                teamdb1s = _update_list_with_key(session.query(Team).all(),
                                                 teamdbs,
                                                 lambda t : t.code,
                                                 preserve_old=True,
                                                 update_value_fn=update_team,
                                                 creator_fn=session_add)
                teamdbs = {t.code : t for t in teamdbs}

                # Create contest (including associated user groups) in the database.
                cdb = contestconfig._makecontest()
                cdbs = [cdb]
                cdb1s = _update_list_with_key(session.query(Contest).all(),
                                              cdbs,
                                              lambda c : c.name,
                                              preserve_old=True,
                                              update_value_fn=update_contest,
                                              creator_fn=session_add)
                cdb1 = cdb1s[cdb.name]

                # Set the contest's main group.
                cdb1.main_group = cdb1.get_group(contestconfig.defaultgroup.name)

                # Create participations in the database.

                # Team object for a given user
                def user_team(u):
                    t = contestconfig.users[u].team
                    if t is None:
                        return None
                    else:
                        return teamdbs[t.code]
                # Team object in the database for a given user
                def user_team1(u):
                    t = contestconfig.users[u].team
                    if t is None:
                        return None
                    else:
                        return teamdb1s[t.code]

                def make_participation(u):
                    gdb = cdb.get_group(contestconfig.users[u].group.name)
                    return contestconfig._makeparticipation(u, cdb, udbs[u],
                                                            gdb, user_team(u))

                pdbs = [make_participation(u) for u in contestconfig.users]
                pdb1s = _update_list_with_key(cdb1.participations,
                                              pdbs,
                                              lambda p : p.user.username,
                                              preserve_old=True,
                                              update_value_fn=update_participation)
                pdbs = {p.user.username : p for p in pdbs}

                for username, u in iteritems(pdb1s):
                    u.user = udb1s[username]
                    u.group = cdb1.get_group(
                        contestconfig.users[username].group.name)
                    u.team = user_team1(username)

                # The test user participation.
                test_pdb = pdbs[contestconfig._mytestuser.username]
                test_pdb1 = pdb1s[contestconfig._mytestuser.username]

                # This is an ugly hack to prevent problems when reordering or
                # adding tasks. Since we delete after adding and updating,
                # there might otherwise at one point be two tasks with the same
                # number.
                for t in cdb1.tasks:
                    t.num += len(contestconfig.tasks) + len(cdb1.tasks)

                tdbs = [t._makedbobject(cdb, self.file_cacher)
                        for t in contestconfig.tasks.values()]
                tdbs_dict = {t.name: t for t in tdbs}
                # We only set the active dataset when importing a new task.
                # Afterwards, the active dataset has to be set using the web
                # interface.

                def task_creator(name, v):
                    tdb = tdbs_dict[name]
                    ddb1 = session.query(Dataset) \
                        .filter(Dataset.task == v) \
                        .filter(Dataset.description ==
                                tdb.active_dataset.description).first()
                    assert ddb1 is not None
                    v.active_dataset = ddb1
                tdb1s = _update_list_with_key(cdb1.tasks,
                                              tdbs,
                                              lambda t : t.name,
                                              preserve_old=False,
                                              update_value_fn=update_task,
                                              creator_fn=task_creator)
                tdbs = {t.name : t for t in tdbs}

                sdb1ss = {}
                if not self.no_test:
                    logger.warning("Replacing test submissions")
                    for t in contestconfig.tasks:
                        tdb = tdbs[t]
                        tdb1 = tdb1s[t]
                        # Mark old test submissions for deletion.
                        sdb1s = session.query(Submission) \
                            .filter(Submission.participation == test_pdb1) \
                            .filter(Submission.task == tdb1) \
                            .filter(Submission.additional_info != None).all()
                        for sdb1 in sdb1s:
                            assert sdb1.is_unit_test()
                            _to_delete.append(sdb1)

                        # Create test submissions in the database.
                        sdbs = contestconfig.tasks[t]._make_test_submissions(
                            test_pdb, tdb, False)
                        sdb1s = []
                        for sdb in sdbs:
                            sdb1 = _copy(sdb)
                            sdb1.task = tdb1
                            sdb1.participation = test_pdb1
                            session.add(sdb1)
                            sdb1s.append(sdb1)
                        sdb1ss[t] = sdb1s

                for v in _to_delete:
                    if isinstance(v, Task):
                        logger.warning("Removing task {}"
                                       .format(v.name))
                        if any(not s.is_unit_test() for s in v.submissions):
                            logger.warning(
                                "There are submissions for task {}."
                                .format(v.name))
                            if not self.force:
                                logger.error("Aborting. Run with -f to force "
                                             "deletion.")
                                return
                    elif isinstance(v, Participation):
                        logger.warning("Removing participation {}"
                                       .format(v.user.username))
                        if any(not s.is_unit_test() for s in v.submissions):
                            logger.warning(
                                "There are submissions for participation {}."
                                .format(v.user.username))
                            if not self.force:
                                logger.error("Aborting. Run with -f to force "
                                             "deletion.")
                                return

                if self.force:
                    logger.warning("Force flace -f set.")

                ans = input("Proceed? [y/N] ").strip().lower()
                if ans not in ["y", "yes"]:
                    logger.error("Aborting.")
                    return

                # Delete marked objects
                for v in _to_delete:
                    session.delete(v)

                session.commit()

                if not self.no_test:
                    evaluation_service = self.connect_to(
                        ServiceCoord("EvaluationService", 0))
                    for t in contestconfig.tasks:
                        sdb1s = sdb1ss[t]
                        # Notify EvaluationService of the new test submissions.
                        for sdb1 in sdb1s:
                            evaluation_service.new_submission(
                                submission_id=sdb1.id)
                    evaluation_service.disconnect()

                logger.info("Import finished (new contest id: %s).",
                            cdb.id if cdb1 is None else cdb1.id)