def log_default(self, timestamp_from_dt=None, timestamp_to_dt=None,
                    limit=None, rel_filepath=None, stop_on_copy=False,
                    revision_from=None, revision_to=None, changelist=False,
                    use_merge_history=False):
        """Allow for the most-likely kind of log listing: the complete list,
        a FROM and TO timestamp, a FROM timestamp only, or a quantity limit.
        """

        full_url_or_path = self.__url_or_path
        if rel_filepath is not None:
            full_url_or_path += '/' + rel_filepath

        timestamp_from_phrase = ('{' + timestamp_from_dt.isoformat() + '}') \
            if timestamp_from_dt \
            else ''

        timestamp_to_phrase = ('{' + timestamp_to_dt.isoformat() + '}') \
            if timestamp_to_dt \
            else ''

        args = []

        if timestamp_from_phrase or timestamp_to_phrase:
            if not timestamp_from_phrase:
                raise ValueError("The default log retriever can not take a TO "
                                 "timestamp without a FROM timestamp.")

            if not timestamp_to_phrase:
                timestamp_to_phrase = 'HEAD'

            args += ['-r', timestamp_from_phrase + ':' + timestamp_to_phrase]

        if revision_from or revision_to:
            if timestamp_from_phrase or timestamp_to_phrase:
                raise ValueError("The default log retriever can not take both "
                                 "timestamp and revision number ranges.")

            if not revision_from:
                revision_from = '1'

            if not revision_to:
                revision_to = 'HEAD'

            args += ['-r', str(revision_from) + ':' + str(revision_to)]

        if limit is not None:
            args += ['-l', str(limit)]

        if stop_on_copy is True:
            args += ['--stop-on-copy']

        if use_merge_history is True:
            args += ['--use-merge-history']

        if changelist is True:
            args += ['--verbose']

        result = self.run_command(
            'log',
            args + ['--xml', full_url_or_path],
            do_combine=True)

        root = xml.etree.ElementTree.fromstring(result)
        named_fields = ['date', 'msg', 'revision', 'author', 'changelist']
        c = collections.namedtuple(
            'LogEntry',
            named_fields)

        # Merge history can create nested log entries, so use iter instead of findall
        for e in root.iter('logentry'):
            entry_info = {x.tag: x.text for x in e.getchildren()}

            date = None
            date_text = entry_info.get('date')
            if date_text is not None:
                date = dateutil.parser.parse(date_text)

            log_entry = {
                'msg': entry_info.get('msg'),
                'author': entry_info.get('author'),
                'revision': int(e.get('revision')),
                'date': date
            }

            if changelist is True:
                cl = []
                for ch in e.findall('paths/path'):
                    cl.append((ch.attrib['action'], ch.text))

                log_entry['changelist'] = cl
            else:
                log_entry['changelist'] = None

            yield c(**log_entry)
def log_default ( self , timestamp_from_dt = None , timestamp_to_dt = None , limit = None , rel_filepath = None , stop_on_copy = False , revision_from = None , revision_to = None , changelist = False , use_merge_history = False ) : full_url_or_path = self . __url_or_path if rel_filepath is not None : full_url_or_path += '/' + rel_filepath timestamp_from_phrase = ( '{' + timestamp_from_dt . isoformat ( ) + '}' ) if timestamp_from_dt else '' timestamp_to_phrase = ( '{' + timestamp_to_dt . isoformat ( ) + '}' ) if timestamp_to_dt else '' args = [ ] if timestamp_from_phrase or timestamp_to_phrase : if not timestamp_from_phrase : raise ValueError ( "The default log retriever can not take a TO " "timestamp without a FROM timestamp." ) if not timestamp_to_phrase : timestamp_to_phrase = 'HEAD' args += [ '-r' , timestamp_from_phrase + ':' + timestamp_to_phrase ] if revision_from or revision_to : if timestamp_from_phrase or timestamp_to_phrase : raise ValueError ( "The default log retriever can not take both " "timestamp and revision number ranges." ) if not revision_from : revision_from = '1' if not revision_to : revision_to = 'HEAD' args += [ '-r' , str ( revision_from ) + ':' + str ( revision_to ) ] if limit is not None : args += [ '-l' , str ( limit ) ] if stop_on_copy is True : args += [ '--stop-on-copy' ] if use_merge_history is True : args += [ '--use-merge-history' ] if changelist is True : args += [ '--verbose' ] result = self . run_command ( 'log' , args + [ '--xml' , full_url_or_path ] , do_combine = True ) root = xml . etree . ElementTree . fromstring ( result ) named_fields = [ 'date' , 'msg' , 'revision' , 'author' , 'changelist' ] c = collections . namedtuple ( 'LogEntry' , named_fields ) for e in root . iter ( 'logentry' ) : entry_info = { x . tag : x . text for x in e . getchildren ( ) } date = None date_text = entry_info . get ( 'date' ) if date_text is not None : date = dateutil . parser . parse ( date_text ) log_entry = { 'msg' : entry_info . get ( 'msg' ) , 'author' : entry_info . get ( 'author' ) , 'revision' : int ( e . get ( 'revision' ) ) , 'date' : date } if changelist is True : cl = [ ] for ch in e . findall ( 'paths/path' ) : cl . append ( ( ch . attrib [ 'action' ] , ch . text ) ) log_entry [ 'changelist' ] = cl else : log_entry [ 'changelist' ] = None yield c ( ** log_entry )
Allow for the most-likely kind of log listing: the complete list,
        a FROM and TO timestamp, a FROM timestamp only, or a quantity limit.