Esempio n. 1
0
    def importPerson(self, person):
        p = person["person"]
        if p["role"] == "Contestant":        
            t = int(p["team-id"])
            self.peopleInTeam[t] += 1
            self.contestants += 1
            query = "UPDATE teams SET contestant%d_id = %%s, contestant%d_name = %%s WHERE team_id = %%s" % (self.peopleInTeam[t],self.peopleInTeam[t])
            params = (self.contestants, "%s %s" % (p["first-name"], p["last-name"]), int(p["team-id"]))
            cursor = dbConn.cursor()
            cursor.execute(query, params)
	elif p["role"] == "Coach":
            t = int(p["team-id"])
            query = "UPDATE teams SET coach_name = %s WHERE team_id = %s"
            params = ("%s %s" % (p["first-name"], p["last-name"]), int(p["team-id"]))
            cursor = dbConn.cursor()
            cursor.execute(query, params)
Esempio n. 2
0
 def importTeam(self, team):
     t = team["team"]
     
     query = "INSERT INTO teams (id, team_id, team_name, institution_id, school_name, school_short, country) VALUES (%s,%s,%s,%s,%s,%s,%s)"
     params = (int(t["id"]), int(t["id"]), t["name"], int(t["institution-id"]), t["affiliation"], t["affiliation-short-name"], t["nationality"])
     cursor = dbConn.cursor()
     cursor.execute(query, params)
Esempio n. 3
0
    def loadConfiguration(self):
        # Read the list of problem names
        self.probKeywords = {}

        cursor = dbConn.cursor()
        cursor.execute("SELECT problem_id, keyword FROM problem_keywords")
        row = cursor.fetchone()
        while (row != None):
            if (row[0] in self.probKeywords):
                self.probKeywords[row[0]].append(row[1].lower())
            else:
                self.probKeywords[row[0]] = [row[1].lower()]

            row = cursor.fetchone()

        # get latest known edit times for every team/path
        cursor.execute(
            "SELECT id, team_id, path, modify_timestamp FROM file_modtime")
        row = cursor.fetchone()
        while (row != None):
            self.lastEditTimes[(row[1], row[2])] = [row[0], row[3], None]

            row = cursor.fetchone()

        # get existing mapping records for all mapped files.
        cursor.execute(
            "SELECT id, team_id, path, problem_id, lang_id, override FROM file_to_problem"
        )
        row = cursor.fetchone()
        while (row != None):
            self.fileMappings[(int(row[1]),
                               row[2])] = MappingRec(row[0], row[3], row[4],
                                                     row[5], None)

            # Old mapping
            # 0 -> id, 1 -> problem_id, 2 -> override, 3 -> new_problem_id

            row = cursor.fetchone()

        # load any team-specific strips.
        cursor.execute("SELECT team_id, str FROM team_strips")
        row = cursor.fetchone()
        while (row != None):
            if (row[0] in self.teamStrips):
                self.teamStrips[row[0]].append(row[1].lower())
            else:
                self.teamStrips[row[0]] = [row[1].lower()]

            row = cursor.fetchone()

        cursor.close()
Esempio n. 4
0
    def initCDS( self ):
        """Initialization that just needs to be done for runs with backups from the CDS.
        This is getting kind of ugly."""

        # figure out a start time in the format we will get from the CDS.
        cursor = dbConn.cursor()
        cursor.execute( "SELECT start_time FROM contests ORDER BY id DESC LIMIT 1" )
        row = cursor.fetchone()
        if ( row == None ):
            print("Error: no contest found in the database.")
            exit(1)

        startTime = time.strftime( "%a, %d %b %Y %H:%M:%S GMT", time.gmtime(0) )
        self.teamLastModified = {};
        for teamIdx in range( 1, self.lastTeam + 1 ):
            self.teamLastModified[ teamIdx ] = startTime;
