#!/usr/bin/env python #RockTest #Programming Competition Judge's Console, "rt_judge", V2.0.1 #Last modification: March 11, 2006 #RockTest consists primarily of three GUI programs: RockTest Team Console, # RockTest Judge's Console, and RockTest Tabulation Console. There are also # "rt_update", a file copying program, "setup.sh", an install script, # and various help files. #Copyright 2003, 2004, 2005, 2006 #Michael P. Conlon, Ph.D. #Computer Science Department #Slippery Rock University of Pennsylvania #Slippery Rock, PA 16057 #Email: michael.conlon@sru.edu #724-738-2143 # This program is free software; you may redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # or see http://www.gnu.org/copyleft/gpl.html. #Bugs: File locking is completely broken. #See the comments in RockTest Team Console for more information. from Tkinter import * from string import * import os import commands import threading import sys import fcntl TRUE=1 COLOR="#c5ffc5" COLOR2="#ffffcc" MENU=0 ENTRY=1 root=Tk() root.title("RockTest Judge's Console") root.iconbitmap("@/usr/local/bin/rocktest/rock_mask.xbm") #This works! root.iconmask("@/usr/local/bin/rocktest/rock_gbg.xbm") def strip_cr(text): loc=99999 while loc >= 0: loc = find(text, '\r') if loc >= 0: text = text[:loc] + text[loc+1:] return text class conf_class: def __init__(self): self.runlimit = StringVar() #default maximum runtime for team programs self.runlimit.set("10 sec") #initialized to 10 seconds. self.team_no = StringVar() self.prob_no = StringVar() self.lang = StringVar() self.dfn = StringVar() self.output = StringVar() self.ruling = StringVar() self.team_no.set("") self.teams_home=commands.getoutput(\ "grep team01 /etc/passwd | awk -F: '{print $6}'")[:-2] self.prob_no.set("") self.lang.set("") self.dfn.set("program1.dat") self.output.set("") self.ext_map={"BASIC":".bas","C":".c","C++":".cpp","FORTRAN":".for", \ "Java":".java","PHP":".php","Pascal":".pas","Python":".py"} self.no_compile = ("BASIC", "PHP", "Python") self.team_name = "team01" self.prog_fn = "" self.judgements = ("correct", "syntax error", "runtime error",\ "no output", "insufficient output", "incorrect output", \ "excessive output", "bad output format", "excessive run time", \ "non-algorithmic solution", "Don't open files!") self.ruling.set("correct") #Find judge's home directory. self.judge_home = os.environ["HOME"] #print "Judge directory is " + self.judge_home self.data=0 #Program parameters #Is there a configuration file? try: #if 1: #If there is, get parameters from the file. fd = open('/usr/local/etc/rocktest/rocktest.conf') self.data = fd.readlines() #print self.data #sys.exit(1) for self.line in self.data: self.line = self.line[:-1] #print "Line:", self.line if self.line[:13] == "problem_count": self.prob_count = atoi(self.line[14:]) elif self.line[:10] == "team_count": self.team_count = atoi(self.line[11:]) #elif self.line[:15] == "language_count": #self.language_ct = atoi(self.line[16:]) #for i in range(self.language_ct): #pass fd.close() #print "File closed." #sys.exit(1) #else: except: #,print "Error processing initialization file." self.team_count = 40 self.prob_count = 10 self.team_list = () for i in range(1, self.team_count+1): if i < 10: self.team_list = self.team_list + ("0" + str(i),) else: self.team_list = self.team_list + (str(i),) self.avail_dfs = "program1.dat", "program1.csv" self.prob_list = () for i in range(1, self.prob_count+1): self.prob_list = self.prob_list + (str(i),) conf=conf_class() def clear_dirs(): #Clear files from last contest or trial contest. #Clear old program files and certificates from teams' directories. #First, find where team home directories are. #print "Team home is " + conf.team_home for i in range(conf.team_count): #Loop through all teams' names no = i + 1 team_dir = conf.teams_home if no < 10: team_dir = team_dir + "0" team_dir = team_dir + "%d" % no try: #print "Listing team directory." output = os.listdir(team_dir) #print "Files to be removed:" #print output #print "Looping through files." for file in output: if file[:7] == "program": #print "Removing file:", file try: os.remove("%s/%s" % (team_dir, file)) except: pass #Truncate team certificate file. #print "Truncating certificates file." #print "Team directory is", team_dir status, output = commands.getstatusoutput( 'echo > %s/certificates/certificates' % team_dir) #print "Status is", status #print "Output is", output except OSError: pass #sys.exit(1) #Next, remove certificate, program, and clarification request files from # /tmp/rocktest. try: os.system('rm -f /tmp/rocktest/submissions/program*') except OSError: pass try: os.system('rm -f /tmp/rocktest/submissions/clar_req*') except OSError: pass try: os.system('rm -f /tmp/rocktest/certificates/*') except OSError: pass #Then, empty the tabulation file of prior rulings. os.system('echo "#TEAM PROBLEM RULING TIMESTAMP" > /tmp/rocktest/tabulation') #Finally, remove clarification requests, and reinitialize the #clarification file. os.system("rm -f /tmp/rocktest/submissions/clar_req*") text = "General:\n\n" for i in range(1, conf.prob_count+1): text = text + "Problem %d:\n\n" % i os.system('echo "%s"> /tmp/rocktest/clarifications' % text) class warning_box_class: def __init__(self, parent, name, text, ok_but_text, cancel_but_text, just): self.msg=StringVar() self.tmp_msg=StringVar() self.msg.set(text) self.parent = parent self.name = name self.ok_button_text = ok_but_text self.cancel_button_text = cancel_but_text self.just = just def close(self): #Close the info box. self.warning_box.destroy() def clear_em(self): clear_dirs() self.warning_box.destroy() def create(self, msg=""): #Create the dialog box. self.warning_box=Toplevel(self.parent, bg=COLOR2) self.warning_box.title(self.name) #Use the default message if there is no msg parameter. if msg == "": self.tmp_msg.set(self.msg.get()) else: self.tmp_msg.set(msg) self.abt_msg=Message(self.warning_box, textvariable=self.tmp_msg, justify=self.just, aspect=300, width=400, bg=COLOR2).pack(side=TOP) self.button_frame = Frame(self.warning_box) self.ok_button=Button(self.button_frame, text=self.ok_button_text) self.ok_button.configure(command=lambda obj=self: obj.clear_em()) self.ok_button.pack(side=LEFT) self.cancel_button=Button(self.button_frame, text=self.cancel_button_text) self.cancel_button.configure(command=lambda obj=self: obj.close()) self.cancel_button.pack(side=RIGHT) self.button_frame.pack(side=BOTTOM) #Create "Are you sure?" warning box. box_name="Are you sure?" ok_but_text="Delete Files" cancel_but_text="Cancel" msg="""Warning!!! You are about to delete all users' program files and data files, all submitted programs, and all clarification requests and responses. """ del_warning_box=warning_box_class(root, box_name, msg, ok_but_text, cancel_but_text, CENTER) class info_box_class: def __init__(self, parent, name, text, but_text, just): self.msg=StringVar() self.tmp_msg=StringVar() self.msg.set(text) self.parent = parent self.name = name self.button_text = but_text self.just = just def close(self): #Close the info box. self.info_box.destroy() def create(self, msg=""): #Create the dialog box. self.info_box=Toplevel(self.parent, bg=COLOR2) self.info_box.title(self.name) #Use the default message if there is no msg parameter. if msg == "": self.tmp_msg.set(self.msg.get()) else: self.tmp_msg.set(msg) self.abt_msg=Message(self.info_box, textvariable=self.tmp_msg, justify=self.just, aspect=300, width=400, bg=COLOR2).pack(side=TOP) self.ok_button=Button(self.info_box, text=self.button_text) self.ok_button.configure(command=lambda obj=self: obj.close()) self.ok_button.pack(side=BOTTOM) #Create "About RockTest" info box. box_name="About RockTest" but_text="Close" msg="""RockTest Judge's Console V. 2.0.1 Copyright 2003-2006 Michael P. Conlon, Ph.D., Computer Science Department, Slippery Rock University Email: michael.conlon@sru.edu No warranty; distribution and modification is permitted under the Gnu General Public License, V2 (or later). See http://www.gnu.org/copyleft/gpl.html for details.""" about_info_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "Help" info box. box_name="Help" but_text="Close" msg=""" 1) Click on "Update" to check on the number of ungraded programs. After the first "Update", the "Ungraded Programs" indicator will be automatically updated every three minutes or so. However, you can still click on "Update" to get a more recent count. 2) If there are ungraded programs, click on "Get program" to fetch the program. All the indicators ("Team", "Problem Number", "Programming Language", and "Timestamp") will be updated as the program is fetched for grading. 3) Click on the "Data file" menu button to select the correct data file for this program. 4) If the programming language requires a separate "compile" step, click on the "Compile" button. The "Compile" button will remain depressed until the compile process is complete. (Expect a delay.) Once the compile is done, the compiler output will appear in the lower pane. 5) To run the program with the selected data file, click on the "Run" button. The output will appear in the lower pane. 6) If the program does not run to completion, you can set a different runtime limit by clicking on the "Runtime Limit" button. 7) If you want to see the source code of the program, click on the "View Source" button. The source code of the program will appear in the lower pane. 8) If there is a problem, sometimes it helps to see the team's directory. For this, click on "List Team Files". """ help_info_box=info_box_class(root, box_name, msg, but_text, LEFT) #Create "Cannot copy file" info box. box_name="Cannot copy program file" but_text="Close" msg="""Unable to copy program file. It may be that another judge copied the file just before you tried to. Just move on to grade the next program, if there is one ready.""" ccpf_info_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "No Data Directory" info box. #box_name="No Judge's Data Directory" #but_text="Close" #msg=""" #Cannot find judge's data directory. #1) Quit RockTest and create a "~/judge/data" # directory. #2) Copy the official data files into that # directory. #3) Then restart the RockTest Judge's Console. #""" #no_data_dir_box=info_box_class(root, box_name, msg, but_text, LEFT) #Create "No Data file" info box. box_name="No Data File Found" but_text="Close" msg=""" Cannot find data file. Click on "Contest/Setup real contest..." or "Contest/Setup practice contest...". If you have already done this, then no data file has been created for this problem. Advise the contest master of this problem immediately. The data file can be copied manually into your $HOME/judge/data directory to fix this problem. """ no_data_file_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "No Source file" info box. box_name="No Source Code File" but_text="Close" msg=""" Cannot find %s program file. """ % conf.lang.get() no_source_file_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "No ML file" info box. box_name="No Machine Code File" but_text="Close" msg=""" Cannot find machine code file. If you have just gotten the program, you need to compile the program first. It is also possible that the compile step failed. If you have submitted judgement on the program, your copy of the source code and object code has been deleted. Wait for a resubmission. """ no_ml_file_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "No judge dir" info box. box_name="No Judge Directory" but_text="Close" msg="""You need a 'judge' directory within your home directory to operate the judge's console. Close this box, close the program, create a ~/judge directory, then restart the judge's console. """ no_judge_dir_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "Excessive run time" info box. box_name="Runtime Limit Exceeded" but_text="Close" msg=""" The program has exceeded the allowable run time. """ excess_run_time_box=info_box_class(root, box_name, msg, but_text, CENTER) #This object not needed anymore? #Create "Press the OK button" info box. #box_name="Notice!" #but_text="Close" #msg=""" #After changing the team, problem number, #programming language, or data file name, #you must press "OK" before proceeding. #""" #press_OK_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "Supervisor's usercode missing" info box. box_name="Missing usercode!" but_text="Close" msg=""" Enter supervisor's usercode before pressing the 'Copy Files' button. """ missing_usercode_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "Wrong permissions box" info box. box_name="Wrong permissions!" but_text="Close" msg=""" The contest supervisor's home directory must give execute permission to group and others. Cannot proceed.""" wrong_perms_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "Trial Contest Ready box" info box. box_name="Trial Contest Ready" but_text="OK" msg=""" The data for the trial contest has been copied into your \"$HOME/judge/data\" directory. """ trial_contest_ready_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "Contest Ready box" info box. box_name="Contest Ready" but_text="OK" msg=""" The data for the contest has been copied into your \"$HOME/judge/data\" directory. """ contest_ready_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "View Parameters" info box. box_name = "Parameters" but_text="OK" msg='Number of teams: %d\nNumber of problems: %d\n'%(conf.team_count, conf.prob_count) param_info_box=info_box_class(root, box_name, msg, but_text, LEFT) #Create "File Taken" info box. box_name = "File taken" but_text="OK" msg=""" Another judge is grading the program. Check again later for additional programs to judge.""" file_taken_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "Request Taken" info box. box_name = "Request taken" but_text="OK" msg=""" Another judge is handling the clarification request. Check again for clarification requests about other problems.""" req_taken_box=info_box_class(root, box_name, msg, but_text, CENTER) class start_contest_dialog_class: def __init__(self, parent, msg, name, data_kind): self.msg=StringVar() self.msg.set(msg) self.parent = parent self.name = name self.data_kind = data_kind #trial_data or data self.ok_button_text = "Copy Files" self.cancel_button_text = "Cancel" self.user=StringVar() self.user.set("") def close(self): #Close the dialog box. self.start_contest_dialog.destroy() def contest_setup(self): #print "Data kind: ", self.data_kind if len(self.user.get()) == 0: missing_usercode_box.create() return #First, check that contest supervisor's ~/judge/trial_data directory has #read and execute access for the group. status, output=commands.getstatusoutput( "ls -al ~%s/rocktest/%s | head -2 |tail -1 | grep -v ^......-..-" % (self.user.get(), self.data_kind)) if status != 0: wrong_perms_box.create() else: #Permissions are okay. Create directories and copy data files. #print "Clearing data directory." os.system("rm -f %s/judge/data/*.dat %s/judge/data/*.csv"\ % (conf.judge_home, conf.judge_home)) #print "Command: cp ~%s/rocktest/%s/* %s/judge/data" % \ #(self.user.get(), self.data_kind, conf.judge_home) os.system("rt_cp ~%s/rocktest/%s/* %s/judge/data" % (self.user.get(),\ self.data_kind, conf.judge_home)) if self.data_kind == "trial_data": trial_contest_ready_box.create() else: contest_ready_box.create() self.close() return def create(self): #Create the dialog box. self.start_contest_dialog=Toplevel(self.parent, bg=COLOR) self.start_contest_dialog.title(self.name) self.abt_msg=Message(self.start_contest_dialog, textvariable=self.msg, justify=LEFT, aspect=300, width=400, bg=COLOR).pack(side=TOP) self.entry_frame = Frame(self.start_contest_dialog, bg=COLOR) Label(self.entry_frame, text="Enter contest supervisor's usercode:", bg=COLOR).pack(side=LEFT) self.path_entry=Entry(self.entry_frame, textvariable=self.user, width=15, bg=COLOR2).pack(side=LEFT, expand=NO) self.entry_frame.pack(side=TOP) self.button_frame = Frame(self.start_contest_dialog, bg=COLOR) self.ok_button=Button(self.button_frame, text=self.ok_button_text) self.ok_button.configure(command=self.contest_setup) #self.ok_button.configure(command=lambda obj=self: obj.contest_setup()) self.ok_button.pack(side=LEFT) self.cancel_button=Button(self.button_frame, text=self.cancel_button_text) self.cancel_button.configure(command=lambda obj=self: obj.close()) self.cancel_button.pack(side=RIGHT) self.button_frame.pack(side=BOTTOM) #Create "Start Trial Contest" dialog box. msg = """To start the practice contest, practice data files will be copied from the contest supervisor's $HOME/rocktest/trial_data directory to your $HOME/judge/data directory. """ name = "Set Up Trial Contest" kind = "trial_data" start_trial_dialog=start_contest_dialog_class(root, msg, name, kind) #Create "Start Contest" dialog box. msg = """To start the contest, data files will be copied from the contest supervisor's $HOME/rocktest/data directory to your $HOME/judge/data directory. """ name = "Set Up Contest" kind = "data" start_contest_dialog=start_contest_dialog_class(root, msg, name, kind) class clarif_response_dlg_class: def __init__(self, parent, name): self.msg=StringVar() self.parent = parent self.name = name def close(self): #Close the info box. self.dlg_box.destroy() def get_request(self): #Get text of team's clarification request. prob=strip(gui.prob_to_clarify.get()) if prob=="General": prob="%d" % (conf.prob_count + 1) else: prob=strip(prob[7:]) if atoi(prob) < 10: prob = "0" + prob self.file = commands.getoutput( "ls -tr /tmp/rocktest/submissions/clar_req%s* 2>/dev/null | head -1" % prob) if self.file != "": self.text = commands.getoutput("cat %s" % self.file) #Move the file to the judge's directory to keep others from handling it. os.system('mv %s %s/judge' % (self.file, conf.judge_home)) return self.text else: return "" def create(self, msg=""): #First, lock this section by locking the empty file "rt_lock_r". try: self.lockfile = open("/tmp/rocktest/submissions/rt_lock_r", "w") #fcntl.flock(self.lockfile.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB) fcntl.flock(self.lockfile.fileno(), fcntl.LOCK_EX) except IOError: req_taken_box.create() return req = self.get_request() #Unlock the critical section. self.lockfile.close() if req == "": req_taken_box.create() return #Create the dialog box. self.dlg_box=Toplevel(self.parent, bg=COLOR) self.dlg_box.title(self.name) self.top_frame=Frame(self.dlg_box, width=500, height=45, bg=COLOR) if strip(gui.prob_to_clarify.get()) == "General": Label(self.top_frame, text="%s Clarification Request:" % strip(gui.prob_to_clarify.get()), bg=COLOR, \ font=("Helvetica", 12, "bold")).pack() else: Label(self.top_frame, text="Clarification Request for %s:" % \ strip(gui.prob_to_clarify.get()), bg=COLOR, \ font=("Helvetica", 12, "bold")).pack() self.top_frame.pack(side=TOP) self.req_frame=Frame(self.dlg_box, bg=COLOR2, relief=RIDGE, bd=3) self.req_text=Text(self.req_frame, bg=COLOR2, font=("Courier", 10), wrap=WORD, width=60, height=8) self.req_text.insert(0.0, req) self.vscroll1 = Scrollbar(self.req_frame, command=self.req_text.yview) self.req_text.configure(yscrollcommand=self.vscroll1.set) self.vscroll1.pack(side=RIGHT, expand=NO, fill=Y) self.req_text.pack() self.req_frame.pack(side=TOP) self.second_frame=Frame(self.dlg_box, height=45, bg=COLOR) Label(self.second_frame, text="Judge's Response:", bg=COLOR, font=("Helvetica", 12, "bold")).pack() self.second_frame.pack(side=TOP) self.reply_frame=Frame(self.dlg_box, width=500, height=200, bg=COLOR2, relief=RIDGE, bd=3) self.reply_text=Text(self.reply_frame, bg=COLOR2, font=("Courier", 10), wrap=WORD, width=60, height=8) #Unless judge enters some text, don't allow submission. self.reply_text.bind('', enable_submit_button) self.vscroll2 = Scrollbar(self.reply_frame, command=self.reply_text.yview) self.reply_text.configure(yscrollcommand=self.vscroll2.set) self.vscroll2.pack(side=RIGHT, expand=NO, fill=Y) self.reply_text.pack() self.reply_frame.pack(side=TOP) self.button_frame=Frame(self.dlg_box, width=500, height=45, bg=COLOR2) self.submit_button=Button(self.button_frame, text="Submit",state=DISABLED, \ command=self.submit_req) #self.submit_button.configure(command=lambda obj=self: obj.close()) self.submit_button.grid(row=0, column=0) self.cancel_button=Button(self.button_frame, text="Cancel", command=self.cancel_req) #self.cancel_button.configure(command=lambda obj=self: obj.close()) self.cancel_button.grid(row=0, column=1) self.button_frame.pack() def submit_req(self): self.newtext="\nClarification request:\n\n" + self.req_text.get(0.0, END) + \ "\nJudges' response:\n\n" + self.reply_text.get(0.0, END) + "\n" #Lock this section by locking the empty file "rt_lock_c". self.lockfile_c = open("/tmp/rocktest/rt_lock_c", "w") fcntl.flock(self.lockfile_c.fileno(), fcntl.LOCK_EX) #Open the clarifications file, read it, and close it. self.clarifile = open("/tmp/rocktest/clarifications", "r") self.clartext=self.clarifile.read() self.clarifile.close() self.prob=strip(gui.prob_to_clarify.get()) self.loc=find(self.prob, " ") if self.loc > 0: self.prob=self.prob[:self.loc] + self.prob[self.loc+1:] self.prob=self.prob + ":" #Insert the new text in the appropriate place. self.loc = find(self.clartext, self.prob) + len(self.prob) + 1 self.clartext=self.clartext[:self.loc] + self.newtext + self.clartext[self.loc:] #Eliminate multiple blank lines. self.loc=find(self.clartext, "\n\n\n") while self.loc > 0: self.clartext = self.clartext[:self.loc] + self.clartext[self.loc+1:] self.loc=find(self.clartext, "\n\n\n") os.system('echo "%s" > /tmp/rocktest/clarifications' % self.clartext) #Next, delete the clarification request file from judge's directory. os.system("rm -f %s/judge%s" % (conf.judge_home, self.file[rfind(self.file, '/'):])) self.lockfile_c.close() #Unlocks the clarifications file. self.close() def cancel_req(self): self.req_text.delete(0.0, END) self.reply_text.delete(0.0, END) #Copy the clarification request file back to submissions: os.system('cp %s/judge%s %s' % (conf.judge_home, self.file[rfind(self.file, '/'):], self.file)) self.close() #Close the window. #def enable_submit(self): # self.submit_button.configure(state=NORMAL) clarif_response_dlg = clarif_response_dlg_class(root, "Clarification Response") def kill_program(pfn): #print "Entering 'kill_program()'" #Kill a user program that's been running too long. #First, find the pid of the running program. #Actually, there are several processes to kill. for proc in os.popen( #For Linux: 'ps -ao pid,args | grep -i \"%s\" | grep -v grep' % (pfn)).readlines(): #For Solaris: #'ps -eo pid,args | grep -i \"%s\" | grep -v grep' % (pfn)).readlines(): pid = split(proc)[0] #Now kill it! os.system("kill -9 %s" % pid) excess_run_time_box.create() return class Execute(threading.Thread): def run(self): lang = conf.lang.get() dfn = conf.dfn.get() pfn = conf.prog_fn #Convert runlimit to milliseconds, and to an int. rl = conf.runlimit.get() if rl[-3:] == "sec": runlimit = atoi(rl[:-4]) * 1000 else: #minutes runlimit = atoi(rl[:-4]) * 60000 #Set a limit timer to stop runaway programs. id = root.after(runlimit, kill_program, pfn[:find(pfn, '.')]) if lang == "BASIC": output = commands.getoutput(\ "nice -19 bwbasic %s/judge/%s < %s/judge/data/%s" %\ (conf.judge_home, pfn, conf.judge_home, dfn)) #Remove carriage returns from BwBASIC output. output = strip_cr(output) #Remove BWBASIC: prompt from last line of output. loc = rfind(output, '\n') output = output[:loc+1] #Remove "? " prompt from input statement's output. loc = 99999 while loc >=0: loc = find(output, '\n? ') if loc >=0: output = output[:loc] + output[loc+3:] #For JDK Java #elif lang == "Java": #output = commands.getoutput( #"cd %s/judge && nice -19 java %s < %s/judge/data/%s && cd %s"\ #% (conf.judge_home, pfn[:find(pfn, '.')], conf.judge_home,\ #dfn, conf.judge_home)) #For gcj Java and other compiled languages elif conf.lang.get() in ("C", "C++", "FORTRAN", "Java", "Pascal"): output = commands.getoutput("nice -19 %s/judge/%s < %s/judge/data/%s"\ % (conf.judge_home, pfn[:find(pfn, '.')], conf.judge_home, dfn)) elif conf.lang.get() == "PHP": output = commands.getoutput( "nice -19 php -q %s/judge/%s < %s/judge/data/%s" % \ (conf.judge_home, pfn, conf.judge_home, dfn)) elif conf.lang.get() == "Python": output = commands.getoutput( "nice -19 python %s/judge/%s < %s/judge/data/%s" % \ (conf.judge_home, pfn, conf.judge_home, dfn)) else: print "Error. Undefined programming language." sys.exit(1) root.after_cancel(id) gui.textbox.insert(END, output) #These next functions are needed because .bind() cannot pass any parameters, # not even the object name, to the function that is to be bound. def delay_set_team_num(x): #print "set_team_no() called." gui.delay_set_team_no() def disable_act_buttons(x): gui.disable_action_buttons() def edit_clarif_file(): os.system("kwrite /tmp/rocktest/clarifications >/dev/null 2>&1 &") def enable_submit_button(x): clarif_response_dlg.submit_button.configure(state=NORMAL) class gui_class: def __init__(self, root): root.minsize(800,450) root.maxsize(800, 1000) h=39 #Height of setup frame. self.timer_id = -1 #Used for timer in self.check_ungraded(). #Build menubar and drop-down menus. self.menubar = Menu(root, relief=SUNKEN) #Create a pulldown file menu, and add it to the menu bar. self.file_menu=Menu(self.menubar, tearoff=0) self.file_menu.add_command(label="Quit", command=root.quit) self.menubar.add_cascade(label="File", menu=self.file_menu) #Create a pulldown view menu, and add it to the menu bar. self.view_menu=Menu(self.menubar, tearoff=0) #self.view_menu.add_command(label="Change Team Number Control", # command=self.toggle_team_no_widget) self.view_menu.add_command(label="Font size...", command=self.change_font_size) self.menubar.add_cascade(label="View", menu=self.view_menu) #Create a pulldown contest menu, and add it to the menu bar. self.contest_menu=Menu(self.menubar, tearoff=0) self.contest_menu.add_command(label="Clear contestants' directories...", command=del_warning_box.create) self.contest_menu.add_command(label="Set up practice contest...", command=start_trial_dialog.create) self.contest_menu.add_command(label="Set up real contest...", command=start_contest_dialog.create) self.menubar.add_cascade(label="Contest", menu=self.contest_menu) #Create a pulldown clarifications menu, and add it to the menu bar. self.clarif_menu=Menu(self.menubar, tearoff=0) self.clarif_menu.add_command(label="Edit Clarification File", command=edit_clarif_file) self.menubar.add_cascade(label="Clarifications", menu=self.clarif_menu) #Create a pulldown help menu, and add it to the menu bar. self.help_menu=Menu(self.menubar, tearoff=0) self.help_menu.add_command(label="Help...", command=help_info_box.create) self.help_menu.add_command(label="View program parameters...", \ command=param_info_box.create) self.help_menu.add_command(label="About RockTest...", command=about_info_box.create) self.menubar.add_cascade(label="Help", menu=self.help_menu) self.timestamp=StringVar() root.config(menu=self.menubar) root.config(bg=COLOR) #Create the top frame. self.topframe = Frame(root, bg=COLOR, width=800, height= 2 * h) self.to_grade_frame = Frame(self.topframe, bg=COLOR, borderwidth=3,\ relief=RIDGE, height=h, width=310) Label(self.to_grade_frame, text="Ungraded Programs:", wraplength=90, \ bg=COLOR ).place(anchor=W, x=0, rely=0.5) self.prog_ct = StringVar() Label(self.to_grade_frame, textvariable = self.prog_ct, bg=COLOR2, width=5, \ relief=SUNKEN, justify=CENTER).place(anchor=W, x=70, rely=0.5) self.update_button = Button(self.to_grade_frame, text="Update",\ command=self.check_ungraded) self.update_button.place(anchor=W, x=115, rely=0.5) self.get_pgm_button=Button(self.to_grade_frame, text="Get program",\ state=DISABLED, command=self.prep_problem, width=9) self.get_pgm_button.place(anchor=W, x=200, rely=0.5) #self.to_grade_frame.pack(side=LEFT) self.to_grade_frame.place(anchor=NW, x=0, y=0) self.clarif_frame=Frame(self.topframe, bg=COLOR2, borderwidth=3,\ relief=RIDGE, height=h, width=460) Label(self.clarif_frame, text="Clarification\nrequests:", \ bg=COLOR2).place(anchor=NW, x=0, y=0) self.clar_upd_button=Button(self.clarif_frame, text="Update", \ command=self.update_clars) self.clar_upd_button.place(anchor=NW, x=80, y=0) Label(self.clarif_frame, text="Select\nsubject:", bg=COLOR2)\ .place(anchor=NW, x=170, y=0) self.prob_to_clarify=StringVar() self.prob_to_clarify.set(" General ") self.avail_reqs=[" General "] self.clar_req_menu=OptionMenu(self.clarif_frame, self.prob_to_clarify, \ *self.avail_reqs) self.clar_req_menu.configure(state=DISABLED) self.clar_req_menu.place(anchor=NW, x=230, y=0) self.respond_button=Button(self.clarif_frame, text="Respond", \ command=self.respond_to_clar_req, state=DISABLED) self.respond_button.place(anchor=NE, relx=1.0, y=0) self.clarif_frame.place(anchor=NE, relx=1.0, y=0) self.setup_frame = Frame(self.topframe, bg=COLOR, borderwidth=3, \ relief=RIDGE, height=h, width=500) Label(self.setup_frame, text="Team:",bg=COLOR).place(anchor=W, x=0, rely=0.5) Label(self.setup_frame, textvariable=conf.team_no, relief=SUNKEN, \ bg=COLOR2, width=4).place(anchor=W, x=45, rely=0.5) Label(self.setup_frame, text="Problem Number:", bg=COLOR, wraplength=80)\ .place(anchor=W, x=90, rely=0.5) Label(self.setup_frame, textvariable=conf.prob_no, relief=SUNKEN,\ bg=COLOR2, width=4).place(anchor=W, x=150, rely=0.5) Label(self.setup_frame, text="Programming Language:", bg=COLOR, \ wraplength=100).place(anchor=W, x=192, rely=0.5) Label(self.setup_frame, textvariable=conf.lang, relief=SUNKEN, bg=COLOR2,\ width=10).place(anchor=W, x=278, rely=0.5) Label(self.setup_frame, text="Timestamp:", width=11, bg=COLOR)\ .place(anchor=W, x=362, rely=0.5) self.ts=Label(self.setup_frame, textvariable=self.timestamp,\ relief=SUNKEN, width=6, bg=COLOR2).place(anchor=W, x=442, rely=0.5) #self.lang_menu.bind('', disable_act_buttons) #self.lang_menu.place(anchor=W, x=325, rely=0.5) self.setup_frame.place(anchor=NW, x=0,y=h) self.topframe.pack(side=TOP, expand=NO) #Create the control (lower) frame. self.control_frame=Frame(root, bg=COLOR, borderwidth=3, relief=RIDGE,\ height=75, width=800) Label(self.control_frame, text="Data\nfile:", bg=COLOR, wraplength=60)\ .place(anchor=W, x=0, rely=0.25) self.df_menu_x = 190 self.df_menu = OptionMenu(self.control_frame, conf.dfn, *conf.avail_dfs) self.df_menu.place(anchor=E, x=self.df_menu_x, rely=0.25) self.max_rt_label = Label(self.control_frame, text="Runtime\nLimit:",\ bg=COLOR).place(anchor=W, x=0, rely=0.75) self.max_rt_menu=OptionMenu(self.control_frame, conf.runlimit,\ "10 sec","30 sec", " 1 min"," 5 min") self.max_rt_menu.place(anchor=E, x=self.df_menu_x, rely=0.75) self.button_frame=Frame(self.control_frame) self.cb=Button(self.button_frame, text="Compile", width=12, state=DISABLED, command=self.compile) self.cb.grid(row=0, column=0) self.rb=Button(self.button_frame, text="Run", width=12,\ state=DISABLED, command=self.run) self.rb.grid(row=0, column=1) self.vb=Button(self.button_frame, text="View source", width=12,\ state=DISABLED, command=self.view_source) self.vb.grid(row=1, column=0) self.lb=Button(self.button_frame, text="List Team Files", width=12, command=self.list_team_dir) self.lb.grid(row=1, column=1) self.button_frame.place(anchor=W, x=220, rely=0.5) Label(self.control_frame, text="Ruling:", bg=COLOR).place(\ anchor=CENTER, x=595, rely=0.25) self.judgement_menu=OptionMenu(self.control_frame, conf.ruling, \ *conf.judgements).place(anchor=CENTER, x=595, rely=0.75) self.submit_button=Button(self.control_frame, text="Submit Ruling",\ state=DISABLED, height=3, wraplength=60, command=self.submit) self.submit_button.place(anchor=E, relx=1.0, rely=0.5) self.control_frame.pack(side=TOP, expand=NO) self.action_frame=Frame(root, bg=COLOR2, borderwidth=3) self.textbox = Text(self.action_frame, wrap=WORD, width=133, font=("Courier", 10), bg=COLOR2, relief=RIDGE) self.vscroll = Scrollbar(self.action_frame, command=self.textbox.yview) self.textbox.configure(yscrollcommand=self.vscroll.set) self.vscroll.pack(side=RIGHT, expand=YES, fill=Y) self.textbox.pack(side=RIGHT, expand=YES, fill=BOTH) #vert_size=root.winfo_height() #print vert_size #self.action_frame.place(x=0, y=2.5*h+8, relheight=0.71, relwidth=1.0) ##### self.action_frame.pack(side=TOP, expand=NO) #Create ~judge and ~judge/data directories. if not ("judge" in os.listdir("%s" % conf.judge_home)): os.makedirs("%s/judge" % conf.judge_home) os.system("chgrp rocktest %s/judge" % conf.judge_home) os.chmod("%s/judge" % conf.judge_home, 488) #488_ten == 750_eight if not ("data" in os.listdir("%s/judge" % conf.judge_home)): os.makedirs("%s/judge/data" % conf.judge_home) os.system("chgrp rocktest %s/judge/data" % conf.judge_home) os.chmod("%s/judge/data" % conf.judge_home, 1512) #1512_ten == 2750_eight def respond_to_clar_req(self): self.disable_response_buttons() clarif_response_dlg.create() def update_clars(self): status, self.clar_req_list =commands.getstatusoutput(\ "ls -t /tmp/rocktest/submissions | grep \"clar_req\" | sed 's/clar_req//' | awk -F- '{print $1}' | uniq") #print self.clar_req_list self.avail_reqs=[] if not self.clar_req_list: #print "No outstanding requests" self.avail_reqs.append(" None ") self.respond_button.configure(state = DISABLED) else: while len(self.clar_req_list) > 1: #print "Length = ", len(self.clar_req_list) no = self.clar_req_list[:2] #Note: "no" is a string of numerals if atoi(no) == conf.prob_count + 1: self.avail_reqs.append(" General ") else: if atoi(no) < 10: no = no[1] #Truncate leading zero. self.avail_reqs.append("Problem %2s" % no) self.clar_req_list = self.clar_req_list[3:] #print "self.avail_reqs = \n", self.avail_reqs self.prob_to_clarify.set(self.avail_reqs[0]) self.clar_req_menu.destroy() self.clar_req_menu=OptionMenu(self.clarif_frame, self.prob_to_clarify, \ *self.avail_reqs) self.clar_req_menu.place(anchor=NW, x=230, y=0) if strip(self.prob_to_clarify.get()) != "None": self.respond_button.configure(state=NORMAL) id = self.respond_button.after(30000, self.disable_response_buttons) def disable_response_buttons(self): self.clar_req_menu.configure(state=DISABLED) self.respond_button.configure(state=DISABLED) def check_ungraded(self): if self.timer_id != -1: self.get_pgm_button.after_cancel(self.timer_id) self.timer_id = -1 status, self.filelist=commands.getstatusoutput(\ "ls -t /tmp/rocktest/submissions | grep \"program\"") #print self.filelist status, prog_ct = commands.getstatusoutput(\ "ls /tmp/rocktest/submissions | grep \"program\" | wc -l") #print prog_ct self.prog_ct.set(prog_ct) if atoi(prog_ct) > 0: self.get_pgm_button.configure(state=NORMAL) else: self.get_pgm_button.configure(state=DISABLED) #Check automatically every 3 minutes. self.timer_id = self.get_pgm_button.after(180000, self.check_ungraded) def create_team_entry(self): self.team_entry=Entry(self.setup_frame, textvariable=conf.team_no, width=3, justify=CENTER, bg=COLOR2) self.team_entry.bind('', disable_act_buttons) self.team_entry.place(anchor=W, x=45, rely=0.5) def delay_set_team_no(self): self.team_menu.after(3000, self.set_team_no) def set_team_no(self): conf.team_name = "team" + conf.team_no.get() #print "Team name is now ", conf.team_name def change_font_size(self): self.fontsz_listbox=Listbox(root, width=3, bg=COLOR2, selectmode=SINGLE) self.fontsz_listbox_exists=TRUE for num in ("6","8","10","12","14","16","18"): self.fontsz_listbox.insert(END, num) self.fontsz_listbox.place(x=50,y=7,height=18*self.fontsz_listbox.size()) self.fontsz_listbox.tkraise() self.fontsz_listbox.bind('', lambda event, obj=self: obj.set_font_size(), '+') def set_font_size(self): point_size=self.fontsz_listbox.get(self.fontsz_listbox.curselection()[0]) self.textbox.configure(font=("Courier", atoi(point_size))) self.fontsz_listbox.destroy() def enable_action_buttons(self): self.cb.configure(state=NORMAL) self.rb.configure(state=NORMAL) self.vb.configure(state=NORMAL) def disable_action_buttons(self): self.textbox.delete(1.0, END) self.cb.configure(state=DISABLED) self.rb.configure(state=DISABLED) self.vb.configure(state=DISABLED) def prep_problem(self): #"~/judge" directory must already exist. if not ("judge" in os.listdir("%s" % conf.judge_home)): no_judge_dir_box.create() return #First, lock this section by locking the empty file "rt_lock_p". try: output=commands.getoutput('ls -l /tmp/rocktest/submissions/rt_lock_p /tmp/rocktest/submissions/rt_lock_r') #print output #print "Locking rt_lock_p" file = open("/tmp/rocktest/submissions/rt_lock_p", "w") fcntl.flock(file.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB) #print "rt_lock_p locked, non-blocking. Program collection locked." output=commands.getoutput('ls -l /tmp/rocktest/submissions/rt_lock_p /tmp/rocktest/submissions/rt_lock_r') #print output except: file_taken_box.create() return #Check that there is still a program to grade. status, prog_ct = commands.getstatusoutput(\ 'ls /tmp/rocktest/submissions | grep "program" | wc -l') self.prog_ct.set(prog_ct) if atoi(prog_ct) == 0: file.close() #print "rt_lock_p unlocked. Program collection unlocked." file_taken_box.create() return else: #Get the filename from an up-to-date file listing. filename = commands.getoutput(\ "ls -t /tmp/rocktest/submissions | grep \"program\" | tail -1") #print "Filename is ", filename self.cert_fn = filename[:find(filename,".")] if not os.path.exists("/tmp/rocktest/certificates/" + self.cert_fn): os.system("touch /tmp/rocktest/certificates/%s" % self.cert_fn) status, output = commands.getstatusoutput(\ "mv -f /tmp/rocktest/submissions/%s ~/judge" % filename) if status != 0: file.close() #print "rt_lock_p unlocked. Program collection unlocked." output=commands.getoutput('ls -l /tmp/rocktest/submissions/rt_lock_p /tmp/rocktest/submissions/rt_lock_r') #print output ccpf_info_box.create() return #Now that the file has been moved, it is safe to unlock. file.close() #Unlocks the file. #print "rt_lock_p unlocked. Program collection unlocked." #Set parameters. conf.prog_fn = filename #Get file timestamp. status, output = \ commands.getstatusoutput("ls -l ~/judge/%s | awk '{print $8}'" % \ conf.prog_fn) if status == 0: #Note that timestamp ignores date. self.timestamp.set(output) #Get file's team number. i = find(filename,"-") + 1 conf.team_no.set(filename[i:i+2]) conf.team_name = "team" + conf.team_no.get() #Get problem number. i = i - 1 conf.prob_no.set(filename[7:i]) #Get programming language. ext = filename[find(filename,"."):] for lang in conf.ext_map: if conf.ext_map[lang] == ext: break if ext == conf.ext_map[lang]: conf.lang.set(lang) else: print "Unknown programming language." sys.exit(1) #Write file parameters to certificate file. #os.system("echo \"Team: %s\nProblem: %s\nLanguage: %s\nTimestamp: %s\" > /tmp/rocktest/certificates/%s"\ # % (conf.team_no.get(), conf.prob_no.get(), conf.lang.get(), \ # self.timestamp.get(), self.cert_fn)) #Reconfigure the datafile menu to reflect the problem number. avail_dfs=[] prob_no = conf.prob_no.get() #print "prob_no =", prob_no dflist= commands.getoutput("ls ~/judge/data | grep \"program%s\"" %\ prob_no) #print "dflist = ", dflist #for file in dflist: while len(dflist) > 7: #while find(dflist,"\n") >= 0: i = find(dflist, '\n') #print "i = ", i if i == -1: file = dflist[0:] dflist="" else: file = dflist[:i] dflist = dflist[i+1:] #print "file is ", file #rint "dflist = ", dflist no = file[7:find(file,".")] #Trim trailing "a", "b", etc. if no[-1:] not in "0123456789": no = no[:-1] #print no, prob_no avail_dfs.append(file) #print "avail_dfs = ", avail_dfs #sys.exit(1) conf.avail_dfs = avail_dfs #print "avail_dfs[0] =\n", avail_dfs[0] #print "avail_dfs =", avail_dfs try: conf.dfn.set(avail_dfs[0]) except IndexError: no_data_file_box.create() return self.df_menu.destroy() self.df_menu = OptionMenu(self.control_frame, conf.dfn, *conf.avail_dfs) self.df_menu.place(anchor=E, x=self.df_menu_x, rely=0.25) #Disable "update" and "get program" buttons until this program is graded. self.get_pgm_button.configure(state=DISABLED) self.update_button.configure(state=DISABLED) try: #Remove machine code file if one exists. os.remove("%s/judge/%s" % (conf.judge_home, fn)) except: pass self.enable_action_buttons() #Disable "compile" button for interpreted languages. if conf.lang.get() in conf.no_compile: self.cb.configure(state=DISABLED) gui.submit_button.configure(state=DISABLED) def submit(self): #Submit the judge's ruling #os.system("echo \"Ruling: %s\" >> /tmp/rocktest/certificates/%s" % \ # (conf.ruling.get(), self.cert_fn)) self.update_button.configure(state=NORMAL) #Remove source code and object code files. os.system("rm -f ~/judge/%s" % conf.prog_fn) if not (conf.lang.get() in conf.no_compile): os.system("rm -f ~/judge/%s" % conf.prog_fn[:find(conf.prog_fn,'.')]) #Append the ruling to the tabulation file. #Does the tabulation file exist? #First, lock this section by locking the empty file "rt_lock_t". self.tablockfile = open("/tmp/rocktest/rt_lock_t", "w") fcntl.flock(self.tablockfile.fileno(), fcntl.LOCK_EX) #print "rt_lock_t locks tabulation file." status, output =commands.getstatusoutput('ls /tmp/rocktest | grep "tabulation"') #print "Status = %s\n" % status #print "Output = ", output if status != 0: os.system('echo "#TEAM PROBLEM RULING TIMESTAMP" > /tmp/rocktest/tabulation') else: #This may not be necessary anymore. self.line_ct=commands.getoutput('cat /tmp/rocktest/tabulation | wc -l') if self.line_ct == "0": os.system('echo "#TEAM PROBLEM RULING TIMESTAMP" >> /tmp/rocktest/tabulation') ruling_no = 0 #output = commands.getoutput("cat /tmp/rocktest/tabulation") #print "Before update:\n", output while conf.judgements[ruling_no] != conf.ruling.get(): ruling_no += 1 os.system('echo "%s %s %s %s" >> /tmp/rocktest/tabulation' % (conf.team_name, conf.prob_no.get(), ruling_no, gui.timestamp.get())) #output = commands.getoutput("cat /tmp/rocktest/tabulation") #print "After update:\n", output #Next, prepend a certificate to the team's "certificates" file in # its "certificates" directory. os.system('echo "Team: %s\nProblem: %s\nLanguage: %s\nTimestamp: %s\nRuling: %s" > %s/tempo'\ % (conf.team_no.get(), conf.prob_no.get(), conf.lang.get(), \ self.timestamp.get(), conf.ruling.get(), conf.judge_home)) os.system("rt_update ~%s/certificates/certificates %s/tempo" % (conf.team_name, conf.judge_home)) os.system("rm %s/tempo" % conf.judge_home) gui.submit_button.configure(state=DISABLED) #Unlock the critical section. self.tablockfile.close() #print "rt_lock_t unlocked. Tabulation file unlocked." self.disable_action_buttons() self.textbox.delete(1.0, END) self.textbox.insert(END, "Judgement submitted.") return def compile(self): #Does source program file exist? if not (conf.prog_fn in os.listdir("%s/judge" % conf.judge_home)): no_source_file_box.create() return self.textbox.delete(1.0, END) if conf.lang.get() in conf.no_compile: #No compiler for these languages. output = "No compilation needed for this programming language." return self.textbox.insert(END, "Compiling. Please wait.") if conf.lang.get()=="C": #output = commands.getoutput("gcc -lm -o ~/judge/%s ~/judge/%s" %\ #(conf.prog_fn[:find(conf.prog_fn,'.')], conf.prog_fn)) output = commands.getoutput("gcc -lm -o %s/judge/%s %s/judge/%s"\ % (conf.judge_home, conf.prog_fn[:find(conf.prog_fn,'.')], \ conf.judge_home, conf.prog_fn)) if output == "": output = "Compile successful.\n" elif conf.lang.get()=="C++": output = commands.getoutput("g++ -lm -o %s/judge/%s %s/judge/%s"\ % (conf.judge_home, conf.prog_fn[:find(conf.prog_fn,'.')], \ conf.judge_home, conf.prog_fn)) if output == "": output = "Compile successful.\n" elif conf.lang.get()=="FORTRAN": output = commands.getoutput("f77 -o %s/judge/%s %s/judge/%s" %\ (conf.judge_home, conf.prog_fn[:find(conf.prog_fn,'.')], \ conf.judge_home, conf.prog_fn)) if output == "": output = "Compile successful.\n" elif conf.lang.get()=="Java": #For JDK Java #output = commands.getoutput("javac %s/judge/%s" % (conf.judge_home, conf.prog_fn)) #Compiling gcj: #output = commands.getoutput("gcj --main=%s -o ~/judge/%s ~/judge/%s" \ #% (conf.prog_fn[:find(conf.prog_fn,'.')], \ #conf.prog_fn[:find(conf.prog_fn,'.')], \ #conf.prog_fn)) self.dash_spot = find(conf.prog_fn,'-') self.dot_spot = find(conf.prog_fn,'.') self.temp_fn = conf.prog_fn[:self.dash_spot] + conf.prog_fn[self.dot_spot:] os.system('cp -f %s/judge/%s %s/judge/%s' % \ (conf.judge_home, conf.prog_fn, conf.judge_home, self.temp_fn)) output = commands.getoutput("gcj --main=%s -o %s/judge/%s %s/judge/%s" \ % (self.temp_fn[:find(self.temp_fn,'.')], conf.judge_home,\ conf.prog_fn[:self.dot_spot], conf.judge_home,\ self.temp_fn)) os.system('rm -f %s/judge/%s' % (conf.judge_home, self.temp_fn)) if output == "": output = "Compile successful.\n" elif conf.lang.get() == "Pascal": status, output = commands.getstatusoutput( "fpc -Co -Cr -o%s/judge/%s -Se10 -vew %s/judge/%s" % \ (conf.judge_home, conf.prog_fn[:find(conf.prog_fn,'.')], conf.judge_home, conf.prog_fn)) ##Using P2C to preprocess. #status, output = commands.getstatusoutput( # "p2c -a %s/judge/%s 2> /dev/null" % (conf.judge_home, conf.prog_fn)) ##If the status is zero and the filename does not appear in the ##preprocessor output, there are no errors or warnings. #stat = find(output, conf.prog_fn) #if (status == 0 and stat < 0): # commands.getoutput("p2cc -o %s/judge/%s %s/judge/%s" % \ # (conf.judge_home, conf.prog_fn[:find(conf.prog_fn,'.')],\ # conf.judge_home, conf.prog_fn)) #else: # status=1 #output=commands.getoutput('echo "%s" | grep -v Translation' % output) #output=output + "\nTranslation aborted.\n" if (output == "" or status == 0): output = output + "\nCompile successful.\n" self.textbox.delete(1.0, END) self.textbox.insert(END, output) def run(self): self.submit_button.configure(state=NORMAL) lang = conf.lang.get() dfn = conf.dfn.get() pfn = conf.prog_fn if lang in conf.no_compile: #Does source program file exist? if not (pfn in os.listdir("%s/judge" % conf.judge_home)): no_source_file_box.create() return else: #Does machine language program file exist? #Code for JDK Java: #if conf.lang.get() == "Java": #if not ((pfn[:find(pfn,".")] + ".class") in \ #os.listdir("%s/judge" % conf.judge_home)): #no_ml_file_box.create() #return #elif #Remove "if" from next line if uncommenting this line. if not (pfn[:find(pfn,'.')] in os.listdir("%s/judge" % conf.judge_home)): no_ml_file_box.create() return #Does data file exist? if not (dfn in os.listdir("%s/judge/data" % conf.judge_home)): no_data_file_box.create() return #Clear previous output. self.textbox.delete(1.0, END) #Execute the program as a separate thread. Execute().start() def list_team_dir(self): #conf.team_name may not be up-to-date. status, dir = commands.getstatusoutput( "ls -l %steam%s" % (conf.teams_home[:-4], conf.team_no.get())) self.textbox.delete(1.0, END) self.textbox.insert(END, dir) def view_source(self): self.textbox.delete(1.0, END) source=commands.getoutput("cat %s/judge/%s" % \ (conf.judge_home, conf.prog_fn)) self.textbox.insert(END, source) conf=conf_class() gui=gui_class(root) root.mainloop()