#!/usr/bin/env python #RockTest #Programming Competition Judge's Console, "rt_judge", V1.2.3 #Last modification: February 29, 2004 #RockTest consists primarily of two GUI programs: RockTest Team Console, # and RockTest Judge's Console. There are also a spreadsheet for # tabulation and help files. #Copyright 2003, 2004 #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 #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. #Bugs: none known. #Features needed: # SRU "Rock" icon # Log file # Problem queueing # Clarification acceptance and response #See the comments in RockTest Team Console for more information. from Tkinter import * from string import * import os import commands import threading FALSE=0 TRUE=1 COLOR="#c5ffc5" COLOR2="#ffffcc" root=Tk() root.title("RockTest Judge's Console") 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.team_no.set("01") self.prob_no.set("1") self.lang.set("C++") self.dfn.set("program1.dat") self.output.set("") self.ext_map={"BASIC":".bas","C":".c","C++":".cpp","FORTRAN":"for", \ "Java":".java","Pascal":".pas","Python":".py"} self.no_compile = ("BASIC", "Python") self.team_name = "team01" self.prog_fn = "program1.cpp" #Find judge's home directory. self.home_dir = commands.getoutput("echo $HOME") conf=conf_class() def clear_dirs(): #Clear old program files from teams' directories. #First, find where team home directories are. #Assume there will always be a "team01". team_home = commands.getoutput("cd ~team01; pwd") team_home = team_home[:rfind(team_home, '/')] for i in range(99): #Loop through all teams' names no = i + 1 team = "team" if no < 10: team = "team0" team = team + "%d" % no try: output = os.listdir("%s/%s" % (team_home, team)) for file in output: if file[:7] == "program": #print file os.remove("%s/%s/%s" % (team_home, team, file)) except OSError: pass 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. """ 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. 1.2.3 Copyright 2003, 2004 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) Set the team number, problem number, programming language, and data file name by clicking on the appropriate widget and selecting the desired setting. 2) Then click on the "OK" button. This will enable the buttons in the next row. 3) 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. 4) To run the program with the selected data file, click on the "Run" button. The output will appear in the lower pane. 5) If the program does not run to completion, you can set a different runtime limit by clicking on the "Runtime Limit:" button. 6) 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. 7) 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. Check that the team number, problem number, and programming language options are all properly set. If so, check that team directories are group-owned by 'rocktest', with read and write permissions for the group. Also check that the file for this program is group-owned by 'rocktest' and sgid rocktest.""" 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. Be sure you have entered its correct name in the "Data File Name" entry. Data files should be in the "~/judge/data" directory. """ 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. You need to compile the program first. It is also possible that the compile step failed. """ 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) #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) 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/judge/%s | head -2 |tail -1 | grep -v ^......-..-" % (self.user.get(), self.data_kind)) #print "Output: ", output #print "Status is ", status 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 ~/judge/data/*.dat ~/judge/data/*.csv > /dev/null 2>&1") print "Copying data from ~%s/judge/%s" % (self.user.get(), self.data_kind) os.system("cp ~%s/judge/%s/* ~/judge/data" % (self.user.get(), self.data_kind)) 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=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/judge/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/judge/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) 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( 'ps -ao 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.home_dir, pfn, conf.home_dir, 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:] elif conf.lang.get() in ("C", "C++", "FORTRAN", "Java", "Pascal"): output = commands.getoutput("nice -19 %s/judge/%s < %s/judge/data/%s"\ % (conf.home_dir, pfn[:find(pfn, '.')], conf.home_dir, dfn)) elif conf.lang.get() == "Python": output = commands.getoutput( "nice -19 python %s/judge/%s < %s/judge/data/%s" % \ (conf.home_dir, pfn, conf.home_dir, dfn)) else: print "Error. Undefined programming language." sys.exit(1) root.after_cancel(id) gui.textbox.insert(END, output) class gui_class: def __init__(self, root): root.minsize(720,450) root.maxsize(1000, 1000) h=45 #Height of setup frame. #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="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="Set up practice contest...", command=start_trial_dialog.create) self.contest_menu.add_command(label="Clear contestants' directories...", command=del_warning_box.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 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="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) self.setup_frame = Frame(root, bg=COLOR, borderwidth=3, relief=RIDGE, height=h) #, width=700) Label(self.setup_frame, text="Team:",bg=COLOR).place(anchor=W, x=0, rely=0.5) #Team-number widget options: #Use this code if you want team number to be in an option menu, BUT # make sure the options all fit on the judge's screen, or some will not # be available. #self.team_menu= OptionMenu(self.setup_frame, conf.team_no, "01",\ # "02","03","04","05","06","07","08","09","10","11","12","13","14",\ # "15","16","17","18","19","20","21","22","23","24","25","26","27",\ # "28","29","30","31","32","33","34","35","36","37","38","39","40") #self.team_menu.bind('', lambda event, obj=self: \ # obj.disable_action_buttons(), '+') #self.team_menu.place(anchor=W, x=45, rely=0.5) #Use this code if you want the judge to type the team number into an entry # box. Not as friendly as the above code, but uses less monitor real # estate. Judge must remember to enter the leading zero for teams # numbered below 10. self.team_entry=Entry(self.setup_frame, textvariable=conf.team_no, width=3, justify=CENTER, bg=COLOR2) self.team_entry.bind('', lambda event, obj=self: \ obj.disable_action_buttons(), '+') self.team_entry.place(anchor=W, x=45, rely=0.5) #End of team-number widget options. Label(self.setup_frame, text="Problem Number:", bg=COLOR, wraplength=80)\ .place(anchor=W, x=120, rely=0.5) self.prob_no_menu = OptionMenu(self.setup_frame, conf.prob_no,\ "1","2","3","4","5","6","7","8","9","10") self.prob_no_menu.bind('', \ lambda event, obj=self: obj.disable_action_buttons(), '+') self.prob_no_menu.place(anchor=W, x=175, rely=0.5) Label(self.setup_frame, text="Programming Language:", bg=COLOR, \ wraplength=100).place(anchor=W, x=243, rely=0.5) self.lang_menu = OptionMenu(self.setup_frame, conf.lang,\ "BASIC","C","C++","FORTRAN", "Java","Pascal","Python") self.lang_menu.bind('', lambda event, obj=self: \ obj.disable_action_buttons(), '+') self.lang_menu.place(anchor=W, x=325, rely=0.5) Label(self.setup_frame, text="Data File Name:", wraplength=90, bg=COLOR)\ .place(anchor=W, x=450, rely=0.5) self.lb_frame = Frame(self.setup_frame, bg=COLOR) self.dfn_entry = Entry(self.lb_frame, textvariable=conf.dfn, width=12,\ bg=COLOR2).pack(side=LEFT) #bmp=Bitmap(data=) self.dfn_button = Button(self.lb_frame, text="v", width=1, height=1, \ command=lambda obj=self: obj.set_listbox()) self.dfn_button.bind('', lambda event, obj=self: \ obj.textbox.delete(1.0, END), '+') self.dfn_listbox_exists = FALSE self.dfn_button.pack(side=LEFT) self.lb_frame.place(anchor=W, x=510, rely=0.5) Button(self.setup_frame, text="OK", command=self.prep_problem)\ .place(anchor=E, relx=1.0, rely=0.5) #self.setup_frame.place(x=0, y=0, height=h, relwidth=1.0) self.setup_frame.pack(side=TOP, fill=X, expand=NO) self.control_frame=Frame(root, bg=COLOR, borderwidth=3, relief=RIDGE) Label(self.control_frame, text="Timestamp:", width=11, bg=COLOR)\ .grid(row=0, column=2) self.ts=Label(self.control_frame, textvariable=self.timestamp, relief=\ SUNKEN, width=6, bg=COLOR2).grid(row=0, column=3) self.cb=Button(self.control_frame, text="Compile", width=11, state=DISABLED, command=self.compile) self.cb.grid(row=0, column=0) self.rb=Button(self.control_frame, text="Run", width=11, state=DISABLED, command=self.run) self.rb.grid(row=0, column=1) self.vb=Button(self.control_frame, text="View source", width=11, state=DISABLED, command=self.view_source) self.vb.grid(row=1, column=0) self.lb=Button(self.control_frame, text="List Team Files", width=11, command=self.list_team_dir) self.lb.grid(row=1, column=1) self.max_rt_label = Label(self.control_frame, text="Runtime Limit:",\ width=14, bg=COLOR).grid(row=1, column=2) self.max_rt_menu=OptionMenu(self.control_frame, conf.runlimit,\ "10 sec","30 sec", " 1 min"," 5 min").grid(row=1, column=3) #self.control_frame.place(x=0, y=h+2, height=1.6*h, relwidth=1.0) self.control_frame.pack(side=TOP, fill=BOTH) 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, fill=Y) self.textbox.pack(side=RIGHT, 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, fill=BOTH) #Create ~judge and ~judge/data directories. if not ("judge" in os.listdir("%s" % conf.home_dir)): os.makedirs("%s/judge" % conf.home_dir) os.system("chgrp rocktest %s/judge" % conf.home_dir) os.chmod("%s/judge" % conf.home_dir, 488) #488_ten == 750_eight if not ("data" in os.listdir("%s/judge" % conf.home_dir)): os.makedirs("%s/judge/data" % conf.home_dir) os.system("chgrp rocktest %s/judge/data" % conf.home_dir) os.chmod("%s/judge/data" % conf.home_dir, 1512) #1512_ten == 2750_eight def set_listbox(self): #If listbox is already open, close it and return. if self.dfn_listbox_exists: self.dfn_listbox.destroy() self.dfn_listbox_exists = FALSE return #Create listbox window. self.dfn_listbox=Listbox(root, width=16, selectmode=SINGLE) self.dfn_listbox_exists = TRUE #Delete any existing list elements. self.dfn_listbox.delete(0, self.dfn_listbox.size()-1) #next, insert the data file names with the current problem's # number. for filename in os.listdir("%s/judge/data" % conf.home_dir): if find(filename, conf.prob_no.get()) > 0: self.dfn_listbox.insert(END, filename) self.dfn_listbox.place(x=463, y=33, height=20*self.dfn_listbox.size()) self.dfn_listbox.tkraise() self.dfn_listbox.bind('', lambda event, obj=self: \ obj.get_data_file(), '+') def get_data_file(self): conf.dfn.set(self.dfn_listbox.get(self.dfn_listbox.curselection()[0])) self.dfn_listbox.destroy() 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) #self.lb.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) #self.lb.configure(state=DISABLED) def prep_problem(self): #"~/judge" directory must already exist. if not ("judge" in os.listdir("%s" % conf.home_dir)): no_judge_dir_box.create() return #Set parameters from control frame option buttons. conf.team_name = "team" + conf.team_no.get() conf.prog_fn = "program" + conf.prob_no.get() + \ conf.ext_map[conf.lang.get()] #Copy program file into ~/judge. #print "Copy command: " + "cp -f ~%s/%s ~/judge" % \ # (conf.team_name, conf.prog_fn) status, output = commands.getstatusoutput("ls -l ~%s/%s" % \ (conf.team_name, conf.prog_fn)) if status == 0: self.timestamp.set(output[50:56]) status, output = commands.getstatusoutput("cp -f ~%s/%s ~/judge" % \ (conf.team_name, conf.prog_fn)) #The above two lines are commented out and the following two lines #are inserted for testing. #status, output = commands.getstatusoutput("cp -f ~/python/%s ~/judge"\ # % conf.prog_fn) if status != 0: ccpf_info_box.create() return try: os.remove("%s/judge/%s" % (conf.home_dir, conf.prog_fn[:find(conf.prog_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) def control_frame_consistent(self): if conf.team_name[4:] != conf.team_no.get() or \ conf.prog_fn[7] != conf.prob_no.get() or \ not (conf.prog_fn in os.listdir("%s/judge" % conf.home_dir)): return FALSE return TRUE def compile(self): if not self.control_frame_consistent(): self.disable_action_buttons() press_OK_box.create() return #Does source program file exist? if not (conf.prog_fn in os.listdir("%s/judge" % conf.home_dir)): 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)) if output == "": output = "Compile successful.\n" elif conf.lang.get()=="C++": #print "Compiling." output = commands.getoutput("g++ -lm -o ~/judge/%s ~/judge/%s" %\ (conf.prog_fn[:find(conf.prog_fn,'.')], conf.prog_fn)) if output == "": output = "Compile successful.\n" elif conf.lang.get()=="FORTRAN": #print "Compiling." output = commands.getoutput("f77 -o ~/judge/%s ~/judge/%s" %\ (conf.prog_fn[:find(conf.prog_fn,'.')], conf.prog_fn)) if output == "": output = "Compile successful.\n" elif conf.lang.get()=="Java": 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)) if output == "": output = "Compile successful.\n" #output = "No Java compiler available." elif conf.lang.get() == "Pascal": status, output = commands.getstatusoutput( "fpc -Co -Cr -o~/judge/%s -Se10 -vew ~/judge/%s" % \ (conf.prog_fn[:find(conf.prog_fn,'.')], conf.prog_fn)) ##Using P2C to preprocess. #status, output = commands.getstatusoutput( # "p2c -a ~/judge/%s 2> /dev/null" % 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 ~/judge/%s ~/judge/%s" % \ # (conf.prog_fn[:find(conf.prog_fn,'.')], 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): if not self.control_frame_consistent(): self.disable_action_buttons() press_OK_box.create() return 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.home_dir)): no_source_file_box.create() return else: #Does machine language program file exist? if not (pfn[:find(pfn,'.')] in os.listdir("%s/judge" % conf.home_dir)): no_ml_file_box.create() return #Does data file exist? if not (dfn in os.listdir("%s/judge/data" % conf.home_dir)): 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): #if not self.control_frame_consistent(): #self.disable_action_buttons() #press_OK_box.create() #return dir = commands.getoutput("ls -l ~%s" % conf.team_name) self.textbox.delete(1.0, END) self.textbox.insert(END, dir) def view_source(self): if not self.control_frame_consistent(): self.disable_action_buttons() press_OK_box.create() return self.textbox.delete(1.0, END) source=commands.getoutput("cat ~/judge/%s" % conf.prog_fn) self.textbox.insert(END, source) conf=conf_class() gui=gui_class(root) root.mainloop()