Esempio n. 5
0
    def loadConfiguration( self ):
        # Read the list of problem names
        self.probKeywords = {}

        cursor = dbConn.cursor()
        cursor.execute( "SELECT problem_id, keyword FROM problem_keywords" )
        row = cursor.fetchone()
        while ( row != None ):
            if ( row[ 0 ] in self.probKeywords ):
                self.probKeywords[ row[ 0 ] ].append( row[ 1 ].lower() )
            else:
                self.probKeywords[ row[ 0 ] ] = [ row[ 1 ].lower() ]

            row = cursor.fetchone()

        # get latest known edit times for every team/path
        cursor.execute( "SELECT id, team_id, path, modify_time_utc FROM file_modtime" )
        row = cursor.fetchone()
        while ( row != None ):
            t = int( calendar.timegm( row[ 3 ].timetuple() ) )
            self.lastEditTimes[ ( row[ 1 ], row[ 2 ] ) ] = [ row[ 0 ], t, None ]

            row = cursor.fetchone()
        
        # get existing mapping records for all mapped files.
        cursor.execute( "SELECT id, team_id, path, problem_id, lang_id, override FROM file_to_problem" )
        row = cursor.fetchone()
        while ( row != None ):
            self.fileMappings[ ( int( row[ 1 ] ), row[ 2 ] ) ] = MappingRec( row[ 0 ], row[ 3 ], row[ 4 ], row[ 5 ], None )
                  
# Old mapping
# 0 -> id, 1 -> problem_id, 2 -> override, 3 -> new_problem_id
                
            row = cursor.fetchone()

        # load any team-specific strips.
        cursor.execute( "SELECT team_id, str FROM team_strips" )
        row = cursor.fetchone()
        while ( row != None ):
            if ( row[ 0 ] in self.teamStrips ):
                self.teamStrips[ row[ 0 ] ].append( row[ 1 ].lower() )
            else:
                self.teamStrips[ row[ 0 ] ] = [ row[ 1 ].lower() ]

            row = cursor.fetchone()
        
        cursor.close()
Esempio n. 6
0
    def initCDS(self):
        """Initialization that just needs to be done for runs with backups from the CDS.
        This is getting kind of ugly."""

        # figure out a start time in the format we will get from the CDS.
        cursor = dbConn.cursor()
        cursor.execute(
            "SELECT start_time FROM contests ORDER BY start_time DESC LIMIT 1")
        row = cursor.fetchone()
        if (row == None):
            print("Error: no contest found in the database.")
            exit(1)

        startTime = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(0))
        self.teamLastModified = {}
        for teamIdx in range(1, self.lastTeam + 1):
            self.teamLastModified[teamIdx] = startTime
Esempio n. 7
0
    def importConfig( self, info ):

        t = info[ "info" ][ "start-time" ]

        match = re.compile( '(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})\.\d*([-+]\d{2})' ).match( t )
        if not match:
            print("Error: can't parse start time")
            exit(1)

        # here, we're truncating seconds, but we could round.
        dt = datetime.strptime( match.group( 1 ), "%Y-%m-%dT%H:%M:%S" )

        # add in the UTC Offset (there should be an easier way to do this)
        start_time = (dt - datetime(1970,1,1)).total_seconds()
        start_time = start_time - int( match.group( 2 ) ) * 3600

        # Parse contest duration
        match = re.compile( '(\d{1,}):(\d{2}):(\d{2})' ).match( info[ "info" ][ "duration" ] )
        if not match:
            print("Error: can't parse start duration")
            exit(1)

        duration = int( match.group( 1 ) ) * 3600 + int( match.group( 3 ) ) * 60 + int( match.group( 2 ) )

        # Parse freeze time.
        match = re.compile( '(\d{1,}):(\d{2}):(\d{2})' ).match( info[ "info" ][ "scoreboard-freeze-duration" ] )
        if not match:
            print("Error: can't parse freeze duration")
            exit(1)

        freeze_duration = int( match.group( 1 ) ) * 3600 + int( match.group( 2 ) ) * 60 + int( match.group( 3 ) )
        freeze_time = duration - freeze_duration

        query = "INSERT INTO contests (contest_name, start_time, length, freeze ) VALUES (%s,%s,%s,%s)"
	params = (info[ "info" ][ "name" ],  start_time, duration, freeze_time)
        cursor = dbConn.cursor()
        cursor.execute(query, params)
