Esempio n. 1
0
  def itemlog(self, path_parts, rev, sortby, first, limit, options):
    """see vclib.Repository.itemlog docstring

    rev parameter can be a revision number, a branch number, a tag name,
    or None. If None, will return information about all revisions, otherwise,
    will only return information about the specified revision or branch.

    Option values returned by this implementation:

      cvs_tags
        dictionary of Tag objects for all tags encountered
    """
    if self.itemtype(path_parts, rev) != vclib.FILE:  # does auth-check
      raise vclib.Error("Path '%s' is not a file." % (_path_join(path_parts)))

    path = self.rcsfile(path_parts, 1)
    sink = TreeSink()
    rcsparse.parse(open(path, 'rb'), sink)
    filtered_revs = _file_log(sink.revs.values(), sink.tags, sink.lockinfo,
                              sink.default_branch, rev)
    for rev in filtered_revs:
      if rev.prev and len(rev.number) == 2:
        rev.changed = rev.prev.next_changed
    options['cvs_tags'] = sink.tags

    if sortby == vclib.SORTBY_DATE:
      filtered_revs.sort(_logsort_date_cmp)
    elif sortby == vclib.SORTBY_REV:
      filtered_revs.sort(_logsort_rev_cmp)

    if len(filtered_revs) < first:
      return []
    if limit:
      return filtered_revs[first:first+limit]
    return filtered_revs
Esempio n. 2
0
  def itemlog(self, path_parts, rev, sortby, first, limit, options):
    """see vclib.Repository.itemlog docstring

    rev parameter can be a revision number, a branch number, a tag name,
    or None. If None, will return information about all revisions, otherwise,
    will only return information about the specified revision or branch.

    Option values returned by this implementation:

      cvs_tags
        dictionary of Tag objects for all tags encountered
    """
    if self.itemtype(path_parts, rev) != vclib.FILE:  # does auth-check
      raise vclib.Error("Path '%s' is not a file." % (_path_join(path_parts)))

    path = self.rcsfile(path_parts, 1)
    sink = TreeSink()
    rcsparse.parse(open(path, 'rb'), sink)
    filtered_revs = _file_log(sink.revs.values(), sink.tags, sink.lockinfo,
                              sink.default_branch, rev)
    for rev in filtered_revs:
      if rev.prev and len(rev.number) == 2:
        rev.changed = rev.prev.next_changed
    options['cvs_tags'] = sink.tags

    if sortby == vclib.SORTBY_DATE:
      filtered_revs.sort(_logsort_date_cmp)
    elif sortby == vclib.SORTBY_REV:
      filtered_revs.sort(_logsort_rev_cmp)
      
    if len(filtered_revs) < first:
      return []
    if limit:
      return filtered_revs[first:first+limit]
    return filtered_revs
Esempio n. 3
0
 def openfile(self, path_parts, rev, options):
   if self.itemtype(path_parts, rev) != vclib.FILE:  # does auth-check
     raise vclib.Error("Path '%s' is not a file." % (_path_join(path_parts)))
   path = self.rcsfile(path_parts, 1)
   sink = COSink(rev)
   rcsparse.parse(open(path, 'rb'), sink)
   revision = sink.last and sink.last.string
   return cStringIO.StringIO('\n'.join(sink.sstext.text)), revision
Esempio n. 4
0
 def openfile(self, path_parts, rev, options):
   if self.itemtype(path_parts, rev) != vclib.FILE:  # does auth-check
     raise vclib.Error("Path '%s' is not a file." % (_path_join(path_parts)))
   path = self.rcsfile(path_parts, 1)
   sink = COSink(rev)
   rcsparse.parse(open(path, 'rb'), sink)
   revision = sink.last and sink.last.string
   return cStringIO.StringIO('\n'.join(sink.sstext.text)), revision
