
The function responsible for determining the file name for the .ics files was not handling paths properly, resulting in a single .ics file being generated. This fixes the issue and also tweaks the INFO output a bit. Change-Id: Ib620cf5d683f74b3d5066e6e6ce75e1b7e36ed1d
228 lines
7.1 KiB
Python
228 lines
7.1 KiB
Python
#! /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
|
|
|
|
import const
|
|
from meeting import Meeting
|
|
|
|
|
|
"""Utility functions for check and gate jobs."""
|
|
|
|
|
|
def publish(meeting, ical):
|
|
"""Publish meeting information and ical file to wiki."""
|
|
|
|
pass
|
|
|
|
|
|
def load_meetings(yaml_dir, meeting_list=None):
|
|
"""Return a list of Meetings initialized from files in yaml_dir."""
|
|
|
|
meetings_yaml = []
|
|
for file_name in os.listdir(yaml_dir):
|
|
yaml_file = os.path.join(yaml_dir, file_name)
|
|
if not os.path.isfile(yaml_file):
|
|
continue
|
|
if meeting_list and yaml_file not in meeting_list:
|
|
continue
|
|
meetings_yaml.append(yaml_file)
|
|
|
|
meetings = [Meeting(yaml.load(open(f, 'r')), f)
|
|
for f in meetings_yaml]
|
|
|
|
logging.info('Loaded %d meetings from YAML' % (len(meetings)))
|
|
|
|
return meetings
|
|
|
|
|
|
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.
|
|
|
|
"""
|
|
|
|
meeting_list = None
|
|
if meeting_list_file:
|
|
meeting_list = open(meeting_list_file).read().splitlines()
|
|
|
|
meetings = load_meetings(yaml_dir,
|
|
meeting_list)
|
|
|
|
# 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(yaml.load(open(file, 'r')), file))
|
|
logging.info('Loaded %d meetings form YAML' % len(meetings))
|
|
|
|
schedules = []
|
|
for meeting in meetings:
|
|
for schedule in meeting.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
|