hgext/convert/cvsps.py
changeset 7862 02981000012e
parent 7601 49355875c805
child 7950 9bbcfa898cd3
equal deleted inserted replaced
7861:2bc14da14992 7862:02981000012e
    31         .lines     - a tuple (+lines, -lines) or None
    31         .lines     - a tuple (+lines, -lines) or None
    32         .parent    - Previous revision of this entry
    32         .parent    - Previous revision of this entry
    33         .rcs       - name of file as returned from CVS
    33         .rcs       - name of file as returned from CVS
    34         .revision  - revision number as tuple
    34         .revision  - revision number as tuple
    35         .tags      - list of tags on the file
    35         .tags      - list of tags on the file
       
    36         .synthetic - is this a synthetic "file ... added on ..." revision?
    36     '''
    37     '''
    37     def __init__(self, **entries):
    38     def __init__(self, **entries):
    38         self.__dict__.update(entries)
    39         self.__dict__.update(entries)
    39 
    40 
    40 class logerror(Exception):
    41 class logerror(Exception):
   105     re_32 = re.compile('=============================================================================$')
   106     re_32 = re.compile('=============================================================================$')
   106     re_50 = re.compile('revision ([\\d.]+)(\s+locked by:\s+.+;)?$')
   107     re_50 = re.compile('revision ([\\d.]+)(\s+locked by:\s+.+;)?$')
   107     re_60 = re.compile(r'date:\s+(.+);\s+author:\s+(.+);\s+state:\s+(.+?);(\s+lines:\s+(\+\d+)?\s+(-\d+)?;)?')
   108     re_60 = re.compile(r'date:\s+(.+);\s+author:\s+(.+);\s+state:\s+(.+?);(\s+lines:\s+(\+\d+)?\s+(-\d+)?;)?')
   108     re_70 = re.compile('branches: (.+);$')
   109     re_70 = re.compile('branches: (.+);$')
   109 
   110 
       
   111     file_added_re = re.compile(r'file [^/]+ was (initially )?added on branch')
       
   112 
   110     prefix = ''   # leading path to strip of what we get from CVS
   113     prefix = ''   # leading path to strip of what we get from CVS
   111 
   114 
   112     if directory is None:
   115     if directory is None:
   113         # Current working directory
   116         # Current working directory
   114 
   117 
   277             # as this state is re-entered for subsequent revisions of a file.
   280             # as this state is re-entered for subsequent revisions of a file.
   278             match = re_50.match(line)
   281             match = re_50.match(line)
   279             assert match, _('expected revision number')
   282             assert match, _('expected revision number')
   280             e = logentry(rcs=scache(rcs), file=scache(filename),
   283             e = logentry(rcs=scache(rcs), file=scache(filename),
   281                     revision=tuple([int(x) for x in match.group(1).split('.')]),
   284                     revision=tuple([int(x) for x in match.group(1).split('.')]),
   282                     branches=[], parent=None)
   285                     branches=[], parent=None,
       
   286                     synthetic=False)
   283             state = 6
   287             state = 6
   284 
   288 
   285         elif state == 6:
   289         elif state == 6:
   286             # expecting date, author, state, lines changed
   290             # expecting date, author, state, lines changed
   287             match = re_60.match(line)
   291             match = re_60.match(line)
   336                 state = 0
   340                 state = 0
   337                 store = True
   341                 store = True
   338             else:
   342             else:
   339                 e.comment.append(line)
   343                 e.comment.append(line)
   340 
   344 
       
   345         # When a file is added on a branch B1, CVS creates a synthetic
       
   346         # dead trunk revision 1.1 so that the branch has a root.
       
   347         # Likewise, if you merge such a file to a later branch B2 (one
       
   348         # that already existed when the file was added on B1), CVS
       
   349         # creates a synthetic dead revision 1.1.x.1 on B2.  Don't drop
       
   350         # these revisions now, but mark them synthetic so
       
   351         # createchangeset() can take care of them.
       
   352         if (store and
       
   353               e.dead and
       
   354               e.revision[-1] == 1 and      # 1.1 or 1.1.x.1
       
   355               len(e.comment) == 1 and
       
   356               file_added_re.match(e.comment[0])):
       
   357             ui.debug(_('found synthetic rev in %s: %r\n')
       
   358                      % (e.rcs, e.comment[0]))
       
   359             e.synthetic = True
       
   360 
   341         if store:
   361         if store:
   342             # clean up the results and save in the log.
   362             # clean up the results and save in the log.
   343             store = False
   363             store = False
   344             e.tags = util.sort([scache(x) for x in tags.get(e.revision, [])])
   364             e.tags = util.sort([scache(x) for x in tags.get(e.revision, [])])
   345             e.comment = scache('\n'.join(e.comment))
   365             e.comment = scache('\n'.join(e.comment))
   397         .comment   - commit message
   417         .comment   - commit message
   398         .date      - the commit date as a (time,tz) tuple
   418         .date      - the commit date as a (time,tz) tuple
   399         .entries   - list of logentry objects in this changeset
   419         .entries   - list of logentry objects in this changeset
   400         .parents   - list of one or two parent changesets
   420         .parents   - list of one or two parent changesets
   401         .tags      - list of tags on this changeset
   421         .tags      - list of tags on this changeset
       
   422         .synthetic - from synthetic revision "file ... added on branch ..."
   402     '''
   423     '''
   403     def __init__(self, **entries):
   424     def __init__(self, **entries):
   404         self.__dict__.update(entries)
   425         self.__dict__.update(entries)
   405 
   426 
   406 def createchangeset(ui, log, fuzz=60, mergefrom=None, mergeto=None):
   427 def createchangeset(ui, log, fuzz=60, mergefrom=None, mergeto=None):
   435                 ui.status(util.ellipsis(t, 80) + '\n')
   456                 ui.status(util.ellipsis(t, 80) + '\n')
   436 
   457 
   437         c.entries.append(e)
   458         c.entries.append(e)
   438         files[e.file] = True
   459         files[e.file] = True
   439         c.date = e.date       # changeset date is date of latest commit in it
   460         c.date = e.date       # changeset date is date of latest commit in it
       
   461 
       
   462     # Mark synthetic changesets
       
   463 
       
   464     for c in changesets:
       
   465         # Synthetic revisions always get their own changeset, because
       
   466         # the log message includes the filename.  E.g. if you add file3
       
   467         # and file4 on a branch, you get four log entries and three
       
   468         # changesets:
       
   469         #   "File file3 was added on branch ..." (synthetic, 1 entry)
       
   470         #   "File file4 was added on branch ..." (synthetic, 1 entry)
       
   471         #   "Add file3 and file4 to fix ..."     (real, 2 entries)
       
   472         # Hence the check for 1 entry here.
       
   473         c.synthetic = (len(c.entries) == 1 and c.entries[0].synthetic)
   440 
   474 
   441     # Sort files in each changeset
   475     # Sort files in each changeset
   442 
   476 
   443     for c in changesets:
   477     for c in changesets:
   444         def pathcompare(l, r):
   478         def pathcompare(l, r):
   544             for f in c.entries:
   578             for f in c.entries:
   545                 p = max(p, versions.get((f.rcs, f.parent), None))
   579                 p = max(p, versions.get((f.rcs, f.parent), None))
   546 
   580 
   547         c.parents = []
   581         c.parents = []
   548         if p is not None:
   582         if p is not None:
   549             c.parents.append(changesets[p])
   583             p = changesets[p]
       
   584 
       
   585             # Ensure no changeset has a synthetic changeset as a parent.
       
   586             while p.synthetic:
       
   587                 assert len(p.parents) <= 1, \
       
   588                        _('synthetic changeset cannot have multiple parents')
       
   589                 if p.parents:
       
   590                     p = p.parents[0]
       
   591                 else:
       
   592                     p = None
       
   593                     break
       
   594 
       
   595             if p is not None:
       
   596                 c.parents.append(p)
   550 
   597 
   551         if mergefrom:
   598         if mergefrom:
   552             m = mergefrom.search(c.comment)
   599             m = mergefrom.search(c.comment)
   553             if m:
   600             if m:
   554                 m = m.group(1)
   601                 m = m.group(1)
   580                     continue
   627                     continue
   581 
   628 
   582         branches[c.branch] = i
   629         branches[c.branch] = i
   583         i += 1
   630         i += 1
   584 
   631 
       
   632     # Drop synthetic changesets (safe now that we have ensured no other
       
   633     # changesets can have them as parents).
       
   634     i = 0
       
   635     while i < len(changesets):
       
   636         if changesets[i].synthetic:
       
   637             del changesets[i]
       
   638         else:
       
   639             i += 1
       
   640 
   585     # Number changesets
   641     # Number changesets
   586 
   642 
   587     for i, c in enumerate(changesets):
   643     for i, c in enumerate(changesets):
   588         c.id = i + 1
   644         c.id = i + 1
   589 
   645