Esempio n. 8
0
    def checkActivity( self, bdir, tag ):
        """Scan the given backup dir and generate reports of the state of
        files believed to correspond to various problems in the problem set."""

        # Time when this script started running.
        scriptStartTime = int( time.time() )

        self.loadConfiguration()

        # Get diff reports from git.
        gitDiffs = self.parseGitDiffs( bdir )

        # We should rethink some of the following loop.  Right now, it
        # tries to find file changes, including changes to editor auto-save
        # files.  But, to report changed lines in the file, we depend on git
        # (which probably isn't tracking these auto-save files, so we'd have
        # nothing to report)
        
        # Visit home directory for each team.
        tlist = sorted( glob.glob( bdir + '/team*' ) )
        for tdir in tlist:
            ( dirname, tname ) = os.path.split( tdir )
            team = int( tname.lstrip( 'team' ) )
            cmd = "find %s/ -type f" % tdir
            for f in os.popen( cmd ).readlines():
                f = f.rstrip( '\n' )
                fname = f[len(tdir) + 1:]
                ( dummy, extension ) = os.path.splitext( fname )
                extension = extension.lstrip( '.' )
                if extension in self.extensionMap:
                    fobj = File( fname, os.path.getmtime( f ) )

                    # Get lines changed, etc.  We need to consult the git diff output.
                    # The tag is to make sure we only record lines changed on an analysis
                    # pass that's paired to a git commit.  Independent analysis passes
                    # don't get this, since that could infate the appearance of how
                    # much editing is being done.
                    gitPath = f[len(bdir) + 1:]
                    if gitPath in gitDiffs and tag != DEFAULT_TAG:
                        fobj.linesChanged = gitDiffs[ gitPath ][ 0 ] + gitDiffs[ gitPath ][ 1 ];

                    mappingRec = None
                    lastEditRec = None

                    # Files with completely implausible modification times can get ignored.
                    ignoreEdit = False

                    # see if there's a mapping for this file.
                    if ( team, fname ) in self.fileMappings:
                        mappingRec = self.fileMappings[ ( team, fname ) ]

                    # If there's no forced mapping for this problem, try to guess one.
                    if ( mappingRec == None or mappingRec.override == 0 ):
                        prob = self.guessProblem( team, fobj.path )
                        if prob != None:
                            if mappingRec == None:
                                mappingRec = MappingRec( None, None, self.extensionMap[ extension ],
                                                         0, None );
                                self.fileMappings[ ( team, fname ) ] = mappingRec
                                
                            if mappingRec.problem_id != prob:
                                mappingRec.new_problem_id = prob;
                    
                    # see if there's an edit record for this file.
                    if ( team, fname ) in self.lastEditTimes:
                        lastEditRec = self.lastEditTimes[ ( team, fname ) ]

                    # check common editor auto-saves, to see if there
                    # is a fresher modification time.
                    autoTime = self.checkAutosaves( f );
                    if ( autoTime != None and autoTime > fobj.time ):
                        fobj.time = autoTime

                    # Try to gurad against anomalous file edit times. These are unlikely to happen,
                    # but they could look strange in the report or even suppress tracking of files
                    # if they have a modification time in the future.

                    # No edits should happen before the start of the contest or after right now.
                    if fobj.time < self.contestStart:
                        fobj.time = self.contestStart
                   
                    # If the file really changes, we definitely want to record it, possibly with
                    # a sane-ified modification time.
                    if fobj.time < scriptStartTime - 2 * self.backupInterval:
                        if fobj.linesChanged > 0:
                            fobj.time = int( scriptStartTime - self.backupInterval / 2 )

                    # If the file looks like it changed in the future, ignore it unless git agrees it's changing.
                    if fobj.time > scriptStartTime + self.backupInterval:
                        print "Future Modification: ", fobj.path, " changed ", fobj.linesChanged
                        if fobj.linesChanged > 0:
                            fobj.time = scriptStartTime
                        else:
                            ignoreEdit = True

                    # Is this newer than our last known edit?
                    # We don't just depend on git for this, since we can
                    # also watch auto-saves.
                    if not ignoreEdit and ( lastEditRec == None or lastEditRec[ 1 ] + 10 < fobj.time ):
                        if lastEditRec == None:
                            lastEditRec = [ None, None, None ]
                            self.lastEditTimes[ ( team, fname ) ] = lastEditRec
                                
                        # Grab file size and number of lines.
                        fobj.size = os.path.getsize( f )
                        fobj.lineCount = self.countLines( f )
                        
                        lastEditRec[ 2 ] = fobj;


        # Write out any new mappings
        cursor = dbConn.cursor()
        for k, v in self.fileMappings.iteritems():
            if v.new_problem_id != None:
                if v.db_id == None:
                    update = "INSERT INTO file_to_problem (team_id, path, problem_id, lang_id, override ) VALUES ( '%s', '%s', '%s', '%s', '0' )" % ( k[ 0 ], dbConn.escape_string( k[ 1 ] ), v.new_problem_id, v.lang_id )
                
                    cursor.execute( update )
                else:
                    update = "UPDATE file_to_problem SET problem_id='%s' WHERE id='%d'" % ( v.new_problem_id, v[ 0 ] )
                    cursor.execute( update )
                print "( %s, %s ) -> %s" % ( k[ 0 ], k[ 1 ], v.new_problem_id )

        # Write out fresh edit times to file_modtime and new records to edit_activity
        cursor = dbConn.cursor()
        for k, v in self.lastEditTimes.iteritems():
            if v[ 2 ] != None:
                tstr = time.strftime( "%Y-%m-%d %H:%M:%S", time.gmtime( v[ 2 ].time ) )

                if v[ 0 ] == None:
                    update = "INSERT INTO file_modtime (team_id, path, modify_time_utc ) VALUES ( '%s', '%s', '%s' )" % ( k[ 0 ], dbConn.escape_string( k[ 1 ] ), tstr )
                
                    cursor.execute( update )
                else:
                    update = "UPDATE file_modtime SET modify_time_utc='%s' WHERE id='%d'" % ( tstr, v[ 0 ] )
                    cursor.execute( update )

                # Compute time since start of contest.
                cmin = ( v[ 2 ].time - self.contestStart ) / 60

                update = "INSERT INTO edit_activity (team_id, path, modify_time_utc, modify_time, file_size_bytes, line_count, lines_changed, git_tag ) VALUES ( '%s', '%s', '%s', '%s', '%d', '%d', '%d', '%s' )" % ( k[ 0 ], dbConn.escape_string( k[ 1 ] ), tstr, cmin, v[ 2 ].size, v[ 2 ].lineCount, v[ 2 ].linesChanged, tag )
                
                cursor.execute( update )
                

        # Create and write the summary of edit activity by problem, edit_latest

        # Map from team and problem_id to a triple, database_id,
        # timestamp and valid flag.  the valid flag lets us delete
        # database rows (say, if a file_to_problem mapping changes).  An
        # entry is valid as long as there is a file that's mapped to
        # the given problem, even if the file no longer exists.
        modLatest = {}

        # get latest known edit times for every team/problem.
        cursor.execute( "SELECT id, team_id, problem_id, modify_time_utc FROM edit_latest" )
        row = cursor.fetchone()
        while ( row != None ):
            t = int( calendar.timegm( row[ 3 ].timetuple() ) )
            modLatest[ ( row[ 1 ], row[ 2 ] ) ] = [ row[ 0 ], t, 0 ]
            row = cursor.fetchone()
        
        for k, v in self.fileMappings.iteritems():
            prob = v.problem_id
            if v.new_problem_id != None:
                prob = v.new_problem_id
                
            if prob != None and prob != 'none':
                if k in self.lastEditTimes:
                    lastEditRec = self.lastEditTimes[ k ]
                    t = lastEditRec[ 1 ]
                    if lastEditRec[ 2 ] != None:
                        t = lastEditRec[ 2 ].time;
                
                    if ( k[ 0 ], prob ) in modLatest:
                        rec = modLatest[ ( k[ 0 ], prob ) ]
                        if t > rec[ 1 ]:
                            rec[ 1 ] = t
                        rec[ 2 ] = 1;
                    else:
                        modLatest[ ( k[ 0 ], prob ) ] = [ None, t, 1 ]

        for k, v in modLatest.iteritems():
            tstr = time.strftime( "%Y-%m-%d %H:%M:%S", time.gmtime( v[ 1 ] ) )
            if v[ 0 ] == None:
                update = "INSERT INTO edit_latest (team_id, problem_id, modify_time_utc ) VALUES ( '%s', '%s', '%s' )" % ( k[ 0 ], k[ 1 ], tstr )
                
                cursor.execute( update )
            elif v[ 2 ]:
                update = "UPDATE edit_latest SET modify_time_utc='%s' WHERE id='%d'" % ( tstr, v[ 0 ] )
                cursor.execute( update )
            else:
                update = "DELETE FROM edit_latest WHERE id='%d'" % ( v[ 0 ] )
                cursor.execute( update )
