⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 blame.py

📁 PHP写的图片查看器
💻 PY
📖 第 1 页 / 共 2 页
字号:
#!/usr/local/bin/python# -*-python-*-## Copyright (C) 2000-2001 The ViewCVS Group. All Rights Reserved.# Copyright (C) 2000 Curt Hagenlocher <curt@hagenlocher.org>## By using this file, you agree to the terms and conditions set forth in# the LICENSE.html file which can be found at the top level of the ViewCVS# distribution or at http://viewcvs.sourceforge.net/license-1.html.## Contact information:#   Greg Stein, PO Box 760, Palo Alto, CA, 94302#   gstein@lyra.org, http://viewcvs.sourceforge.net/## -----------------------------------------------------------------------## blame.py: Annotate each line of a CVS file with its author,#           revision #, date, etc.## -----------------------------------------------------------------------## This software is being maintained as part of the ViewCVS project.# Information is available at:#    http://viewcvs.sourceforge.net/## This file is based on the cvsblame.pl portion of the Bonsai CVS tool,# developed by Steve Lamm for Netscape Communications Corporation.  More# information about Bonsai can be found at#    http://www.mozilla.org/bonsai.html## cvsblame.pl, in turn, was based on Scott Furman's cvsblame script## -----------------------------------------------------------------------#import stringimport sysimport osimport reimport timeimport mathimport cgiimport rcsparseclass CVSParser(rcsparse.Sink):  # Precompiled regular expressions  trunk_rev   = re.compile('^[0-9]+\\.[0-9]+$')  last_branch = re.compile('(.*)\\.[0-9]+')  is_branch   = re.compile('(.*)\\.0\\.([0-9]+)')  d_command   = re.compile('^d(\d+)\\s(\\d+)')  a_command   = re.compile('^a(\d+)\\s(\\d+)')  SECONDS_PER_DAY = 86400  def __init__(self):    self.Reset()  def Reset(self):    self.last_revision = {}    self.prev_revision = {}    self.revision_date = {}    self.revision_author = {}    self.revision_branches = {}    self.next_delta = {}    self.prev_delta = {}    self.tag_revision = {}    self.revision_symbolic_name = {}    self.timestamp = {}    self.revision_ctime = {}    self.revision_age = {}    self.revision_log = {}    self.revision_deltatext = {}    self.revision_map = []    self.lines_added  = {}    self.lines_removed = {}  # Map a tag to a numerical revision number.  The tag can be a symbolic  # branch tag, a symbolic revision tag, or an ordinary numerical  # revision number.  def map_tag_to_revision(self, tag_or_revision):    try:      revision = self.tag_revision[tag_or_revision]      match = self.is_branch.match(revision)      if match:        branch = match.group(1) + '.' + match.group(2)        if self.last_revision.get(branch):          return self.last_revision[branch]        else:          return match.group(1)      else:        return revision    except:      return ''  # Construct an ordered list of ancestor revisions to the given  # revision, starting with the immediate ancestor and going back  # to the primordial revision (1.1).  #  # Note: The generated path does not traverse the tree the same way  #       that the individual revision deltas do.  In particular,  #       the path traverses the tree "backwards" on branches.  def ancestor_revisions(self, revision):    ancestors = []    revision = self.prev_revision.get(revision)    while revision:      ancestors.append(revision)      revision = self.prev_revision.get(revision)    return ancestors  # Split deltatext specified by rev to each line.  def deltatext_split(self, rev):    lines = string.split(self.revision_deltatext[rev], '\n')    if lines[-1] == '':      del lines[-1]    return lines  # Extract the given revision from the digested RCS file.  # (Essentially the equivalent of cvs up -rXXX)  def extract_revision(self, revision):    path = []    add_lines_remaining = 0    start_line = 0    count = 0    while revision:      path.append(revision)      revision = self.prev_delta.get(revision)    path.reverse()    path = path[1:]  # Get rid of head revision    text = self.deltatext_split(self.head_revision)    # Iterate, applying deltas to previous revision    for revision in path:      adjust = 0      diffs = self.deltatext_split(revision)      self.lines_added[revision]   = 0      self.lines_removed[revision] = 0      lines_added_now = 0      lines_removed_now = 0      for command in diffs:        dmatch = self.d_command.match(command)        amatch = self.a_command.match(command)        if add_lines_remaining > 0:          # Insertion lines from a prior "a" command          text.insert(start_line + adjust, command)          add_lines_remaining = add_lines_remaining - 1          adjust = adjust + 1        elif dmatch:          # "d" - Delete command          start_line = string.atoi(dmatch.group(1))          count      = string.atoi(dmatch.group(2))          begin = start_line + adjust - 1          del text[begin:begin + count]          adjust = adjust - count          lines_removed_now = lines_removed_now + count        elif amatch:          # "a" - Add command          start_line = string.atoi(amatch.group(1))          count      = string.atoi(amatch.group(2))          add_lines_remaining = count          lines_added_now = lines_added_now + count        else:          raise RuntimeError, 'Error parsing diff commands'      self.lines_added[revision]   = self.lines_added[revision]   + lines_added_now      self.lines_removed[revision] = self.lines_removed[revision] + lines_removed_now    return text  def set_head_revision(self, revision):    self.head_revision = revision  def set_principal_branch(self, branch_name):    self.principal_branch = branch_name  def define_tag(self, name, revision):    # Create an associate array that maps from tag name to    # revision number and vice-versa.    self.tag_revision[name] = revision    ### actually, this is a bit bogus... a rev can have multiple names    self.revision_symbolic_name[revision] = name  def set_comment(self, comment):    self.file_description = comment  def set_description(self, description):    self.rcs_file_description = description  # Construct dicts that represent the topology of the RCS tree  # and other arrays that contain info about individual revisions.  #  # The following dicts are created, keyed by revision number:  #   self.revision_date     -- e.g. "96.02.23.00.21.52"  #   self.timestamp         -- seconds since 12:00 AM, Jan 1, 1970 GMT  #   self.revision_author   -- e.g. "tom"  #   self.revision_branches -- descendant branch revisions, separated by spaces,  #                             e.g. "1.21.4.1 1.21.2.6.1"  #   self.prev_revision     -- revision number of previous *ancestor* in RCS tree.  #                             Traversal of this array occurs in the direction  #                             of the primordial (1.1) revision.  #   self.prev_delta        -- revision number of previous revision which forms  #                             the basis for the edit commands in this revision.  #                             This causes the tree to be traversed towards the  #                             trunk when on a branch, and towards the latest trunk  #                             revision when on the trunk.  #   self.next_delta        -- revision number of next "delta".  Inverts prev_delta.  #  # Also creates self.last_revision, keyed by a branch revision number, which  # indicates the latest revision on a given branch,  #   e.g. self.last_revision{"1.2.8"} == 1.2.8.5  def define_revision(self, revision, timestamp, author, state,                      branches, next):    self.tag_revision[revision] = revision    branch = self.last_branch.match(revision).group(1)    self.last_revision[branch] = revision    #self.revision_date[revision] = date    self.timestamp[revision] = timestamp    # Pretty print the date string    ltime = time.localtime(self.timestamp[revision])    formatted_date = time.strftime("%d %b %Y %H:%M", ltime)    self.revision_ctime[revision] = formatted_date    # Save age    self.revision_age[revision] = ((time.time() - self.timestamp[revision])                                   / self.SECONDS_PER_DAY)    # save author    self.revision_author[revision] = author    # ignore the state    # process the branch information    branch_text = ''    for branch in branches:      self.prev_revision[branch] = revision      self.next_delta[revision] = branch      self.prev_delta[branch] = revision      branch_text = branch_text + branch + ''    self.revision_branches[revision] = branch_text    # process the "next revision" information    if next:      self.next_delta[revision] = next      self.prev_delta[next] = revision      is_trunk_revision = self.trunk_rev.match(revision) is not None      if is_trunk_revision:        self.prev_revision[revision] = next      else:        self.prev_revision[next] = revision  # Construct associative arrays containing info about individual revisions.  #  # The following associative arrays are created, keyed by revision number:  #   revision_log        -- log message  #   revision_deltatext  -- Either the complete text of the revision,  #                          in the case of the head revision, or the  #                          encoded delta between this revision and another.  #                          The delta is either with respect to the successor  #                          revision if this revision is on the trunk or  #                          relative to its immediate predecessor if this  #                          revision is on a branch.  def set_revision_info(self, revision, log, text):    self.revision_log[revision] = log    self.revision_deltatext[revision] = text  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, 'r')    except:      raise RuntimeError, ('error: %s appeared to be under CVS control, ' +              'but the RCS file is inaccessible.') % rcs_pathname    rcsparse.Parser().parse(rcsfile, self)    rcsfile.close()    if opt_rev in [None, '', 'HEAD']:      # Explicitly specified topmost revision in tree      revision = self.head_revision

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -