1# Copyright 2023 The Pigweed Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may not 4# use this file except in compliance with the License. You may obtain a copy of 5# the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations under 13# the License. 14"""Docs widget that provides up-to-date info about the next Pigweed Live.""" 15 16 17import datetime 18import sys 19 20from docutils import nodes 21from docutils.parsers.rst import Directive 22from sphinx.application import Sphinx 23 24try: 25 import pytz # type: ignore 26 27 PYTZ_AVAILABLE = True 28except ImportError: 29 PYTZ_AVAILABLE = False 30 31 32class PigweedLiveDirective(Directive): 33 """Generates the up-to-date Pigweed Live info.""" 34 35 datetime_format = '%Y-%m-%d %H:%M:%S' 36 # TODO: b/303859828 - Update this data sometime between 2025-09-22 37 # and 2025-10-20. 38 meetings = [ 39 '2024-07-01 13:00:00', 40 '2024-07-29 13:00:00', 41 '2024-08-26 13:00:00', 42 '2024-09-23 13:00:00', 43 '2024-10-21 13:00:00', 44 '2024-12-16 13:00:00', 45 '2025-01-13 13:00:00', 46 '2025-02-10 13:00:00', 47 '2025-03-10 13:00:00', 48 '2025-04-07 13:00:00', 49 '2025-05-05 13:00:00', 50 '2025-06-02 13:00:00', 51 '2025-06-30 13:00:00', 52 '2025-07-28 13:00:00', 53 '2025-08-25 13:00:00', 54 '2025-09-22 13:00:00', 55 '2025-10-20 13:00:00', 56 '2025-11-17 13:00:00', 57 '2025-12-15 13:00:00', 58 ] 59 timezone = pytz.timezone('US/Pacific') 60 61 def run(self) -> list[nodes.Node]: 62 return [self._make_paragraph()] 63 64 def _make_paragraph(self) -> nodes.Node: 65 next_meeting = self._find_next_meeting() 66 paragraph = nodes.paragraph() 67 paragraph += nodes.Text('Our next Pigweed Live is ') 68 meeting_text = nodes.strong() 69 meeting_text += nodes.Text(next_meeting) 70 paragraph += meeting_text 71 paragraph += nodes.Text( 72 ( 73 ". Please join us to discuss what's new in Pigweed and " 74 "anything else Pigweed-related that's on your mind. " 75 ) 76 ) 77 refuri = 'https://groups.google.com/g/pigweed' 78 link = nodes.reference(refuri=refuri) 79 link += nodes.Text('Join our mailing list') 80 paragraph += link 81 paragraph += nodes.Text(" to receive an invite to the next meeting.") 82 return paragraph 83 84 def _find_next_meeting(self) -> str: 85 current_datetime = self.timezone.localize(datetime.datetime.now()) 86 next_meeting = None 87 for meeting in self.meetings: 88 unlocalized_datetime = datetime.datetime.strptime( 89 meeting, self.datetime_format 90 ) 91 meeting_datetime = self.timezone.localize(unlocalized_datetime) 92 if current_datetime > meeting_datetime: 93 continue 94 next_meeting = meeting_datetime 95 break 96 if next_meeting is None: 97 sys.exit( 98 'ERROR: Pigweed Live meeting data needs to be updated. ' 99 'Update the `meetings` list in `PigweedLiveDirective`. ' 100 'See b/303859828.' 101 ) 102 else: 103 date = next_meeting.strftime('%a %b %d, %Y') 104 hour = next_meeting.strftime('%I%p').lstrip('0') 105 timezone = 'PDT' if next_meeting.dst() else 'PST' 106 return f'{date} {hour} ({timezone})' 107 108 109def setup(app: Sphinx) -> dict[str, bool]: 110 """Initialize the directive.""" 111 if PYTZ_AVAILABLE: 112 app.add_directive('pigweed-live', PigweedLiveDirective) 113 return { 114 'parallel_read_safe': True, 115 'parallel_write_safe': True, 116 } 117