Esempio n. 9
0
    def __init__(self, basePath):
        # path to the top of the backup directory.
        self.basePath = basePath

        # index of the last team in the competition.
        self.lastTeam = config["teambackup"]["lastTeam"]

        # interval for updating team backups, used in this script to freshen stale modification
        # times, if it looks like there's a reason.
        self.backupInterval = config["teambackup"]["interval"]

        # Strings to strip from the filename before we try to guess
        self.commonStrips = ['problem', 'prob', '_', '-']

        # Valid source file extensions, and what each one says
        # about the source language.
        self.extensionMap = {
            'cc': "C++",
            'cpp': "C++",
            'c': "C",
            'java': "Java",
            'py': "Python"  # FIXME: do we want to discern between Python 2/3?
        }

        # map from problem ID to a list of keywords to look for.
        self.probKeywords = {}

        # List of problems.  We use this mostly as the offficial
        # list of problem letters, from the configuration.
        self.problemList = problems

        # Contest start time in Unix seconds from the database.
        cursor = dbConn.cursor()
        cursor.execute(
            "SELECT start_time FROM contests ORDER BY start_time DESC LIMIT 1")
        row = cursor.fetchone()
        if (row == None):
            print("Error: no contest found in the database.")
            exit(1)

        self.contestStart = row[0]

        # For each team, a list of team-specific strips from filenames.
        self.teamStrips = {}

        # we use the next two fields to hold copies of database
        # information (the file_to_problem and file_modtime tables)
        # while the script is running, and to update the tables once
        # the script has run.

        # For every team and path, this is a triple, datatabase_id,
        # latest modification time and File object (if the file has
        # has changed).  We only add a new entry to edit_activity if
        # it's sufficiently newer than what we have there or if we just
        # committed and git reports that a file has changed.
        self.lastEditTimes = {}

        # map from team_id and path to a MappingRec instance
        # containing db_id, problem_id, lang_id, override flag and new
        # problem ID (if we just generated a new mapping).  This lets
        # us know what to ignore in the mapping and what to update
        # when we re-write the database.  Multiple files may map to
        # the same problem, if the team is working on multiple
        # versions or has some supporting files.
        self.fileMappings = {}