Esempio n. 5
0
    def dirlogs(self, path_parts, rev, entries, options):
        """see vclib.Repository.dirlogs docstring

    rev can be a tag name or None. if set only information from revisions
    matching the tag will be retrieved

    Option values recognized by this implementation:

      cvs_subdirs
        boolean. true to fetch logs of the most recently modified file in each
        subdirectory

    Option values returned by this implementation:

      cvs_tags, cvs_branches
        lists of tag and branch names encountered in the directory
    """
        if self.itemtype(path_parts, rev) != vclib.DIR:  # does auth-check
            raise vclib.Error("Path '%s' is not a directory." %
                              (string.join(path_parts, "/")))
        entries_to_fetch = []
        for entry in entries:
            if vclib.check_path_access(self, path_parts + [entry.name], None,
                                       rev):
                entries_to_fetch.append(entry)

        subdirs = options.get('cvs_subdirs', 0)

        dirpath = self._getpath(path_parts)
        alltags = {  # all the tags seen in the files of this dir
            'MAIN': '',
            'HEAD': '1.1'
        }

        for entry in entries_to_fetch:
            entry.rev = entry.date = entry.author = None
            entry.dead = entry.absent = entry.log = entry.lockinfo = None
            path = _log_path(entry, dirpath, subdirs)
            if path:
                entry.path = path
                try:
                    rcsparse.parse(open(path, 'rb'),
                                   InfoSink(entry, rev, alltags))
                except IOError, e:
                    entry.errors.append("rcsparse error: %s" % e)
                except RuntimeError, e:
                    entry.errors.append("rcsparse error: %s" % e)
                except rcsparse.RCSStopParser:
                    pass
Esempio n. 6
0
  def dirlogs(self, path_parts, rev, entries, options):
    """see vclib.Repository.dirlogs docstring

    rev can be a tag name or None. if set only information from revisions
    matching the tag will be retrieved

    Option values recognized by this implementation:

      cvs_subdirs
        boolean. true to fetch logs of the most recently modified file in each
        subdirectory

    Option values returned by this implementation:

      cvs_tags, cvs_branches
        lists of tag and branch names encountered in the directory
    """
    if self.itemtype(path_parts, rev) != vclib.DIR:  # does auth-check
      raise vclib.Error("Path '%s' is not a directory."
                        % (part2path(path_parts)))
    entries_to_fetch = []
    for entry in entries:
      if vclib.check_path_access(self, path_parts + [entry.name], None, rev):
        entries_to_fetch.append(entry)

    subdirs = options.get('cvs_subdirs', 0)

    dirpath = self._getpath(path_parts)
    alltags = {           # all the tags seen in the files of this dir
      'MAIN' : '',
      'HEAD' : '1.1'
    }

    for entry in entries_to_fetch:
      entry.rev = entry.date = entry.author = None
      entry.dead = entry.absent = entry.log = entry.lockinfo = None
      path = _log_path(entry, dirpath, subdirs)
      if path:
        entry.path = path
        try:
          rcsparse.parse(open(path, 'rb'), InfoSink(entry, rev, alltags))
          if self.guesser:
            entry.log = self.guesser.utf8(entry.log)
        except IOError, e:
          entry.errors.append("rcsparse error: %s" % e)
        except RuntimeError, e:
          entry.errors.append("rcsparse error: %s" % e)
        except rcsparse.RCSStopParser:
          pass
