"Fossies" - the Fresh Open Source Software Archive

Member "viewvc-1.1.27/lib/query.py" (6 Jun 2019, 14535 Bytes) of package /linux/misc/viewvc-1.1.27.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "query.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.1.26_vs_1.1.27.

    1 #!/usr/bin/env python
    2 # -*-python-*-
    3 #
    4 # Copyright (C) 1999-2019 The ViewCVS Group. All Rights Reserved.
    5 #
    6 # By using this file, you agree to the terms and conditions set forth in
    7 # the LICENSE.html file which can be found at the top level of the ViewVC
    8 # distribution or at http://viewvc.org/license-1.html.
    9 #
   10 # For more information, visit http://viewvc.org/
   11 #
   12 # -----------------------------------------------------------------------
   13 #
   14 # CGI script to process and display queries to CVSdb
   15 #
   16 # This script is part of the ViewVC package. More information can be
   17 # found at http://viewvc.org
   18 #
   19 # -----------------------------------------------------------------------
   20 
   21 import os
   22 import sys
   23 import string
   24 import time
   25 
   26 import cvsdb
   27 import viewvc
   28 import ezt
   29 import debug
   30 import urllib
   31 import fnmatch
   32 
   33 class FormData:
   34     def __init__(self, form):
   35         self.valid = 0
   36         
   37         self.repository = ""
   38         self.branch = ""
   39         self.directory = ""
   40         self.file = ""
   41         self.who = ""
   42         self.sortby = ""
   43         self.date = ""
   44         self.hours = 0
   45 
   46         self.decode_thyself(form)
   47         
   48     def decode_thyself(self, form):
   49         try:
   50             self.repository = string.strip(form["repository"].value)
   51         except KeyError:
   52             pass
   53         except TypeError:
   54             pass
   55         else:
   56             self.valid = 1
   57         
   58         try:
   59             self.branch = string.strip(form["branch"].value)
   60         except KeyError:
   61             pass
   62         except TypeError:
   63             pass
   64         else:
   65             self.valid = 1
   66             
   67         try:
   68             self.directory = string.strip(form["directory"].value)
   69         except KeyError:
   70             pass
   71         except TypeError:
   72             pass
   73         else:
   74             self.valid = 1
   75             
   76         try:
   77             self.file = string.strip(form["file"].value)
   78         except KeyError:
   79             pass
   80         except TypeError:
   81             pass
   82         else:
   83             self.valid = 1
   84             
   85         try:
   86             self.who = string.strip(form["who"].value)
   87         except KeyError:
   88             pass
   89         except TypeError:
   90             pass
   91         else:
   92             self.valid = 1
   93             
   94         try:
   95             self.sortby = string.strip(form["sortby"].value)
   96         except KeyError:
   97             pass
   98         except TypeError:
   99             pass
  100         
  101         try:
  102             self.date = string.strip(form["date"].value)
  103         except KeyError:
  104             pass
  105         except TypeError:
  106             pass
  107         
  108         try:
  109             self.hours = int(form["hours"].value)
  110         except KeyError:
  111             pass
  112         except TypeError:
  113             pass
  114         except ValueError:
  115             pass
  116         else:
  117             self.valid = 1
  118         
  119 ## returns a tuple-list (mod-str, string)
  120 def listparse_string(str):
  121     return_list = []
  122 
  123     cmd = ""
  124     temp = ""
  125     escaped = 0
  126     state = "eat leading whitespace"
  127 
  128     for c in str:
  129         ## handle escaped charactors
  130         if not escaped and c == "\\":
  131             escaped = 1
  132             continue
  133 
  134         ## strip leading white space
  135         if state == "eat leading whitespace":
  136             if c in string.whitespace:
  137                 continue
  138             else:
  139                 state = "get command or data"
  140 
  141         ## parse to '"' or ","
  142         if state == "get command or data":
  143 
  144             ## just add escaped charactors
  145             if escaped:
  146                 escaped = 0
  147                 temp = temp + c
  148                 continue
  149 
  150             ## the data is in quotes after the command
  151             elif c == "\"":
  152                 cmd = temp
  153                 temp = ""
  154                 state = "get quoted data"
  155                 continue
  156 
  157             ## this tells us there was no quoted data, therefore no
  158             ## command; add the command and start over
  159             elif c == ",":
  160                 ## strip ending whitespace on un-quoted data
  161                 temp = string.rstrip(temp)
  162                 return_list.append( ("", temp) )
  163                 temp = ""
  164                 state = "eat leading whitespace"
  165                 continue
  166 
  167             ## record the data
  168             else:
  169                 temp = temp + c
  170                 continue
  171                 
  172         ## parse until ending '"'
  173         if state == "get quoted data":
  174             
  175             ## just add escaped charactors
  176             if escaped:
  177                 escaped = 0
  178                 temp = temp + c
  179                 continue
  180 
  181             ## look for ending '"'
  182             elif c == "\"":
  183                 return_list.append( (cmd, temp) )
  184                 cmd = ""
  185                 temp = ""
  186                 state = "eat comma after quotes"
  187                 continue
  188 
  189             ## record the data
  190             else:
  191                 temp = temp + c
  192                 continue
  193 
  194         ## parse until ","
  195         if state == "eat comma after quotes":
  196             if c in string.whitespace:
  197                 continue
  198 
  199             elif c == ",":
  200                 state = "eat leading whitespace"
  201                 continue
  202 
  203             else:
  204                 print "format error"
  205                 sys.exit(1)
  206 
  207     if cmd or temp:
  208         return_list.append((cmd, temp))
  209 
  210     return return_list
  211 
  212 def decode_command(cmd):
  213     if cmd == "r":
  214         return "regex"
  215     elif cmd == "l":
  216         return "like"
  217     else:
  218         return "exact"
  219 
  220 def form_to_cvsdb_query(cfg, form_data):
  221     query = cvsdb.CreateCheckinQuery()
  222     query.SetLimit(cfg.cvsdb.row_limit)
  223 
  224     if form_data.repository:
  225         for cmd, str in listparse_string(form_data.repository):
  226             cmd = decode_command(cmd)
  227             query.SetRepository(str, cmd)
  228         
  229     if form_data.branch:
  230         for cmd, str in listparse_string(form_data.branch):
  231             cmd = decode_command(cmd)
  232             query.SetBranch(str, cmd)
  233         
  234     if form_data.directory:
  235         for cmd, str in listparse_string(form_data.directory):
  236             cmd = decode_command(cmd)
  237             query.SetDirectory(str, cmd)
  238 
  239     if form_data.file:
  240         for cmd, str in listparse_string(form_data.file):
  241             cmd = decode_command(cmd)
  242             query.SetFile(str, cmd)
  243 
  244     if form_data.who:
  245         for cmd, str in listparse_string(form_data.who):
  246             cmd = decode_command(cmd)
  247             query.SetAuthor(str, cmd)
  248 
  249     if form_data.sortby == "author":
  250         query.SetSortMethod("author")
  251     elif form_data.sortby == "file":
  252         query.SetSortMethod("file")
  253     else:
  254         query.SetSortMethod("date")
  255 
  256     if form_data.date:
  257         if form_data.date == "hours" and form_data.hours:
  258             query.SetFromDateHoursAgo(form_data.hours)
  259         elif form_data.date == "day":
  260             query.SetFromDateDaysAgo(1)
  261         elif form_data.date == "week":
  262             query.SetFromDateDaysAgo(7)
  263         elif form_data.date == "month":
  264             query.SetFromDateDaysAgo(31)
  265             
  266     return query
  267 
  268 def prev_rev(rev):
  269     '''Returns a string representing the previous revision of the argument.'''
  270     r = string.split(rev, '.')
  271     # decrement final revision component
  272     r[-1] = str(int(r[-1]) - 1)
  273     # prune if we pass the beginning of the branch
  274     if len(r) > 2 and r[-1] == '0':
  275         r = r[:-2]
  276     return string.join(r, '.')
  277 
  278 def is_forbidden(cfg, cvsroot_name, module):
  279     '''Return 1 if MODULE in CVSROOT_NAME is forbidden; return 0 otherwise.'''
  280 
  281     # CVSROOT_NAME might be None here if the data comes from an
  282     # unconfigured root.  This interfaces doesn't care that the root
  283     # isn't configured, but if that's the case, it will consult only
  284     # the base and per-vhost configuration for authorizer and
  285     # authorizer parameters.
  286     if cvsroot_name:
  287         authorizer, params = cfg.get_authorizer_and_params_hack(cvsroot_name)
  288     else:
  289         authorizer = cfg.options.authorizer
  290         params = cfg.get_authorizer_params()
  291         
  292     # If CVSROOT_NAME isn't configured to use an authorizer, nothing
  293     # is forbidden.  If it's configured to use something other than
  294     # the 'forbidden' authorizer, complain.  Otherwise, check for
  295     # forbiddenness per the PARAMS as expected.
  296     if not authorizer:
  297         return 0
  298     if authorizer != 'forbidden':    
  299         raise Exception("The 'forbidden' authorizer is the only one supported "
  300                         "by this interface.  The '%s' root is configured to "
  301                         "use a different one." % (cvsroot_name))
  302     forbidden = params.get('forbidden', '')
  303     forbidden = map(string.strip, filter(None, string.split(forbidden, ',')))
  304     default = 0
  305     for pat in forbidden:
  306         if pat[0] == '!':
  307             default = 1
  308             if fnmatch.fnmatchcase(module, pat[1:]):
  309                 return 0
  310         elif fnmatch.fnmatchcase(module, pat):
  311             return 1
  312     return default
  313     
  314 def build_commit(server, cfg, desc, files, cvsroots, viewvc_link):
  315     ob = _item(num_files=len(files), files=[])
  316     ob.log = desc and string.replace(server.escape(desc), '\n', '<br />') or ''
  317 
  318     for commit in files:
  319         repository = commit.GetRepository()
  320         directory = commit.GetDirectory()
  321         cvsroot_name = cvsroots.get(repository)
  322 
  323         ## find the module name (if any)
  324         try:
  325             module = filter(None, string.split(directory, '/'))[0]
  326         except IndexError:
  327             module = None
  328 
  329         ## skip commits we aren't supposed to show
  330         if module and ((module == 'CVSROOT' and cfg.options.hide_cvsroot) \
  331                        or is_forbidden(cfg, cvsroot_name, module)):
  332             continue
  333 
  334         ctime = commit.GetTime()
  335         if not ctime:
  336             ctime = "&nbsp;"
  337         else:
  338           if (cfg.options.use_localtime):
  339             ctime = time.strftime("%y/%m/%d %H:%M %Z", time.localtime(ctime))
  340           else:
  341             ctime = time.strftime("%y/%m/%d %H:%M", time.gmtime(ctime)) \
  342                     + ' UTC'
  343         
  344         ## make the file link
  345         try:
  346             file = (directory and directory + "/") + commit.GetFile()
  347         except:
  348             raise Exception, str([directory, commit.GetFile()])
  349 
  350         ## If we couldn't find the cvsroot path configured in the
  351         ## viewvc.conf file, or we don't have a VIEWVC_LINK, then
  352         ## don't make the link.
  353         if cvsroot_name and viewvc_link:
  354             flink = '[%s] <a href="%s/%s?root=%s">%s</a>' % (
  355                     cvsroot_name, viewvc_link, urllib.quote(file),
  356                     cvsroot_name, file)
  357             if commit.GetType() == commit.CHANGE:
  358                 dlink = '%s/%s?root=%s&amp;view=diff&amp;r1=%s&amp;r2=%s' % (
  359                     viewvc_link, urllib.quote(file), cvsroot_name,
  360                     prev_rev(commit.GetRevision()), commit.GetRevision())
  361             else:
  362                 dlink = None
  363         else:
  364             flink = '[%s] %s' % (repository, file)
  365             dlink = None
  366 
  367         ob.files.append(_item(date=ctime,
  368                               author=commit.GetAuthor(),
  369                               link=flink,
  370                               rev=commit.GetRevision(),
  371                               branch=commit.GetBranch(),
  372                               plus=int(commit.GetPlusCount()),
  373                               minus=int(commit.GetMinusCount()),
  374                               type=commit.GetTypeString(),
  375                               difflink=dlink,
  376                               ))
  377 
  378     return ob
  379 
  380 def run_query(server, cfg, form_data, viewvc_link):
  381     query = form_to_cvsdb_query(cfg, form_data)
  382     db = cvsdb.ConnectDatabaseReadOnly(cfg)
  383     db.RunQuery(query)
  384 
  385     commit_list = query.GetCommitList()
  386     if not commit_list:
  387         return [ ], 0
  388 
  389     row_limit_reached = query.GetLimitReached()
  390 
  391     commits = [ ]
  392     files = [ ]
  393 
  394     cvsroots = {}
  395     viewvc.expand_root_parents(cfg)
  396     rootitems = cfg.general.svn_roots.items() + cfg.general.cvs_roots.items()
  397     for key, value in rootitems:
  398         cvsroots[cvsdb.CleanRepository(value)] = key
  399 
  400     current_desc = commit_list[0].GetDescription()
  401     for commit in commit_list:
  402         desc = commit.GetDescription()
  403         if current_desc == desc:
  404             files.append(commit)
  405             continue
  406 
  407         commits.append(build_commit(server, cfg, current_desc, files,
  408                                     cvsroots, viewvc_link))
  409 
  410         files = [ commit ]
  411         current_desc = desc
  412 
  413     ## add the last file group to the commit list
  414     commits.append(build_commit(server, cfg, current_desc, files,
  415                                 cvsroots, viewvc_link))
  416 
  417     # Strip out commits that don't have any files attached to them.  The
  418     # files probably aren't present because they've been blocked via
  419     # forbiddenness.
  420     def _only_with_files(commit):
  421         return len(commit.files) > 0
  422     commits = filter(_only_with_files, commits)
  423   
  424     return commits, row_limit_reached
  425 
  426 def main(server, cfg, viewvc_link):
  427   try:
  428 
  429     form = server.FieldStorage()
  430     form_data = FormData(form)
  431 
  432     if form_data.valid:
  433         commits, row_limit_reached = run_query(server, cfg,
  434                                                form_data, viewvc_link)
  435         query = None
  436     else:
  437         commits = [ ]
  438         row_limit_reached = 0
  439         query = 'skipped'
  440 
  441     docroot = cfg.options.docroot
  442     if docroot is None and viewvc_link:
  443         docroot = viewvc_link + '/' + viewvc.docroot_magic_path
  444         
  445     data = ezt.TemplateData({
  446       'cfg' : cfg,
  447       'address' : cfg.general.address,
  448       'vsn' : viewvc.__version__,
  449       'repository' : server.escape(form_data.repository),
  450       'branch' : server.escape(form_data.branch),
  451       'directory' : server.escape(form_data.directory),
  452       'file' : server.escape(form_data.file),
  453       'who' : server.escape(form_data.who),
  454       'docroot' : docroot,
  455       'sortby' : form_data.sortby,
  456       'date' : form_data.date,
  457       'query' : query,
  458       'row_limit_reached' : ezt.boolean(row_limit_reached),
  459       'commits' : commits,
  460       'num_commits' : len(commits),
  461       'rss_href' : None,
  462       'hours' : form_data.hours and form_data.hours or 2,
  463       })
  464 
  465     # generate the page
  466     server.header()
  467     template = viewvc.get_view_template(cfg, "query")
  468     template.generate(server.file(), data)
  469 
  470   except SystemExit, e:
  471     pass
  472   except:
  473     exc_info = debug.GetExceptionData()
  474     server.header(status=exc_info['status'])
  475     debug.PrintException(server, exc_info) 
  476 
  477 class _item:
  478   def __init__(self, **kw):
  479     vars(self).update(kw)