예제 #1
0
 def get_events(self):
     """Generator that yields all events in the calendar.
     """
     ics_filenames = glob(os.path.join(self.path, 'Events', '*.ics'))
     for ics_filename in ics_filenames:
         with open(ics_filename, 'rt') as ics_file:
             for component in vobject.readComponents(ics_file):
                 for event in component.vevent_list:
                     #event.prettyPrint()
                     event.dtstart.value = tz.normalize_to_utc(event.dtstart.value)
                     event.dtend.value = tz.normalize_to_utc(event.dtend.value)
                     #event.prettyPrint()
                     yield event
     return
예제 #2
0
def main(args=sys.argv[1:]):
    option_parser = optparse.OptionParser(
        usage='usage: ical2org [options] [calendar titles]',
        conflict_handler='resolve',
        description='Convert iCal calendar entries to org-mode data for use with emacs',
        )
    option_parser.add_option('-c', '--config',
                             action='store',
                             dest='config_filename',
                             help='Configuration file name. Defaults to ~/.ical2org',
                             default=os.path.expanduser('~/.ical2org'),
                             )
    option_parser.add_option('--begin', '-b', '--days-ago',
                             action='store',
                             dest='days_ago',
                             help='Number of days back in time to search. Defaults to 14.',
                             default=14,
                             type=int,
                             )
    option_parser.add_option('--end', '-e', '--days-ahead',
                             action='store',
                             dest='days_ahead',
                             help='Number of days forward in time to search. Defaults to 30.',
                             default=30,
                             type=int,
                             )
    option_parser.add_option('-v', '--verbose',
                             action='count',
                             dest='verbose_level',
                             default=1,
                             help='Increase verbose level',
                             )
    option_parser.add_option('-q', '--quiet',
                             action='store_const',
                             const=0,
                             dest='verbose_level',
                             help='Turn off verbose output',
                             )
    option_parser.add_option('--output-file', '-o',
                             action='store',
                             dest='output_file_name',
                             help='Write the output to the named file instead of stdout',
                             default=None,
                             )
    option_parser.add_option('--all',
                             action='store_false',
                             dest='active_only',
                             default=True,
                             help='Include all calendars, not just active.',
                             )
    option_parser.add_option('--input-directory',
                             action='store',
                             dest='input_directory',
                             default=os.path.expanduser('~/Library/Calendars'),
                             help='Directory containing calendars. Defaults to ~/Library/Calendars.',
                             )
    option_parser.add_option('--format', '-f',
                             action='store',
                             dest='format',
                             type='choice',
                             choices=FORMATTER_FACTORIES.keys(),
                             default='org',
                             help='Output format. One of %s. Defaults to "diary".' % FORMATTER_FACTORIES.keys(),
                             )
    option_parser.add_option('--opt', '--formatter-option',
                             action='callback',
                             type='string',
                             callback=remember_formatter_option,
                             help='Formatter-specific option name=value',
                             )
    option_parser.add_option('--help',
                             action='callback',
                             callback=show_verbose_help,
                             help='Verbose help',
                             )
                             
    options, calendar_titles = option_parser.parse_args(args)

    log_level = VERBOSE_LEVELS.get(options.verbose_level, logging.DEBUG)
    logging.basicConfig(level=log_level, format='%(message)s')

    config = ConfigParser()
    config.read([options.config_filename])

    # Compute the date range for items to be included in our output.
    start_date = tz.normalize_to_utc(datetime.datetime.combine(
        datetime.date.today() - datetime.timedelta(options.days_ago),
        datetime.time.min,
        ))
    end_date = tz.normalize_to_utc(datetime.datetime.combine(
        datetime.date.today() + datetime.timedelta(options.days_ahead + 1),
        datetime.time.min,
        ))
    logging.info('Starting %d days ago at %s', options.days_ago, start_date.astimezone(tz.local))
    logging.info('Ending %d days from now at %s', options.days_ahead, end_date.astimezone(tz.local))

    if options.output_file_name:
        logging.info('Writing to %s', options.output_file_name)

    # Load the calendars
    if calendar_titles:
        calendar_generator = calendars.get_by_titles(path=options.input_directory,
                                                     titles=calendar_titles)
    else:
        calendar_generator = calendars.discover(path=options.input_directory,
                                                active_only=options.active_only)

    # Process the calendar data
    output = sys.stdout
    if options.output_file_name:
        output = codecs.open(options.output_file_name, 'wt', 'UTF-8')
    try:
        formatter = FORMATTER_FACTORIES[options.format](output, config, options)
        for calendar in calendar_generator:
            logging.info('Processing: %s', calendar.title)
            formatter.start_calendar(calendar)
            for event in filter.unique(filter.by_date_range(calendar.get_events(),
                                                            start_date,
                                                            end_date,
                                                            )):
                logging.info('  %s', event.summary.value)
                formatter.add_event(event)
            formatter.end_calendar(calendar)
    finally:
        formatter.close()
        if output != sys.stdout:
            output.close()
    return