Esempio n. 7
0
  def parse_cvs_file(self, rcs_pathname, opt_rev = None, opt_m_timestamp = None):
    # Args in:  opt_rev - requested revision
    #           opt_m - time since modified
    # Args out: revision_map
    #           timestamp
    #           revision_deltatext

    # CheckHidden(rcs_pathname)
    try:
      rcsfile = open(rcs_pathname, 'rb')
    except:
      raise RuntimeError, ('error: %s appeared to be under CVS control, ' +
              'but the RCS file is inaccessible.') % rcs_pathname

    rcsparse.parse(rcsfile, self)
    rcsfile.close()

    if opt_rev in [None, '', 'HEAD']:
      # Explicitly specified topmost revision in tree
      revision = self.head_revision
    else:
      # Symbolic tag or specific revision number specified.
      revision = self.map_tag_to_revision(opt_rev)
      if revision == '':
        raise RuntimeError, 'error: -r: No such revision: ' + opt_rev

    # The primordial revision is not always 1.1!  Go find it.
    primordial = revision
    while self.prev_revision.get(primordial):
      primordial = self.prev_revision[primordial]

    # Don't display file at all, if -m option is specified and no
    # changes have been made in the specified file.
    if opt_m_timestamp and self.timestamp[revision] < opt_m_timestamp:
      return ''

    # Figure out how many lines were in the primordial, i.e. version 1.1,
    # check-in by moving backward in time from the head revision to the
    # first revision.
    line_count = 0
    if self.revision_deltatext.get(self.head_revision):
      tmp_array = self.deltatext_split(self.head_revision)
      line_count = len(tmp_array)

    skip = 0

    rev = self.prev_revision.get(self.head_revision)
    while rev:
      diffs = self.deltatext_split(rev)
      for command in diffs:
        dmatch = self.d_command.match(command)
        amatch = self.a_command.match(command)
        if skip > 0:
          # Skip insertion lines from a prior "a" command
          skip = skip - 1
        elif dmatch:
          # "d" - Delete command
          start_line = int(dmatch.group(1))
          count      = int(dmatch.group(2))
          line_count = line_count - count
        elif amatch:
          # "a" - Add command
          start_line = int(amatch.group(1))
          count      = int(amatch.group(2))
          skip       = count
          line_count = line_count + count
        else:
          raise RuntimeError, 'error: illegal RCS file'

      rev = self.prev_revision.get(rev)

    # Now, play the delta edit commands *backwards* from the primordial
    # revision forward, but rather than applying the deltas to the text of
    # each revision, apply the changes to an array of revision numbers.
    # This creates a "revision map" -- an array where each element
    # represents a line of text in the given revision but contains only
    # the revision number in which the line was introduced rather than
    # the line text itself.
    #
    # Note: These are backward deltas for revisions on the trunk and
    # forward deltas for branch revisions.

    # Create initial revision map for primordial version.
    self.revision_map = [primordial] * line_count

    ancestors = [revision, ] + self.ancestor_revisions(revision)
    ancestors = ancestors[:-1]  # Remove "1.1"
    last_revision = primordial
    ancestors.reverse()
    for revision in ancestors:
      is_trunk_revision = self.trunk_rev.match(revision) is not None

      if is_trunk_revision:
        diffs = self.deltatext_split(last_revision)

        # Revisions on the trunk specify deltas that transform a
        # revision into an earlier revision, so invert the translation
        # of the 'diff' commands.
        for command in diffs:
          if skip > 0:
            skip = skip - 1
          else:
            dmatch = self.d_command.match(command)
            amatch = self.a_command.match(command)
            if dmatch:
              start_line = int(dmatch.group(1))
              count      = int(dmatch.group(2))
              temp = []
              while count > 0:
                temp.append(revision)
                count = count - 1
              self.revision_map = (self.revision_map[:start_line - 1] +
                      temp + self.revision_map[start_line - 1:])
            elif amatch:
              start_line = int(amatch.group(1))
              count      = int(amatch.group(2))
              del self.revision_map[start_line:start_line + count]
              skip = count
            else:
              raise RuntimeError, 'Error parsing diff commands'

      else:
        # Revisions on a branch are arranged backwards from those on
        # the trunk.  They specify deltas that transform a revision
        # into a later revision.
        adjust = 0
        diffs = self.deltatext_split(revision)
        for command in diffs:
          if skip > 0:
            skip = skip - 1
          else:
            dmatch = self.d_command.match(command)
            amatch = self.a_command.match(command)
            if dmatch:
              start_line = int(dmatch.group(1))
              count      = int(dmatch.group(2))
              adj_begin  = start_line + adjust - 1
              adj_end    = start_line + adjust - 1 + count
              del self.revision_map[adj_begin:adj_end]
              adjust = adjust - count
            elif amatch:
              start_line = int(amatch.group(1))
              count      = int(amatch.group(2))
              skip = count
              temp = []
              while count > 0:
                temp.append(revision)
                count = count - 1
              self.revision_map = (self.revision_map[:start_line + adjust] +
                      temp + self.revision_map[start_line + adjust:])
              adjust = adjust + skip
            else:
              raise RuntimeError, 'Error parsing diff commands'

      last_revision = revision

    return revision
