def do_execute(backend, criteria, ind, execute_dir, executable_file_path, test_index, test_name, report_path): """ Funkcija koja obavlja zadatak radne niti za pokretanja testa backend - back-end koji se trenutno koristi criteria - kriterijum pregleda zadatka (bodovanje, način izvršavanja itd.) ind - indeks pokretanja testa (1..N) - za svaki novi test kreće od jedinice execute_dir - direktorijum u kojem se inicira izvršenje executable_file_path - relativna putanja do izvršnog fajla (uključujući i njegov naziv) - relativna u odnosu na execute_dir test_index - unikatni identifikator pokretanja testa test_name - naziv testa koji se izvršava report_path - putanja do fajla sa konzolnim izlazom testa (uključujući i njegov naziv) Vraća interni format (objekat klase SingleRunResult) o uspešnosti pokretanja """ backend.execute_test(test_name, execute_dir, executable_file_path, test_index, report_path) try: r = backend.parse_testing_artefacts(test_name, execute_dir, criteria.blocking_tests, test_index) return r except RuntimeError as err: util.fatal_error(err.message)
def show_diffs_from_student(backend, config): """ Pokreće vizuelni diff alat kako bi se prikazale razlike između izmenjenog zadatka (alternativne verzije) i zadatka onako kako ga je student uradio backend - back-end koji se trenutno koristi config - globalna konfiguracija alata za pregled """ print 'Uporedjivanje fajlova prepravljenog zadatka sa verzijama fajlova koje je ostavio student...' # Biće pretraženi alt i current direktorijumi i biće pokrenut vizuelni diff za fajlove koji se razlikuju: onlyfiles = [ f for f in os.listdir(config.CURRENT_ALT_ASSIGNMENT_PATH) if path.isfile(join(config.CURRENT_ALT_ASSIGNMENT_PATH, f)) ] found = False for f in onlyfiles: alt = join(config.CURRENT_ALT_ASSIGNMENT_PATH, f) student = join(config.CURRENT_ASSIGNMENT_PATH, f) # Diff se vrši samo ako isti fajl postoji i u config.CURRENT_ASSIGNMENT_PATH direktorijumu: if path.isfile(student) and not util.filename_matches( f, backend.get_ignore_files_pattern()): if not util.cmp_files_ignore_newlines(alt, student): found = True command = config.VISUAL_DIFF_CMD.format(student, alt) ret = call(command, shell=True) if ret != 0: util.fatal_error( '''Pokretanje vizuelnog diff alata nije uspelo! Komanda koja je pokrenuta:\n{0}'''.format(command)) if not found: print 'Trenutno nema razlika izmedju prepravljenog zadatka i studentske verzije!'
def destroy(cloud_name, name): try: driver = cloud.get_cloud_driver(cloud_name) key = driver.get_key_pair(name) driver.delete_key_pair(key) except Exception as e: util.fatal_error(str(e))
def __init__(self, data_config, save_dir, data_filenames=None): self.data_config = data_config self.save_dir = save_dir # self.vocab_sizes = {} self.joint_label_lookup_maps = {} self.reverse_maps = {} self.vocab_maps = {} self.vocab_lookups = None self.oovs = {} # make directory for vocabs self.vocabs_dir = "%s/assets.extra" % save_dir if not os.path.exists(self.vocabs_dir): try: os.mkdir(self.vocabs_dir) except OSError as e: util.fatal_error("Failed to create vocabs directory: %s; %s" % (self.vocabs_dir, e.strerror)) else: tf.logging.log( tf.logging.INFO, "Successfully created vocabs directory: %s" % self.vocabs_dir) else: tf.logging.log(tf.logging.INFO, "Using vocabs directory: %s" % self.vocabs_dir) self.vocab_names_sizes = self.make_vocab_files(self.data_config, self.save_dir, data_filenames)
def dispatch(fn_name): try: tf.logging.log( tf.logging.INFO, f"evaluation_fns_np.dispatch({fn_name}) => " f" {fn_dispatcher[fn_name]}") return fn_dispatcher[fn_name] except KeyError: util.fatal_error(f"evaluation_fns_np.dispatch: " f"Undefined evaluation function '{fn_name}'")
def get_accumulator(fn_name): try: tf.logging.log( tf.logging.INFO, f"evaluation_fns_np.get_accumulator({fn_name}) => " f"{accumulator_factory[fn_name]}") return accumulator_factory[fn_name]() except KeyError: util.fatal_error((f"get_accumulator: Undefined evaluation function ", f"'{fn_name}'"))
def open_assignment(backend, config, station): """ Otvara pojedinačan studentski zadatak na osnovu zadatog naziva računara na kojem je urađen zadatak Zadatak se kopira na putanju config.CURRENT_ASSIGNMENT_PATH, trenutno selektovan računar se menja na zadati. Nakon toga poziva se metoda backend.after_assignment_loaded() koja dozvoljava dodatne akcije nakon otvaranja zadatka. config - globalna konfiguracija alata za pregled station - oznaka računara na kojem je zadatak urađen """ print 'Otvaranje studentskog zadatka sa racunara {0}...'.format(station) logging.info('Otvaranje studentskog zadatka sa racunara: {0}'.format(station)) start_dir = join(config.ASSIGNMENTS_PATH, station) matches = backend.find_project_recursive(start_dir) if len(matches) == 0: print bcolors.FAIL \ + 'U direktorijumu "{0}" nije pronadjen fajl za identifikaciju projekta (pattern: "{1}")!'\ .format(start_dir, backend.get_project_pattern()) + bcolors.ENDC return False if len(matches) > 1: print bcolors.FAIL \ + 'U direktorijumu "{0}" pronadjeno je vise direktorijuma kandidata za projektni direktorijum: {1}!'\ .format(start_dir, matches) + bcolors.ENDC return False util.clear_directory(config.CURRENT_ASSIGNMENT_PATH) util.clear_directory(config.CURRENT_ALT_ASSIGNMENT_PATH) onlyfiles = [f for f in os.listdir(matches[0]) if path.isfile(join(matches[0], f))] for file in onlyfiles: src = join(matches[0], file) dst = join(config.CURRENT_ASSIGNMENT_PATH, os.path.basename(file)) copyfile(src, dst) alt = join(config.ALTERED_ASSIGNMENTS_PATH, station) if path.isdir(alt): print bcolors.BOLD + 'Postoji i izmenjeno resenje ovog zadatka, pa se ono kopira u: "{0}"'\ .format(config.CURRENT_ALT_ASSIGNMENT_PATH) + bcolors.ENDC onlyfiles = [f for f in os.listdir(alt) if path.isfile(join(alt, f))] for file in onlyfiles: src = join(alt, file) dst = join(config.CURRENT_ALT_ASSIGNMENT_PATH, os.path.basename(file)) copyfile(src, dst) write_current_station(config, station) proj = basename(util.identify_project_file(backend, config.CURRENT_ASSIGNMENT_PATH)) print('Identifikovani projektni fajl: {0}'.format(proj)) try: backend.after_assignment_loaded(config.CURRENT_ASSIGNMENT_PATH, proj) except RuntimeError as err: util.fatal_error(err.message)
def get_embedding_table(self, name, embedding_dim, include_oov, pretrained_fname=None, num_embeddings=None, cwr_ood=False): if False: pass else: with tf.variable_scope("%s_embeddings" % name): initializer = tf.random_normal_initializer() if pretrained_fname: pretrained_embeddings = util.load_pretrained_embeddings( pretrained_fname) pretrained_num_embeddings, pretrained_embedding_dim = pretrained_embeddings.shape if pretrained_embedding_dim != embedding_dim: util.fatal_error( "Pre-trained %s embedding dim does not match specified dim (%d vs %d)." % (name, pretrained_embedding_dim, embedding_dim)) if num_embeddings and num_embeddings != pretrained_num_embeddings: util.fatal_error( "Number of pre-trained %s embeddings does not match specified " "number of embeddings (%d vs %d)." % (name, pretrained_num_embeddings, num_embeddings)) num_embeddings = pretrained_num_embeddings if not cwr_ood: num_embeddings -= 1 pretrained_embeddings = pretrained_embeddings[:-1, :] initializer = tf.constant_initializer( pretrained_embeddings) embedding_table = tf.get_variable( name="embeddings", shape=[num_embeddings, embedding_dim], initializer=initializer) if include_oov: oov_embedding = tf.get_variable( name="oov_embedding", shape=[1, embedding_dim], initializer=tf.random_normal_initializer()) embedding_table = tf.concat( [embedding_table, oov_embedding], axis=0, name="embeddings_table") return embedding_table
def execute_build_command(backend, config, criteria, comp, stations, current_assignment_path, autobuild_path): """ Izvršenje komande koja obavlja kompajliranje zadatka backend - back-end koji se trenutno koristi config - globalna konfiguracija alata za pregled criteria - kriterijum pregleda zadatka (bodovanje, način izvršavanja itd.) comp - oznaka računara na kojem je urađen zadatak koji se pregleda stations - kolekcija računara i studenata koji su radili zadatak (ključ - oznaka računara, podatak - lista - broj indeksa i ime/prezime studenta) current_assignment_path - putanja na kojoj se nalazi studentski zadatak koji se kompajlira autobuild_path - putanja na kojoj se nalazi autobuild varijanta tekućeg zadatka """ logging.info( 'Pokrenuto je kompajliranje tekuceg projekta u direktorijumu: {0}'. format(current_assignment_path)) build_report_path = join(autobuild_path, backend.get_build_report_filename()) code = internal_build_project(backend, config, criteria, current_assignment_path, autobuild_path) if code == 0: print bcolors.OKGREEN + 'Kompajliranje projekta je uspesno.' + bcolors.ENDC elif code == 1: print bcolors.FAIL + '''Kompajliranje projekta je generisalo upozorenja! Mozete nastaviti sa izvrsenjem testova, ukoliko zelite da pregledate izvestaj o kompajliranju, on se nalazi u fajlu: "{0}"'''.format( backend.get_build_report_filename()) + bcolors.ENDC else: if vm_build_error(build_report_path): util.fatal_error('''Kompajliranje projekta je neuspesno. Razlog neuspeha je cinjenica da je sva virtuelna memorija potrosena. Najbolje je da restartujete sistem pa potom nastavite pregled.''') else: print bcolors.FAIL \ + 'Kompajliranje projekta je neuspesno. Bice prikazan fajl ("{0}") sa izvestajem kompajliranja.'\ .format(backend.get_build_report_filename()) + bcolors.ENDC raw_input('Pritisnite <ENTER> za nastavak...') util.show_text_edit(config, build_report_path) final_report.update_final_report( config, criteria, stations, comp, datetime.datetime.now().isoformat(), status=ASSIGNMENT_STATUS_FAILS_TO_COMPILE) sys.exit(0)
def read_criteria_file(self, config): if path.isfile(config.RATING_CRITERIA_FILENAME): logging.debug( 'Ucitavanje sadrzaja kriterijumskog fajla: "{0}"'.format( config.RATING_CRITERIA_FILENAME)) with open(config.RATING_CRITERIA_FILENAME) as data_file: try: data = json.load(data_file) except ValueError: util.fatal_error( 'Fajl sa kriterijumom pregledanja nije u dobrom formatu!' ) try: self.backend_selection = data['backend'] self.assignment_files = data['files'] self.score_distribution = data['tests'] self.blocking_tests = data['blockers'] self.total_points = data['total_points'] except KeyError as err: util.fatal_error( 'Podešavanje "{0}" nedostaje u kriterijumskom fajlu.'. format(err.message)) # runs opcija nije obavezna. Ako se ne zada, koriste se podrazumevane vrednosti: if 'runs' in data: self.runs_spec = data['runs'] else: self.runs_spec = {"total": 1, "pass_limit": 1} # Formiranje ukupnog težinskog faktora - koji je zbir pojedinačnih težinskih faktora svih testova self.total_weight = 0 for s in self.score_distribution: self.total_weight += s.values()[0] # Formiranje pojedinačnih procentualnih vrednosti testova - određuje se u odnosu na ta koliko procentualno # iznosi težina datog testa u odnosu na ukupan težinski faktor for i, s in enumerate(self.score_distribution): self.score_distribution[i] = { s.keys()[0]: { "factor": s.values()[0], "percent": float(s.values()[0]) / self.total_weight * 100.00 } } # Provera da li je lista blokirajućih testova validna: for b in self.blocking_tests: if self.score_distribution[b] is None: util.fatal_error( '''Test pod nazivom "{0}" definisan je kao blokirajuc a pritom nije definisano bodovanje za njega (u fajlu sa kriterijumom ocenjivanja: "{1}")''' .format(b, config.RATING_CRITERIA_FILENAME)) else: util.fatal_error( 'Kriterijumski fajl nije pronadjen pod nazivom: {0}'.format( config.RATING_CRITERIA_FILENAME))
def list_cloud_keys(cloud_name): try: driver = cloud.get_cloud_driver(cloud_name) kk = driver.list_key_pairs() except Exception as e: util.fatal_error(str(e)) headers = ['Name'] keys = ['name'] jsonList = [] for key in kk: dict = {} dict['name'] = key.name jsonList.append(dict) util.print_list(headers, keys, jsonList) return
def show_diffs_from_initial(backend, config): """ Pokreće vizuelni diff alat kako bi se prikazale razlike između trenutnog zadatka i postavke zadatka backend - back-end koji se trenutno koristi config - globalna konfiguracija alata za pregled """ initfiles = [ f for f in os.listdir(config.INITIAL_PROJECT_PATH) if path.isfile(join(config.INITIAL_PROJECT_PATH, f)) ] if len(initfiles) == 0: util.fatal_error( 'U folder "{0}" potrebno je kopirati fajlove koji cine postavku zadatka!' .format(config.INITIAL_PROJECT_PATH)) print 'Uporedjivanje fajlova zadatka sa pocetnim verzijama fajlova...' onlyfiles = [ f for f in os.listdir(config.CURRENT_ASSIGNMENT_PATH) if path.isfile(join(config.CURRENT_ASSIGNMENT_PATH, f)) ] found = False for f in onlyfiles: init = join(config.INITIAL_PROJECT_PATH, f) if not util.filename_matches(f, backend.get_ignore_files_pattern()): if not path.isfile(init): init = '/dev/null' student = join(config.CURRENT_ASSIGNMENT_PATH, f) if (init == '/dev/null' or (not util.cmp_files_ignore_newlines(init, student))): found = True command = config.VISUAL_DIFF_CMD.format(init, student) ret = call(command, shell=True) if ret != 0: util.fatal_error( '''Pokretanje vizuelnog diff alata nije uspelo! Komanda koja je pokrenuta:\n{0}'''.format(command)) if not found: print 'Trenutno nema razlika izmedju studentskog zadatka i pocetne verzije!'
def parse_testing_artefacts(self, test_name, dir_path, blocking_tests, unique_id): blocker = test_name in blocking_tests gtest_status_path = self.get_status_report_path( dir_path, test_name, unique_id) gtest_report_name = self.get_testing_report_filename( test_name, unique_id) # Očitavanje statusnog koda koji je dobijen prilikom izvršenja testa (nalazi se u posebnom tekstualnom fajlu): if not os.path.isfile(gtest_status_path): raise RuntimeError( '''Nije uspelo izvrsenje testova - fajl sa statusom izvrsenja ({0}) nije pronadjen. Ovo je interna greska, kontaktirati autora alata.'''.format(gtest_status_path)) with open(gtest_status_path, 'r') as f: status_str = f.read() try: status = int(status_str) except ValueError: raise RuntimeError( '''Sadrzaj fajla sa statusom izvrsenja nije u skladu sa ocekivanim. Fajl: {0} Ovo je interna greska, kontaktirati autora alata.'''.format(gtest_status_path)) # Sistemski program "timeout" koji se koristi za pokretanje testova vraća kod 124 ukoliko je prekinuo predugo # izvršenje: if status == 0: pass # Tek treba da se odredi da li je test prošao ili ne, za sada se samo zna da je izvršenje prošlo elif status == 124: return SingleRunResult(name=test_name, result='timed-out', duration=float(self.execution_timeout), blocker=blocker) # Ovde je obrađena malo komplikovanija situacija. # Ako je povratni kod 'timeout' komande 1 - onda ima dva podslučaja. # Prvi, češći podslučaj je da to indikuje da je pokrenuti test pao. # Drugi, ređi podslučaj je da to indikuje nasilni prekid izvršenja testa, usled segfault-a ili slično. U tom slučaju, nema analize rezultata testa. elif (status == 1 and (not self.is_execution_report_created( dir_path, test_name, unique_id))) or status > 1: return SingleRunResult(name=test_name, result='crashed', duration=0, blocker=blocker) # Učitavanje XML fajla sa rezultatom izvršenja, ako ima takvog fajla: filename = join(dir_path, gtest_report_name) error_message = '''Interna greska: format XML fajla sa rezultatima testiranja nije validan! Fajl cije parsiranje nije uspelo: {0}'''.format(filename) if not os.path.isfile(filename): raise RuntimeError( '''Nije uspelo izvrsenje testova - fajl sa izvestajem ({0}) nije pronadjen. Ovo verovatno ukazuje na timeout prilikom izvrsenja.'''.format(filename)) e = ElementTree.parse(filename).getroot() if e.tag != 'testsuites': raise RuntimeError(error_message) for suite in e: if not 'name' in suite.attrib: raise RuntimeError(error_message) suite_name = suite.attrib['name'] for case in suite: blocker = False if case.tag != 'testcase': raise RuntimeError(error_message) if not 'name' in case.attrib: raise RuntimeError(error_message) if not 'status' in case.attrib: raise RuntimeError(error_message) name = '{0}.{1}'.format(suite_name, case.attrib['name']) # Proverava da li je definisano bodovanje za test koji je izvrsen: if name != test_name: util.fatal_error( 'Interna greska! Fajl sa izvestajem ne sadrzi rezultate odgovarajuceg testa.\n' + 'Kontaktirati autora alata.') if case.attrib['status'] == 'run': if case.find('failure') is None: execution = 'passed' else: execution = 'failed'
data_root_logs = os.path.join(data_root, "logs") if not os.path.isdir(data_root_logs): os.mkdir(data_root_logs) pg_log = os.path.join(data_root_logs, pgver) if not os.path.isdir(pg_log): os.mkdir(pg_log) if util.get_platform() == "Windows": print("Giving current user permission to log dir") cur_user = getpass.getuser() batcmd = 'icacls "' + pg_log + '" /grant "' + cur_user + \ '":(OI)(CI)F' err = os.system(batcmd) if err: msg = "ERROR: Unable to set permissions on log dir " + \ " (err=" + str(err) + ")" util.fatal_error(msg) util.set_column("logdir", pgver, pg_log) if args.svcname > '': util.set_column("svcname", pgver, args.svcname) ## AUTOSTART ########################################### if ((args.autostart is None) or (autostart == args.autostart)): sys.exit(0) if util.get_platform() == "Windows": datadir = util.get_column('datadir', pgver) svcname = util.get_column('svcname', pgver, 'PostgreSQL ' + dotver + ' Server') cmd_file = tempfile.mktemp(".bat") fh = open(cmd_file, "w")
'--attention_configs', help='Comma-separated list of paths to attention configuration json.') arg_parser.add_argument( '--combine_test_files', action='store_true', help='Whether to combine list of test files into a single score.') arg_parser.set_defaults(debug=False) arg_parser.set_defaults(combine_test_files=False) args, leftovers = arg_parser.parse_known_args() util.init_logging(tf.logging.INFO) if not os.path.isdir(args.save_dir): util.fatal_error("save_dir not found: %s" % args.save_dir) # Load all the various configurations # todo: validate json data_config = train_utils.load_json_configs(args.data_config) model_config = train_utils.load_json_configs(args.model_configs) task_config = train_utils.load_json_configs(args.task_configs, args) layer_config = train_utils.load_json_configs(args.layer_configs) attention_config = train_utils.load_json_configs(args.attention_configs) # attention_config = {} # if args.attention_configs and args.attention_configs != '': # attention_config = # Combine layer, task and layer, attention maps # layer_task_config = {}
def unpack_assignments(config, stations, two_groups): """ Raspakuje arhivu sa svim studentskim radovima iz direktorijuma config.ARCHIVE_PATH config - globalna konfiguracija alata za pregled stations - kolekcija računara i studenata koji su radili zadatak (ključ - oznaka računara, podatak - lista - broj indeksa i ime/prezime studenta) two_groups - boolean koji indikuje da li je zadatak rađen u dve grupe (A i B) """ util.make_sure_path_exists(config.TEMP_PATH) # Ukoliko se u prihvatnom direktorijumu nalazi arhiva, ona će biti raspakovana u direktorijum sa studentskim # zadacima i potom premeštena u backup direktorijum: archives = glob.glob( join(config.ARCHIVE_PATH, config.ASSIGNMENTS_ARCHIVE_PATTERN)) found = 0 for a in archives: found = found + 1 print 'Pronadjena je nova arhiva sa zadacima koja ce biti obradjena' print 'Raspakivanje arhive "{0}" u direktorijum "{1}"...'.format( a, config.TEMP_PATH) command = config.EXTRACT_ASSIGNMENTS_CMD.format(a, config.TEMP_PATH) ret = call(command, shell=True) if ret != 0: util.fatal_error( 'Raspakivanje arhive sa zadacima je neuspesno!\nKomanda koja je pokrenuta:\n{0}' .format(command)) if found == 0: util.fatal_error('''Nije pronadjena arhiva sa zadacima! Molim proverite da li arhiva koju ste prilozili ima adekvatan naziv i adekvatnu ekstenziju! Ocekuje se naziv poput sledeceg: {0}'''.format( config.ASSIGNMENTS_ARCHIVE_PATTERN)) # Učitavanje liste studenata iz raspakovanog sadrzaja arhive: matches = glob.glob(join(config.TEMP_PATH, config.STUDENTS_LIST_PATTERN)) if len(matches) == 0: util.fatal_error( 'Nije pronadjena lista studenata (pattern za trazenje: "{0}")'. format(config.STUDENTS_LIST_PATTERN)) if len(matches) > 1: util.fatal_error( 'Pronadjen je vise od jednog fajla koji je kandidat za listu studenata. Kandidati: {0}' .format(matches)) # Ako zadatak ima samo jednu grupu (nema grupe A i B), onda se lista studenata samo kopira na destinaciju # (neće biti njene podele na dve podgrupe): if not two_groups: copyfile(matches[0], join(config.ASSIGNMENTS_PATH, basename(matches[0]))) logging.debug( 'Ucitavanje spiska studenata prilikom raspakivanja arhive...') ifile = open(matches[0], "rb") reader = csv.DictReader(ifile, dialect='excel', fieldnames=['station', 'id', 'name']) for row in reader: station = row['station'].strip() id = row['id'].strip() name = row['name'].strip() if id: logging.debug( 'Ucitano: Stanica: {0}, Broj indeksa: {1}, Ime: {2}'.format( station, id, name)) stations[station] = [id, name] ifile.close() logging.debug('Ucitavanje spiska studenata zavrseno') if two_groups: group1_list = open( join(config.GROUP1_DIR, config.ASSIGNMENTS_PATH, "spisak_stud_koji_trenutno_rade_proveru.txt"), "a+") group2_list = open( join(config.GROUP2_DIR, config.ASSIGNMENTS_PATH, "spisak_stud_koji_trenutno_rade_proveru.txt"), "a+") # Arhive koje su pronađene u direktorijumu sa studentskim zadacima biće raspakovane i potom obrisane: archives = sorted( glob.glob( join(config.TEMP_PATH, config.SINGLE_ASSIGNMENT_ARCHIVE_PATTERN))) for a in archives: logging.debug( 'Pronadjena je sledeca arhiva sa pojedinacnim zadatkom: {0}'. format(a)) # Manipulacija nazivom arhive, kako bi se došlo do oznake stanice na kojoj je student radio: name = os.path.basename(a)[:-len(config.SINGLE_ASSIGNMENT_ARCHIVE_EXT)] tokens = name.split('_') station = tokens[len(tokens) - 1] # Proces kopiranja zadataka vođen je spiskom studenata koji su radili proveru. # Ako stanica nije na tom spisku, znači da je u pitanju blanko direktorijum i on se preskače. if station in stations: if two_groups: station_num = int(station[1:]) if station_num % 2 == 0: station_directory = join(config.GROUP1_DIR, config.ASSIGNMENTS_PATH, station) if not station in stations: util.fatal_error( 'Racunar sa oznakom "{0}" nije pronadjen u spisku studenata koji rade proveru!' .format(station)) group1_list.write('{0}, {1}, {2}\n'.format( station, stations[station][0], stations[station][1])) else: station_directory = join(config.GROUP2_DIR, config.ASSIGNMENTS_PATH, station) if not station in stations: util.fatal_error( 'Racunar sa oznakom "{0}" nije pronadjen u spisku studenata koji rade proveru!' .format(station)) group2_list.write('{0}, {1}, {2}\n'.format( station, stations[station][0], stations[station][1])) else: station_directory = join(config.ASSIGNMENTS_PATH, station) logging.debug( 'Raspakivanje zadatka "{0}" u direktorijum "{1}"'.format( a, station_directory)) util.make_sure_path_exists(station_directory) command = config.EXTRACT_SINGLE_ASSIGNMENT_CMD.format( a, station_directory) ret = call(command, shell=True) if ret != 0: util.fatal_error( 'Raspakivanje pojedinacnog zadatka je neuspesno!\nKomanda koja je pokrenuta:\n{0}' .format(command)) os.remove(a) util.clear_directory(config.TEMP_PATH)
def update_final_report(config, criteria, stations, station, time, status = None, comment = None, results = None, score = None, correction = None): """ Ažurira finalni izveštaj sa pojedinačnim elementom ocene zadatka Mehanizam rada je takav da će menjati samo jedan <assignment> nod u XML fajlu i to onaj koji se tiče zadatka kojem se prijavljuju izmene u rezultatu. Ostatak sadržaja neće biti učitavan i menjan. config - globalna konfiguracija alata za pregled criteria - kriterijum pregleda zadatka (bodovanje, način izvršavanja itd.) stations - kolekcija računara i studenata koji su radili zadatak (ključ - oznaka računara, podatak - lista - broj indeksa i ime/prezime studenta) station - oznaka računara na kojem je zadatak urađen time - timestamp poslednje izmene na rezultatima status - status celog zadatka comment - komentar pregledača na zadatak results - lista tuple objekata TestResults - rezultat izvršenja testova score - procentualni učinak studenta na zadatku correction - korekcija koju je pregledač uveo """ print 'Azuriranje XML fajla sa izvestajem sa ispita: "{0}"'.format(config.FINAL_REPORT_FILENAME) try: criteria.total_points # Provera da li je definisana varijabla except NameError: criteria.total_points = 100 total_points_f = float(criteria.total_points) if not (results is None): total = 0.0 for r in results: if r.success: total += r.score # Ako fajl ne postoji, kreiraj korenski element: if not(path.isfile(config.FINAL_REPORT_FILENAME)): root = objectify.Element('assignments') else: with open(config.FINAL_REPORT_FILENAME) as f: xml = f.read() root = objectify.fromstring(xml) # Probaj pronaci <assignment> tag koji se odnosi na zadatu stanicu: assign = None for a in root.getchildren(): if a.get('station') == station: assign = a # Ako prethodno ne postoji takav <assignment>, kreiraj novi: if assign == None: assign = objectify.SubElement(root, 'assignment') # Podesi nove podatke: assign.set('station', station) assign['id'] = stations[station][0] assign['name'] = stations[station][1] # Podesi nove podatke: assign.time = time if not (results is None): assign['test-score'] = '{:.2f}'.format(total) if not (comment is None): assign['comment'] = comment if not (score is None): assign['direct-score'] = '{:.2f}'.format(score) assign['final-pct'] = '{:.2f}'.format(score) if not (correction is None): # Ako je zadata korekcija 0 - onda se korekcija ukida: if correction == 0: sub = assign.find('correction') if (sub is not None): assign.remove(sub) else: assign['correction'] = '{:+.2f}'.format(correction) final_number = 0 reason = u'nema uspešnih testova' if assign.find('test-score') is not None: final_number = float(assign['test-score']) reason = u'{:+.2f}% na uspešne testove'.format(final_number) if correction != 0: final_number = final_number + correction reason = reason + u' i {:+.2f}% korekcija'.format(correction) final = '{:.2f}'.format(final_number) points = int(round(final_number * (total_points_f / 100.0), 0)) assign['final-pct'] = final assign['final-points'] = points assign['reason'] = reason if not (results is None): # Ako je bilo direktno zadatog rezultata, nakon što su izvršeni automatski testovi, taj skor se briše: sub = assign.find('direct-score') if (sub is not None): assign.remove(sub) while True: sub = assign.find('tests') if (sub is None): break; assign.remove(sub) tests_root = objectify.SubElement(assign, 'tests') for r in results: test = objectify.SubElement(tests_root, 'test') test.attrib['name'] = r.name test['runs'] = r.runs test['passes'] = r.passes test['failures'] = r.failures test['test-fails'] = r.test_fails test['crashes'] = r.crashes test['time-outs'] = r.time_outs test['total-duration'] = '{:.2f}'.format(r.total_duration) test['max-duration'] = '{:.2f}'.format(r.max_duration) test['success'] = r.success test['score'] = '{:.2f}'.format(r.score) test['factor'] = r.factor executions = objectify.SubElement(test, 'executions') for e in r.executions: elem = objectify.SubElement(executions, 'passed') elem._setText(str(e).lower()) # Logika za odredjivanje broja poena, u odnosu na status rada i ostale parametre: if not (status is None): assign['status'] = status if status == ASSIGNMENT_STATUS_BLOCKED: final = '0' points = 0 reason = u'makar jedan od blokirajućih testova ne prolazi' elif status == ASSIGNMENT_STATUS_FAILS_TO_COMPILE: final = '0' points = 0 reason = u'projekat se ne kompajlira uspešno' elif status == ASSIGNMENT_STATUS_DIRECTLY_RATED: final = assign['direct-score'] final_number = float(assign['direct-score']) points = int(round(final_number * (total_points_f / 100.0), 0)) reason = u'direktno zadata ocena' elif status == ASSIGNMENT_STATUS_OK: final_number = float(assign['test-score']) reason = u'{0}% na uspešne testove'.format(final_number) sub = assign.find('correction') if (sub is not None): corr = float(assign['correction']) final_number = final_number + corr reason = reason + u' i {:+.2f}% korekcija'.format(corr) final = '{:.2f}'.format(final_number) points = int(round(final_number * (total_points_f / 100.0), 0)) elif status == ASSIGNMENT_STATUS_SKIPPED: final_number = 0 points = 0 final = '{:.2f}'.format(final_number) reason = u'rad je preskočen' else: util.fatal_error('''Interna greska: status "{0}" nema definisana pravila za bodovanje! Kontaktirati autora programa.'''.format(status)) assign['final-pct'] = final assign['final-points'] = points assign['reason'] = reason # Upiši izmenjen fajl: f = open(config.FINAL_REPORT_FILENAME, 'w') objectify.deannotate(root) # Skidanje objectify anotacija # Dodaje se XML zaglavlje u kojem se navodi UTF-8 kao upotrebljeno enkodiranje i referencira se XSLT dokument: f.write('<?xml version="1.0" encoding="UTF-8"?>\n<?xml-stylesheet type="text/xsl" href="{0}"?>\n' .format(config.FINAL_REPORT_XSLT_FILENAME)) f.write(etree.tostring(root, xml_declaration=False, encoding='utf-8', pretty_print=True)) f.close()
def import_from_file(cloud_name, name, pub_key_file): try: driver = cloud.get_cloud_driver(cloud_name) driver.import_key_pair_from_file(name, pub_key_file) except Exception as e: util.fatal_error(str(e))
def execute_run_tests_command(backend, config, criteria, stations, run_path, comp): """ Izvršenje komande koja obavlja pokretanje svih testova za zadatak backend - back-end koji se trenutno koristi config - globalna konfiguracija alata za pregled criteria - kriterijum pregleda zadatka (bodovanje, način izvršavanja itd.) stations - kolekcija računara i studenata koji su radili zadatak (ključ - oznaka računara, podatak - lista - broj indeksa i ime/prezime studenta) run_path - putanja na kojoj se nalazi studentski zadatak čiji se testovi izvršavaju comp - oznaka računara na kojem je urađen zadatak koji se pregleda """ if not path.isdir(config.AUTOTEST_PATH): util.fatal_error( '''Prilikom postavljanja zadatka nije postavljena autotest varijanta zadatka.\n' Ako zelite da koristite automatsko testiranje, kreirajte direktorijum "{0}" i postavite autotest varijantu u njega.''' .format(config.AUTOTEST_PATH)) if not path.isdir(run_path): util.fatal_error( 'Ne mogu se pokrenuti testovi jer projekat nije prethodno kompajliran.\n' + 'Upotrebite komandu build za kompajliranje projekta.') util.make_sure_path_exists(config.REPORTS_PATH) current_reports_path = join(config.REPORTS_PATH, comp) util.make_sure_path_exists(current_reports_path) util.clear_directory(current_reports_path) logging.info( 'Pokrenuti su automatski testovi tekuceg projekta u direktorijumu: {0}' .format(run_path)) proj = util.identify_project_file(backend, run_path) executable = backend.identify_project_executable(proj) all_results = [] tests = [] for s in criteria.score_distribution: tests.append(s.keys()[0]) # Zakazivanje izvršenja testova od strane (potencijalno) više niti za izvršenje testova: print('Sledeci testovi ce biti izvrseni: {0}'.format(', '.join(tests))) print('Svaki test se izvrsava {0} put(a)'.format( criteria.runs_spec['total'])) for t in tests: execution_results[t] = [None] * criteria.runs_spec['total'] for i in range(backend.get_parallel_testing_threads_count()): t = Thread(target=execution_worker_thread, args=(backend, criteria, i, run_path, executable)) t.daemon = True t.start() for t in tests: test_index = 0 for run in range(1, criteria.runs_spec['total'] + 1): execution_queue.put([ test_index, t, get_console_report_path(config, comp, t, test_index) ]) test_index += 1 execution_queue.join() # Grupisanje dobijenih rezultata - konsolidacija rezultata po svakom pojedinačnom testu (po nazivu testa): for t in tests: results = execution_results[t] # Određivanje najdužeg vremena izvršenja ovog testa: max_duration = results[0].duration executions = [] for r in results: if r.duration > max_duration: max_duration = r.duration executions.append(r.result == 'passed') passes = sum(1 for x in results if x.result == 'passed') entry = TestResults( name=t, runs=criteria.runs_spec['total'], passes=passes, failures=sum(1 for x in results if x.result != 'passed'), test_fails=sum(1 for x in results if x.result == 'failed'), crashes=sum(1 for x in results if x.result == 'crashed'), time_outs=sum(1 for x in results if x.result == 'timed-out'), total_duration=sum(x.duration for x in results), max_duration=max_duration, score=get_score(criteria, t)["percent"], factor=get_score(criteria, t)["factor"], success=(passes / float(criteria.runs_spec['total'])) >= criteria.runs_spec['pass_limit'], executions=executions) all_results.append(entry) # Ispis rezimea pokretanja testova na konzolu: total = len(criteria.score_distribution) passed = 0 score = 0 blockers = False for t in all_results: print '' header_line = 'TEST: {0}, ukupno izvrsenja: {1}'.format(t.name, t.runs) print '*' * len(header_line) print bcolors.BOLD + header_line + bcolors.ENDC print '*' * len(header_line) if t.runs < criteria.runs_spec['total']: print bcolors.FAIL \ + 'Detektovano je dovoljno negativnih ishoda pa nije obavljeno svih {0} zahtevanih pokretanja'\ .format(criteria.runs_spec['total']) + bcolors.ENDC if t.passes > 0: print bcolors.OKGREEN + 'PROSAO: {0} put(a)'.format( t.passes) + bcolors.ENDC if t.failures > 0: print bcolors.FAIL + 'PAO: {0} put(a), od toga:'.format( t.failures) + bcolors.ENDC if t.test_fails > 0: print bcolors.FAIL + ' Formirao los rezultat: {0} put(a)'.format( t.test_fails) + bcolors.ENDC if t.crashes > 0: print bcolors.FAIL + ' Nasilno prekinuo izvrsenje: {0} put(a)'.format( t.crashes) + bcolors.ENDC if t.time_outs > 0: print bcolors.FAIL + ' Prekoracio dozvoljeno vreme: {0} put(a)'.format( t.time_outs) + bcolors.ENDC print 'Ukupno vreme izvrsenja: {0}, najduze pokretanje: {1}'.format( t.total_duration, t.max_duration) if t.success: print bcolors.OKGREEN + 'Test se smatra uspesnim, tezina: {0} (od ukupno {1}), procentualno: {2:.2f}%'\ .format(t.factor, criteria.total_weight, t.score) + bcolors.ENDC passed += 1 score += t.score else: print bcolors.FAIL + 'Test se smatra neuspesnim' + bcolors.ENDC if t in criteria.blocking_tests: blockers = True print bcolors.FAIL + 'Ovo je blokirajuci test!' + bcolors.ENDC print '' if passed == total: print bcolors.OKGREEN \ + '''Uspesno su izvrseni svi testovi (ukupno je: {0} testova).\nUkupno ostvareno procenata: {1:.2f}%'''.format(total, score) + bcolors.ENDC else: failed = total - passed print bcolors.FAIL + '''Palo je {0} testova, od ukupno {1}! Procenat testova koji prolaze: {2:.2f}%, procentualni ucinak: {3:.2f}%'''.format( failed, total, float(passed) / total * 100.0, score) + bcolors.ENDC status = ASSIGNMENT_STATUS_OK if blockers: print bcolors.FAIL + bcolors.BOLD \ + 'Pao je makar jedan blokirajuci test! U izvestaju je naznaceno da u ovom radu postoje takvi testovi.' \ + bcolors.ENDC status = ASSIGNMENT_STATUS_BLOCKED final_report.update_final_report(config, criteria, stations, comp, datetime.datetime.now().isoformat(), status=status, results=all_results)
def internal_build_project(backend, config, criteria, current_assignment_path, autobuild_path): """ Interna pomoćna metoda koja vrši kompajliranje projekta (studentskog zadatka) backend - back-end koji se trenutno koristi config - globalna konfiguracija alata za pregled criteria - kriterijum pregleda zadatka (bodovanje, način izvršavanja itd.) current_assignment_path - putanja do zadatka koji se kompajlira autobuild_path - putanja na kojoj se nalazi autobuild varijanta tekućeg zadatka Vraća indikaciju da li je kompajliranje uspešno obavljeno 0 - kompajliranje je uspešno 1 - produkovan je izvršni fajl ali je kompajliranje vratilo upozorenja 2 - kompajliranje je neuspešno """ logging.info( 'Pokrenuto je kompajliranje projekta u direktorijumu: {0}'.format( current_assignment_path)) # Brisanje trenutnog sadrzaja autobuild direktorijuma: print('Brisanje sadrzaja direktorijuma "{0}"'.format(autobuild_path)) util.make_sure_path_exists(autobuild_path) util.clear_directory(autobuild_path) # Kopiranje svih fajlova iz osnovnog direktorijuma u autobuild poddirektorijum: print('Kopiranje izvornih fajlova iz "{0}" u "{1}"'.format( current_assignment_path, autobuild_path)) onlyfiles = [ f for f in os.listdir(current_assignment_path) if path.isfile(join(current_assignment_path, f)) ] autotestfiles = [ f for f in os.listdir(config.AUTOTEST_PATH) if path.isfile(join(config.AUTOTEST_PATH, f)) ] for f in onlyfiles: if (f in criteria.assignment_files) or ( f not in autotestfiles and filename_matches_assignment_pattern(backend, f)): copyfile(join(current_assignment_path, f), join(autobuild_path, f)) # Obrada događaja koji se inicira pre nego što se obavi kompajliranje zadatka: try: backend.before_build(autobuild_path) except RuntimeError as err: util.fatal_error(err.message) # Kopiranje dodatnih fajlova iz autotest direktorijuma u autobuild poddirektorijum: print('Kopiranje autotest fajlova iz "{0}" u "{1}"'.format( config.AUTOTEST_PATH, autobuild_path)) if len(autotestfiles) == 0: util.fatal_error( 'Projekat se ne moze kompajlirati jer autotest varijanta zadatka nije postavljena u direktorijum: "{0}"!' .format(config.AUTOTEST_PATH)) for f in autotestfiles: # Proverava se da li je fajl naveden u listi fajlova u kojima studenti unose resenje zadatka. # Ako je tako, onda taj fajl ne bi smeo da bude postavljen u autotest folder. if f in criteria.assignment_files: util.fatal_error( '''Fajl "{0}" je postavljen u "{1}" direktorijum a ocekuje se da studenti unose svoje resenje u taj fajl. Fajlovi iz "{1}" direktorijuma kopiraju se preko studentskog resenja, tako da bi kopiranjem ovog fajla unistili kljucni deo resenja. Molim da procitate deo uputstva za koriscenje alata za pregled koji se odnosi na postavljanje fajlova u ovaj direktorijum.''' .format(f, config.AUTOTEST_PATH)) copyfile(join(config.AUTOTEST_PATH, f), join(autobuild_path, f)) # Potom, sledi kompajliranje projekta: ret = backend.build_project( util.identify_project_file(backend, autobuild_path)) # Poslednja linija izvešaja o kompajliranju treba da sadrži informaciju o potencijalnim upozorenjima i greškama tokom kompajliranja: f = open(join(autobuild_path, backend.get_build_report_filename()), 'r') lines = f.readlines() last_line = lines[len(lines) - 1] regex = re.compile( '(?P<errors>\d+)\serror\(s\),\s(?P<warnings>\d+)\swarning\(s\)', re.IGNORECASE) m = regex.match(last_line) if m: errors = int(m.group('errors')) warnings = int(m.group('warnings')) if (errors == 0 and warnings == 0): return 0 if (errors == 0): return 1 return 2 else: util.fatal_error( '''Interna greska: izvestaj o kompajliranju ne sadrzi poslednju liniju sa brojem gresaka i upozorenja. Nije moguce utvrditi ishod kompajliranja. Potrebno je kontaktirati autora alata.''' )
def dispatch(fn_name): try: return fn_dispatcher[fn_name] except KeyError: util.fatal_error('Undefined evaluation function `%s' % fn_name)
def get_accumulator(fn_name): try: return accumulator_factory[fn_name]() except KeyError: util.fatal_error('Undefined evaluation function `%s' % fn_name)
def execute_export_command(config, criteria, stations): """ Izvršavanje komande koja vrši izvoz rezultata u format koji se može lako uvesti u Evidenciju config - globalna konfiguracija alata za pregled criteria - kriterijum pregleda zadatka (bodovanje, način izvršavanja itd.) stations - kolekcija računara i studenata koji su radili zadatak (ključ - oznaka računara, podatak - lista - broj indeksa i ime/prezime studenta) """ error_message = 'Interna greška: format XML fajla nije validan!\nFajl čije parsiranje nije uspelo: {0}'\ .format(config.FINAL_REPORT_FILENAME) if not (path.isfile(config.FINAL_REPORT_FILENAME)): util.fatal_error( 'Ne može se izvršiti izvoz podataka pošto fajl sa izveštajem još uvek ne postoji!' ) else: with open(config.FINAL_REPORT_FILENAME) as f: xml = f.read() root = objectify.fromstring(xml) # Provera dve uslova: # 1) Da li su svi radovi ocenjeni? # 2) Da li postoje preskočeni radovi u izveštaju? # Ako je bilo koji od ovih uslova tačan, izvoz rezultata nije moguć: done_stations = {} for child in root.getchildren(): if child.tag != 'assignment': util.fatal_error(error_message) if child['status'] == ASSIGNMENT_STATUS_SKIPPED: util.fatal_error( 'Ne može se izvršiti izvoz rezultata jer postoje preskočeni radovi!\n' + 'Molim da ocenite ove radove pa pokušate izvoz ponovo.') done_stations[child.attrib['station']] = 1 if set(stations) != set(done_stations): util.fatal_error( 'Ne može se izvršiti izvoz rezultata jer nisu svi radovi ocenjeni!\n' + 'Molim da ocenite ove radove pa pokušate izvoz ponovo.') try: criteria.total_points # Provera da li je definisana varijabla except NameError: criteria.total_points = 100 total_points_f = float(criteria.total_points) with open(config.EXPORTED_REPORT_FILENAME, 'w') as wfile: # Upis zaglavlja u CSV fajl: wfile.write('indeks,ime,prezime,poeni,ukupno_poena,ip,datum\n') for child in root.getchildren(): if child.tag != 'assignment': util.fatal_error(error_message) indeks = child['id'] naziv = child['name'].text razmak = naziv.find(' ') # Odredjivanje imena i prezimena: if razmak == -1: ime = naziv prezime = '' else: ime = naziv[:razmak] prezime = naziv[razmak + 1:] final_score = float(child['final-pct']) poeni = int(round(final_score * (total_points_f / 100.0), 0)) wfile.write('"{0}","{1}","{2}",{3},{4},,\n'.format( indeks, ime, prezime, poeni, criteria.total_points)) command = config.COMPRESS_REPORT_COMMAND ret = call(command, shell=True) if ret != 0: util.fatal_error( '''Pokretanje alata za komprimovanje CSV izveštaja u ZIP arhivu nije uspelo! Komanda koja je pokrenuta:\n{0}'''.format(command)) print 'Završen je izvoz podataka. Arhiva {0} sadrži rezultate pregleda.'.format( config.EXPORTED_ARCHIVE_FILENAME)