Esempio n. 10
0
if not path.startswith( prefix ):
    print "Bad path format"
    usage()

# Strip off the front, and extract the team id.
path = path[len(prefix):]
mg = re.match( "^([0-9]+)", path )
if ( mg == None ):
    print "Bad path format, no team id"
    usage()

team = mg.group( 1 )

path = path[ len(team)+1:]

cursor = dbConn.cursor()

# Make sure this is a legal problem_id.
if prob not in config['problems']:
    print "Bad problem id: %s" % prob
    usage()

# Just to get the extension map.
analyzer = Analyzer( BACKUP_TOP )

# See if there is already an entry for this file.
cmd = "SELECT team_id FROM file_to_problem WHERE path='%s' AND team_id='%s'" % ( path, team )
cursor.execute( cmd )

# Just see if it's arealdy there.  There should be a better way to do this.
if cursor.fetchone() == None:
Esempio n. 11
0
    def __init__( self, basePath ):
        # path to the top of the backup directory.
        self.basePath = basePath

        # index of the last team in the competition.
        self.lastTeam = config[ "teambackup" ][ "lastTeam" ]

        # interval for updating team backups, used in this script to freshen stale modification
        # times, if it looks like there's a reason.
        self.backupInterval = config[ "teambackup" ][ "interval" ]

        # Strings to strip from the filename before we try to guess
        self.commonStrips = [ 'problem', 'prob', '_', '-' ]

        # Valid source file extensions, and what each one says
        # about the source language.
        self.extensionMap = {
            'cc': "C++",
            'cpp': "C++",
            'c': "C",
            'java': "Java",
            'py': "Python" # FIXME: do we want to discern between Python 2/3?
            }

        # map from problem ID to a list of keywords to look for.
        self.probKeywords = {}

        # List of problems.  We use this mostly as the offficial
        # list of problem letters, from the configuration.
        self.problemList = problems

        # Contest start time in Unix seconds from the database.
        cursor = dbConn.cursor()
        cursor.execute( "SELECT start_time FROM contests ORDER BY id DESC LIMIT 1" )
        row = cursor.fetchone()
        if ( row == None ):
            print("Error: no contest found in the database.")
            exit(1)

        self.contestStart = row[0]

        # For each team, a list of team-specific strips from filenames.
        self.teamStrips = {}

        # we use the next two fields to hold copies of database
        # information (the file_to_problem and file_modtime tables)
        # while the script is running, and to update the tables once
        # the script has run.

        # For every team and path, this is a triple, datatabase_id,
        # latest modification time and File object (if the file has
        # has changed).  We only add a new entry to edit_activity if
        # it's sufficiently newer than what we have there or if we just
        # committed and git reports that a file has changed.
        self.lastEditTimes = {}

        # map from team_id and path to a MappingRec instance
        # containing db_id, problem_id, lang_id, override flag and new
        # problem ID (if we just generated a new mapping).  This lets
        # us know what to ignore in the mapping and what to update
        # when we re-write the database.  Multiple files may map to
        # the same problem, if the team is working on multiple
        # versions or has some supporting files.
        self.fileMappings = {}