예제 #3
0
def by_date_range(events, start, end):
    """Iterate over the incoming events and yield those that fall within the date range.
    """
    log.debug('filtering between %s and %s', start, end)
    for event in events:

        # Fix time zones in date objects
        event_start = event.dtstart.value
        event_end = event.dtend.value
        if not isinstance(event_start, datetime.datetime):
            event_start = datetime.datetime.combine(event.dtstart.value,
                                                    datetime.time.min,
                                                    )
            if event_start == event_end:
                event_end = datetime.datetime.combine(event.dtend.value,
                                                      datetime.time.max,
                                                      )
            else:
                event_end = datetime.datetime.combine(event.dtend.value,
                                                      datetime.time.min,
                                                      )
                

        event_start = tz.normalize_to_utc(event_start)
        event_end = tz.normalize_to_utc(event_end)

        # Replace the dates in case we updated the timezone
        event.dtstart.value = event_start
        event.dtend.value = event_end
        
#         event.prettyPrint()
#         sys.stdout.flush()
        
        event_rrule = getattr(event, 'rrule', None)
        log.debug('checking %s - %s == %s',
                  event.dtstart.value,
                  event.dtend.value,
                  event.summary.value,
                  )
        if event_rrule is not None:
            duration = event.dtend.value - event.dtstart.value
            rruleset = event.getrruleset(False)

            # Clean up timezone values in rrules.
            # Based on ShootQ calendarparser module.
            for rrule in rruleset._rrule:
                # normalize start and stop dates for each recurrance
                if rrule._dtstart:
                    rrule._dtstart = tz.normalize_to_utc(rrule._dtstart)
                if hasattr(rrule, '_dtend') and rrule._dtend:
                    rrule._dtend = tz.normalize_to_utc(rrule._dtend)
                if rrule._until:
                    rrule._until = tz.normalize_to_utc(rrule._until)
            if rruleset._exdate:
                # normalize any exclusion dates
                exdates = []
                for exdate in rruleset._exdate:
                    exdate = tz.normalize_to_utc(exdate)
                rruleset._exdate = exdates
            if hasattr(rruleset, '_tzinfo') and rruleset._tzinfo is None:
                # if the ruleset doesn't have a time zone, give it
                # the local zone
                rruleset._tzinfo = tz.local

            # Explode the event into repeats
            for recurrance in rruleset.between(start, end, inc=True):
                log.debug('  recurrance %s', recurrance)
                dupe = event.__class__.duplicate(event)
                dupe.dtstart.value = tz.normalize_to_utc(recurrance)
                dupe.dtend.value = tz.normalize_to_utc(recurrance + duration)
                yield dupe
                
        elif event_start >= start and event_end <= end:
            yield event
