#! /usr/bin/env python # -*- coding: utf-8 -*- # # Copyright 2014 OpenStack Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging import os import yaml from arbiter import const from arbiter import meeting """Utility functions for check and gate jobs.""" def publish(meeting, ical): """Publish meeting information and ical file to wiki.""" pass def convert_yaml_to_ical(yaml_dir, ical_dir, meeting_list_file=None): """Convert meeting YAML files to the iCal format and place in ical_dir. If meeting_list is specified, only those meetings in yaml_dir with filenames contained in meeting_list are converted; otherwise, all meeting in yaml_dir are converted. """ meetings = meeting.load_meetings(yaml_dir) # convert meetings to a list of ical for m in meetings: m.write_ical(ical_dir) # TODO(jotan): verify converted ical is valid logging.info('Wrote %d meetings to iCal' % (len(meetings))) def check_uniqueness(): """Check for uniqueness in meeting room and time combination. During gate job, we do not care about the meeting name. """ # reads the current changes and verifies change_list = _read_yaml_files(const.DEFAULT_YAML_DIR) change_dict = _counting_dict_with(_make_schedule_key, change_list) # fails if duplicates exist if len(change_dict) == sum(change_dict.values()): return 0 else: change_dict = _make_schedule_dict(_make_schedule_key, change_list, False) for key in change_dict: if len(change_dict[key]) > 1: meeting_quote = ['\'' + m + '\'' for m in change_dict[key]] meeting_str = ', '.join(meeting_quote) logging.error('Meetings %s are in conflict.' % (meeting_str)) return 1 def check_conflicts(): """Return whether the meeting would create scheduling conflicts. At this point, we are comparing the changes against the origin, while the meeting do matter. If a meeting from the changes and a different meeting from the origin shares the same time, then we have a conflict. """ # reads the current changes and verifies change_list = _read_yaml_files(const.DEFAULT_YAML_DIR) change_dict = _make_schedule_dict(_make_schedule_key, change_list, True) # FIXME(lbragstad): Removed the clonerepo script since Jenkins takes care # of that. The path resolution needs to be fix here too. origin_dict = _make_schedule_dict(_make_schedule_key, _read_yaml_files(const.DEFAULT_YAML_DIR), True) # make a set with all the meeting time meeting_time_set = set(list(change_dict.keys()) + list(origin_dict.keys())) # compares the two, keep track of a conflict flag conflict = False # doing this way so we can log all the conflicts for key in meeting_time_set: # both the changes and the original have this meeting time if key in change_dict and key in origin_dict: # and they are actually different meetings if change_dict[key] != origin_dict[key]: logging.error('Meetings \'%s\' and \'%s\' are in conflict.' % (change_dict[key], origin_dict[key])) conflict = True if conflict: return 1 return 0 def _read_yaml_files(directory): """Reads all the yaml in the given directory and returns a list of schedules times. :param directory: location of the yaml files :returns: list of schedules """ yaml_files = [] for file in os.listdir('.'): if os.path.isfile(file) and file.endswith(const.YAML_FILE_EXT): yaml_files.append(file) meetings = [] for file in yaml_files: meetings.append(meeting.Meeting(yaml.load(open(file, 'r')), file)) logging.info('Loaded %d meetings form YAML' % len(meetings)) schedules = [] for m in meetings: for schedule in m.get_schedule_tuple(): schedules.append(schedule) return schedules def _counting_dict_with(key_maker, list): """Make a counting dictionary. The key is obtained by a function applied to the element; the value counts the occurrence of the item in the list. :param key_maker: converts list items to strings :returns: counting dictionary """ item_dict = {} for item in list: # just join the elements in the tuple together as key key = key_maker(item) if key in item_dict: item_dict[key] += 1 else: item_dict[key] = 1 return item_dict def _make_schedule_dict(key_maker, list, replace_flag): """Make a schedule dictionary. The key is the time of the meeting. If replace_flag is true, then the value is the meeting name; otherwise, if replace_flag is false, the value is a list of meeting names. :param key_maker: converts list items to strings :param list: the list of schedules :param replace_flag: determines the value of the dictionary :returns: schedule dictionary """ item_dict = {} for item in list: key = key_maker(item) if replace_flag: item_dict[key] = item[0] else: if key in item_dict: item_dict[key] += [item[0]] else: item_dict[key] = [item[0]] return item_dict def _make_schedule_key(schedule): """A key making function for a schedule item. The first item in the schedule is meeting name, followed by a tuple of time, day, and room. :param schedule: a schedule tuple :returns: string representation of the schedule tuple """ schedule_time = schedule[1] schedules_str = [str(schedule_time[0]), schedule_time[1], schedule_time[2]] key = ''.join(schedules_str) return key