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

Compare commits

...

41 Commits

Author SHA1 Message Date
cmpilato
6956afae73 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.1.0@2451 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-08 16:51:21 +00:00
cmpilato
80a5efb953 Tag the 1.1.0 final release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/tags/1.1.0@2161 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-13 13:50:12 +00:00
cmpilato
8843044571 Tag the 1.1.0 final release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/tags/1.1.0@2158 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-13 13:36:38 +00:00
cmpilato
8b426f6fb3 Merge from trunk r2152, recording 1.0.8's CHANGES here.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2153 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 17:26:56 +00:00
cmpilato
19ee8b32df Record a merge that effectively happened in r2147.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2148 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 17:09:57 +00:00
cmpilato
a5389019fa Bump copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2147 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 17:09:01 +00:00
cmpilato
7f272fbe04 Merge from trunk r2123 and r2124, the log message summary of which is:
Try to make ViewVC provide a consistent, predictable data dictionary
   in all of its templated views.  Do this with a custom, dictionary-like
   class that prevents the creation of new keys after an initial
   instantiation of keys and (possibly dummy) values.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2144 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 17:01:10 +00:00
cmpilato
89edf0ac04 Merge from trunk r2142, whose log message read thusly:
Finish issue #402: Split the 'use_pagesize' configuration directive
   into two: 'log_pagesize' and 'dir_pagesize', individually controlling
   the size of pages used (if at all) for the revision log and directory
   views, respectively.
   
   * conf/viewvc.conf.dist
     (use_pagesize): Removed, in favor of...
     (dir_pagesize, log_pagesize): ...these.
   
   * lib/viewvc.py,
   * lib/config.py,
   * bin/standalone.py
     Replace the use and tooling around 'use_pagesize' with
     'dir_pagesize' and 'log_pagesize' as appropriate.
   
   * templates/include/paging.ezt,
   * templates/include/dir_header.ezt
     Stop using the option value to determine whether or not to show
     pagination UI.  Use the presence of some pages instead.
     
   * docs/upgrading-howto.html
     Note the changes in options.
   
   Patch by: Lei Zhang <thestig{_AT_}google.com>
             (Tweaked by me.)

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2143 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 15:49:50 +00:00
cmpilato
71fbec8871 Merge from trunk r2140, whose log message read thusly:
Fix the GUI mode of standalone.py -- it wasn't even starting
   correctly, and we don't need a toggle for 'enscript' any more.
   
   * bin/standalone.py
     (GUI.__init__): Pass the configuration file to handle_config().
       Lose 'enscript'-related stuff.
     (GUI.toggle_use_enscript): Remove.
     (cli): Fix call to gui(), dropping bogus parameter.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2141 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 15:35:06 +00:00
cmpilato
504b1e1a8a Merge from trunk r2137, whose log message read thusly:
Fix issue #409, an exception thrown when sorting by revision in a
   remote Subversion directory view.
   
   * lib/vclib/svn/svn_ra.py
     (RemoteSubversionRepository.dirlogs): Store the entry's revision as
       a string, for consistency with other vclib modules.
   
   Reported by: Wojciech Wróblewski <wojtek{_AT_}elmi.pl>

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2139 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 14:59:32 +00:00
cmpilato
cf9381e0ee Backport to the 1.1.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/svn_repos.py
     (_get_history): Add easy-out for repositories with 0 revisions.
   
   Reported by: Wojciech Wróblewski <wojtek{_AT_}elmi.pl>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2135 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-04 14:58:46 +00:00
cmpilato
3907172131 Merge from trunk r2128-2129.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2130 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-04-20 17:41:32 +00:00
cmpilato
c34752ce92 Merge from trunk r2121, whose log message read thusly:
* templates/include/file_header.ezt
     Lose template reference of 'log_href_rev', which was removed in
     r2116 as unused.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2122 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-24 16:34:22 +00:00
cmpilato
40cc23f12a Merge from trunk r2119, whose log message read thusly:
Clutterkiller!  Put the default configuration files into a conf/
   subdirectory.
   
   * conf/
     New subdirectory.
   
   * cvsgraph.conf.dist,
   * mimetypes.conf.dist,
   * viewvc.conf.dist
     Move these from here ...
   
   * conf/cvsgraph.conf.dist,
   * conf/mimetypes.conf.dist,
   * conf/viewvc.conf.dist
     ... to here.
   
   * viewvc-install
     (FILE_INFO_LIST): Track new locations of configuration files.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2120 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-19 20:44:47 +00:00
cmpilato
9b7fea99d4 Merge from trunk a few relavent and recent changes (r2110:2117).
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2118 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-19 18:09:29 +00:00
cmpilato
85949a6464 Merge from trunk r2107, which updates copyright info only.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2108 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-18 16:45:10 +00:00
cmpilato
d5291a6b98 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.1.x@2104 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-18 12:52:24 +00:00
cmpilato
9e41d171c9 Merge from trunk r2101, whose log message read thusly:
Finish issue #401: Support MIME type overrides in ViewVC configuration.
   Trade the 'mime_types_file' option for 'mime_types_files' -- an
   ordered list of MIME mapping files to consult.  And provide our own
   (empty) mapping file that folks can use to override the mappings
   provided by other such files.
   
   * mimetypes.conf.dist
     New file.
   
   * viewvc.conf.dist
     (mime_types_files): Was mime_types_file, and now accepts multiple values.
   
   * lib/config.py
     (Config._force_multi_value): Add "mime_types_files" to the list of
       multi-value configuration options.
     (Config.set_defaults): Track rename of mime_types_file parameter,
       now setting the default to a list containing only "mimetypes.conf".
   
   * lib/viewvc.py
     (load_config): Track new name and format of mime_types_files option.
   
   * viewvc-install
     (FILE_INFO_LIST): Also install mimetypes.conf.dist as itself and as
       mimetypes.conf.
   
   * INSTALL
     (INSTALLING VIEWVC): Update reference to renamed configuration option.
   
   * docs/upgrading-howto.html
     Update this document.

Also:

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2102 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-06 16:44:37 +00:00
cmpilato
da54e91dea 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.1.x@2099 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-26 16:15:55 +00:00
cmpilato
41b2ae2c7a Tweak a CHANGES entry for line length reduction.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2098 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-26 16:14:15 +00:00
cmpilato
1815220abe Note r2092 merge CHANGE.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2094 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-20 15:32:57 +00:00
cmpilato
a080d8eef4 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.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2092 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-20 15:24:39 +00:00
cmpilato
8c4af42d56 Merge from trunk r2088, whose log message read:
Remove dead code.
   
   * lib/popen.py
     (pipe_cmds, _copy): Remove as unused.
   
   * bin/standalone.py
     (StandaloneServer.run_viewvc): Tweak comment that referred to pipe_cmds().

   Found by: Rune Halvorsen <runeh {AT} sanedefaults.net>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2089 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-03 03:54:24 +00:00
cmpilato
7f1d0952fc Backport from trunk r2086, whose log message read thusly:
Fix issue #398 (File Log Viewer Shows Wrong Log Message) by asking the
   vclib layer for revision-sorted output rather than "whatever you want
   to give me".
   
   * lib/viewvc.py
     (markup_or_annotate): Pass vclib.SORTBY_REV instead of vclib.SORTBY_DEFAULT
       to the itemlog() interface.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2087 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-02 18:13:11 +00:00
cmpilato
222aa4ec1f Merge from trunk r2083.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2084 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-01-13 19:11:15 +00:00
cmpilato
c03bfd4b89 Merge from trunk r2081.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2082 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-01-13 18:52:33 +00:00
cmpilato
6fa8cdf117 On the 1.1.x branch: Merge from trunk r2078 and r2079.
* lib/cvsdb.py,
* bin/make-database


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2080 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-01-13 18:22:12 +00:00
cmpilato
c4c777ffe6 Backport from trunk r2070.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2071 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-19 19:49:13 +00:00
cmpilato
3680903ed4 Backport from trunk r2067 and r2068.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2069 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-19 19:46:55 +00:00
cmpilato
6fe61a11bb Merge from trunk r2063 and r2064.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2065 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-10 17:28:43 +00:00
cmpilato
437975652f Merge from trunk r2058, whose log message read thusly:
Allow admins to enable/disable diff/patch views via the allowed_views
   configuration bit.
   
   * lib/viewvc.py
     (view_diff, view_patch): Only show diffs if 'diff' is one of the
       allowed views.
   
   * lib/config.py
     (Config.set_defaults): Add 'diff' to the set of allowed_views (and
       sort the values alphabetically where here).
   
   * viewvc.conf.dist
     (allowed_views): Add 'diff' to the set of views you can specify, and
       include it in the default values.  While here, sort the values
       alphabetically.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2062 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-05 17:25:10 +00:00
cmpilato
7ff75bec7b Record recent merges to this branch.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2060 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-05 17:08:12 +00:00
cmpilato
ea03f20f46 Remove unnecessary empty mergeinfo.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2059 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-05 17:05:29 +00:00
cmpilato
a5df515d79 Merge from trunk r2047, whose log message read thusly:
Avoid returning huge lists of variables from get_file_view_info(), and
   use an ad-hoc class to hold all that stuff instead.
   
   * lib/viewvc.py
     (get_file_view_info): Now return an object with interesting
       member variables instead of a nasty long list of values in an
       easy-to-goof-up order.
     (common_template_data, view_directory, view_log, view_diff): Update
       uses of get_file_view_info to track new calling semantics.

Why?  Just trying to avoid unnecessary branch divergence.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2057 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-20 16:39:43 +00:00
cmpilato
fabe8e8a66 Merge from trunk r2055, whose log message read thusly:
Add a configuration option for telling ViewVC to *not* honor the
   svn:mime-type property.
   
   * lib/config.py
     (Config.set_defaults): Set options.svn_ignore_mimetype default value.
   
   * viewvc.conf.dist
     (svn_ignore_mimetype): New.
   
   * lib/viewvc.py
     (calculate_mime_type): Consult cfg.options.svn_ignore_mimetype
       before looking up the 'svn:mime-type' property.
   
   * docs/upgrading-howto.html
     Add a note about the new configuration option.
   
   Patch (mostly) by: JJ <eggsgloriouseggs {_AT_} gmail.com>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2056 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-13 21:45:08 +00:00
cmpilato
f01fcc4ec4 Merge from trunk r2053, whose log message read thusly:
It's very confusing to comment out the authorizer configuration line
   and have that mean "use an authorizer".  So let's just prevent that
   confusion right now, okay?
   
   * lib/config.py
     (Config.set_defaults): Set 'authorizer' by default to None.
   
   * viewvc.conf.dist
     (authorizer): Update comments for correctness, and don't imply that
       "forbidden" is the default authorizer.
   
   * docs/upgrading-howto.html
     Stop saying that "forbidden" is the default authorizer.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2054 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-13 21:22:05 +00:00
cmpilato
05e99f4c7b Merge from trunk r2051, whose log message read thusly:
Finish issue #384 - repos._revinfo_raw() is doing far too much work
   when no authz is in use.  Vastly improves performance of
   repos.itemlog() for local Subversion repositories *not* protected by
   an authorizer.
   
   * lib/vclib/svn/svn_repos.py
     (LocalSubversionRepository._revinfo): Was ._revinfo_raw().  Now
       encapsulates the caching logic that used to live in .revinfo(), plus
       the old logic of _revinfo_raw() modified to avoid changed-path
       processing when that processing isn't strictly required by callers.
     (LocalSubversionRepository.revinfo): Make this just a thin wrapper
       around ._revinfo() now.  Internal callers of this function updated
       to use ._revinfo() instead.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2052 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-13 21:16:25 +00:00
cmpilato
d8aff4e58f Merge r2048 from trunk.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2049 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-13 20:07:15 +00:00
cmpilato
e8d3d6ad89 docs/upgrading-howto.html: Don't claim as removed options not in 1.0.x.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2042 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-05 21:13:19 +00:00
cmpilato
1317088e3c * CHANGES: Combine some changes, and remove a now-bogus one.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2040 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-05 16:30:49 +00:00
cmpilato
fe81ee5969 Branch for 1.1 stabilization.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/1.1.x@2033 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-30 17:31:36 +00:00
40 changed files with 1104 additions and 719 deletions

20
CHANGES
View File

