1
0
mirror of https://github.com/vitalif/viewvc-4intranet synced 2019-04-16 04:14:59 +03:00

Compare commits

..

88 Commits

Author SHA1 Message Date
cmpilato
9f0a7f316d Retroactively "peg" the svn:externals property on these tags which
pulls in the 'templates-contrib' area.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/tags/1.0.11@2451 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-08 16:51:21 +00:00
cmpilato
537a0b0f48 Tag the 1.0.11 final release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/tags/1.0.11@2357 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-29 15:52:08 +00:00
cmpilato
d69336d89a Bump copyright year in LICENSE.html.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2354 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-29 15:38:36 +00:00
cmpilato
1ea70fe311 Copyright bumps only.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2351 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-29 15:35:40 +00:00
cmpilato
3b8bb7e39f Update CHANGES file for today's release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2348 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-29 15:24:41 +00:00
cmpilato
a929f630e6 Merge from trunk r2344.
There were too many ways to do something as simple as HTML escaping in
the ViewVC codebase.  Simplify, conjoin, remove, etc.

* lib/sapi.py
  (escape): New function.  *The* preferred HTML-escaping mechanism.
  (Server.escape): New common Server object escape mechanism (which
    uses the aforementioned escape(), of course).
  (CgiServer.escape, WsgiServer.escape, AspServer.escape,
   ModPythonServer.escape): Lose as unnecessary.

* lib/viewvc.py
  (): Replace all uses of cgi.escape() with sapi.escape().
  (prepare_hidden_values): Escape hidden form variable names and values. 
  
* lib/query.py
  (main): Use server.escape() instead of cgi.escape().

* lib/blame.py
  (HTMLBlameSource.__getitem__): Use sapi.escape() instead of
    cgi.escape().

* lib/idiff.py
  (_mdiff_split, _differ_split): Use sapi.escape() instead of
    cgi.escape().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2346 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-11 20:19:31 +00:00
cmpilato
a0133ce584 Oops! Fix version typos.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2343 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-10 22:01:43 +00:00
cmpilato
fa94d647f3 Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2340 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-10 21:50:25 +00:00
cmpilato
c0d0e0b097 Revert change accidentally committed in r2337.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2338 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-10 21:49:13 +00:00
cmpilato
383ad7aac2 Schedule the 1.0.10 release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2337 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-10 21:48:46 +00:00
cmpilato
8a446830cc Merge some copyright bumps.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2336 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-10 21:46:49 +00:00
cmpilato
06e8eec7ca Merge from trunk r2325 and r2326:
* lib/viewvc.py
     (query_backup): Switch to using the sapi interface for output file
       I/O instead of using 'print'.
     (view_queryform): Escape user-provided input before passing it
       directly off to the templates.  Can you say "XSS attack vector"?

Also:

* CHANGES
  Note the security fix.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2329 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-02-10 19:44:30 +00:00
cmpilato
0225c7dc13 Merge from trunk r2265 whose log message read:
Fix issue #427 - regex filtering broken by bogus validator function.
   
   * lib/viewvc.py
     (_validate_regex): Try compiling the incoming regex, returning True
       on success and None otherwise.  (Simply 'pass'ing caused all
       regexs to fail validation.)
   
   Patch by: Robert Fleming <flemingr{_AT_}tigris.org>

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2328 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-02-10 19:41:15 +00:00
cmpilato
b08bea6a1d Merge r2303 from trunk (or, the deletion half of the viewvc.org directory
move, at least).

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2305 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-04 21:52:32 +00:00
cmpilato
ac34cc35ce Partially merge from trunk r1875 in order to fix some bugs viewing
resources in remote Subversion repositories that have spaces (or other
URI-unsafe characters) in their names.

* lib/vclib/svn_ra/__init__.py
  (): Import urllib.
  (SubversionRepository._geturl): New.
  (temp_checkout, SubversionRepository.openfile,
   SubversionRepository.itemlog, SubversionRepository.annotate,
   SubversionRepository._get_dirents): Use new _geturl() function to
    construct URLs.

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2243 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-17 15:14:04 +00:00
cmpilato
1567b2ee0c Begin a new release cycle, the sequel.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2237 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-11 13:10:15 +00:00
cmpilato
3ce548a72b Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2233 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-11 13:01:53 +00:00
cmpilato
c771aa971c Let's roll 1.0.9 today.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2231 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-11 12:57:48 +00:00
cmpilato
0adab05e44 Merge from trunk r2225, whose log message read:
* lib/viewvc.py
     (view_error): Settle for simple HTML-escaping of error messages
       rather than full htmlification.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2227 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-14 20:46:22 +00:00