Esempio n. 12
0
if not path.startswith(prefix):
    print "Bad path format"
    usage()

# Strip off the front, and extract the team id.
path = path[len(prefix):]
mg = re.match("^([0-9]+)", path)
if (mg == None):
    print "Bad path format, no team id"
    usage()

team = mg.group(1)

path = path[len(team) + 1:]

cursor = dbConn.cursor()

# Make sure this is a legal problem_id.
if prob not in config['problems']:
    print "Bad problem id: %s" % prob
    usage()

# Just to get the extension map.
analyzer = Analyzer(BACKUP_TOP)

# See if there is already an entry for this file.
cmd = "SELECT team_id FROM file_to_problem WHERE path='%s' AND team_id='%s'" % (
    path, team)
cursor.execute(cmd)

# Just see if it's arealdy there.  There should be a better way to do this.
Esempio n. 13
0
    def importProblem(self, problem):
        p = problem["problem"]
        query = "INSERT INTO problems (id, problem_id, problem_name, color) VALUES (%s,%s,%s,%s)"
        params =  (int(p["id"]), dbConn.escape_string(p["label"]), dbConn.escape_string(p["name"]), dbConn.escape_string(p["rgb"]))
	cursor = dbConn.cursor()
        cursor.execute(query, params)
Esempio n. 14
0
 def cleanTables(self):
     cursor = dbConn.cursor()
     cursor.execute("DELETE FROM teams")
     cursor.execute("DELETE FROM problems")