Changeset 1241 in tailor for vcpx/repository/darcs/source.py


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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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.