Changeset 1241 in tailor


Ignore:
Timestamp:
08/15/06 00:11:26 (7 years ago)
Author:
lele@…
Hash name:
20060814221126-97f81-d54d76cb84ff96793c96fa5b09a762fd389cdc18
Message:

Reimplement the fixup of darcs hunks order

Location:
vcpx
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • vcpx/tests/darcs.py

    r1223 r1241  
    169169        cset = csets[2] 
    170170        self.assertEqual(cset.revision, 'moved') 
    171         self.assertEqual(len(cset.entries), 2) 
    172  
    173         entry = cset.entries[0] 
    174         self.assertEqual(entry.name, 'bdir') 
    175         self.assertEqual(entry.action_kind, entry.ADDED) 
    176  
    177         entry = cset.entries[1] 
     171        self.assertEqual(len(cset.entries), 1) 
     172 
     173        entry = cset.entries[0] 
    178174        self.assertEqual(entry.name, 'dir') 
    179         self.assertEqual(entry.action_kind, entry.RENAMED) 
     175        self.assertEqual(entry.action_kind, entry.ADDED) 
    180176 
    181177        cset = csets[3] 
     
    358354                            if ((e.name.startswith(n.name+'/') or (e.old_name==n.name)) and 
    359355                                (n.action_kind==n.ADDED or n.action_kind==n.RENAMED))] 
    360                 for ee in postadds: 
    361                     print ee 
    362356                self.assertEqual(postadds, []) 
    363357 
     
    398392""" 
    399393 
     394    MIXED_TEST = """ 
     395<changelog> 
     396<patch author='esj@harvee.org' date='20050104213401' local_date='Tue Jan  4 22:34:01 CET 2005' inverted='False' hash='20050104213401-fab45-49c3d772521e523fa84be43883b235dbcbf9d61c.gz'> 
     397        <name>feedback and logging </name> 
     398        <comment>this patch has three major changes.  First is the addition of the 
     399false negative feedback so that spam that leaks through 
     400can be identified and corrected. 
     401 
     402second is the logging changes minimizing information 
     403dumped at the highest levels (1) in order to speed up message processing 
     404 
     405third is updating portalocker for modern pythons. 
     406</comment> 
     407    <summary> 
     408    <move from="ancillary/mbox2rpc.py" to="ancillary/fnsource.py"/> 
     409    <move from="ancillary/rpc2mbox.py" to="web-ui/cgi-exec/fnsink.py"/> 
     410    <modify_file> 
     411    ancillary/fnsource.py<added_lines num='335'/> 
     412    </modify_file> 
     413    <modify_file> 
     414    ancillary/global_configuration<added_lines num='8'/> 
     415    </modify_file> 
     416    <add_file> 
     417    ancillary/mbox2rpc.py 
     418    </add_file> 
     419    <modify_file> 
     420    ancillary/mbox2spamtrap.py<removed_lines num='1'/><added_lines num='1'/> 
     421    </modify_file> 
     422    <add_file> 
     423    ancillary/rpc2mbox.py 
     424    </add_file> 
     425    <modify_file> 
     426    modules/camram_email.py<removed_lines num='17'/><added_lines num='33'/> 
     427    </modify_file> 
     428    <modify_file> 
     429    modules/camram_utils.py<removed_lines num='2'/><added_lines num='5'/> 
     430    </modify_file> 
     431    <modify_file> 
     432    modules/configuration.py<removed_lines num='15'/><added_lines num='15'/> 
     433    </modify_file> 
     434    <modify_file> 
     435    modules/dbm_utils.py<removed_lines num='4'/><added_lines num='4'/> 
     436    </modify_file> 
     437    <modify_file> 
     438    modules/log.py<removed_lines num='1'/><added_lines num='1'/> 
     439    </modify_file> 
     440    <modify_file> 
     441    modules/portalocker.py<removed_lines num='2'/><added_lines num='2'/> 
     442    </modify_file> 
     443    <modify_file> 
     444    sgid/build.sh<removed_lines num='1'/><added_lines num='4'/> 
     445    </modify_file> 
     446    <modify_file> 
     447    src/core_filter.py<removed_lines num='50'/><added_lines num='55'/> 
     448    </modify_file> 
     449    <modify_file> 
     450    src/postfix_filter.py<removed_lines num='35'/><added_lines num='49'/> 
     451    </modify_file> 
     452    <modify_file> 
     453    src/postfix_stamper.py<removed_lines num='17'/><added_lines num='18'/> 
     454    </modify_file> 
     455    <modify_file> 
     456    web-ui/cgi-exec/correct.py<removed_lines num='17'/><added_lines num='17'/> 
     457    </modify_file> 
     458    <modify_file> 
     459    web-ui/cgi-exec/edit_config.py<removed_lines num='23'/><added_lines num='26'/> 
     460    </modify_file> 
     461    <modify_file> 
     462    web-ui/cgi-exec/fnsink.py<added_lines num='154'/> 
     463    </modify_file> 
     464    <modify_file> 
     465    web-ui/cgi-exec/recover.py<removed_lines num='5'/><added_lines num='5'/> 
     466    </modify_file> 
     467    <modify_file> 
     468    web-ui/cgi-exec/spamtrap_display.py<removed_lines num='4'/><added_lines num='4'/> 
     469    </modify_file> 
     470    <modify_file> 
     471    web-ui/templates/correct.html<removed_lines num='1'/><added_lines num='1'/> 
     472    </modify_file> 
     473    </summary> 
     474</patch> 
     475</changelog> 
     476""" 
     477 
    400478    def testAddAndRename(self): 
    401479        "Verify if the parser degrades (add A)+(rename A B) to (add B)" 
     
    405483 
    406484        cset = csets.next() 
    407         for e in cset.entries: print e 
    408485 
    409486        entry = cset.entries[2] 
    410487        self.assertEqual(entry.name, 'vcpx/repository/git/__init__.py') 
    411         self.assertEqual(entry.action_kind, entry.ADD) 
     488        self.assertEqual(entry.action_kind, entry.ADDED) 
     489 
     490        log = StringIO(self.MIXED_TEST) 
     491        csets = changesets_from_darcschanges(log) 
     492 
     493        cset = csets.next() 
     494        self.assertEqual([], [e for e in cset.entries if e.name == 'ancillary/mbox2rpc.py']) 
     495        self.assertEqual([], [e for e in cset.entries if e.action_kind == e.RENAMED]) 
  • vcpx/repository/darcs/source.py

    r1222 r1241  
    1414import re 
    1515 
     16from vcpx.changes import ChangesetEntry, Changeset 
    1617from vcpx.shwrap import ExternalCommand, PIPE, STDOUT 
    1718from vcpx.source import UpdatableSourceWorkingDir, ChangesetApplicationFailure, \ 
     
    2122 
    2223 
     24class DarcsChangeset(Changeset): 
     25    """ 
     26    Fixup darcs idiosyncrasies: 
     27 
     28    - collapse "add A; rename A B" into "add B" 
     29    - collapse "rename A B; remove B" into "remove A" 
     30    """ 
     31 
     32    def __init__(self, revision, date, author, log, entries=None, **other): 
     33        """ 
     34        Initialize a new DarcsChangeset. 
     35        """ 
     36 
     37        super(DarcsChangeset, self).__init__(revision, date, author, log, entries=None, **other) 
     38        if entries is not None: 
     39            for e in entries: 
     40                self.addEntry(e, revision) 
     41 
     42    def addEntry(self, entry, revision): 
     43        """ 
     44        Fixup darcs idiosyncrasies: 
     45         
     46        - collapse "add A; rename A B" into "add B" 
     47        - collapse "rename A B; remove B" into "remove A" 
     48        """ 
     49 
     50        # This should not happen, since the parser feeds us an already built 
     51        # list of ChangesetEntries, anyway... 
     52        if not isinstance(entry, ChangesetEntry): 
     53            return super(DarcsChangeset, self).addEntry(entry, revision) 
     54 
     55        # Ok, before adding this entry, check it against already 
     56        # known: if this is an add, and there's a rename (such as "add 
     57        # A; rename A B; ") then... 
     58         
     59        if entry.action_kind == entry.ADDED: 
     60            # ... we have to check existings, because of a bug in 
     61            # darcs: `changes --xml` (as of 1.0.7) emits the changes 
     62            # in the wrong order, that is, it prefers to start with 
     63            # renames, *always*, even when they obviously follows the 
     64            # add of the same entry (even, it should apply this "fix" 
     65            # by its own). 
     66            # 
     67            # So, if there's a rename of this entry there, change that 
     68            # to an addition instead, and don't insert any other entry 
     69 
     70            dirname = entry.name+'/' # darcs hopefully use forward slashes also under win 
     71             
     72            for i,e in enumerate(self.entries): 
     73                if e.action_kind == e.RENAMED and e.old_name == entry.name: 
     74                    # Luckily enough (since removes are the first entries 
     75                    # in the list, that is) by anticipating the add we 
     76                    # cure also the case below, when addition follows 
     77                    # edit. 
     78                    e.action_kind = e.ADDED 
     79                    e.old_name = None 
     80                    return e 
     81 
     82                # Assert also that add_dir events must preceeds any 
     83                # add_file and ren_file that have that dir as target, 
     84                # and that add_file preceeds any edit. 
     85 
     86                if ((e.name == entry.name or e.name.startswith(dirname)) 
     87                    or (e.action_kind == e.RENAMED and e.old_name.startswith(dirname))): 
     88                    self.entries.insert(i, entry) 
     89                    return entry 
     90 
     91        # Likewise, if this is a deletion, and there is a rename of this 
     92        # entry (such as "rename A B; remove B") then ... 
     93         
     94        elif entry.action_kind == entry.DELETED: 
     95            # turn the existing rename into a deletion instead 
     96             
     97            for i,e in enumerate(self.entries): 
     98                if e.action_kind == e.RENAMED and e.name == entry.name: 
     99                    e.action_kind = e.DELETED 
     100                    e.name = e.old_name 
     101                    e.old_name = None 
     102                    return e 
     103 
     104        # Ok, it must be either an edit or a rename: the former goes 
     105        # obviously to the end, and since the latter, as said, come 
     106        # in very early, appending is just good. 
     107        self.entries.append(entry) 
     108        return entry 
     109 
     110         
    23111def changesets_from_darcschanges(changes, unidiff=False, repodir=None, 
    24112                                 chunksize=2**15): 
     
    55143    from xml.sax.handler import ContentHandler, ErrorHandler 
    56144    from datetime import datetime 
    57     from vcpx.changes import ChangesetEntry, Changeset 
    58145 
    59146    class DarcsXMLChangesHandler(ContentHandler): 
     
    97184        def endElement(self, name): 
    98185            if name == 'patch': 
    99                 entries = [] 
    100                 todo = self.current['entries'] 
    101                 # Darcs allows "rename A B; remove B": collapse those 
    102                 # into "remove A" 
    103                 while todo: 
    104                     e = todo.pop(0) 
    105                     if e.action_kind == e.RENAMED: 
    106                         lookfor = e.name 
    107                         forget = [] 
    108                         for i,n in enumerate(todo): 
    109                             if n.action_kind == n.DELETED and n.name == lookfor: 
    110                                 e.action_kind = e.DELETED 
    111                                 e.name = e.old_name 
    112                                 e.old_name = None 
    113                                 entries.append(e) 
    114                                 forget.append(i) 
    115                                 forget.reverse() 
    116                                 for i in forget: 
    117                                     del todo[i] 
    118                                 break 
    119                             elif n.action_kind == n.RENAMED and n.old_name == lookfor: 
    120                                 forget.append(i) 
    121                                 lookfor = n.name 
    122                         if not forget: 
    123                             entries.append(e) 
    124                     else: 
    125                         entries.append(e) 
    126  
    127                 # Darcs changes --xml (as of 1.0.7) emits bad ordered hunks: it 
    128                 # begins with file moves, apparently for no good reason. Do as 
    129                 # little reordering as needed to adjust the meaning, ie moving all 
    130                 # add_dirs before add_file and ren_file that have that dir as 
    131                 # target 
    132  
    133                 sorted = False 
    134                 while not sorted: 
    135                     sorted = True 
    136                     for i,e in enumerate(entries): 
    137                         if e.action_kind == e.RENAMED: 
    138                             for j,n in enumerate(entries[i+1:]): 
    139                                 if ((e.name.startswith(n.name+'/') or e.old_name==n.name) and 
    140                                     (n.action_kind == n.ADDED or n.action_kind == n.RENAMED)): 
    141                                     m = entries.pop(i+1+j) 
    142                                     entries.insert(i, m) 
    143                                     sorted = False 
    144  
    145                 cset = Changeset(self.current['name'], 
    146                                  self.current['date'], 
    147                                  self.current['author'], 
    148                                  self.current['comment'], 
    149                                  entries, 
    150                                  tags=self.current.get('tags',[])) 
     186                cset = DarcsChangeset(self.current['name'], 
     187                                      self.current['date'], 
     188                                      self.current['author'], 
     189                                      self.current['comment'], 
     190                                      self.current['entries'], 
     191                                      tags=self.current.get('tags',[])) 
    151192                cset.darcs_hash = self.current['hash'] 
    152193                if self.darcsdiff: 
Note: See TracChangeset for help on using the changeset viewer.