예제 #4
0
def main(args=sys.argv[1:]):
    option_parser = optparse.OptionParser(
        usage='usage: ical2org [options] [calendar titles]',
        conflict_handler='resolve',
        description=
        'Convert iCal calendar entries to org-mode data for use with emacs',
    )
    option_parser.add_option(
        '-c',
        '--config',
        action='store',
        dest='config_filename',
        help='Configuration file name. Defaults to ~/.ical2org',
        default=os.path.expanduser('~/.ical2org'),
    )
    option_parser.add_option(
        '--begin',
        '-b',
        '--days-ago',
        action='store',
        dest='days_ago',
        help='Number of days back in time to search. Defaults to 14.',
        default=14,
        type=int,
    )
    option_parser.add_option(
        '--end',
        '-e',
        '--days-ahead',
        action='store',
        dest='days_ahead',
        help='Number of days forward in time to search. Defaults to 30.',
        default=30,
        type=int,
    )
    option_parser.add_option(
        '-v',
        '--verbose',
        action='count',
        dest='verbose_level',
        default=1,
        help='Increase verbose level',
    )
    option_parser.add_option(
        '-q',
        '--quiet',
        action='store_const',
        const=0,
        dest='verbose_level',
        help='Turn off verbose output',
    )
    option_parser.add_option(
        '--output-file',
        '-o',
        action='store',
        dest='output_file_name',
        help='Write the output to the named file instead of stdout',
        default=None,
    )
    option_parser.add_option(
        '--all',
        action='store_false',
        dest='active_only',
        default=True,
        help='Include all calendars, not just active.',
    )
    option_parser.add_option(
        '--input-directory',
        action='store',
        dest='input_directory',
        default=os.path.expanduser('~/Library/Calendars'),
        help='Directory containing calendars. Defaults to ~/Library/Calendars.',
    )
    option_parser.add_option(
        '--format',
        '-f',
        action='store',
        dest='format',
        type='choice',
        choices=FORMATTER_FACTORIES.keys(),
        default='org',
        help='Output format. One of %s. Defaults to "diary".' %
        FORMATTER_FACTORIES.keys(),
    )
    option_parser.add_option(
        '--opt',
        '--formatter-option',
        action='callback',
        type='string',
        callback=remember_formatter_option,
        help='Formatter-specific option name=value',
    )
    option_parser.add_option(
        '--help',
        action='callback',
        callback=show_verbose_help,
        help='Verbose help',
    )

    options, calendar_titles = option_parser.parse_args(args)

    log_level = VERBOSE_LEVELS.get(options.verbose_level, logging.DEBUG)
    logging.basicConfig(level=log_level, format='%(message)s')

    config = ConfigParser()
    config.read([options.config_filename])

    # Compute the date range for items to be included in our output.
    start_date = tz.normalize_to_utc(
        datetime.datetime.combine(
            datetime.date.today() - datetime.timedelta(options.days_ago),
            datetime.time.min,
        ))
    end_date = tz.normalize_to_utc(
        datetime.datetime.combine(
            datetime.date.today() + datetime.timedelta(options.days_ahead + 1),
            datetime.time.min,
        ))
    logging.info('Starting %d days ago at %s', options.days_ago,
                 start_date.astimezone(tz.local))
    logging.info('Ending %d days from now at %s', options.days_ahead,
                 end_date.astimezone(tz.local))

    if options.output_file_name:
        logging.info('Writing to %s', options.output_file_name)

    # Load the calendars
    if calendar_titles:
        calendar_generator = calendars.get_by_titles(
            path=options.input_directory, titles=calendar_titles)
    else:
        calendar_generator = calendars.discover(
            path=options.input_directory, active_only=options.active_only)

    # Process the calendar data
    output = codecs.getwriter('utf-8')(sys.stdout)
    if options.output_file_name:
        output = codecs.open(options.output_file_name, 'wt', 'UTF-8')
    try:
        formatter = FORMATTER_FACTORIES[options.format](output, config,
                                                        options)
        for calendar in calendar_generator:
            logging.info('Processing: %s', calendar.title)
            formatter.start_calendar(calendar)
            for event in filter.unique(
                    filter.by_date_range(
                        calendar.get_events(),
                        start_date,
                        end_date,
                    )):
                logging.info('  %s', event.summary.value)
                formatter.add_event(event)
            formatter.end_calendar(calendar)
    finally:
        formatter.close()
        if output != sys.stdout:
            output.close()
    return