Esempio n. 8
0
  def parse_cvs_file(self, rcs_pathname, opt_rev = None, opt_m_timestamp = None):
    # Args in:  opt_rev - requested revision
    #           opt_m - time since modified
    # Args out: revision_map
    #           timestamp
    #           revision_deltatext

    # CheckHidden(rcs_pathname)
    try:
      rcsfile = open(rcs_pathname, 'rb')
    except:
      raise RuntimeError, ('error: %s appeared to be under CVS control, ' +
              'but the RCS file is inaccessible.') % rcs_pathname

    rcsparse.parse(rcsfile, self)
    rcsfile.close()

    if opt_rev in [None, '', 'HEAD']:
      # Explicitly specified topmost revision in tree
      revision = self.head_revision
    else:
      # Symbolic tag or specific revision number specified.
      revision = self.map_tag_to_revision(opt_rev)
      if revision == '':
        raise RuntimeError, 'error: -r: No such revision: ' + opt_rev

    # The primordial revision is not always 1.1!  Go find it.
    primordial = revision
    while self.prev_revision.get(primordial):
      primordial = self.prev_revision[primordial]

    # Don't display file at all, if -m option is specified and no
    # changes have been made in the specified file.
    if opt_m_timestamp and self.timestamp[revision] < opt_m_timestamp:
      return ''

    # Figure out how many lines were in the primordial, i.e. version 1.1,
    # check-in by moving backward in time from the head revision to the
    # first revision.
    line_count = 0
    if self.revision_deltatext.get(self.head_revision):
      tmp_array = self.deltatext_split(self.head_revision)
      line_count = len(tmp_array)

    skip = 0

    rev = self.prev_revision.get(self.head_revision)
    while rev:
      diffs = self.deltatext_split(rev)
      for command in diffs:
        dmatch = self.d_command.match(command)
        amatch = self.a_command.match(command)
        if skip > 0:
          # Skip insertion lines from a prior "a" command
          skip = skip - 1
        elif dmatch:
          # "d" - Delete command
          start_line = string.atoi(dmatch.group(1))
          count      = string.atoi(dmatch.group(2))
          line_count = line_count - count
        elif amatch:
          # "a" - Add command
          start_line = string.atoi(amatch.group(1))
          count      = string.atoi(amatch.group(2))
          skip       = count
          line_count = line_count + count
        else:
          raise RuntimeError, 'error: illegal RCS file'

      rev = self.prev_revision.get(rev)

    # Now, play the delta edit commands *backwards* from the primordial
    # revision forward, but rather than applying the deltas to the text of
    # each revision, apply the changes to an array of revision numbers.
    # This creates a "revision map" -- an array where each element
    # represents a line of text in the given revision but contains only
    # the revision number in which the line was introduced rather than
    # the line text itself.
    #
    # Note: These are backward deltas for revisions on the trunk and
    # forward deltas for branch revisions.

    # Create initial revision map for primordial version.
    self.revision_map = [primordial] * line_count

    ancestors = [revision, ] + self.ancestor_revisions(revision)
    ancestors = ancestors[:-1]  # Remove "1.1"
    last_revision = primordial
    ancestors.reverse()
    for revision in ancestors:
      is_trunk_revision = self.trunk_rev.match(revision) is not None

      if is_trunk_revision:
        diffs = self.deltatext_split(last_revision)

        # Revisions on the trunk specify deltas that transform a
        # revision into an earlier revision, so invert the translation
        # of the 'diff' commands.
        for command in diffs:
          if skip > 0:
            skip = skip - 1
          else:
            dmatch = self.d_command.match(command)
            amatch = self.a_command.match(command)
            if dmatch:
              start_line = string.atoi(dmatch.group(1))
              count      = string.atoi(dmatch.group(2))
              temp = []
              while count > 0:
                temp.append(revision)
                count = count - 1
              self.revision_map = (self.revision_map[:start_line - 1] +
                      temp + self.revision_map[start_line - 1:])
            elif amatch:
              start_line = string.atoi(amatch.group(1))
              count      = string.atoi(amatch.group(2))
              del self.revision_map[start_line:start_line + count]
              skip = count
            else:
              raise RuntimeError, 'Error parsing diff commands'

      else:
        # Revisions on a branch are arranged backwards from those on
        # the trunk.  They specify deltas that transform a revision
        # into a later revision.
        adjust = 0
        diffs = self.deltatext_split(revision)
        for command in diffs:
          if skip > 0:
            skip = skip - 1
          else:
            dmatch = self.d_command.match(command)
            amatch = self.a_command.match(command)
            if dmatch:
              start_line = string.atoi(dmatch.group(1))
              count      = string.atoi(dmatch.group(2))
              adj_begin  = start_line + adjust - 1
              adj_end    = start_line + adjust - 1 + count
              del self.revision_map[adj_begin:adj_end]
              adjust = adjust - count
            elif amatch:
              start_line = string.atoi(amatch.group(1))
              count      = string.atoi(amatch.group(2))
              skip = count
              temp = []
              while count > 0:
                temp.append(revision)
                count = count - 1
              self.revision_map = (self.revision_map[:start_line + adjust] +
                      temp + self.revision_map[start_line + adjust:])
              adjust = adjust + skip
            else:
              raise RuntimeError, 'Error parsing diff commands'

      last_revision = revision

    return revision