cmpilato
f45fc973b7 Merge from trunk r2217, whose log message read thusly:
Try to avoid content spoofing errors.  Prior to this change, a URL
   like this:
   
      http://localhost/viewvc/subversion/?view=foo%22)%20was%20passed\
      %20as%20a%20parameter.20%20Visit%20http://www.baddy.com%20to%20\
      figure%20out%20why%20(%22foo
   
   Would result in an error page that read as follows:
   
      An illegal value ("foo") was passed as a parameter. Visit
      http://www.baddy.com to figure out why ("foo") was passed as a
      parameter.
   
   (where "http://www.baddy.com" was linkified, and could potentially
   point to a malicious website.)
   
   With this change, we will avoid printing unknown parameter names, and
   will show the parameter name rather its value when a bogus value is
   detected.  Yes, there's admittedly some information loss here that
   might be useful to the well-meaning but fat-fingered user, but the
   security aspect is more important.
   
   * lib/viewvc.py
     (_validate_param): Don't print illegal parameter names, and show the
       (legal) parameter name rather than its value when that value is
       illegal.

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2219 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-06 19:06:51 +00:00
cmpilato
14b35861c2 * lib/viewvc.py
(Request.run_viewvc): Oops!  Remove a mapping of view=rev to view=revision
    picked up during the backport of trunk changes committed in r2214.
    ViewVC 1.0.x still uses view=rev!


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2216 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-06 16:52:56 +00:00
cmpilato
6f0e5334ff ### NOTE: Part of this was reverted in r2216. ###
Merge from trunk r2211, r2212, and r2213, whose combined log message
might have read as follows:

   * lib/viewvc.py
     (_validate_view, _validate_mimetype): New validation functions.
     (_re_validate_mimetype): Removed as unused.
     (_legal_params): Tweak the validation routines for 'view' and
       'content-type' to point to _validate_view() and _validate_mimetype(),
       respectively.
     (_validate_param): Now check for non-zero result from validation
       functions as the "valid" indicator, rather than requiring each of
       them to raise an exception in troubled times.
     (Request.run_viewvc): Use an intermediate variable to simplify some
       logic around input parameter validation.  Move the logic that maps
       view=rev to view=revision into the parameter validation loop.
       Lose now-unnecessary validation of 'content-type' parameter -- the
       normal parameter validation stuff should catch problems there.

Also:

* CHANGES
  Record the relevant bits of these changes.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2214 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-06 16:45:40 +00:00
cmpilato
5129453aa8 Merge from trunk r2201, which contains some minor documentation
markup tweaks.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2203 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-15 20:12:57 +00:00
cmpilato
59b1e1d817 Add placeholder for 1.0.9's CHANGES.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2155 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 17:28:36 +00:00
cmpilato
fde7ddfa78 * lib/viewvc.py
(__version__): Bump to 1.0.9-dev.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2154 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 17:27:48 +00:00
cmpilato
e55a53826a Let's pretend we'll release 1.0.8 today, shall we?
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2149 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 17:12:06 +00:00
cmpilato
2e42e8210a Update copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2145 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 17:06:06 +00:00
cmpilato
07019eaf2b Backport from trunk r2137: Fix issue #409, an exception thrown when
sorting by revision in a remote Subversion directory view.

* lib/vclib/svn_ra/__init__.py
  (get_logs): Store the entry's revision as a string, for consistency
    with other vclib modules.

Also:

* CHANGES
  Record this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2138 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 14:57:37 +00:00
cmpilato
ee17367b8b Backport to the 1.0.x branch trunk's r2134, whose log message read thusly:
Fix an exception in log views of Subversion repositories with 0
   revisions.
   
   * lib/vclib/svn/__init__.py
     (_get_history): Add easy-out for repositories with 0 revisions.
   
   Reported by: Wojciech Wróblewski <wojtek{_AT_}elmi.pl>

Also:

* CHANGES
  Note this fix.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2136 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-04 15:00:22 +00:00
cmpilato
63e89c6517 Merge from trunk r2128-2129.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2131 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-04-20 17:42:06 +00:00
cmpilato
89c5af7d9d Update copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2109 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-18 16:56:29 +00:00
cmpilato
743fcdd6ae Merge from trunk r2103, whose log message read thusly:
Fix namespace problem with raised Exception.
   
   * lib/viewvc.py
     (view_revision): raise *debug.*ViewVCException.
   
   Patch by: Kamesh Jayachandran <kamesh@collab.net>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2105 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-18 12:52:59 +00:00
cmpilato
9451f373e8 Merge from trunk r2097, whose log message read thusly:
Finish issue #396 - Malformed accept-language header crashes viewvc
   
   * lib/accept.py
     (AcceptLanguageParseError): Was AcceptParseError.
     (_parse): Track renamed Exception.
   
   * lib/viewvc.py
     (Request.__init__): Catch and handle raised AcceptLanguageParseError.
   
   Patch by: Rune Halvorsen <runefh{_AT_}gmail.com>,
             me

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2100 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-26 16:16:40 +00:00
cmpilato
c0ce6b9dbe Merge from trunk r2090, whose log message read thusly:
ViewVC doesn't "do" directory entry sorting by revision for CVS, so
   don't imply that it does in the UI.
   
   * lib/viewvc.py
     (view_directory): Don't provide sortby_rev_href to the template.
   
   * templates/directory.ezt
     Only offer sort links when those links are provided by ViewVC.
   
   * templates/dir_new.ezt
     Only offer sort links when those links are provided by ViewVC.  Use
     date-based sorting if rev-based sorting isn't available.

Also:

* CHANGES
  Note this change.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2093 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-20 15:31:27 +00:00
cmpilato
e498d9fdbe Record a bunch of old merges (as determined from log message harvesting)
in Subversion's mergeinfo tracking system.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2061 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-05 17:23:38 +00:00
cmpilato
1bb0b7ee38 Merge r2048 from trunk.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2050 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-13 20:09:01 +00:00
cmpilato
7bafa7b77e Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2020 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-14 22:06:35 +00:00
cmpilato
1bc2914f4b Finalize release date for 1.0.7. Need to get this regression fix available.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2018 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-14 21:47:06 +00:00
cmpilato
06f6ba27d0 Backport from trunk r2016, whose log message reads thusly:
Fix issue #373: Regression: "as text" view no longer transmits
   Content-type: text/plain header.
   
   * lib/viewvc.py
     (Request.run_viewvc): Add 'text/plain' to the list of content types
       allowed to be specified via the CGI query params.
     (view_checkout): Revert the change from r1978 which caused this to
       ignore the content-type query param; we'll go back to paying
       attention to that, and simply trust that Request.run_viewvc() has
       sanitized it.

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2017 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-02 15:57:59 +00:00
cmpilato
6cf12dd9b3 Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2006 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-09-16 19:05:57 +00:00
cmpilato
a234ea1105 Set release date.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@2004 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-09-16 17:47:58 +00:00
cmpilato
fd3db29ade Add missing module import statement.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1995 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-08-20 19:05:44 +00:00
cmpilato
2e684b109f Fix the import cycle problem with the mod_python stuffs (issue #369).
* bin/mod_python/viewvc.py,
* bin/mod_python/query.py
  Use the 'imp' module and its offerings to load the right 'viewvc'
  and 'query' modules (from the ViewVC lib directory, not from the
  mod_python directory).

* CHANGES
  Note this change.

Patch by: Eygene Ryabinkin <konvpalto {at} tigris.org>,
          me


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1993 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-08-20 17:44:29 +00:00
cmpilato
39c10d903b * lib/viewvc.py,
* lib/vclib/ccvs/rcsparse/common.py,
* lib/vclib/ccvs/rcsparse/default.py,
* lib/vclib/ccvs/rcsparse/texttools.py,
* lib/blame.py,
* lib/popen.py
  Purge tab characters from code save for in comments where the tabs
  are to be interpreted literally.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1985 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-08-13 17:48:17 +00:00
cmpilato
25a30fb45f Note recent change.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1984 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-08-13 17:46:29 +00:00
cmpilato
2f1008737a Fix some indentation-based syntax exceptions caused by stray tab
characters.

* lib/blame.py
  (make_html): Do import of vclib.ccvs.blame here, the only place it's
    needed.

* lib/vclib/ccvs/blame.py
  (CVSParser.parse_cvs_file): Replace some stray tab characters with
    spaces.

Found by: Matt Benson <mbenson {at} apache.org>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1983 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-08-13 17:33:57 +00:00
cmpilato
e800659377 Update the URL reference in light of r1978 and r1979.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1981 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-07-28 19:26:42 +00:00
cmpilato
f75096b6c6 Backport from trunk r1978:
Finish issue #354: Lose ability to set Content-type via CGI params.
   
   For security purposes (because spoofing Content-type headers can have
   undesirable side effects), no longer recognize 'content-type' CGI
   parameters whose values aren't one of the magic MIME types ViewVC uses
   for its own (non-MIME-type-setting) purposes.
   
   * lib/viewvc.py
     (Request.run_viewvc): Ignore content-type CGI parameters whose
       values aren't one of the magic ViewVC MIME types used to indicate
       that folks want the markup view.
     (view_checkout): No longer consult the query parameters for a MIME type.

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1979 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-07-28 18:58:46 +00:00
cmpilato
8f28ea0798 Backport from trunk r1896, and note the fix in CHANGES.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1897 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-22 17:51:25 +00:00
cmpilato
2a6c68b575 Backport r1888 from trunk:
Fix issue #348 by making the 'co' parser more resilient to multiple
   "special" lines of output.
   
   Previously, output like the following would choke because the code was
   able to deal with the first "special" line (the warning about unknown
   phrases), but then wasn't able to handle the second "special" line
   (about no side branches).
   
      $ co -pTAG_NAME /cvs/repos/some-file,v
      /cvs/repos/some-file,v  -->  standard output
      co: /cvs/repos/some-file,v: warning: Unknown phrases like `commitid ...;' are present.
      co: /cvs/repos/some-file,v: no side branches present for 1.1
   
   If either of these lines had been the only special ones, stuff worked
   fine.  But in concert, it all fell apart.
   
   * lib/vclib/ccvs/bincvs.py
     (_parse_co_header): Use a line-reading loop instead of trying to
       expect certain output on specific lines.
   
   Verified by: Ross Becker <ross {at} trapezenetworks.com>

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1889 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-14 17:11:30 +00:00
cmpilato
b1becd4c33 Add CHANGES item for recent bugfix.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1885 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-12 18:56:17 +00:00
cmpilato
e3514e6a3d Merge from trunk r1882 and r1883, fixing issue #346 on the 1.0.x line
(though perhaps not entirely, if use_rcsparse is set).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1884 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-12 18:52:13 +00:00
cmpilato
2337c9be23 Ahh ... begin the cycle anew ...
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1826 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-28 15:39:54 +00:00
cmpilato
d803878191 Update to use new name of the license file.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1824 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-28 15:19:35 +00:00
cmpilato
269f2087b4 Update copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1823 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-28 15:18:12 +00:00
cmpilato
220af43401 * lib/viewvc.py
(_get_svn_location): Doh!  Return the parts we calculated.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1822 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-27 01:49:57 +00:00
cmpilato
de7782a53a Avoid errors caused by invoking the Subversion command-line client by
a userid that a) has no ~/.subversion area and b) can't create one
(due to lack of permissions).

* lib/vclib/svn/__init__.py
  (BlameSource.__init__): Use a read-only temporary directory for
    Subversion's runtime configuration directory.
  (BlameSource.__del__): New (deletes the temporary directory).

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1821 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-27 01:06:58 +00:00
cmpilato
d177c057b0 Security fixes for remote Subversion repositories.
* lib/vclib/svn_ra/__init__.py
  (LogCollector.add_log): Record copyfrom info.

* lib/viewvc.py
  (view_log): Implement a cache of path-forbiddenness check results,
    and combine a pair of similarly conditioned blocks.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1820 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-25 21:48:27 +00:00
cmpilato
65a68936e7 Type fix.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1819 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-25 21:24:16 +00:00
cmpilato
1c613a947f Make 'forbiddenre' significantly more powerful by allowing folks to
distinguish between file and directory paths.

* viewvc.conf.dist
  (forbiddenre): Update documentation to note that directory paths
    will contains trailing slashes, and provide a related example.

* lib/config.py
  (is_forbidden): If using the 'forbiddenre' option, test directory
    paths only after appending a trailing forward slash.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1817 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-25 20:47:24 +00:00
cmpilato
da5b54e95d Fix the plus/minus line change counting in query results to ignore
values from unreadable files.

* lib/viewvc.py
  (build_commit): Calculate total plus/minus line change count for a
    given commit item (based on the sums of those values in
    non-forbidden file commits associated with it).
  (view_query): Update plus/minus line change count totals only
    *after* trimming unauthorized files

* docs/template-authoring-guide.html
  (query_results): Note new commits.plus and commits.minus items; fix
    description of the plus_count and minus_count items.

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1815 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-25 19:21:08 +00:00
cmpilato
4e27b4f06b Update copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1814 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-22 15:11:30 +00:00
cmpilato
88c95433f2 Security fix: block access to forbidden paths via the p1 and p2 diff
view parameters.

* lib/viewvc.py
  (_get_svn_location): New, abstracted -- and tweaked to do
    forbiddenness checks -- from _get_diff_path_parts().
  (_get_diff_path_parts): Now use _get_svn_location().

* CHANGES
  Record these changes.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1811 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-22 13:01:25 +00:00
cmpilato
4db1ef6d19 * templates/error.ezt
Bring up-to-date with trunk's version, only showing tracebacks when no
  human-friendly message is provided in the error, and restoring the
  workaround for older IE versions.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1810 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-22 13:01:11 +00:00
cmpilato
2af50a5f27 Security fixes: strip forbidden changed paths in the Subversion
revision view, and don't traverse log history into forbidden locations.

* lib/viewvc.py
  (view_revision): Filter out changes whose paths are forbidden, and
    make copies from unreadable sources look like regular adds (without
    history).

* lib/viewvc.py
  (view_log): When traversing log history on Subversion objects, if
    the object was copied from a forbidden location, make it appear to
    be a regular add (without history) and stop traversing history.

* CHANGES
  Record these changes.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1809 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-22 02:01:09 +00:00
cmpilato
f4f3459c8e Merge from trunk r1806, whose log message read thusly:
Honor hide_cvsroot more like the CVSROOT is forbidden than simply obscured.

   * lib/viewvc.py
     (is_cvsroot_path): New helper function.
     (view_directory, generate_tarball, build_commit): Use is_cvsroot_path().

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1807 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-21 21:49:34 +00:00
cmpilato
ec081f5d8e Backport (sorta) the "forbiddenre" support from trunk.
* lib/config.py
  (Config._force_multi_value): Add 'forbiddenre' to the list.
  (Config.is_forbidden): Now accept 'root_and_path' instead of just a
    module name.  Also, accept 'pathkind'.  Finally, support the new
    'forbiddenre' as a superceding configuration decision over
    'forbidden' (the support for which has been tweaked to deal with
    the new function input).

* lib/viewvc.py
  (Request.run_viewvc, view_directory, generate_tarball, build_commit): 
    Update calls to cfg.is_forbidden(), now calling for files and
    directories (of all depths).

* lib/query.py
  (build_commit): Update calls to cfg.is_forbidden(), now calling for
    files and directories (of all depths).

* viewvc.conf.dist
  Document the new 'forbiddenre' configuration parameter.

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1802 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-21 20:05:57 +00:00
cmpilato
e0eb1f6331 Note recent changes.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1801 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-21 19:24:47 +00:00
cmpilato
94ba398034 On the 1.0.x branch:
Fix buglets (and minor security leak) related to the files attached
to commit items in the query view and query.cgi script results.  These
views still returned commit objects with all attached metadata even
when all the files associated with that commit were blocked due to
configured forbiddenness.  The generic query.ezt template masked this
bug (because it was keyed on the files more so than on the commit
items), but query_results.ezt revealed it.  Also, we were doing change
limiting at the wrong time, so you'd get results that showed 2 files
but read "Only first 5 files shown...".

* lib/viewvc.py
  (build_commit): Trade the 'limited_files' parameter for a
    'max_files' parameter, and change the way file counting and
    filtering happens so we get accurate file counts and the maximum
    number of allowed files when limiting changes.  Now returns None
    if the would-be-returned commit item has no associated allowed
    files, and defers building of the commit item until necessary.
  (view_query): Don't do file limiting here, defer it to
    build_commit().  Also, watch for (and ignore) None returns from
    build_commit(), too.

* lib/query.py
  (run_query): Strip out commits which have no associated files.
    Since commits in the query view are file-driven, the only way we
    could have a commit that has no files is if the files were
    stripped by forbiddenness checks.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1800 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-21 19:08:34 +00:00
cmpilato
7e250b8f24 Record recent changes.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1782 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-12 15:41:47 +00:00
cmpilato
64eb245377 Entity-escape RSS descriptions, and wrap them in <pre> tags.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1781 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-12 15:40:26 +00:00
cmpilato
d3092409b2 Merge r1779 from trunk, whose log message read thusly:
Finish issue #238 by not making HTML out of short log messages in RSS
   format mode.
   
   * lib/viewvc.py
     (format_log): Now accept optional 'htmlize' parameter.
     (build_commit): Accept 'format' parameter, and use it to determine
       what value to pass for the 'htmlize' parameter of an updated call
       to format_log().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1780 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-12 15:37:30 +00:00
cmpilato
652dc5b571 Backport trunk's r1765, in which we recommend adding ViewVC to robots.txt.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1766 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-07 02:21:46 +00:00
cmpilato
d04cdeca8c Backport from trunk r1706:
Prevent Exception when generating tarballs for remote Subversion
   repositories.
   
   * lib/vclib/svn_ra/__init__.py
     (SelfCleanFP.read): Add default parameter value for 'len' argument.
   
   Patch by: Ceri Storey <cez@necrofish.org.uk>

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1707 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-09-14 13:05:57 +00:00
cmpilato
480eb1a1f7 Merge from trunk to the 1.0.x release branch r1695, whose log message
read thusly:

   Finish issue #306 - RSS content type should be more specific.
   
   * lib/viewvc.py
     (view_query): Use "application/rss+xml" instead "text/xml" for 
       the RSS feed output stream's content type.  Suggested by 
       Phil Ringnalda <philringnalda@tigris.org>.

Also:

* CHANGES
  Note the change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1696 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-07-09 18:20:20 +00:00
cmpilato
e477c03157 * viewvc-install
(TREE_LIST): Install the contributed templates, too.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1645 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-05-03 18:03:36 +00:00
cmpilato
b4d5c1d9d6 * CHANGES
Note the fix from r1628.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1629 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-26 19:39:10 +00:00
cmpilato
8e1eb9be9a * bin/loginfo-handler
(Cvs1Dot12ArgParse): Handle the imported sources case, too.  Thanks to
    Mark Keisler <mark@mitsein.net> for pointing this out in IRC today.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1628 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-26 19:38:35 +00:00
cmpilato
cb1bf2a45b Add an externals definition which pulls in contributed template sets
for ViewVC 1.0.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1622 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-25 19:43:27 +00:00
cmpilato
60ae172120 Backport from trunk r1605, whose log message read thusly:
Finish issue #287 by ensuring that in a clash of root names, the
   first-listed, cvs_roots-found, CVS repository wins.
   
   * lib/query.py
     (run_query): Ensure that in a rootname clash situation, the CVS
       repository wins.
   
   * lib/viewvc.py
     (list_roots): Ensure that in a rootname clash situation, the CVS
       repository wins.

Also:

* CHANGES
  Note this fix.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1606 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-13 09:16:46 +00:00
cmpilato
f029071eae Merge from trunk r1596-1599, which is bunch of license-related juggling.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1601 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 18:39:52 +00:00
cmpilato
fa95ce8b08 Delete the svn:mergeinfo property.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1600 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 18:33:06 +00:00
cmpilato
3a415a308e Update make-release script with latest from trunk.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1596 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 15:45:21 +00:00
cmpilato
627e506a76 Copy notes directory from trunk.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1595 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 15:44:58 +00:00
cmpilato
267ea727a0 Update license-1.html file.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1594 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 15:43:07 +00:00
cmpilato
965e1cfaff Update copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1593 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 15:38:34 +00:00
cmpilato
3ffe822b0c Do some documentation and website reorg and purging.
* docs
  New.

* www
* viewcvs.sourceforge.net
  Removed.

* viewvc.org/url-reference.html
* viewvc.org/upgrading.html
* viewvc.org/template-authoring-guide.html
  Move these...

* docs/url-reference.html
* docs/upgrading-howto.html
* docs/template-authoring-guide.html
  ...to here.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1587 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 07:20:02 +00:00
cmpilato
e6de1376bc Begin a new release cycle.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.0.x@1583 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 06:49:34 +00:00
54 changed files with 1008 additions and 1572 deletions

52
CHANGES
View File

@@ -1,3 +1,55 @@
Version 1.0.11 (released 29-Mar-2010)
* security fix: escape user-provided search_re input to avoid XSS attack
Version 1.0.10 (released 10-Mar-2010)
* security fix: escape user-provided query form input to avoid XSS attack
* fix errors viewing remote Subversion paths with URI-unsafe characters
* fix regexp input validation (issue #426, #427, #440)
Version 1.0.9 (released 11-Aug-2009)
* security fix: validate the 'view' parameter to avoid XSS attack
* security fix: avoid printing illegal parameter names and values
Version 1.0.8 (released 05-May-2009)
* fix directory view sorting UI
* tolerate malformed Accept-Language headers (issue #396)
* fix directory log views in revision-less Subversion repositories
* fix exception in rev-sorted remote Subversion directory views (issue #409)
Version 1.0.7 (released 14-Oct-2008)
* fix regression in the 'as text' download view (issue #373)
Version 1.0.6 (released 16-Sep-2008)
* security fix: ignore arbitrary user-provided MIME types (issue #354)
* fix bug in regexp search filter when used with sticky tag (issue #346)
* fix bug in handling of certain 'co' output (issue #348)
* fix regexp search filter template bug
* fix annotate code syntax error
* fix mod_python import cycle (issue #369)
Version 1.0.5 (released 28-Feb-2008)
* security fix: omit commits of all-forbidden files from query results
* security fix: disallow direct URL navigation to hidden CVSROOT folder
* security fix: strip forbidden paths from revision view
* security fix: don't traverse log history thru forbidden locations
* security fix: honor forbiddenness via diff view path parameters
* new 'forbiddenre' regexp-based path authorization feature
* fix root name conflict resolution inconsistencies (issue #287)
* fix an oversight in the CVS 1.12.9 loginfo-handler support
* fix RSS feed content type to be more specific (issue #306)
* fix entity escaping problems in RSS feed data (issue #238)
* fix bug in tarball generation for remote Subversion repositories
* fix query interface file-count-limiting logic
* fix query results plus/minus count to ignore forbidden files
* fix blame error caused by 'svn' unable to create runtime config dir
Version 1.0.4 (released 10-Apr-2007)
* fix some markup bugs in query views (issue #266)

10
INSTALL
View File

@@ -260,6 +260,16 @@ or if you've got Mod_Python installed you can use METHOD D:
http://<server_name>/viewvc/~checkout~/<module_name>
http://<server_name>/viewvc/<module_name>.tar.gz?view=tar
5) Optional: Protect your ViewVC instance from server-whacking webcrawlers.
As ViewVC is a web-based application which each page containing various
links to other pages and views, you can expect your server's performance
to suffer if a webcrawler finds your ViewVC instance and begins
traversing those links. We highly recommend that you add your ViewVC
location to a site-wide robots.txt file. Visit the Wikipedia page
for Robots.txt (http://en.wikipedia.org/wiki/Robots.txt) for more
information.
UPGRADING VIEWVC
-----------------

View File

@@ -1,63 +1,21 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>ViewVC: License v1</title>
<link rel="stylesheet" type="text/css" href="./styles.css"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<div id="title">
<a href="http://www.viewvc.org/"><img
src="./images/title.jpg" alt="ViewVC: Repository Browsing"/></a>
</div>
<div id="menu">
<p><a href="./index.html">Home</a> |
<a href="http://viewvc.tigris.org/">Project Page</a> |
<a href="./download.html">Download</a> |
<a href="./upgrading.html">Upgrading</a> |
<a href="./contributing.html">Contributing</a> |
<a href="./license-1.html">License</a> |
<a href="./contact.html">Contact</a> |
<a href="./who.html">About</a>
</p>
</div>
<table id="pagetable">
<tr>
<td id="pagecolumn1">
<h4>On this page:</h4>
<ul id="bookmarks">
<li><a href="#sec-license">License</a></li>
</ul>
<hr/>
<address><a href="mailto:&#117&#115&#101&#114&#115&#64&#118&#105&#101&#119&#118&#99&#46&#116&#105&#103&#114&#105&#115&#46&#111&#114&#103">ViewVC Users Group</a></address>
</td>
<td id="pagecolumn2">
<div class="section">
<h2 id="sec-license">License</h2>
<p>The following text constitutes the license agreement for the <a
href="./index.html">ViewVC</a> software (formerly known as
ViewCVS). It is an agreement between <a
href="./who.html#sec-viewcvs-group">The ViewCVS Group</a> and the
users of ViewVC.</p>
href="http://www.viewvc.org/">ViewVC</a> software (formerly known
as ViewCVS). It is an agreement between <a
href="http://www.viewvc.org/who.html#sec-viewcvs-group">The ViewCVS
Group</a> and the users of ViewVC.</p>
<p style="font-size: 80%;"><em>Note: the copyright years were updated
on May 12, 2001 and September 5, 2002. No other changes were made
to the license.</em></p>
<blockquote>
<hr/>
<p><strong>Copyright &copy; 1999-2002 The ViewCVS Group. All rights
<p><strong>Copyright &copy; 1999-2010 The ViewCVS Group. All rights
reserved.</strong></p>
<p>By using ViewVC, you agree to the terms and conditions set forth
@@ -90,10 +48,19 @@
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.</p>
</div>
</blockquote>
<hr />
<p>The following changes have occured to this license over time:</p>
<ul>
<li>May 12, 2001 &mdash; copyright years updated</li>
<li>September 5, 2002 &mdash; copyright years updated</li>
<li>March 17, 2006 &mdash; software renamed from "ViewCVS"</li>
<li>April 10, 2007 &mdash; copyright years updated</li>
<li>February 22, 2008 &mdash; copyright years updated</li>
<li>March 29, 2010 &mdash; copyright years updated</li>
</ul>
</td>
</tr>
</table>
</body>
</html>

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -77,6 +77,8 @@ def Cvs1Dot12ArgParse(args):
if args[1] == '- New directory':
return None, None
elif args[1] == '- Imported sources':
return None, None
else:
directory = args.pop(0)
files = []

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -42,9 +42,23 @@ if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
import sapi
import viewvc
import query
reload(query) # need reload because initial import loads this stub file
import imp
# Import real ViewVC module
fp, pathname, description = imp.find_module('viewvc', [LIBRARY_DIR])
try:
viewvc = imp.load_module('viewvc', fp, pathname, description)
finally:
if fp:
fp.close()
# Import real ViewVC Query modules
fp, pathname, description = imp.find_module('query', [LIBRARY_DIR])
try:
query = imp.load_module('query', fp, pathname, description)
finally:
if fp:
fp.close()
cfg = viewvc.load_config(CONF_PATHNAME)

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -42,9 +42,15 @@ if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
import sapi
import viewvc
reload(viewvc) # need reload because initial import loads this stub file
import imp
# Import real ViewVC module
fp, pathname, description = imp.find_module('viewvc', [LIBRARY_DIR])
try:
viewvc = imp.load_module('viewvc', fp, pathname, description)
finally:
if fp:
fp.close()
def index(req):
server = sapi.ModPythonServer(req)

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 2004 James Henstridge
#
# By using this file, you agree to the terms and conditions set forth in

View File

@@ -1586,10 +1586,20 @@ td {
<td>Boolean</td>
<td>True if files list was cut short due to <tt>limit_changes</tt>.</td>
</tr>
<tr class="varlevel2">
<td class="varname">commits.minus</td>
<td>String</td>
<td>Total number of lines removed from files in this commit.</td>
</tr>
<tr class="varlevel2">
<td class="varname">commits.num_files</td>
<td>String</td>
<td>Number of files in the <var>commits.files</var> list.</td>
<td>Total number of files in the <var>commits.files</var> list.</td>
</tr>
<tr class="varlevel2">
<td class="varname">commits.plus</td>
<td>String</td>
<td>Number of lines added to files in this commit.</td>
</tr>
<tr class="varlevel2">
<td class="varname">commits.rev</td>
@@ -1630,12 +1640,14 @@ td {
<tr class="varlevel1">
<td class="varname">minus_count</td>
<td>String</td>
<td>Total number of lines removed in the commit (over all files).</td>
<td>Total number of lines removed from all files across all returned
commits.</td>
</tr>
<tr class="varlevel1">
<td class="varname">plus_count</td>
<td>String</td>
<td>Total number of lines added in the commit (over all files).</td>
<td>Total number of lines added to all files across all returned
commits.</td>
</tr>
<tr class="varlevel1">
<td class="varname">queryform_href</td>

View File

@@ -89,7 +89,7 @@ th.caption {
<li><a href="#compat-tarball">'<code>tarball=1</code>' Parameter &rArr; '<code>view=tar</code>'</a></li>
<li><a href="#compat-graph">'<code>graph=1</code>' Parameter &rArr; '<code>view=graph</code>'</a></li>
<li><a href="#compat-makeimage">'<code>graph=1&makeimage=1</code>' Parameters &rArr; '<code>view=graphimg</code>'</a></li>
<li><a href="#compat-content_type">'<code>content_type=text/vnd.viewcvs-markup</code>' and '<code>content_type=text/x-cvsweb-markup</code>' Parameters&rArr; '<code>view=markup</code>'
<li><a href="#compat-content_type">'<code>content-type=text/vnd.viewcvs-markup</code>' and '<code>content-type=text/x-cvsweb-markup</code>' Parameters&rArr; '<code>view=markup</code>'
<li><a href="#compat-attic">'<code>Attic/FILE</code>' Paths &rArr; '<code>FILE</code>'</a></li>
</ul>
</div>
@@ -284,11 +284,6 @@ th.caption {
<td>depends</td>
<td><a href="#view-param"><code>view</code> parameter</a>, not needed if the <code>default_file_view</code> configuration variable is set to <code>co</code>, since that makes the checkout view the default view for file paths. Also not needed if the <code>/*checkout*</code> magic prefix or the <code>revision</code> parameter is present.
</tr>
<tr>
<td><code>content-type=<var>TYPE</var></code></td>
<td>optional</td>
<td>MIME type to send with checked out file, default is a guess based on file extension</td>
</tr>
<tr>
<td><code>revision=<var>REVISION</var></code></td>
<td>optional</td>
@@ -872,7 +867,7 @@ th.caption {
<td>file query string</td>
</tr>
<tr>
<td><code>file_match=FILE_MATCH</code></td>
<td><code>file_match=<var>FILE_MATCH</var></code></td>
<td>optional</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type of file match</td>
</tr>
@@ -882,37 +877,37 @@ th.caption {
<td>author query string</td>
</tr>
<tr>
<td><code>who_match=WHO_MATCH</code></td>
<td><code>who_match=<var>WHO_MATCH</var></code></td>
<td>optional</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type of author match</td>
</tr>
<tr>
<td><code>querysort=SORT</code></td>
<td><code>querysort=<var>SORT</var></code></td>
<td>optional</td>
<td>"date" "author" or "file" determining order of query results</td>
</tr>
<tr>
<td><code>date=DATE</code></td>
<td><code>date=<var>DATE</var></code></td>
<td>optional</td>
<td>"hours" "day" "week" "month" "all" or "explicit" to filter query results by date</td>
</tr>
<tr>
<td><code>hours=HOURS</code></td>
<td><code>hours=<var>HOURS</var></code></td>
<td>optional</td>
<td>number of hours back to include results from when <code><var>DATE</var></code> is "hours"</td>
</tr>
<tr>
<td><code>mindate=MINDATE</code></td>
<td><code>mindate=<var>MINDATE</var></code></td>
<td>optional</td>
<td>earliest date to include results from when <code><var>DATE</var></code> is "explicit"</td>
</tr>
<tr>
<td><code>maxdate=MAXDATE</code></td>
<td><code>maxdate=<var>MAXDATE</var></code></td>
<td>optional</td>
<td>latest date to include results from when <code><var>DATE</var></code> is "explicit"</td>
</tr>
<tr>
<td><code>limit_changes=LIMIT_CHANGES</code></td>
<td><code>limit_changes=<var>LIMIT_CHANGES</var></code></td>
<td>optional</td>
<td>maximum number of files to list per commit in query results. Default is value of <code>limit_changes</code> configuration option</td>
</tr>
@@ -970,7 +965,7 @@ th.caption {
<td>branch query string</td>
</tr>
<tr>
<td><code>branch_match=BRANCH_MATCH</code></td>
<td><code>branch_match=<var>BRANCH_MATCH</var></code></td>
<td>optional</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type of branch match</td>
</tr>
@@ -985,7 +980,7 @@ th.caption {
<td>file query string</td>
</tr>
<tr>
<td><code>file_match=FILE_MATCH</code></td>
<td><code>file_match=<var>FILE_MATCH</var></code></td>
<td>optional</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type of file match</td>
</tr>
@@ -995,47 +990,47 @@ th.caption {
<td>author query string</td>
</tr>
<tr>
<td><code>who_match=WHO_MATCH</code></td>
<td><code>who_match=<var>WHO_MATCH</var></code></td>
<td>optional</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type of author match</td>
</tr>
<tr>
<td><code>querysort=SORT</code></td>
<td><code>querysort=<var>SORT</var></code></td>
<td>optional</td>
<td>"date" "author" or "file" determining order of query results</td>
</tr>
<tr>
<td><code>date=DATE</code></td>
<td><code>date=<var>DATE</var></code></td>
<td>optional</td>
<td>"hours" "day" "week" "month" "all" or "explicit" to filter query results by date</td>
</tr>
<tr>
<td><code>hours=HOURS</code></td>
<td><code>hours=<var>HOURS</var></code></td>
<td>optional</td>
<td>number of hours back to include results from when <code><var>DATE</var></code> is "hours"</td>
</tr>
<tr>
<td><code>mindate=MINDATE</code></td>
<td><code>mindate=<var>MINDATE</var></code></td>
<td>optional</td>
<td>earliest date to include results from when <code><var>DATE</var></code> is "explicit"</td>
</tr>
<tr>
<td><code>maxdate=MAXDATE</code></td>
<td><code>maxdate=<var>MAXDATE</var></code></td>
<td>optional</td>
<td>latest date to include results from when <code><var>DATE</var></code> is "explicit"</td>
</tr>
<tr>
<td><code>format=FORMAT</code></td>
<td><code>format=<var>FORMAT</var></code></td>
<td>optional</td>
<td>"rss" or "backout" values to generate an rss feed or list of commands to back out changes instead showing a normal query result page</td>
</tr>
<tr>
<td><code>limit=LIMIT</code></td>
<td><code>limit=<var>LIMIT</var></code></td>
<td>optional</td>
<td>maximum number of file-revisions to process during a query. Default is value of <code>row_limit</code> configuration option</td>
</tr>
<tr>
<td><code>limit_changes=LIMIT_CHANGES</code></td>
<td><code>limit_changes=<var>LIMIT_CHANGES</var></code></td>
<td>optional</td>
<td>maximum number of files to list per commit in query results. Default is value of <code>limit_changes</code> configuration option</td>
</tr>
@@ -1087,7 +1082,7 @@ th.caption {
<td><a href="#revision-param"><code>revision</code> parameter</a></td>
</tr>
<tr>
<td><code>limit_changes=LIMIT_CHANGES</code></td>
<td><code>limit_changes=<var>LIMIT_CHANGES</var></code></td>
<td>optional</td>
<td>maximum number of files to list per commit. Default is value of <code>limit_changes</code> configuration option</td>
</tr>
@@ -1233,8 +1228,8 @@ th.caption {
<h3 id="compat-makeimage">'<code>graph=1&amp;makeimage=1</code>' Parameters &rArr; '<code>view=graphimg</code>'</h3>
<p>A <code>graph=1&amp;makeimage=1</code> parameter is treated like a <code>view=graph</code> parameter. There is currently no redirect when it is encountered, but there could be one in the future.</p>
<h3 id="compat-content_type">'<code>content_type=text/vnd.viewcvs-markup</code>' and '<code>content_type=text/x-cvsweb-markup</code>' Parameters&rArr; '<code>view=markup</code>'</h3>
<p><code>content_type=text/vnd.viewcvs-markup</code> and <code>content_type=text/x-cvsweb-markup</code> parameters are treated like a <code>view=markup</code> parameter. There is currently no redirect when it is encountered, but there could be one in the future.</p>
<h3 id="compat-content_type">'<code>content-type=text/vnd.viewcvs-markup</code>' and '<code>content-type=text/x-cvsweb-markup</code>' Parameters&rArr; '<code>view=markup</code>'; other values ignored</h3>
<p><code>content-type=text/vnd.viewcvs-markup</code> and <code>content-type=text/x-cvsweb-markup</code> parameters are treated like a <code>view=markup</code> parameter. There is currently no redirect when it is encountered, but there could be one in the future. Other values of the <code>content-type</code> parameter, which were used to dictate the MIME type of files displayed in the checkout/download view prior to ViewVC 1.0.6, are ignored.</p>
<h3 id="compat-attic">'<code>Attic/FILE</code>' Paths &rArr; '<code>FILE</code>'</h3>
<p>When ViewVC encounters an invalid repository path whose last or second-to-last component is named <code>Attic</code>, and stripping the component yields a valid path, it will redirect to a URL with that path.</p>

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2009 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -39,7 +39,7 @@ def _parse(hdr, result):
while pos < len(hdr):
name = _re_token.match(hdr, pos)
if not name:
raise AcceptParseError()
raise AcceptLanguageParseError()
a = result.item_class(string.lower(name.group(1)))
pos = name.end()
while 1:
@@ -210,7 +210,7 @@ class _LanguageSelector:
def append(self, item):
self.requested.append(item)
class AcceptParseError(Exception):
class AcceptLanguageParseError(Exception):
pass
def _test():

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2010 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
@@ -31,10 +31,8 @@ import os
import re
import time
import math
import cgi
import vclib
import vclib.ccvs.blame
import sapi
re_includes = re.compile('\\#(\\s*)include(\\s*)"(.*?)"')
@@ -82,7 +80,7 @@ class HTMLBlameSource:
diff_url = None
if item.prev_rev:
diff_url = '%sr1=%s&amp;r2=%s' % (self.diff_url, item.prev_rev, item.rev)
thisline = link_includes(cgi.escape(item.text), self.repos,
thisline = link_includes(sapi.escape(item.text), self.repos,
self.path_parts, self.include_url)
return _item(text=thisline, line_number=item.line_number,
rev=item.rev, prev_rev=item.prev_rev,
@@ -100,6 +98,7 @@ class _item:
def make_html(root, rcs_path):
import vclib.ccvs.blame
bs = vclib.ccvs.blame.BlameSource(os.path.join(root, rcs_path))
count = bs.num_lines
@@ -161,9 +160,9 @@ def make_html(root, rcs_path):
# Close the highlighted section
#if (defined $mark_cmd and mark_cmd != 'begin'):
# chop($output)
# output = output + endOfRow + (startOfRow % row_color)
# inMark = 0
# chop($output)
# output = output + endOfRow + (startOfRow % row_color)
# inMark = 0
print output
print endOfRow + '</table>'

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -19,6 +19,8 @@ import os
import string
import ConfigParser
import fnmatch
import re
import vclib
#########################################################################
@@ -39,7 +41,7 @@ import fnmatch
class Config:
_sections = ('general', 'options', 'cvsdb', 'templates')
_force_multi_value = ('cvs_roots', 'forbidden',
_force_multi_value = ('cvs_roots', 'forbidden', 'forbiddenre',
'svn_roots', 'languages', 'kv_files',
'root_parents')
@@ -151,8 +153,9 @@ class Config:
self.general.svn_path = ''
self.general.mime_types_file = ''
self.general.address = '<a href="mailto:user@insert.your.domain.here">No admin address has been configured</a>'
self.general.forbidden = ()
self.general.kv_files = [ ]
self.general.forbidden = []
self.general.forbiddenre = []
self.general.kv_files = []
self.general.languages = ['en-us']
self.templates.directory = None
@@ -222,19 +225,65 @@ class Config:
self.options.http_expiration_time = 600
self.options.generate_etags = 1
def is_forbidden(self, module):
if not module:
def is_forbidden(self, root, path_parts, pathtype):
# If we don't have a root and path to check, get outta here.
if not (root and path_parts):
return 0
default = 0
for pat in self.general.forbidden:
if pat[0] == '!':
default = 1
if fnmatch.fnmatchcase(module, pat[1:]):
return 0
elif fnmatch.fnmatchcase(module, pat):
return 1
return default
# Give precedence to the new 'forbiddenre' stuff first.
if self.general.forbiddenre:
# Join the root and path-parts together into one path-like thing.
root_and_path = string.join([root] + path_parts, "/")
if pathtype == vclib.DIR:
root_and_path = root_and_path + '/'
# If we still have a list of strings, replace those suckers with
# lists of (compiled_regex, negation_flag)
if type(self.general.forbiddenre[0]) == type(""):
for i in range(len(self.general.forbiddenre)):
pat = self.general.forbiddenre[i]
if pat[0] == '!':
self.general.forbiddenre[i] = (re.compile(pat[1:]), 1)
else:
self.general.forbiddenre[i] = (re.compile(pat), 0)
# Do the forbiddenness test.
default = 0
for (pat, negated) in self.general.forbiddenre:
match = pat.search(root_and_path)
if negated:
default = 1
if match:
return 0
elif match:
return 1
return default
# If no 'forbiddenre' is in use, we check 'forbidden', which only
# looks at the top-most directory.
elif self.general.forbidden:
# A root and a single non-directory path component? That's not
# a module.
if len(path_parts) == 1 and pathtype != vclib.DIR:
return 0
# Do the forbiddenness test.
module = path_parts[0]
default = 0
for pat in self.general.forbidden:
if pat[0] == '!':
default = 1
if fnmatch.fnmatchcase(module, pat[1:]):
return 0
elif fnmatch.fnmatchcase(module, pat):
return 1
return default
# No forbiddenness configuration? Just allow it.
else:
return 0
def _parse_roots(config_name, config_value):
roots = { }

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -38,13 +38,17 @@ if SHOW_TIMES:
else:
_times[which] = t
def dump():
for name, value in _times.items():
print '%s: %.6f<br />' % (name, value)
def t_dump(out):
out.write('<div>')
names = _times.keys()
names.sort()
for name in names:
out.write('%s: %.6fs<br/>\n' % (name, _times[name]))
out.write('</div>')
else:
t_start = t_end = dump = lambda *args: None
t_start = t_end = t_dump = lambda *args: None
class ViewVCException:

View File

@@ -200,7 +200,7 @@ Directives
equivalent to "[CALLBACK QUAL_NAME]"
"""
#
# Copyright (C) 2001-2005 Greg Stein. All Rights Reserved.
# Copyright (C) 2001-2007 Greg Stein. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -20,7 +20,7 @@ import difflib
import sys
import re
import ezt
import cgi
import sapi
def sidebyside(fromlines, tolines, context):
"""Generate side by side diff"""
@@ -49,18 +49,18 @@ def _mdiff_split(flag, (line_number, text)):
while True:
m = _re_mdiff.search(text, pos)
if not m:
segments.append(_item(text=cgi.escape(text[pos:]), type=None))
segments.append(_item(text=sapi.escape(text[pos:]), type=None))
break
if m.start() > pos:
segments.append(_item(text=cgi.escape(text[pos:m.start()]), type=None))
segments.append(_item(text=sapi.escape(text[pos:m.start()]), type=None))
if m.group(1) == "+":
segments.append(_item(text=cgi.escape(m.group(2)), type="add"))
segments.append(_item(text=sapi.escape(m.group(2)), type="add"))
elif m.group(1) == "-":
segments.append(_item(text=cgi.escape(m.group(2)), type="remove"))
segments.append(_item(text=sapi.escape(m.group(2)), type="remove"))
elif m.group(1) == "^":
segments.append(_item(text=cgi.escape(m.group(2)), type="change"))
segments.append(_item(text=sapi.escape(m.group(2)), type="change"))
pos = m.end()
@@ -166,12 +166,12 @@ def _differ_split(row, guide):
for m in _re_differ.finditer(guide, pos):
if m.start() > pos:
segments.append(_item(text=cgi.escape(line[pos:m.start()]), type=None))
segments.append(_item(text=cgi.escape(line[m.start():m.end()]),
segments.append(_item(text=sapi.escape(line[pos:m.start()]), type=None))
segments.append(_item(text=sapi.escape(line[m.start():m.end()]),
type="change"))
pos = m.end()
segments.append(_item(text=cgi.escape(line[pos:]), type=None))
segments.append(_item(text=sapi.escape(line[pos:]), type=None))
return _item(gap=ezt.boolean(gap), type=type, segments=segments,
left_number=left_number, right_number=right_number)

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -364,11 +364,11 @@ class _pipe:
else:
if self.thread:
self.thread.join()
if type(self.child_pid) == type([]):
if type(self.child_pid) == type([]):
for pid in self.child_pid:
exit = os.waitpid(pid, 0)[1]
return exit
else:
else:
return os.waitpid(self.child_pid, 0)[1]
return None

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -25,6 +25,7 @@ import time
import cvsdb
import viewvc
import vclib
import ezt
import debug
import urllib
@@ -282,10 +283,8 @@ def build_commit(server, cfg, desc, files, cvsroots, viewvc_link):
ob.log = '&nbsp;'
for commit in files:
dir_parts = filter(None, string.split(commit.GetDirectory(), '/'))
if dir_parts \
and ((dir_parts[0] == 'CVSROOT' and cfg.options.hide_cvsroot) \
or cfg.is_forbidden(dir_parts[0])):
parts = filter(None, string.split(commit.GetDirectory(), '/'))
if parts and cfg.options.hide_cvsroot and parts[0] == 'CVSROOT':
continue
ctime = commit.GetTime()
@@ -304,6 +303,11 @@ def build_commit(server, cfg, desc, files, cvsroots, viewvc_link):
file = (directory and directory + "/") + commit.GetFile()
cvsroot_name = cvsroots.get(repository)
## skip forbidden files
if cfg.is_forbidden(cvsroot_name,
filter(None, string.split(file, "/")), vclib.FILE):
continue
## if we couldn't find the cvsroot path configured in the
## viewvc.conf file, then don't make the link
if cvsroot_name:
@@ -345,7 +349,7 @@ def run_query(server, cfg, form_data, viewvc_link):
files = [ ]
cvsroots = {}
rootitems = cfg.general.cvs_roots.items() + cfg.general.svn_roots.items()
rootitems = cfg.general.svn_roots.items() + cfg.general.cvs_roots.items()
for key, value in rootitems:
cvsroots[cvsdb.CleanRepository(value)] = key
@@ -366,6 +370,13 @@ def run_query(server, cfg, form_data, viewvc_link):
commits.append(build_commit(server, cfg, current_desc, files,
cvsroots, viewvc_link))
# Strip out commits that don't have any files attached to them. The
# files probably aren't present because they've been blocked via
# forbiddenness.
def _only_with_files(commit):
return len(commit.files) > 0
commits = filter(_only_with_files, commits)
return commits
def main(server, cfg, viewvc_link):
@@ -387,12 +398,11 @@ def main(server, cfg, viewvc_link):
'cfg' : cfg,
'address' : cfg.general.address,
'vsn' : viewvc.__version__,
'repository' : server.escape(form_data.repository, 1),
'branch' : server.escape(form_data.branch, 1),
'directory' : server.escape(form_data.directory, 1),
'file' : server.escape(form_data.file, 1),
'who' : server.escape(form_data.who, 1),
'repository' : server.escape(form_data.repository),
'branch' : server.escape(form_data.branch),
'directory' : server.escape(form_data.directory),
'file' : server.escape(form_data.file),
'who' : server.escape(form_data.who),
'docroot' : cfg.options.docroot is None \
and viewvc_link + '/' + viewvc.docroot_magic_path \
or cfg.options.docroot,

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -20,6 +20,7 @@ import string
import os
import sys
import re
import cgi
# global server object. It will be either a CgiServer or a proxy to
@@ -27,6 +28,18 @@ import re
server = None
# Simple HTML string escaping. Note that we always escape the
# double-quote character -- ViewVC shouldn't ever need to preserve
# that character as-is, and sometimes needs to embed escaped values
# into HTML attributes.
def escape(s):
s = string.replace(s, '&', '&amp;')
s = string.replace(s, '>', '&gt;')
s = string.replace(s, '<', '&lt;')
s = string.replace(s, '"', "&quot;")
return s
class Server:
def __init__(self):
self.pageGlobals = {}
@@ -34,6 +47,9 @@ class Server:
def self(self):
return self
def escape(self, s):
return escape(s)
def close(self):
pass
@@ -129,9 +145,6 @@ class CgiServer(Server):
global server
server = self
global cgi
import cgi
def addheader(self, name, value):
self.headers.append((name, value))
@@ -161,9 +174,6 @@ class CgiServer(Server):
print 'This document is located <a href="%s">here</a>.' % url
sys.exit(0)
def escape(self, s, quote = None):
return cgi.escape(s, quote)
def getenv(self, name, value=None):
ret = os.environ.get(name, value)
if self.iis and name == 'PATH_INFO' and ret:
@@ -221,9 +231,6 @@ class AspServer(ThreadedServer):
self.response.Redirect(url)
sys.exit()
def escape(self, s, quote = None):
return self.server.HTMLEncode(str(s))
def getenv(self, name, value = None):
ret = self.request.ServerVariables(name)()
if not type(ret) is types.UnicodeType:
@@ -285,9 +292,6 @@ class ModPythonServer(ThreadedServer):
self.request = request
self.headerSent = 0
global cgi
import cgi
def addheader(self, name, value):
self.request.headers_out.add(name, value)
@@ -311,9 +315,6 @@ class ModPythonServer(ThreadedServer):
% (url, url))
sys.exit()
def escape(self, s, quote = None):
return cgi.escape(s, quote)
def getenv(self, name, value = None):
try:
return self.request.subprocess_env[name]

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -534,31 +534,25 @@ def _parse_co_header(fp):
raise COMalformedOutput, "Unable to find filename in co output stream"
filename = match.group(1)
# look for a revision in the second line.
line = fp.readline()
if not line:
raise COMalformedOutput, "Missing second line from co output stream"
match = _re_co_revision.match(line)
if match:
return filename, match.group(1)
elif _re_co_missing_rev.match(line) or _re_co_side_branches.match(line):
raise COMissingRevision, "Got missing revision error from co output stream"
elif _re_co_warning.match(line):
pass
else:
raise COMalformedOutput, "Unable to find revision in co output stream"
# look through subsequent lines for a revision. we might encounter
# some ignorable or problematic lines along the way.
while 1:
line = fp.readline()
if not line:
break
# look for a revision.
match = _re_co_revision.match(line)
if match:
return filename, match.group(1)
elif _re_co_missing_rev.match(line) or _re_co_side_branches.match(line):
raise COMissingRevision, "Got missing revision error from co output stream"
elif _re_co_warning.match(line):
pass
else:
break
# if we get here, the second line wasn't a revision, but it was a
# warning we can ignore. look for a revision in the third line.
line = fp.readline()
if not line:
raise COMalformedOutput, "Missing third line from co output stream"
match = _re_co_revision.match(line)
if match:
return filename, match.group(1)
raise COMalformedOutput, "Unable to find revision in co output stream"
# if your rlog doesn't use 77 '=' characters, then this must change
LOG_END_MARKER = '=' * 77 + '\n'
ENTRY_END_MARKER = '-' * 28 + '\n'

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2008 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
@@ -346,7 +346,7 @@ class CVSParser(rcsparse.Sink):
is_trunk_revision = self.trunk_rev.match(revision) is not None
if is_trunk_revision:
diffs = self.deltatext_split(last_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
@@ -379,7 +379,7 @@ class CVSParser(rcsparse.Sink):
# the trunk. They specify deltas that transform a revision
# into a later revision.
adjust = 0
diffs = self.deltatext_split(revision)
diffs = self.deltatext_split(revision)
for command in diffs:
if skip > 0:
skip = skip - 1

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -78,7 +78,7 @@ class RCSStopParser(Exception):
#
class _Parser:
stream_class = None # subclasses need to define this
stream_class = None # subclasses need to define this
def parse_rcs_admin(self):
while 1:
@@ -196,7 +196,7 @@ class _Parser:
if token == ';':
break
author = author + token + ' '
author = author[:-1] # toss the trailing space
author = author[:-1] # toss the trailing space
# Parse state
self.ts.match('state')
@@ -206,7 +206,7 @@ class _Parser:
if token == ';':
break
state = state + token + ' '
state = state[:-1] # toss the trailing space
state = state[:-1] # toss the trailing space
# Parse branches
self.ts.match('branches')

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -26,7 +26,7 @@ class _TokenStream:
# note: we use a multiple of a standard block size
CHUNK_SIZE = 192 * 512 # about 100k
# CHUNK_SIZE = 5 # for debugging, make the function grind...
# CHUNK_SIZE = 5 # for debugging, make the function grind...
def __init__(self, file):
self.rcsfile = file
@@ -51,7 +51,7 @@ class _TokenStream:
buf = self.rcsfile.read(self.CHUNK_SIZE)
if buf == '':
# signal EOF by returning None as the token
del self.buf # so we fail if get() is called again
del self.buf # so we fail if get() is called again
return None
idx = 0

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -25,7 +25,7 @@ _tt = TextTools
_idchar_list = map(chr, range(33, 127)) + map(chr, range(160, 256))
_idchar_list.remove('$')
_idchar_list.remove(',')
#_idchar_list.remove('.') leave as part of 'num' symbol
#_idchar_list.remove('.') # leave as part of 'num' symbol
_idchar_list.remove(':')
_idchar_list.remove(';')
_idchar_list.remove('@')
@@ -41,10 +41,10 @@ _T_STRING_START = 40
_T_STRING_SPAN = 60
_T_STRING_END = 70
_E_COMPLETE = 100 # ended on a complete token
_E_TOKEN = 110 # ended mid-token
_E_STRING_SPAN = 130 # ended within a string
_E_STRING_END = 140 # ended with string-end ('@') (could be mid-@@)
_E_COMPLETE = 100 # ended on a complete token
_E_TOKEN = 110 # ended mid-token
_E_STRING_SPAN = 130 # ended within a string
_E_STRING_END = 140 # ended with string-end ('@') (could be mid-@@)
_SUCCESS = +100
@@ -65,7 +65,7 @@ class _mxTokenStream:
# note: we use a multiple of a standard block size
CHUNK_SIZE = 192 * 512 # about 100k
# CHUNK_SIZE = 5 # for debugging, make the function grind...
# CHUNK_SIZE = 5 # for debugging, make the function grind...
def __init__(self, file):
self.rcsfile = file

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2009 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -15,9 +15,11 @@
import vclib
import os
import os.path
import stat
import string
import cStringIO
import signal
import shutil
import time
import tempfile
import popen
@@ -237,6 +239,9 @@ class NodeHistory:
def _get_history(svnrepos, full_name, rev, options={}):
if svnrepos.youngest == 0:
return {}
fsroot = svnrepos._getroot(rev)
show_all_logs = options.get('svn_show_all_dir_logs', 0)
if not show_all_logs:
@@ -498,13 +503,36 @@ class BlameSource:
rootpath = '/' + rootpath
if os.sep != '/':
rootpath = string.replace(rootpath, os.sep, '/')
# Make a read-only temporary directory for Subversion to use as
# its runtime config dir. (Read-only because that will prevent
# Subversion from fleshing out all the default runtime config
# contents.)
self.config_dir = self._mkdtemp()
os.chmod(self.config_dir, stat.S_IRUSR | stat.S_IXUSR)
url = 'file://' + string.join([rootpath, fs_path], "/")
fp = popen.popen(svn_client_path,
('blame', "-r%d" % int(rev), "--non-interactive",
("blame",
"-r%d" % int(rev),
"--non-interactive",
"--config-dir", self.config_dir,
"%s@%d" % (url, int(rev))),
'rb', 1)
self.fp = fp
def _mkdtemp(self):
### FIXME: When we require Python 2.3, this can go away.
for i in range(10):
dir = tempfile.mktemp()
try:
os.mkdir(dir, 0700)
return dir
except OSError, e:
if e.errno == errno.EEXIST:
continue # try again
raise
raise IOError, (errno.EEXIST, "No usable temporary directory name found")
def __getitem__(self, idx):
if idx == self.idx:
@@ -529,6 +557,13 @@ class BlameSource:
self.last = item
self.idx = idx
return item
def __del__(self):
try:
if self.config_dir:
shutil.rmtree(self.config_dir)
except:
pass
class BlameSequencingError(Exception):

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2009 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -20,6 +20,7 @@ import re
import tempfile
import popen2
import time
import urllib
from vclib.svn import Revision, ChangedPath, _datestr_to_date, _compare_paths, _cleanup_path
from svn import core, delta, client, wc, ra
@@ -100,8 +101,12 @@ def created_rev(svnrepos, full_name, rev):
kind = ra.svn_ra_check_path(svnrepos.ra_session, full_name, rev,
svnrepos.pool)
if kind == core.svn_node_dir:
props = ra.svn_ra_get_dir(svnrepos.ra_session, full_name,
rev, svnrepos.pool)
retval = ra.svn_ra_get_dir(svnrepos.ra_session, full_name,
rev, svnrepos.pool)
if type(retval) == type([]) and len(retval) == 3:
props = retval[2]
else: # compat with older (broken) bindings
props = retval
return int(props[core.SVN_PROP_ENTRY_COMMITTED_REV])
return core.SVN_INVALID_REVNUM
@@ -176,12 +181,14 @@ class LogCollector:
# Changed paths have leading slashes
changed_paths = paths.keys()
changed_paths.sort(lambda a, b: _compare_paths(a, b))
this_path = None
copyfrom_path = copyfrom_rev = this_path = None
if self.path in changed_paths:
this_path = self.path
change = paths[self.path]
if change.copyfrom_path:
this_path = change.copyfrom_path
copyfrom_path = change.copyfrom_path[1:]
copyfrom_rev = change.copyfrom_rev
for changed_path in changed_paths:
if changed_path != self.path:
# If a parent of our path was copied, our "next previous"
@@ -194,7 +201,7 @@ class LogCollector:
if self.show_all_logs or this_path:
date = _datestr_to_date(date, pool)
entry = Revision(revision, date, author, message, None,
self.path[1:], None, None)
self.path[1:], copyfrom_path, copyfrom_rev)
self.logs.append(entry)
if this_path:
self.path = this_path
@@ -214,7 +221,7 @@ def get_logs(svnrepos, full_name, rev, files):
rev, author, date, log, changes = \
_get_rev_details(svnrepos, entry.created_rev, subpool)
rev_info_cache[entry.created_rev] = rev, author, date, log
file.rev = rev
file.rev = str(rev)
file.author = author
file.date = _datestr_to_date(date, subpool)
file.log = log
@@ -228,7 +235,7 @@ def temp_checkout(svnrepos, path, rev, pool):
"""Check out file revision to temporary file"""
temp = tempfile.mktemp()
stream = core.svn_stream_from_aprfile(temp, pool)
url = svnrepos.rootpath + (path and '/' + path)
url = svnrepos._geturl(path)
client.svn_client_cat(core.Stream(stream), url, _rev2optrev(rev),
svnrepos.ctx, pool)
core.svn_stream_close(stream)
@@ -240,7 +247,7 @@ class SelfCleanFP:
self._path = path
self._eof = 0
def read(self, len):
def read(self, len=None):
if len:
chunk = self._fp.read(len)
else:
@@ -317,10 +324,10 @@ class SubversionRepository(vclib.Repository):
raise vclib.ItemNotFound(path_parts)
def openfile(self, path_parts, rev):
path = self._getpath(path_parts)
rev = self._getrev(rev)
url = self.rootpath
if len(path_parts):
url = self.rootpath + '/' + self._getpath(path_parts)
url = self._geturl(path)
tmp_file = tempfile.mktemp()
stream = core.svn_stream_from_aprfile(tmp_file, self.pool)
### rev here should be the last history revision of the URL
@@ -347,18 +354,15 @@ class SubversionRepository(vclib.Repository):
get_logs(self, self._getpath(path_parts), self._getrev(rev), entries)
def itemlog(self, path_parts, rev, options):
full_name = self._getpath(path_parts)
path = self._getpath(path_parts)
rev = self._getrev(rev)
url = self._geturl(path)
# It's okay if we're told to not show all logs on a file -- all
# the revisions should match correctly anyway.
lc = LogCollector(full_name, options.get('svn_show_all_dir_logs', 0))
dir_url = self.rootpath
if full_name:
dir_url = dir_url + '/' + full_name
lc = LogCollector(path, options.get('svn_show_all_dir_logs', 0))
cross_copies = options.get('svn_cross_copies', 0)
client.svn_client_log([dir_url], _rev2optrev(rev), _rev2optrev(1),
client.svn_client_log([url], _rev2optrev(rev), _rev2optrev(1),
1, not cross_copies, lc.add_log,
self.ctx, self.pool)
revs = lc.logs
@@ -373,7 +377,7 @@ class SubversionRepository(vclib.Repository):
def annotate(self, path_parts, rev):
path = self._getpath(path_parts)
rev = self._getrev(rev)
url = self.rootpath + (path and '/' + path)
url = self._geturl(path)
blame_data = []
@@ -423,13 +427,17 @@ class SubversionRepository(vclib.Repository):
raise vclib.InvalidRevision(rev)
return rev
def _geturl(self, path=None):
if not path:
return self.rootpath
return self.rootpath + '/' + urllib.quote(path, "/*~")
def _get_dirents(self, path, rev):
dir_url = self._geturl(path)
if path:
key = str(rev) + '/' + path
dir_url = self.rootpath + '/' + path
else:
key = str(rev)
dir_url = self.rootpath
dirents = self._dirent_cache.get(key)
if dirents:
return dirents

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -14,7 +14,7 @@
#
# -----------------------------------------------------------------------
__version__ = '1.0.4'
__version__ = '1.0.11'
# this comes from our library; measure the startup time
import debug
@@ -25,7 +25,6 @@ debug.t_start('imports')
import sys
import os
import sapi
import cgi
import string
import urllib
import mimetypes
@@ -112,7 +111,10 @@ class Request:
# process the Accept-Language: header
hal = server.getenv('HTTP_ACCEPT_LANGUAGE','')
self.lang_selector = accept.language(hal)
try:
self.lang_selector = accept.language(hal)
except accept.AcceptLanguageParseError:
self.lang_selector = accept.language('en')
self.language = self.lang_selector.select_from(cfg.general.languages)
# load the key/value files, given the selected language
@@ -147,6 +149,9 @@ class Request:
# Process the query params
for name, values in self.server.params().items():
# we only care about the first value
value = values[0]
# patch up old queries that use 'cvsroot' to look like they used 'root'
if name == 'cvsroot':
name = 'root'
@@ -158,12 +163,12 @@ class Request:
needs_redirect = 1
# validate the parameter
_validate_param(name, values[0])
_validate_param(name, value)
# if we're here, then the parameter is okay
self.query_dict[name] = values[0]
self.query_dict[name] = value
# handle view parameter
# Resolve the view parameter into a handler function.
self.view_func = _views.get(self.query_dict.get('view', None),
self.view_func)
@@ -191,7 +196,7 @@ class Request:
# handle tarball magic suffixes
if self.view_func is download_tarball:
if (self.query_dict.get('parent')):
del path_parts[-1]
del path_parts[-1]
elif path_parts[-1][-7:] == ".tar.gz":
path_parts[-1] = path_parts[-1][:-7]
@@ -283,13 +288,19 @@ class Request:
needs_redirect = 1
if self.repos and self.view_func is not redirect_pathrev:
# If this is an intended-to-be-hidden CVSROOT path, complain.
if cfg.options.hide_cvsroot \
and is_cvsroot_path(self.roottype, path_parts):
raise debug.ViewVCException('%s: unknown location'
% self.where, '404 Not Found')
# Make sure path exists
self.pathrev = pathrev = self.query_dict.get('pathrev')
self.pathtype = _repos_pathtype(self.repos, path_parts, pathrev)
if self.pathtype is None:
# path doesn't exist, see if it could be an old-style ViewVC URL
# with a fake suffix
# Path doesn't exist, see if it could be an old-style ViewVC URL
# with a fake suffix.
result = _strip_suffix('.diff', path_parts, pathrev, vclib.FILE, \
self.repos, view_diff) or \
_strip_suffix('.tar.gz', path_parts, pathrev, vclib.DIR, \
@@ -308,7 +319,7 @@ class Request:
if result:
self.path_parts, self.pathtype, self.view_func = result
self.where = _path_join(self.path_parts)
needs_redirect = 1
needs_redirect = 1
else:
raise debug.ViewVCException('%s: unknown location'
% self.where, '404 Not Found')
@@ -327,11 +338,11 @@ class Request:
self.where = _path_join(attic_parts)
needs_redirect = 1
# If this is a forbidden directory, stop now
if self.path_parts and self.pathtype == vclib.DIR \
and cfg.is_forbidden(self.path_parts[0]):
raise debug.ViewVCException('%s: unknown location' % path_parts[0],
'404 Not Found')
# If this is a forbidden location, stop now
if cfg.is_forbidden(self.rootname, self.path_parts, self.pathtype):
raise debug.ViewVCException('%s: unknown location' \
% _path_join(self.path_parts),
'404 Not Found')
if self.view_func is None:
# view parameter is not set, try looking at pathtype and the
@@ -340,7 +351,7 @@ class Request:
self.view_func = view_roots
elif self.pathtype == vclib.DIR:
# ViewCVS 0.9.2 used to put ?tarball=1 at the end of tarball urls
if self.query_dict.has_key('tarball'):
if self.query_dict.has_key('tarball'):
self.view_func = download_tarball
else:
self.view_func = view_directory
@@ -499,7 +510,7 @@ class Request:
if view_func is download_tarball:
if not where and not cfg.options.root_as_url_component:
url = url + '/' + rootname + '-root'
params['parent'] = '1'
params['parent'] = '1'
url = url + '.tar.gz'
# add trailing slash for a directory
@@ -590,34 +601,48 @@ def _validate_param(name, value):
this function throws an exception. Otherwise, it simply returns None.
"""
# First things first -- check that we have a legal parameter name.
try:
validator = _legal_params[name]
except KeyError:
raise debug.ViewVCException(
'An illegal parameter name ("%s") was passed.' % name,
'An illegal parameter name was provided.',
'400 Bad Request')
# Is there a validator? Is it a regex or a function? Validate if
# we can, returning without incident on valid input.
if validator is None:
return
elif hasattr(validator, 'match'):
if validator.match(value):
return
else:
if validator(value):
return
# is the validator a regex?
if hasattr(validator, 'match'):
if not validator.match(value):
raise debug.ViewVCException(
'An illegal value ("%s") was passed as a parameter.' %
value, '400 Bad Request')
return
# the validator must be a function
validator(value)
# If we get here, the input value isn't valid.
raise debug.ViewVCException(
'An illegal value was provided for the "%s" parameter.' % (name),
'400 Bad Request')
def _validate_regex(value):
# hmm. there isn't anything that we can do here.
### we need to watch the flow of these parameters through the system
### to ensure they don't hit the page unescaped. otherwise, these
### parameters could constitute a CSS attack.
pass
try:
re.compile(value)
return True
except:
return None
def _validate_view(value):
# Return true iff VALUE is one of our allowed views.
return _views.has_key(value)
def _validate_mimetype(value):
# For security purposes, we only allow mimetypes from a predefined set
# thereof.
return value in (viewcvs_mime_type, alt_mime_type, 'text/plain')
# obvious things here. note that we don't need uppercase for alpha.
_re_validate_alpha = re.compile('^[a-z]+$')
@@ -626,17 +651,13 @@ _re_validate_number = re.compile('^[0-9]+$')
# when comparing two revs, we sometimes construct REV:SYMBOL, so ':' is needed
_re_validate_revnum = re.compile('^[-_.a-zA-Z0-9:~\\[\\]/]*$')
# it appears that RFC 2045 also says these chars are legal: !#$%&'*+^{|}~`
# but woah... I'll just leave them out for now
_re_validate_mimetype = re.compile('^[-_.a-zA-Z0-9/]+$')
# date time values
_re_validate_datetime = re.compile(r'^(\d\d\d\d-\d\d-\d\d(\s+\d\d:\d\d(:\d\d)?)?)?$')
# the legal query parameters and their validation functions
_legal_params = {
'root' : None,
'view' : None,
'view' : _validate_view,
'search' : _validate_regex,
'p1' : None,
'p2' : None,
@@ -662,7 +683,7 @@ _legal_params = {
'tr2' : _re_validate_revnum,
'rev' : _re_validate_revnum,
'revision' : _re_validate_revnum,
'content-type' : _re_validate_mimetype,
'content-type' : _validate_mimetype,
# for query
'branch' : _validate_regex,
@@ -906,6 +927,9 @@ def is_viewable_image(mime_type):
def is_text(mime_type):
return not mime_type or mime_type[:5] == 'text/'
def is_cvsroot_path(roottype, path_parts):
return roottype == 'cvs' and path_parts and path_parts[0] == 'CVSROOT'
def is_plain_text(mime_type):
return not mime_type or mime_type == 'text/plain'
@@ -974,13 +998,18 @@ def get_file_view_info(request, where, rev=None, mime_type=None, pathrev=-1):
_re_rewrite_url = re.compile('((http|https|ftp|file|svn|svn\+ssh)(://[-a-zA-Z0-9%.~:_/]+)((\?|\&amp;)([-a-zA-Z0-9%.~:_]+)=([-a-zA-Z0-9%.~:_])+)*(#([-a-zA-Z0-9%.~:_]+)?)?)')
_re_rewrite_email = re.compile('([-a-zA-Z0-9_.\+]+)@(([-a-zA-Z0-9]+\.)+[A-Za-z]{2,4})')
def htmlify(html):
html = cgi.escape(html)
html = sapi.escape(html)
html = re.sub(_re_rewrite_url, r'<a href="\1">\1</a>', html)
html = re.sub(_re_rewrite_email, r'<a href="mailto:\1&#64;\2">\1&#64;\2</a>', html)
return html
def format_log(log, cfg):
s = htmlify(log[:cfg.options.short_log_len])
def format_log(log, cfg, htmlize=1):
if not log:
return log
if htmlize:
s = htmlify(log[:cfg.options.short_log_len])
else:
s = sapi.escape(log[:cfg.options.short_log_len])
if len(log) > cfg.options.short_log_len:
s = s + '...'
return s
@@ -1304,7 +1333,7 @@ def markup_stream_python(fp, cfg):
### It doesn't escape stuff quite right, nor does it munge URLs and
### mailtos as well as we do.
html = cgi.escape(fp.read())
html = sapi.escape(fp.read())
pp = py2html.PrettyPrint(PyFontify.fontify, "rawhtml", "color")
pp.set_mode_rawhtml_color()
html = pp.fontify(html)
@@ -1457,7 +1486,7 @@ def prepare_hidden_values(params):
hidden_values = []
for name, value in params.items():
hidden_values.append('<input type="hidden" name="%s" value="%s" />' %
(name, value))
(sapi.escape(name), sapi.escape(value)))
return string.join(hidden_values, '')
def sort_file_data(file_data, roottype, sortdir, sortby, group_dirs):
@@ -1537,16 +1566,9 @@ def view_directory(request):
cfg.options.hide_attic))
options["cvs_subdirs"] = (cfg.options.show_subdir_lastmod and
cfg.options.show_logs)
file_data = request.repos.listdir(request.path_parts, request.pathrev,
options)
# Filter file list if a regex is specified
search_re = request.query_dict.get('search', '')
if cfg.options.use_re_search and search_re:
file_data = search_files(request.repos, request.path_parts, request.pathrev,
file_data, search_re)
# Retrieve log messages, authors, revision numbers, timestamps
request.repos.dirlogs(request.path_parts, request.pathrev, file_data, options)
@@ -1556,6 +1578,12 @@ def view_directory(request):
sort_file_data(file_data, request.roottype, sortdir, sortby,
cfg.options.sort_group_dirs)
# If a regex is specified, build a compiled form thereof for filtering
searchstr = None
search_re = request.query_dict.get('search', '')
if cfg.options.use_re_search and search_re:
searchstr = re.compile(search_re)
# loop through entries creating rows and changing these values
rows = [ ]
num_displayed = 0
@@ -1587,13 +1615,14 @@ def view_directory(request):
(file.kind == vclib.DIR and 'dir')
row.errors = file.errors
if cfg.is_forbidden(request.rootname, request.path_parts + [file.name],
file.kind):
continue
if file.kind == vclib.DIR:
if (where == '') and (cfg.is_forbidden(file.name)):
continue
if (request.roottype == 'cvs' and cfg.options.hide_cvsroot
and where == '' and file.name == 'CVSROOT'):
if cfg.options.hide_cvsroot \
and is_cvsroot_path(request.roottype,
request.path_parts + [file.name]):
continue
row.view_href = request.get_url(view_func=view_directory,
@@ -1621,10 +1650,17 @@ def view_directory(request):
escape=1)
elif file.kind == vclib.FILE:
if searchstr is not None:
if request.roottype == 'cvs' and (file.errors or file.dead):
continue
if not search_file(request.repos, request.path_parts + [file.name],
request.pathrev, searchstr):
continue
if request.roottype == 'cvs' and file.dead:
num_dead = num_dead + 1
if hideattic:
continue
num_displayed = num_displayed + 1
file_where = where_prefix + file.name
@@ -1697,6 +1733,9 @@ def view_directory(request):
data['sortby_%s_href' % sortby] = request.get_url(params={'sortdir':
revsortdir},
escape=1)
# CVS doesn't support sorting by rev
if request.roottype == "cvs":
data['sortby_rev_href'] = None
# set cvs-specific fields
if request.roottype == 'cvs':
@@ -1891,10 +1930,12 @@ def view_log(request):
# selected revision
selected_rev = request.query_dict.get('r1')
paths_forbidden = {}
entries = [ ]
name_printed = { }
cvs = request.roottype == 'cvs'
for rev in show_revs:
last_one = 0
entry = _item()
entry.rev = rev.string
entry.state = (cvs and rev.dead and 'dead')
@@ -1959,8 +2000,27 @@ def view_log(request):
entry.vendor_branch = None
if rev.filename != request.where:
entry.orig_path = rev.filename
entry.copy_path = rev.copy_path
entry.copy_rev = rev.copy_rev
# If this path has been copied, check the copy source for
# forbiddenness. If it's forbidden, we'll a) pretend this is a
# regular add (instead of a copy), and b) stop traversing history.
if rev.copy_path:
if not paths_forbidden.has_key(rev.copy_path):
paths_forbidden[rev.copy_path] = \
cfg.is_forbidden(request.rootname,
_path_parts(rev.copy_path), pathtype)
if paths_forbidden[rev.copy_path]:
entry.prev = None
last_one = 1
else:
entry.copy_path = rev.copy_path
entry.copy_rev = rev.copy_rev
entry.copy_href = request.get_url(view_func=view_log,
where=rev.copy_path,
pathtype=vclib.FILE,
params={'pathrev': rev.copy_rev},
escape=1)
if entry.orig_path:
entry.orig_href = request.get_url(view_func=view_log,
@@ -1969,14 +2029,6 @@ def view_log(request):
params={'pathrev': rev.string},
escape=1)
if rev.copy_path:
entry.copy_href = request.get_url(view_func=view_log,
where=rev.copy_path,
pathtype=vclib.FILE,
params={'pathrev': rev.copy_rev},
escape=1)
# view/download links
if pathtype is vclib.FILE:
entry.view_href, entry.download_href, entry.download_text_href, \
@@ -2033,10 +2085,12 @@ def view_log(request):
# Save our escaping until the end so stuff above works
if entry.orig_path:
entry.orig_path = request.server.escape(entry.orig_path)
entry.orig_path = request.server.escape(entry.orig_path)
if entry.copy_path:
entry.copy_path = request.server.escape(entry.copy_path)
entries.append(entry)
if last_one:
break
data = common_template_data(request)
data.update({
@@ -2160,7 +2214,7 @@ def view_annotate(request):
diff_url = request.get_url(view_func=view_diff,
params={'r1': None, 'r2': None},
escape=1, partial=1)
escape=1, partial=1)
include_url = request.get_url(view_func=view_log, where='/WHERE/',
pathtype=vclib.FILE, params={}, escape=1)
@@ -2242,58 +2296,23 @@ def view_cvsgraph(request):
request.server.header()
generate_page(request, "graph", data)
def search_files(repos, path_parts, rev, files, search_re):
""" Search files in a directory for a regular expression.
Does a check-out of each file in the directory. Only checks for
the first match.
"""
# Pass in search regular expression. We check out
# each file and look for the regular expression. We then return the data
# for all files that match the regex.
# Compile to make sure we do this as fast as possible.
searchstr = re.compile(search_re)
# Will become list of files that have at least one match.
# new_file_list also includes directories.
new_file_list = [ ]
# Loop on every file (and directory)
for file in files:
# Is this a directory? If so, append name to new_file_list
# and move to next file.
if file.kind != vclib.FILE:
new_file_list.append(file)
continue
# Only files at this point
# Shouldn't search binary files, or should we?
# Should allow all text mime types to pass.
if not is_text(guess_mime(file.name)):
continue
# Only text files at this point
# Assign contents of checked out file to fp.
fp = repos.openfile(path_parts + [file.name], rev)[0]
# Read in each line, use re.search to search line.
# If successful, add file to new_file_list and break.
while 1:
line = fp.readline()
if not line:
break
if searchstr.search(line):
new_file_list.append(file)
# close down the pipe (and wait for the child to terminate)
fp.close()
break
return new_file_list
def search_file(repos, path_parts, rev, search_re):
"""Return 1 iff the contents of the file at PATH_PARTS in REPOS as
of revision REV matches regular expression SEARCH_RE."""
# Read in each line of a checked-out file, and then use re.search to
# search line.
fp = repos.openfile(path_parts, rev)[0]
matches = 0
while 1:
line = fp.readline()
if not line:
break
if search_re.search(line):
matches = 1
fp.close()
break
return matches
def view_doc(request):
"""Serve ViewVC static content locally.
@@ -2562,21 +2581,29 @@ def diff_parse_headers(fp, diff_type, rev1, rev2, sym1=None, sym2=None):
return date1, date2, flag, string.join(header_lines, '')
def _get_svn_location(request, base_rev, rev):
repos = request.repos
try:
parts = _path_parts(vclib.svn.get_location(repos, request.where,
repos._getrev(base_rev),
repos._getrev(rev)))
except vclib.InvalidRevision:
raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
'to diff', '400 Bad Request')
except vclib.ItemNotFound:
raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
'to diff', '400 Bad Request')
if request.cfg.is_forbidden(request.rootname, parts, vclib.FILE):
raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
'to diff', '400 Bad Request')
return parts
def _get_diff_path_parts(request, query_key, rev, base_rev):
if request.query_dict.has_key(query_key):
parts = _path_parts(request.query_dict[query_key])
elif request.roottype == 'svn':
try:
repos = request.repos
parts = _path_parts(vclib.svn.get_location(repos, request.where,
repos._getrev(base_rev),
repos._getrev(rev)))
except vclib.InvalidRevision:
raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
'to diff', '400 Bad Request')
except vclib.ItemNotFound:
raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
'to diff', '400 Bad Request')
parts = _get_svn_location(request, base_rev, rev)
else:
parts = request.path_parts
return parts
@@ -2896,6 +2923,11 @@ def generate_tarball(out, request, reldir, stack, dir_mtime=None):
if cvs and (file.rev is None or file.dead):
continue
# Skip forbidden files.
if request.cfg.is_forbidden(request.rootname, rep_path + [file.name],
file.kind):
continue
# If we get here, we've seen at least one valid file in the
# current directory. For CVS, we need to make sure there are
# directory parents to contain it, so we flush the stack.
@@ -2926,13 +2958,16 @@ def generate_tarball(out, request, reldir, stack, dir_mtime=None):
if file.errors or file.kind != vclib.DIR:
continue
# Skip forbidden/hidden directories (top-level only).
if not rep_path:
if (request.cfg.is_forbidden(file.name)
or (cvs and request.cfg.options.hide_cvsroot
and file.name == 'CVSROOT')):
continue
# Skip hidden directories (top-level only).
if request.cfg.options.hide_cvsroot \
and is_cvsroot_path(request.roottype, rep_path + [file.name]):
continue
# Skip forbidden subdirs.
if request.cfg.is_forbidden(request.rootname, rep_path + [file.name],
file.kind):
continue
mtime = request.roottype == 'svn' and file.date or None
generate_tarball(out, request, reldir + [file.name], stack, mtime)
@@ -2959,8 +2994,9 @@ def download_tarball(request):
def view_revision(request):
if request.roottype == "cvs":
raise ViewVCException("Revision view not supported for CVS repositories "
"at this time.", "400 Bad Request")
raise debug.ViewVCException("Revision view not supported for CVS "
"repositories at this time.",
"400 Bad Request")
data = common_template_data(request)
query_dict = request.query_dict
@@ -2976,6 +3012,14 @@ def view_revision(request):
if check_freshness(request, None, str(rev), weak=1):
return
# Strip forbidden changed paths (we allow forbidden copyfrom-paths
# to leak through, though).
def _only_allowed(change):
return not request.cfg.is_forbidden(request.rootname,
_path_parts(change.filename),
change.pathtype)
changes = filter(_only_allowed, changes)
# Handle limit_changes parameter
cfg_limit_changes = request.cfg.options.limit_changes
limit_changes = int(query_dict.get('limit_changes', cfg_limit_changes))
@@ -3001,10 +3045,24 @@ def view_revision(request):
pathtype = (change.pathtype == vclib.FILE and 'file') \
or (change.pathtype == vclib.DIR and 'dir') \
or None
if (change.action == 'added' or change.action == 'replaced') \
and not change.is_copy:
change.text_mods = 0
change.prop_mods = 0
# If this is an add or a replacement, we'll verify that copyfrom
# paths are readable (if this is a copy), and if not claim this
# isn't a copy after all. And if it ain't a copy (now or "after
# all"), we'll clear the text_mods and prop_mods flags.
if (change.action == 'added' or change.action == 'replaced'):
if change.is_copy \
and request.cfg.is_forbidden(request.rootname,
_path_parts(change.base_path),
change.pathtype):
change.is_copy = 0
if change.action == 'added':
change.base_path = None
change.base_rev = None
if not change.is_copy:
change.text_mods = 0
change.prop_mods = 0
view_func = None
if change.pathtype is vclib.FILE:
@@ -3109,19 +3167,22 @@ def view_queryform(request):
data['query_action'], data['query_hidden_values'] = \
request.get_form(view_func=view_query, params={'limit_changes': None})
def escaped_query_dict_get(itemname, itemdefault=''):
return request.server.escape(request.query_dict.get(itemname, itemdefault))
# default values ...
data['branch'] = request.query_dict.get('branch', '')
data['branch_match'] = request.query_dict.get('branch_match', 'exact')
data['dir'] = request.query_dict.get('dir', '')
data['file'] = request.query_dict.get('file', '')
data['file_match'] = request.query_dict.get('file_match', 'exact')
data['who'] = request.query_dict.get('who', '')
data['who_match'] = request.query_dict.get('who_match', 'exact')
data['querysort'] = request.query_dict.get('querysort', 'date')
data['date'] = request.query_dict.get('date', 'hours')
data['hours'] = request.query_dict.get('hours', '2')
data['mindate'] = request.query_dict.get('mindate', '')
data['maxdate'] = request.query_dict.get('maxdate', '')
data['branch'] = escaped_query_dict_get('branch', '')
data['branch_match'] = escaped_query_dict_get('branch_match', 'exact')
data['dir'] = escaped_query_dict_get('dir', '')
data['file'] = escaped_query_dict_get('file', '')
data['file_match'] = escaped_query_dict_get('file_match', 'exact')
data['who'] = escaped_query_dict_get('who', '')
data['who_match'] = escaped_query_dict_get('who_match', 'exact')
data['querysort'] = escaped_query_dict_get('querysort', 'date')
data['date'] = escaped_query_dict_get('date', 'hours')
data['hours'] = escaped_query_dict_get('hours', '2')
data['mindate'] = escaped_query_dict_get('mindate', '')
data['maxdate'] = escaped_query_dict_get('maxdate', '')
data['limit_changes'] = int(request.query_dict.get('limit_changes',
request.cfg.options.limit_changes))
@@ -3219,28 +3280,24 @@ def prev_rev(rev):
r = r[:-2]
return string.join(r, '.')
def build_commit(request, files, limited_files, dir_strip):
commit = _item(num_files=len(files), files=[])
commit.limited_files = ezt.boolean(limited_files)
def build_commit(request, files, max_files, dir_strip, format):
"""Return a commit object build from the information in FILES, or
None if no allowed files are present in the set. DIR_STRIP is the
path prefix to remove from the commit object's set of files. If
MAX_FILES is non-zero, it is used to limit the number of files
returned in the commit object. FORMAT is the requested output
format of the query request."""
author = files[0].GetAuthor()
date = files[0].GetTime()
desc = files[0].GetDescription()
commit.log = htmlify(desc)
commit.short_log = format_log(desc, request.cfg)
commit.author = request.server.escape(files[0].GetAuthor())
commit.rss_date = make_rss_time_string(files[0].GetTime(), request.cfg)
if request.roottype == 'svn':
commit.rev = files[0].GetRevision()
commit.rss_url = '%s://%s%s' % \
(request.server.getenv("HTTPS") == "on" and "https" or "http",
request.server.getenv("HTTP_HOST"),
request.get_url(view_func=view_revision,
params={'revision': commit.rev},
escape=1))
else:
commit.rev = None
commit.rss_url = None
commit_rev = files[0].GetRevision()
len_strip = len(dir_strip)
commit_files = []
num_allowed = 0
plus_count = 0
minus_count = 0
for f in files:
commit_time = f.GetTime()
if commit_time:
@@ -3257,8 +3314,16 @@ def build_commit(request, files, limited_files, dir_strip):
assert dirname[:len_strip] == dir_strip
assert len(dirname) == len_strip or dirname[len(dir_strip)] == '/'
dirname = dirname[len_strip+1:]
filename = dirname and ("%s/%s" % (dirname, filename)) or filename
where = dirname and ("%s/%s" % (dirname, filename)) or filename
# skip files in forbidden or hidden modules
path_parts = _path_parts(where)
if request.cfg.is_forbidden(request.rootname, path_parts, vclib.FILE):
continue
if request.cfg.options.hide_cvsroot \
and is_cvsroot_path(request.roottype, path_parts):
continue
# In CVS, we can actually look at deleted revisions; in Subversion
# we can't -- we'll look at the previous revision instead.
if request.roottype == 'svn':
@@ -3273,14 +3338,14 @@ def build_commit(request, files, limited_files, dir_strip):
where=dirname, pathtype=vclib.DIR,
params=params, escape=1)
log_href = request.get_url(view_func=view_log,
where=filename, pathtype=vclib.FILE,
where=where, pathtype=vclib.FILE,
params=params, escape=1)
diff_href = view_href = download_href = None
view_href = request.get_url(view_func=view_markup,
where=filename, pathtype=vclib.FILE,
where=where, pathtype=vclib.FILE,
params=params, escape=1)
download_href = request.get_url(view_func=view_checkout,
where=filename, pathtype=vclib.FILE,
where=where, pathtype=vclib.FILE,
params=params, escape=1)
if change_type == 'Change':
diff_href_params = params.copy()
@@ -3290,27 +3355,29 @@ def build_commit(request, files, limited_files, dir_strip):
'diff_format': None
})
diff_href = request.get_url(view_func=view_diff,
where=filename, pathtype=vclib.FILE,
where=where, pathtype=vclib.FILE,
params=diff_href_params, escape=1)
prefer_markup = ezt.boolean(default_view(guess_mime(filename),
request.cfg) == view_markup)
request.cfg) == view_markup)
# skip files in forbidden or hidden modules
dir_parts = filter(None, string.split(dirname, '/'))
if dir_parts \
and ((dir_parts[0] == 'CVSROOT'
and request.cfg.options.hide_cvsroot) \
or request.cfg.is_forbidden(dir_parts[0])):
# Update plus/minus line change count.
plus = int(f.GetPlusCount())
minus = int(f.GetMinusCount())
plus_count = plus_count + plus
minus_count = minus_count + minus
num_allowed = num_allowed + 1
if max_files and num_allowed > max_files:
continue
commit.files.append(_item(date=commit_time,
commit_files.append(_item(date=commit_time,
dir=request.server.escape(dirname),
file=request.server.escape(f.GetFile()),
file=request.server.escape(filename),
author=request.server.escape(f.GetAuthor()),
rev=rev,
branch=f.GetBranch(),
plus=int(f.GetPlusCount()),
minus=int(f.GetMinusCount()),
plus=plus,
minus=minus,
type=change_type,
dir_href=dir_href,
log_href=log_href,
@@ -3318,30 +3385,56 @@ def build_commit(request, files, limited_files, dir_strip):
download_href=download_href,
prefer_markup=prefer_markup,
diff_href=diff_href))
# No files survived forbiddenness checks? Let's just pretend this
# little commit didn't happen, shall we?
if not len(commit_files):
return None
commit = _item(num_files=len(commit_files), files=commit_files,
plus=plus_count, minus=minus_count)
commit.limited_files = ezt.boolean(num_allowed > len(commit_files))
commit.log = htmlify(desc)
commit.short_log = format_log(desc, request.cfg, format != 'rss')
commit.author = request.server.escape(author)
commit.rss_date = make_rss_time_string(date, request.cfg)
if request.roottype == 'svn':
commit.rev = commit_rev
commit.rss_url = '%s://%s%s' % \
(request.server.getenv("HTTPS") == "on" and "https" or "http",
request.server.getenv("HTTP_HOST"),
request.get_url(view_func=view_revision,
params={'revision': commit.rev},
escape=1))
else:
commit.rev = None
commit.rss_url = None
return commit
def query_backout(request, commits):
request.server.header('text/plain')
if commits:
print '# This page can be saved as a shell script and executed.'
print '# It should be run at the top of your work area. It will update'
print '# your working copy to back out the changes selected by the'
print '# query.'
print
else:
print '# No changes were selected by the query.'
print '# There is nothing to back out.'
server_fp = get_writeready_server_file(request, 'text/plain')
if not commits:
server_fp.write("""\
# No changes were selected by the query.
# There is nothing to back out.
""")
return
server_fp.write("""\
# This page can be saved as a shell script and executed.
# It should be run at the top of your work area. It will update
# your working copy to back out the changes selected by the
# query.
""")
for commit in commits:
for fileinfo in commit.files:
if request.roottype == 'cvs':
print 'cvs update -j %s -j %s %s/%s' \
% (fileinfo.rev, prev_rev(fileinfo.rev),
fileinfo.dir, fileinfo.file)
server_fp.write('cvs update -j %s -j %s %s/%s\n'
% (fileinfo.rev, prev_rev(fileinfo.rev),
fileinfo.dir, fileinfo.file))
elif request.roottype == 'svn':
print 'svn merge -r %s:%s %s/%s' \
% (fileinfo.rev, prev_rev(fileinfo.rev),
fileinfo.dir, fileinfo.file)
server_fp.write('svn merge -r %s:%s %s/%s\n'
% (fileinfo.rev, prev_rev(fileinfo.rev),
fileinfo.dir, fileinfo.file))
def view_query(request):
if not is_query_supported(request):
@@ -3365,7 +3458,7 @@ def view_query(request):
format = request.query_dict.get('format')
limit = int(request.query_dict.get('limit', 0))
limit_changes = int(request.query_dict.get('limit_changes',
request.cfg.options.limit_changes))
request.cfg.options.limit_changes))
match_types = { 'exact':1, 'like':1, 'glob':1, 'regex':1, 'notregex':1 }
sort_types = { 'date':1, 'author':1, 'file':1 }
@@ -3451,46 +3544,49 @@ def view_query(request):
current_desc = query.commit_list[0].GetDescriptionID()
current_rev = query.commit_list[0].GetRevision()
dir_strip = _path_join(repos_dir)
for commit in query.commit_list:
# base modification time on the newest commit ...
if commit.GetTime() > mod_time: mod_time = commit.GetTime()
# form plus/minus totals
plus_count = plus_count + int(commit.GetPlusCount())
minus_count = minus_count + int(commit.GetMinusCount())
# group commits with the same commit message ...
desc = commit.GetDescriptionID()
commit_desc = commit.GetDescriptionID()
commit_rev = commit.GetRevision()
# base modification time on the newest commit
if commit.GetTime() > mod_time:
mod_time = commit.GetTime()
# For CVS, group commits with the same commit message.
# For Subversion, group them only if they have the same revision number
if request.roottype == 'cvs':
if current_desc == desc:
if not limit_changes or len(files) < limit_changes:
files.append(commit)
else:
limited_files = 1
if current_desc == commit_desc:
files.append(commit)
continue
else:
if current_rev == commit.GetRevision():
if not limit_changes or len(files) < limit_changes:
files.append(commit)
else:
limited_files = 1
if current_rev == commit_rev:
files.append(commit)
continue
# if our current group has any allowed files, append a commit
# with those files.
if len(files):
commits.append(build_commit(request, files, limited_files, dir_strip))
# append this grouping
commit_item = build_commit(request, files, limit_changes,
dir_strip, format)
if commit_item:
# update running plus/minus totals
plus_count = plus_count + commit_item.plus
minus_count = minus_count + commit_item.minus
commits.append(commit_item)
files = [ commit ]
limited_files = 0
current_desc = desc
current_rev = commit.GetRevision()
current_desc = commit_desc
current_rev = commit_rev
# we need to tack on our last commit grouping, but, again, only if
# it has allowed files.
if len(files):
commits.append(build_commit(request, files, limited_files, dir_strip))
# we need to tack on our last commit grouping, if any
commit_item = build_commit(request, files, limit_changes,
dir_strip, format)
if commit_item:
# update running plus/minus totals
plus_count = plus_count + commit_item.plus
minus_count = minus_count + commit_item.minus
commits.append(commit_item)
# only show the branch column if we are querying all branches
# or doing a non-exact branch match on a CVS repository.
show_branch = ezt.boolean(request.roottype == 'cvs' and
@@ -3534,7 +3630,7 @@ def view_query(request):
})
if format == 'rss':
request.server.header("text/xml")
request.server.header("application/rss+xml")
generate_page(request, "rss", data)
else:
request.server.header()
@@ -3564,10 +3660,10 @@ for code, view in _views.items():
def list_roots(cfg):
allroots = { }
for root in cfg.general.cvs_roots.keys():
allroots[root] = [cfg.general.cvs_roots[root], 'cvs']
for root in cfg.general.svn_roots.keys():
allroots[root] = [cfg.general.svn_roots[root], 'svn']
for root in cfg.general.cvs_roots.keys():
allroots[root] = [cfg.general.cvs_roots[root], 'cvs']
return allroots
def load_config(pathname=None, server=None):
@@ -3636,9 +3732,9 @@ def view_error(server, cfg):
exc_dict = debug.GetExceptionData()
status = exc_dict['status']
if exc_dict['msg']:
exc_dict['msg'] = htmlify(exc_dict['msg'])
exc_dict['msg'] = server.escape(exc_dict['msg'])
if exc_dict['stacktrace']:
exc_dict['stacktrace'] = htmlify(exc_dict['stacktrace'])
exc_dict['stacktrace'] = server.escape(exc_dict['stacktrace'])
handled = 0
# use the configured error template if possible
@@ -3670,7 +3766,7 @@ def main(server, cfg):
finally:
debug.t_end('main')
debug.dump()
debug.t_dump(server.file())
debug.DumpChildren(server)

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC

53
notes/TODO Normal file
View File

@@ -0,0 +1,53 @@
PREFACE
-------
This file will go away soon after release 0.8. Please use the SourceForge
tracker to resubmit any of the items listed below, if you think, it is
still an issue:
http://sourceforge.net/tracker/?group_id=18760
Before reporting please check, whether someone else has already done this.
Working patches increase the chance to be included into the next release.
-- PeFu / October 2001
TODO ITEMS
----------
*) add Tamminen Eero's comments on how to make Linux directly execute
the Python script. From email on Feb 19.
[ add other examples, such as my /bin/sh hack or the teeny CGI stub
importing the bulk hack ]
*) insert rcs_path into PATH before calling "rcsdiff". rcsdiff might
use "co" and needs to find it on the path.
*) show the "locked" flag (attach it to the LogEntry objects).
Idea from Russell Gordon <russell@hoopscotch.dhs.org>
*) committing with a specific revision number:
http://mailman.lyra.org/pipermail/viewcvs/2000q1/000008.html
*) add capability similar to cvs2cl.pl:
http://mailman.lyra.org/pipermail/viewcvs/2000q2/000050.html
suggestion from Chris Meyer <cmeyer@gatan.com>.
*) add a tree view of the directory structure (and files?)
*) include a ConfigParser.py to help older Python installations
*) add a check for the rcs programs/paths to viewvc-install. clarify the
dependency on RCS in the docs.
*) have a "check" mode that verifies binaries are available on rcs_path
-> alternately (probably?): use rcsparse rather than external tools
KNOWN BUGS
----------
*) time.timezone seems to not be available on some 1.5.2 installs.
I was unable to verify this. On RedHat and SuSE Linux this bug
is non existant.
*) With old repositories containing many branches, tags or thousands
or revisions, the cvsgraph feature becomes unusable (see INSTALL).
ViewVC can't do much about this, but it might be possible to
investigate the number of branches, tags and revision in advance
and disable the cvsgraph links, if the numbers exceed a certain
treshold.

85
notes/releases.txt Normal file
View File

@@ -0,0 +1,85 @@
RELEASE MANAGEMENT
ViewVC rolls releases from release branches associate with each minor
version of the software. For example, the 1.1.0 is rolled from the
1.1.x branch. The same is true for the 1.1.1, 1.1.2, ... releases.
There is a script, `tools/make-release', which creates a release
directory and the various archive files that we distribute. All other
steps required to get a ViewVC release out of the door require manual
execution (currently by C. Michael Pilato). Those steps are as
follows:
Checkout a working copy of the release branch for the release you
intend to roll, and in that working copy, perform the following steps
(X, Y, and Z below represent integral major, minor, and patch version
numbers, and not literal):
1. Review any open bug reports:
http://viewvc.tigris.org/servlets/ProjectIssues
2. Add a new subsection to the file 'docs/upgrading.html' describing
all user visible changes for users of previous releases of ViewVC.
Commit any modifications. NOTE: This step should not be necessary
for patch releases.
3. Verify that copyright years are correct in both the LICENSE.html
file and the source code.
4. Update and commit the 'CHANGES' file.
5. Test, test, test! There is no automatic testsuite available. So
just run with permuting different `viewvc.conf' settings... and
pray. Fix what needs fixin', keeping the CHANGES file in sync
with the branch.
6. At this point, the source code committed to the release branch
should exactly reflect what you wish to distribute and dub "the
release".
7. Edit the file 'lib/viewvc.py' and remove the "-dev" suffix from
__version__. The remainder should be of the form "X.Y.Z", where X,
Y, and Z are positive integers. Do NOT commit this change.
8. Update your working copy to HEAD, and tag the release:
svn update
svn cp -m "Tag the X.Y.Z final release." . \
http://viewvc.tigris.org/svn/viewvc/tags/X.Y.Z
9. Go into an empty directory and run the 'make-release' script:
tools/make-release viewvc-X.Y.Z tags/X.Y.Z
10. Verify the archive files:
- do they have a LICENSE.html file?
- do they have necessary include documentation?
- do they *not* have unnecessary stuff?
- do they install and work correctly?
11. Upload the created archive files (tar.gz and zip) into the Files
and Documents section of the Tigris.org project, and modify the
CHECKSUMS document there accordingly. Also, drop a copy of the
archive files into the root directory of the viewvc.org website
(unversioned).
12. Update the websites (both the viewvc.org/ and www/ ones) to refer
to the new release files.
13. Edit the file 'lib/viewvc.py' again, re-adding the "-dev" suffix
and incrementing the patch number assigned to the __version__
variable, and commit:
svn ci -m "Begin a new release cycle."
14. Edit the Issue Tracker configuration options, adding a new Version
for the just-released one, and a new Milestone for the next patch
(and possibly, minor or major) release. (For the Milestone sort
key, use a packed integer XXYYZZ: 1.0.3 == 10003, 2.11.4 == 21104.)
15. Write an announcement explaining all the cool new features and
post it to the announce@ list, to the project's News area, and to
other places interested in this sort of stuff, such as Freshmeat
(http://www.freshmeat.net).

View File

@@ -4,22 +4,30 @@
<thead>
<tr>
<th class="vc_header[is sortby "file"]_sort[end]" colspan="2">
<a href="[sortby_file_href]#dirlist">File
[if-any sortby_file_href]<a href="[sortby_file_href]#dirlist">File</a>[else]File[end]
[is sortby "file"]
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
width="13" height="13"
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
[end]
</a>
</th>
[if-any sortby_rev_href]
<th class="vc_header[is sortby "rev"]_sort[end]">
<a href="[sortby_rev_href]#dirlist">Last Change
<a href="[sortby_rev_href]#dirlist">Last Change</a>
[is sortby "rev"]
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
width="13" height="13"
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
[end]
</a>
[else]
<th class="vc_header[is sortby "date"]_sort[end]">
[if-any sortby_date_href]<a href="[sortby_date_href]#dirlist">Last Change</a>[else]Last Change[end]
[is sortby "date"]
<img class="vc_sortarrow" alt="[is sortdir "down"](date)[end]"
width="13" height="13"
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
[end]
[end]
</th>
</tr>
</thead>

View File

@@ -4,50 +4,45 @@
<thead>
<tr>
<th class="vc_header[is sortby "file"]_sort[end]" colspan="2">
<a href="[sortby_file_href]#dirlist">File
[if-any sortby_file_href]<a href="[sortby_file_href]#dirlist">File</a>[else]File[end]
[is sortby "file"]
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
width="13" height="13"
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
[end]
</a>
</th>
<th class="vc_header[is sortby "rev"]_sort[end]">
<a href="[sortby_rev_href]#dirlist">Rev.
[if-any sortby_rev_href]<a href="[sortby_rev_href]#dirlist">Rev.</a>[else]Rev.[end]
[is sortby "rev"]
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
width="13" height="13"
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
[end]
</a>
</th>
<th class="vc_header[is sortby "date"]_sort[end]">
<a href="[sortby_date_href]#dirlist">Age
[if-any sortby_date_href]<a href="[sortby_date_href]#dirlist">Age</a>[else]Age[end]
[is sortby "date"]
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
width="13" height="13"
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
[end]
</a>
</th>
<th class="vc_header[is sortby "author"]_sort[end]">
<a href="[sortby_author_href]#dirlist">Author
[if-any sortby_author_href]<a href="[sortby_author_href]#dirlist">Author</a>[else]Author[end]
[is sortby "author"]
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
width="13" height="13"
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
[end]
</a>
</th>
[is cfg.options.show_logs "1"]
<th class="vc_header[is sortby "log"]_sort[end]">
<a href="[sortby_log_href]#dirlist">Last log entry
[if-any sortby_log_href]<a href="[sortby_log_href]#dirlist">Last log entry</a>[else]Last log entry[end]
[is sortby "log"]
<img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
width="13" height="13"
src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
[end]
</a>
</th>
[end]
</tr>

View File

@@ -9,16 +9,43 @@
<h3>An Exception Has Occurred</h3>
[if-any msg]
<p><pre>[msg]</pre></p>
<p>[msg]</p>
[end]
[if-any status]
<h4>HTTP Response Status</h4>
<p><pre>[status]</pre></p>
<hr />
[end]
[if-any msg][else]
<h4>Python Traceback</h4>
<p><pre>
[stacktrace]
</pre></p>
[end]
[# Here follows a bunch of space characters, present to ensure that
our error message is larger than 512 bytes so that IE's "Friendly
Error Message" won't show. For more information, see
http://oreillynet.com/onjava/blog/2002/09/internet_explorer_subverts_err.html]
</body>
</html>

View File

@@ -1,34 +1,24 @@
[if-any search_re_form]
<hr />
[# this table holds the selectors on the left, and reset on the right ]
<table class="auto">
<tr>
<td>Show files containing the regular expression:</td>
<td>
<form method="get" action="[search_re_action]">
<div>
[search_re_hidden_values]
<input type="text" name="search" value="[search_re]" />
<input type="submit" value="Show" />
</div>
</form>
</td>
</tr>
[if-any search_re]
<tr>
<td>&nbsp;</td>
<td>
<form method="get" action="[search_tag_action]">
<div>
[search_tag_hidden_values]
<input type="submit" value="Show all files" />
</div>
</form>
</td>
</tr>
[end]
</table>
<hr />
<div>
Show files containing the regular expression:
<form method="get" action="[search_re_action]" style="display: inline;">
<div style="display: inline;">
[search_re_hidden_values]
<input type="text" name="search" value="[search_re]" />
<input type="submit" value="Show" />
</div>
</form>
[if-any search_re]
<form method="get" action="[search_re_action]" style="display: inline;">
<div style="display: inline;">
[search_re_hidden_values]
<input type="submit" value="Show all files" />
</div>
</form>
[end]
[end]
</div>
[# if you want to disable tarball generation remove the following: ]
[if-any tarball_href]

View File

@@ -9,8 +9,8 @@
<title>[if-any commits.rev][commits.rev]: [end][[commits.author]] [commits.short_log]</title>
[if-any commits.rss_url]<link>[commits.rss_url]</link>[end]
<author>[commits.author]</author>
<pubDate>[commits.rss_date]</pubDate>
<description>[commits.log]</description>
<pubDate>[if-any commits.rss_date][commits.rss_date][else](unknown date)[end]</pubDate>
<description>&lt;pre&gt;[format "xml"][commits.log][end]&lt;/pre&gt;</description>
</item>[end]
</channel>
</rss>

View File

@@ -1,6 +1,6 @@
#!/bin/sh
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2009 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -17,17 +17,18 @@
### Validate input
if test $# != 2 && test $# != 1; then
echo "Usage: $0 TARGET-DIRECTORY [TAGNAME]"
echo "Usage: $0 TARGET-DIRECTORY [BRANCH]"
echo ""
echo "If TAGNAME is not provided, the release will be rolled from trunk."
echo "If BRANCH (i.e. \"tags/1.1.0\" or \"branches/1.0.x\") is not provided,"
echo "the release will be rolled from trunk."
exit 1
fi
TARGET=${1}
if test $# == 1; then
if test $# = 1; then
ROOT=trunk
else
ROOT=tags/${2}
ROOT=${2}
fi
if test -e ${TARGET}; then
@@ -36,7 +37,8 @@ if test -e ${TARGET}; then
fi
### Grab an export from the Subversion repository.
echo "Exporting into:" ${TARGET}
EXPORT_URL="http://viewvc.tigris.org/svn/viewvc/${ROOT}"
echo "Exporting '${EXPORT_URL}' into '${TARGET}'"
for PLATFORM in unix windows; do
if test ${PLATFORM} = windows; then
@@ -45,30 +47,44 @@ for PLATFORM in unix windows; do
EOL="--native-eol LF"
fi
svn export ${EOL} http://viewvc.tigris.org/svn/viewvc/${ROOT} ${TARGET}
echo "Beginning build for ${PLATFORM}:"
echo " Exporting source code..."
svn export --quiet ${EOL} ${EXPORT_URL} ${TARGET}
### Various shifting, cleanup.
# Documentation is now also distributed together with the release, but
# we still copy the license file to its traditional place (it is small
# and many files still contain comments refering to this location):
# Remove some not useful directories
rm -r ${TARGET}/{elemx,tests,tools,tparse,viewcvs.sourceforge.net,www}
for JUNK in elemx \
notes \
tests \
tools \
tparse \
viewcvs.sourceforge.net \
viewvc.org \
www; do
if [ -d ${TARGET}/${JUNK} ]; then
echo " Removing ${TARGET}/${JUNK}..."
rm -r ${TARGET}/${JUNK}
fi
done
# Make sure permissions are reasonable:
echo " Normalizing permissions..."
find ${TARGET} -print | xargs chmod uoa+r
find ${TARGET} -type d -print | xargs chmod uoa+x
if test ${PLATFORM} = windows; then
# Create also a ZIP file for those poor souls :-) still using Windows:
echo " Creating ZIP archive..."
zip -qor9 ${TARGET}.zip ${TARGET}
else
# Cut the tarball:
echo " Creating tarball archive..."
tar cf - ${TARGET} | gzip -9 > ${TARGET}.tar.gz
fi
# remove target directory
rm -r ${TARGET}
done
echo 'Done.'
echo "Done."

View File

@@ -1,2 +0,0 @@
*.tar.gz
*.zip

View File

@@ -1 +0,0 @@
RedirectMatch ^(.*)$ http://www.viewvc.org/$1

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- Mode: python -*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
#
# 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 ViewVC
@@ -75,8 +75,9 @@ if sys.platform == "win32":
## destination path,
## boolean -- prompt before replacing?)
TREE_LIST = [
("lib", "lib", 0),
("templates", "templates", 1),
("lib", "lib", 0),
("templates", "templates", 1),
("templates-contrib", "templates-contrib", 1),
]

View File

@@ -142,8 +142,9 @@ use_rcsparse = 0
address = <a href="mailto:cvs-admin@insert.your.domain.here">No admin address has been configured</a>
#
# This should contain a list of modules in the repository that should not be
# displayed (by default or by explicit path specification).
# This should contain a list of modules (that is, top-level directories within
# repositories) that should not be displayed (by default or by explicit path
# specification).
#
# This configuration can be a simple list of modules, or it can get quite
# complex:
@@ -162,8 +163,9 @@ address = <a href="mailto:cvs-admin@insert.your.domain.here">No admin address ha
#
# Tests are case-sensitive.
#
forbidden =
# NOTE: This is for the hiding of modules within repositories, *not*
# for the hiding of repositories (roots) themselves.
#
# Some examples:
#
# Disallow "example" but allow all others:
@@ -184,6 +186,40 @@ forbidden =
# Allow "xml", forbid other modules starting with "x", and allow the rest:
# forbidden = !xml, x*, !*
#
forbidden =
#
# This is similar to 'forbidden', but differs in some key ways:
#
# *) Rather than shell-style "glob" expressions, the values in this
# list are regular expressions. You can still prepend a ! character
# to each regular expression to invert its meaning, though.
#
# *) It compares not against modules only, but against paths consisting
# of the repository (or root) name plus the path of the versioned file
# or directory to be tested. For example, to see if the user is
# authorized to see the path "/trunk/www/index.html" in the repository
# whose root name is "svnrepos", this authorizer will test the path
# "svnrepos/trunk/www/index.html" against the list of forbidden regular
# expressions. Directory paths will be terminated by a forward slash.
#
# NOTE: Use of this configuration option will *disable* any configuration of
# the 'forbidden' option -- they cannot be used simultaneously.
#
# Some examples:
#
# Disallow files named "PRIVATE", but allow all others:
# forbiddenre = /PRIVATE$
#
# Allow only the "example1" and "example2" roots and the paths inside them,
# disallowing all others (which can be done in multiple ways):
# forbiddenre = !^example1(/|$), !^example2(/|$)/
# forbiddenre = !^example[12](/|$)
#
# Only allow visibility of HTML files and the directories that hold them:
# forbiddenre = !^.*(/|\.html)$
#
forbiddenre =
#
# This option provides a mechanism for custom key/value pairs to be

View File

@@ -1,2 +0,0 @@
*.tar.gz
*.zip

View File

@@ -1,68 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>ViewVC: Contact</title>
<link rel="stylesheet" type="text/css" href="./styles.css"/>
</head>
<body>
<div id="title">
<a href="http://www.viewvc.org/"><img
src="./images/title.jpg" alt="ViewVC: Repository Browsing"/></a>
</div>
<div id="menu">
<p><a href="./index.html">Home</a> |
<a href="http://viewvc.tigris.org/">Project Page</a> |
<a href="./download.html">Download</a> |
<a href="./upgrading.html">Upgrading</a> |
<a href="./contributing.html">Contributing</a> |
<a href="./license-1.html">License</a> |
<a href="./contact.html">Contact</a> |
<a href="./who.html">About</a>
</p>
</div>
<table id="pagetable">
<tr>
<td id="pagecolumn1">
<h4>On this page:</h4>
<ul id="bookmarks">
<li><a href="#sec-contacting-us">Contacting Us</a></li>
</ul>
<hr/>
<address><a href="mailto:&#117&#115&#101&#114&#115&#64&#118&#105&#101&#119&#118&#99&#46&#116&#105&#103&#114&#105&#115&#46&#111&#114&#103">ViewVC Users Group</a></address>
</td>
<td id="pagecolumn2">
<div class="section">
<h2 id="sec-contacting-us">Contacting Us</h2>
<p>Please send any comments, questions, or suggestions to the <a
href="mailto:&#117&#115&#101&#114&#115&#64&#118&#105&#101&#119&#118&#99&#46&#116&#105&#103&#114&#105&#115&#46&#111&#114&#103">ViewVC users mailing
list</a>. There is also a <a
href="mailto:&#100&#101&#118&#64&#118&#105&#101&#119&#118&#99&#46&#116&#105&#103&#114&#105&#115&#46&#111&#114&#103">mailing list specifically for
ViewVC developers</a>. You can subscribe to these lists, as well
view the list archives, (and other
project lists) <a
href="http://viewvc.tigris.org/servlets/ProjectMailingListList"
>here</a>.</p>
<p>ViewVC is an <a href="http://www.opensource.org/">Open
Source</a> project, and all <a href="./contributing.html">contributions</a>
are welcome.</p>
</div>
</td>
</tr>
</table>
</body>
</html>

View File

@@ -1,276 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>ViewVC: Contributing</title>
<link rel="stylesheet" type="text/css" href="./styles.css"/>
</head>
<body>
<div id="title">
<a href="http://www.viewvc.org/"><img
src="./images/title.jpg" alt="ViewVC: Repository Browsing"/></a>
</div>
<div id="menu">
<p><a href="./index.html">Home</a> |
<a href="http://viewvc.tigris.org/">Project Page</a> |
<a href="./download.html">Download</a> |
<a href="./upgrading.html">Upgrading</a> |
<a href="./contributing.html">Contributing</a> |
<a href="./license-1.html">License</a> |
<a href="./contact.html">Contact</a> |
<a href="./who.html">About</a>
</p>
</div>
<table id="pagetable">
<tr>
<td id="pagecolumn1">
<h4>On this page:</h4>
<ul id="bookmarks">
<li><a href="#sec-getting-started">Getting Started</a></li>
<li><a href="#sec-testing">Testing and Reporting</a></li>
<li><a href="#sec-coding-style">Coding Style</a></li>
<li><a href="#sec-patches">Submitting Patches</a></li>
<li><a href="#sec-security">Security</a></li>
<li><a href="#sec-adding-features">Adding Features</a></li>
<li><a href="#sec-templates">Hacking on Templates</a></li>
<li><a href="#sec-releasing">Release Management</a></li>
</ul>
<hr/>
<address><a href="mailto:&#117&#115&#101&#114&#115&#64&#118&#105&#101&#119&#118&#99&#46&#116&#105&#103&#114&#105&#115&#46&#111&#114&#103">ViewVC Users Group</a></address>
</td>
<td id="pagecolumn2">
<div class="section">
<h2 id="sec-getting-started">Getting Started</h2>
<p>Some basic knowledge about <a
href="http://www.python.org">Python</a> and development tools like
<code>diff</code> is required. Your best bet is to start with a
fresh source code snapshot, which you may obtain from our
Subversion repository (see instructions <a
href="./download.html#sec-subversion">here</a>).</p>
<p>Version control history can be obtained using Subversion clients,
but is also browsable using <a
href="http://viewvc.tigris.org/source/browse/viewvc/trunk/"
>tigris.org's integrated ViewVC tool</a>.</p>
</div>
<div class="section">
<h2 id="sec-testing">Testing and Reporting</h2>
<p>Testing usability and the installation process on different
platforms is also a valuable contribution. Please report your
results back to us developers. Bandwidth is getting cheaper daily,
so don't be afraid &mdash; in fact, feel encouraged &mdash; to dump
as much detail about the problems you are seeing as possible into
your bug reports. Here are some things you definitely should
try to include:</p>
<ul>
<li>What version of ViewVC you are using (if you are using a source
snapshot, tell us the date of that snapshot).</li>
<li>What operating system your ViewVC is running on.</li>
<li>What version of Python you are using.</li>
<li>Whether you are running ViewVC standalone, or as a CGI program
under a web server (and if so, what web server).</li>
<li>The URL of your ViewVC instantiation, if it is public.
Sometimes, letting developers see the problem for themselves can
save everyone alot of time.</li>
</ul>
</div>
<div class="section">
<h2 id="sec-coding-style">Coding Style</h2>
<p>Unlike its predecessor, CvsWeb, ViewVC is written in Python, so it
doesn't suffer from the "unmaintainable code effect" that hits most
Perl projects sooner or later:</p>
<blockquote><em>&quot;[Perl] combines all the worst aspects of C and Lisp: a
billion different sublanguages in one monolithic executable. It
combines the power of C with the readability of PostScript.&quot;</em>
&mdash;&nbsp;Jamie&nbsp;Zawinski
</blockquote>
<p>Of course, a symphony of insanity can be composed in any language,
so we do try to stick to some basic guiding principles. Maintain
whatever style is present in the code being modified. New code can
use anything sane (which generally means <a
href="http://python.sourceforge.net/peps/pep-0008.html">PEP&nbsp;8</a>).
Our only real peeve is if someone writes a function call as:
<code>some_func&nbsp;(args)</code> &mdash; that space between the
function name and opening parenthesis is Huge Badness. Oh, and we
do <strong>not</strong> use Subversion keywords (such as
<code>$</code><code>Id$</code>) within the source.</p>
<p>Otherwise&hellip; <em>shrug</em>.</p>
</div>
<div class="section">
<h2 id="sec-patches">Submitting Patches</h2>
<p>Nothing speaks more loudly when bugs or features are the topic than
a patch. And quite frankly, sometimes if you want something done,
you gotta do it yourself. So, patches are always welcome. If you
aren't sure what exactly a &quot;patch&quot; is, or don't know how
to generate one, but you've got code contributions to make, please
don't hesitate to ask questions on the mailing lists. Patch
generation and application are pretty easy thing to get the hang of,
and drastically simplify code submission and review.</p>
<p>Please use the <a
href="http://viewvc.tigris.org/servlets/ProjectIssues">Issue
Tracker</a> to submit your patches. Unified contextual diffs
against the latest development snapshot are preferred.</p>
<p>If you have commit access, then you should know what you're doing.
Just make changes directly. Subscribing to the <a
href="http://viewvc.tigris.org/servlets/ProjectMailingListList"
><tt>dev@</tt> developer mailing list</a> is recommended in any
case.</p>
</div>
<div class="section">
<h2 id="sec-security">Security</h2>
<p>Since ViewVC is used on the Internet, security is a major concern.
If you need to pass data from the request into an external program,
please don't use <code>os.system()</code> or
<code>os.popen()</code>. Please use the module
<code>lib/popen.py</code> that is included in the ViewVC
distribution instead.</p>
</div>
<div class="section">
<h2 id="sec-adding-features">Adding Features</h2>
<p>If you need a new configuration option think carefully, into which
section it belongs. Try to keep the content of
<code>cgi/viewvc.conf.dist</code> file and the library module
<code>lib/config.py</code> in sync.</p>
<p>Because ViewVC is a Web-based application, people will have ViewVC
URLs hyperlinked from other sites, embedded in emails, bookmarked
in their browsers, etc. It is very important to ensure that those
URLs continue to retrieve the information they were intended to
retrieve even if ViewVC is upgraded on the hosting server. In
other words, as new features require modifications to the <a
href="./url-reference.html">ViewVC URL schema</a>, make sure those
modifications preserve the existing functionality of all ViewVC
URLs.</p>
<p>The library subdirectory contains a module <code>debug.py</code>,
which you may find useful for performance testing.</p>
<p>If a new file or module is added, a new line in the installer
program <code>viewvc-install</code> is required.</p>
</div>
<div class="section">
<h2 id="sec-templates">Hacking on Templates</h2>
<p>The library module <code>ezt.py</code> contains a module docstring
which describes the directives used in the HTML templates used by
ViewVC. The templates themselves can be found in the
<code>templates</code> subdirectory. We're currently developing a
how-to guide for <a href="./template-authoring-guide.html">ViewVC
template customization</a>.</p>
</div>
<div class="section">
<h2 id="sec-releasing">Release Management</h2>
<p>There is a script, <code>tools/make-release</code>, which creates a
release directory and the various archive files that we distribute.
All other steps required to get a ViewVC release out of the door
require manual execution (currently by C. Michael Pilato). Those
steps are as follows:</p>
<ol>
<li>Add a new subsection to the file
<code>website/upgrading.html</code> describing all user visible
changes for users of previous releases of ViewVC.</li>
<li>Update the <code>CHANGES</code> file</li>
<li>Update the <code>website/index.html</code> file to refer to the
new X.Y files. (there are three links to update)</li>
<li>Edit the file <code>lib/viewvc.py</code> and remove the
<tt>"-dev"</tt> suffix from <code>__version__</code>. The
remainder should be of the form X.Y.Z, where X, Y, and Z are
positive integers.</li>
<li>Ensure all of the above changes have been committed.</li>
<li>Test, Test, Test! At the time of this writing (1.0-dev) there
is no automatic testsuite available. So just run with
permuting different <code>viewvc.conf</code> settings&hellip;
and pray.</li>
<li>Review any open <a
href="http://viewvc.tigris.org/servlets/ProjectIssues">bug
reports.</a></li>
<li>Use <code>svn cp</code> to tag the release to
<code>/tags/<i>X</i>.<i>Y</i>.<i>Z</i></code>, where
<i>X</i>, <i>Y</i>, and <i>Z</i> should be replaced by the
release number from above. If a developer is willing to
volunteer as a bug fix patch release manager, it is now
possible to start here at this point with a feature-frozen
branch using <code>svn cp</code> to copy the tag to
<code>/branches/<i>X</i>.<i>Y</i>.x</code>.</li>
<li>Go into an empty directory and run <code>tools/make-release
viewvc-<i>X.Y.Z</i> <i>X.Y.Z</i></code>. This step requires
read access to the Subversion source code repository.</li>
<li>Upload the created archive files (tar.gz and zip) into the
Files and Documents section of the Tigris.org project.</li>
<li>Edit the file <code>lib/viewvc.py</code> again and this time
increment the <code>__version__</code> for the next release
cycle, again append the <code>-dev</code> to the version and
again <code>svn commit -m "Begin a new release cycle."
lib/viewvc.py</code>.</li>
<li>Write an announcement explaining all the cool new features and
post it <a
href="mailto:&#97&#110&#110&#111&#117&#110&#99&#101&#64&#118&#105&#101&#119&#118&#99&#46&#116&#105&#103&#114&#105&#115&#46&#111&#114&#103">&#97&#110&#110&#111&#117&#110&#99&#101&#64&#118&#105&#101&#119&#118&#99&#46&#116&#105&#103&#114&#105&#115&#46&#111&#114&#103</a>,
to the project's News area, and to other places interested in
this sort of stuff (such as <a
href="http://www.freshmeat.net">Freshmeat</a>).</p>
</ol>
</div>
</td>
</tr>
</table>
</body>
</html>

View File

@@ -1,79 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>ViewVC: Download</title>
<link rel="stylesheet" type="text/css" href="./styles.css"/>
</head>
<body>
<div id="title">
<a href="http://www.viewvc.org/"><img
src="./images/title.jpg" alt="ViewVC: Repository Browsing"/></a>
</div>
<div id="menu">
<p><a href="./index.html">Home</a> |
<a href="http://viewvc.tigris.org/">Project Page</a> |
<a href="./download.html">Download</a> |
<a href="./upgrading.html">Upgrading</a> |
<a href="./contributing.html">Contributing</a> |
<a href="./license-1.html">License</a> |
<a href="./contact.html">Contact</a> |
<a href="./who.html">About</a>
</p>
</div>
<table id="pagetable">
<tr>
<td id="pagecolumn1">
<h4>On this page:</h4>
<ul id="bookmarks">
<li><a href="#sec-download">Downloading</a></li>
<li><a href="#sec-subversion">Subversion</a></li>
</ul>
<hr/>
<address><a href="mailto:&#117&#115&#101&#114&#115&#64&#118&#105&#101&#119&#118&#99&#46&#116&#105&#103&#114&#105&#115&#46&#111&#114&#103">ViewVC Users Group</a></address>
</td>
<td id="pagecolumn2">
<div class="section">
<h2 id="sec-download">Downloading</h2>
<p>You can download the ViewVC (and the older ViewCVS releases, too)
from our <a
href="http://viewvc.tigris.org/servlets/ProjectDocumentList?folderID=6004"
>File and Documents</a> area. For information about what has
changed in each release, see the <a
href="http://viewvc.tigris.org/source/browse/viewvc/trunk/CHANGES?rev=HEAD"
>CHANGES</a> file.</p>
<p>We are also making <a href="./nightly/">nightly snapshots</a>
available in tar.gz and zip formats.</p>
</div>
<div class="section">
<h2 id="sec-subversion">Subversion</h2>
<p>The source code for ViewVC is maintained in a Subversion repository
at Tigris.org. You can checkout the trunk of our development tree
from <a href="http://viewvc.tigris.org/svn/viewvc/trunk/"
><tt>http://viewvc.tigris.org/svn/viewvc/trunk/</tt></a>. You'll
need to provide your Tigris.org username and password when so
prompted, or, if you don't have a Tigris.org account, use "guest"
as both the username and password.</p>
</div>
</td>
</tr>
</table>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

View File

@@ -1,192 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>ViewVC: Repository Browsing</title>
<link rel="stylesheet" type="text/css" href="./styles.css"/>
</head>
<body>
<div id="title">
<a href="http://www.viewvc.org/"><img
src="./images/title.jpg" alt="ViewVC: Repository Browsing"/></a>
</div>
<div id="menu">
<p><a href="./index.html">Home</a> |
<a href="http://viewvc.tigris.org/">Project Page</a> |
<a href="./download.html">Download</a> |
<a href="./upgrading.html">Upgrading</a> |
<a href="./contributing.html">Contributing</a> |
<a href="./license-1.html">License</a> |
<a href="./contact.html">Contact</a> |
<a href="./who.html">About</a>
</p>
</div>
<table id="pagetable">
<tr>
<td id="pagecolumn1">
<h4>On this page:</h4>
<ul id="bookmarks">
<li><a href="#sec-what-is-viewvc">What Is ViewVC?</a></li>
<li><a href="#sec-requirements">Requirements</a></li>
<li><a href="#sec-future">Future Plans</a></li>
</ul>
<hr/>
<address><a href="mailto:&#117&#115&#101&#114&#115&#64&#118&#105&#101&#119&#118&#99&#46&#116&#105&#103&#114&#105&#115&#46&#111&#114&#103">ViewVC Users Group</a></address>
</td>
<td id="pagecolumn2">
<div class="section">
<h2 id="sec-what-is-viewvc">What Is ViewVC?</h2>
<p>ViewVC is a browser interface for CVS and Subversion version
control repositories. It generates templatized HTML to present
navigable directory, revision, and change log listings. It can
display specific versions of files as well as diffs between those
versions. Basically, ViewVC provides the bulk of the report-like
functionality you expect out of your version control tool, but much
more prettily than the average textual command-line program
output.</p>
<p>Here are some of the additional features of ViewVC:</p>
<ul>
<li>Support for filesystem-accessible CVS and Subversion repositories.</li>
<li>Individually configurable virtual host support.</li>
<li>Line-based annotation/blame display.</li>
<li>Revision graph capabilities (via integration with <a
href="http://www.akhphd.au.dk/~bertho/cvsgraph/">CvsGraph</a>)
(<em>CVS only</em>).</li>
<li>Syntax highlighting support (via integration with <a
href="http://www.codento.com/people/mtr/genscript/">GNU
enscript</a> or
<a href="http://www.andre-simon.de/">Highlight</a>).</li>
<li><a href="http://www.mozilla.org/projects/bonsai/">Bonsai</a>-like
repository query facilities.</li>
<li>Template-driven output generation.</li>
<li>Colorized, side-by-side differences.</li>
<li>Tarball generation (by tag/branch for CVS, by revision for
Subversion).</li>
<li>I18N support based on the Accept-Language request header.</li>
<li>Ability to run either as CGI script or as a standalone
server.</li>
<li>Regexp-based file searching.</li>
<li>INI-like configuration file (as opposed to requiring actual code
tweaks).</li>
</ul>
<p>For a complete list of changes present in each release, see
ViewVC's <a
href="http://viewvc.tigris.org/source/browse/viewvc/trunk/CHANGES?rev=HEAD"
>CHANGES</a> file.</p>
</div>
<div class="section">
<h2 id="sec-requirements">Requirements</h2>
<p>The only hard software requirement for running ViewVC is <a
href="http://www.python.org/">Python 1.5.2</a> or later. All other
requirements depend on what you want to do with the tool.</p>
<p>If you plan to use ViewVC with CVS repositories, you need the
following things:</p>
<ul>
<li><a href="http://www.cs.purdue.edu/homes/trinkle/RCS/">RCS</a>
(Revision Control System)</li>
<li><a href="http://www.gnu.org/software/diffutils/diffutils.html">GNU
diff</a></li>
<li>Read-only, physical access to a CVS repository.</li>
</ul>
<p>For use with Subversion repositories, you need these things:</p>
<ul>
<li><a href="http://subversion.tigris.org/">Subversion</a> 1.2 or
later and its SWIG Python bindings.</li>
<li><a href="http://www.gnu.org/software/diffutils/diffutils.html">GNU
diff</a></li>
<li>Physical access to a Subversion repository (though there is
limited, use-at-your-risk support for remote access, too).</li>
</ul>
<p>ViewVC integrates with additional pieces of software to provide
certain bits of optional functionality:</p>
<ul>
<li><a href="http://www.mysql.com/">MySQL</a> &mdash; Needed to use
the commit database query functionality.</li>
<li><a href="http://www.codento.com/people/mtr/genscript/">GNU
enscript</a> &mdash; Needed for syntax highlighting in versioned
file contents displays</li>
<li><a href="http://www.akhphd.au.dk/~bertho/cvsgraph/">CvsGraph</a>
&mdash; Needed for version graph displays.</li>
<li><a href="http://httpd.apache.org/">Apache HTTP Server</a>, or
another server capable of running CGI programs &mdash; unless
you just want ViewVC to run in standalone server mode.</li>
</ul>
</div>
<div class="section">
<h2 id="sec-future">Future Plans</h2>
<p>ViewVC is an Open Source project. So any future development
depends on the <a href="./contributing.html">contributions</a> that
will be made by its user community. Certainly working patches have
a greater chance to become realized quickly than feature requests,
but please don't hesitate to submit your suggestions to our <a
href="http://viewvc.tigris.org/servlets/ProjectIssues">issue
tracker</a>.</p>
<p>Some things we're thinking about include:</p>
<ul>
<li>UI streamlining/simplification.</li>
<li>Integration with CVS and Subversion commit mail scripts.</li>
<li>Integration with an indexer such as LXR.</li>
</ul>
</div>
</td>
</tr>
</table>
</body>
</html>

View File

@@ -1,151 +0,0 @@
body {
background-color: rgb(180,193,205);
background-image: url('./images/bg-grad.jpg');
background-repeat: repeat-x;
color: black;
font-family: arial, sans-serif;
font-size: 90%;
margin: 0;
}
#title {
background-color: rgb(100,128,150);
height: 60px;
}
img {
border: none;
}
hr {
width: 95%;
height: 1px;
}
address {
text-align: center;
font-size: 60%;
font-style: normal;
}
h2 {
background-color: rgb(204,213,221);
padding: 2px 0.5em 2px 0.5em;
margin: 0;
border-bottom: dotted 1px rgb(180,193,205);
font-size: 110%;
}
h3 {
padding: 2px 0.5em 2px 0.5em;
margin: 0;
font-size: 100%;
font-weight: bold;
}
h4 {
padding: 2px 0.5em 2px 0.5em;
margin: 0;
font-size: 90%;
font-weight: bold;
}
p, dl, ul, ol {
padding: 0.5em;
margin: 0;
font-size: 90%;
}
ul, ol {
padding: 0.5em;
margin: 0 0 0 0.25in;
}
li {
font-size: 90%;
}
code {
font-size: 105%;
font-style: italic;
font-family: monospace;
}
blockquote {
padding: 0.5em;
margin: 0 0.25in 0 0.25in;
font-size: 80%;
}
.section {
background: white;
border-color: rgb(24,24,24);
border-width: 1px 2px 2px 1px;
border-style: solid;
padding: 0;
margin-bottom: 0.5em;
}
#menu {
background: black;
color: white;
}
#menu a, #menu a:visited {
background: black;
color: white;
text-decoration: none;
}
#menu a:hover {
background: black;
color: white;
text-decoration: underline;
}
#submenu {
background: rgb(90%,97%,99%);
font-size: 80%;
}
#pagetable tr {
vertical-align: top;
}
#pagetable {
width: 100%;
}
#pagecolumn1 {
width: 175px;
padding: 0;
}
#pagecolumn1 a, #pagecolumn1 a:visited {
color: rgb(0,0,164);
text-decoration: none;
}
#pagecolumn1 a:hover {
text-decoration: underline;
}
#pagecolumn2 {
padding: 0;
}
#pagecolumn2 a, #pagecolumn2 a:visited {
color: rgb(0,0,164);
text-decoration: underline;
}
#pagecolumn2 a:hover {
background-color: rgb(180,193,205);
text-decoration: underline;
}
#bookmarks {
padding-left: 0.25in;
font-size: 80%;
white-space: nowrap;
}

View File

@@ -1,159 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>ViewVC: About</title>
<link rel="stylesheet" type="text/css" href="./styles.css"/>
</head>
<body>
<div id="title">
<a href="http://www.viewvc.org/"><img
src="./images/title.jpg" alt="ViewVC: Repository Browsing"/></a>
</div>
<div id="menu">
<p><a href="./index.html">Home</a> |
<a href="http://viewvc.tigris.org/">Project Page</a> |
<a href="./download.html">Download</a> |
<a href="./upgrading.html">Upgrading</a> |
<a href="./contributing.html">Contributing</a> |
<a href="./license-1.html">License</a> |
<a href="./contact.html">Contact</a> |
<a href="./who.html">About</a>
</p>
</div>
<table id="pagetable">
<tr>
<td id="pagecolumn1">
<h4>On this page:</h4>
<ul id="bookmarks">
<li><a href="#sec-history">The History of ViewVC</a></li>
<li><a href="#sec-viewcvs-group">The ViewCVS Group</a></li>
<li><a href="#sec-site-credits">About This Site</a></li>
</ul>
<hr/>
<address><a href="mailto:&#117&#115&#101&#114&#115&#64&#118&#105&#101&#119&#118&#99&#46&#116&#105&#103&#114&#105&#115&#46&#111&#114&#103">ViewVC Users Group</a></address>
</td>
<td id="pagecolumn2">
<div class="section">
<h2 id="sec-history">The History of ViewVC</h2>
<p>The ViewVC software was inspired by <a
href="http://people.freebsd.org/~fenner/cvsweb/">cvsweb</a>
(originally written by Bill Fenner and then further developed by <a
href="mailto:zeller@think.de">Henner Zeller</a>). Greg Stein
wanted to make some changes and updates, but cvsweb was implemented
in Perl. He wrote:</p>
<blockquote style="font-style: italic;">&quot;While I can manage some
Perl, cvsweb was rather unmaintainable for me. So I undertook the
task to convert the software to Python. As a result, I've actually
been able to go <em>way</em> beyond the simple changes that I had
envisioned.&quot;</blockquote>
<p>So ViewVC started out as just a port of the cvsweb script,
originally called ViewCVS. Along the way, it has had numerous
cleanups and other modifications, a process simplified by the
elegance of the <a href="http://www.python.org/">Python</a>
language.</p>
<p>In 2001, the ViewCVS project was moved to <a
href="http://www.sourceforge.net">SourceForge</a>, a popular
software collaboration environment. There the project continued to
mature, releasing several stable-yet-pre-1.0 versions. In 2002,
C. Michael Pilato began implementing support for Subversion in
ViewCVS, building atop the beginnings of a version control
abstraction layer begun by Lucas Bruand. Along the way, Russell
Yanofsky delivered large improvements to that abstraction, and to
ViewCVS as whole. ViewCVS was well on its way to releasing a 1.0
version.</p>
<p>Of course, now that ViewCVS could browse Subversion repositories as
easily as CVS ones, the ViewCVS name seemed inappropriate. Also,
SourceForge's lack of support for Subversion (which was already
well past its 1.0 release, and becoming hugely popular) in its
project version control offerings was annoying ViewCVS primary
developers. So in late 2005, the decision was made to rename the
project to ViewVC, to convert the project's CVS data to Subversion,
and to move the project and its Subversion data to <a
href="http://www.tigris.org">Tigris.org</a>.</p>
<p>Today, ViewVC is being developed at <a
href="http://viewvc.tigris.org">http://viewvc.tigris.org</a> by a
small community of folks</a>.</p>
</div>
<div class="section">
<h2 id="sec-viewcvs-group">The ViewCVS Group</h2>
<p>The ViewCVS Group is an informal group of people working on and
developing the ViewVC package. The current set of members are
listed below with some of their notable contributions:</p>
<dl>
<dt><a href="http://www.lyra.org/greg/">Greg Stein</a></dt>
<dd>original python port of Henner Zeller's cvsweb, secure popen
implementation, configuration file implementation, rcsparse
module, and EZT template engine</dd>
<dt>Jay Painter</dt>
<dd>CVSdb query engine</dd>
<dt>Tanaka Akira</dt>
<dd>enscript colorization and tarball generation
</dd>
<dt>Tim Cera</dt>
<dd>CvsGraph support, log_table template, regular expression search,
and paging capability</dd>
<dt>Peter Funk</dt>
<dd>standalone server, blimp logo, and numerous improvements to
ViewVC's interfaces and documentation</dd>
<dt>Lucas Bruand</dt>
<dd>C++ RCS parser (tparse) and vclib module for supporting new
version control systems</dd>
<dt><a href="http://www.cmichaelpilato.com/">C. Michael Pilato</a></dt>
<dd>Subversion support, root_as_url alternative URL scheme,
templatization work, website design, documentation</dd>
<dt>Russell Yanofsky</dt>
<dd>Windows support and the sapi module for supporting multiple web
server interfaces, sweeping abstraction and UI improvements</dd>
<dt>James Henstridge</dt>
<dd>integrated query interface, support for querying Subversion
repositories, caching support, CSS formatting, and the EZT
&quot;define&quot; directive</dd>
</dl>
</div>
<div class="section">
<h2 id="sec-site-credits">About This Site</h2>
<p>The ViewVC website was designed by <a
href="http://www.cmichaelpilato.com/">C. Michael Pilato</a>. All
HTML was hand-edited in Emacs, and the little splashes of graphical
goodness owe their existence to Adobe PhotoShop. Textual content
for the site is mostly the work of Greg Stein, but has been tweaked
through the ages by various ViewVC contributors.</p>
</div>
</td>
</tr>
</table>
</body>
</html>

View File

@@ -1,70 +0,0 @@
<html>
<head>
<title>ViewVC - Version Control Repository Browser</title>
<!-- Custom stylations to hide the obnoxious project info -->
<style type="text/css">
#projecthome .axial { display: none; }
#apphead h1 { display: none; }
#longdescription { border: none; }
#longdescription h2 { display: none; }
#customcontent h2 { display: block; }
</style>
<!-- End custom stylations -->
</head>
<body>
<div class="app" id="customcontent">
<h1>ViewVC &mdash; Web-based Version Control Repository Browsing</h1>
<div class="h2">
<h2>Latest Release</h2>
<p>The most recent release of ViewVC is: <strong>1.0.0-rc1</strong></p>
</div>
<div class="h2">
<h2>What Is ViewVC?</h2>
<p>ViewVC is a browser interface for CVS and Subversion version
control repositories. It generates templatized HTML to present
navigable directory, revision, and change log listings. It can
display specific versions of files as well as diffs between those
versions. Basically, ViewVC provides the bulk of the report-like
functionality you expect out of your version control tool, but much
more prettily than the average textual command-line program
output.</p>
<p>Here are some of the additional features of ViewVC:</p>
<ul>
<li>Support for filesystem-accessible CVS and Subversion repositories</li>
<li>Individually configurable virtual host support</li>
<li>Line-based annotation/blame display</li>
<li>Revision graph capabilities (<em>CVS only</em>)</li>
<li>Syntax highlighting support</li>
<li>Commit metadata query facilities</li>
<li>Template-driven output generation</li>
<li>Colorized, side-by-side differences</li>
<li>Tarball generation (by tag/branch for CVS, by revision for
Subversion)</li>
<li>Localization support based on the Accept-Language request header</li>
<li>Ability to run either as CGI script or as a standalone
server</li>
<li>Regexp-based file searching</li>
<li>INI-like configuration file (as opposed to requiring actual code
tweaks)</li>
</ul>
<p>For a complete list of changes present in each release, see
ViewVC's <a
href="http://viewvc.tigris.org/source/browse/viewvc/trunk/CHANGES?rev=HEAD"
>CHANGES</a> file.</p>
</div>
</div>
</body>
</html>

View File

@@ -1,30 +0,0 @@
<!-- Overrides the left-nav tool bar on viewvc.tigris.org, a feature
specific to tigris.org's CEE branding. See www/overrides/ in the
look.tigris.org project for details. -->
<!-- dd --><ul>
<li><a href="http://www.viewvc.org/"
>Project website</a></li>
<!-- #################################################### --></ul></dd><dd><ul>
<li><a href="http://viewvc.tigris.org/servlets/ProjectMemberList"
>Membership</a></li>
<!-- #################################################### --></ul></dd><dd><ul>
<li><a href="http://viewvc.tigris.org/servlets/ProjectNewsList"
>Announcements</a></li>
<!-- li><a href="http://viewvc.tigris.org/servlets/ProjectForumView"
>Discussion forums</a></li -->
<li><a href="http://viewvc.tigris.org/servlets/ProjectMailingListList"
>Mailing lists</a></li>
<li><a href="http://viewvc.tigris.org/servlets/ProjectDocumentList"
>Documents &amp; files</a></li>
<li><a href="http://viewvc.tigris.org/source/browse/viewvc/"
>Subversion</a></li>
<li><a href="http://viewvc.tigris.org/issues/buglist.cgi?component=viewvc&amp;issue_status=UNCONFIRMED&amp;issue_status=NEW&amp;issue_status=STARTED&amp;issue_status=REOPENED"
>Issue tracker</a></li>
</ul><!-- /dd -->