@@ -1,4 +1,4 @@
Version 1.1.0 (released ??-???-????)
Version 1.1.0 (released 13-May-2009)
* add support for full content diffs (issue #153)
* make many more data dictionary items available to all views
@@ -12,9 +12,7 @@ Version 1.1.0 (released ??-???-????)
* add support for query by log message (issues #22, #121)
* fix bug parsing 'svn blame' output with too-long author names (issue #221)
* fix default standalone.py port to be within private IANA range (issue #234)
* add support for integration with GNU source-highlight (issue #285)
* add unified configury of allowed views
* add support for disabling the checkout view (now the default state)
* add unified configury of allowed views; checkout view disabled by default
* add support for ranges of revisions to svndbadmin (issue #224)
* make the query handling more forgiving of malformatted subdirs (issue #244)
* add support for per-root configuration overrides (issue #371)
@@ -36,7 +34,19 @@ Version 1.1.0 (released ??-???-????)
* show RSS/query links only for roots found in commits database (issue #357)
* recognize Subversion svn:mime-type property values (issue #364)
* hide CVS files when viewing tags/branches on which they don't exist
* add support for hiding errorful entries from the directory view (issue #105)
* allow hiding of errorful entries from the directory view (issue #105)
* fix directory view sorting UI
* tolerate malformed Accept-Language headers (issue #396)
* allow MIME type mapping overrides in ViewVC configuration (issue #401)
* fix exception in rev-sorted remote Subversion directory views (issue #409)
* allow setting of page sizes for log and dir views individually (issue #402)
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)

View File

@@ -139,7 +139,7 @@ installation instructions.
default_root
root_as_url_component
rcs_dir
mime_types_file
mime_types_files
There are some other options that are usually nice to change. See
viewvc.conf for more information. ViewVC provides a working,

View File

@@ -15,7 +15,7 @@
<blockquote>
<p><strong>Copyright &copy; 1999-2008 The ViewCVS Group. All rights
<p><strong>Copyright &copy; 1999-2009 The ViewCVS Group. All rights
reserved.</strong></p>
<p>By using ViewVC, you agree to the terms and conditions set forth
@@ -59,6 +59,7 @@
<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 18, 2009 &mdash; copyright years updated</li>
</ul>
</body>

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2007 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
@@ -18,22 +18,22 @@
import os, sys, string
import popen2
import getopt
INTRO_TEXT = """\
This script creates the database and tables in MySQL used by the
ViewVC checkin database. You will be prompted for: database server
hostname, database user, database user password, and database name.
This script will use the 'mysql' program to create the database for
you. You will then need to set the appropriate parameters in the
[cvsdb] section of your viewvc.conf file.
"""
DATABASE_SCRIPT="""\
## ------------------------------------------------------------------------
## Stuff common to all schemas
##
DATABASE_SCRIPT_COMMON="""\
DROP DATABASE IF EXISTS <dbname>;
CREATE DATABASE <dbname>;
USE <dbname>;
"""
## ------------------------------------------------------------------------
## Version 0: The original, Bonsai-compatible schema.
##
DATABASE_SCRIPT_VERSION_0="""\
DROP TABLE IF EXISTS branches;
CREATE TABLE branches (
id mediumint(9) NOT NULL auto_increment,
@@ -121,28 +121,213 @@ CREATE TABLE tags (
) TYPE=MyISAM;
"""
## ------------------------------------------------------------------------
## Version 1: Adds the 'metadata' table. Adds 'descid' index to
## 'checkins' table, and renames that table to 'commits'.
##
DATABASE_SCRIPT_VERSION_1="""\
DROP TABLE IF EXISTS branches;
CREATE TABLE branches (
id mediumint(9) NOT NULL auto_increment,
branch varchar(64) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE branch (branch)
) TYPE=MyISAM;
DROP TABLE IF EXISTS commits;
CREATE TABLE commits (
type enum('Change','Add','Remove'),
ci_when datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
whoid mediumint(9) DEFAULT '0' NOT NULL,
repositoryid mediumint(9) DEFAULT '0' NOT NULL,
dirid mediumint(9) DEFAULT '0' NOT NULL,
fileid mediumint(9) DEFAULT '0' NOT NULL,
revision varchar(32) binary DEFAULT '' NOT NULL,
stickytag varchar(255) binary DEFAULT '' NOT NULL,
branchid mediumint(9) DEFAULT '0' NOT NULL,
addedlines int(11) DEFAULT '0' NOT NULL,
removedlines int(11) DEFAULT '0' NOT NULL,
descid mediumint(9),
UNIQUE repositoryid (repositoryid,dirid,fileid,revision),
KEY ci_when (ci_when),
KEY whoid (whoid),
KEY repositoryid_2 (repositoryid),
KEY dirid (dirid),
KEY fileid (fileid),
KEY branchid (branchid),
KEY descid (descid)
) TYPE=MyISAM;
DROP TABLE IF EXISTS descs;
CREATE TABLE descs (
id mediumint(9) NOT NULL auto_increment,
description text,
hash bigint(20) DEFAULT '0' NOT NULL,
PRIMARY KEY (id),
KEY hash (hash)
) TYPE=MyISAM;
DROP TABLE IF EXISTS dirs;
CREATE TABLE dirs (
id mediumint(9) NOT NULL auto_increment,
dir varchar(255) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE dir (dir)
) TYPE=MyISAM;
DROP TABLE IF EXISTS files;
CREATE TABLE files (
id mediumint(9) NOT NULL auto_increment,
file varchar(255) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE file (file)
) TYPE=MyISAM;
DROP TABLE IF EXISTS people;
CREATE TABLE people (
id mediumint(9) NOT NULL auto_increment,
who varchar(128) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE who (who)
) TYPE=MyISAM;
DROP TABLE IF EXISTS repositories;
CREATE TABLE repositories (
id mediumint(9) NOT NULL auto_increment,
repository varchar(64) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE repository (repository)
) TYPE=MyISAM;
DROP TABLE IF EXISTS tags;
CREATE TABLE tags (
repositoryid mediumint(9) DEFAULT '0' NOT NULL,
branchid mediumint(9) DEFAULT '0' NOT NULL,
dirid mediumint(9) DEFAULT '0' NOT NULL,
fileid mediumint(9) DEFAULT '0' NOT NULL,
revision varchar(32) binary DEFAULT '' NOT NULL,
UNIQUE repositoryid (repositoryid,dirid,fileid,branchid,revision),
KEY repositoryid_2 (repositoryid),
KEY dirid (dirid),
KEY fileid (fileid),
KEY branchid (branchid)
) TYPE=MyISAM;
DROP TABLE IF EXISTS metadata;
CREATE TABLE metadata (
name varchar(255) binary DEFAULT '' NOT NULL,
value text,
PRIMARY KEY (name),
UNIQUE name (name)
) TYPE=MyISAM;
INSERT INTO metadata (name, value) VALUES ('version', '1');
"""
BONSAI_COMPAT="""
WARNING: Creating Bonsai-compatible legacy database version. Some ViewVC
features may not be available, or may not perform especially well.
"""
## ------------------------------------------------------------------------
def usage_and_exit(errmsg=None):
stream = errmsg is None and sys.stdout or sys.stderr
stream.write("""\
Usage: %s [OPTIONS]
This script creates the database and tables in MySQL used by the
ViewVC checkin database. In order to operate correctly, it needs to
know the following: your database server hostname, database user,
database user password, and database name. (You will be prompted for
any of this information that you do not provide via command-line
options.) This script will use the 'mysql' program to create the
database for you. You will then need to set the appropriate
parameters in the [cvsdb] section of your viewvc.conf file.
Options:
--dbname=ARG Use ARG as the ViewVC database name to create.
[Default: ViewVC]
--help Show this usage message.
--hostname=ARG Use ARG as the hostname for the MySQL connection.
[Default: localhost]
--password=ARG Use ARG as the password for the MySQL connection.
--username=ARG Use ARG as the username for the MySQL connection.
--version=ARG Create the database using the schema employed by
version ARG of ViewVC. Valid values are:
[ "1.0" ]
""" % (os.path.basename(sys.argv[0])))
if errmsg is not None:
stream.write("[ERROR] %s.\n" % (errmsg))
sys.exit(1)
sys.exit(0)
if __name__ == "__main__":
try:
print INTRO_TEXT
# Parse the command-line options, if any.
dbname = version = hostname = username = password = None
opts, args = getopt.getopt(sys.argv[1:], '', [ 'dbname=',
'help',
'hostname=',
'password=',
'username=',
'version=',
])
if len(args) > 0:
usage_and_exit("Unexpected command-line parameters")
for name, value in opts:
if name == '--help':
usage_and_exit(0)
elif name == '--dbname':
dbname = value
elif name == '--hostname':
hostname = value
elif name == '--username':
username = value
elif name == '--password':
password = value
elif name == '--version':
if value in ["1.0"]:
version = value
else:
usage_and_exit("Invalid version specified")
# Prompt for necessary information
host = raw_input("MySQL Hostname [default: localhost]: ") or ""
user = raw_input("MySQL User: ")
passwd = raw_input("MySQL Password: ")
dbase = raw_input("ViewVC Database Name [default: ViewVC]: ") or "ViewVC"
# Prompt for information not provided via command-line options.
if hostname is None:
hostname = raw_input("MySQL Hostname [default: localhost]: ") or ""
if username is None:
username = raw_input("MySQL User: ")
if password is None:
password = raw_input("MySQL Password: ")
if dbname is None:
dbname = raw_input("ViewVC Database Name [default: ViewVC]: ") or "ViewVC"
# Create the database
dscript = string.replace(DATABASE_SCRIPT, "<dbname>", dbase)
host_option = host and "--host=%s" % (host) or ""
dscript = string.replace(DATABASE_SCRIPT_COMMON, "<dbname>", dbname)
if version == "1.0":
print BONSAI_COMPAT
dscript = dscript + DATABASE_SCRIPT_VERSION_0
else:
dscript = dscript + DATABASE_SCRIPT_VERSION_1
host_option = hostname and "--host=%s" % (hostname) or ""
if sys.platform == "win32":
cmd = "mysql --user=%s --password=%s %s "\
% (user, passwd, host_option)
% (username, password, host_option)
mysql = os.popen(cmd, "w") # popen2.Popen3 is not provided on windows
mysql.write(dscript)
status = mysql.close()
else:
cmd = "{ mysql --user=%s --password=%s %s ; } 2>&1" \
% (user, passwd, host_option)
% (username, password, host_option)
pipes = popen2.Popen3(cmd)
pipes.tochild.write(dscript)
pipes.tochild.close()
@@ -150,10 +335,11 @@ if __name__ == "__main__":
status = pipes.wait()
if status:
print "[ERROR] the database did not create sucessfully."
print "[ERROR] The database did not create sucessfully."
sys.exit(1)
print "Database created successfully."
print "Database created successfully. Don't forget to configure the "
print "[cvsdb] section of your viewvc.conf file."
except KeyboardInterrupt:
pass
sys.exit(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

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

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2007 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
@@ -226,9 +226,16 @@ If this doesn't work, please click on the link above.
save_stdout = sys.stdout
save_stderr = sys.stderr
# For external tools like enscript we also need to redirect
# the real stdout file descriptor. (On windows, reassigning the
# sys.stdout variable is sufficient because pipe_cmds makes it
# the standard output for child processes.)
# the real stdout file descriptor.
#
# FIXME: This code used to carry the following comment:
#
# (On windows, reassigning the sys.stdout variable is sufficient
# because pipe_cmds makes it the standard output for child
# processes.)
#
# But we no longer use pipe_cmds. So at the very least, the
# comment is stale. Is the code okay, though?
if sys.platform != "win32": save_realstdout = os.dup(1)
try:
try:
@@ -375,7 +382,7 @@ def gui(host, port):
# Early loading of configuration here. Used to
# allow tinkering with configuration settings through the gui:
handle_config()
handle_config(options.config_file)
if not LIBRARY_DIR:
cfg.options.cvsgraph_conf = "../cgi/cvsgraph.conf.dist"
@@ -389,14 +396,6 @@ def gui(host, port):
command=self.toggle_use_cvsgraph)
self.cvsgraph_toggle.pack(side='top', anchor='w')
# enscript toggle:
self.enscript_ivar = Tkinter.IntVar()
self.enscript_ivar.set(cfg.options.use_enscript)
self.enscript_toggle = Tkinter.Checkbutton(self.options_frm,
text="enable enscript (needs binary)", var=self.enscript_ivar,
command=self.toggle_use_enscript)
self.enscript_toggle.pack(side='top', anchor='w')
# show_subdir_lastmod toggle:
self.subdirmod_ivar = Tkinter.IntVar()
self.subdirmod_ivar.set(cfg.options.show_subdir_lastmod)
@@ -422,16 +421,27 @@ def gui(host, port):
command=self.toggle_use_localtime)
self.use_localtime_toggle.pack(side='top', anchor='w')
# use_pagesize integer var:
self.usepagesize_lbl = Tkinter.Label(self.options_frm,
text='Paging (number of items per page, 0 disables):')
self.usepagesize_lbl.pack(side='top', anchor='w')
self.use_pagesize_ivar = Tkinter.IntVar()
self.use_pagesize_ivar.set(cfg.options.use_pagesize)
self.use_pagesize_entry = Tkinter.Entry(self.options_frm,
width=10, textvariable=self.use_pagesize_ivar)
self.use_pagesize_entry.bind('<Return>', self.set_use_pagesize)
self.use_pagesize_entry.pack(side='top', anchor='w')
# log_pagesize integer var:
self.log_pagesize_lbl = Tkinter.Label(self.options_frm,
text='Paging (number of items per log page, 0 disables):')
self.log_pagesize_lbl.pack(side='top', anchor='w')
self.log_pagesize_ivar = Tkinter.IntVar()
self.log_pagesize_ivar.set(cfg.options.log_pagesize)
self.log_pagesize_entry = Tkinter.Entry(self.options_frm,
width=10, textvariable=self.log_pagesize_ivar)
self.log_pagesize_entry.bind('<Return>', self.set_log_pagesize)
self.log_pagesize_entry.pack(side='top', anchor='w')
# dir_pagesize integer var:
self.dir_pagesize_lbl = Tkinter.Label(self.options_frm,
text='Paging (number of items per dir page, 0 disables):')
self.dir_pagesize_lbl.pack(side='top', anchor='w')
self.dir_pagesize_ivar = Tkinter.IntVar()
self.dir_pagesize_ivar.set(cfg.options.dir_pagesize)
self.dir_pagesize_entry = Tkinter.Entry(self.options_frm,
width=10, textvariable=self.dir_pagesize_ivar)
self.dir_pagesize_entry.bind('<Return>', self.set_dir_pagesize)
self.dir_pagesize_entry.pack(side='top', anchor='w')
# directory view template:
self.dirtemplate_lbl = Tkinter.Label(self.options_frm,
@@ -507,9 +517,6 @@ def gui(host, port):
def toggle_use_cvsgraph(self, event=None):
cfg.options.use_cvsgraph = self.cvsgraph_ivar.get()
def toggle_use_enscript(self, event=None):
cfg.options.use_enscript = self.enscript_ivar.get()
def toggle_use_localtime(self, event=None):
cfg.options.use_localtime = self.use_localtime_ivar.get()
@@ -519,8 +526,11 @@ def gui(host, port):
def toggle_useresearch(self, event=None):
cfg.options.use_re_search = self.useresearch_ivar.get()
def set_use_pagesize(self, event=None):
cfg.options.use_pagesize = self.use_pagesize_ivar.get()
def set_log_pagesize(self, event=None):
cfg.options.log_pagesize = self.log_pagesize_ivar.get()
def set_dir_pagesize(self, event=None):
cfg.options.dir_pagesize = self.dir_pagesize_ivar.get()
def set_templates_log(self, event=None):
cfg.templates.log = self.logtemplate_svar.get()
@@ -614,7 +624,7 @@ def cli(argv):
if pid != 0:
sys.exit()
if options.start_gui:
gui(options.host, options.port, options.config_file)
gui(options.host, options.port)
return
elif options.port:
def ready(server):

View File

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

32
conf/mimetypes.conf.dist Normal file
View File

@@ -0,0 +1,32 @@
#---------------------------------------------------------------------------
#
# MIME type mapping file for ViewVC
#
# Information on ViewVC is located at the following web site:
# http://viewvc.org/
#
#---------------------------------------------------------------------------
# THE FORMAT OF THIS FILE
#
# This file contains records -- one per line -- of the following format:
#
# MIME_TYPE [EXTENSION [EXTENSION ...]]
#
# where whitespace separates the MIME_TYPE from the EXTENSION(s),
# and the EXTENSIONs from each other.
#
# For example:
#
# text/x-csh csh
# text/x-csrc c
# text/x-diff diff patch
# image/png png
# image/jpeg jpeg jpg jpe
#
# By default, this file is left empty, allowing ViewVC to continue
# consulting it first without overriding the MIME type mappings
# found in more standard mapping files (such as those provided as
# part of the operating system or web server software).
#
#

View File

@@ -60,7 +60,7 @@
# default_root
# root_as_url_component
# rcs_dir
# mime_types_file
# mime_types_files
# the many options in the [utilities] section
#
# It is usually desirable to change the following variables:
@@ -127,13 +127,26 @@ cvs_roots = cvs: /home/cvsroot
default_root = cvs
#
# This is a pathname to a MIME types file to help viewvc to guess the
# correct MIME type on checkout. If you are having problems with the
# default guess on the MIME type, then uncomment this option and point
# it at a MIME type file.
# This is a list of pathnames to a set of MIME type mapping files to
# help ViewVC guess the correct MIME type of a versioned file. The
# pathnames listed here are specified in order of authoritativeness
# either as absolute paths or relative to this configuration file.
#
# For example, you can use the mime.types provided by Apache here:
#mime_types_file = /usr/local/apache2/conf/mime.types
# As a convenience, ViewVC provides a MIME type mapping file
# (mimetypes.conf) which is, by default, the preferred provider of
# MIME type mapping answers, but which is also empty. If you find
# that ViewVC is unable to accurately guess MIME types based on the
# extensions of some of your versioned files, you can add records of
# your preferred mappings to the provided mimetypes.conf file (or to
# your system's mapping files, if you wish).
#
# You might, for example, wish to have ViewVC also consult the mapping
# files provided by your operating system and Apache.
#
# mime_types_files = mimetypes.conf,
# /etc/mime.types,
# /usr/local/apache2/conf/mime.types
mime_types_files = mimetypes.conf
# The address of the local repository maintainer. (This option is
# provided only as a convenience for ViewVC installations which are
@@ -266,8 +279,8 @@ checkout_magic = 0
# allowed_views: List the ViewVC views which are enabled. Views not
# in this comma-delited list will not be served (or, will return an
# error on attempted access).
# Possible values: "tar", "annotate", "co", "markup", "roots"
allowed_views = markup, annotate, roots
# Possible values: "annotate", "co", "diff", "markup", "roots", "tar"
allowed_views = annotate, diff, markup, roots
# authorizer: The name of the ViewVC authorizer plugin to use when
# authorizing access to repository contents. This value must be the
@@ -286,9 +299,9 @@ allowed_views = markup, annotate, roots
# NOTE: Only one authorizer may be in use for a given ViewVC request.
# It doesn't matter if you configure the parameters of multiple
# authorizer plugins -- only the authorizer whose name is configured
# here (or effectively configured here via vhost configuration) will
# be activated.
authorizer = forbidden
# here (or effectively configured here via per-vhost or per-root
# configuration) will be activated.
authorizer =
# hide_cvsroot: Don't show the CVSROOT directory
# 1 Hide CVSROOT directory
@@ -332,6 +345,13 @@ http_expiration_time = 600
# 0 Don't generate Etags
generate_etags = 1
# Don't use the svn:mime-type property to determine how to display a
# file in the markup view. This is especially helpful when versioned
# images carry the default Subversion-calculated MIME type of
# "application/octet-stream" (which isn't recognized as viewable type
# by browsers).
svn_ignore_mimetype = 0
# svn_config_dir: Path of the Subversion runtime configuration
# directory ViewVC should consult for various things, including cached
# remote authentication credentials. If unset, Subversion will use
@@ -506,13 +526,22 @@ use_re_search = 0
# use_re_search = 1
#
# Split directories and logs into pages.
# Allows ViewVC to present discrete pages to the users instead of the
# entire log or directory.
# Set use_pagesize to the number of entries you want displayed on a page.
# Split directory listings across pages as needed. Allows ViewVC to
# present discrete pages to the users instead of the entire directory.
# Set dir_pagesize to the number of entries you want displayed on a page,
# or 0 to disable pagination.
#
use_pagesize = 0
# use_pagesize = 20
dir_pagesize = 0
# dir_pagesize = 20
#
# Split revision log listings across multiple pages as needed. Allows
# ViewVC to present discrete pages to the users instead of the entire log.
# Set log_pagesize to the number of entries you want displayed on a page,
# or 0 to disable pagination.
#
log_pagesize = 0
# log_pagesize = 20
# Limit number of changed paths shown per commit in the Subversion revision
# view and in query results. This is not a hard limit (the UI provides

View File

@@ -161,12 +161,6 @@ td {
resource. Valid only when <var>pathtype</var> is <tt>file</tt>
or (for Subversion roots) <tt>dir</tt>.</td>
</tr>
<tr class="varlevel1">
<td class="varname">log_rev_href</td>
<td>String</td>
<td>Revision number of the file-revision currently being viewed, or
None.</td>
</tr>
<tr class="varlevel1">
<td class="varname">nav_path</td>
<td>List</td>
@@ -450,10 +444,10 @@ td {
<tr class="varlevel1">
<td class="varname">annotation</td>
<td>String</td>
<td>If set, indicates that annotations were requested. Valid values
are "annotated" (annotation was successful), "binary" (file contents
are not line-based and human-readable), and "error" (something went
wrong during annotation).</td>
<td>Valid values are "none" (no annotations were attempted),
"annotated" (annotation was successful), "binary" (file contents
are not line-based and human-readable), and "error" (something
went wrong during annotation).</td>
</tr>
<tr class="varlevel1">
<td class="varname">author</td>
@@ -1087,18 +1081,11 @@ td {
<td>String</td>
<td>Current search expression, if any.</td>
</tr>
<tr class="varlevel1">
<td class="varname">search_re_form</td>
<td>Boolean</td>
<td>Indicates whether or not to display the regular expression search
form. Value depends on the whether searching is enabled in the
configuration and whether or not the current directory is
empty.</td>
</tr>
<tr class="varlevel1">
<td class="varname">search_re_action</td>
<td>String</td>
<td>Form action URL for the regular expression search form.</td>
<td>Form action URL for the regular expression search form,
if searching is available.</td>
</tr>
<tr class="varlevel1">
<td class="varname">search_re_hidden_values</td>
@@ -2073,6 +2060,11 @@ td {
<td>String</td>
<td>URL for the current view but with <tt>limit_changes</tt> disabled.</td>
</tr>
<tr class="varlevel1">
<td class="varname">num_changes</td>
<td>String</td>
<td>Number of paths changed in this revision.</td>
</tr>
<tr class="varlevel1">
<td class="varname">next_href</td>
<td>String</td>

View File

@@ -137,9 +137,8 @@ td {
configuration's "general" section.</li>
<li>Finally, ensure that that the new <code>authorizer</code>
option is set to either "forbidden" (which is the default) or
"forbiddenre", depending on which of those you were using in
ViewVC 1.0.x.</li>
option is set to either "forbidden" or "forbiddenre", depending
on which of those you were using in ViewVC 1.0.x.</li>
</ol>
@@ -215,10 +214,9 @@ td {
<li>options/py2html_path</li>
<li>options/use_enscript</li>
<li>options/use_highlight</li>
<li>options/use_pagesize</li>
<li>options/use_php</li>
<li>options/use_py2html</li>
<li>options/use_pygments</li>
<li>options/use_source_highlight</li>
</ul>
</div>
@@ -226,16 +224,23 @@ td {
<div class="h3">
<h3>Checkin Database</h3>
<p>In ViewVC 1.1, the <code>svndbadmin</code> program's "rebuild"
subcommand has had its purpose become more defined. It no longer
accepts a revision argument, and therefore can now only be used to
completely rebuild the entirety of the checkin database information
for a Subversion repository (instead of being able to only update
the information related to single Subversion revision). For
per-revision updating, use <code>svndbadmin update</code> and
<p>ViewVC 1.1 introduces to the <code>cvsdbadmin</code>
and <code>svndbadmin</code> tools a new "purge" operation, which
allows you to remove all the information related to a given root
from your checkins database (without disturbing the information
associated with other roots). Likewise, the "rebuild" command in
those tools now implies a "purge" followed by an update.</p>
<p>As a related change, the <code>svndbadmin</code> program's
"rebuild" subcommand has had its purpose become more defined. It
no longer accepts a revision argument, and therefore can now only
be used to completely rebuild the entirety of the checkin database
information for a Subversion repository (instead of being able to
only update the information related to single Subversion revision).
For per-revision updating, use <code>svndbadmin update</code> and
provide a revision (or revision range). And to get the previous
rebuild-a-revision effect, pass the new <code>--force</code>
option to <code>svndbadmin update</code>.</p>
rebuild-a-revision effect, pass the new <code>--force</code> option
to <code>svndbadmin update</code>.</p>
<p>In other words, where you once did this:</p>
@@ -249,6 +254,19 @@ td {
</pre>
</blockquote>
<p>To enhance the performance of the new "purge" operation, ViewVC 1.1
introduces some slight changes to the checkin database schema. If
you use the <code>make-database</code> tool to (re)create your
checkins database, it will by default employ the new database
schema. This should cause the database to be virtually unusable by
previous versions of ViewVC, and that's by design. If, however,
you need to (re)create your checkins database and you require
compatibility with previous versions of ViewVC or ViewCVS, simply
pass the "--version=1.0" option to the <code>make-database</code>
script. Note that your "purge" and "rebuild" operations could be
abysmally slow, though, as that version of the database schema is
not optimized for those operations.</p>
</div>
<div class="h3">
@@ -296,6 +314,22 @@ td {
<li>options/allow_tar</li>
</ul>
<p>ViewVC now honors the "svn:mime-type" property stored on
Subversion-versioned files as the primary source of MIME type
determination (before falling back to name-based MIME mappings and
such). However, this can negatively affect the viewability of
certain files &mdash; especially images &mdash; whose
"svn:mime-type" properties are set incorrectly, such as will happen
if Subversion itself merely determines that the file isn't
human-readable and uses the "application/octet-stream" MIME type to
record this determination. To make ViewVC <em>not</em> honor the
"svn:mime-type" property value, set the <code>svn_ignore_mimetype</code>
configuration option.</p>
<p>Speaking of MIME types, the option <code>mime_types_file</code> is
now <code>mime_types_files</code>, as it now carries multiple paths
to MIME mappings files, ordered by preference.</p>
<p>The <code>use_rcsparse</code> option was moved from the "general"
section to the "options" section.</p>
@@ -631,6 +665,11 @@ allow_tar = 1
<td>revision.ezt</td>
<td>now is an iterable list of objects with .name and .value attributes</td>
</tr>
<tr class="added">
<td class="varname">num_changes</td>
<td>revision.ezt</td>
<td>added</td>
</tr>
</tbody>
</table>
@@ -659,7 +698,7 @@ allow_tar = 1
<h3>Checkin Database</h3>
<p>ViewVC 1.0 reads and writes commit times in the MySQL database in
UTC time rather than local time. This can cause times displayed on
UTC time rather than local time. This can cause times displayed on
the query page to be a few hours off if an old database is being
used with a new version of ViewVC. The best way to fix this is to
rebuild the database with the new version of cvsdbadmin, but it
@@ -702,7 +741,8 @@ allow_tar = 1
<li>options/root_as_url_component</li>
<li>options/default_file_view</li>
<li>options/sort_group_dirs</li>
<li>options/use_pagesize</li>
<li>options/dir_pagesize</li>
<li>options/log_pagesize</li>
<li>options/limit_changes</li>
<li>options/use_localtime</li>
<li>options/cross_copies</li>

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-2007 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

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2008 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
@@ -40,7 +40,7 @@ import fnmatch
class Config:
_sections = ('general', 'utilities', 'options', 'cvsdb', 'templates')
_force_multi_value = ('cvs_roots', 'svn_roots', 'languages', 'kv_files',
'root_parents', 'allowed_views')
'root_parents', 'allowed_views', 'mime_types_files')
def __init__(self):
for section in self._sections:
@@ -197,7 +197,7 @@ class Config:
self.general.svn_roots = { }
self.general.root_parents = []
self.general.default_root = ''
self.general.mime_types_file = ''
self.general.mime_types_files = ["mimetypes.conf"]
self.general.address = ''
self.general.kv_files = [ ]
self.general.languages = ['en-us']
@@ -213,12 +213,13 @@ class Config:
self.options.root_as_url_component = 1
self.options.checkout_magic = 0
self.options.allowed_views = ['markup', 'annotate', 'roots']
self.options.authorizer = 'forbidden'
self.options.allowed_views = ['annotate', 'diff', 'markup', 'roots']
self.options.authorizer = None
self.options.mangle_email_addresses = 0
self.options.default_file_view = "log"
self.options.http_expiration_time = 600
self.options.generate_etags = 1
self.options.svn_ignore_mimetype = 0
self.options.svn_config_dir = None
self.options.use_rcsparse = 0
self.options.sort_by = 'file'
@@ -246,7 +247,8 @@ class Config:
self.options.use_cvsgraph = 0
self.options.cvsgraph_conf = "cvsgraph.conf"
self.options.use_re_search = 0
self.options.use_pagesize = 0
self.options.dir_pagesize = 0
self.options.log_pagesize = 0
self.options.limit_changes = 100
self.templates.diff = None

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2007 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,14 @@ import re
import vclib
import dbi
## Current commits database schema version number.
##
## Version 0 was the original Bonsai-compatible version.
##
## Version 1 added the 'metadata' table (which holds the 'version' key)
## and renamed all the 'repository'-related stuff to be 'root'-
##
CURRENT_SCHEMA_VERSION = 1
## error
error = "cvsdb error"
@@ -37,6 +45,7 @@ class CheckinDatabase:
self._passwd = passwd
self._database = database
self._row_limit = row_limit
self._version = None
## database lookup caches
self._get_cache = {}
@@ -48,6 +57,19 @@ class CheckinDatabase:
self._host, self._port, self._user, self._passwd, self._database)
cursor = self.db.cursor()
cursor.execute("SET AUTOCOMMIT=1")
table_list = self.GetTableList()
if 'metadata' in table_list:
version = self.GetMetadataValue("version")
if version is None:
self._version = 0
else:
self._version = int(version)
else:
self._version = 0
if self._version > CURRENT_SCHEMA_VERSION:
raise Exception("Database version %d is newer than the last "
"version supported by this software."
% (self._version))
def sql_get_id(self, table, column, value, auto_set):
sql = "SELECT id FROM %s WHERE %s=%%s" % (table, column)
@@ -147,6 +169,42 @@ class CheckinDatabase:
return list
def GetTableList(self):
sql = "SHOW TABLES"
cursor = self.db.cursor()
cursor.execute(sql)
list = []
while 1:
row = cursor.fetchone()
if row == None:
break
list.append(row[0])
return list
def GetMetadataValue(self, name):
sql = "SELECT value FROM metadata WHERE name=%s"
sql_args = (name)
cursor = self.db.cursor()
cursor.execute(sql, sql_args)
try:
(value,) = cursor.fetchone()
except TypeError:
return None
return value
def SetMetadataValue(self, name, value):
assert(self._version > 0)
sql = "REPLACE INTO metadata (name, value) VALUES (%s, %s)"
sql_args = (name, value)
cursor = self.db.cursor()
try:
cursor.execute(sql, sql_args)
except Exception, e:
raise Exception("Error setting metadata: '%s'\n"
"\tname = %s\n"
"\tvalue = %s\n"
% (str(e), name, value))
def GetBranchID(self, branch, auto_set = 1):
return self.get_id("branches", "branch", branch, auto_set)
@@ -251,7 +309,9 @@ class CheckinDatabase:
minus_count = commit.GetMinusCount() or '0'
description_id = self.GetDescriptionID(commit.GetDescription())
sql = "REPLACE INTO checkins"\
commits_table = self._version >= 1 and 'commits' or 'checkins'
sql = "REPLACE INTO %s" % (commits_table)
sql = sql + \
" (type,ci_when,whoid,repositoryid,dirid,fileid,revision,"\
" stickytag,branchid,addedlines,removedlines,descid)"\
"VALUES(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
@@ -304,58 +364,69 @@ class CheckinDatabase:
return "(%s)" % (string.join(sqlList, " OR "))
def CreateSQLQueryString(self, query):
tableList = [("checkins", None)]
commits_table = self._version >= 1 and 'commits' or 'checkins'
tableList = [(commits_table, None)]
condList = []
if len(query.repository_list):
tableList.append(("repositories",
"(checkins.repositoryid=repositories.id)"))
"(%s.repositoryid=repositories.id)"
% (commits_table)))
temp = self.SQLQueryListString("repositories.repository",
query.repository_list)
condList.append(temp)
if len(query.branch_list):
tableList.append(("branches", "(checkins.branchid=branches.id)"))
tableList.append(("branches",
"(%s.branchid=branches.id)" % (commits_table)))
temp = self.SQLQueryListString("branches.branch",
query.branch_list)
condList.append(temp)
if len(query.directory_list):
tableList.append(("dirs", "(checkins.dirid=dirs.id)"))
tableList.append(("dirs",
"(%s.dirid=dirs.id)" % (commits_table)))
temp = self.SQLQueryListString("dirs.dir", query.directory_list)
condList.append(temp)
if len(query.file_list):
tableList.append(("files", "(checkins.fileid=files.id)"))
tableList.append(("files",
"(%s.fileid=files.id)" % (commits_table)))
temp = self.SQLQueryListString("files.file", query.file_list)
condList.append(temp)
if len(query.author_list):
tableList.append(("people", "(checkins.whoid=people.id)"))
tableList.append(("people",
"(%s.whoid=people.id)" % (commits_table)))
temp = self.SQLQueryListString("people.who", query.author_list)
condList.append(temp)
if len(query.comment_list):
tableList.append(("descs", "(checkins.descid=descs.id)"))
tableList.append(("descs",
"(%s.descid=descs.id)" % (commits_table)))
temp = self.SQLQueryListString("descs.description",
query.comment_list)
condList.append(temp)
if query.from_date:
temp = "(checkins.ci_when>=\"%s\")" % (str(query.from_date))
temp = "(%s.ci_when>=\"%s\")" \
% (commits_table, str(query.from_date))
condList.append(temp)
if query.to_date:
temp = "(checkins.ci_when<=\"%s\")" % (str(query.to_date))
temp = "(%s.ci_when<=\"%s\")" \
% (commits_table, str(query.to_date))
condList.append(temp)
if query.sort == "date":
order_by = "ORDER BY checkins.ci_when DESC,descid"
order_by = "ORDER BY %s.ci_when DESC,descid" % (commits_table)
elif query.sort == "author":
tableList.append(("people", "(checkins.whoid=people.id)"))
tableList.append(("people",
"(%s.whoid=people.id)" % (commits_table)))
order_by = "ORDER BY people.who,descid"
elif query.sort == "file":
tableList.append(("files", "(checkins.fileid=files.id)"))
tableList.append(("files",
"(%s.fileid=files.id)" % (commits_table)))
order_by = "ORDER BY files.file,descid"
## exclude duplicates from the table list, and split out join
@@ -381,8 +452,8 @@ class CheckinDatabase:
elif self._row_limit:
limit = "LIMIT %s" % (str(self._row_limit))
sql = "SELECT checkins.* FROM %s %s %s %s" % (
tables, conditions, order_by, limit)
sql = "SELECT %s.* FROM %s %s %s %s" \
% (commits_table, tables, conditions, order_by, limit)
return sql
@@ -433,8 +504,13 @@ class CheckinDatabase:
if file_id == None:
return None
sql = "SELECT * FROM checkins WHERE "\
" repositoryid=%s AND dirid=%s AND fileid=%s AND revision=%s"
commits_table = self._version >= 1 and 'commits' or 'checkins'
sql = "SELECT * FROM %s WHERE "\
" repositoryid=%%s "\
" AND dirid=%%s"\
" AND fileid=%%s"\
" AND revision=%%s"\
% (commits_table)
sql_args = (repository_id, dir_id, file_id, commit.GetRevision())
cursor = self.db.cursor()
@@ -451,40 +527,58 @@ class CheckinDatabase:
def sql_delete(self, table, key, value, keep_fkey = None):
sql = "DELETE FROM %s WHERE %s=%%s" % (table, key)
sql_args = (value, )
commits_table = self._version >= 1 and 'commits' or 'checkins'
if keep_fkey:
sql += " AND %s NOT IN (SELECT %s FROM checkins WHERE %s = %%s)" \
% (key, keep_fkey, keep_fkey)
sql_args = (value, value)
sql += " AND %s NOT IN (SELECT %s FROM %s WHERE %s = %%s)" \
% (key, keep_fkey, commits_table, keep_fkey)
sql_args = (value, value)
cursor = self.db.cursor()
cursor.execute(sql, sql_args)
def sql_purge(self, table, key, fkey, ftable):
sql = "DELETE FROM %s WHERE %s NOT IN (SELECT %s FROM %s)" \
% (table, key, fkey, ftable)
cursor = self.db.cursor()
cursor.execute(sql)
def PurgeRepository(self, repository):
rep_id = self.GetRepositoryID(repository)
if not rep_id:
raise Exception, "Unknown repository '%s'" % (repository)
sql = "SELECT * FROM checkins WHERE repositoryid=%s"
sql_args = (rep_id, )
cursor = self.db.cursor()
cursor.execute(sql, sql_args)
checkins = []
while 1:
try:
(ci_type, ci_when, who_id, repository_id,
dir_id, file_id, revision, sticky_tag, branch_id,
plus_count, minus_count, description_id) = cursor.fetchone()
except TypeError:
break
checkins.append([file_id, dir_id, branch_id, description_id, who_id])
#self.sql_delete('repositories', 'id', rep_id)
self.sql_delete('checkins', 'repositoryid', rep_id)
for checkin in checkins:
self.sql_delete('files', 'id', checkin[0], 'fileid')
self.sql_delete('dirs', 'id', checkin[1], 'dirid')
self.sql_delete('branches', 'id', checkin[2], 'branchid')
self.sql_delete('descs', 'id', checkin[3], 'descid')
self.sql_delete('people', 'id', checkin[4], 'whoid')
if (self._version >= 1):
self.sql_delete('repositories', 'id', rep_id)
self.sql_purge('commits', 'repositoryid', 'id', 'repositories')
self.sql_purge('files', 'id', 'fileid', 'commits')
self.sql_purge('dirs', 'id', 'dirid', 'commits')
self.sql_purge('branches', 'id', 'branchid', 'commits')
self.sql_purge('descs', 'id', 'descid', 'commits')
self.sql_purge('people', 'id', 'whoid', 'commits')
else:
sql = "SELECT * FROM checkins WHERE repositoryid=%s"
sql_args = (rep_id, )
cursor = self.db.cursor()
cursor.execute(sql, sql_args)
checkins = []
while 1:
try:
(ci_type, ci_when, who_id, repository_id,
dir_id, file_id, revision, sticky_tag, branch_id,
plus_count, minus_count, description_id) = \
cursor.fetchone()
except TypeError:
break
checkins.append([file_id, dir_id, branch_id,
description_id, who_id])
#self.sql_delete('repositories', 'id', rep_id)
self.sql_delete('checkins', 'repositoryid', rep_id)
for checkin in checkins:
self.sql_delete('files', 'id', checkin[0], 'fileid')
self.sql_delete('dirs', 'id', checkin[1], 'dirid')
self.sql_delete('branches', 'id', checkin[2], 'branchid')
self.sql_delete('descs', 'id', checkin[3], 'descid')
self.sql_delete('people', 'id', checkin[4], 'whoid')
## the Commit class holds data on one commit, the representation is as
## close as possible to how it should be committed and retrieved to the

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2007 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
@@ -48,13 +48,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

@@ -460,7 +460,10 @@ class Template:
def _cmd_print(self, valrefs, ctx):
value = _get_value(valrefs[0], ctx)
args = map(lambda valref, ctx=ctx: _get_value(valref, ctx), valrefs[1:])
_write_value(value, args, ctx)
try:
_write_value(value, args, ctx)
except TypeError:
raise Exception("Unprintable value type for '%s'" % (str(valrefs[0][0])))
def _cmd_format(self, printer, ctx):
if type(printer) is TupleType:
@@ -522,7 +525,8 @@ class Template:
((valref,), unused, section) = args
list = _get_value(valref, ctx)
if isinstance(list, StringType):
raise NeedSequenceError()
raise NeedSequenceError("The value of '%s' is not a sequence"
% (valref[0]))
refname = valref[0]
ctx.for_iterators[refname] = iterator = _iter(list)
for unused in iterator:
@@ -672,6 +676,41 @@ def _write_value(value, args, ctx):
ctx.printers.append(printer)
class TemplateData:
"""A custom dictionary-like object that allows one-time definition
of keys, and only value fetches and changes, and key deletions,
thereafter.
EZT doesn't require the use of this special class -- a normal
dict-type data dictionary works fine. But use of this class will
assist those who want the data sent to their templates to have a
consistent set of keys."""
def __init__(self, initial_data={}):
self._items = initial_data
def __getitem__(self, key):
return self._items.__getitem__(key)
def __setitem__(self, key, item):
assert self._items.has_key(key)
return self._items.__setitem__(key, item)
def __delitem__(self, key):
return self._items.__delitem__(key)
def keys(self):
return self._items.keys()
def merge(self, template_data):
"""Merge the data in TemplataData instance TEMPLATA_DATA into this
instance. Avoid the temptation to use this conditionally in your
code -- it rather defeats the purpose of this class."""
assert isinstance(template_data, TemplateData)
self._items.update(template_data._items)
class Context:
"""A container for the execution context"""
def __init__(self, fp):

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2007 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
@@ -131,194 +131,6 @@ def popen(cmd, args, mode, capture_err=1):
# crap. shouldn't be here.
sys.exit(127)
def pipe_cmds(cmds, out=None):
"""Executes a sequence of commands. The output of each command is directed to
the input of the next command. A _pipe object is returned for writing to the
first command's input. The output of the last command is directed to the
"out" file object or the standard output if "out" is None. If "out" is not an
OS file descriptor, a separate thread will be spawned to send data to its
write() method."""
if out is None:
out = sys.stdout
if sys.platform == "win32":
### FIXME: windows implementation ignores "out" argument, always
### writing last command's output to standard out
if debug.SHOW_CHILD_PROCESSES:
dbgIn = StringIO.StringIO()
hStdIn, handle = win32popen.MakeSpyPipe(1, 0, (dbgIn,))
i = 0
for cmd in cmds:
i = i + 1
dbgOut, dbgErr = StringIO.StringIO(), StringIO.StringIO()
if i < len(cmds):
nextStdIn, hStdOut = win32popen.MakeSpyPipe(1, 1, (dbgOut,))
x, hStdErr = win32popen.MakeSpyPipe(None, 1, (dbgErr,))
else:
ehandle = win32event.CreateEvent(None, 1, 0, None)
nextStdIn, hStdOut = win32popen.MakeSpyPipe(None, 1, (dbgOut, sapi.server.file()), ehandle)
x, hStdErr = win32popen.MakeSpyPipe(None, 1, (dbgErr,))
command = win32popen.CommandLine(cmd[0], cmd[1:])
phandle, pid, thandle, tid = win32popen.CreateProcess(command, hStdIn, hStdOut, hStdErr)
if debug.SHOW_CHILD_PROCESSES:
debug.Process(command, dbgIn, dbgOut, dbgErr)
dbgIn = dbgOut
hStdIn = nextStdIn
else:
hStdIn, handle = win32popen.CreatePipe(1, 0)
spool = None
i = 0
for cmd in cmds:
i = i + 1
if i < len(cmds):
nextStdIn, hStdOut = win32popen.CreatePipe(1, 1)
else:
# very last process
nextStdIn = None
if sapi.server.inheritableOut:
# send child output to standard out
hStdOut = win32popen.MakeInheritedHandle(win32popen.FileObject2File(sys.stdout),0)
ehandle = None
else:
ehandle = win32event.CreateEvent(None, 1, 0, None)
x, hStdOut = win32popen.MakeSpyPipe(None, 1, (sapi.server.file(),), ehandle)
command = win32popen.CommandLine(cmd[0], cmd[1:])
phandle, pid, thandle, tid = win32popen.CreateProcess(command, hStdIn, hStdOut, None)
hStdIn = nextStdIn
return _pipe(win32popen.File2FileObject(handle, 'wb'), phandle, ehandle)
# flush the stdio buffers since we are about to change the FD under them
sys.stdout.flush()
sys.stderr.flush()
prev_r, parent_w = os.pipe()
null = os.open('/dev/null', os.O_RDWR)
child_pids = []
for cmd in cmds[:-1]:
r, w = os.pipe()
pid = os.fork()
if not pid:
# in the child
# hook up stdin to the "read" channel
os.dup2(prev_r, 0)
# hook up stdout to the output channel
os.dup2(w, 1)
# toss errors
os.dup2(null, 2)
# close these extra descriptors
os.close(prev_r)
os.close(parent_w)
os.close(null)
os.close(r)
os.close(w)
# time to run the command
try:
os.execvp(cmd[0], cmd)
except:
pass
sys.exit(127)
# in the parent
child_pids.append(pid)
# we don't need these any more
os.close(prev_r)
os.close(w)
# the read channel of this pipe will feed into to the next command
prev_r = r
# no longer needed
os.close(null)
# done with most of the commands. set up the last command to write to "out"
if not hasattr(out, 'fileno'):
r, w = os.pipe()
pid = os.fork()
if not pid:
# in the child (the last command)
# hook up stdin to the "read" channel
os.dup2(prev_r, 0)
# hook up stdout to "out"
if hasattr(out, 'fileno'):
if out.fileno() != 1:
os.dup2(out.fileno(), 1)
out.close()
else:
# "out" can't be hooked up directly, so use a pipe and a thread
os.dup2(w, 1)
os.close(r)
os.close(w)
# close these extra descriptors
os.close(prev_r)
os.close(parent_w)
# run the last command
try:
os.execvp(cmds[-1][0], cmds[-1])
except:
pass
sys.exit(127)
child_pids.append(pid)
# not needed any more
os.close(prev_r)
if not hasattr(out, 'fileno'):
os.close(w)
thread = _copy(r, out)
thread.start()
else:
thread = None
# write into the first pipe, wait on the final process
return _pipe(os.fdopen(parent_w, 'w'), child_pids, thread=thread)
class _copy(threading.Thread):
def __init__(self, srcfd, destfile):
self.srcfd = srcfd
self.destfile = destfile
threading.Thread.__init__(self)
def run(self):
try:
while 1:
s = os.read(self.srcfd, 1024)
if not s:
break
self.destfile.write(s)
finally:
os.close(self.srcfd)
class _pipe:
"Wrapper for a file which can wait() on a child process at close time."

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2008 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
@@ -412,13 +412,10 @@ def main(server, cfg, viewvc_link):
commits = [ ]
query = 'skipped'
script_name = server.getenv('SCRIPT_NAME', '')
data = {
data = ezt.TemplateData({
'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),
@@ -435,16 +432,11 @@ def main(server, cfg, viewvc_link):
'commits' : commits,
'num_commits' : len(commits),
'rss_href' : None,
}
if form_data.hours:
data['hours'] = form_data.hours
else:
data['hours'] = 2
server.header()
'hours' : form_data.hours and form_data.hours or 2,
})
# generate the page
server.header()
template = viewvc.get_view_template(cfg, "query")
template.generate(server.file(), data)

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2007 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

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2007 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

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2007 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

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2007 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

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2008 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
@@ -21,7 +21,7 @@ import tempfile
import popen2
import time
import urllib
from svn_repos import Revision, SVNChangedPath, _datestr_to_date, _compare_paths, _path_parts, _cleanup_path, _rev2optrev
from svn_repos import Revision, SVNChangedPath, _datestr_to_date, _compare_paths, _path_parts, _cleanup_path, _rev2optrev, _fix_subversion_exception
from svn import core, delta, client, wc, ra
@@ -254,7 +254,7 @@ class RemoteSubversionRepository(vclib.Repository):
dirent = dirents[entry.name]
entry.date, entry.author, entry.log, changes = \
self.revinfo(dirent.created_rev)
entry.rev = dirent.created_rev
entry.rev = str(dirent.created_rev)
entry.size = dirent.size
entry.lockinfo = None
if locks.has_key(entry.name):
@@ -362,6 +362,7 @@ class RemoteSubversionRepository(vclib.Repository):
info2 = p2, _date_from_rev(r2), r2
return vclib._diff_fp(temp1, temp2, info1, info2, self.diff_cmd, args)
except core.SubversionException, e:
_fix_subversion_exception(e)
if e.apr_err == vclib.svn.core.SVN_ERR_FS_NOT_FOUND:
raise vclib.InvalidRevision
raise
@@ -486,6 +487,7 @@ class RemoteSubversionRepository(vclib.Repository):
try:
results = ra.get_locations(self.ra_session, path, rev, [old_rev])
except core.SubversionException, e:
_fix_subversion_exception(e)
if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
raise vclib.ItemNotFound(path)
raise

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2008 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,11 +15,9 @@
import vclib
import os
import os.path
import stat
import string
import cStringIO
import signal
import shutil
import time
import tempfile
import popen
@@ -31,6 +29,19 @@ from svn import fs, repos, core, client, delta
if (core.SVN_VER_MAJOR, core.SVN_VER_MINOR, core.SVN_VER_PATCH) < (1, 3, 1):
raise Exception, "Version requirement not met (needs 1.3.1 or better)"
### Pre-1.5 Subversion doesn't have SVN_ERR_CEASE_INVOCATION
try:
_SVN_ERR_CEASE_INVOCATION = core.SVN_ERR_CEASE_INVOCATION
except:
_SVN_ERR_CEASE_INVOCATION = core.SVN_ERR_CANCELLED
### Pre-1.5 SubversionException's might not have the .msg and .apr_err members
def _fix_subversion_exception(e):
if not hasattr(e, 'apr_err'):
e.apr_err = e[1]
if not hasattr(e, 'message'):
e.message = e[0]
def _allow_all(root, path, pool):
"""Generic authz_read_func that permits access to all paths"""
@@ -167,13 +178,16 @@ class NodeHistory:
return
self.histories.append([revision, _cleanup_path(path)])
if self.limit and len(self.histories) == self.limit:
raise core.SubversionException("", core.SVN_ERR_CEASE_INVOCATION)
raise core.SubversionException("", _SVN_ERR_CEASE_INVOCATION)
def __getitem__(self, idx):
return self.histories[idx]
def _get_history(svnrepos, path, rev, path_type, limit=0, options={}):
if svnrepos.youngest == 0:
return []
rev_paths = []
fsroot = svnrepos._getroot(rev)
show_all_logs = options.get('svn_show_all_dir_logs', 0)
@@ -190,7 +204,8 @@ def _get_history(svnrepos, path, rev, path_type, limit=0, options={}):
repos.svn_repos_history(svnrepos.fs_ptr, path, history.add_history,
1, rev, options.get('svn_cross_copies', 0))
except core.SubversionException, e:
if e.apr_err != core.SVN_ERR_CEASE_INVOCATION:
_fix_subversion_exception(e)
if e.apr_err != _SVN_ERR_CEASE_INVOCATION:
raise
# Now, iterate over those history items, checking for changes of
@@ -210,7 +225,7 @@ def _log_helper(svnrepos, path, rev, lockinfo):
copyfrom_rev, copyfrom_path = fs.copied_from(rev_root, path)
# Assemble our LogEntry
date, author, msg, changes = svnrepos.revinfo(rev)
date, author, msg, changes = svnrepos._revinfo(rev)
if fs.is_file(rev_root, path):
size = fs.file_length(rev_root, path)
else:
@@ -314,6 +329,7 @@ class BlameSource:
client.blame2(local_url, _rev2optrev(rev), _rev2optrev(first_rev),
_rev2optrev(rev), self._blame_cb, ctx)
except core.SubversionException, e:
_fix_subversion_exception(e)
if e.apr_err == core.SVN_ERR_CLIENT_IS_BINARY_FILE:
raise vclib.NonTextualFileContents
raise
@@ -456,7 +472,7 @@ class LocalSubversionRepository(vclib.Repository):
continue
path = self._getpath(entry_path_parts)
entry_rev = _get_last_history_rev(fsroot, path)
date, author, msg, changes = self.revinfo(entry_rev)
date, author, msg, changes = self._revinfo(entry_rev)
entry.rev = str(entry_rev)
entry.date = date
entry.author = author
@@ -554,100 +570,125 @@ class LocalSubversionRepository(vclib.Repository):
youngest_rev, oldest_rev)
return source, youngest_rev
def _revinfo_raw(self, rev):
fsroot = self._getroot(rev)
# Get the changes for the revision
editor = repos.ChangeCollector(self.fs_ptr, fsroot)
e_ptr, e_baton = delta.make_editor(editor)
repos.svn_repos_replay(fsroot, e_ptr, e_baton)
changes = editor.get_changes()
changedpaths = {}
def _revinfo(self, rev, include_changed_paths=0):
"""Internal-use, cache-friendly revision information harvester."""
# Now get the revision property info. Would use
# editor.get_root_props(), but something is broken there...
revprops = fs.revision_proplist(self.fs_ptr, rev)
msg = revprops.get(core.SVN_PROP_REVISION_LOG)
author = revprops.get(core.SVN_PROP_REVISION_AUTHOR)
datestr = revprops.get(core.SVN_PROP_REVISION_DATE)
# Copy the Subversion changes into a new hash, converting them into
# ChangedPath objects.
found_readable = found_unreadable = 0
for path in changes.keys():
change = changes[path]
if change.path:
change.path = _cleanup_path(change.path)
if change.base_path:
change.base_path = _cleanup_path(change.base_path)
is_copy = 0
if not hasattr(change, 'action'): # new to subversion 1.4.0
action = vclib.MODIFIED
if not change.path:
action = vclib.DELETED
elif change.added:
action = vclib.ADDED
replace_check_path = path
if change.base_path and change.base_rev:
replace_check_path = change.base_path
if changedpaths.has_key(replace_check_path) \
and changedpaths[replace_check_path].action == vclib.DELETED:
action = vclib.REPLACED
else:
if change.action == repos.CHANGE_ACTION_ADD:
action = vclib.ADDED
elif change.action == repos.CHANGE_ACTION_DELETE:
action = vclib.DELETED
elif change.action == repos.CHANGE_ACTION_REPLACE:
action = vclib.REPLACED
else:
def _revinfo_helper(rev, include_changed_paths):
# Get the revision property info. (Would use
# editor.get_root_props(), but something is broken there...)
revprops = fs.revision_proplist(self.fs_ptr, rev)
msg = revprops.get(core.SVN_PROP_REVISION_LOG)
author = revprops.get(core.SVN_PROP_REVISION_AUTHOR)
datestr = revprops.get(core.SVN_PROP_REVISION_DATE)
date = _datestr_to_date(datestr)
# Optimization: If our caller doesn't care about the changed
# paths, and we don't need them to do authz determinations, let's
# get outta here.
if self.auth is None and not include_changed_paths:
return date, author, msg, None
# If we get here, then we either need the changed paths because we
# were asked for them, or we need them to do authorization checks.
# Either way, we need 'em, so let's get 'em.
fsroot = self._getroot(rev)
editor = repos.ChangeCollector(self.fs_ptr, fsroot)
e_ptr, e_baton = delta.make_editor(editor)
repos.svn_repos_replay(fsroot, e_ptr, e_baton)
changedpaths = {}
changes = editor.get_changes()
# Copy the Subversion changes into a new hash, checking
# authorization and converting them into ChangedPath objects.
found_readable = found_unreadable = 0
for path in changes.keys():
change = changes[path]
if change.path:
change.path = _cleanup_path(change.path)
if change.base_path:
change.base_path = _cleanup_path(change.base_path)
is_copy = 0
if not hasattr(change, 'action'): # new to subversion 1.4.0
action = vclib.MODIFIED
if (action == vclib.ADDED or action == vclib.REPLACED) \
and change.base_path \
and change.base_rev:
is_copy = 1
if change.item_kind == core.svn_node_dir:
pathtype = vclib.DIR
elif change.item_kind == core.svn_node_file:
pathtype = vclib.FILE
if not change.path:
action = vclib.DELETED
elif change.added:
action = vclib.ADDED
replace_check_path = path
if change.base_path and change.base_rev:
replace_check_path = change.base_path
if changedpaths.has_key(replace_check_path) \
and changedpaths[replace_check_path].action == vclib.DELETED:
action = vclib.REPLACED
else:
if change.action == repos.CHANGE_ACTION_ADD:
action = vclib.ADDED
elif change.action == repos.CHANGE_ACTION_DELETE:
action = vclib.DELETED
elif change.action == repos.CHANGE_ACTION_REPLACE:
action = vclib.REPLACED
else:
action = vclib.MODIFIED
if (action == vclib.ADDED or action == vclib.REPLACED) \
and change.base_path \
and change.base_rev:
is_copy = 1
if change.item_kind == core.svn_node_dir:
pathtype = vclib.DIR
elif change.item_kind == core.svn_node_file:
pathtype = vclib.FILE
else:
pathtype = None
parts = _path_parts(path)
if vclib.check_path_access(self, parts, pathtype, rev):
if is_copy and change.base_path and (change.base_path != path):
parts = _path_parts(change.base_path)
if not vclib.check_path_access(self, parts, pathtype, change.base_rev):
is_copy = 0
change.base_path = None
change.base_rev = None
changedpaths[path] = SVNChangedPath(path, rev, pathtype,
change.base_path,
change.base_rev, action,
is_copy, change.text_changed,
change.prop_changes)
found_readable = 1
else:
found_unreadable = 1
# If our caller doesn't care about changed paths, we must be
# here for authz reasons only. That means the minute we've
# found both a readable and an unreadable path, we can bail out.
if (not include_changed_paths) and found_readable and found_unreadable:
return date, author, None, None
# Okay, we've process all our paths. Let's filter our metadata,
# and return the requested data.
if found_unreadable:
msg = None
if not found_readable:
author = None
date = None
if include_changed_paths:
return date, author, msg, changedpaths.values()
else:
pathtype = None
return date, author, msg, None
parts = _path_parts(path)
if vclib.check_path_access(self, parts, pathtype, rev):
if is_copy and change.base_path and (change.base_path != path):
parts = _path_parts(change.base_path)
if not vclib.check_path_access(self, parts, pathtype, change.base_rev):
is_copy = 0
change.base_path = None
change.base_rev = None
changedpaths[path] = SVNChangedPath(path, rev, pathtype,
change.base_path,
change.base_rev, action,
is_copy, change.text_changed,
change.prop_changes)
found_readable = 1
else:
found_unreadable = 1
# Return our tuple, auth-filtered: date, author, msg, changes
if found_unreadable:
msg = None
if not found_readable:
author = None
datestr = None
date = _datestr_to_date(datestr)
return date, author, msg, changedpaths.values()
def revinfo(self, rev):
# Consult the revinfo cache first. If we don't have cached info,
# or our caller wants changed paths and we don't have those for
# this revision, go do the real work.
rev = self._getrev(rev)
cached_info = self._revinfo_cache.get(rev)
if not cached_info:
cached_info = self._revinfo_raw(rev)
if not cached_info \
or (include_changed_paths and cached_info[3] is None):
cached_info = _revinfo_helper(rev, include_changed_paths)
self._revinfo_cache[rev] = cached_info
return cached_info[0], cached_info[1], cached_info[2], cached_info[3]
def revinfo(self, rev):
return self._revinfo(rev, 1)
def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
p1 = self._getpath(path_parts1)
p2 = self._getpath(path_parts2)
@@ -661,7 +702,7 @@ class LocalSubversionRepository(vclib.Repository):
args = vclib._diff_args(type, options)
def _date_from_rev(rev):
date, author, msg, changes = self.revinfo(rev)
date, author, msg, changes = self._revinfo(rev)
return date
try:
@@ -671,6 +712,7 @@ class LocalSubversionRepository(vclib.Repository):
info2 = p2, _date_from_rev(r2), r2
return vclib._diff_fp(temp1, temp2, info1, info2, self.diff_cmd, args)
except core.SubversionException, e:
_fix_subversion_exception(e)
if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
raise vclib.InvalidRevision
raise
@@ -710,6 +752,7 @@ class LocalSubversionRepository(vclib.Repository):
results = repos.svn_repos_trace_node_locations(self.fs_ptr, path,
rev, [old_rev], _allow_all)
except core.SubversionException, e:
_fix_subversion_exception(e)
if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
raise vclib.ItemNotFound(path)
raise
@@ -759,6 +802,7 @@ class LocalSubversionRepository(vclib.Repository):
try:
mid_id = fs.node_id(self._getroot(mid), path)
except core.SubversionException, e:
_fix_subversion_exception(e)
if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
cmp = -1
else:

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2008 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
@@ -14,7 +14,7 @@
#
# -----------------------------------------------------------------------
__version__ = '1.1-dev'
__version__ = '1.1.0'
# this comes from our library; measure the startup time
import debug
@@ -81,7 +81,7 @@ _sticky_vars = [
]
# number of extra pages of information on either side of the current
# page to fetch (see use_pagesize configuration option)
# page to fetch (see dir_pagesize/log_pagesize configuration option)
EXTRA_PAGES = 3
# for reading/writing between a couple descriptors
@@ -106,7 +106,10 @@ class Request:
# process the Accept-Language: header, and load the key/value
# files, given the selected language
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)
self.kv = cfg.load_kv_files(self.language)
@@ -993,8 +996,20 @@ def default_view(mime_type, cfg):
return view_checkout
def get_file_view_info(request, where, rev=None, mime_type=None, pathrev=-1):
"""Return common hrefs and a viewability flag used for various views
of FILENAME at revision REV whose MIME type is MIME_TYPE."""
"""Return an object holding common hrefs and a viewability flag used
for various views of FILENAME at revision REV whose MIME type is
MIME_TYPE.
The object's members include:
view_href
download_href
download_text_href
annotate_href
revision_href
prefer_markup
"""
rev = rev and str(rev) or None
mime_type = mime_type or guess_mime(where)
if pathrev == -1: # cheesy default value, since we need to preserve None
@@ -1042,8 +1057,12 @@ def get_file_view_info(request, where, rev=None, mime_type=None, pathrev=-1):
prefer_markup = default_view(mime_type, request.cfg) == view_markup
return view_href, download_href, download_text_href, \
annotate_href, revision_href, ezt.boolean(prefer_markup)
return _item(view_href=view_href,
download_href=download_href,
download_text_href=download_text_href,
annotate_href=annotate_href,
revision_href=revision_href,
prefer_markup=ezt.boolean(prefer_markup))
# Regular expressions for location text that looks like URLs and email
@@ -1154,40 +1173,44 @@ def html_time(request, secs, extended=0):
return s
def common_template_data(request, revision=None, mime_type=None):
"""Return a ezt.TemplateData instance with data dictionary items
common to most ViewVC views."""
cfg = request.cfg
data = {
# Initialize data dictionary members (sorted alphanumerically)
data = ezt.TemplateData({
'annotate_href' : None,
'cfg' : cfg,
'vsn' : __version__,
'kv' : request.kv,
'docroot' : cfg.options.docroot is None \
'docroot' : cfg.options.docroot is None \
and request.script_name + '/' + docroot_magic_path \
or cfg.options.docroot,
'username' : request.username,
'where' : request.server.escape(request.where),
'roottype' : request.roottype,
'download_href' : None,
'download_text_href' : None,
'graph_href': None,
'kv' : request.kv,
'lockinfo' : None,
'log_href' : None,
'nav_path' : nav_path(request),
'pathtype' : None,
'prefer_markup' : ezt.boolean(0),
'queryform_href' : None,
'rev' : None,
'revision_href' : None,
'rootname' : request.rootname \
and request.server.escape(request.rootname) or None,
'rootpath' : request.rootpath,
'pathtype' : None,
'nav_path' : nav_path(request),
'view' : _view_codes[request.view_func],
'rev' : None,
'lockinfo' : None,
'view_href' : None,
'annotate_href' : None,
'download_href' : None,
'download_text_href' : None,
'revision_href' : None,
'queryform_href' : None,
'roots_href' : request.get_url(view_func=view_roots, escape=1, params={}),
'roottype' : request.roottype,
'rss_href' : None,
'tarball_href' : None,
'up_href' : None,
'log_href' : None,
'log_href_rev': None,
'graph_href': None,
'rss_href' : None,
'roots_href' : request.get_url(view_func=view_roots, escape=1, params={}),
'prefer_markup' : ezt.boolean(0),
}
'username' : request.username,
'view' : _view_codes[request.view_func],
'view_href' : None,
'vsn' : __version__,
'where' : request.server.escape(request.where),
})
rev = revision
if not rev:
@@ -1214,11 +1237,14 @@ def common_template_data(request, revision=None, mime_type=None):
params={}, escape=1)
if request.pathtype == vclib.FILE:
data['view_href'], data['download_href'], data['download_text_href'], \
data['annotate_href'], data['revision_href'], data['prefer_markup'] \
= get_file_view_info(request, request.where, data['rev'], mime_type)
data['log_href'] = request.get_url(view_func=view_log,
params={}, escape=1)
fvi = get_file_view_info(request, request.where, data['rev'], mime_type)
data['view_href'] = fvi.view_href
data['download_href'] = fvi.download_href
data['download_text_href'] = fvi.download_text_href
data['annotate_href'] = fvi.annotate_href
data['revision_href'] = fvi.revision_href
data['prefer_markup'] = fvi.prefer_markup
data['log_href'] = request.get_url(view_func=view_log, params={}, escape=1)
if request.roottype == 'cvs' and cfg.options.use_cvsgraph:
data['graph_href'] = request.get_url(view_func=view_cvsgraph,
params={}, escape=1)
@@ -1417,6 +1443,9 @@ def make_rss_time_string(date, cfg):
return None
return time.strftime("%a, %d %b %Y %H:%M:%S", time.gmtime(date)) + ' UTC'
def make_comma_sep_list_string(items):
return string.join(map(lambda x: x.name, items), ', ')
def get_itemprops(request, path_parts, rev):
itemprops = request.repos.itemprops(path_parts, rev)
propnames = itemprops.keys()
@@ -1444,7 +1473,8 @@ def calculate_mime_type(request, path_parts, rev):
mime_type = None
if not path_parts:
return None
if request.roottype == 'svn':
if request.roottype == 'svn' \
and (not request.cfg.options.svn_ignore_mimetype):
try:
itemprops = request.repos.itemprops(path_parts, rev)
mime_type = itemprops.get('svn:mime-type')
@@ -1458,7 +1488,7 @@ def markup_or_annotate(request, is_annotate):
cfg = request.cfg
path, rev = _orig_path(request, is_annotate and 'annotate' or 'revision')
lines = fp = image_src_href = None
annotation = None
annotation = 'none'
revision = None
mime_type = calculate_mime_type(request, path, rev)
@@ -1497,7 +1527,7 @@ def markup_or_annotate(request, is_annotate):
fp.close()
data = common_template_data(request, revision)
data.update({
data.merge(ezt.TemplateData({
'mime_type' : mime_type,
'log' : None,
'date' : None,
@@ -1517,20 +1547,18 @@ def markup_or_annotate(request, is_annotate):
'lines' : lines,
'properties' : get_itemprops(request, path, rev),
'annotation' : annotation,
})
}))
if cfg.options.show_log_in_markup:
options = {'svn_latest_log': 1} ### FIXME: No longer needed?
revs = request.repos.itemlog(path, revision, vclib.SORTBY_DEFAULT,
revs = request.repos.itemlog(path, revision, vclib.SORTBY_REV,
0, 1, options)
entry = revs[-1]
data.update({
'date' : make_time_string(entry.date, cfg),
'author' : entry.author,
'changed' : entry.changed,
'log' : htmlify(entry.log, cfg.options.mangle_email_addresses),
'size' : entry.size,
})
data['date'] = make_time_string(entry.date, cfg)
data['author'] = entry.author
data['changed'] = entry.changed
data['log'] = htmlify(entry.log, cfg.options.mangle_email_addresses)
data['size'] = entry.size
if entry.date is not None:
data['ago'] = html_time(request, entry.date, 1)
@@ -1538,15 +1566,14 @@ def markup_or_annotate(request, is_annotate):
if request.roottype == 'cvs':
branch = entry.branch_number
prev = entry.prev or entry.parent
data.update({
'state' : entry.dead and 'dead',
'prev' : prev and prev.string,
'vendor_branch' : ezt.boolean(branch and branch[2] % 2 == 1),
'branches' : string.join(map(lambda x: x.name, entry.branches), ', '),
'tags' : string.join(map(lambda x: x.name, entry.tags), ', '),
'branch_points': string.join(map(lambda x: x.name,
entry.branch_points), ', ')
})
data['state'] = entry.dead and 'dead'
data['prev'] = prev and prev.string
data['vendor_branch'] = ezt.boolean(branch and branch[2] % 2 == 1)
### TODO: Should this be using prep_tags() instead?
data['branches'] = make_comma_sep_list_string(entry.branches)
data['tags'] = make_comma_sep_list_string(entry.tags)
data['branch_points']= make_comma_sep_list_string(entry.branch_points)
if path != request.path_parts:
orig_path = _path_join(path)
@@ -1649,10 +1676,14 @@ def view_roots(request):
href=href))
data = common_template_data(request)
data['roots'] = roots
data.merge(ezt.TemplateData({
'roots' : roots,
}))
generate_page(request, "roots", data)
def view_directory(request):
cfg = request.cfg
# For Subversion repositories, the revision acts as a weak validator for
# the directory listing (to take into account template changes or
# revision property changes).
@@ -1666,7 +1697,6 @@ def view_directory(request):
return
# List current directory
cfg = request.cfg
options = {}
if request.roottype == 'cvs':
hideattic = int(request.query_dict.get('hideattic',
@@ -1686,11 +1716,11 @@ def view_directory(request):
# however, when sorting by other properties or not paging, we've no
# choice but to fetch dirlogs for everything.
debug.t_start("dirlogs")
if cfg.options.use_pagesize and sortby == 'file':
if cfg.options.dir_pagesize and sortby == 'file':
dirlogs_first = int(request.query_dict.get('dir_pagestart', 0))
if dirlogs_first > len(file_data):
dirlogs_first = 0
dirlogs_last = dirlogs_first + cfg.options.use_pagesize
dirlogs_last = dirlogs_first + cfg.options.dir_pagesize
for file in file_data:
file.rev = None
file.date = None
@@ -1802,10 +1832,13 @@ def view_directory(request):
row.mime_type = calculate_mime_type(request, _path_parts(file_where),
file.rev)
row.view_href, row.download_href, row.download_text_href, \
row.annotate_href, row.revision_href, \
row.prefer_markup \
= get_file_view_info(request, file_where, file.rev, row.mime_type)
fvi = get_file_view_info(request, file_where, file.rev, row.mime_type)
row.view_href = fvi.view_href
row.download_href = fvi.download_href
row.download_text_href = fvi.download_text_href
row.annotate_href = fvi.annotate_href
row.revision_href = fvi.revision_href
row.prefer_markup = fvi.prefer_markup
row.log_href = request.get_url(view_func=view_log,
where=file_where,
pathtype=vclib.FILE,
@@ -1820,9 +1853,10 @@ def view_directory(request):
rows.append(row)
# prepare the data that will be passed to the template
# Prepare the data that will be passed to the template, based on the
# common template data.
data = common_template_data(request)
data.update({
data.merge(ezt.TemplateData({
'entries' : rows,
'sortby' : sortby,
'sortdir' : sortdir,
@@ -1856,7 +1890,25 @@ def view_directory(request):
'branch_tags': None,
'plain_tags': None,
'properties': get_itemprops(request, request.path_parts, request.pathrev),
})
'tree_rev' : None,
'tree_rev_href' : None,
'dir_paging_action' : None,
'dir_paging_hidden_values' : [],
'search_re_action' : None,
'search_re_hidden_values' : [],
# Populated by paging()/paging_sws()
'picklist' : [],
'picklist_len' : 0,
# Populated by pathrev_form()
'pathrev_action' : None,
'pathrev_hidden_values' : [],
'pathrev_clear_action' : None,
'pathrev_clear_hidden_values' : [],
'pathrev' : None,
'lastrev' : None,
}))
# clicking on sort column reverses sort order
if sortdir == 'down':
@@ -1867,24 +1919,27 @@ 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':
plain_tags = options['cvs_tags']
plain_tags.sort(icmp)
plain_tags.reverse()
data['plain_tags']= plain_tags
branch_tags = options['cvs_branches']
branch_tags.sort(icmp)
branch_tags.reverse()
data.update({
'attic_showing' : ezt.boolean(not hideattic),
'show_attic_href' : request.get_url(params={'hideattic': 0}, escape=1),
'hide_attic_href' : request.get_url(params={'hideattic': 1}, escape=1),
'branch_tags': branch_tags,
'plain_tags': plain_tags,
})
data['branch_tags']= branch_tags
data['attic_showing'] = ezt.boolean(not hideattic)
data['show_attic_href'] = request.get_url(params={'hideattic': 0},
escape=1)
data['hide_attic_href'] = request.get_url(params={'hideattic': 1},
escape=1)
# set svn-specific fields
elif request.roottype == 'svn':
@@ -1897,22 +1952,20 @@ def view_directory(request):
params={},
escape=1)
if cfg.options.use_pagesize:
if cfg.options.dir_pagesize:
data['dir_paging_action'], data['dir_paging_hidden_values'] = \
request.get_form(params={'dir_pagestart': None})
pathrev_form(request, data)
### one day, if EZT has "or" capability, we can lose this
data['search_re_form'] = ezt.boolean(cfg.options.use_re_search)
if data['search_re_form']:
if cfg.options.use_re_search:
data['search_re_action'], data['search_re_hidden_values'] = \
request.get_form(params={'search': None})
if cfg.options.use_pagesize:
if cfg.options.dir_pagesize:
data['dir_pagestart'] = int(request.query_dict.get('dir_pagestart',0))
data['entries'] = paging(data, 'entries', data['dir_pagestart'], 'name',
cfg.options.use_pagesize)
cfg.options.dir_pagesize)
generate_page(request, "directory", data)
@@ -2072,11 +2125,11 @@ def view_log(request):
sortby = vclib.SORTBY_DEFAULT
first = last = 0
if cfg.options.use_pagesize:
if cfg.options.log_pagesize:
log_pagestart = int(request.query_dict.get('log_pagestart', 0))
first = log_pagestart - min(log_pagestart,
(EXTRA_PAGES * cfg.options.use_pagesize))
last = log_pagestart + ((EXTRA_PAGES + 1) * cfg.options.use_pagesize) + 1
(EXTRA_PAGES * cfg.options.log_pagesize))
last = log_pagestart + ((EXTRA_PAGES + 1) * cfg.options.log_pagesize) + 1
show_revs = request.repos.itemlog(request.path_parts, request.pathrev,
sortby, first, last - first, options)
@@ -2172,9 +2225,13 @@ def view_log(request):
# view/download links
if pathtype is vclib.FILE:
entry.view_href, entry.download_href, entry.download_text_href, \
entry.annotate_href, entry.revision_href, entry.prefer_markup \
= get_file_view_info(request, request.where, rev.string, mime_type)
fvi = get_file_view_info(request, request.where, rev.string, mime_type)
entry.view_href = fvi.view_href
entry.download_href = fvi.download_href
entry.download_text_href = fvi.download_text_href
entry.annotate_href = fvi.annotate_href
entry.revision_href = fvi.revision_href
entry.prefer_markup = fvi.prefer_markup
else:
entry.revision_href = request.get_url(view_func=view_revision,
params={'revision': rev.string},
@@ -2232,8 +2289,16 @@ def view_log(request):
entry.copy_path = request.server.escape(entry.copy_path)
entries.append(entry)
diff_select_action, diff_select_hidden_values = \
request.get_form(view_func=view_diff,
params={'r1': None, 'r2': None, 'tr1': None,
'tr2': None, 'diff_format': None})
logsort_action, logsort_hidden_values = \
request.get_form(params={'logsort': None})
data = common_template_data(request)
data.update({
data.merge(ezt.TemplateData({
'default_branch' : None,
'mime_type' : mime_type,
'rev_selected' : selected_rev,
@@ -2241,6 +2306,8 @@ def view_log(request):
'logsort' : logsort,
'human_readable' : ezt.boolean(diff_format in ('h', 'l')),
'log_pagestart' : None,
'log_paging_action' : None,
'log_paging_hidden_values' : [],
'entries': entries,
'head_prefer_markup' : ezt.boolean(0),
'head_view_href' : None,
@@ -2252,42 +2319,45 @@ def view_log(request):
'tag_download_href': None,
'tag_download_text_href': None,
'tag_annotate_href': None,
})
'diff_select_action' : diff_select_action,
'diff_select_hidden_values' : diff_select_hidden_values,
'logsort_action' : logsort_action,
'logsort_hidden_values' : logsort_hidden_values,
'tags' : [],
'branch_tags' : [],
'plain_tags' : [],
# Populated by paging()/paging_sws()
'picklist' : [],
'picklist_len' : 0,
# Populated by pathrev_form()
'pathrev_action' : None,
'pathrev_hidden_values' : [],
'pathrev_clear_action' : None,
'pathrev_clear_hidden_values' : [],
'pathrev' : None,
'lastrev' : None,
}))
lastrev = pathrev_form(request, data)
data['diff_select_action'], data['diff_select_hidden_values'] = \
request.get_form(view_func=view_diff,
params={'r1': None, 'r2': None, 'tr1': None,
'tr2': None, 'diff_format': None})
data['logsort_action'], data['logsort_hidden_values'] = \
request.get_form(params={'logsort': None})
if pathtype is vclib.FILE:
if not request.pathrev or lastrev is None:
view_href, download_href, download_text_href, \
annotate_href, revision_href, prefer_markup \
= get_file_view_info(request, request.where, None, mime_type, None)
data.update({
'head_view_href': view_href,
'head_download_href': download_href,
'head_download_text_href': download_text_href,
'head_annotate_href': annotate_href,
'head_prefer_markup': prefer_markup,
})
fvi = get_file_view_info(request, request.where, None, mime_type, None)
data['head_view_href']= fvi.view_href
data['head_download_href']= fvi.download_href
data['head_download_text_href']= fvi.download_text_href
data['head_annotate_href']= fvi.annotate_href
data['head_prefer_markup']= fvi.prefer_markup
if request.pathrev and request.roottype == 'cvs':
view_href, download_href, download_text_href, \
annotate_href, revision_href, prefer_markup \
= get_file_view_info(request, request.where, None, mime_type)
data.update({
'tag_view_href': view_href,
'tag_download_href': download_href,
'tag_download_text_href': download_text_href,
'tag_annotate_href': annotate_href,
'tag_prefer_markup': prefer_markup,
})
fvi = get_file_view_info(request, request.where, None, mime_type)
data['tag_view_href']= fvi.view_href
data['tag_download_href']= fvi.download_href
data['tag_download_text_href']= fvi.download_text_href
data['tag_annotate_href']= fvi.annotate_href
data['tag_prefer_markup']= fvi.prefer_markup
else:
data['head_view_href'] = request.get_url(view_func=view_directory,
params={}, escape=1)
@@ -2307,23 +2377,20 @@ def view_log(request):
branches.append(branch)
data['default_branch'] = prep_tags(request, branches)
data['tags'] = tags = [ ]
data['branch_tags'] = branch_tags = []
data['plain_tags'] = plain_tags = []
for tag, rev in tagitems:
if rev.co_rev:
tags.append(_item(rev=rev.co_rev.string, name=tag))
data['tags'].append(_item(rev=rev.co_rev.string, name=tag))
if rev.is_branch:
branch_tags.append(tag)
data['branch_tags'].append(tag)
else:
plain_tags.append(tag)
data['plain_tags'].append(tag)
if cfg.options.use_pagesize:
if cfg.options.log_pagesize:
data['log_paging_action'], data['log_paging_hidden_values'] = \
request.get_form(params={'log_pagestart': None})
data['log_pagestart'] = int(request.query_dict.get('log_pagestart',0))
data['entries'] = paging_sws(data, 'entries', data['log_pagestart'],
'rev', cfg.options.use_pagesize, first)
'rev', cfg.options.log_pagesize, first)
generate_page(request, "log", data)
@@ -2377,8 +2444,6 @@ def view_cvsgraph(request):
if not cfg.options.use_cvsgraph:
raise debug.ViewVCException('Graph view is disabled', '403 Forbidden')
data = common_template_data(request)
# If cvsgraph can't find its supporting libraries, uncomment and set
# accordingly. Do the same in view_cvsgraph_image().
#os.environ['LD_LIBRARY_PATH'] = '/usr/lib:/usr/local/lib:/path/to/cvsgraph'
@@ -2410,11 +2475,11 @@ def view_cvsgraph(request):
escape=1, partial=1),
rcsfile), 'rb', 0)
data.update({
data = common_template_data(request)
data.merge(ezt.TemplateData({
'imagemap' : fp,
'imagesrc' : imagesrc,
})
}))
generate_page(request, "graph", data)
def search_file(repos, path_parts, rev, search_re):
@@ -2789,6 +2854,10 @@ def setup_diff(request):
def view_patch(request):
if 'diff' not in request.cfg.options.allowed_views:
raise debug.ViewVCException('Diff generation is disabled',
'403 Forbidden')
cfg = request.cfg
query_dict = request.query_dict
p1, p2, rev1, rev2, sym1, sym2 = setup_diff(request)
@@ -2822,6 +2891,10 @@ def view_patch(request):
def view_diff(request):
if 'diff' not in request.cfg.options.allowed_views:
raise debug.ViewVCException('Diff generation is disabled',
'403 Forbidden')
cfg = request.cfg
query_dict = request.query_dict
p1, p2, rev1, rev2, sym1, sym2 = setup_diff(request)
@@ -2913,20 +2986,35 @@ def view_diff(request):
no_format_params = request.query_dict.copy()
no_format_params['diff_format'] = None
fvi = get_file_view_info(request, path_left, rev1)
left = _item(date=rcsdiff_date_reformat(date1, cfg),
path=path_left, rev=rev1, tag=sym1)
left.view_href, left.download_href, left.download_text_href, \
left.annotate_href, left.revision_href, left.prefer_markup \
= get_file_view_info(request, path_left, rev1)
path=path_left,
rev=rev1,
tag=sym1,
view_href=fvi.view_href,
download_href=fvi.download_href,
download_text_href=fvi.download_text_href,
annotate_href=fvi.annotate_href,
revision_href=fvi.revision_href,
prefer_markup=fvi.prefer_markup)
fvi = get_file_view_info(request, path_right, rev2)
right = _item(date=rcsdiff_date_reformat(date2, cfg),
path=path_right, rev=rev2, tag=sym2)
right.view_href, right.download_href, right.download_text_href, \
right.annotate_href, right.revision_href, right.prefer_markup \
= get_file_view_info(request, path_right, rev2)
path=path_right,
rev=rev2,
tag=sym2,
view_href=fvi.view_href,
download_href=fvi.download_href,
download_text_href=fvi.download_text_href,
annotate_href=fvi.annotate_href,
revision_href=fvi.revision_href,
prefer_markup=fvi.prefer_markup)
diff_format_action, diff_format_hidden_values = \
request.get_form(params=no_format_params)
data = common_template_data(request)
data.update({
data.merge(ezt.TemplateData({
'left' : left,
'right' : right,
'raw_diff' : raw_diff_fp,
@@ -2938,11 +3026,9 @@ def view_diff(request):
'patch_href' : request.get_url(view_func=view_patch,
params=no_format_params,
escape=1),
})
data['diff_format_action'], data['diff_format_hidden_values'] = \
request.get_form(params=no_format_params)
'diff_format_action' : diff_format_action,
'diff_format_hidden_values' : diff_format_hidden_values,
}))
generate_page(request, "diff", data)
@@ -3136,11 +3222,11 @@ 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")
cfg = request.cfg
data = common_template_data(request)
query_dict = request.query_dict
try:
rev = request.repos._getrev(query_dict.get('revision'))
@@ -3169,6 +3255,7 @@ def view_revision(request):
more_changes_href = None
first_changes = None
first_changes_href = None
num_changes = len(changes)
if limit_changes and len(changes) > limit_changes:
more_changes = len(changes) - limit_changes
params = query_dict.copy()
@@ -3262,28 +3349,28 @@ def view_revision(request):
pathtype=None,
params={'revision': str(rev + 1)},
escape=1)
data.update({
jump_rev_action, jump_rev_hidden_values = \
request.get_form(params={'revision': None})
data = common_template_data(request)
data.merge(ezt.TemplateData({
'rev' : str(rev),
'author' : author,
'date' : date_str,
'log' : msg and htmlify(msg, cfg.options.mangle_email_addresses) or None,
'ago' : None,
'ago' : date is not None and html_time(request, date, 1) or None,
'changes' : changes,
'prev_href' : prev_rev_href,
'next_href' : next_rev_href,
'num_changes' : num_changes,
'limit_changes': limit_changes,
'more_changes': more_changes,
'more_changes_href': more_changes_href,
'first_changes': first_changes,
'first_changes_href': first_changes_href,
})
if date is not None:
data['ago'] = html_time(request, date, 1)
data['jump_rev_action'], data['jump_rev_hidden_values'] = \
request.get_form(params={'revision': None})
'jump_rev_action' : jump_rev_action,
'jump_rev_hidden_values' : jump_rev_hidden_values,
}))
if rev == youngest_rev:
request.server.addheader("Cache-control", "no-store")
generate_page(request, "revision", data)
@@ -3316,32 +3403,32 @@ def view_queryform(request):
% (request.rootname, request.where),
'403 Forbidden')
data = common_template_data(request)
data['query_action'], data['query_hidden_values'] = \
query_action, query_hidden_values = \
request.get_form(view_func=view_query, params={'limit_changes': None})
# 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['comment'] = request.query_dict.get('comment', '')
data['comment_match'] = request.query_dict.get('comment_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['limit_changes'] = int(request.query_dict.get('limit_changes',
request.cfg.options.limit_changes))
data['dir_href'] = request.get_url(view_func=view_directory, params={},
escape=1)
limit_changes = \
int(request.query_dict.get('limit_changes',
request.cfg.options.limit_changes))
data = common_template_data(request)
data.merge(ezt.TemplateData({
'branch' : request.query_dict.get('branch', ''),
'branch_match' : request.query_dict.get('branch_match', 'exact'),
'dir' : request.query_dict.get('dir', ''),
'file' : request.query_dict.get('file', ''),
'file_match' : request.query_dict.get('file_match', 'exact'),
'who' : request.query_dict.get('who', ''),
'who_match' : request.query_dict.get('who_match', 'exact'),
'comment' : request.query_dict.get('comment', ''),
'comment_match' : request.query_dict.get('comment_match', 'exact'),
'querysort' : request.query_dict.get('querysort', 'date'),
'date' : request.query_dict.get('date', 'hours'),
'hours' : request.query_dict.get('hours', '2'),
'mindate' : request.query_dict.get('mindate', ''),
'maxdate' : request.query_dict.get('maxdate', ''),
'limit_changes' : limit_changes,
'dir_href' : request.get_url(view_func=view_directory, params={},
escape=1),
}))
generate_page(request, "query_form", data)
def parse_date(datestr):
@@ -3812,7 +3899,7 @@ def view_query(request):
return
data = common_template_data(request)
data.update({
data.merge(ezt.TemplateData({
'sql': sql,
'english_query': english_query(request),
'queryform_href': request.get_url(view_func=view_queryform, escape=1),
@@ -3828,8 +3915,7 @@ def view_query(request):
params={'date': 'month'},
escape=1,
prefix=1),
})
}))
if format == 'rss':
generate_page(request, "rss", data, "application/rss+xml")
else:
@@ -3965,9 +4051,14 @@ def load_config(pathname=None, server=None):
cfg.set_defaults()
cfg.load_config(pathname, server and server.getenv("HTTP_HOST"))
# load mime types file
if cfg.general.mime_types_file:
mimetypes.init([cfg.general.mime_types_file])
# Load mime types file(s), but reverse the order -- our
# configuration uses a most-to-least preferred approach, but the
# 'mimetypes' package wants things the other way around.
if cfg.general.mime_types_files:
files = cfg.general.mime_types_files[:]
files.reverse()
files = map(lambda x: os.path.join(os.path.dirname(pathname), x), files)
mimetypes.init(files)
debug.t_end('load-config')
return cfg
@@ -4012,7 +4103,7 @@ def main(server, cfg):
finally:
debug.t_end('main')
debug.dump()
debug.t_dump(server.file())
debug.DumpChildren(server)

View File

@@ -50,7 +50,7 @@ numbers, and not literal):
9. Go into an empty directory and run the 'make-release' script:
tools/make-release viewvc-X.Y.Z X.Y.Z
tools/make-release viewvc-X.Y.Z tags/X.Y.Z
10. Verify the archive files:

View File

@@ -49,7 +49,7 @@
[else]
[is changes.type "add"]
<tr>
<td id="l[changes.line_number]">[if-any right.annotate_href]<a href="[right.annotate_href]#l[changes.line_number]">[changes.line_number]</a>[else][changes.line_number][end]</td>
<td class="vc_diff_line_number" id="l[changes.line_number]">[if-any right.annotate_href]<a href="[right.annotate_href]#l[changes.line_number]">[changes.line_number]</a>[else][changes.line_number][end]</td>
<td class="vc_diff_empty">&nbsp;</td>
<td class="vc_diff_add">&nbsp;[changes.right]</td>
</tr>
@@ -64,7 +64,7 @@
[is changes.type "change"]
<tr>
[if-any changes.have_right]
<td id="l[changes.line_number]">[if-any right.annotate_href]<a href="[right.annotate_href]#l[changes.line_number]">[changes.line_number]</a>[else][changes.line_number][end]</td>
<td class="vc_diff_line_number" id="l[changes.line_number]">[if-any right.annotate_href]<a href="[right.annotate_href]#l[changes.line_number]">[changes.line_number]</a>[else][changes.line_number][end]</td>
[else]
<td></td>
[end]
@@ -112,7 +112,7 @@
</tr>
[else]
<tr>
<td id="l[changes.line_number]">[if-any right.annotate_href]<a href="[right.annotate_href]#l[changes.line_number]">[changes.line_number]</a>[else][changes.line_number][end]</td>
<td class="vc_diff_line_number" id="l[changes.line_number]">[if-any right.annotate_href]<a href="[right.annotate_href]#l[changes.line_number]">[changes.line_number]</a>[else][changes.line_number][end]</td>
<td class="vc_diff_nochange">&nbsp;[changes.left]</td>
<td class="vc_diff_nochange">&nbsp;[changes.right]</td>
</tr>

View File

@@ -4,23 +4,31 @@
<thead>
<tr>
<th style="width: 200px" class="vc_header[is sortby "file"]_sort[end]">
<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 style="width: 96px" class="vc_header"></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

@@ -229,6 +229,8 @@ form { margin: 0; }
font-family: sans-serif;
font-size: smaller;
}
.vc_diff_line_number {
}
.vc_raw_diff {
background-color: #cccccc;
font-size: smaller;

View File

@@ -8,7 +8,7 @@
<hr />
<div class="vc_summary">
Revision [if-any revision_href]<a href="[revision_href]"><strong>[rev]</strong></a>[else]<strong>[rev]</strong>[end] -
([if-any annotation][is annotation "annotated"]<a href="[view_href]"><strong>hide annotations</strong></a>[end][else]<a href="[annotate_href]"><strong>show annotations</strong></a>[end])
([is annotation "annotated"]<a href="[view_href]"><strong>hide annotations</strong></a>[else]<a href="[annotate_href]"><strong>show annotations</strong></a>[end])
[if-any download_href](<a href="[download_href]"><strong>download</strong></a>)[end]
[if-any download_text_href](<a href="[download_text_href]"><strong>as text</strong></a>)[end]
@@ -43,14 +43,12 @@ Revision [if-any revision_href]<a href="[revision_href]"><strong>[rev]</strong><
[if-any lockinfo]
<br />Lock status: <img src="[docroot]/images/lock.png" alt="Locked" width="16" height="16" /> [lockinfo]
[end]
[if-any annotation]
[is annotation "binary"]
<br /><strong>Unable to calculate annotation data on binary file contents.</strong>
[end]
[is annotation "error"]
<br /><strong>Error occurred while calculating annotation data.</strong>
[end]
[end]
[is state "dead"]
<br /><strong><em>FILE REMOVED</em></strong>
[end]

View File

@@ -32,7 +32,7 @@
<td>[include "pathrev_form.ezt"]</td>
</tr>
[if-any search_re_form]
[if-any search_re_action]
<tr>
<td>Filter files by content:</td>
<td><form method="get" action="[search_re_action]" style="display: inline;">
@@ -63,7 +63,7 @@
</table>
[is cfg.options.use_pagesize "0"]
[is picklist_len "0"]
[else]
[is picklist_len "1"]
[else]

View File

@@ -2,7 +2,7 @@
[is pathtype "file"]
<a href="[up_href]"><img src="[docroot]/images/back_small.png" class="vc_icon" alt="Parent Directory" /> Parent Directory</a>
[if-any log_href]
| <a href="[log_href][if-any log_href_rev]#rev[log_href_rev][end]"><img src="[docroot]/images/log.png" class="vc_icon" alt="Revision Log" /> Revision Log</a>
| <a href="[log_href]"><img src="[docroot]/images/log.png" class="vc_icon" alt="Revision Log" /> Revision Log</a>
[end]
[if-any graph_href]
| <a href="[graph_href]"><img src="[docroot]/images/cvsgraph_16x16.png" class="vc_icon" alt="View Revision Graph" /> Revision Graph</a>

View File

@@ -1,4 +1,4 @@
[is cfg.options.use_pagesize "0"]
[is picklist_len "0"]
[else]
[is picklist_len "1"]
[else]
@@ -17,6 +17,4 @@
</select>
</form>
[end]
[end]
[end]

View File

@@ -28,6 +28,11 @@
<td>[if-any date][date][else]<em>(unknown date)</em>[end]
[if-any ago]<em>([ago] ago)</em>[end]</td>
</tr>
<tr align="left">
<th>Changed paths:</th>
<td><strong>[num_changes]</strong>
[if-any more_changes](showing only [limit_changes]; <a href="[more_changes_href]">show all</a>)[end][if-any first_changes](<a href="[first_changes_href]">show only first [first_changes]</a>)[end]</td>
</tr>
<tr align="left">
<th>Log Message:</th>
<td><pre class="vc_log">[log]</pre></td>
@@ -39,17 +44,6 @@
<p><strong>Changed paths:</strong></p>
[if-any more_changes]
<div>
Only [limit_changes] changes shown,
<a href="[more_changes_href]">display [more_changes] more changes...</a>
</div>
[end]
[if-any first_changes]
<div><a href="[first_changes_href]">Show only first [first_changes] changes...</div>
[end]
<table cellspacing="1" cellpadding="2">
<thead>
<tr align="left">
@@ -75,6 +69,11 @@
<td colspan="5">No changed paths.</td>
</tr>
[end]
[if-any more_changes]
<tr>
<td colspan="5">[[]<a href="[more_changes_href]">...</a>]</td>
</tr>
[end]
</tbody>
</table>

View File

@@ -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
@@ -48,7 +50,7 @@ for PLATFORM in unix windows; do
echo "Beginning build for ${PLATFORM}:"
echo " Exporting source code..."
svn export --quiet ${EOL} http://viewvc.tigris.org/svn/viewvc/${ROOT} ${TARGET}
svn export --quiet ${EOL} ${EXPORT_URL} ${TARGET}
### Various shifting, cleanup.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- Mode: python -*-
#
# Copyright (C) 1999-2007 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
@@ -58,10 +58,12 @@ FILE_INFO_LIST = [
("bin/cvsdbadmin", "bin/cvsdbadmin", 0755, 1, 0, 0),
("bin/svndbadmin", "bin/svndbadmin", 0755, 1, 0, 0),
("bin/make-database", "bin/make-database", 0755, 1, 0, 0),
("viewvc.conf.dist", "viewvc.conf.dist", 0644, 0, 0, 0),
("viewvc.conf.dist", "viewvc.conf", 0644, 0, 1, 0),
("cvsgraph.conf.dist", "cvsgraph.conf.dist", 0644, 0, 0, 0),
("cvsgraph.conf.dist", "cvsgraph.conf", 0644, 0, 1, 0),
("conf/viewvc.conf.dist", "viewvc.conf.dist", 0644, 0, 0, 0),
("conf/viewvc.conf.dist", "viewvc.conf", 0644, 0, 1, 0),
("conf/cvsgraph.conf.dist", "cvsgraph.conf.dist", 0644, 0, 0, 0),
("conf/cvsgraph.conf.dist", "cvsgraph.conf", 0644, 0, 1, 0),
("conf/mimetypes.conf.dist", "mimetypes.conf.dist", 0644, 0, 0, 0),
("conf/mimetypes.conf.dist", "mimetypes.conf", 0644, 0, 1, 0),
]
if sys.platform == "win32":
FILE_INFO_LIST.extend([