viewcvs-web r137 - in trunk: . bin docs lib lib/vcauth lib/vcauth/forbidden lib/vcauth/forbiddenre lib/vcauth/svnauthz lib/vclib lib/vclib/ccvs lib/vclib/ccvs/rcsparse lib/vclib/svn notes notes/logo scripts templates templates-contrib/newvc templates-contrib/tabbed/templates templates-contrib/tabbed/templates/docroot templates-contrib/tabbed/templates/docroot/images templates-contrib/tabbed/templates/include templates-contrib/viewsvn templates/docroot templates/docroot/images templates/include tparse viewvc.org viewvc.org/images viewvc.org/nightly windows www
- From: ovitters svn gnome org
- To: svn-commits-list gnome org
- Subject: viewcvs-web r137 - in trunk: . bin docs lib lib/vcauth lib/vcauth/forbidden lib/vcauth/forbiddenre lib/vcauth/svnauthz lib/vclib lib/vclib/ccvs lib/vclib/ccvs/rcsparse lib/vclib/svn notes notes/logo scripts templates templates-contrib/newvc templates-contrib/tabbed/templates templates-contrib/tabbed/templates/docroot templates-contrib/tabbed/templates/docroot/images templates-contrib/tabbed/templates/include templates-contrib/viewsvn templates/docroot templates/docroot/images templates/include tparse viewvc.org viewvc.org/images viewvc.org/nightly windows www
- Date: Mon, 3 Nov 2008 09:57:02 +0000 (UTC)
Author: ovitters
Date: Mon Nov 3 09:57:02 2008
New Revision: 137
URL: http://svn.gnome.org/viewvc/viewcvs-web?rev=137&view=rev
Log:
Merge latest change made upstream with local version.
Added:
trunk/lib/vcauth/forbiddenre/
- copied from r136, /tags/viewcvs-2008-11-03/lib/vcauth/forbiddenre/
trunk/lib/vclib/ccvs/bincvs.py
- copied unchanged from r136, /tags/viewcvs-2008-11-03/lib/vclib/ccvs/bincvs.py
trunk/lib/vclib/ccvs/ccvs.py
- copied unchanged from r136, /tags/viewcvs-2008-11-03/lib/vclib/ccvs/ccvs.py
trunk/lib/vclib/svn/svn_ra.py
- copied unchanged from r136, /tags/viewcvs-2008-11-03/lib/vclib/svn/svn_ra.py
trunk/lib/vclib/svn/svn_repos.py
- copied unchanged from r136, /tags/viewcvs-2008-11-03/lib/vclib/svn/svn_repos.py
trunk/notes/logo/
- copied from r136, /tags/viewcvs-2008-11-03/notes/logo/
trunk/templates-contrib/newvc/
- copied from r136, /tags/viewcvs-2008-11-03/templates-contrib/newvc/
trunk/templates-contrib/tabbed/templates/docroot/images/lock.png
- copied unchanged from r136, /tags/viewcvs-2008-11-03/templates-contrib/tabbed/templates/docroot/images/lock.png
trunk/templates-contrib/tabbed/templates/include/fileview.ezt
- copied unchanged from r136, /tags/viewcvs-2008-11-03/templates-contrib/tabbed/templates/include/fileview.ezt
trunk/templates-contrib/tabbed/templates/include/props.ezt
- copied unchanged from r136, /tags/viewcvs-2008-11-03/templates-contrib/tabbed/templates/include/props.ezt
trunk/templates-contrib/viewsvn/
- copied from r136, /tags/viewcvs-2008-11-03/templates-contrib/viewsvn/
trunk/templates/docroot/images/favicon.ico
- copied unchanged from r136, /tags/viewcvs-2008-11-03/templates/docroot/images/favicon.ico
trunk/templates/docroot/images/lock.png
- copied unchanged from r136, /tags/viewcvs-2008-11-03/templates/docroot/images/lock.png
trunk/templates/docroot/images/viewvc-logo.png
- copied unchanged from r136, /tags/viewcvs-2008-11-03/templates/docroot/images/viewvc-logo.png
trunk/templates/file.ezt
- copied unchanged from r136, /tags/viewcvs-2008-11-03/templates/file.ezt
trunk/templates/include/props.ezt
- copied unchanged from r136, /tags/viewcvs-2008-11-03/templates/include/props.ezt
trunk/viewvc.org/favicon.ico
- copied unchanged from r136, /tags/viewcvs-2008-11-03/viewvc.org/favicon.ico
Modified:
trunk/ (props changed)
trunk/CHANGES
trunk/INSTALL
trunk/LICENSE.html
trunk/bin/cvsdbadmin
trunk/bin/loginfo-handler
trunk/bin/make-database
trunk/bin/standalone.py
trunk/bin/svndbadmin
trunk/docs/template-authoring-guide.html
trunk/docs/upgrading-howto.html
trunk/docs/url-reference.html
trunk/lib/blame.py
trunk/lib/config.py
trunk/lib/cvsdb.py
trunk/lib/debug.py
trunk/lib/popen.py
trunk/lib/query.py
trunk/lib/vcauth/__init__.py
trunk/lib/vcauth/forbidden/__init__.py
trunk/lib/vcauth/svnauthz/__init__.py
trunk/lib/vclib/__init__.py
trunk/lib/vclib/ccvs/__init__.py
trunk/lib/vclib/ccvs/blame.py
trunk/lib/vclib/ccvs/rcsparse/common.py
trunk/lib/vclib/ccvs/rcsparse/default.py
trunk/lib/vclib/ccvs/rcsparse/texttools.py
trunk/lib/vclib/svn/__init__.py
trunk/lib/viewvc.py
trunk/notes/releases.txt
trunk/scripts/last-merge-tag
trunk/templates-contrib/tabbed/templates/annotate.ezt
trunk/templates-contrib/tabbed/templates/diff.ezt
trunk/templates-contrib/tabbed/templates/directory.ezt
trunk/templates-contrib/tabbed/templates/docroot/styles.css
trunk/templates-contrib/tabbed/templates/include/diff_form.ezt
trunk/templates-contrib/tabbed/templates/include/dir_footer.ezt
trunk/templates-contrib/tabbed/templates/include/dir_header.ezt
trunk/templates-contrib/tabbed/templates/include/header.ezt
trunk/templates-contrib/tabbed/templates/include/log_footer.ezt
trunk/templates-contrib/tabbed/templates/include/log_header.ezt
trunk/templates-contrib/tabbed/templates/include/pathrev_form.ezt
trunk/templates-contrib/tabbed/templates/log.ezt
trunk/templates-contrib/tabbed/templates/markup.ezt
trunk/templates-contrib/tabbed/templates/query_form.ezt
trunk/templates-contrib/tabbed/templates/query_results.ezt
trunk/templates-contrib/tabbed/templates/revision.ezt
trunk/templates/diff.ezt
trunk/templates/dir_new.ezt
trunk/templates/directory.ezt
trunk/templates/docroot/help_dirview.html
trunk/templates/docroot/help_log.html
trunk/templates/docroot/help_query.html
trunk/templates/docroot/help_rootview.html
trunk/templates/docroot/styles.css
trunk/templates/include/diff_form.ezt
trunk/templates/include/dir_footer.ezt
trunk/templates/include/dir_header.ezt
trunk/templates/include/header.ezt
trunk/templates/include/log_header.ezt
trunk/templates/include/paging.ezt
trunk/templates/include/pathrev_form.ezt
trunk/templates/include/sort.ezt
trunk/templates/log.ezt
trunk/templates/log_table.ezt
trunk/templates/query_form.ezt
trunk/templates/revision.ezt
trunk/tparse/tparse.h
trunk/viewvc-install
trunk/viewvc.conf.dist
trunk/viewvc.org/contact.html
trunk/viewvc.org/contributing.html
trunk/viewvc.org/download.html
trunk/viewvc.org/faq.html
trunk/viewvc.org/images/title.jpg
trunk/viewvc.org/images/title.xcf
trunk/viewvc.org/index.html
trunk/viewvc.org/nightly/build-viewvc-snapshot
trunk/viewvc.org/styles.css
trunk/viewvc.org/who.html
trunk/windows/README
trunk/www/index.html
Modified: trunk/CHANGES
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Mon Nov 3 09:57:02 2008
@@ -17,8 +17,56 @@
* add support for disabling the checkout view (now the default state)
* 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
+ * add support for per-root configuration overrides (issue #371)
* add support for optional email address mangling (issue #290)
+ * extensible path-based authorization subsystem (issue #268), supporting:
+ - Subversion authz files (new)
+ - regexp-based path hiding (for compat with 1.0.x)
+ - file glob top-level directory hiding (for compat with 1.0.x)
+ * allow default file view to be "markup" (issue #305)
+ * add support for displaying file/directory properties (issue #39)
+ * pagination improvements
+ * add gzip output encoding support for template-driven pages
+ * fix cache control bugs (issue #259)
+ * add RSS feed URL generation for file history
+ * add support for remote creation of ViewVC checkins database
+ * add integration with Pygments for syntax highlighting
+ * preserve executability of Subversion files in tarballs (issue #233)
+ * add ability to set Subversion runtime config dir (issue #351, issue #339)
+ * 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)
+
+Version 1.0.7 (released 14-Oct-2008)
+
+ * fix regression in the 'as text' download view (issue #373)
+
+Version 1.0.6 (released 16-Sep-2008)
+
+ * security fix: ignore arbitrary user-provided MIME types (issue #354)
+ * fix bug in regexp search filter when used with sticky tag (issue #346)
+ * fix bug in handling of certain 'co' output (issue #348)
+ * fix regexp search filter template bug
+ * fix annotate code syntax error
+ * fix mod_python import cycle (issue #369)
+
+Version 1.0.5 (released 28-Feb-2008)
+
+ * security fix: omit commits of all-forbidden files from query results
+ * security fix: disallow direct URL navigation to hidden CVSROOT folder
+ * security fix: strip forbidden paths from revision view
+ * security fix: don't traverse log history thru forbidden locations
+ * security fix: honor forbiddenness via diff view path parameters
+ * new 'forbiddenre' regexp-based path authorization feature
+ * fix root name conflict resolution inconsistencies (issue #287)
+ * fix an oversight in the CVS 1.12.9 loginfo-handler support
+ * fix RSS feed content type to be more specific (issue #306)
+ * fix entity escaping problems in RSS feed data (issue #238)
+ * fix bug in tarball generation for remote Subversion repositories
+ * fix query interface file-count-limiting logic
+ * fix query results plus/minus count to ignore forbidden files
+ * fix blame error caused by 'svn' unable to create runtime config dir
Version 1.0.4 (released 10-Apr-2007)
Modified: trunk/INSTALL
==============================================================================
--- trunk/INSTALL (original)
+++ trunk/INSTALL Mon Nov 3 09:57:02 2008
@@ -43,13 +43,8 @@
* MySQL 3.22 and MySQLdb 0.9.0 or later to create a commit database
(http://www.mysql.com/)
(http://sourceforge.net/projects/mysql-python)
- * one of the following syntax highlighting programs:
- - GNU enscript
- (http://www.codento.com/people/mtr/genscript/)
- - Highlight 2.2.10 or later (we recommend 2.4.5 or later)
- (http://www.andre-simon.de/)
- - GNU source-highlight 2.5 or later
- (http://www.gnu.org/software/src-highlite/)
+ * Pygments 0.9 or later, syntax highlighting engine
+ (http://pygments.org)
* CvsGraph 1.5.0 or later, graphical CVS revision tree generator
(http://www.akhphd.au.dk/~bertho/cvsgraph/)
@@ -225,8 +220,8 @@
you copied the files to.
Note: If you are using Mod_Python under Apache 1.3 the tarball generation
- and enscript colorizing features may not work because they use
- multithreading. They do work fine with Apache 2.
+ feature may not work because it uses multithreading. This works fine
+ under Apache 2.
continue with step 3).
@@ -256,6 +251,16 @@
http://<server_name>/viewvc/~checkout~/<module_name>
http://<server_name>/viewvc/<module_name>.tar.gz?view=tar
+5) Optional: Protect your ViewVC instance from server-whacking webcrawlers.
+
+ As ViewVC is a web-based application which each page containing various
+ links to other pages and views, you can expect your server's performance
+ to suffer if a webcrawler finds your ViewVC instance and begins
+ traversing those links. We highly recommend that you add your ViewVC
+ location to a site-wide robots.txt file. Visit the Wikipedia page
+ for Robots.txt (http://en.wikipedia.org/wiki/Robots.txt) for more
+ information.
+
UPGRADING VIEWVC
-----------------
@@ -386,21 +391,11 @@
ENABLING SYNTAX COLORATION
--------------------------
-Enscript and Highlight are two programs that can colorize source code
-for a lot of languages. ViewVC can be configured to use either one.
-
-1) Install Enscript, Highlight, or GNU Source Highlight using your
- system's package manager, or by downloading from the project home pages.
-
-2) Set either the 'use_enscript' or 'use_highlight' or 'use_source_highlight'
- option in viewvc.conf to 1.
-
-3) You may also need to set 'enscript', 'highlight', or 'source_highlight'
- option in the [utilities] section if the executables are not located
- on the system PATH.
-
-That's it! Now when you view the contents of recognized filetypes in
-ViewVC, you should see colorized syntax.
+ViewVC uses Pygments (http://pygments.org) for syntax coloration. You
+need only install a suitable version of that module, and if ViewVC
+finds it in your Python module path, it will use it (unless you
+specifically disable the feature by setting use_pygments = 0 in your
+viewvc.conf file).
CVSGRAPH CONFIGURATION
@@ -438,9 +433,12 @@
Unlike the CVS integration, which simply wraps the RCS and CVS utility
programs, the Subversion integration requires additional Python
libraries. To use ViewVC with Subversion, make sure you have both
-Subversion itself and the Subversion Python bindings installed. See
-Subversion's installation notes for more details on how to build and
-install these items.
+Subversion itself and the Subversion Python bindings installed. These
+can be obtained through typical package distribution mechanisms, or
+may be build from source. (See the files 'INSTALL' and
+'subversion/bindings/swig/INSTALL' in the Subversion source tree for
+more details on how to build and install Subversion and its Python
+bindings.)
Generally speaking, you'll know when your installation of Subversion's
bindings has been successful if you can import the 'svn.core' module
Modified: trunk/LICENSE.html
==============================================================================
--- trunk/LICENSE.html (original)
+++ trunk/LICENSE.html Mon Nov 3 09:57:02 2008
@@ -15,7 +15,7 @@
<blockquote>
-<p><strong>Copyright © 1999-2007 The ViewCVS Group. All rights
+<p><strong>Copyright © 1999-2008 The ViewCVS Group. All rights
reserved.</strong></p>
<p>By using ViewVC, you agree to the terms and conditions set forth
@@ -58,6 +58,7 @@
<li>September 5, 2002 — copyright years updated</li>
<li>March 17, 2006 — software renamed from "ViewCVS"</li>
<li>April 10, 2007 — copyright years updated</li>
+ <li>February 22, 2008 — copyright years updated</li>
</ul>
</body>
Modified: trunk/bin/cvsdbadmin
==============================================================================
--- trunk/bin/cvsdbadmin (original)
+++ trunk/bin/cvsdbadmin Mon Nov 3 09:57:02 2008
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
#
# 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
@@ -43,7 +43,7 @@
import string
import cvsdb
import viewvc
-import vclib.bincvs
+import vclib.ccvs
def UpdateFile(db, repository, path, update, quiet_level):
@@ -129,7 +129,8 @@
3. %s [[-q] -q] purge REPOS-PATH
1. Rebuild the commit database information for the repository located
- at REPOS-PATH.
+ at REPOS-PATH, after first purging information specific to that
+ repository (if any).
2. Update the commit database information for all unrecorded commits
in the repository located at REPOS-PATH.
@@ -168,6 +169,7 @@
# get repository and path, and do the work
root, path_parts = RootPath(args[2], quiet_level)
+ rootpath = vclib.ccvs.canonicalize_rootpath(root)
try:
cfg = viewvc.load_config(CONF_PATHNAME)
db = cvsdb.ConnectDatabase(cfg)
@@ -178,8 +180,8 @@
db.PurgeRepository(root)
if command in ('rebuild', 'update'):
- repository = vclib.bincvs.BinCVSRepository(None, root,
- cfg.utilities)
+ repository = vclib.ccvs.CVSRepository(None, rootpath, None,
+ cfg.utilities, 0)
RecurseUpdate(db, repository, path_parts,
command == 'update', quiet_level)
except KeyboardInterrupt:
Modified: trunk/bin/loginfo-handler
==============================================================================
--- trunk/bin/loginfo-handler (original)
+++ trunk/bin/loginfo-handler Mon Nov 3 09:57:02 2008
@@ -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.
#
# 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
@@ -44,7 +44,7 @@
import re
import cvsdb
import viewvc
-import vclib.bincvs
+import vclib.ccvs
DEBUG_FLAG = 0
@@ -223,7 +223,8 @@
def ProcessLoginfo(rootpath, directory, files):
cfg = viewvc.load_config(CONF_PATHNAME)
db = cvsdb.ConnectDatabase(cfg)
- repository = vclib.bincvs.BinCVSRepository(None, rootpath, cfg.utilities)
+ repository = vclib.ccvs.CVSRepository(None, rootpath, None,
+ cfg.utilities, 0)
# split up the directory components
dirpath = filter(None, string.split(os.path.normpath(directory), os.sep))
Modified: trunk/bin/make-database
==============================================================================
--- trunk/bin/make-database (original)
+++ trunk/bin/make-database Mon Nov 3 09:57:02 2008
@@ -20,11 +20,12 @@
import popen2
INTRO_TEXT = """\
-This script creates the database and tables in MySQL used by the ViewVC
-checkin database. You will be prompted for: database user, database user
-password, and database name. This script will use mysql to create the
-database for you. You will then need to set the appropriate parameters
-in your viewvc.conf file under the [cvsdb] section.
+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="""\
@@ -121,24 +122,27 @@
"""
if __name__ == "__main__":
+ try:
print INTRO_TEXT
-
+
+ # 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]: ")
- if not dbase:
- dbase = "ViewVC"
+ dbase = 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 ""
if sys.platform == "win32":
- # popen2.Popen3 is not provided on windows
- cmd = "mysql --user=%s --password=%s" % (user, passwd)
- mysql = os.popen(cmd, "w")
+ cmd = "mysql --user=%s --password=%s %s "\
+ % (user, passwd, 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 ; } 2>&1" % (user, passwd)
+ cmd = "{ mysql --user=%s --password=%s %s ; } 2>&1" \
+ % (user, passwd, host_option)
pipes = popen2.Popen3(cmd)
pipes.tochild.write(dscript)
pipes.tochild.close()
@@ -146,9 +150,11 @@
status = pipes.wait()
if status:
- print "[ERROR] the database did not create sucessfully."
- sys.exit(1)
+ print "[ERROR] the database did not create sucessfully."
+ sys.exit(1)
print "Database created successfully."
- sys.exit(0)
+ except KeyboardInterrupt:
+ pass
+ sys.exit(0)
Modified: trunk/bin/standalone.py
==============================================================================
--- trunk/bin/standalone.py (original)
+++ trunk/bin/standalone.py Mon Nov 3 09:57:02 2008
@@ -17,7 +17,7 @@
__author__ = "Peter Funk <pf artcom-gmbh de>"
__date__ = "11 November 2001"
-__version__ = "$Revision: 1590 $"
+__version__ = "$Revision: 1962 $"
__credits__ = """Guido van Rossum, for an excellent programming language.
Greg Stein, for writing ViewCVS in the first place.
Ka-Ping Yee, for the GUI code and the framework stolen from pydoc.py.
@@ -63,6 +63,7 @@
else:
host = 'localhost'
script_alias = 'viewvc'
+ config_file = None
# --- web browser interface: ----------------------------------------------
@@ -284,7 +285,7 @@
# XXX Move this code out of this function.
# Early loading of configuration here. Used to
# allow tinkering with some configuration settings:
- handle_config()
+ handle_config(options.config_file)
if options.repositories:
cfg.general.default_root = "Development"
for repo_name in options.repositories.keys():
@@ -331,9 +332,9 @@
pass
print 'server stopped'
-def handle_config():
+def handle_config(config_file):
global cfg
- cfg = viewvc.load_config(CONF_PATHNAME)
+ cfg = viewvc.load_config(config_file or CONF_PATHNAME)
# --- graphical interface: --------------------------------------------------
@@ -576,8 +577,9 @@
class BadUsage(Exception): pass
try:
- opts, args = getopt.getopt(argv[1:], 'gdp:r:h:s:',
- ['gui', 'daemon', 'port=', 'repository=', 'script-alias='])
+ opts, args = getopt.getopt(argv[1:], 'gdc:p:r:h:s:',
+ ['gui', 'daemon', 'config-file=', 'host=',
+ 'port=', 'repository=', 'script-alias='])
for opt, val in opts:
if opt in ('-g', '--gui'):
options.start_gui = 1
@@ -601,6 +603,10 @@
elif opt in ('-s', '--script-alias'):
options.script_alias = \
string.join(filter(None, string.split(val, '/')), '/')
+ elif opt in ('-c', '--config-file'):
+ options.config_file = val
+ if options.start_gui and options.config_file:
+ raise BadUsage, "--config-file option is not valid in GUI mode."
if not options.start_gui and not options.port:
raise BadUsage, "You must supply a valid port, or run in GUI mode."
if options.daemon:
@@ -608,7 +614,7 @@
if pid != 0:
sys.exit()
if options.start_gui:
- gui(options.host, options.port)
+ gui(options.host, options.port, options.config_file)
return
elif options.port:
def ready(server):
@@ -626,10 +632,16 @@
sys.stderr.write("""Usage: %(cmd)s [OPTIONS]
Run a simple, standalone HTTP server configured to serve up ViewVC
-requests. ViewVC configuration is read from viewvc.conf file, if available.
+requests.
Options:
+ --config-file=PATH (-c) Use the file at PATH as the ViewVC configuration
+ file. If not specified, ViewVC will try to use
+ the configuration file in its installation tree;
+ otherwise, built-in default values are used.
+ (Not valid in GUI mode.)
+
--daemon (-d) Background the server process.
--host=HOST (-h) Start the server listening on HOST. You need
Modified: trunk/bin/svndbadmin
==============================================================================
--- trunk/bin/svndbadmin (original)
+++ trunk/bin/svndbadmin Mon Nov 3 09:57:02 2008
@@ -66,6 +66,7 @@
import cvsdb
import viewvc
+import vclib
class SvnRepo:
"""Class used to manage a connection to a SVN repository."""
@@ -278,7 +279,8 @@
3. %s [-v] purge REPOS-PATH
1. Rebuild the commit database information for the repository located
- at REPOS-PATH across all revisions.
+ at REPOS-PATH across all revisions, after first purging
+ information specific to that repository (if any).
2. Update the commit database information for the repository located
at REPOS-PATH across all revisions or, optionally, only for the
@@ -324,8 +326,9 @@
repository = args[2]
if not os.path.exists(repository):
- sys.stderr.write('ERROR: could not find repository %s\n' % repository)
+ sys.stderr.write('ERROR: could not find repository %s\n' % args[2])
usage()
+ repository = vclib.svn.canonicalize_rootpath(repository)
revs = []
if len(sys.argv) > 3:
Modified: trunk/docs/template-authoring-guide.html
==============================================================================
--- trunk/docs/template-authoring-guide.html (original)
+++ trunk/docs/template-authoring-guide.html Mon Nov 3 09:57:02 2008
@@ -59,13 +59,13 @@
<li><a href="#variables-common">Common Template Variable Set (COMMON)</a></li>
<li><a href="#variables-pathrev">Path Revision Form Variable Set (PATHREV)</a></li>
<li><a href="#variables-paging">Paging Form Variable Set (PAGING)</a></li>
- <li><a href="#variables-annotate">Annotation View (annotate.ezt)</a></li>
+ <li><a href="#variables-properties">Property Listing Variable Set (PROPERTIES)</a></li>
+ <li><a href="#variables-file">File Contents View (file.ezt)</a></li>
<li><a href="#variables-graph">Revision Graph View (graph.ezt)</a></li>
<li><a href="#variables-diff">File Difference View (diff.ezt)</a></li>
<li><a href="#variables-directory">Directory Listing View (directory.ezt)</a></li>
<li><a href="#variables-error">Error View (error.ezt)</a></li>
<li><a href="#variables-log">Revision Log View (log.ezt)</a></li>
- <li><a href="#variables-markup">File Contents View (markup.ezt)</a></li>
<li><a href="#variables-query_results">Revision History Query Results View (query_results.ezt, rss.ezt)</a></li>
<li><a href="#variables-query_form">Revision History Query Form View (query_form.ezt)</a></li>
<li><a href="#variables-revision">Revision/ChangeSet View (revision.ezt)</a></li>
@@ -113,16 +113,6 @@
of the configuration file.</td>
</tr>
<tr class="varlevel1">
- <td class="varname">change_root_action</td>
- <td>String</td>
- <td>Form action URL for the root selection form.</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">change_root_hidden_values</td>
- <td>String</td>
- <td>Hidden value HTML markup for the root selection form.</td>
-</tr>
-<tr class="varlevel1">
<td class="varname">docroot</td>
<td>String</td>
<td>URL of the static documents directory, generally used for
@@ -160,6 +150,11 @@
abstract name is <var>l10n</var>.</td>
</tr>
<tr class="varlevel1">
+ <td class="varname">lockinfo</td>
+ <td>String</td>
+ <td>Information about the lock status of the current resource.</td>
+</tr>
+<tr class="varlevel1">
<td class="varname">log_href</td>
<td>String</td>
<td>URL of the ViewVC revision log view for the current
@@ -223,33 +218,10 @@
<td>Name of the current repository (root).</td>
</tr>
<tr class="varlevel1">
- <td class="varname">roots</td>
- <td>List</td>
- <td>Set of configured viewable repositories.</td>
-</tr>
-<tr class="varlevel2">
- <td class="varname">roots.name</td>
- <td>String</td>
- <td>Name of a configured repository.</td>
-</tr>
-<tr class="varlevel2">
- <td class="varname">roots.path</td>
+ <td class="varname">roots_href</td>
<td>String</td>
- <td>Server-local location of a configured repository. WARNING: Revealing
- information to untrusted guests about the details of your server
- configuration can have negative security implications. Use this
- token at your own risk.</td>
-</tr>
-<tr class="varlevel2">
- <td class="varname">roots.type</td>
- <td>String</td>
- <td>Version control type of a configured repository. Valid
- values: <tt>cvs</tt>, <tt>svn</tt>.</td>
-</tr>
-<tr class="varlevel2">
- <td class="varname">roots.href</td>
- <td>String</td>
- <td>URL of root directory view for a configured repository.</td>
+ <td>URL of ViewVC root listing view. Valid only when ViewVC is
+ configured in roots-as-url-components mode.</td>
</tr>
<tr class="varlevel1">
<td class="varname">rootpath</td>
@@ -281,6 +253,11 @@
<td>Link to the current object's parent directory view.</td>
</tr>
<tr class="varlevel1">
+ <td class="varname">username</td>
+ <td>String</td>
+ <td>Authenticated username of the requesting user.</td>
+</tr>
+<tr class="varlevel1">
<td class="varname">view</td>
<td>String</td>
<td>Name of the current view. Valid values: <tt>annotate</tt>
@@ -343,8 +320,8 @@
</tr>
<tr class="varlevel1">
<td class="varname">pathrev_hidden_values</td>
- <td>String</td>
- <td>Hidden value HTML markup for the revision/tag selection form.</td>
+ <td>List</td>
+ <td>Hidden value name/value pairs for the revision/tag selection form.</td>
</tr>
<tr class="varlevel1">
<td class="varname">pathrev_clear_action</td>
@@ -353,8 +330,8 @@
</tr>
<tr class="varlevel1">
<td class="varname">pathrev_clear_hidden_values</td>
- <td>String</td>
- <td>Hidden value HTML markup for the path revision clear button.</td>
+ <td>List</td>
+ <td>Hidden value name/value pairs for the path revision clear button.</td>
</tr>
</tbody>
</table>
@@ -377,9 +354,9 @@
<td>List of pages that make up the current directory or log view.</td>
</tr>
<tr class="varlevel2">
- <td class="varname">picklist.start</td>
+ <td class="varname">picklist.count</td>
<td>String</td>
- <td>Name of first item on the page</td>
+ <td>Number of the first item on the page (indexed from 0)</td>
</tr>
<tr class="varlevel2">
<td class="varname">picklist.end</td>
@@ -387,14 +364,21 @@
<td>Name of last item on the page</td>
</tr>
<tr class="varlevel2">
+ <td class="varname">picklist.more</td>
+ <td>Boolean</td>
+ <td>If set, indicates that this picklist item is a placeholder for
+ an unspecified number of additional pages. In this case,
+ <code>picklist.end</code> is undefined.</td>
+</tr>
+<tr class="varlevel2">
<td class="varname">picklist.page</td>
<td>String</td>
<td>Page number (indexed from 1)</td>
</tr>
<tr class="varlevel2">
- <td class="varname">picklist.count</td>
+ <td class="varname">picklist.start</td>
<td>String</td>
- <td>Number of the first item on the page (indexed from 0)</td>
+ <td>Name of first item on the page</td>
</tr>
<tr class="varlevel1">
<td class="varname">picklist_len</td>
@@ -406,7 +390,44 @@
</div>
<div class="h3">
-<h3 id="variables-annotate">Annotation View (annotate.ezt)</h3>
+<h3 id="variables-properties">Property Listing Variable Set (PROPERTIES)</h3>
+<table>
+<thead>
+<tr>
+ <th>Variable</th>
+ <th>Type</th>
+ <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr class="varlevel1">
+ <td class="varname">properties</td>
+ <td>List</td>
+ <td>List of item properties set on the current directory, minus
+ those with undisplayable names.</td>
+</tr>
+<tr class="varlevel2">
+ <td class="varname">properties.name</td>
+ <td>String</td>
+ <td>Name of an item property.</td>
+</tr>
+<tr class="varlevel2">
+ <td class="varname">properties.undisplayable</td>
+ <td>Boolean</td>
+ <td>Indicates whether or not the value of this property is
+ undisplayable (by virtue of not being UTF-8 text).</td>
+</tr>
+<tr class="varlevel2">
+ <td class="varname">properties.value</td>
+ <td>String</td>
+ <td>Value of this property.</td>
+</tr>
+</tbody>
+</table>
+</div>
+
+<div class="h3">
+<h3 id="variables-file">File Contents View (file.ezt)</h3>
<table>
<thead>
<tr>
@@ -418,7 +439,8 @@
<tbody>
<tr class="include">
<td colspan="3">Includes all variables from the
- <a href="#variables-common">COMMON</a> variable set</td>
+ <a href="#variables-common">COMMON</a> and
+ <a href="#variables-properties">PROPERTIES</a> variable sets</td>
</tr>
<tr class="varlevel1">
<td class="varname">ago</td>
@@ -426,6 +448,14 @@
<td>Text description of the time elapsed since <var>date</var>.</td>
</tr>
<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>
+</tr>
+<tr class="varlevel1">
<td class="varname">author</td>
<td>String</td>
<td>Author of the revision being viewed.</td>
@@ -454,6 +484,13 @@
being viewed.</td>
</tr>
<tr class="varlevel1">
+ <td class="varname">image_src_href</td>
+ <td>String</td>
+ <td>URL used to display the current revision of the file as an
+ embedded image. (Set only if the file is not a web-viewable
+ image.)</td>
+</tr>
+<tr class="varlevel1">
<td class="varname">lines</td>
<td>List</td>
<td>Set of objects containing information about the most recent
@@ -473,7 +510,7 @@
the line.</td>
</tr>
<tr class="varlevel2">
- <td class="varname">lines.diff_url</td>
+ <td class="varname">lines.diff_href</td>
<td>String</td>
<td>URL of the ViewVC file difference view which displays the
modification of the line.</td>
@@ -687,8 +724,8 @@
</tr>
<tr class="varlevel1">
<td class="varname">diff_format_hidden_values</td>
- <td>String</td>
- <td>Hidden value HTML markup for the diff format selection form.</td>
+ <td>List</td>
+ <td>Hidden value name/value pairs for the diff format selection form.</td>
</tr>
<tr class="varlevel1">
<td class="varname">left</td>
@@ -836,8 +873,9 @@
<tr class="include">
<td colspan="3">Includes all variables from the
<a href="#variables-common">COMMON</a>,
- <a href="#variables-pathrev">PATHREV</a>, and
- <a href="#variables-paging">PAGING</a> variable sets</td>
+ <a href="#variables-pathrev">PATHREV</a>,
+ <a href="#variables-paging">PAGING</a>, and
+ <a href="#variables-properties">PROPERTIES</a> variable sets</td>
</tr>
<tr class="varlevel1">
<td class="varname">attic_showing</td>
@@ -866,8 +904,8 @@
</tr>
<tr class="varlevel1">
<td class="varname">dir_paging_hidden_values</td>
- <td>String</td>
- <td>Hidden value HTML markup for the page selection form.</td>
+ <td>List</td>
+ <td>Hidden value name/value pairs for the page selection form.</td>
</tr>
<tr class="varlevel1">
<td class="varname">entries</td>
@@ -923,6 +961,11 @@
entry.</td>
</tr>
<tr class="varlevel2">
+ <td class="varname">entries.lockinfo</td>
+ <td>String</td>
+ <td>Information about the lock status of the directory entry.</td>
+</tr>
+<tr class="varlevel2">
<td class="varname">entries.log</td>
<td>String</td>
<td>Log message of last modification to the directory entry.</td>
@@ -1059,8 +1102,8 @@
</tr>
<tr class="varlevel1">
<td class="varname">search_re_hidden_values</td>
- <td>String</td>
- <td>Hidden value HTML markup for the regular expression search form.</td>
+ <td>List</td>
+ <td>Hidden value name/value pairs for the regular expression search form.</td>
</tr>
<tr class="varlevel1">
<td class="varname">show_attic_href</td>
@@ -1181,11 +1224,6 @@
<a href="#variables-paging">PAGING</a> variable sets</td>
</tr>
<tr class="varlevel1">
- <td class="varname">annotate_href</td>
- <td>String</td>
- <td>URL for annotate view of the HEAD revision of the file.</td>
-</tr>
-<tr class="varlevel1">
<td class="varname">branch_tags</td>
<td>List</td>
<td>Names of branch tags in the file. CVS only.</td>
@@ -1210,19 +1248,8 @@
</tr>
<tr class="varlevel1">
<td class="varname">diff_select_hidden_values</td>
- <td>String</td>
- <td>Hidden value HTML markup for the diff selection form.</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">download_href</td>
- <td>String</td>
- <td>URL to download the HEAD revision of the file.</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">download_text_href</td>
- <td>String</td>
- <td>URL to download the HEAD revision of the file as
- <tt>text/plain</tt>.</td>
+ <td>List</td>
+ <td>Hidden value name/value pairs for the diff selection form.</td>
</tr>
<tr class="varlevel1">
<td class="varname">entries</td>
@@ -1357,6 +1384,11 @@
<td>URL to download the file revision as <tt>text/plain</tt>.</td>
</tr>
<tr class="varlevel2">
+ <td class="varname">entries.lockinfo</td>
+ <td>String</td>
+ <td>Information about the lock status of this revision.</td>
+</tr>
+<tr class="varlevel2">
<td class="varname">entries.log</td>
<td>String</td>
<td>Revision log message.</td>
@@ -1451,6 +1483,33 @@
for a directory revision.</td>
</tr>
<tr class="varlevel1">
+ <td class="varname">head_annotate_href</td>
+ <td>String</td>
+ <td>URL for annotate view of the HEAD revision of the file.</td>
+</tr>
+<tr class="varlevel1">
+ <td class="varname">head_download_href</td>
+ <td>String</td>
+ <td>URL to download the HEAD revision of the file.</td>
+</tr>
+<tr class="varlevel1">
+ <td class="varname">head_download_text_href</td>
+ <td>String</td>
+ <td>URL to download the HEAD revision of the file as
+ <tt>text/plain</tt>.</td>
+</tr>
+<tr class="varlevel1">
+ <td class="varname">head_prefer_markup</td>
+ <td>Boolean</td>
+ <td>Indicates whether to make the default HEAD file link a link to the markup
+ page instead of the checkout page.</td>
+</tr>
+<tr class="varlevel1">
+ <td class="varname">head_view_href</td>
+ <td>String</td>
+ <td>URL for markup view of the HEAD revision of the file.</td>
+</tr>
+<tr class="varlevel1">
<td class="varname">human_readable</td>
<td>Boolean</td>
<td>Indicates whether or not currently selected diff format
@@ -1470,8 +1529,8 @@
</tr>
<tr class="varlevel1">
<td class="varname">log_paging_hidden_values</td>
- <td>String</td>
- <td>Hidden value HTML markup for the page selection form.</td>
+ <td>List</td>
+ <td>Hidden value name/value pairs for the page selection form.</td>
</tr>
<tr class="varlevel1">
<td class="varname">logsort</td>
@@ -1486,8 +1545,8 @@
</tr>
<tr class="varlevel1">
<td class="varname">logsort_hidden_values</td>
- <td>String</td>
- <td>Hidden value HTML markup for the log sort drop down box</td>
+ <td>List</td>
+ <td>Hidden value name/value pairs for the log sort drop down box</td>
</tr>
<tr class="varlevel1">
<td class="varname">mime_type</td>
@@ -1500,12 +1559,6 @@
<td>Names of non-branch in the file. CVS only.</td>
</tr>
<tr class="varlevel1">
- <td class="varname">prefer_markup</td>
- <td>Boolean</td>
- <td>Indicates whether to make the default file link a link to the markup
- page instead of the checkout page.</td>
-</tr>
-<tr class="varlevel1">
<td class="varname">rev_selected</td>
<td>String</td>
<td>Revision number currently selected for diffs.</td>
@@ -1531,8 +1584,8 @@
<tr class="varlevel1">
<td class="varname">tag_prefer_markup</td>
<td>Boolean</td>
- <td>Indicates whether to make the default file link a link to the markup
- page instead of the checkout page.</td>
+ <td>Indicates whether to make the default sticky tag file link a
+ link to the markup page instead of the checkout page.</td>
</tr>
<tr class="varlevel1">
<td class="varname">tag_view_href</td>
@@ -1556,117 +1609,6 @@
<td>String</td>
<td>Tag name</td>
</tr>
-<tr class="varlevel1">
- <td class="varname">view_href</td>
- <td>String</td>
- <td>URL for markup view of the HEAD revision of the file.</td>
-</tr>
-</tbody>
-</table>
-</div>
-
-<div class="h3">
-<h3 id="variables-markup">File Contents View (markup.ezt)</h3>
-<table>
-<thead>
-<tr>
- <th>Variable</th>
- <th>Type</th>
- <th>Description</th>
-</tr>
-</thead>
-<tbody>
-<tr class="include">
- <td colspan="3">Includes all variables from the
- <a href="#variables-common">COMMON</a> variable set</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">ago</td>
- <td>String</td>
- <td>Text description of the time elapsed since <var>date</var>.</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">author</td>
- <td>String</td>
- <td>Author of the revision being viewed.</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">branch_points</td>
- <td>String</td>
- <td>List of branch tag names which branch off of the revision being
- viewed (CVS only).</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">branches</td>
- <td>List</td>
- <td>If revision currently being viewed is on a branch, list of names
- for the branch.</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">changed</td>
- <td>String</td>
- <td>Numbers of lines added and removed since the previous revision.</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">date</td>
- <td>String</td>
- <td>Date (in UTC if not otherwise configured) of the revision currently
- being viewed.</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">log</td>
- <td>String</td>
- <td>Log message of the revision currently being viewed.</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">markup</td>
- <td>File</td>
- <td>Marked up contents of the current file revision.</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">mime_type</td>
- <td>String</td>
- <td>MIME type of the current file.</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">orig_path</td>
- <td>String</td>
- <td>When viewing an old file revision through a copy of the file,
- this is the old file revision's original path.</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">orig_href</td>
- <td>String</td>
- <td>URL of a ViewVC log view for <code>orig_path</code>.</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">prev</td>
- <td>String</td>
- <td>Previous revision number.</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">size</td>
- <td>String</td>
- <td>Size of the file revision, in bytes. Subversion only.</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">state</td>
- <td>String</td>
- <td>State of the file revision. Possible values: <tt>dead</tt>, and
- the empty string.</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">tags</td>
- <td>List</td>
- <td>Names of tags that have been applied to the current file
- revision.</td>
-</tr>
-<tr class="varlevel1">
- <td class="varname">vendor_branch</td>
- <td>Boolean</td>
- <td>Indicates whether or not the current file revision is on a vendor
- branch.</td>
-</tr>
</tbody>
</table>
</div>
@@ -1784,9 +1726,19 @@
<td>True if files list was cut short due to <tt>limit_changes</tt>.</td>
</tr>
<tr class="varlevel2">
+ <td class="varname">commits.minus</td>
+ <td>String</td>
+ <td>Total number of lines removed from files in this commit.</td>
+</tr>
+<tr class="varlevel2">
<td class="varname">commits.num_files</td>
<td>String</td>
- <td>Number of files in the <var>commits.files</var> list.</td>
+ <td>Total number of files in the <var>commits.files</var> list.</td>
+</tr>
+<tr class="varlevel2">
+ <td class="varname">commits.plus</td>
+ <td>String</td>
+ <td>Number of lines added to files in this commit.</td>
</tr>
<tr class="varlevel2">
<td class="varname">commits.rev</td>
@@ -1827,12 +1779,14 @@
<tr class="varlevel1">
<td class="varname">minus_count</td>
<td>String</td>
- <td>Total number of lines removed in the commit (over all files).</td>
+ <td>Total number of lines removed from all files across all returned
+ commits.</td>
</tr>
<tr class="varlevel1">
<td class="varname">plus_count</td>
<td>String</td>
- <td>Total number of lines added in the commit (over all files).</td>
+ <td>Total number of lines added to all files across all returned
+ commits.</td>
</tr>
<tr class="varlevel1">
<td class="varname">querysort</td>
@@ -1955,8 +1909,8 @@
</tr>
<tr class="varlevel1">
<td class="varname">query_hidden_values</td>
- <td>String</td>
- <td>Hidden value HTML markup for query form.</td>
+ <td>List</td>
+ <td>Hidden value name/value pairs for query form.</td>
</tr>
<tr class="varlevel1">
<td class="varname">querysort</td>
@@ -2095,8 +2049,8 @@
</tr>
<tr class="varlevel1">
<td class="varname">jump_rev_hidden_values</td>
- <td>String</td>
- <td>Hidden value HTML markup for revision jump form.</td>
+ <td>List</td>
+ <td>Hidden value name/value pairs for revision jump form.</td>
</tr>
<tr class="varlevel1">
<td class="varname">limit_changes</td>
@@ -2153,6 +2107,35 @@
<td colspan="3">Includes all variables from the
<a href="#variables-common">COMMON</a> variable set</td>
</tr>
+<tr class="varlevel1">
+ <td class="varname">roots</td>
+ <td>List</td>
+ <td>Set of configured viewable repositories.</td>
+</tr>
+<tr class="varlevel2">
+ <td class="varname">roots.name</td>
+ <td>String</td>
+ <td>Name of a configured repository.</td>
+</tr>
+<tr class="varlevel2">
+ <td class="varname">roots.path</td>
+ <td>String</td>
+ <td>Server-local location of a configured repository. WARNING: Revealing
+ information to untrusted guests about the details of your server
+ configuration can have negative security implications. Use this
+ token at your own risk.</td>
+</tr>
+<tr class="varlevel2">
+ <td class="varname">roots.type</td>
+ <td>String</td>
+ <td>Version control type of a configured repository. Valid
+ values: <tt>cvs</tt>, <tt>svn</tt>.</td>
+</tr>
+<tr class="varlevel2">
+ <td class="varname">roots.href</td>
+ <td>String</td>
+ <td>URL of root directory view for a configured repository.</td>
+</tr>
</tbody>
</table>
Modified: trunk/docs/upgrading-howto.html
==============================================================================
--- trunk/docs/upgrading-howto.html (original)
+++ trunk/docs/upgrading-howto.html Mon Nov 3 09:57:02 2008
@@ -109,14 +109,117 @@
</div>
<div class="h3">
-<h3>Mod_Python Stubs</h3>
+<h3>Path-Based Authorization / Forbidden Modules</h3>
-<p>The Mod_Python stub scripts haved been renamed from
- <code>viewvc.py</code> and <code>query.py</code> to
- <code>viewvc_mp.py</code> and <code>query_mp.py</code>,
- respectively, to avoid triggering an Exception from Mod_Python's
- module import loop detection logic. You'll need to update your
- Apache configuration files to point to the new script names.</p>
+<p>ViewVC 1.1 introduces a new pluggable authorization (authz)
+ subsystem which gives administrators greater control over the
+ accessibility of the information ViewVC displays in its output.
+ ViewVC provides a number of working authz modules and a framework for
+ configuring them. But of specific interest to folks upgrading from
+ ViewVC 1.0 is that one of these new modules has replaced the
+ handling of forbidden modules. As such, the <code>forbidden</code>
+ configuration option now lives under the configuration section
+ specific to that authz module.</p>
+
+<p>Migrating your existing configuration of forbidden modules should
+ be fairly straightforward:</p>
+
+<ol>
+
+ <li>In the new "authz-forbidden" section of viewvc.conf, set the
+ <code>forbidden</code> option to the same value as the
+ <code>forbidden</code> option in your ViewVC 1.0.x
+ configuration's "general" section.</li>
+
+ <li>In the new "authz-forbiddenre" section of viewvc.conf, set the
+ <code>forbiddenre</code> option to the same value as the
+ <code>forbiddenre</code> option in your ViewVC 1.0.x
+ 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>
+
+</ol>
+
+<p>Of course, you might wish to take advantage of another of the
+ provided authz modules. Or, you might wish to write a brand new
+ one for your purposes. The flexibility is yours.</p>
+
+<p><strong>Known Issues:</strong></p>
+
+<ul>
+
+ <li>ViewVC does not provide an <em>authentication</em> framework.
+ It does, however, inherit authenticated usernames as determined
+ by the HTTP server (Apache, e.g.) via the CGI environment. So,
+ any authorization module that assigns privileges based on
+ usernames will work only if ViewVC is deployed in a way that
+ requires successful authentication (as opposed to allowing
+ anonymous access).</li>
+
+ <li>Currently, the root listing view only honors the global or
+ vhost-specific configurations, <em>not</em> any root-specific
+ configuration. In the event that ViewVC is using root-specific
+ configuration for its authorization stuffs, this may cause
+ either the unintended leak of root names to users or the
+ inability to see roots at all. However, for root-specific
+ ViewVC views, all configuration — include root-specific
+ configuration — is honored. If you are concerned about
+ leaking root names in the root listing view, you might consider
+ disabling that view altogether by removing <code>roots</code>
+ from the list of views specified in the
+ <code>allowed_views</code> configuration option.</li>
+
+ <li>The experimental module which allows ViewVC to serve up views
+ of remote Subversion repositories is not yet fully integrated
+ with the authorization subsystem, and almost certainly will
+ leak privileged data. Sorry. That's (one reason) why it's
+ experimental.</li>
+
+</ul>
+
+</div>
+
+<div class="h3">
+<h3>Syntax Highlighting</h3>
+
+<p>ViewVC 1.0.x supports syntax highlighting provided by multiple
+ third-party highlighting engines, including GNU enscript, GNU
+ source-highlight, highlight, php, and py2html. Unfortunately, each
+ of those integrations worked differently than the others. Some
+ supported line numbers, some didn't; some were under active
+ development and recognized newer languages; some weren't; each had
+ its own set of CSS stylations that needed to be customized;
+ etc.</p>
+
+<p>In ViewVC 1.1, we've dropped support for all of those integations
+ in favor of a single integration with <a
+ href="http://www.pygments.org/" >Pygments</a>, a
+ Python-module-based syntax highlighting engine. As such, the
+ configuration options for the various other engines (both those
+ that enabled the integration and those that specified the locations
+ of the third-party tools) have been removed from ViewVC, and have
+ been replaced by a single new configuration option:
+ <code>enable_syntax_coloration</code>.</p>
+
+<p>The list of removed options is as follows:</p>
+
+<ul>
+ <li>options/enscript_path</li>
+ <li>options/highlight_convert_tabs</li>
+ <li>options/highlight_path</li>
+ <li>options/markup_line_numbers</li>
+ <li>options/php_exe</li>
+ <li>options/py2html_path</li>
+ <li>options/use_enscript</li>
+ <li>options/use_highlight</li>
+ <li>options/use_php</li>
+ <li>options/use_py2html</li>
+ <li>options/use_pygments</li>
+ <li>options/use_source_highlight</li>
+</ul>
</div>
@@ -149,32 +252,6 @@
</div>
<div class="h3">
-<h3>Forbidden Modules</h3>
-
-<p>ViewVC 1.1 introduces a new pluggable authorization (authz)
- subsystem which gives administrators greater control over the
- accessibility of the information ViewVC displays in its output.
- ViewVC provides a number of working authz modules and framework for
- configuring them. But of specific interest to folks upgrading from
- ViewVC 1.0 is that one of these new modules has replaced the
- handling of forbidden modules. As such, the <code>forbidden</code>
- configuration option now lives under the configuration section
- specific to that authz module.</p>
-
-<p>Migrating your existing configuration of forbidden modules should
- be fairly straightforward. Simply ensure that that the new
- <code>authorizer</code> option is set to "forbidden" (which is the
- default), and in the new "authz-forbidden" section of viewvc.conf,
- set the <code>forbidden</code> option to the same thing it was set
- to when it lived in the "options" section.</p>
-
-<p>Of course, you might wish to take advantage of another of the
- provided authz modules. Or, you might wish to write a brand new
- one for your purposes. The flexibility is yours.</p>
-
-</div>
-
-<div class="h3">
<h3>Configuration Options</h3>
<p>This section covers changes to configuration options not already
@@ -188,17 +265,10 @@
following options were added:</p>
<ul>
- <li>options/use_py2html</li>
<li>utilities/cvsgraph</li>
<li>utilities/cvsnt</li>
<li>utilities/diff</li>
- <li>utilities/enscript</li>
- <li>utilities/gzip</li>
- <li>utilities/highlight</li>
- <li>utilities/php</li>
- <li>utilities/py2html_dir</li>
<li>utilities/rcs_dir</li>
- <li>utilities/sed</li>
<li>utilities/svn</li>
</ul>
@@ -209,10 +279,6 @@
<li>general/rcs_path</li>
<li>general/svn_path</li>
<li>options/cvsgraph_path</li>
- <li>options/enscript_path</li>
- <li>options/highlight_path</li>
- <li>options/php_exe</li>
- <li>options/py2html_path</li>
</ul>
<p>All the options which governed which ViewVC views were enabled have
@@ -233,6 +299,10 @@
<p>The <code>use_rcsparse</code> option was moved from the "general"
section to the "options" section.</p>
+<p>The <code>log_sort</code> option's value "cvs" has been renamed to
+ "none" (for general application across all supported version
+ control systems).</p>
+
<p>Custom sections which define per-virtual-host configuration option
overrides must now have their names prefixed with "vhost-". Also,
instead of a hyphen (-) between the virtual host name and the base
@@ -261,6 +331,7 @@
<p>The following is a grab-bag of additional new options:</p>
<ul>
+ <li>options/hide_errorful_entries</li>
<li>options/mangle_email_addresses</li>
</ul>
@@ -274,6 +345,16 @@
Authoring Guide</a> for the current set of variables available to
each templates.</p>
+<p>One notable change in ViewVC 1.1 is that the markup.ezt and
+ annotate.ezt templates have been combined into a single file.ezt
+ template.</p>
+
+<p>Also, the configuration options under the <code>[templates]</code>
+ section are now paths relative to the configured template directory
+ (either the value of the <code>options/template_dir</code>
+ option, or the default "templates" directory), instead of being
+ relative to the configuration location.</p>
+
<table>
<thead>
<tr>
@@ -288,108 +369,68 @@
<td><em>all templates</em></td>
<td>added</td>
</tr>
+<tr class="removed">
+ <td class="varname">change_root_action</td>
+ <td><em>all templates</em></td>
+ <td>removed</td>
+</tr>
+<tr class="removed">
+ <td class="varname">change_root_hidden_values</td>
+ <td><em>all templates</em></td>
+ <td>removed</td>
+</tr>
+<tr class="removed">
+ <td class="varname">roots</td>
+ <td><em>all templates</em> except roots.ezt</td>
+ <td>removed</td>
+</tr>
<tr class="added">
<td class="varname">roots.path</td>
- <td><em>all templates</em></td>
+ <td>roots.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">queryform_href</td>
- <td>annotate.ezt, diff.ezt, graph.ezt, log.ezt, log_table.ezt, markup.ezt,
+ <td>diff.ezt, file.ezt, graph.ezt, log.ezt, log_table.ezt,
query_form.ezt, revision.ezt, roots.ezt</td>
<td>added</td>
</tr>
<tr class="added">
<td class="varname">tarball_href</td>
- <td>annotate.ezt, diff.ezt, graph.ezt, log.ezt, log_table.ezt, markup.ezt,
+ <td>diff.ezt, file.ezt, graph.ezt, log.ezt, log_table.ezt,
query_form.ezt, query_results.ezt, revision.ezt, roots.ezt</td>
<td>added</td>
</tr>
<tr class="added">
- <td class="varname">mime_type</td>
- <td>annotate.ezt</td>
+ <td class="varname">properties</td>
+ <td>directory.ezt, file.ezt</td>
<td>added</td>
</tr>
<tr class="added">
- <td class="varname">log</td>
- <td>annotate.ezt</td>
+ <td class="varname">properties.name</td>
+ <td>directory.ezt, file.ezt</td>
<td>added</td>
</tr>
<tr class="added">
- <td class="varname">date</td>
- <td>annotate.ezt</td>
- <td>added</td>
-</tr>
-<tr class="added">
- <td class="varname">ago</td>
- <td>annotate.ezt</td>
+ <td class="varname">properties.undisplayable</td>
+ <td>directory.ezt, file.ezt</td>
<td>added</td>
</tr>
<tr class="added">
- <td class="varname">author</td>
- <td>annotate.ezt</td>
+ <td class="varname">properties.value</td>
+ <td>directory.ezt, file.ezt</td>
<td>added</td>
</tr>
-<tr class="added">
- <td class="varname">branches</td>
- <td>annotate.ezt</td>
- <td>added</td>
-</tr>
-<tr class="added">
- <td class="varname">tags</td>
- <td>annotate.ezt</td>
- <td>added</td>
-</tr>
-<tr class="added">
- <td class="varname">branch_points</td>
- <td>annotate.ezt</td>
- <td>added</td>
-</tr>
-<tr class="added">
- <td class="varname">changed</td>
- <td>annotate.ezt</td>
- <td>added</td>
-</tr>
-<tr class="added">
- <td class="varname">size</td>
- <td>annotate.ezt</td>
- <td>added</td>
-</tr>
-<tr class="added">
- <td class="varname">state</td>
- <td>annotate.ezt</td>
- <td>added</td>
-</tr>
-<tr class="added">
- <td class="varname">vendor_branch</td>
- <td>annotate.ezt</td>
- <td>added</td>
-</tr>
-<tr class="added">
- <td class="varname">prev</td>
- <td>annotate.ezt</td>
- <td>added</td>
+<tr class="changed">
+ <td class="varname">diff_format_hidden_values</td>
+ <td>diff.ezt</td>
+ <td>now is an iterable list of objects with .name and .value attributes</td>
</tr>
<tr class="changed">
<td class="varname">diff_type</td>
<td>diff.ezt</td>
<td>new value: <code>f</code></td>
</tr>
-<tr class="changed">
- <td class="varname">entries.log</td>
- <td>directory.ezt, dir_alternate.ezt</td>
- <td>now always contains untruncated log message</td>
-</tr>
-<tr class="added">
- <td class="varname">entries.short_log</td>
- <td>directory.ezt, dir_alternate.ezt</td>
- <td>added</td>
-</tr>
-<tr class="added">
- <td class="varname">rss_link_href</td>
- <td>query.ezt, rss.ezt</td>
- <td>added</td>
-</tr>
<tr class="renamed">
<td class="varname">date_left</td>
<td>diff.ezt</td>
@@ -500,6 +541,96 @@
<td>diff.ezt</td>
<td>added</td>
</tr>
+<tr class="changed">
+ <td class="varname">dir_paging_hidden_values</td>
+ <td>directory.ezt, , dir_alternate.ezt</td>
+ <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
+<tr class="changed">
+ <td class="varname">entries.log</td>
+ <td>directory.ezt, dir_alternate.ezt</td>
+ <td>now always contains untruncated log message</td>
+</tr>
+<tr class="added">
+ <td class="varname">entries.short_log</td>
+ <td>directory.ezt, dir_alternate.ezt</td>
+ <td>added</td>
+</tr>
+<tr class="changed">
+ <td class="varname">search_re_hidden_values</td>
+ <td>directory.ezt, dir_alternate.ezt</td>
+ <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
+<tr class="changed">
+ <td class="varname">search_tag_hidden_values</td>
+ <td>directory.ezt, dir_alternate.ezt</td>
+ <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
+<tr class="changed">
+ <td class="varname">pathrev_clear_hidden_values</td>
+ <td>log.ezt, log_table.ezt, directory.ezt, dir_alternate.ezt</td>
+ <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
+<tr class="changed">
+ <td class="varname">pathrev_hidden_values</td>
+ <td>log.ezt, log_table.ezt, directory.ezt, dir_alternate.ezt</td>
+ <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
+<tr class="renamed">
+ <td class="varname">annotate_href</td>
+ <td>log.ezt, log_table.ezt</td>
+ <td>renamed to <code>head_annotate_href</code></td>
+</tr>
+<tr class="changed">
+ <td class="varname">diff_form_hidden_values</td>
+ <td>log.ezt, log_table.ezt</td>
+ <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
+<tr class="renamed">
+ <td class="varname">download_href</td>
+ <td>log.ezt, log_table.ezt</td>
+ <td>renamed to <code>head_download_href</code></td>
+</tr>
+<tr class="renamed">
+ <td class="varname">download_text_href</td>
+ <td>log.ezt, log_table.ezt</td>
+ <td>renamed to <code>head_download_text_href</code></td>
+</tr>
+<tr class="changed">
+ <td class="varname">log_paging_hidden_values</td>
+ <td>log.ezt, log_table.ezt</td>
+ <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
+<tr class="changed">
+ <td class="varname">logsort_hidden_values</td>
+ <td>log.ezt, log_table.ezt</td>
+ <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
+<tr class="renamed">
+ <td class="varname">prefer_markup</td>
+ <td>log.ezt, log_table.ezt</td>
+ <td>renamed to <code>head_prefer_markup</code></td>
+</tr>
+<tr class="renamed">
+ <td class="varname">view_href</td>
+ <td>log.ezt, log_table.ezt</td>
+ <td>renamed to <code>head_view_href</code></td>
+</tr>
+<tr class="added">
+ <td class="varname">rss_link_href</td>
+ <td>query.ezt, rss.ezt</td>
+ <td>added</td>
+</tr>
+<tr class="changed">
+ <td class="varname">query_hidden_values</td>
+ <td>query_form.ezt</td>
+ <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
+<tr class="changed">
+ <td class="varname">jump_rev_hidden_values</td>
+ <td>revision.ezt</td>
+ <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
</tbody>
</table>
Modified: trunk/docs/url-reference.html
==============================================================================
--- trunk/docs/url-reference.html (original)
+++ trunk/docs/url-reference.html Mon Nov 3 09:57:02 2008
@@ -1,6 +1,6 @@
<html>
<head>
-<title>ViewVC 1.0 URL Reference</title>
+<title>ViewVC 1.1 URL Reference</title>
<style>
body {
background-color: rgb(180,193,205);
@@ -88,7 +88,7 @@
<ul>
<li><a href="#compat-viewrev">'<code>view=rev</code>' Parameter ⇒ '<code>view=revision</code>'</a></li>
<li><a href="#compat-cvsroot">'<code>cvsroot</code>' Parameter ⇒ '<code>root</code>'</a></li>
- <li><a href="#compat-only_with_tag>'<code>only_with_tag</code>' Parameter ⇒ '<code>pathrev</code>'</a></li>
+ <li><a href="#compat-only_with_tag">'<code>only_with_tag</code>' Parameter ⇒ '<code>pathrev</code>'</a></li>
<li><a href="#compat-oldcheckout">'<code>~checkout~</code>' Magic Path Prefix ⇒ '<code>*checkout*</code>'</a></li>
<li><a href="#compat-checkout">'<code>*checkout*</code>' Magic Path Prefix ⇒ '<code>view=co</code>'</a></li>
<li><a href="#compat-root">'<code>root</code>' Parameter ⇒ Root Path Component</a></li>
@@ -98,7 +98,7 @@
<li><a href="#compat-tarball">'<code>tarball=1</code>' Parameter ⇒ '<code>view=tar</code>'</a></li>
<li><a href="#compat-graph">'<code>graph=1</code>' Parameter ⇒ '<code>view=graph</code>'</a></li>
<li><a href="#compat-makeimage">'<code>graph=1&makeimage=1</code>' Parameters ⇒ '<code>view=graphimg</code>'</a></li>
- <li><a href="#compat-content_type">'<code>content_type=text/vnd.viewcvs-markup</code>' and '<code>content_type=text/x-cvsweb-markup</code>' Parameters⇒ '<code>view=markup</code>'
+ <li><a href="#compat-content_type">'<code>content-type=text/vnd.viewcvs-markup</code>' and '<code>content-type=text/x-cvsweb-markup</code>' Parameters⇒ '<code>view=markup</code>'
<li><a href="#compat-attic">'<code>Attic/FILE</code>' Paths ⇒ '<code>FILE</code>'</a></li>
</ul>
</div>
@@ -1013,6 +1013,17 @@
of author match</td>
</tr>
<tr>
+ <td><code>comment=<var>COMMENT</var></code></td>
+ <td>optional</td>
+ <td>log message query string</td>
+ </tr>
+ <tr>
+ <td><code>comment_match=<var>COMMENT_MATCH</var></code></td>
+ <td>optional</td>
+ <td>"exact" "like" "glob" "regex" or "notregex" determining type
+ of log message match</td>
+ </tr>
+ <tr>
<td><code>querysort=SORT</code></td>
<td>optional</td>
<td>"date" "author" or "file" determining order of query results</td>
@@ -1456,11 +1467,14 @@
<h3 id="compat-content_type">'<code>content_type=text/vnd.viewcvs-markup</code>' and '<code>content_type=text/x-cvsweb-markup</code>' Parameters⇒ '<code>view=markup</code>'</h3>
-<p><code>content_type=text/vnd.viewcvs-markup</code> and
- <code>content_type=text/x-cvsweb-markup</code> parameters are
+<p><code>content-type=text/vnd.viewcvs-markup</code> and
+ <code>content-type=text/x-cvsweb-markup</code> parameters are
treated like a <code>view=markup</code> parameter. There is
currently no redirect when it is encountered, but there could be
- one in the future.</p>
+ one in the future. Other values of the <code>content-type</code>
+ parameter, which were used to dictate the MIME type of files
+ displayed in the checkout/download view prior to ViewVC 1.0.6, are
+ ignored.</p>
<h3 id="compat-attic">'<code>Attic/FILE</code>' Paths ⇒ '<code>FILE</code>'</h3>
Modified: trunk/lib/blame.py
==============================================================================
--- trunk/lib/blame.py (original)
+++ trunk/lib/blame.py Mon Nov 3 09:57:02 2008
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 2000 Curt Hagenlocher <curt hagenlocher org>
#
# By using this file, you agree to the terms and conditions set forth in
@@ -34,7 +34,6 @@
import math
import cgi
import vclib
-import vclib.ccvs.blame
re_includes = re.compile('\\#(\\s*)include(\\s*)"(.*?)"')
@@ -101,6 +100,7 @@
def make_html(root, rcs_path):
+ import vclib.ccvs.blame
bs = vclib.ccvs.blame.BlameSource(os.path.join(root, rcs_path))
line = 0
Modified: trunk/lib/config.py
==============================================================================
--- trunk/lib/config.py (original)
+++ trunk/lib/config.py Mon Nov 3 09:57:02 2008
@@ -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
@@ -39,8 +39,7 @@
class Config:
_sections = ('general', 'utilities', 'options', 'cvsdb', 'templates')
- _force_multi_value = ('cvs_roots', 'forbidden',
- 'svn_roots', 'languages', 'kv_files',
+ _force_multi_value = ('cvs_roots', 'svn_roots', 'languages', 'kv_files',
'root_parents', 'allowed_views')
def __init__(self):
@@ -163,18 +162,32 @@
return
self._process_root_options(self.parser, rootname)
+ def _get_parser_items(self, parser, section):
+ """Basically implement ConfigParser.items() for pre-Python-2.3 versions."""
+ try:
+ return self.parser.items(section)
+ except AttributeError:
+ d = {}
+ for option in parser.options(section):
+ d[option] = parser.get(section, option)
+ return d.items()
+
def get_authorizer_params(self, authorizer, rootname=None):
if not self.conf_path:
return {}
-
+
params = {}
authz_section = 'authz-%s' % (authorizer)
+ for section in self.parser.sections():
+ if section == authz_section:
+ for key, value in self._get_parser_items(self.parser, section):
+ params[key] = value
if rootname:
root_authz_section = 'root-%s/authz-%s' % (rootname, authorizer)
- for section in self.parser.sections():
- if section == authz_section \
- or (rootname and section == root_authz_section):
- params.update(self.parser.items(section))
+ for section in self.parser.sections():
+ if section == root_authz_section:
+ for key, value in self._get_parser_items(self.parser, section):
+ params[key] = value
return params
def set_defaults(self):
@@ -185,7 +198,7 @@
self.general.root_parents = []
self.general.default_root = ''
self.general.mime_types_file = ''
- self.general.address = '<a href="mailto:user insert your domain here">No admin address has been configured</a>'
+ self.general.address = ''
self.general.kv_files = [ ]
self.general.languages = ['en-us']
@@ -196,36 +209,31 @@
self.utilities.cvsnt = None
self.utilities.svn = ''
self.utilities.diff = ''
- self.utilities.enscript = ''
- self.utilities.highlight = ''
- self.utilities.source_highlight = ''
- self.utilities.py2html_dir = '.'
- self.utilities.php = 'php'
self.utilities.cvsgraph = ''
- self.utilities.gzip = ''
- self.utilities.sed = ''
self.options.root_as_url_component = 1
self.options.checkout_magic = 0
- self.options.allowed_views = ['markup', 'annotate']
+ self.options.allowed_views = ['markup', 'annotate', 'roots']
self.options.authorizer = 'forbidden'
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_config_dir = None
self.options.use_rcsparse = 0
self.options.sort_by = 'file'
self.options.sort_group_dirs = 1
self.options.hide_attic = 1
+ self.options.hide_errorful_entries = 0
self.options.log_sort = 'date'
self.options.diff_format = 'h'
self.options.hide_cvsroot = 1
self.options.hr_breakable = 1
self.options.hr_funout = 1
- self.options.hr_ignore_white = 1
+ self.options.hr_ignore_white = 0
self.options.hr_ignore_keyword_subst = 1
self.options.hr_intraline = 0
- self.options.allow_compress = 1
+ self.options.allow_compress = 0
self.options.template_dir = "templates"
self.options.docroot = None
self.options.show_subdir_lastmod = 0
@@ -234,27 +242,19 @@
self.options.cross_copies = 0
self.options.use_localtime = 0
self.options.short_log_len = 80
- self.options.use_py2html = 0
- self.options.use_enscript = 0
- self.options.use_highlight = 0
- self.options.highlight_line_numbers = 1
- self.options.highlight_convert_tabs = 2
- self.options.use_source_highlight = 0
- self.options.source_highlight_line_numbers = 1
- self.options.use_php = 0
+ self.options.enable_syntax_coloration = 1
self.options.use_cvsgraph = 0
self.options.cvsgraph_conf = "cvsgraph.conf"
self.options.use_re_search = 0
self.options.use_pagesize = 0
self.options.limit_changes = 100
- self.templates.annotate = None
self.templates.diff = None
self.templates.directory = None
self.templates.error = None
+ self.templates.file = None
self.templates.graph = None
self.templates.log = None
- self.templates.markup = None
self.templates.query = None
self.templates.query_form = None
self.templates.query_results = None
@@ -270,6 +270,7 @@
self.cvsdb.readonly_passwd = ''
self.cvsdb.row_limit = 1000
self.cvsdb.rss_row_limit = 100
+ self.cvsdb.check_database_for_root = 0
def _startswith(somestr, substr):
return somestr[:len(substr)] == substr
Modified: trunk/lib/cvsdb.py
==============================================================================
--- trunk/lib/cvsdb.py (original)
+++ trunk/lib/cvsdb.py Mon Nov 3 09:57:02 2008
@@ -17,6 +17,7 @@
import fnmatch
import re
+import vclib
import dbi
@@ -457,9 +458,13 @@
return commit
- def sql_delete(self, table, key, value):
+ def sql_delete(self, table, key, value, keep_fkey = None):
sql = "DELETE FROM %s WHERE %s=%%s" % (table, key)
sql_args = (value, )
+ if keep_fkey:
+ sql += " AND %s NOT IN (SELECT %s FROM checkins WHERE %s = %%s)" \
+ % (key, keep_fkey, keep_fkey)
+ sql_args = (value, value)
cursor = self.db.cursor()
cursor.execute(sql, sql_args)
@@ -480,16 +485,16 @@
plus_count, minus_count, description_id) = cursor.fetchone()
except TypeError:
break
- checkins.append([file_id, dir_id, branch_id, description_id])
+ 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])
- self.sql_delete('dirs', 'id', checkin[1])
- self.sql_delete('branches', 'id', checkin[2])
- self.sql_delete('descs', 'id', checkin[3])
-
+ 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
@@ -771,7 +776,8 @@
directory = string.join(path_parts[:-1], "/")
file = path_parts[-1]
- revs = repository.itemlog(path_parts, revision, {"cvs_pass_rev": 1})
+ revs = repository.itemlog(path_parts, revision, vclib.SORTBY_DEFAULT,
+ 0, 0, {"cvs_pass_rev": 1})
for rev in revs:
commit = CreateCommit()
commit.SetRepository(repository.rootpath)
Modified: trunk/lib/debug.py
==============================================================================
--- trunk/lib/debug.py (original)
+++ trunk/lib/debug.py Mon Nov 3 09:57:02 2008
@@ -1,6 +1,6 @@
# -*-python-*-
#
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -68,12 +68,6 @@
return "ViewVC Unrecoverable Error: %s" % self.msg
-class ViewVCNotAuthorizedException(ViewVCException):
- def __init__(self, user, what):
- msg = 'User "%s" is not authorized to see %s' % (user, what)
- ViewVCException.__init__(self, msg, '501 Not Authorized')
-
-
def PrintException(server, exc_data):
status = exc_data['status']
msg = exc_data['msg']
Modified: trunk/lib/popen.py
==============================================================================
--- trunk/lib/popen.py (original)
+++ trunk/lib/popen.py Mon Nov 3 09:57:02 2008
@@ -1,6 +1,6 @@
# -*-python-*-
#
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
Modified: trunk/lib/query.py
==============================================================================
--- trunk/lib/query.py (original)
+++ trunk/lib/query.py Mon Nov 3 09:57:02 2008
@@ -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.
#
# 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
@@ -390,6 +390,13 @@
commits.append(build_commit(server, cfg, current_desc, files,
cvsroots, viewvc_link))
+ # Strip out commits that don't have any files attached to them. The
+ # files probably aren't present because they've been blocked via
+ # forbiddenness.
+ def _only_with_files(commit):
+ return len(commit.files) > 0
+ commits = filter(_only_with_files, commits)
+
return commits
def main(server, cfg, viewvc_link):
Modified: trunk/lib/vcauth/__init__.py
==============================================================================
--- trunk/lib/vcauth/__init__.py (original)
+++ trunk/lib/vcauth/__init__.py Mon Nov 3 09:57:02 2008
@@ -1,6 +1,6 @@
# -*-python-*-
#
-# Copyright (C) 2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 2006-2008 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -19,39 +19,31 @@
class GenericViewVCAuthorizer:
"""Abstract class encapsulating version control authorization routines."""
- def __init__(self, username, root, params={}):
+ def __init__(self, username=None, params={}):
"""Create a GenericViewVCAuthorizer object which will be used to
validate that USERNAME has the permissions needed to view version
- control repository ROOT (in whole or in part). PARAMS is a
- dictionary of custom parameters for the authorizer.
-
- Raise ViewVCRootAccessNotAuthorized error if USERNAME isn't
- allowed to see this repository at all."""
+ control repositories (in whole or in part). PARAMS is a
+ dictionary of custom parameters for the authorizer."""
pass
- def check_path_access(self, path_parts, rev=None):
+ def check_root_access(self, rootname):
+ """Return 1 iff the associated username is permitted to read ROOTNAME."""
+ pass
+
+ def check_path_access(self, rootname, path_parts, pathtype, rev=None):
"""Return 1 iff the associated username is permitted to read
- revision REV of the path PATH_PARTS in the repository associated
- with this authorizer."""
+ revision REV of the path PATH_PARTS (of type PATHTYPE) in
+ repository ROOTNAME."""
pass
-class ViewVCRootAccessNotAuthorized(Exception):
- def __init__(self, rootname, username):
- self.rootname = rootname
- self.username = username
- def __str__(self):
- return "Access to root '%s' by user '%s' is denied." \
- % (self.rootname, self.username)
-
-
##############################################################################
class ViewVCAuthorizer(GenericViewVCAuthorizer):
"""The uber-permissive authorizer."""
- def __init__(self):
- pass
+ def check_root_access(self, rootname):
+ return 1
- def check_path_access(self, path_parts, rev=None):
+ def check_path_access(self, rootname, path_parts, pathtype, rev=None):
return 1
Modified: trunk/lib/vcauth/forbidden/__init__.py
==============================================================================
--- trunk/lib/vcauth/forbidden/__init__.py (original)
+++ trunk/lib/vcauth/forbidden/__init__.py Mon Nov 3 09:57:02 2008
@@ -1,6 +1,6 @@
# -*-python-*-
#
-# Copyright (C) 2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 2006-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
@@ -16,25 +16,24 @@
class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
"""A simple top-level module authorizer."""
- def __init__(self, username, root, params={}):
+ def __init__(self, username, params={}):
forbidden = params.get('forbidden', '')
- self.root = root
self.forbidden = map(string.strip,
filter(None, string.split(forbidden, ',')))
-
- def check_path_access(self, path_parts, rev=None):
+
+ def check_root_access(self, rootname):
+ return 1
+
+ def check_path_access(self, rootname, path_parts, pathtype, rev=None):
# No path? No problem.
if not path_parts:
return 1
- # If we have a single path part, we can't tell if this is a file
- # or a directory. So we ask our version control system. If it's
- # not a directory, we don't care about it.
- if len(path_parts) == 1:
- if self.root.itemtype(path_parts, rev) != vclib.DIR:
- return 1
+ # Not a directory? We aren't interested.
+ if pathtype != vclib.DIR:
+ return 1
- # At this point we're looking a path we believe to be a directory.
+ # At this point we're looking at a directory path.
module = path_parts[0]
default = 1
for pat in self.forbidden:
Modified: trunk/lib/vcauth/svnauthz/__init__.py
==============================================================================
--- trunk/lib/vcauth/svnauthz/__init__.py (original)
+++ trunk/lib/vcauth/svnauthz/__init__.py Mon Nov 3 09:57:02 2008
@@ -1,6 +1,6 @@
# -*-python-*-
#
-# Copyright (C) 2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 2006-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
@@ -21,20 +21,34 @@
class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
"""Subversion authz authorizer module"""
- def __init__(self, username, root, params={}):
- rootname = root.rootname()
- self.paths = {} # paths-in-root -> access boolean for USERNAME
+ def __init__(self, username, params={}):
+ self.username = username
+ self.rootpaths = { } # {root -> { paths -> access boolean for USERNAME }}
# Get the authz file location from a passed-in parameter.
- authz_file = params.get('authzfile')
- if not authz_file:
+ self.authz_file = params.get('authzfile')
+ if not self.authz_file:
raise debug.ViewVCException("No authzfile configured")
- if not os.path.exists(authz_file):
+ if not os.path.exists(self.authz_file):
raise debug.ViewVCException("Configured authzfile file not found")
+ def _get_paths_for_root(self, rootname):
+ if self.rootpaths.has_key(rootname):
+ return self.rootpaths[rootname]
+
+ paths_for_root = { }
+
# Parse the authz file.
cp = ConfigParser()
- cp.read(authz_file)
+ cp.read(self.authz_file)
+
+ # Figure out if there are any aliases for the current username
+ aliases = []
+ if cp.has_section('aliases'):
+ for alias in cp.options('aliases'):
+ entry = cp.get('aliases', alias)
+ if entry == self.username:
+ aliases.append(alias)
# Figure out which groups USERNAME has a part of.
groups = []
@@ -69,12 +83,15 @@
entries = string.split(cp.get('groups', groupname), ',')
for entry in entries:
entry = string.strip(entry)
- if entry == username:
+ if entry == self.username:
group_member = 1
break
elif entry[0:1] == "@" and _process_group(entry[1:]):
group_member = 1
break
+ elif entry[0:1] == "&" and entry[1:] in aliases:
+ group_member = 1
+ break
if group_member:
groups.append(groupname)
return group_member
@@ -83,31 +100,31 @@
for group in cp.options('groups'):
_process_group(group)
- # Read the other (non-"groups") sections, and figure out in which
- # repositories USERNAME or his groups have read rights.
- root_is_readable = 0
- for section in cp.sections():
-
- # Skip the "groups" section -- we handled that already.
- if section == 'groups':
- continue
-
- # Skip sections not related to our rootname. While we're at it,
- # go ahead and figure out the repository path we're talking about.
- if section.find(':') == -1:
- path = section
- else:
- root, path = string.split(section, ':', 1)
- if root != rootname:
- continue
-
+ def _userspec_matches_user(userspec):
+ # If there is an inversion character, recurse and return the
+ # opposite result.
+ if userspec[0:1] == '~':
+ return not _userspec_matches_user(userspec[1:])
+
+ # See if the userspec applies to our current user.
+ return userspec == '*' \
+ or userspec == self.username \
+ or (self.username is not None and userspec == "$authenticated") \
+ or (self.username is None and userspec == "$anonymous") \
+ or (userspec[0:1] == "@" and userspec[1:] in groups) \
+ or (userspec[0:1] == "&" and userspec[1:] in aliases)
+
+ def _process_access_section(section):
+ """Inline function for determining user access in a single
+ config secction. Return a two-tuple (ALLOW, DENY) containing
+ the access determination for USERNAME in a given authz file
+ SECTION (if any)."""
+
# Figure if this path is explicitly allowed or denied to USERNAME.
allow = deny = 0
for user in cp.options(section):
user = string.strip(user)
- if user == '*' \
- or user == username \
- or (user[0:1] == "@" and user[1:] in groups):
+ if _userspec_matches_user(user):
# See if the 'r' permission is among the ones granted to
# USER. If so, we can stop looking. (Entry order is not
# relevant -- we'll use the most permissive entry, meaning
@@ -116,28 +133,91 @@
deny = not allow
if allow:
break
+ return allow, deny
+
+ # Read the other (non-"groups") sections, and figure out in which
+ # repositories USERNAME or his groups have read rights. We'll
+ # first check groups that have no specific repository designation,
+ # then superimpose those that have a repository designation which
+ # matches the one we're asking about.
+ root_sections = []
+ for section in cp.sections():
+
+ # Skip the "groups" section -- we handled that already.
+ if section == 'groups':
+ continue
+
+ if section == 'aliases':
+ continue
+
+ # Process root-agnostic access sections; skip (but remember)
+ # root-specific ones that match our root; ignore altogether
+ # root-specific ones that don't match our root. While we're at
+ # it, go ahead and figure out the repository path we're talking
+ # about.
+ if section.find(':') == -1:
+ path = section
+ else:
+ name, path = string.split(section, ':', 1)
+ if name == rootname:
+ root_sections.append(section)
+ continue
+
+ # Check for a specific access determination.
+ allow, deny = _process_access_section(section)
# If we got an explicit access determination for this path and this
# USERNAME, record it.
if allow or deny:
- if allow:
- root_is_readable = 1
if path != '/':
path = '/' + string.join(filter(None, string.split(path, '/')), '/')
- self.paths[path] = allow
+ paths_for_root[path] = allow
- # If USERNAME can't see this root at all, raise an error.
+ # Okay. Superimpose those root-specific values now.
+ for section in root_sections:
+
+ # Get the path again.
+ name, path = string.split(section, ':', 1)
+
+ # Check for a specific access determination.
+ allow, deny = _process_access_section(section)
+
+ # If we got an explicit access determination for this path and this
+ # USERNAME, record it.
+ if allow or deny:
+ if path != '/':
+ path = '/' + string.join(filter(None, string.split(path, '/')), '/')
+ paths_for_root[path] = allow
+
+ # If the root isn't readable, there's no point in caring about all
+ # the specific paths the user can't see. Just point the rootname
+ # to a None paths dictionary.
+ root_is_readable = 0
+ for path in paths_for_root.keys():
+ if paths_for_root[path]:
+ root_is_readable = 1
+ break
if not root_is_readable:
- raise vcauth.ViewVCRootAccessNotAuthorized(rootname, username)
+ paths_for_root = None
+
+ self.rootpaths[rootname] = paths_for_root
+ return paths_for_root
- def check_path_access(self, path_parts, rev=None):
+ def check_root_access(self, rootname):
+ paths = self._get_paths_for_root(rootname)
+ return (paths is not None) and 1 or 0
+
+ def check_path_access(self, rootname, path_parts, pathtype, rev=None):
# Crawl upward from the path represented by PATH_PARTS toward to
# the root of the repository, looking for an explicitly grant or
# denial of access.
+ paths = self._get_paths_for_root(rootname)
+ if paths is None:
+ return 0
parts = path_parts[:]
while parts:
path = '/' + string.join(parts, '/')
- if self.paths.has_key(path):
- return self.paths[path]
+ if paths.has_key(path):
+ return paths[path]
del parts[-1]
- return self.paths.get('/', 0)
+ return paths.get('/', 0)
Modified: trunk/lib/vclib/__init__.py
==============================================================================
--- trunk/lib/vclib/__init__.py (original)
+++ trunk/lib/vclib/__init__.py Mon Nov 3 09:57:02 2008
@@ -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
@@ -37,6 +37,12 @@
REPLACED = 'replaced'
MODIFIED = 'modified'
+# log sort keys
+SORTBY_DEFAULT = 0 # default/no sorting
+SORTBY_DATE = 1 # sorted by date, youngest first
+SORTBY_REV = 2 # sorted by revision, youngest first
+
+
# ======================================================================
#
class Repository:
@@ -50,6 +56,13 @@
def rootpath(self):
"""Return the location of this repository."""
+
+ def authorizer(self):
+ """Return the vcauth.Authorizer object associated with this
+ repository, or None if no such association has been made."""
+
+ def open(self):
+ """Open a connection to the repository."""
def itemtype(self, path_parts, rev):
"""Return the type of the item (file or dir) at the given path and revision
@@ -94,7 +107,7 @@
New properties will be set on all of the DirEntry objects in the entries
list. At the very least, a "rev" property will be set to a revision
number or None if the entry doesn't have a number. Other properties that
- may be set include "date", "author", and "log".
+ may be set include "date", "author", "log", "size", and "lockinfo".
The path is specified as a list of components, relative to the root
of the repository. e.g. ["subdir1", "subdir2", "filename"]
@@ -108,7 +121,7 @@
options is a dictionary of implementation specific options
"""
- def itemlog(self, path_parts, rev, options):
+ def itemlog(self, path_parts, rev, sortby, first, limit, options):
"""Retrieve an item's log information
The result is a list of Revision objects
@@ -118,9 +131,28 @@
rev is the revision of the item to return information about
+ sortby indicates the way in which the returned list should be
+ sorted (SORTBY_DEFAULT, SORTBY_DATE, SORTBY_REV)
+
+ first is the 0-based index of the first Revision returned (after
+ sorting, if any, has occured)
+
+ limit is the maximum number of returned Revisions, or 0 to return
+ all available data
+
options is a dictionary of implementation specific options
"""
+ def itemprops(self, path_parts, rev):
+ """Return a dictionary mapping property names to property values
+ for properties stored on an item.
+
+ The path is specified as a list of components, relative to the root
+ of the repository. e.g. ["subdir1", "subdir2", "filename"]
+
+ rev is the revision of the item to return information about.
+ """
+
def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
"""Return a diff (in GNU diff format) of two file revisions
@@ -155,6 +187,17 @@
doesn't support a global revision concept.
"""
+ def isexecutable(self, path_parts, rev):
+ """Return true iff a given revision of a versioned file is to be
+ considered an executable program or script.
+
+ The path is specified as a list of components, relative to the root
+ of the repository. e.g. ["subdir1", "subdir2", "filename"]
+
+ rev is the revision of the item to return information about
+ """
+
+
# ======================================================================
class DirEntry:
"""Instances represent items in a directory listing"""
@@ -173,7 +216,7 @@
class Revision:
"""Instances holds information about revisions of versioned resources"""
- def __init__(self, number, string, date, author, changed, log, size):
+ def __init__(self, number, string, date, author, changed, log, size, lockinfo):
"""Create a new Revision() item:
NUMBER: Revision in an integer-based, sortable format
STRING: Revision as a string
@@ -182,6 +225,7 @@
CHANGED: Lines-changed (contextual diff) information
LOG: Log message associated with the creation of this revision
SIZE: Size (in bytes) of this revision's fulltext (files only)
+ LOCKINFO: Information about locks held on this revision
"""
self.number = number
self.string = string
@@ -190,6 +234,7 @@
self.changed = changed
self.log = log
self.size = size
+ self.lockinfo = lockinfo
def __cmp__(self, other):
return cmp(self.number, other.number)
@@ -350,3 +395,26 @@
def _label(self, (path, date, rev)):
date = date and time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date))
return "%s\t%s\t%s" % (path, date, rev)
+
+
+def check_root_access(repos):
+ """Return 1 iff the associated username is permitted to read REPOS,
+ as determined by consulting REPOS's Authorizer object (if any)."""
+
+ auth = repos.authorizer()
+ if not auth:
+ return 1
+ return auth.check_root_access(repos.rootname())
+
+def check_path_access(repos, path_parts, pathtype=None, rev=None):
+ """Return 1 iff the associated username is permitted to read
+ revision REV of the path PATH_PARTS (of type PATHTYPE) in repository
+ REPOS, as determined by consulting REPOS's Authorizer object (if any)."""
+
+ auth = repos.authorizer()
+ if not auth:
+ return 1
+ if not pathtype:
+ pathtype = repos.itemtype(path_parts, rev)
+ return auth.check_path_access(repos.rootname(), path_parts, pathtype, rev)
+
Modified: trunk/lib/vclib/ccvs/__init__.py
==============================================================================
--- trunk/lib/vclib/ccvs/__init__.py (original)
+++ trunk/lib/vclib/ccvs/__init__.py Mon Nov 3 09:57:02 2008
@@ -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
@@ -9,347 +9,35 @@
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
-
-"""
-This is a Version Control library driver for locally accessible cvs-repositories.
-"""
-
import os
-import string
-import re
-import cStringIO
-import tempfile
-
-import vclib
-import rcsparse
-import blame
-
-### The functionality shared with bincvs should probably be moved to a
-### separate module
-from vclib.bincvs import CVSRepository, Revision, Tag, \
- _file_log, _log_path
-
-class CCVSRepository(CVSRepository):
- def dirlogs(self, path_parts, rev, entries, options):
- """see vclib.Repository.dirlogs docstring
-
- rev can be a tag name or None. if set only information from revisions
- matching the tag will be retrieved
-
- Option values recognized by this implementation:
-
- cvs_subdirs
- boolean. true to fetch logs of the most recently modified file in each
- subdirectory
-
- Option values returned by this implementation:
-
- cvs_tags, cvs_branches
- lists of tag and branch names encountered in the directory
- """
- subdirs = options.get('cvs_subdirs', 0)
-
- dirpath = self._getpath(path_parts)
- alltags = { # all the tags seen in the files of this dir
- 'MAIN' : '',
- 'HEAD' : '1.1'
- }
-
- for entry in entries:
- entry.rev = entry.date = entry.author = entry.dead = entry.log = None
- path = _log_path(entry, dirpath, subdirs)
- if path:
- entry.path = path
- try:
- rcsparse.parse(open(path, 'rb'), InfoSink(entry, rev, alltags))
- except IOError, e:
- entry.errors.append("rcsparse error: %s" % e)
- except RuntimeError, e:
- entry.errors.append("rcsparse error: %s" % e)
- except rcsparse.RCSStopParser:
- pass
-
- branches = options['cvs_branches'] = []
- tags = options['cvs_tags'] = []
- for name, rev in alltags.items():
- if Tag(None, rev).is_branch:
- branches.append(name)
- else:
- tags.append(name)
-
- def itemlog(self, path_parts, rev, options):
- """see vclib.Repository.itemlog docstring
-
- rev parameter can be a revision number, a branch number, a tag name,
- or None. If None, will return information about all revisions, otherwise,
- will only return information about the specified revision or branch.
-
- Option values returned by this implementation:
-
- cvs_tags
- dictionary of Tag objects for all tags encountered
- """
- path = self.rcsfile(path_parts, 1)
- sink = TreeSink()
- rcsparse.parse(open(path, 'rb'), sink)
- filtered_revs = _file_log(sink.revs.values(), sink.tags,
- sink.default_branch, rev)
- for rev in filtered_revs:
- if rev.prev and len(rev.number) == 2:
- rev.changed = rev.prev.next_changed
- options['cvs_tags'] = sink.tags
-
- return filtered_revs
-
- def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
- temp1 = tempfile.mktemp()
- open(temp1, 'wb').write(self.openfile(path_parts1, rev1)[0].getvalue())
- temp2 = tempfile.mktemp()
- open(temp2, 'wb').write(self.openfile(path_parts2, rev2)[0].getvalue())
-
- r1 = self.itemlog(path_parts1, rev1, {})[-1]
- r2 = self.itemlog(path_parts2, rev2, {})[-1]
-
- info1 = (self.rcsfile(path_parts1, root=1, v=0), r1.date, r1.string)
- info2 = (self.rcsfile(path_parts2, root=1, v=0), r2.date, r2.string)
-
- diff_args = vclib._diff_args(type, options)
-
- return vclib._diff_fp(temp1, temp2, info1, info2,
- self.utilities.diff or 'diff', diff_args)
-
- def annotate(self, path_parts, rev=None):
- source = blame.BlameSource(self.rcsfile(path_parts, 1), rev)
- return source, source.revision
-
- def revinfo(self, rev):
- raise vclib.UnsupportedFeature
-
- def openfile(self, path_parts, rev=None):
- path = self.rcsfile(path_parts, 1)
- sink = COSink(rev)
- rcsparse.parse(open(path, 'rb'), sink)
- revision = sink.last and sink.last.string
- return cStringIO.StringIO(string.join(sink.sstext.text, "\n")), revision
-
-class MatchingSink(rcsparse.Sink):
- """Superclass for sinks that search for revisions based on tag or number"""
-
- def __init__(self, find):
- """Initialize with tag name or revision number string to match against"""
- if not find or find == 'MAIN' or find == 'HEAD':
- self.find = None
- else:
- self.find = find
-
- self.find_tag = None
-
- def set_principal_branch(self, branch_number):
- if self.find is None:
- self.find_tag = Tag(None, branch_number)
-
- def define_tag(self, name, revision):
- if name == self.find:
- self.find_tag = Tag(None, revision)
-
- def admin_completed(self):
- if self.find_tag is None:
- if self.find is None:
- self.find_tag = Tag(None, '')
- else:
- try:
- self.find_tag = Tag(None, self.find)
- except ValueError:
- pass
-
-class InfoSink(MatchingSink):
- def __init__(self, entry, tag, alltags):
- MatchingSink.__init__(self, tag)
- self.entry = entry
- self.alltags = alltags
- self.matching_rev = None
- self.perfect_match = 0
-
- def define_tag(self, name, revision):
- MatchingSink.define_tag(self, name, revision)
- self.alltags[name] = revision
-
- def admin_completed(self):
- MatchingSink.admin_completed(self)
- if self.find_tag is None:
- # tag we're looking for doesn't exist
- raise rcsparse.RCSStopParser
-
- def define_revision(self, revision, date, author, state, branches, next):
- if self.perfect_match:
- return
-
- tag = self.find_tag
- rev = Revision(revision, date, author, state == "dead")
-
- # perfect match if revision number matches tag number or if revision is on
- # trunk and tag points to trunk. imperfect match if tag refers to a branch
- # and this revision is the highest revision so far found on that branch
- perfect = ((rev.number == tag.number) or
- (not tag.number and len(rev.number) == 2))
- if perfect or (tag.is_branch and tag.number == rev.number[:-1] and
- (not self.matching_rev or
- rev.number > self.matching_rev.number)):
- self.matching_rev = rev
- self.perfect_match = perfect
-
- def set_revision_info(self, revision, log, text):
- if self.matching_rev:
- if revision == self.matching_rev.string:
- self.entry.rev = self.matching_rev.string
- self.entry.date = self.matching_rev.date
- self.entry.author = self.matching_rev.author
- self.entry.dead = self.matching_rev.dead
- self.entry.log = log
- raise rcsparse.RCSStopParser
- else:
- raise rcsparse.RCSStopParser
-
-class TreeSink(rcsparse.Sink):
- d_command = re.compile('^d(\d+)\\s(\\d+)')
- a_command = re.compile('^a(\d+)\\s(\\d+)')
-
- def __init__(self):
- self.revs = { }
- self.tags = { }
- self.head = None
- self.default_branch = None
-
- def set_head_revision(self, revision):
- self.head = revision
-
- def set_principal_branch(self, branch_number):
- self.default_branch = branch_number
-
- def define_tag(self, name, revision):
- # check !tags.has_key(tag_name)
- self.tags[name] = revision
-
- def define_revision(self, revision, date, author, state, branches, next):
- # check !revs.has_key(revision)
- self.revs[revision] = Revision(revision, date, author, state == "dead")
-
- def set_revision_info(self, revision, log, text):
- # check revs.has_key(revision)
- rev = self.revs[revision]
- rev.log = log
-
- changed = None
- added = 0
- deled = 0
- if self.head != revision:
- changed = 1
- lines = string.split(text, '\n')
- idx = 0
- while idx < len(lines):
- command = lines[idx]
- dmatch = self.d_command.match(command)
- idx = idx + 1
- if dmatch:
- deled = deled + string.atoi(dmatch.group(2))
- else:
- amatch = self.a_command.match(command)
- if amatch:
- count = string.atoi(amatch.group(2))
- added = added + count
- idx = idx + count
- elif command:
- raise "error while parsing deltatext: %s" % command
-
- if len(rev.number) == 2:
- rev.next_changed = changed and "+%i -%i" % (deled, added)
- else:
- rev.changed = changed and "+%i -%i" % (added, deled)
-
-class StreamText:
- d_command = re.compile('^d(\d+)\\s(\\d+)')
- a_command = re.compile('^a(\d+)\\s(\\d+)')
-
- def __init__(self, text):
- self.text = string.split(text, "\n")
-
- def command(self, cmd):
- adjust = 0
- add_lines_remaining = 0
- diffs = string.split(cmd, "\n")
- if diffs[-1] == "":
- del diffs[-1]
- if len(diffs) == 0:
- return
- if diffs[0] == "":
- del diffs[0]
- for command in diffs:
- if add_lines_remaining > 0:
- # Insertion lines from a prior "a" command
- self.text.insert(start_line + adjust, command)
- add_lines_remaining = add_lines_remaining - 1
- adjust = adjust + 1
- continue
- dmatch = self.d_command.match(command)
- amatch = self.a_command.match(command)
- if dmatch:
- # "d" - Delete command
- start_line = string.atoi(dmatch.group(1))
- count = string.atoi(dmatch.group(2))
- begin = start_line + adjust - 1
- del self.text[begin:begin + count]
- adjust = adjust - count
- elif amatch:
- # "a" - Add command
- start_line = string.atoi(amatch.group(1))
- count = string.atoi(amatch.group(2))
- add_lines_remaining = count
- else:
- raise RuntimeError, 'Error parsing diff commands'
-
-def secondnextdot(s, start):
- # find the position the second dot after the start index.
- return string.find(s, '.', string.find(s, '.', start) + 1)
-
-
-class COSink(MatchingSink):
- def __init__(self, rev):
- MatchingSink.__init__(self, rev)
-
- def set_head_revision(self, revision):
- self.head = Revision(revision)
- self.last = None
- self.sstext = None
-
- def admin_completed(self):
- MatchingSink.admin_completed(self)
- if self.find_tag is None:
- raise vclib.InvalidRevision(self.find)
-
- def set_revision_info(self, revision, log, text):
- tag = self.find_tag
- rev = Revision(revision)
+import os.path
- if rev.number == tag.number:
- self.log = log
- depth = len(rev.number)
+def canonicalize_rootpath(rootpath):
+ return os.path.normpath(rootpath)
- if rev.number == self.head.number:
- assert self.sstext is None
- self.sstext = StreamText(text)
- elif (depth == 2 and tag.number and rev.number >= tag.number[:depth]):
- assert len(self.last.number) == 2
- assert rev.number < self.last.number
- self.sstext.command(text)
- elif (depth > 2 and rev.number[:depth-1] == tag.number[:depth-1] and
- (rev.number <= tag.number or len(tag.number) == depth-1)):
- assert len(rev.number) - len(self.last.number) in (0, 2)
- assert rev.number > self.last.number
- self.sstext.command(text)
- else:
- rev = None
- if rev:
- #print "tag =", tag.number, "rev =", rev.number, "<br>"
- self.last = rev
+def expand_root_parent(parent_path):
+ # Each subdirectory of PARENT_PATH that contains a child
+ # "CVSROOT/config" is added the set of returned roots. Or, if the
+ # PARENT_PATH itself contains a child "CVSROOT/config", then all its
+ # subdirectories are returned as roots.
+ roots = {}
+ subpaths = os.listdir(parent_path)
+ cvsroot = os.path.exists(os.path.join(parent_path, "CVSROOT", "config"))
+ for rootname in subpaths:
+ rootpath = os.path.join(parent_path, rootname)
+ if cvsroot \
+ or (os.path.exists(os.path.join(rootpath, "CVSROOT", "config"))):
+ roots[rootname] = canonicalize_rootpath(rootpath)
+ return roots
+
+
+def CVSRepository(name, rootpath, authorizer, utilities, use_rcsparse):
+ rootpath = canonicalize_rootpath(rootpath)
+ if use_rcsparse:
+ import ccvs
+ return ccvs.CCVSRepository(name, rootpath, authorizer, utilities)
+ else:
+ import bincvs
+ return bincvs.BinCVSRepository(name, rootpath, authorizer, utilities)
Modified: trunk/lib/vclib/ccvs/blame.py
==============================================================================
--- trunk/lib/vclib/ccvs/blame.py (original)
+++ trunk/lib/vclib/ccvs/blame.py Mon Nov 3 09:57:02 2008
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 2000 Curt Hagenlocher <curt hagenlocher org>
#
# By using this file, you agree to the terms and conditions set forth in
Modified: trunk/lib/vclib/ccvs/rcsparse/common.py
==============================================================================
--- trunk/lib/vclib/ccvs/rcsparse/common.py (original)
+++ trunk/lib/vclib/ccvs/rcsparse/common.py Mon Nov 3 09:57:02 2008
@@ -1,6 +1,6 @@
# -*-python-*-
#
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
Modified: trunk/lib/vclib/ccvs/rcsparse/default.py
==============================================================================
--- trunk/lib/vclib/ccvs/rcsparse/default.py (original)
+++ trunk/lib/vclib/ccvs/rcsparse/default.py Mon Nov 3 09:57:02 2008
@@ -1,6 +1,6 @@
# -*-python-*-
#
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
Modified: trunk/lib/vclib/ccvs/rcsparse/texttools.py
==============================================================================
--- trunk/lib/vclib/ccvs/rcsparse/texttools.py (original)
+++ trunk/lib/vclib/ccvs/rcsparse/texttools.py Mon Nov 3 09:57:02 2008
@@ -1,6 +1,6 @@
# -*-python-*-
#
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
Modified: trunk/lib/vclib/svn/__init__.py
==============================================================================
--- trunk/lib/vclib/svn/__init__.py (original)
+++ trunk/lib/vclib/svn/__init__.py Mon Nov 3 09:57:02 2008
@@ -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
@@ -10,657 +10,46 @@
#
# -----------------------------------------------------------------------
-"Version Control lib driver for locally accessible Subversion repositories"
+"Version Control lib driver for Subversion repositories"
-import vclib
import os
import os.path
-import string
-import cStringIO
-import signal
-import time
-import tempfile
-import popen
import re
-from svn import fs, repos, core, client, delta
+_re_url = re.compile('^(http|https|file|svn|svn\+[^:]+)://')
-### Require Subversion 1.3.1 or better.
-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)"
-
-
-def _allow_all(root, path, pool):
- """Generic authz_read_func that permits access to all paths"""
- return 1
-
-
-def _fs_path_join(base, relative):
- # Subversion filesystem paths are '/'-delimited, regardless of OS.
- joined_path = base + '/' + relative
- parts = filter(None, string.split(joined_path, '/'))
- return string.join(parts, '/')
-
-
-def _cleanup_path(path):
- """Return a cleaned-up Subversion filesystem path"""
- return string.join(filter(None, string.split(path, '/')), '/')
-
-
-def _compare_paths(path1, path2):
- path1_len = len (path1);
- path2_len = len (path2);
- min_len = min(path1_len, path2_len)
- i = 0
-
- # Are the paths exactly the same?
- if path1 == path2:
- return 0
-
- # Skip past common prefix
- while (i < min_len) and (path1[i] == path2[i]):
- i = i + 1
-
- # Children of paths are greater than their parents, but less than
- # greater siblings of their parents
- char1 = '\0'
- char2 = '\0'
- if (i < path1_len):
- char1 = path1[i]
- if (i < path2_len):
- char2 = path2[i]
-
- if (char1 == '/') and (i == path2_len):
- return 1
- if (char2 == '/') and (i == path1_len):
- return -1
- if (i < path1_len) and (char1 == '/'):
- return -1
- if (i < path2_len) and (char2 == '/'):
- return 1
-
- # Common prefix was skipped above, next character is compared to
- # determine order
- return cmp(char1, char2)
-
-
-def _rev2optrev(rev):
- assert type(rev) is int
- rt = core.svn_opt_revision_t()
- rt.kind = core.svn_opt_revision_number
- rt.value.number = rev
- return rt
-
-
-def _rootpath2url(rootpath, path):
- rootpath = os.path.abspath(rootpath)
- if rootpath and rootpath[0] != '/':
- rootpath = '/' + rootpath
- if os.sep != '/':
- rootpath = string.replace(rootpath, os.sep, '/')
- return 'file://' + string.join([rootpath, path], "/")
-
-
-def _datestr_to_date(datestr):
+def canonicalize_rootpath(rootpath):
try:
- return core.svn_time_from_cstring(datestr) / 1000000
+ import svn.core
+ return svn.core.svn_path_canonicalize(rootpath)
except:
- return None
-
-
-def _fs_rev_props(fsptr, rev):
- author = fs.revision_prop(fsptr, rev, core.SVN_PROP_REVISION_AUTHOR)
- msg = fs.revision_prop(fsptr, rev, core.SVN_PROP_REVISION_LOG)
- date = fs.revision_prop(fsptr, rev, core.SVN_PROP_REVISION_DATE)
- return date, author, msg
-
-
-def date_from_rev(svnrepos, rev):
- if (rev < 0) or (rev > svnrepos.youngest):
- raise vclib.InvalidRevision(rev)
- return _datestr_to_date(fs.revision_prop(svnrepos.fs_ptr, rev,
- core.SVN_PROP_REVISION_DATE))
-
-
-def get_location(svnrepos, path, rev, old_rev):
- try:
- results = repos.svn_repos_trace_node_locations(svnrepos.fs_ptr, path,
- rev, [old_rev], _allow_all)
- except core.SubversionException, e:
- if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
- raise vclib.ItemNotFound(path)
- raise
-
- try:
- old_path = results[old_rev]
- except KeyError:
- raise vclib.ItemNotFound(path)
-
- return _cleanup_path(old_path)
-
+ if re.search(_re_url, rootpath):
+ return rootpath[-1] == '/' and rootpath[:-1] or rootpath
+ return os.path.normpath(rootpath)
-def last_rev(svnrepos, path, peg_revision, limit_revision=None):
- """Given PATH, known to exist in PEG_REVISION, find the youngest
- revision older than, or equal to, LIMIT_REVISION in which path
- exists. Return that revision, and the path at which PATH exists in
- that revision."""
-
- # Here's the plan, man. In the trivial case (where PEG_REVISION is
- # the same as LIMIT_REVISION), this is a no-brainer. If
- # LIMIT_REVISION is older than PEG_REVISION, we can use Subversion's
- # history tracing code to find the right location. If, however,
- # LIMIT_REVISION is younger than PEG_REVISION, we suffer from
- # Subversion's lack of forward history searching. Our workaround,
- # ugly as it may be, involves a binary search through the revisions
- # between PEG_REVISION and LIMIT_REVISION to find our last live
- # revision.
- peg_revision = svnrepos._getrev(peg_revision)
- limit_revision = svnrepos._getrev(limit_revision)
- try:
- if peg_revision == limit_revision:
- return peg_revision, path
- elif peg_revision > limit_revision:
- fsroot = svnrepos._getroot(peg_revision)
- history = fs.node_history(fsroot, path)
- while history:
- path, peg_revision = fs.history_location(history)
- if peg_revision <= limit_revision:
- return max(peg_revision, limit_revision), _cleanup_path(path)
- history = fs.history_prev(history, 1)
- return peg_revision, _cleanup_path(path)
- else:
- orig_id = fs.node_id(svnrepos._getroot(peg_revision), path)
- while peg_revision != limit_revision:
- mid = (peg_revision + 1 + limit_revision) / 2
- try:
- mid_id = fs.node_id(svnrepos._getroot(mid), path)
- except core.SubversionException, e:
- if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
- cmp = -1
- else:
- raise
- else:
- ### Not quite right. Need a comparison function that only returns
- ### true when the two nodes are the same copy, not just related.
- cmp = fs.compare_ids(orig_id, mid_id)
-
- if cmp in (0, 1):
- peg_revision = mid
- else:
- limit_revision = mid - 1
- return peg_revision, path
- finally:
+def expand_root_parent(parent_path):
+ roots = {}
+ if re.search(_re_url, parent_path):
pass
-
-
-def created_rev(svnrepos, full_name, rev):
- return fs.node_created_rev(svnrepos._getroot(rev), full_name)
-
-
-class Revision(vclib.Revision):
- "Hold state for each revision's log entry."
- def __init__(self, rev, date, author, msg, size,
- filename, copy_path, copy_rev):
- vclib.Revision.__init__(self, rev, str(rev), date, author, None, msg, size)
- self.filename = filename
- self.copy_path = copy_path
- self.copy_rev = copy_rev
-
-
-class NodeHistory:
- def __init__(self, fs_ptr, show_all_logs):
- self.histories = {}
- self.fs_ptr = fs_ptr
- self.show_all_logs = show_all_logs
-
- def add_history(self, path, revision, pool):
- # If filtering, only add the path and revision to the histories
- # list if they were actually changed in this revision (where
- # change means the path itself was changed, or one of its parents
- # was copied). This is useful for omitting bubble-up directory
- # changes.
- if not self.show_all_logs:
- rev_root = fs.revision_root(self.fs_ptr, revision)
- changed_paths = fs.paths_changed(rev_root)
- paths = changed_paths.keys()
- if path not in paths:
- # Look for a copied parent
- test_path = path
- found = 0
- while 1:
- off = string.rfind(test_path, '/')
- if off < 0:
- break
- test_path = test_path[0:off]
- if test_path in paths:
- copyfrom_rev, copyfrom_path = fs.copied_from(rev_root, test_path)
- if copyfrom_rev >= 0 and copyfrom_path:
- found = 1
- break
- if not found:
- return
- self.histories[revision] = _cleanup_path(path)
-
-
-def _get_history(svnrepos, full_name, rev, options={}):
- fsroot = svnrepos._getroot(rev)
- show_all_logs = options.get('svn_show_all_dir_logs', 0)
- if not show_all_logs:
- # See if the path is a file or directory.
- kind = fs.check_path(fsroot, full_name)
- if kind is core.svn_node_file:
- show_all_logs = 1
-
- # Instantiate a NodeHistory collector object.
- history = NodeHistory(svnrepos.fs_ptr, show_all_logs)
-
- # Do we want to cross copy history?
- cross_copies = options.get('svn_cross_copies', 0)
-
- # Get the history items for PATH.
- repos.svn_repos_history(svnrepos.fs_ptr, full_name, history.add_history,
- 1, rev, cross_copies)
- return history.histories
-
-
-def _log_helper(svnrepos, rev, path):
- rev_root = fs.revision_root(svnrepos.fs_ptr, rev)
-
- # Was this path rev the target of a copy?
- copyfrom_rev, copyfrom_path = fs.copied_from(rev_root, path)
-
- # Assemble our LogEntry
- datestr, author, msg = _fs_rev_props(svnrepos.fs_ptr, rev)
- date = _datestr_to_date(datestr)
- if fs.is_file(rev_root, path):
- size = fs.file_length(rev_root, path)
else:
- size = None
- entry = Revision(rev, date, author, msg, size, path,
- copyfrom_path and _cleanup_path(copyfrom_path),
- copyfrom_rev)
- return entry
-
-
-def _fetch_log(svnrepos, full_name, which_rev, options):
- revs = []
-
- if options.get('svn_latest_log', 0):
- rev = _log_helper(svnrepos, which_rev, full_name)
- if rev:
- revs.append(rev)
+ # Any subdirectories of PARENT_PATH which themselves have a child
+ # "format" are returned as roots.
+ subpaths = os.listdir(parent_path)
+ for rootname in subpaths:
+ rootpath = os.path.join(parent_path, rootname)
+ if os.path.exists(os.path.join(rootpath, "format")):
+ roots[rootname] = canonicalize_rootpath(rootpath)
+ return roots
+
+
+def SubversionRepository(name, rootpath, authorizer, utilities, config_dir):
+ rootpath = canonicalize_rootpath(rootpath)
+ if re.search(_re_url, rootpath):
+ import svn_ra
+ return svn_ra.RemoteSubversionRepository(name, rootpath, authorizer,
+ utilities, config_dir)
else:
- history_set = _get_history(svnrepos, full_name, which_rev, options)
- history_revs = history_set.keys()
- history_revs.sort()
- history_revs.reverse()
- for history_rev in history_revs:
- rev = _log_helper(svnrepos, history_rev, history_set[history_rev])
- if rev:
- revs.append(rev)
- return revs
-
-def _get_last_history_rev(fsroot, path):
- history = fs.node_history(fsroot, path)
- history = fs.history_prev(history, 0)
- history_path, history_rev = fs.history_location(history)
- return history_rev
-
-def get_youngest_revision(svnrepos):
- return svnrepos.youngest
-
-def temp_checkout(svnrepos, path, rev):
- """Check out file revision to temporary file"""
- temp = tempfile.mktemp()
- fp = open(temp, 'wb')
- try:
- root = svnrepos._getroot(rev)
- stream = fs.file_contents(root, path)
- try:
- while 1:
- chunk = core.svn_stream_read(stream, core.SVN_STREAM_CHUNK_SIZE)
- if not chunk:
- break
- fp.write(chunk)
- finally:
- core.svn_stream_close(stream)
- finally:
- fp.close()
- return temp
-
-class FileContentsPipe:
- def __init__(self, root, path):
- self._stream = fs.file_contents(root, path)
- self._eof = 0
-
- def read(self, len=None):
- chunk = None
- if not self._eof:
- if len is None:
- buffer = cStringIO.StringIO()
- try:
- while 1:
- hunk = core.svn_stream_read(self._stream, 8192)
- if not hunk:
- break
- buffer.write(hunk)
- chunk = buffer.getvalue()
- finally:
- buffer.close()
-
- else:
- chunk = core.svn_stream_read(self._stream, len)
- if not chunk:
- self._eof = 1
- return chunk
-
- def readline(self):
- chunk = None
- if not self._eof:
- chunk, self._eof = core.svn_stream_readline(self._stream, '\n')
- if not self._eof:
- chunk = chunk + '\n'
- if not chunk:
- self._eof = 1
- return chunk
-
- def readlines(self):
- lines = []
- while True:
- line = self.readline()
- if not line:
- break
- lines.append(line)
- return lines
-
- def close(self):
- return core.svn_stream_close(self._stream)
-
- def eof(self):
- return self._eof
-
-
-class BlameSource:
- def __init__(self, local_url, rev, first_rev):
- self.idx = -1
- self.first_rev = first_rev
- self.blame_data = []
-
- ctx = client.ctx_t()
- core.svn_config_ensure(None)
- ctx.config = core.svn_config_get_config(None)
- ctx.auth_baton = core.svn_auth_open([])
- try:
- client.blame2(local_url, _rev2optrev(rev), _rev2optrev(1),
- _rev2optrev(rev), self._blame_cb, ctx)
- except vclib.svn.core.SubversionException, e:
- if e.apr_err == vclib.svn.core.SVN_ERR_CLIENT_IS_BINARY_FILE:
- raise vclib.NonTextualFileContents
- raise
-
- def _blame_cb(self, line_no, rev, author, date, text, pool):
- prev_rev = None
- if rev > self.first_rev:
- prev_rev = rev - 1
- self.blame_data.append(vclib.Annotation(text, line_no, rev,
- prev_rev, author, None))
-
- def __getitem__(self, idx):
- if idx != self.idx + 1:
- raise BlameSequencingError()
- self.idx = idx
- return self.blame_data[idx]
-
-
-class BlameSequencingError(Exception):
- pass
-
-
-class SVNChangedPath(vclib.ChangedPath):
- """Wrapper around vclib.ChangedPath which handles path splitting."""
-
- def __init__(self, path, rev, pathtype, base_path, base_rev,
- action, copied, text_changed, props_changed):
- path_parts = filter(None, string.split(path or '', '/'))
- base_path_parts = filter(None, string.split(base_path or '', '/'))
- vclib.ChangedPath.__init__(self, path_parts, rev, pathtype,
- base_path_parts, base_rev, action,
- copied, text_changed, props_changed)
-
-
-class SubversionRepository(vclib.Repository):
- def __init__(self, name, rootpath, utilities):
- if not os.path.isdir(rootpath):
- raise vclib.ReposNotFound(name)
-
- # Initialize some stuff.
- self.rootpath = rootpath
- self.name = name
- self.svn_client_path = utilities.svn or 'svn'
- self.diff_cmd = utilities.diff or 'diff'
-
- # Register a handler for SIGTERM so we can have a chance to
- # cleanup. If ViewVC takes too long to start generating CGI
- # output, Apache will grow impatient and SIGTERM it. While we
- # don't mind getting told to bail, we want to gracefully close the
- # repository before we bail.
- def _sigterm_handler(signum, frame, self=self):
- self._close()
- sys.exit(-1)
- try:
- signal.signal(signal.SIGTERM, _sigterm_handler)
- except ValueError:
- # This is probably "ValueError: signal only works in main
- # thread", which will get thrown by the likes of mod_python
- # when trying to install a signal handler from a thread that
- # isn't the main one. We'll just not care.
- pass
-
- # Open the repository and init some other variables.
- self.repos = repos.svn_repos_open(rootpath)
- self.fs_ptr = repos.svn_repos_fs(self.repos)
- self.youngest = fs.youngest_rev(self.fs_ptr)
- self._fsroots = {}
-
- def rootname(self):
- return self.name
-
- def rootpath(self):
- return self.rootpath
-
- def roottype(self):
- return vclib.SVN
-
- def itemtype(self, path_parts, rev):
- rev = self._getrev(rev)
- basepath = self._getpath(path_parts)
- kind = fs.check_path(self._getroot(rev), basepath)
- if kind == core.svn_node_dir:
- return vclib.DIR
- if kind == core.svn_node_file:
- return vclib.FILE
- raise vclib.ItemNotFound(path_parts)
-
- def openfile(self, path_parts, rev):
- path = self._getpath(path_parts)
- rev = self._getrev(rev)
- fsroot = self._getroot(rev)
- revision = str(_get_last_history_rev(fsroot, path))
- fp = FileContentsPipe(fsroot, path)
- return fp, revision
-
- def listdir(self, path_parts, rev, options):
- basepath = self._getpath(path_parts)
- if self.itemtype(path_parts, rev) != vclib.DIR:
- raise vclib.Error("Path '%s' is not a directory." % basepath)
-
- rev = self._getrev(rev)
- fsroot = self._getroot(rev)
- dirents = fs.dir_entries(fsroot, basepath)
- entries = [ ]
- for entry in dirents.values():
- if entry.kind == core.svn_node_dir:
- kind = vclib.DIR
- elif entry.kind == core.svn_node_file:
- kind = vclib.FILE
- entries.append(vclib.DirEntry(entry.name, kind))
- return entries
-
- def dirlogs(self, path_parts, rev, entries, options):
- fsroot = self._getroot(self._getrev(rev))
- for entry in entries:
- path = self._getpath(path_parts + [entry.name])
- rev = _get_last_history_rev(fsroot, path)
- datestr, author, msg = _fs_rev_props(self.fs_ptr, rev)
- date = _datestr_to_date(datestr)
- entry.rev = str(rev)
- entry.date = date
- entry.author = author
- entry.log = msg
- if entry.kind == vclib.FILE:
- entry.size = fs.file_length(fsroot, path)
-
- def itemlog(self, path_parts, rev, options):
- """see vclib.Repository.itemlog docstring
-
- Option values recognized by this implementation
-
- svn_show_all_dir_logs
- boolean, default false. if set for a directory path, will include
- revisions where files underneath the directory have changed
-
- svn_cross_copies
- boolean, default false. if set for a path created by a copy, will
- include revisions from before the copy
-
- svn_latest_log
- boolean, default false. if set will return only newest single log
- entry
- """
- path = self._getpath(path_parts)
- rev = self._getrev(rev)
-
- revs = _fetch_log(self, path, rev, options)
- revs.sort()
- prev = None
- for rev in revs:
- rev.prev = prev
- prev = rev
- return revs
-
- def annotate(self, path_parts, rev):
- path = self._getpath(path_parts)
- rev = self._getrev(rev)
- fsroot = self._getroot(rev)
-
- history_set = _get_history(self, path, rev, {'svn_cross_copies': 1})
- history_revs = history_set.keys()
- history_revs.sort()
- revision = history_revs[-1]
- first_rev = history_revs[0]
- source = BlameSource(_rootpath2url(self.rootpath, path), rev, first_rev)
- return source, revision
-
- def revinfo(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 = {}
-
- # Now get the revision property info. Would use
- # editor.get_root_props(), but something is broken there...
- datestr, author, msg = _fs_rev_props(self.fs_ptr, rev)
-
- # Copy the Subversion changes into a new hash, converting them into
- # ChangedPath objects.
- 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:
- 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
-
- changedpaths[path] = SVNChangedPath(path, rev, pathtype,
- change.base_path,
- change.base_rev, action,
- is_copy, change.text_changed,
- change.prop_changes)
-
- # Return our tuple: date, author, msg, changes
- return _datestr_to_date(datestr), author, msg, changedpaths.values()
-
- def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
- p1 = self._getpath(path_parts1)
- p2 = self._getpath(path_parts2)
- r1 = self._getrev(rev1)
- r2 = self._getrev(rev2)
- args = vclib._diff_args(type, options)
-
- try:
- temp1 = temp_checkout(self, p1, r1)
- temp2 = temp_checkout(self, p2, r2)
- info1 = p1, date_from_rev(self, r1), r1
- info2 = p2, date_from_rev(self, r2), r2
- return vclib._diff_fp(temp1, temp2, info1, info2, self.diff_cmd, args)
- except vclib.svn.core.SubversionException, e:
- if e.apr_err == vclib.svn.core.SVN_ERR_FS_NOT_FOUND:
- raise vclib.InvalidRevision
- raise
-
- def _getpath(self, path_parts):
- return string.join(path_parts, '/')
-
- def _getrev(self, rev):
- if rev is None or rev == 'HEAD':
- return self.youngest
- try:
- rev = int(rev)
- except ValueError:
- raise vclib.InvalidRevision(rev)
- if (rev < 0) or (rev > self.youngest):
- raise vclib.InvalidRevision(rev)
- return rev
-
- def _getroot(self, rev):
- try:
- return self._fsroots[rev]
- except KeyError:
- r = self._fsroots[rev] = fs.revision_root(self.fs_ptr, rev)
- return r
+ import svn_repos
+ return svn_repos.LocalSubversionRepository(name, rootpath, authorizer,
+ utilities, config_dir)
Modified: trunk/lib/viewvc.py
==============================================================================
--- trunk/lib/viewvc.py (original)
+++ trunk/lib/viewvc.py Mon Nov 3 09:57:02 2008
@@ -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
@@ -14,7 +14,7 @@
#
# -----------------------------------------------------------------------
-__version__ = '1.1-dev'
+__version__ = '1.2-dev'
# this comes from our library; measure the startup time
import debug
@@ -24,27 +24,30 @@
# standard modules that we know are in the path or builtin
import sys
import os
-import sapi
import cgi
-import string
-import urllib
+import gzip
import mimetypes
-import time
import re
import rfc822
import stat
+import string
import struct
-import types
import tempfile
+import time
+import types
+import urllib
-# these modules come from our library (the stub has set up the path)
+# These modules come from our library (the stub has set up the path)
+import accept
import compat
import config
-import popen
import ezt
-import accept
-import vclib
+import popen
+import sapi
import vcauth
+import vclib
+import vclib.ccvs
+import vclib.svn
try:
import idiff
@@ -77,6 +80,10 @@
'limit_changes',
]
+# number of extra pages of information on either side of the current
+# page to fetch (see use_pagesize configuration option)
+EXTRA_PAGES = 3
+
# for reading/writing between a couple descriptors
CHUNK_SIZE = 8192
@@ -96,40 +103,29 @@
self.script_name = _normalize_path(server.getenv('SCRIPT_NAME', ''))
self.browser = server.getenv('HTTP_USER_AGENT', 'unknown')
- # in lynx, it it very annoying to have two links per file, so
- # disable the link at the icon in this case:
- self.no_file_links = string.find(self.browser, 'Lynx') != -1
-
- # newer browsers accept gzip content encoding and state this in a
- # header (netscape did always but didn't state it) It has been
- # reported that these braindamaged MS-Internet Explorers claim
- # that they accept gzip .. but don't in fact and display garbage
- # then :-/
- self.may_compress = (
- ( string.find(server.getenv('HTTP_ACCEPT_ENCODING', ''), 'gzip') != -1
- or string.find(self.browser, 'Mozilla/3') != -1)
- and string.find(self.browser, 'MSIE') == -1
- )
-
- # process the Accept-Language: header
+ # 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)
self.language = self.lang_selector.select_from(cfg.general.languages)
+ self.kv = cfg.load_kv_files(self.language)
# check for an authenticated username
self.username = server.getenv('REMOTE_USER')
- # load the key/value files, given the selected language
- self.kv = cfg.load_kv_files(self.language)
+ # if we allow compressed output, see if the client does too
+ self.gzip_compress_level = 0
+ if cfg.options.allow_compress:
+ http_accept_encoding = os.environ.get("HTTP_ACCEPT_ENCODING", "")
+ if "gzip" in filter(None,
+ map(lambda x: string.strip(x),
+ string.split(http_accept_encoding, ","))):
+ self.gzip_compress_level = 9 # make this configurable?
def run_viewvc(self):
cfg = self.cfg
- # global needed because "import vclib.svn" causes the
- # interpreter to make vclib a local variable
- global vclib
-
# This function first parses the query string and sets the following
# variables. Then it executes the request.
self.view_func = None # function to call to process the request
@@ -144,9 +140,6 @@
self.pathrev = None # current path revision or tag
self.auth = None # authorizer module in use
- # setup the default authorizer (until we have a root)
- self.auth = vcauth.ViewVCAuthorizer()
-
# redirect if we're loading from a valid but irregular URL
# These redirects aren't neccessary to make ViewVC work, it functions
# just fine without them, but they make it easier for server admins to
@@ -168,6 +161,15 @@
# validate the parameter
_validate_param(name, values[0])
+ # Only allow the magic ViewVC MIME types (the ones used for
+ # requesting the markup as as-text views) to be declared via CGI
+ # params. Ignore disallowed values.
+ if (name == 'content-type') and \
+ (not values[0] in (viewcvs_mime_type,
+ alt_mime_type,
+ 'text/plain')):
+ continue
+
# if we're here, then the parameter is okay
self.query_dict[name] = values[0]
@@ -218,7 +220,7 @@
self.rootname = path_parts.pop(0)
else:
self.rootname = ""
- else:
+ elif self.view_func != view_roots:
self.rootname = cfg.general.default_root
elif cfg.options.root_as_url_component:
needs_redirect = 1
@@ -227,59 +229,45 @@
self.path_parts = path_parts
if self.rootname:
- # Create the repository object
- if cfg.general.cvs_roots.has_key(self.rootname):
- cfg.overlay_root_options(self.rootname)
- self.rootpath = os.path.normpath(cfg.general.cvs_roots[self.rootname])
- try:
- if cfg.options.use_rcsparse:
- import vclib.ccvs
- self.repos = vclib.ccvs.CCVSRepository(self.rootname,
- self.rootpath,
- cfg.utilities)
- else:
- import vclib.bincvs
- self.repos = vclib.bincvs.BinCVSRepository(self.rootname,
- self.rootpath,
- cfg.utilities)
- except vclib.ReposNotFound:
- raise debug.ViewVCException(
- 'Unable to locate CVS root "%s". Possible causes include '
- 'having an incorrectly configured path for this root, or the '
- 'server on which the repository lives being inaccessible.' \
- % self.rootname)
- # required so that spawned rcs programs correctly expand $CVSHeader$
- os.environ['CVSROOT'] = self.rootpath
- elif cfg.general.svn_roots.has_key(self.rootname):
+ roottype, rootpath = locate_root(cfg, self.rootname)
+ if roottype:
+ # Overlay root-specific options.
cfg.overlay_root_options(self.rootname)
- self.rootpath = cfg.general.svn_roots[self.rootname]
+
+ # Setup an Authorizer for this rootname and username
+ self.auth = setup_authorizer(cfg, self.username, self.rootname)
+
+ # Create the repository object
try:
- if re.match(_re_rewrite_url, self.rootpath):
- # If the rootpath is a URL, we'll use the svn_ra module, but
- # lie about its name.
- import vclib.svn_ra
- vclib.svn = vclib.svn_ra
+ if roottype == 'cvs':
+ self.rootpath = vclib.ccvs.canonicalize_rootpath(rootpath)
+ self.repos = vclib.ccvs.CVSRepository(self.rootname,
+ self.rootpath,
+ self.auth,
+ cfg.utilities,
+ cfg.options.use_rcsparse)
+ # required so that spawned rcs programs correctly expand
+ # $CVSHeader$
+ os.environ['CVSROOT'] = self.rootpath
+ elif roottype == 'svn':
+ self.rootpath = vclib.svn.canonicalize_rootpath(rootpath)
+ self.repos = vclib.svn.SubversionRepository(self.rootname,
+ self.rootpath,
+ self.auth,
+ cfg.utilities,
+ cfg.options.svn_config_dir)
else:
- self.rootpath = os.path.normpath(self.rootpath)
- import vclib.svn
- self.repos = vclib.svn.SubversionRepository(self.rootname,
- self.rootpath,
- cfg.utilities)
+ raise vclib.ReposNotFound()
except vclib.ReposNotFound:
- raise debug.ViewVCException(
- 'Unable to locate Subversion root "%s". Possible causes include '
- 'having an incorrectly configured path for this root, or the '
- 'server on which the repository lives being inaccessible.' \
- % self.rootname)
- except vclib.InvalidRevision, ex:
- raise debug.ViewVCException(str(ex))
- else:
+ pass
+ if self.repos is None:
raise debug.ViewVCException(
'The root "%s" is unknown. If you believe the value is '
'correct, then please double-check your configuration.'
- % self.rootname, "404 Repository not found")
+ % self.rootname, "404 Not Found")
if self.repos:
+ self.repos.open()
type = self.repos.roottype()
if type == vclib.SVN:
self.roottype = 'svn'
@@ -290,9 +278,6 @@
'The root "%s" has an unknown type (%s).' % (self.rootname, type),
"500 Internal Server Error")
- if self.rootname and cfg.options.authorizer:
- self.auth = setup_authorizer(cfg, self.username, self.repos)
-
# If this is using an old-style 'rev' parameter, redirect to new hotness.
# Subversion URLs will now use 'pathrev'; CVS ones use 'revision'.
if self.repos and self.query_dict.has_key('rev'):
@@ -307,37 +292,43 @@
needs_redirect = 1
if self.repos and self.view_func is not redirect_pathrev:
+ # If this is an intended-to-be-hidden CVSROOT path, complain.
+ if cfg.options.hide_cvsroot \
+ and is_cvsroot_path(self.roottype, path_parts):
+ raise debug.ViewVCException("Unknown location: /%s" % self.where,
+ "404 Not Found")
+
# Make sure path exists
self.pathrev = pathrev = self.query_dict.get('pathrev')
self.pathtype = _repos_pathtype(self.repos, path_parts, pathrev)
if self.pathtype is None:
- # path doesn't exist, see if it could be an old-style ViewVC URL
- # with a fake suffix
- result = _strip_suffix('.diff', path_parts, pathrev, vclib.FILE, \
- self.repos, view_diff) or \
- _strip_suffix('.tar.gz', path_parts, pathrev, vclib.DIR, \
- self.repos, download_tarball) or \
- _strip_suffix('root.tar.gz', path_parts, pathrev, vclib.DIR, \
- self.repos, download_tarball) or \
- _strip_suffix(self.rootname + '-root.tar.gz', \
- path_parts, pathrev, vclib.DIR, \
- self.repos, download_tarball) or \
- _strip_suffix('root', \
- path_parts, pathrev, vclib.DIR, \
- self.repos, download_tarball) or \
- _strip_suffix(self.rootname + '-root', \
- path_parts, pathrev, vclib.DIR, \
+ # Path doesn't exist, see if it could be an old-style ViewVC URL
+ # with a fake suffix.
+ result = _strip_suffix('.diff', path_parts, pathrev, vclib.FILE, \
+ self.repos, view_diff) or \
+ _strip_suffix('.tar.gz', path_parts, pathrev, vclib.DIR, \
+ self.repos, download_tarball) or \
+ _strip_suffix('root.tar.gz', path_parts, pathrev, vclib.DIR,\
+ self.repos, download_tarball) or \
+ _strip_suffix(self.rootname + '-root.tar.gz', \
+ path_parts, pathrev, vclib.DIR, \
+ self.repos, download_tarball) or \
+ _strip_suffix('root', \
+ path_parts, pathrev, vclib.DIR, \
+ self.repos, download_tarball) or \
+ _strip_suffix(self.rootname + '-root', \
+ path_parts, pathrev, vclib.DIR, \
self.repos, download_tarball)
if result:
self.path_parts, self.pathtype, self.view_func = result
self.where = _path_join(self.path_parts)
needs_redirect = 1
else:
- raise debug.ViewVCException('%s: unknown location'
- % self.where, '404 Not Found')
+ raise debug.ViewVCException("Unknown location: /%s" % self.where,
+ "404 Not Found")
- # If we have an old ViewCVS Attic URL which is still valid, then redirect
+ # If we have an old ViewCVS Attic URL which is still valid, redirect
if self.roottype == 'cvs':
attic_parts = None
if (self.pathtype == vclib.FILE and len(self.path_parts) > 1
@@ -351,13 +342,6 @@
self.where = _path_join(attic_parts)
needs_redirect = 1
- # Check authorization for files and directories.
- if self.path_parts:
- if not self.auth.check_path_access(self.path_parts):
- path = _path_join(self.path_parts)
- raise debug.ViewVCNotAuthorizedException(self.username,
- 'path "%s"' % (path))
-
if self.view_func is None:
# view parameter is not set, try looking at pathtype and the
# other parameters
@@ -381,19 +365,26 @@
self.view_func = view_cvsgraph_image
elif self.query_dict.has_key('revision') \
or cfg.options.default_file_view != "log":
- if self.query_dict.get('content-type', None) in (viewcvs_mime_type,
- alt_mime_type):
+ if cfg.options.default_file_view == "markup" \
+ or self.query_dict.get('content-type', None) \
+ in (viewcvs_mime_type, alt_mime_type):
self.view_func = view_markup
else:
self.view_func = view_checkout
else:
self.view_func = view_log
+ # If we've chosen the roots or revision view, our effective
+ # location is not really "inside" the repository, so we have no
+ # path and therefore no path parts or type, either.
+ if self.view_func is view_revision or self.view_func is view_roots:
+ self.where = ''
+ self.path_parts = []
+ self.pathtype = None
+
# if we have a directory and the request didn't end in "/", then redirect
# so that it does.
if (self.pathtype == vclib.DIR and path_info[-1:] != '/'
- and self.view_func is not view_revision
- and self.view_func is not view_roots
and self.view_func is not download_tarball
and self.view_func is not redirect_pathrev):
needs_redirect = 1
@@ -402,14 +393,10 @@
if needs_redirect:
self.server.redirect(self.get_url())
- # Finally done parsing query string, set mime type and call view_func
- self.mime_type = None
- if self.pathtype == vclib.FILE:
- self.mime_type = guess_mime(self.where)
-
# startup is done now.
debug.t_end('startup')
+ # Call the function for the selected view.
self.view_func(self)
def get_url(self, escape=0, partial=0, prefix=0, **args):
@@ -438,13 +425,16 @@
def get_form(self, **args):
"""Constructs a link to another ViewVC page just like the get_link
- function except that it returns a base URL suitable for use as an HTML
- form action and a string of HTML input type=hidden tags with the link
- parameters."""
+ function except that it returns a base URL suitable for use as an
+ HTML form action, and an iterable object with .name and .value
+ attributes representing stuff that should be in <input
+ type=hidden> tags with the link parameters."""
url, params = apply(self.get_link, (), args)
action = self.server.escape(urllib.quote(url, _URL_SAFE_CHARS))
- hidden_values = prepare_hidden_values(params)
+ hidden_values = []
+ for name, value in params.items():
+ hidden_values.append(_item(name=name, value=value))
return action, hidden_values
def get_link(self, view_func=None, where=None, pathtype=None, params=None):
@@ -526,15 +516,8 @@
if where:
url = url + '/' + where
- # add suffix for tarball
- if view_func is download_tarball:
- if not where and not cfg.options.root_as_url_component:
- url = url + '/' + rootname + '-root'
- params['parent'] = '1'
- url = url + '.tar.gz'
-
# add trailing slash for a directory
- elif pathtype == vclib.DIR:
+ if pathtype == vclib.DIR:
url = url + '/'
# normalize top level URLs for use in Location headers and A tags
@@ -563,13 +546,19 @@
view_func = None
# no need to explicitly specify checkout view when it's the default
- # view, when checkout_magic is enabled, or when "revision" is present
+ # view or when checkout_magic is enabled
if view_func is view_checkout:
- if ((cfg.options.default_file_view != "log" and pathtype == vclib.FILE)
- or cfg.options.checkout_magic
- or params.get('revision') is not None):
+ if ((cfg.options.default_file_view == "co" and pathtype == vclib.FILE)
+ or cfg.options.checkout_magic):
view_func = None
+ # no need to explicitly specify markup view when it's the default view
+ if view_func is view_markup:
+ if (cfg.options.default_file_view == "markup" \
+ and pathtype == vclib.FILE):
+ view_func = None
+
+ # set the view parameter
view_code = _view_codes.get(view_func)
if view_code and not (params.has_key('view') and params['view'] is None):
params['view'] = view_code
@@ -662,7 +651,8 @@
_re_validate_mimetype = re.compile('^[-_.a-zA-Z0-9/]+$')
# date time values
-_re_validate_datetime = re.compile(r'^(\d\d\d\d-\d\d-\d\d(\s+\d\d:\d\d(:\d\d)?)?)?$')
+_re_validate_datetime = re.compile(r'^(\d\d\d\d-\d\d-\d\d(\s+\d\d:\d\d'
+ '(:\d\d)?)?)?$')
# the legal query parameters and their validation functions
_legal_params = {
@@ -681,17 +671,13 @@
'pathrev' : _re_validate_revnum,
'dir_pagestart' : _re_validate_number,
'log_pagestart' : _re_validate_number,
- 'hidecvsroot' : _re_validate_number,
'annotate' : _re_validate_revnum,
'graph' : _re_validate_revnum,
'makeimage' : _re_validate_number,
- 'tarball' : _re_validate_number,
- 'parent' : _re_validate_number,
'r1' : _re_validate_revnum,
'tr1' : _re_validate_revnum,
'r2' : _re_validate_revnum,
'tr2' : _re_validate_revnum,
- 'rev' : _re_validate_revnum,
'revision' : _re_validate_revnum,
'content-type' : _re_validate_mimetype,
@@ -718,6 +704,12 @@
'orig_pathtype' : None,
'orig_pathrev' : None,
'orig_view' : None,
+
+ # deprecated
+ 'parent' : _re_validate_number,
+ 'rev' : _re_validate_revnum,
+ 'tarball' : _re_validate_number,
+ 'hidecvsroot' : _re_validate_number,
}
def _path_join(path_parts):
@@ -726,6 +718,8 @@
def _strip_suffix(suffix, path_parts, rev, pathtype, repos, view_func):
"""strip the suffix from a repository path if the resulting path
is of the specified type, otherwise return None"""
+ if not path_parts:
+ return None
l = len(suffix)
if path_parts[-1][-l:] == suffix:
path_parts = path_parts[:]
@@ -739,7 +733,8 @@
return None
def _repos_pathtype(repos, path_parts, rev):
- """return the type of a repository path, or None if the path doesn't exist"""
+ """Return the type of a repository path, or None if the path doesn't
+ exist"""
try:
return repos.itemtype(path_parts, rev)
except vclib.ItemNotFound:
@@ -786,38 +781,42 @@
rev = request.repos._getrev(rev)
except vclib.InvalidRevision:
raise debug.ViewVCException('Invalid revision', '404 Not Found')
- return _path_parts(vclib.svn.get_location(request.repos, path,
- pathrev, rev)), rev
+ return _path_parts(request.repos.get_location(path, pathrev, rev)), rev
return _path_parts(path), rev
-def setup_authorizer(cfg, username, root, params={}):
- rootname = root.rootname()
+def setup_authorizer(cfg, username, rootname):
+ import imp
+
+ # No configured authorizer? No problem.
+ if not cfg.options.authorizer:
+ return None
# First, try to load a module with the configured name.
+ fp = None
try:
- exec('import vcauth.%s' % (cfg.options.authorizer))
- except ImportError:
- raise debug.ViewVCException(
- 'Invalid authorizer (%s) specified for root "%s"' \
- % (cfg.options.authorizer, rootname),
- '500 Internal Server Error')
+ try:
+ fp, path, desc = imp.find_module("%s" % (cfg.options.authorizer),
+ vcauth.__path__)
+ my_auth = imp.load_module('viewvc', fp, path, desc)
+ except ImportError:
+ raise debug.ViewVCException(
+ 'Invalid authorizer (%s) specified for root "%s"' \
+ % (cfg.options.authorizer, rootname),
+ '500 Internal Server Error')
+ finally:
+ if fp:
+ fp.close()
# Now we'll get custom parameters for our particular root.
- exec('my_auth = vcauth.%s' % (cfg.options.authorizer))
params = cfg.get_authorizer_params(cfg.options.authorizer, rootname)
# Finally, instantiate our Authorizer.
- try:
- return my_auth.ViewVCAuthorizer(username, root, params)
- except vcauth.ViewVCRootAccessNotAuthorized:
- raise debug.ViewVCNotAuthorizedException(username,
- 'root "%s"' % (rootname))
+ return my_auth.ViewVCAuthorizer(username, params)
def check_freshness(request, mtime=None, etag=None, weak=0):
- # See if we are supposed to disable etags (for debugging, usually)
-
cfg = request.cfg
+ # See if we are supposed to disable etags (for debugging, usually)
if not cfg.options.generate_etags:
return 0
@@ -863,18 +862,18 @@
return isfresh
def get_view_template(cfg, view_name, language="en"):
- # see if the configuration specifies a template for this view
- tname = vars(cfg.templates).get(view_name)
+ # See if the configuration specifies a template for this view. If
+ # not, use the default template path for this view.
+ tname = vars(cfg.templates).get(view_name) or view_name + ".ezt"
+
+ # Template paths are relative to the configurated template_dir (if
+ # any, "templates" otherwise), so build the template path as such.
+ tname = os.path.join(cfg.options.template_dir or "templates", tname)
- # if there is no specific template definition for this view, look in
- # the default location (relative to the configured template_dir)
- if not tname:
- tname = os.path.join(cfg.options.template_dir, view_name + ".ezt")
-
- # allow per-language template selection
+ # Allow per-language template selection.
tname = string.replace(tname, '%lang%', language)
- # finally, construct the whole template path.
+ # Finally, construct the whole template path.
tname = cfg.path(tname)
debug.t_start('ezt-parse')
@@ -883,13 +882,28 @@
return template
-def generate_page(request, view_name, data, content_type=None):
+def get_writeready_server_file(request, content_type=None):
+ """Return a file handle to a response body stream, after outputting
+ any queued special headers (on REQUEST.server) and (optionally) a
+ 'Content-Type' header whose value is CONTENT_TYPE. After this is
+ called, it is too late to add new headers to the response."""
+ if request.gzip_compress_level:
+ request.server.addheader('Content-Encoding', 'gzip')
if content_type:
request.server.header(content_type)
else:
request.server.header()
+ if request.gzip_compress_level:
+ fp = gzip.GzipFile('', 'wb', request.gzip_compress_level,
+ request.server.file())
+ else:
+ fp = request.server.file()
+ return fp
+
+def generate_page(request, view_name, data, content_type=None):
+ server_fp = get_writeready_server_file(request)
template = get_view_template(request.cfg, view_name, request.language)
- template.generate(request.server.file(), data)
+ template.generate(server_fp, data)
def nav_path(request):
"""Return current path as list of items with "name" and "href" members
@@ -958,6 +972,9 @@
def is_text(mime_type):
return not mime_type or mime_type[:5] == 'text/'
+def is_cvsroot_path(roottype, path_parts):
+ return roottype == 'cvs' and path_parts and path_parts[0] == 'CVSROOT'
+
def is_plain_text(mime_type):
return not mime_type or mime_type == 'text/plain'
@@ -979,10 +996,15 @@
"""Return common hrefs and a viewability flag used for various views
of FILENAME at revision REV whose MIME type is MIME_TYPE."""
rev = rev and str(rev) or None
- mime_type = mime_type or request.mime_type
+ mime_type = mime_type or guess_mime(where)
if pathrev == -1: # cheesy default value, since we need to preserve None
pathrev = request.pathrev
- view_href = download_href = download_text_href = annotate_href = revision_href = None
+
+ view_href = None
+ download_href = None
+ download_text_href = None
+ annotate_href = None
+ revision_href = None
if 'markup' in request.cfg.options.allowed_views:
view_href = request.get_url(view_func=view_markup,
@@ -1034,6 +1056,25 @@
'(([-a-zA-Z0-9]+\.)+[A-Za-z]{2,4})')
# XXXX Gnome hack to turn bug numbers into links
_re_rewrite_bug = re.compile(r'((?:\b(?:bug|issue)[\s#]+|#\s*)(\d\d+))', re.I)
+
+def mangle_email_addresses(text, style=0):
+ # style=2: truncation mangling
+ if style == 2:
+ return re.sub(_re_rewrite_email, r'\1@…', text)
+
+ # style=1: entity-encoding and at-wrapping
+ if style == 1:
+ def _match_replace(matchobj):
+ return string.join(map(lambda x: '&#%d;' % (ord(x)),
+ matchobj.group(1)), '') \
+ + ' {at} ' + \
+ string.join(map(lambda x: '&#%d;' % (ord(x)),
+ matchobj.group(2)), '')
+ return re.sub(_re_rewrite_email, _match_replace, text)
+
+ # otherwise, no mangling
+ return text
+
def htmlify(html, mangle_email_addrs=0):
if not html:
return html
@@ -1042,24 +1083,19 @@
# XXXX Gnome hack to turn bug numbers into links
html = re.sub(_re_rewrite_bug, r'<a href="http://bugzilla.gnome.org/show_bug.cgi?id=\2">\1</a>', html)
- if mangle_email_addrs:
- ### FIXME: I'm sure email address mangling comes in a hundred
- ### different flavors. As a mechanism for defeating spam
- ### harvesters, I suspect that merely obscuring the address only
- ### works for a season (until the obscurity algorithm is added to
- ### the spammers' databases of such things). We have to actually
- ### *lose* information here for it really matter.
- html = re.sub(_re_rewrite_email, r'\1@…', html)
- else:
- html = re.sub(_re_rewrite_email,
- r'<a href="mailto:\1@\2">\1@\2</a>', html)
+ html = mangle_email_addresses(html, mangle_email_addrs)
return html
-def format_log(log, cfg):
+def format_log(log, cfg, htmlize=1):
if not log:
return log
- s = htmlify(log[:cfg.options.short_log_len],
- cfg.options.mangle_email_addresses)
+ if htmlize:
+ s = htmlify(log[:cfg.options.short_log_len],
+ cfg.options.mangle_email_addresses)
+ else:
+ s = cgi.escape(log[:cfg.options.short_log_len])
+ if cfg.options.mangle_email_addresses == 2:
+ s = re.sub(_re_rewrite_email, r'\1 ', s)
if len(log) > cfg.options.short_log_len:
s = s + '...'
return s
@@ -1122,7 +1158,7 @@
s = s + ', ' + ext
return s
-def common_template_data(request):
+def common_template_data(request, revision=None, mime_type=None):
cfg = request.cfg
data = {
'cfg' : cfg,
@@ -1131,14 +1167,17 @@
'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,
- 'rootname' : request.server.escape(request.rootname),
+ '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,
@@ -1151,10 +1190,13 @@
'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),
}
- rev = request.query_dict.get('annotate')
+ rev = revision
+ if not rev:
+ rev = request.query_dict.get('annotate')
if not rev:
rev = request.query_dict.get('revision')
if not rev and request.roottype == 'svn':
@@ -1164,33 +1206,12 @@
and request.repos._getrev(rev) or rev
except vclib.InvalidRevision:
raise debug.ViewVCException('Invalid revision', '404 Not Found')
+
if request.pathtype == vclib.DIR:
data['pathtype'] = 'dir'
elif request.pathtype == vclib.FILE:
data['pathtype'] = 'file'
- data['change_root_action'], data['change_root_hidden_values'] = \
- request.get_form(view_func=view_directory, where='', pathtype=vclib.DIR,
- params={'root': None})
-
- # add in the roots for the selection
- roots = []
- allroots = list_roots(cfg)
- if len(allroots):
- rootnames = allroots.keys()
- rootnames.sort(icmp)
- for rootname in rootnames:
- href = request.get_url(view_func=view_directory,
- where='', pathtype=vclib.DIR,
- params={'root': rootname}, escape=1)
-
- ### TODO: Check root authorization.
- roots.append(_item(name=request.server.escape(rootname),
- type=allroots[rootname][1],
- path=allroots[rootname][0],
- href=href))
- data['roots'] = roots
-
if request.path_parts:
dir = _path_join(request.path_parts[:-1])
data['up_href'] = request.get_url(view_func=view_directory,
@@ -1200,13 +1221,21 @@
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'], request.mime_type)
+ = get_file_view_info(request, request.where, data['rev'], mime_type)
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)
+ file_data = request.repos.listdir(request.path_parts[:-1],
+ request.pathrev, {})
+ def _only_this_file(item):
+ return item.name == request.path_parts[-1]
+ entries = filter(_only_this_file, file_data)
+ if len(entries) == 1:
+ request.repos.dirlogs(request.path_parts[:-1], request.pathrev,
+ entries, {})
+ data['lockinfo'] = entries[0].lockinfo
elif request.pathtype == vclib.DIR:
data['view_href'] = request.get_url(view_func=view_directory,
params={}, escape=1)
@@ -1216,22 +1245,35 @@
escape=1)
if request.roottype == 'svn':
data['revision_href'] = request.get_url(view_func=view_revision,
- params={}, escape=1)
+ params={'revision': data['rev']},
+ escape=1)
data['log_href'] = request.get_url(view_func=view_log,
params={}, escape=1)
- if is_query_supported(request):
- params = {}
- if request.roottype == 'cvs' and request.pathrev:
- params['branch'] = request.pathrev
- data['queryform_href'] = request.get_url(view_func=view_queryform,
- params=params,
- escape=1)
- data['rss_href'] = request.get_url(view_func=view_query,
- params={'date': 'month',
- 'format': 'rss'},
- escape=1)
+ if is_querydb_nonempty_for_root(request):
+ if request.pathtype == vclib.DIR:
+ params = {}
+ if request.roottype == 'cvs' and request.pathrev:
+ params['branch'] = request.pathrev
+ data['queryform_href'] = request.get_url(view_func=view_queryform,
+ params=params,
+ escape=1)
+ data['rss_href'] = request.get_url(view_func=view_query,
+ params={'date': 'month',
+ 'format': 'rss'},
+ escape=1)
+ elif request.pathtype == vclib.FILE:
+ parts = _path_parts(request.where)
+ where = _path_join(parts[:-1])
+ data['rss_href'] = request.get_url(view_func=view_query,
+ where=where,
+ pathtype=request.pathtype,
+ params={'date': 'month',
+ 'format': 'rss',
+ 'file': parts[-1],
+ 'file_match': 'exact'},
+ escape=1)
return data
def retry_read(src, reqlen=CHUNK_SIZE):
@@ -1273,185 +1315,88 @@
if self.posttext:
ctx.fp.write(self.posttext)
-class MarkupShell:
- """A EZT callback object slamming file contents through shell tools."""
-
- def __init__(self, cfg, fp, cmds):
- self.fp = fp
- self.cmds = cmds
- self.cfg = cfg
-
- def __call__(self, ctx):
- ctx.fp.flush()
- try:
- pipe = popen.pipe_cmds(self.cmds, ctx.fp)
- try:
- if self.fp:
- copy_stream(self.fp, pipe, self.cfg)
- self.fp.close()
- self.fp = None
- finally:
- pipe.close()
- except IOError:
- raise debug.ViewVCException \
- ('Error running external program. Command line was: "%s"'
- % string.join(map(lambda args: string.join(args, ' '), self.cmds),
- ' | '))
-
- def __del__(self):
- self.close()
-
- def close(self):
- if self.fp:
- self.fp.close()
- self.fp = None
-
-class MarkupEnscript(MarkupShell):
- def __init__(self, cfg, fp, filename):
-
- # I've tried to pass option '-C' to enscript to generate line numbers
- # Unfortunately this option doesn't work with HTML output in enscript
- # version 1.6.2.
- enscript_cmd = [cfg.utilities.enscript or 'enscript',
- '--color', '--language=html', '--pretty-print',
- '-o', '-', '-']
-
- ### I'd like to also strip the <PRE> and </PRE> tags, too, but
- ### can't come up with a suitable sed expression. Using
- ### '1,/^<PRE>$/d;/<\\/PRE>/,$d;p' gets me most of the way, but
- ### will drop the last line of a non-newline-terminated filed.
- sed_cmd = [cfg.utilities.sed or 'sed', '-n', '/^<PRE>$/,/<\\/PRE>$/p']
-
- MarkupShell.__init__(self, cfg, fp, [enscript_cmd, sed_cmd])
- self.filename = filename
- self.cfg = cfg
-
- def __call__(self, ctx):
- # create a temporary file with the same name as the file in
- # the repository so enscript can detect file type correctly
- dir = compat.mkdtemp("", "viewvc")
- try:
- file = os.path.join(dir, self.filename)
- try:
- copy_stream(self.fp, open(file, 'wb'), self.cfg)
- self.fp.close()
- self.fp = None
- self.cmds[0][-1] = file
- MarkupShell.__call__(self, ctx)
- finally:
- os.unlink(file)
- finally:
- os.rmdir(dir)
-
-class MarkupPHP(MarkupShell):
- def __init__(self, cfg, fp):
- php_cmd = [cfg.utilities.php or 'php', '-q', '-s', '-n']
- MarkupShell.__init__(self, cfg, fp, [php_cmd])
-
-class MarkupHighlight(MarkupShell):
- def __init__(self, cfg, fp, filename):
- highlight_cmd = [cfg.utilities.highlight or 'highlight',
- '--force', '--anchors', '--fragment', '--xhtml']
-
- if cfg.options.highlight_line_numbers:
- highlight_cmd.extend(['--linenumbers'])
-
- if cfg.options.highlight_convert_tabs:
- highlight_cmd.extend(['--replace-tabs',
- str(cfg.options.highlight_convert_tabs)])
-
- highlight_cmd.extend(['-'])
- MarkupShell.__init__(self, cfg, fp, [highlight_cmd])
- self.filename = filename
- self.cfg = cfg
-
- def __call__(self, ctx):
- # create a temporary file with the same name as the file in
- # the repository so highlight can detect file type correctly
- dir = compat.mkdtemp("", "viewvc")
+def markup_stream_pygments(request, cfg, blame_data, fp, filename, mime_type):
+ # Determine if we should use Pygments to highlight our output.
+ # Reasons not to include a) being told not to by the configuration,
+ # b) not being able to import the Pygments modules, and c) Pygments
+ # not having a lexer for our file's format.
+ blame_source = []
+ if blame_data:
+ for i in blame_data:
+ i.text = cgi.escape(i.text)
+ i.diff_href = None
+ if i.prev_rev:
+ i.diff_href = request.get_url(view_func=view_diff,
+ params={'r1': i.prev_rev,
+ 'r2': i.rev},
+ escape=1, partial=1)
+ blame_source.append(i)
+ blame_data = blame_source
+ lexer = None
+ use_pygments = cfg.options.enable_syntax_coloration
+ try:
+ from pygments import highlight
+ from pygments.formatters import HtmlFormatter
+ from pygments.lexers import ClassNotFound, \
+ get_lexer_by_name, \
+ get_lexer_for_mimetype, \
+ get_lexer_for_filename
try:
- file = os.path.join(dir, self.filename)
+ lexer = get_lexer_for_mimetype(mime_type)
+ except ClassNotFound:
try:
- copy_stream(self.fp, open(file, 'wb'), self.cfg)
- self.fp.close()
- self.fp = None
- self.cmds[0][-1] = file
- MarkupShell.__call__(self, ctx)
- finally:
- os.unlink(file)
- finally:
- os.rmdir(dir)
-
-class MarkupSourceHighlight(MarkupShell):
- def __init__(self, cfg, fp, filename):
- basename, ext = os.path.splitext(filename)
- if ext:
- ext = ext[1:]
-
- ### Ideally, we'd use '--output xhtml-css', which would let us supply
- ### supply our own style definitions. Unfortunately, this appears to
- ### be broken in source-highlight 2.3, 2.4, and 2.5 (at least). :-(
- highlight_cmd = [cfg.utilities.source_highlight or 'source-highlight',
- '--out-format', 'xhtml', '--output', 'STDOUT',
- '-s', ext, '--failsafe']
- if cfg.options.source_highlight_line_numbers:
- highlight_cmd.extend(['--line-number-ref=l_'])
-
- sed_cmd = [cfg.utilities.sed or 'sed',
- '-n',
- '/^<pre><tt>/,/<\\/tt><\\/pre>$/p']
-
- MarkupShell.__init__(self, cfg, fp, [highlight_cmd, sed_cmd])
-
-def markup_stream_python(fp, cfg):
- if not cfg.options.use_py2html:
- return None
-
- ### Convert this code to use the recipe at:
- ### http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298
- ### Note that the cookbook states all the code is licensed according to
- ### the Python license.
- try:
- # See if Marc-Andre Lemburg's py2html stuff is around.
- # http://www.egenix.com/files/python/SoftwareDescriptions.html#py2html.py
- ### maybe restrict the import to *only* this directory?
- sys.path.insert(0, cfg.utilities.py2html_dir)
- import py2html
- import PyFontify
+ lexer = get_lexer_for_filename(filename)
+ except ClassNotFound:
+ use_pygments = 0
except ImportError:
- return None
+ use_pygments = 0
- ### It doesn't escape stuff quite right, nor does it munge URLs and
- ### mailtos as well as we do.
- html = cgi.escape(fp.read())
- pp = py2html.PrettyPrint(PyFontify.fontify, "rawhtml", "color")
- pp.set_mode_rawhtml_color()
- html = pp.fontify(html)
- html = re.sub(_re_rewrite_url, r'<a href="\1">\1</a>', html)
- html = re.sub(_re_rewrite_email, r'<a href="mailto:\1">\1</a>', html)
- return html
-
-def markup_stream_php(fp, cfg):
- if not cfg.options.use_php:
- return None
-
- # The following HACK may be be used to allow a PHP CGI executable to be
- # invoked instead of a CLI executable, on systems that do not have PHP's
- # CLI (command line interface) installed. Just uncomment the following lines:
- #os.unsetenv("SERVER_SOFTWARE")
- #os.unsetenv("SERVER_NAME")
- #os.unsetenv("GATEWAY_INTERFACE")
- #os.unsetenv("REQUEST_METHOD")
- #os.unsetenv("SCRIPT_FILENAME")
- #os.unsetenv("PATH_TRANSLATED")
-
- return MarkupPHP(cfg, fp)
-
-markup_streamers = {
- '.py' : markup_stream_python,
- '.php' : markup_stream_php,
- '.inc' : markup_stream_php,
- }
+ # If we aren't going to be highlighting anything, just return the
+ # BLAME_SOURCE. If there's no blame_source, we'll generate a fake
+ # one from the file contents we fetch with PATH and REV.
+ if not use_pygments:
+ if blame_source:
+ return blame_source
+ else:
+ lines = []
+ line_no = 0
+ while 1:
+ line = fp.readline()
+ if not line:
+ break
+ line_no = line_no + 1
+ item = vclib.Annotation(cgi.escape(line), line_no,
+ None, None, None, None)
+ item.diff_href = None
+ lines.append(item)
+ return lines
+
+ # If we get here, we're highlighting something.
+ class PygmentsSink:
+ def __init__(self, blame_data):
+ if blame_data:
+ self.has_blame_data = 1
+ self.blame_data = blame_data
+ else:
+ self.has_blame_data = 0
+ self.blame_data = []
+ self.line_no = 0
+ def write(self, buf):
+ ### FIXME: Don't bank on write() being called once per line
+ if self.has_blame_data:
+ self.blame_data[self.line_no].text = buf
+ else:
+ item = vclib.Annotation(buf, self.line_no + 1,
+ None, None, None, None)
+ item.diff_href = None
+ self.blame_data.append(item)
+ self.line_no = self.line_no + 1
+ ps = PygmentsSink(blame_source)
+ highlight(fp.read(), lexer,
+ HtmlFormatter(nowrap=True,
+ classprefix="pygments-",
+ encoding='utf-8'), ps)
+ return ps.blame_data
def make_time_string(date, cfg):
"""Returns formatted date string in either local time or UTC.
@@ -1477,24 +1422,88 @@
return None
return time.strftime("%a, %d %b %Y %H:%M:%S", time.gmtime(date)) + ' UTC'
-def view_markup(request):
- if 'markup' not in request.cfg.options.allowed_views:
- raise debug.ViewVCException('Markup view is disabled',
- '403 Forbidden')
-
+def get_itemprops(request, path_parts, rev):
+ itemprops = request.repos.itemprops(path_parts, rev)
+ propnames = itemprops.keys()
+ propnames.sort()
+ props = []
+ has_binary_props = 0
+ for name in propnames:
+ value = itemprops[name]
+ undisplayable = ezt.boolean(0)
+ # skip non-utf8 property names
+ try:
+ unicode(name, 'utf8')
+ except:
+ continue
+ # note non-utf8 property values
+ try:
+ unicode(value, 'utf8')
+ except:
+ value = None
+ undisplayable = ezt.boolean(1)
+ props.append(_item(name=name, value=value, undisplayable=undisplayable))
+ return props
+
+def calculate_mime_type(request, path_parts, rev):
+ mime_type = None
+ if not path_parts:
+ return None
+ if request.roottype == 'svn':
+ try:
+ itemprops = request.repos.itemprops(path_parts, rev)
+ mime_type = itemprops.get('svn:mime-type')
+ if mime_type:
+ return mime_type
+ except:
+ pass
+ return guess_mime(path_parts[-1])
+
+def markup_or_annotate(request, is_annotate):
cfg = request.cfg
- path, rev = _orig_path(request)
- fp, revision = request.repos.openfile(path, rev)
+ path, rev = _orig_path(request, is_annotate and 'annotate' or 'revision')
+ lines = fp = image_src_href = None
+ annotation = None
+ revision = None
+ mime_type = calculate_mime_type(request, path, rev)
- # Since the templates could be changed by the user, we can't provide
- # a strong validator for this page, so we mark the etag as weak.
- if check_freshness(request, None, revision, weak=1):
+ # Is this a viewable image type?
+ if is_viewable_image(mime_type) \
+ and 'co' in cfg.options.allowed_views:
+ fp, revision = request.repos.openfile(path, rev)
+ fp.close()
+ if check_freshness(request, None, revision, weak=1):
+ return
+ annotation = 'binary'
+ image_src_href = request.get_url(view_func=view_checkout,
+ params={'revision': rev}, escape=1)
+
+ # Not a viewable image.
+ else:
+ blame_source = None
+ if is_annotate:
+ # Try to annotate this file, but don't croak if we fail.
+ try:
+ blame_source, revision = request.repos.annotate(path, rev)
+ annotation = 'annotated'
+ if check_freshness(request, None, revision, weak=1):
+ return
+ except vclib.NonTextualFileContents:
+ annotation = 'binary'
+ except:
+ annotation = 'error'
+
+ fp, revision = request.repos.openfile(path, rev)
+ if check_freshness(request, None, revision, weak=1):
+ fp.close()
+ return
+ lines = markup_stream_pygments(request, cfg, blame_source, fp,
+ path[-1], mime_type)
fp.close()
- return
- data = common_template_data(request)
+ data = common_template_data(request, revision)
data.update({
- 'mime_type' : request.mime_type,
+ 'mime_type' : mime_type,
'log' : None,
'date' : None,
'ago' : None,
@@ -1509,11 +1518,16 @@
'prev' : None,
'orig_path' : None,
'orig_href' : None,
+ 'image_src_href' : image_src_href,
+ 'lines' : lines,
+ 'properties' : get_itemprops(request, path, rev),
+ 'annotation' : annotation,
})
if cfg.options.show_log_in_markup:
- options = {'svn_latest_log': 1}
- revs = request.repos.itemlog(path, revision, options)
+ options = {'svn_latest_log': 1} ### FIXME: No longer needed?
+ revs = request.repos.itemlog(path, revision, vclib.SORTBY_DEFAULT,
+ 0, 1, options)
entry = revs[-1]
data.update({
'date' : make_time_string(entry.date, cfg),
@@ -1547,50 +1561,26 @@
pathtype=vclib.FILE,
params={'pathrev': revision},
escape=1)
-
- markup_fp = None
- if is_viewable_image(request.mime_type) \
- and 'co' in cfg.options.allowed_views:
- fp.close()
- url = request.get_url(view_func=view_checkout, params={'revision': rev},
- escape=1)
- markup_fp = '<img src="%s" alt="" /><br />' % url
- else:
- basename, ext = os.path.splitext(request.path_parts[-1])
- streamer = markup_streamers.get(ext)
- if streamer:
- markup_fp = streamer(fp, cfg)
-
- # If there wasn't a custom streamer, or the streamer wasn't enabled, we'll
- # try to use one of the configured syntax highlighting programs.
- if not markup_fp:
- if cfg.options.use_enscript:
- markup_fp = MarkupEnscript(cfg, fp, request.path_parts[-1])
- elif cfg.options.use_highlight:
- markup_fp = MarkupHighlight(cfg, fp, request.path_parts[-1])
- elif cfg.options.use_source_highlight:
- markup_fp = MarkupSourceHighlight(cfg, fp, request.path_parts[-1])
- else:
- # If no one has a suitable markup handler, we'll use the default.
- markup_fp = MarkupPipeWrapper(cfg, fp)
- data['markup'] = markup_fp
- generate_page(request, "markup", data)
+ generate_page(request, "file", data)
+
+def view_markup(request):
+ if 'markup' not in request.cfg.options.allowed_views:
+ raise debug.ViewVCException('Markup view is disabled',
+ '403 Forbidden')
+ markup_or_annotate(request, 0)
+
+def view_annotate(request):
+ if 'annotate' not in request.cfg.options.allowed_views:
+ raise debug.ViewVCException('Annotation view is disabled',
+ '403 Forbidden')
+ markup_or_annotate(request, 1)
def revcmp(rev1, rev2):
rev1 = map(int, string.split(rev1, '.'))
rev2 = map(int, string.split(rev2, '.'))
return cmp(rev1, rev2)
-def prepare_hidden_values(params):
- """returns variables from params encoded as a invisible HTML snippet.
- """
- hidden_values = []
- for name, value in params.items():
- hidden_values.append('<input type="hidden" name="%s" value="%s" />' %
- (name, value))
- return string.join(hidden_values, '')
-
def sort_file_data(file_data, roottype, sortdir, sortby, group_dirs):
# convert sortdir into a sign bit
s = sortdir == "down" and -1 or 1
@@ -1643,7 +1633,28 @@
return cmp(string.lower(x), string.lower(y))
def view_roots(request):
+ if 'roots' not in request.cfg.options.allowed_views:
+ raise debug.ViewVCException('Root listing view is disabled',
+ '403 Forbidden')
+
+ # add in the roots for the selection
+ roots = []
+ expand_root_parents(request.cfg)
+ allroots = list_roots(request)
+ if len(allroots):
+ rootnames = allroots.keys()
+ rootnames.sort(icmp)
+ for rootname in rootnames:
+ href = request.get_url(view_func=view_directory,
+ where='', pathtype=vclib.DIR,
+ params={'root': rootname}, escape=1)
+ roots.append(_item(name=request.server.escape(rootname),
+ type=allroots[rootname][1],
+ path=allroots[rootname][0],
+ href=href))
+
data = common_template_data(request)
+ data['roots'] = roots
generate_page(request, "roots", data)
def view_roots_txt(request):
@@ -1659,7 +1670,7 @@
rev = request.repos._getrev(request.pathrev)
except vclib.InvalidRevision:
raise debug.ViewVCException('Invalid revision', '404 Not Found')
- tree_rev = vclib.svn.created_rev(request.repos, request.where, rev)
+ tree_rev = request.repos.created_rev(request.where, rev)
if check_freshness(request, None, str(tree_rev), weak=1):
return
@@ -1671,25 +1682,9 @@
cfg.options.hide_attic))
options["cvs_subdirs"] = (cfg.options.show_subdir_lastmod and
cfg.options.show_logs)
-
file_data = request.repos.listdir(request.path_parts, request.pathrev,
options)
- # Filter file list if a regex is specified
- search_re = request.query_dict.get('search', '')
- if cfg.options.use_re_search and search_re:
- file_data = search_files(request.repos, request.path_parts,
- request.pathrev, file_data, search_re)
-
- # Further filter the file list based on what the user is permitted
- # to see. We do this before called dirlogs because it'll save us
- # some work there, but also so it won't harvest tag/branch names
- # from unauthorized files.
- def _auth_filter(item):
- return request.auth.check_path_access(request.path_parts \
- + [item.name])
- file_data = filter(_auth_filter, file_data)
-
# sort with directories first, and using the "sortby" criteria
sortby = request.query_dict.get('sortby', cfg.options.sort_by) or 'file'
sortdir = request.query_dict.get('sortdir', 'up')
@@ -1711,6 +1706,8 @@
file.log = None
file.author = None
file.size = None
+ file.lockinfo = None
+ file.dead = None
sort_file_data(file_data, request.roottype, sortdir, sortby,
cfg.options.sort_group_dirs)
# request dirlogs only for the slice of files in "this page"
@@ -1723,6 +1720,12 @@
cfg.options.sort_group_dirs)
debug.t_end("dirlogs")
+ # If a regex is specified, build a compiled form thereof for filtering
+ searchstr = None
+ search_re = request.query_dict.get('search', '')
+ if cfg.options.use_re_search and search_re:
+ searchstr = re.compile(search_re)
+
# loop through entries creating rows and changing these values
rows = [ ]
num_displayed = 0
@@ -1738,7 +1741,10 @@
date=None, ago=None, view_href=None, log_href=None,
revision_href=None, annotate_href=None, download_href=None,
download_text_href=None, prefer_markup=ezt.boolean(0))
-
+ if request.roottype == 'cvs' and file.absent:
+ continue
+ if cfg.options.hide_errorful_entries and file.errors:
+ continue
row.rev = file.rev
row.author = file.author
row.state = (request.roottype == 'cvs' and file.dead) and 'dead' or ''
@@ -1748,7 +1754,7 @@
if cfg.options.show_logs:
row.short_log = format_log(file.log, cfg)
row.log = htmlify(file.log, cfg.options.mangle_email_addresses)
-
+ row.lockinfo = file.lockinfo
row.anchor = request.server.escape(file.name)
row.name = request.server.escape(file.name)
row.pathtype = (file.kind == vclib.FILE and 'file') or \
@@ -1756,9 +1762,9 @@
row.errors = file.errors
if file.kind == vclib.DIR:
-
- if (request.roottype == 'cvs' and cfg.options.hide_cvsroot
- and where == '' and file.name == 'CVSROOT'):
+ if cfg.options.hide_cvsroot \
+ and is_cvsroot_path(request.roottype,
+ request.path_parts + [file.name]):
continue
row.view_href = request.get_url(view_func=view_directory,
@@ -1786,19 +1792,25 @@
escape=1)
elif file.kind == vclib.FILE:
-
+ if searchstr is not None:
+ if request.roottype == 'cvs' and (file.errors or file.dead):
+ continue
+ if not search_file(request.repos, request.path_parts + [file.name],
+ request.pathrev, searchstr):
+ continue
if request.roottype == 'cvs' and file.dead:
num_dead = num_dead + 1
if hideattic:
continue
+
num_displayed = num_displayed + 1
file_where = where_prefix + file.name
if request.roottype == 'svn':
row.size = file.size
- ### for Subversion, we should first try to get this from the properties
- row.mime_type = guess_mime(file.name)
+ 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 \
@@ -1852,6 +1864,7 @@
'hide_attic_href' : None,
'branch_tags': None,
'plain_tags': None,
+ 'properties': get_itemprops(request, request.path_parts, request.pathrev),
})
# clicking on sort column reverses sort order
@@ -1888,7 +1901,7 @@
data['tree_rev_href'] = request.get_url(view_func=view_revision,
params={'revision': tree_rev},
escape=1)
- data['youngest_rev'] = vclib.svn.get_youngest_revision(request.repos)
+ data['youngest_rev'] = request.repos.get_youngest_revision()
data['youngest_rev_href'] = request.get_url(view_func=view_revision,
params={},
escape=1)
@@ -1900,8 +1913,7 @@
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
- and (num_displayed > 0 or search_re))
+ data['search_re_form'] = ezt.boolean(cfg.options.use_re_search)
if data['search_re_form']:
data['search_re_action'], data['search_re_hidden_values'] = \
request.get_form(params={'search': None})
@@ -1918,7 +1930,7 @@
# Create the picklist
picklist = data['picklist'] = []
for i in range(0, len(data[key]), pagesize):
- pick = _item(start=None, end=None, count=None)
+ pick = _item(start=None, end=None, count=None, more=ezt.boolean(0))
pick.start = getattr(data[key][i], local_name)
pick.count = i
pick.page = (i / pagesize) + 1
@@ -1941,6 +1953,38 @@
# Slice
return data[key][pagestart:pageend]
+def paging_sws(data, key, pagestart, local_name, pagesize, offset):
+ """Implement sliding window-style paging."""
+ # Create the picklist
+ last_requested = pagestart + (EXTRA_PAGES * pagesize)
+ picklist = data['picklist'] = []
+ has_more = ezt.boolean(0)
+ for i in range(0, len(data[key]), pagesize):
+ pick = _item(start=None, end=None, count=None, more=ezt.boolean(0))
+ pick.start = getattr(data[key][i], local_name)
+ pick.count = offset + i
+ pick.page = (pick.count / pagesize) + 1
+ try:
+ pick.end = getattr(data[key][i+pagesize-1], local_name)
+ except IndexError:
+ pick.end = getattr(data[key][-1], local_name)
+ picklist.append(pick)
+ if pick.count >= last_requested:
+ pick.more = ezt.boolean(1)
+ break
+ data['picklist_len'] = len(picklist)
+ first = pagestart - offset
+ # FIXME: first can be greater than the length of data[key] if
+ # you select a tag or search while on a page other than the first.
+ # Should reset to the first page, but this test won't do that every
+ # time that it is needed. Problem might go away if we don't hide
+ # non-matching files when selecting for tags or searching.
+ if first > len(data[key]):
+ pagestart = 0
+ pageend = first + pagesize
+ # Slice
+ return data[key][first:pageend]
+
def pathrev_form(request, data):
lastrev = None
@@ -1954,12 +1998,12 @@
'orig_view': _view_codes.get(request.view_func)})
if request.pathrev:
- youngest = vclib.svn.get_youngest_revision(request.repos)
- lastrev = vclib.svn.last_rev(request.repos, request.where,
- request.pathrev, youngest)[0]
+ youngest = request.repos.get_youngest_revision()
+ lastrev = request.repos.last_rev(request.where, request.pathrev,
+ youngest)[0]
if lastrev == youngest:
- lastrev = None
+ lastrev = None
data['pathrev'] = request.pathrev
data['lastrev'] = lastrev
@@ -1981,7 +2025,7 @@
pathrev = request.query_dict.get('orig_pathrev')
view = _views.get(request.query_dict.get('orig_view'))
- youngest = vclib.svn.get_youngest_revision(request.repos)
+ youngest = request.repos.get_youngest_revision()
# go out of the way to allow revision numbers higher than youngest
try:
@@ -1997,8 +2041,7 @@
if _repos_pathtype(request.repos, _path_parts(path), new_pathrev):
pathrev = new_pathrev
else:
- pathrev, path = vclib.svn.last_rev(request.repos, path, pathrev,
- new_pathrev)
+ pathrev, path = request.repos.last_rev(path, pathrev, new_pathrev)
# allow clearing sticky revision by submitting empty string
if new_pathrev is None and pathrev == youngest:
pathrev = None
@@ -2008,37 +2051,43 @@
pathtype=pathtype,
params={'pathrev': pathrev}))
-def logsort_date_cmp(rev1, rev2):
- # sort on date; secondary on revision number
- return -cmp(rev1.date, rev2.date) or -cmp(rev1.number, rev2.number)
-
-def logsort_rev_cmp(rev1, rev2):
- # sort highest revision first
- return -cmp(rev1.number, rev2.number)
-
def view_log(request):
cfg = request.cfg
diff_format = request.query_dict.get('diff_format', cfg.options.diff_format)
- logsort = request.query_dict.get('logsort', cfg.options.log_sort)
pathtype = request.pathtype
- if pathtype is vclib.DIR and request.roottype == 'cvs':
- raise debug.ViewVCException('Unsupported feature: log view on CVS '
- 'directory', '400 Bad Request')
+ if pathtype is vclib.DIR:
+ if request.roottype == 'cvs':
+ raise debug.ViewVCException('Unsupported feature: log view on CVS '
+ 'directory', '400 Bad Request')
+ mime_type = None
+ else:
+ mime_type = calculate_mime_type(request, request.path_parts, request.pathrev)
options = {}
options['svn_show_all_dir_logs'] = 1 ### someday make this optional?
options['svn_cross_copies'] = cfg.options.cross_copies
-
+
+ logsort = request.query_dict.get('logsort', cfg.options.log_sort)
+ if request.roottype == "svn":
+ sortby = vclib.SORTBY_DEFAULT
+ logsort = None
+ else:
+ if logsort == 'date':
+ sortby = vclib.SORTBY_DATE
+ elif logsort == 'rev':
+ sortby = vclib.SORTBY_REV
+ else:
+ sortby = vclib.SORTBY_DEFAULT
+
+ first = last = 0
+ if cfg.options.use_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
show_revs = request.repos.itemlog(request.path_parts, request.pathrev,
- options)
- if logsort == 'date':
- show_revs.sort(logsort_date_cmp)
- elif logsort == 'rev':
- show_revs.sort(logsort_rev_cmp)
- else:
- # no sorting
- pass
+ sortby, first, last - first, options)
# selected revision
selected_rev = request.query_dict.get('r1')
@@ -2058,6 +2107,7 @@
entry.ago = html_time(request, rev.date, 1)
entry.log = htmlify(rev.log or "", cfg.options.mangle_email_addresses)
entry.size = rev.size
+ entry.lockinfo = rev.lockinfo
entry.branch_point = None
entry.next_main = None
entry.orig_path = None
@@ -2133,8 +2183,7 @@
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,
- request.mime_type)
+ = get_file_view_info(request, request.where, rev.string, mime_type)
else:
entry.revision_href = request.get_url(view_func=view_revision,
params={'revision': rev.string},
@@ -2148,7 +2197,9 @@
# calculate diff links
if selected_rev != entry.rev:
entry.sel_for_diff_href = \
- request.get_url(view_func=view_log, params={'r1': entry.rev}, escape=1)
+ request.get_url(view_func=view_log,
+ params={'r1': entry.rev},
+ escape=1)
if entry.prev is not None:
entry.diff_to_prev_href = \
request.get_url(view_func=view_diff,
@@ -2193,18 +2244,18 @@
data = common_template_data(request)
data.update({
'default_branch' : None,
- 'mime_type' : request.mime_type,
+ 'mime_type' : mime_type,
'rev_selected' : selected_rev,
'diff_format' : diff_format,
'logsort' : logsort,
'human_readable' : ezt.boolean(diff_format in ('h', 'l')),
'log_pagestart' : None,
'entries': entries,
- 'prefer_markup' : ezt.boolean(0),
- 'view_href' : None,
- 'download_href': None,
- 'download_text_href': None,
- 'annotate_href': None,
+ 'head_prefer_markup' : ezt.boolean(0),
+ 'head_view_href' : None,
+ 'head_download_href': None,
+ 'head_download_text_href': None,
+ 'head_annotate_href': None,
'tag_prefer_markup' : ezt.boolean(0),
'tag_view_href' : None,
'tag_download_href': None,
@@ -2214,10 +2265,6 @@
lastrev = pathrev_form(request, data)
- if cfg.options.use_pagesize:
- data['log_paging_action'], data['log_paging_hidden_values'] = \
- request.get_form(params={'log_pagestart': None})
-
data['diff_select_action'], data['diff_select_hidden_values'] = \
request.get_form(view_func=view_diff,
params={'r1': None, 'r2': None, 'tr1': None,
@@ -2230,20 +2277,19 @@
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,
- request.mime_type, None)
+ = get_file_view_info(request, request.where, None, mime_type, None)
data.update({
- 'view_href': view_href,
- 'download_href': download_href,
- 'download_text_href': download_text_href,
- 'annotate_href': annotate_href,
- 'prefer_markup': prefer_markup,
+ '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,
})
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, request.mime_type)
+ = get_file_view_info(request, request.where, None, mime_type)
data.update({
'tag_view_href': view_href,
'tag_download_href': download_href,
@@ -2252,8 +2298,8 @@
'tag_prefer_markup': prefer_markup,
})
else:
- data['view_href'] = request.get_url(view_func=view_directory,
- params={}, escape=1)
+ data['head_view_href'] = request.get_url(view_func=view_directory,
+ params={}, escape=1)
taginfo = options.get('cvs_tags', {})
tagitems = taginfo.items()
@@ -2282,9 +2328,11 @@
plain_tags.append(tag)
if cfg.options.use_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(data, 'entries', data['log_pagestart'],
- 'rev', cfg.options.use_pagesize)
+ data['entries'] = paging_sws(data, 'entries', data['log_pagestart'],
+ 'rev', cfg.options.use_pagesize, first)
generate_page(request, "log", data)
@@ -2301,96 +2349,13 @@
# The revision number acts as a strong validator.
if not check_freshness(request, None, revision):
- request.server.header(request.query_dict.get('content-type')
- or request.mime_type or 'text/plain')
- copy_stream(fp, request.server.file(), cfg)
+ mime_type = request.query_dict.get('content-type') \
+ or calculate_mime_type(request, path, rev) \
+ or 'text/plain'
+ server_fp = get_writeready_server_file(request, mime_type)
+ copy_stream(fp, server_fp, cfg)
fp.close()
-def view_annotate(request):
- if 'annotate' not in request.cfg.options.allowed_views:
- raise debug.ViewVCException('Annotation view is disabled',
- '403 Forbidden')
-
- cfg = request.cfg
- path, rev = _orig_path(request, 'annotate')
-
- ### be nice to hook this into the template...
- import blame
-
- diff_url = request.get_url(view_func=view_diff,
- params={'r1': None, 'r2': None},
- escape=1, partial=1)
-
- include_url = request.get_url(view_func=view_log, where='/WHERE/',
- pathtype=vclib.FILE, params={}, escape=1)
-
- try:
- source, revision = blame.blame(request.repos, path,
- diff_url, include_url, rev)
- except vclib.NonTextualFileContents:
- raise debug.ViewVCException('Unable to perform line-based annotation on '
- 'non-textual file contents',
- '400 Bad Request')
-
- data = common_template_data(request)
- data.update({
- 'mime_type' : request.mime_type,
- 'log' : None,
- 'date' : None,
- 'ago' : None,
- 'author' : None,
- 'branches' : None,
- 'tags' : None,
- 'branch_points' : None,
- 'changed' : None,
- 'size' : None,
- 'state' : None,
- 'vendor_branch' : None,
- 'prev' : None,
- 'lines': source,
- 'orig_path': None,
- 'orig_href': None,
- })
-
- if cfg.options.show_log_in_markup:
- options = {'svn_latest_log': 1}
- revs = request.repos.itemlog(path, revision, 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,
- })
-
- if entry.date is not None:
- data['ago'] = html_time(request, entry.date, 1)
-
- 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), ', ')
- })
-
- if path != request.path_parts:
- orig_path = _path_join(path)
- data['orig_path'] = orig_path
- data['orig_href'] = request.get_url(view_func=view_log,
- where=orig_path,
- pathtype=vclib.FILE,
- params={'pathrev': revision},
- escape=1)
-
- generate_page(request, "annotate", data)
-
def view_cvsgraph_image(request):
"output the image rendered by cvsgraph"
# this function is derived from cgi/cvsgraphmkimg.cgi
@@ -2403,14 +2368,14 @@
# If cvsgraph can't find its supporting libraries, uncomment and set
# accordingly. Do the same in view_cvsgraph().
#os.environ['LD_LIBRARY_PATH'] = '/usr/lib:/usr/local/lib:/path/to/cvsgraph'
-
- request.server.header('image/png')
+
rcsfile = request.repos.rcsfile(request.path_parts)
fp = popen.popen(cfg.utilities.cvsgraph or 'cvsgraph',
("-c", cfg.path(cfg.options.cvsgraph_conf),
"-r", request.repos.rootpath,
rcsfile), 'rb', 0)
- copy_stream(fp, request.server.file(), cfg)
+
+ copy_stream(fp, get_writeready_server_file(request, 'image/png'), cfg)
fp.close()
def view_cvsgraph(request):
@@ -2428,8 +2393,8 @@
#os.environ['LD_LIBRARY_PATH'] = '/usr/lib:/usr/local/lib:/path/to/cvsgraph'
imagesrc = request.get_url(view_func=view_cvsgraph_image, escape=1)
-
- view = default_view(request.mime_type, cfg)
+ mime_type = guess_mime(request.where)
+ view = default_view(mime_type, cfg)
up_where = _path_join(request.path_parts[:-1])
# Create an image map
@@ -2461,58 +2426,23 @@
generate_page(request, "graph", data)
-def search_files(repos, path_parts, rev, files, search_re):
- """ Search files in a directory for a regular expression.
-
- Does a check-out of each file in the directory. Only checks for
- the first match.
- """
-
- # Pass in search regular expression. We check out
- # each file and look for the regular expression. We then return the data
- # for all files that match the regex.
-
- # Compile to make sure we do this as fast as possible.
- searchstr = re.compile(search_re)
-
- # Will become list of files that have at least one match.
- # new_file_list also includes directories.
- new_file_list = [ ]
-
- # Loop on every file (and directory)
- for file in files:
- # Is this a directory? If so, append name to new_file_list
- # and move to next file.
- if file.kind != vclib.FILE:
- new_file_list.append(file)
- continue
-
- # Only files at this point
-
- # Shouldn't search binary files, or should we?
- # Should allow all text mime types to pass.
- if not is_text(guess_mime(file.name)):
- continue
-
- # Only text files at this point
-
- # Assign contents of checked out file to fp.
- fp = repos.openfile(path_parts + [file.name], rev)[0]
-
- # Read in each line, use re.search to search line.
- # If successful, add file to new_file_list and break.
- while 1:
- line = fp.readline()
- if not line:
- break
- if searchstr.search(line):
- new_file_list.append(file)
- # close down the pipe (and wait for the child to terminate)
- fp.close()
- break
-
- return new_file_list
-
+def search_file(repos, path_parts, rev, search_re):
+ """Return 1 iff the contents of the file at PATH_PARTS in REPOS as
+ of revision REV matches regular expression SEARCH_RE."""
+
+ # Read in each line of a checked-out file, and then use re.search to
+ # search line.
+ fp = repos.openfile(path_parts, rev)[0]
+ matches = 0
+ while 1:
+ line = fp.readline()
+ if not line:
+ break
+ if search_re.search(line):
+ matches = 1
+ fp.close()
+ break
+ return matches
def view_doc(request):
"""Serve ViewVC static content locally.
@@ -2546,16 +2476,16 @@
request.server.addheader('Content-Length', content_length)
if document[-3:] == 'png':
- request.server.header('image/png')
+ mime_type = 'image/png'
elif document[-3:] == 'jpg':
- request.server.header('image/jpeg')
+ mime_type = 'image/jpeg'
elif document[-3:] == 'gif':
- request.server.header('image/gif')
+ mime_type = 'image/gif'
elif document[-3:] == 'css':
- request.server.header('text/css')
+ mime_type = 'text/css'
else: # assume HTML:
- request.server.header()
- copy_stream(fp, request.server.file(), cfg)
+ mime_type = None
+ copy_stream(fp, get_writeready_server_file(request, mime_type), cfg)
fp.close()
def rcsdiff_date_reformat(date_str, cfg):
@@ -2791,33 +2721,21 @@
def _get_diff_path_parts(request, query_key, rev, base_rev):
+ repos = request.repos
if request.query_dict.has_key(query_key):
- path = request.query_dict[query_key]
- parts = _path_parts(path)
- if not request.auth.check_path_access(parts):
- raise debug.ViewVCNotAuthorizedException(self.username,
- 'file "%s"' % (path))
+ parts = _path_parts(request.query_dict[query_key])
elif request.roottype == 'svn':
try:
- repos = request.repos
- path = vclib.svn.get_location(repos, request.where,
- repos._getrev(base_rev),
- repos._getrev(rev))
- parts = _path_parts(path)
- if not request.auth.check_path_access(parts):
- raise debug.ViewVCNotAuthorizedException(self.username,
- 'file "%s"' % (path))
+ parts = _path_parts(repos.get_location(request.where,
+ repos._getrev(base_rev),
+ repos._getrev(rev)))
except vclib.InvalidRevision:
raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
'to diff', '400 Bad Request')
except vclib.ItemNotFound:
raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
'to diff', '400 Bad Request')
- if not request.auth.check_path_access(parts):
- raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
- 'to diff', '400 Bad Request')
else:
- # NOTE: authorization already checked in run_viewvc()
parts = request.path_parts
return parts
@@ -2906,9 +2824,9 @@
date1, date2, flag, headers = diff_parse_headers(fp, diff_type, rev1, rev2,
sym1, sym2)
- request.server.header('text/plain')
- request.server.file().write(headers)
- copy_stream(fp, request.server.file(), cfg)
+ server_fp = get_writeready_server_file(request, 'text/plain')
+ server_fp.write(headers)
+ copy_stream(fp, server_fp, cfg)
fp.close()
@@ -2983,7 +2901,8 @@
path_left = _path_join(p1)
path_right = _path_join(p2)
if fp:
- date1, date2, flag, headers = diff_parse_headers(fp, diff_type, rev1, rev2,
+ date1, date2, flag, headers = diff_parse_headers(fp, diff_type,
+ rev1, rev2,
sym1, sym2)
else:
date1 = date2 = flag = headers = None
@@ -3058,7 +2977,8 @@
# generate a GNU tar extension header for long names.
if len(name) >= 100:
- generate_tarball_header(out, '././@LongLink', len(name), 0644, 0, 0, 0, 'L')
+ generate_tarball_header(out, '././@LongLink', len(name),
+ 0644, 0, 0, 0, 'L')
out.write(name)
out.write('\0' * (511 - ((len(name) + 511) % 512)))
@@ -3121,7 +3041,7 @@
for file in entries:
if cvs and (file.kind != vclib.FILE or file.rev is None or file.dead):
continue
- if file.date > dir_mtime:
+ if (file.date is not None) and (file.date > dir_mtime):
dir_mtime = file.date
# Push current directory onto the stack.
@@ -3140,8 +3060,6 @@
continue
if cvs and (file.rev is None or file.dead):
continue
- if not request.auth.check_path_access(rep_path + [file.name]):
- continue
# If we get here, we've seen at least one valid file in the
# current directory. For CVS, we need to make sure there are
@@ -3151,9 +3069,11 @@
generate_tarball_header(out, dir, mtime=dir_mtime)
del stack[:]
- if cvs:
- info = os.stat(file.path)
- mode = (info[stat.ST_MODE] & 0555) | 0200
+ # Calculate the mode for the file. Sure, we could look directly
+ # at the ,v file in CVS, but that's a layering violation we'd like
+ # to avoid as much as possible.
+ if request.repos.isexecutable(rep_path + [file.name], request.pathrev):
+ mode = 0755
else:
mode = 0644
@@ -3164,7 +3084,8 @@
fp.close()
generate_tarball_header(out, tar_dir + file.name,
- len(contents), mode, file.date)
+ len(contents), mode,
+ file.date is not None and file.date or 0)
out.write(contents)
out.write('\0' * (511 - ((len(contents) + 511) % 512)))
@@ -3173,12 +3094,8 @@
for file in entries:
if file.errors or file.kind != vclib.DIR:
continue
- if (not rep_path) \
- and cvs \
- and request.cfg.options.hide_cvsroot \
- and file.name == 'CVSROOT':
- continue
- if not request.auth.check_path_access(rep_path + [file.name]):
+ if request.cfg.options.hide_cvsroot \
+ and is_cvsroot_path(request.roottype, rep_path + [file.name]):
continue
mtime = request.roottype == 'svn' and file.date or None
@@ -3196,11 +3113,19 @@
if debug.TARFILE_PATH:
fp = open(debug.TARFILE_PATH, 'w')
- else:
- request.server.header('application/octet-stream')
+ else:
+ tarfile = request.rootname
+ if request.path_parts:
+ tarfile = "%s-%s" % (tarfile, request.path_parts[-1])
+ request.server.addheader('Content-Disposition',
+ 'attachment; filename="%s.tar.gz"' % (tarfile))
+ server_fp = get_writeready_server_file(request, 'application/x-gzip')
request.server.flush()
- fp = popen.pipe_cmds([(cfg.utilities.gzip or 'gzip', '-c', '-n')])
-
+
+ # Try to use the Python gzip module, if available; otherwise,
+ # we'll use the configured 'gzip' binary.
+ fp = gzip.GzipFile('', 'wb', 9, server_fp)
+
### FIXME: For Subversion repositories, we can get the real mtime of the
### top-level directory here.
generate_tarball(fp, request, [], [])
@@ -3230,20 +3155,17 @@
rev = request.repos._getrev(query_dict.get('revision'))
except vclib.InvalidRevision:
raise debug.ViewVCException('Invalid revision', '404 Not Found')
-
- # The revision number acts as a weak validator.
- if check_freshness(request, None, str(rev), weak=1):
+ youngest_rev = request.repos.get_youngest_revision()
+
+ # The revision number acts as a weak validator (but we tell browsers
+ # not to cache the youngest revision).
+ if rev != youngest_rev and check_freshness(request, None, str(rev), weak=1):
return
# Fetch the revision information.
date, author, msg, changes = request.repos.revinfo(rev)
date_str = make_time_string(date, cfg)
- # Filter the changes list based on what the user is permitted to see.
- def _auth_filter(item):
- return request.auth.check_path_access(item.path_parts)
- changes = filter(_auth_filter, changes)
-
# Sort the changes list by path.
def changes_sort_by_path(a, b):
return cmp(a.path_parts, b.path_parts)
@@ -3272,13 +3194,6 @@
for change in changes:
change.view_href = change.diff_href = change.type = change.log_href = None
- # If this path was copied, and the user is permitted to see this
- # path but not the path from which it was copied, then lie about
- # this *not* being a copy.
- if change.copied \
- and not request.auth.check_path_access(change.base_path_parts):
- change.copied = 0
-
# If the path is newly added, don't claim text or property
# modifications.
if (change.action == vclib.ADDED or change.action == vclib.REPLACED) \
@@ -3286,7 +3201,7 @@
change.text_changed = 0
change.props_changed = 0
- # Calculate the various view link URLs (for which we must have a pathtype).
+ # Calculate the view link URLs (for which we must have a pathtype).
if change.pathtype:
view_func = None
if change.pathtype is vclib.FILE \
@@ -3350,7 +3265,7 @@
pathtype=None,
params={'revision': str(rev - 1)},
escape=1)
- if rev < request.repos.youngest:
+ if rev < request.repos.get_youngest_revision():
next_rev_href = request.get_url(view_func=view_revision,
where=None,
pathtype=None,
@@ -3378,6 +3293,8 @@
data['jump_rev_action'], data['jump_rev_hidden_values'] = \
request.get_form(params={'revision': None})
+ if rev == youngest_rev:
+ request.server.addheader("Cache-control", "no-store")
generate_page(request, "revision", data)
def is_query_supported(request):
@@ -3386,6 +3303,22 @@
and request.pathtype == vclib.DIR \
and request.roottype in ['cvs', 'svn']
+def is_querydb_nonempty_for_root(request):
+ """Return 1 iff commits database integration is supported *and* the
+ current root is found in that database. Only does this check if
+ check_database is set to 1."""
+ if request.cfg.cvsdb.enabled and request.roottype in ['cvs', 'svn']:
+ if request.cfg.cvsdb.check_database_for_root:
+ global cvsdb
+ import cvsdb
+ db = cvsdb.ConnectDatabaseReadOnly(request.cfg)
+ repos_root, repos_dir = cvsdb.FindRepository(db, request.rootpath)
+ if repos_root:
+ return 1
+ else:
+ return 1
+ return 0
+
def view_queryform(request):
if not is_query_supported(request):
raise debug.ViewVCException('Can not query project root "%s" at "%s".'
@@ -3420,9 +3353,11 @@
generate_page(request, "query_form", data)
-def parse_date(s):
- '''Parse a date string from the query form.'''
- match = re.match(r'^(\d\d\d\d)-(\d\d)-(\d\d)(?:\ +(\d\d):(\d\d)(?::(\d\d))?)?$', s)
+def parse_date(datestr):
+ """Parse a date string from the query form."""
+
+ match = re.match(r'^(\d\d\d\d)-(\d\d)-(\d\d)(?:\ +'
+ '(\d\d):(\d\d)(?::(\d\d))?)?$', datestr)
if match:
year = int(match.group(1))
month = int(match.group(2))
@@ -3505,7 +3440,7 @@
return string.join(ret, '')
def prev_rev(rev):
- '''Returns a string representing the previous revision of the argument.'''
+ """Returns a string representing the previous revision of the argument."""
r = string.split(rev, '.')
# decrement final revision component
r[-1] = str(int(r[-1]) - 1)
@@ -3514,67 +3449,94 @@
r = r[:-2]
return string.join(r, '.')
-def build_commit(request, files, limited_files, dir_strip):
+def build_commit(request, files, max_files, dir_strip, format):
+ """Return a commit object build from the information in FILES, or
+ None if no allowed files are present in the set. DIR_STRIP is the
+ path prefix to remove from the commit object's set of files. If
+ MAX_FILES is non-zero, it is used to limit the number of files
+ returned in the commit object. FORMAT is the requested output
+ format of the query request."""
+
cfg = request.cfg
- commit = _item(num_files=len(files), files=[])
- commit.limited_files = ezt.boolean(limited_files)
+ author = files[0].GetAuthor()
+ date = files[0].GetTime()
desc = files[0].GetDescription()
- commit.log = htmlify(desc, cfg.options.mangle_email_addresses)
- commit.short_log = format_log(desc, cfg)
- commit.author = request.server.escape(files[0].GetAuthor())
- commit.rss_date = make_rss_time_string(files[0].GetTime(), cfg)
- if request.roottype == 'svn':
- commit.rev = files[0].GetRevision()
- commit.rss_url = request.get_url(view_func=view_revision,
- params={'revision': commit.rev},
- escape=1,
- prefix=1)
- else:
- commit.rev = None
- commit.rss_url = None
-
+ commit_rev = files[0].GetRevision()
len_strip = len(dir_strip)
-
+ commit_files = []
+ num_allowed = 0
+ plus_count = 0
+ minus_count = 0
+ found_unreadable = 0
+
for f in files:
- commit_time = f.GetTime()
- if commit_time:
- commit_time = make_time_string(commit_time, cfg)
- change_type = f.GetTypeString()
- rev = f.GetRevision()
- rev_prev = prev_rev(rev)
-
dirname = f.GetDirectory()
filename = f.GetFile()
if dir_strip:
assert dirname[:len_strip] == dir_strip
assert len(dirname) == len_strip or dirname[len(dir_strip)] == '/'
dirname = dirname[len_strip+1:]
- filename = dirname and ("%s/%s" % (dirname, filename)) or filename
+ where = dirname and ("%s/%s" % (dirname, filename)) or filename
+ rev = f.GetRevision()
+ rev_prev = prev_rev(rev)
+ commit_time = f.GetTime()
+ if commit_time:
+ commit_time = make_time_string(commit_time, cfg)
+ change_type = f.GetTypeString()
# In CVS, we can actually look at deleted revisions; in Subversion
# we can't -- we'll look at the previous revision instead.
+ exam_rev = rev
+ if request.roottype == 'svn' and change_type == 'Remove':
+ exam_rev = rev_prev
+
+ # Check path access (since the commits database logic bypasses the
+ # vclib layer and, thus, the vcauth stuff that layer uses).
+ path_parts = _path_parts(where)
+ if path_parts:
+ # Skip files in CVSROOT if asked to hide such.
+ if cfg.options.hide_cvsroot \
+ and is_cvsroot_path(request.roottype, path_parts):
+ found_unreadable = 1
+ continue
+
+ # We have to do a rare authz check here because this data comes
+ # from the CVSdb, not from the vclib providers.
+ #
+ # WARNING: The Subversion CVSdb integration logic is weak, weak,
+ # weak. It has no ability to track copies, so complex
+ # situations like a copied directory with a deleted subfile (all
+ # in the same revision) are very ... difficult. We've no choice
+ # but to omit as unauthorized paths the authorization logic
+ # can't find.
+ try:
+ readable = vclib.check_path_access(request.repos, path_parts,
+ None, exam_rev)
+ except vclib.ItemNotFound:
+ readable = 0
+ if not readable:
+ found_unreadable = 1
+ continue
+
if request.roottype == 'svn':
- if change_type == 'Remove':
- params = { 'pathrev': rev_prev }
- else:
- params = { 'pathrev': rev }
+ params = { 'pathrev': exam_rev }
else:
- params = { 'revision': rev, 'pathrev': f.GetBranch() or None }
-
+ params = { 'revision': exam_rev, 'pathrev': f.GetBranch() or None }
+
dir_href = request.get_url(view_func=view_directory,
where=dirname, pathtype=vclib.DIR,
params=params, escape=1)
log_href = request.get_url(view_func=view_log,
- where=filename, pathtype=vclib.FILE,
+ where=where, pathtype=vclib.FILE,
params=params, escape=1)
diff_href = view_href = download_href = None
if 'markup' in cfg.options.allowed_views:
view_href = request.get_url(view_func=view_markup,
- where=filename, pathtype=vclib.FILE,
+ where=where, pathtype=vclib.FILE,
params=params, escape=1)
if 'co' in cfg.options.allowed_views:
download_href = request.get_url(view_func=view_checkout,
- where=filename, pathtype=vclib.FILE,
+ where=where, pathtype=vclib.FILE,
params=params, escape=1)
if change_type == 'Change':
diff_href_params = params.copy()
@@ -3584,27 +3546,29 @@
'diff_format': None
})
diff_href = request.get_url(view_func=view_diff,
- where=filename, pathtype=vclib.FILE,
+ where=where, pathtype=vclib.FILE,
params=diff_href_params, escape=1)
- prefer_markup = ezt.boolean(default_view(guess_mime(filename),
- cfg) == view_markup)
+ mime_type = calculate_mime_type(request, path_parts, exam_rev)
+ prefer_markup = ezt.boolean(default_view(mime_type, cfg) == view_markup)
- # skip files in forbidden or hidden modules
- dir_parts = filter(None, string.split(dirname, '/'))
- if dir_parts \
- and ((dir_parts[0] == 'CVSROOT'
- and cfg.options.hide_cvsroot) \
- or not request.auth.check_path_access(dir_parts)):
+ # Update plus/minus line change count.
+ plus = int(f.GetPlusCount())
+ minus = int(f.GetMinusCount())
+ plus_count = plus_count + plus
+ minus_count = minus_count + minus
+
+ num_allowed = num_allowed + 1
+ if max_files and num_allowed > max_files:
continue
- commit.files.append(_item(date=commit_time,
+ commit_files.append(_item(date=commit_time,
dir=request.server.escape(dirname),
- file=request.server.escape(f.GetFile()),
+ file=request.server.escape(filename),
author=request.server.escape(f.GetAuthor()),
rev=rev,
branch=f.GetBranch(),
- plus=int(f.GetPlusCount()),
- minus=int(f.GetMinusCount()),
+ plus=plus,
+ minus=minus,
type=change_type,
dir_href=dir_href,
log_href=log_href,
@@ -3612,6 +3576,42 @@
download_href=download_href,
prefer_markup=prefer_markup,
diff_href=diff_href))
+
+ # No files survived authz checks? Let's just pretend this
+ # little commit didn't happen, shall we?
+ if not len(commit_files):
+ return None
+
+ commit = _item(num_files=len(commit_files), files=commit_files,
+ plus=plus_count, minus=minus_count)
+ commit.limited_files = ezt.boolean(num_allowed > len(commit_files))
+
+ # We'll mask log messages in commits which contain unreadable paths,
+ # but even that is kinda iffy. If a person searches for
+ # '/some/hidden/path' across log messages, then gets a response set
+ # that shows commits lacking log message, said person can reasonably
+ # assume that the log messages contained the hidden path, and that
+ # this is likely because they are referencing a real path in the
+ # repository -- a path the user isn't supposed to even know about.
+ if found_unreadable:
+ commit.log = None
+ commit.short_log = None
+ else:
+ commit.log = htmlify(desc)
+ commit.short_log = format_log(desc, cfg, format != 'rss')
+ commit.author = request.server.escape(author)
+ commit.rss_date = make_rss_time_string(date, request.cfg)
+ if request.roottype == 'svn':
+ commit.rev = commit_rev
+ commit.rss_url = '%s://%s%s' % \
+ (request.server.getenv("HTTPS") == "on" and "https" or "http",
+ request.server.getenv("HTTP_HOST"),
+ request.get_url(view_func=view_revision,
+ params={'revision': commit.rev},
+ escape=1))
+ else:
+ commit.rev = None
+ commit.rss_url = None
return commit
def query_backout(request, commits):
@@ -3752,47 +3752,49 @@
current_desc = query.commit_list[0].GetDescriptionID()
current_rev = query.commit_list[0].GetRevision()
dir_strip = _path_join(repos_dir)
+
for commit in query.commit_list:
- # base modification time on the newest commit ...
+ commit_desc = commit.GetDescriptionID()
+ commit_rev = commit.GetRevision()
+
+ # base modification time on the newest commit
if commit.GetTime() > mod_time:
mod_time = commit.GetTime()
- # form plus/minus totals
- plus_count = plus_count + int(commit.GetPlusCount())
- minus_count = minus_count + int(commit.GetMinusCount())
- # group commits with the same commit message ...
- desc = commit.GetDescriptionID()
+
# For CVS, group commits with the same commit message.
# For Subversion, group them only if they have the same revision number
if request.roottype == 'cvs':
- if current_desc == desc:
- if not limit_changes or len(files) < limit_changes:
- files.append(commit)
- else:
- limited_files = 1
+ if current_desc == commit_desc:
+ files.append(commit)
continue
else:
- if current_rev == commit.GetRevision():
- if not limit_changes or len(files) < limit_changes:
- files.append(commit)
- else:
- limited_files = 1
+ if current_rev == commit_rev:
+ files.append(commit)
continue
- # if our current group has any allowed files, append a commit
- # with those files.
- if len(files):
- commits.append(build_commit(request, files, limited_files, dir_strip))
+ # append this grouping
+ commit_item = build_commit(request, files, limit_changes,
+ dir_strip, format)
+ if commit_item:
+ # update running plus/minus totals
+ plus_count = plus_count + commit_item.plus
+ minus_count = minus_count + commit_item.minus
+ commits.append(commit_item)
files = [ commit ]
limited_files = 0
- current_desc = desc
- current_rev = commit.GetRevision()
+ current_desc = commit_desc
+ current_rev = commit_rev
- # we need to tack on our last commit grouping, but, again, only if
- # it has allowed files.
- if len(files):
- commits.append(build_commit(request, files, limited_files, dir_strip))
-
+ # we need to tack on our last commit grouping, if any
+ commit_item = build_commit(request, files, limit_changes,
+ dir_strip, format)
+ if commit_item:
+ # update running plus/minus totals
+ plus_count = plus_count + commit_item.plus
+ minus_count = minus_count + commit_item.minus
+ commits.append(commit_item)
+
# only show the branch column if we are querying all branches
# or doing a non-exact branch match on a CVS repository.
show_branch = ezt.boolean(request.roottype == 'cvs' and
@@ -3865,13 +3867,100 @@
for code, view in _views.items():
_view_codes[view] = code
-def list_roots(cfg):
+def list_roots(request):
+ cfg = request.cfg
allroots = { }
+
+ # Add the viewable Subversion roots
for root in cfg.general.svn_roots.keys():
+ auth = setup_authorizer(cfg, request.username, root)
+ try:
+ vclib.svn.SubversionRepository(root, cfg.general.svn_roots[root], auth,
+ cfg.utilities, cfg.options.svn_config_dir)
+ except vclib.ReposNotFound:
+ continue
allroots[root] = [cfg.general.svn_roots[root], 'svn']
+
+ # Add the viewable CVS roots
for root in cfg.general.cvs_roots.keys():
+ auth = setup_authorizer(cfg, request.username, root)
+ try:
+ vclib.ccvs.CVSRepository(root, cfg.general.cvs_roots[root], auth,
+ cfg.utilities, cfg.options.use_rcsparse)
+ except vclib.ReposNotFound:
+ continue
allroots[root] = [cfg.general.cvs_roots[root], 'cvs']
+
return allroots
+
+def expand_root_parents(cfg):
+ """Expand the configured root parents into individual roots."""
+
+ # Each item in root_parents is a "directory : repo_type" string.
+ for pp in cfg.general.root_parents:
+ pos = string.rfind(pp, ':')
+ if pos < 0:
+ raise debug.ViewVCException(
+ "The path '%s' in 'root_parents' does not include a "
+ "repository type." % (pp))
+
+ repo_type = string.strip(pp[pos+1:])
+ pp = os.path.normpath(string.strip(pp[:pos]))
+
+ if repo_type == 'cvs':
+ roots = vclib.ccvs.expand_root_parent(pp)
+ if cfg.options.hide_cvsroot and roots.has_key('CVSROOT'):
+ del roots['CVSROOT']
+ cfg.general.cvs_roots.update(roots)
+ elif repo_type == 'svn':
+ roots = vclib.svn.expand_root_parent(pp)
+ cfg.general.svn_roots.update(roots)
+ else:
+ raise debug.ViewVCException(
+ "The path '%s' in 'root_parents' has an unrecognized "
+ "repository type." % (pp))
+
+def find_root_in_parents(cfg, rootname, roottype):
+ """Return the rootpath for configured ROOTNAME of ROOTTYPE."""
+
+ # Easy out: caller wants rootname "CVSROOT", and we're hiding those.
+ if rootname == 'CVSROOT' and cfg.options.hide_cvsroot:
+ return None
+
+ for pp in cfg.general.root_parents:
+ pos = string.rfind(pp, ':')
+ if pos < 0:
+ continue
+ repo_type = string.strip(pp[pos+1:])
+ if repo_type != roottype:
+ continue
+ pp = os.path.normpath(string.strip(pp[:pos]))
+
+ if roottype == 'cvs':
+ roots = vclib.ccvs.expand_root_parent(pp)
+ elif roottype == 'svn':
+ roots = vclib.svn.expand_root_parent(pp)
+ else:
+ roots = {}
+ if roots.has_key(rootname):
+ return roots[rootname]
+ return None
+
+def locate_root(cfg, rootname):
+ """Return a 2-tuple ROOTTYPE, ROOTPATH for configured ROOTNAME."""
+ if cfg.general.cvs_roots.has_key(rootname):
+ return 'cvs', cfg.general.cvs_roots[rootname]
+ path_in_parent = find_root_in_parents(cfg, rootname, 'cvs')
+ if path_in_parent:
+ cfg.general.cvs_roots[rootname] = path_in_parent
+ return 'cvs', path_in_parent
+ if cfg.general.svn_roots.has_key(rootname):
+ return 'svn', cfg.general.svn_roots[rootname]
+ path_in_parent = find_root_in_parents(cfg, rootname, 'svn')
+ if path_in_parent:
+ cfg.general.svn_roots[rootname] = path_in_parent
+ return 'svn', path_in_parent
+ return None, None
def load_config(pathname=None, server=None):
debug.t_start('load-config')
@@ -3889,50 +3978,8 @@
# load mime types file
if cfg.general.mime_types_file:
mimetypes.init([cfg.general.mime_types_file])
-
- # special handling for root_parents. Each item in root_parents is
- # a "directory : repo_type" string. For each item in
- # root_parents, we get a list of the subdirectories.
- #
- # If repo_type is "cvs", and the subdirectory contains a child
- # "CVSROOT/config", then it is added to cvs_roots. Or, if the
- # root directory itself contains a child "CVSROOT/config" file,
- # then all its subdirectories are added to cvs_roots.
- #
- # If repo_type is "svn", and the subdirectory contains a child
- # "format", then it is added to svn_roots.
- for pp in cfg.general.root_parents:
- pos = string.rfind(pp, ':')
- if pos < 0:
- raise debug.ViewVCException(
- "The path '%s' in 'root_parents' does not include a "
- "repository type." % pp)
-
- repo_type = string.strip(pp[pos+1:])
- pp = os.path.normpath(string.strip(pp[:pos]))
-
- try:
- subpaths = os.listdir(pp)
- except OSError:
- raise debug.ViewVCException(
- "The path '%s' in 'root_parents' does not refer to "
- "a valid directory." % pp)
-
- cvsroot = os.path.exists(os.path.join(pp, "CVSROOT", "config"))
-
- for subpath in subpaths:
- if os.path.exists(os.path.join(pp, subpath)):
- if (repo_type == 'cvs'
- and (os.path.exists(os.path.join(pp, subpath, "CVSROOT", "config"))
- or (cvsroot and (subpath != 'CVSROOT'
- or not cfg.options.hide_cvsroot)))):
- cfg.general.cvs_roots[subpath] = os.path.join(pp, subpath)
- elif repo_type == 'svn' and \
- os.path.exists(os.path.join(pp, subpath, "format")):
- cfg.general.svn_roots[subpath] = os.path.join(pp, subpath)
-
+
debug.t_end('load-config')
-
return cfg
Modified: trunk/notes/releases.txt
==============================================================================
--- trunk/notes/releases.txt (original)
+++ trunk/notes/releases.txt Mon Nov 3 09:57:02 2008
@@ -65,12 +65,14 @@
archive files into the root directory of the viewvc.org website
(unversioned).
-12. Update the websites (both the viewvc.org/ and www/ ones) to refer
- to the new release files.
+12. On trunk, update the websites (both the viewvc.org/ and www/ ones)
+ to refer to the new release files, and copy the CHANGES for the
+ new release into trunk's CHANGES file.
13. Edit the file 'lib/viewvc.py' again, re-adding the "-dev" suffix
and incrementing the patch number assigned to the __version__
- variable, and commit:
+ variable, and add a new empty block in the branch's CHANGES file,
+ and commit:
svn ci -m "Begin a new release cycle."
Modified: trunk/scripts/last-merge-tag
==============================================================================
--- trunk/scripts/last-merge-tag (original)
+++ trunk/scripts/last-merge-tag Mon Nov 3 09:57:02 2008
@@ -1 +1 @@
-viewcvs-2007-11-25
+viewcvs-2008-11-03
Modified: trunk/templates-contrib/tabbed/templates/annotate.ezt
==============================================================================
--- trunk/templates-contrib/tabbed/templates/annotate.ezt (original)
+++ trunk/templates-contrib/tabbed/templates/annotate.ezt Mon Nov 3 09:57:02 2008
@@ -3,19 +3,7 @@
[define help_href][docroot]/help_rootview.html[end]
[# end]
[include "include/header.ezt" "annotate"]
-
-<table class="auto">
-<tr>
-<td>Revision:</td>
-<td><strong>[if-any revision_href]<a href="[revision_href]">[rev]</a>[else][rev][end]</strong></td>
-</tr>
-[if-any orig_path]
-<tr>
-<td>Original Path:</td>
-<td><strong><a href="[orig_href]"><em>[orig_path]</em></a></strong></td>
-</tr>
-[end]
-</table>
+[include "include/fileview.ezt"]
<div id="vc_main_body">
<!-- ************************************************************** -->
@@ -50,6 +38,8 @@
[end]
</table>
+[include "include/props.ezt"]
+
<!-- ************************************************************** -->
</div>
Modified: trunk/templates-contrib/tabbed/templates/diff.ezt
==============================================================================
--- trunk/templates-contrib/tabbed/templates/diff.ezt (original)
+++ trunk/templates-contrib/tabbed/templates/diff.ezt Mon Nov 3 09:57:02 2008
@@ -6,7 +6,7 @@
<form method="get" action="[diff_format_action]" style="display: inline;">
<div>
- [diff_format_hidden_values]
+ [for diff_format_hidden_values]<input type="hidden" name="[diff_format_hidden_values.name]" value="[diff_format_hidden_values.value]"/>[end]
<select name="diff_format" onchange="submit()">
<option value="h" [is diff_format "h"]selected="selected"[end]>Colored Diff</option>
<option value="l" [is diff_format "l"]selected="selected"[end]>Long Colored Diff</option>
Modified: trunk/templates-contrib/tabbed/templates/directory.ezt
==============================================================================
--- trunk/templates-contrib/tabbed/templates/directory.ezt (original)
+++ trunk/templates-contrib/tabbed/templates/directory.ezt Mon Nov 3 09:57:02 2008
@@ -128,4 +128,5 @@
</table>
+[include "include/props.ezt"]
[include "include/dir_footer.ezt"]
Modified: trunk/templates-contrib/tabbed/templates/docroot/styles.css
==============================================================================
--- trunk/templates-contrib/tabbed/templates/docroot/styles.css (original)
+++ trunk/templates-contrib/tabbed/templates/docroot/styles.css Mon Nov 3 09:57:02 2008
@@ -19,6 +19,7 @@
border: none;
}
tr, td, th { vertical-align: top; }
+th { white-space: nowrap; }
table.auto {
width: auto;
}
@@ -131,6 +132,15 @@
}
+/*** Properties Listing ***/
+.vc_properties {
+ margin: 1em 0;
+}
+.vc_properties h2 {
+ font-size: 115%;
+}
+
+
/*** Markup Summary Header ***/
.vc_summary {
background-color: #eeeeee;
Modified: trunk/templates-contrib/tabbed/templates/include/diff_form.ezt
==============================================================================
--- trunk/templates-contrib/tabbed/templates/include/diff_form.ezt (original)
+++ trunk/templates-contrib/tabbed/templates/include/diff_form.ezt Mon Nov 3 09:57:02 2008
@@ -17,7 +17,7 @@
<tr>
<td> </td>
<td>
- [diff_select_hidden_values]
+ [for diff_select_hidden_values]<input type="hidden" name="[diff_select_hidden_values.name]" value="[diff_select_hidden_values.value]"/>[end]
Diffs between
[if-any tags]
<select name="r1">
Modified: trunk/templates-contrib/tabbed/templates/include/dir_footer.ezt
==============================================================================
--- trunk/templates-contrib/tabbed/templates/include/dir_footer.ezt (original)
+++ trunk/templates-contrib/tabbed/templates/include/dir_footer.ezt Mon Nov 3 09:57:02 2008
@@ -9,7 +9,7 @@
<td>
<form method="get" action="[search_re_action]">
<div>
- [search_re_hidden_values]
+ [for search_re_hidden_values]<input type="hidden" name="[search_re_hidden_values.name]" value="[search_re_hidden_values.value]"/>[end]
<input type="text" name="search" value="[search_re]" />
<input type="submit" value="Show" />
</div>
@@ -22,7 +22,7 @@
<td>
<form method="get" action="[search_tag_action]">
<div>
- [search_tag_hidden_values]
+ [for search_tag_hidden_values]<input type="hidden" name="[search_tag_hidden_values.name]" value="[search_tag_hidden_values.value]"/>[end]
<input type="submit" value="Show all files" />
</div>
</form>
Modified: trunk/templates-contrib/tabbed/templates/include/dir_header.ezt
==============================================================================
--- trunk/templates-contrib/tabbed/templates/include/dir_header.ezt (original)
+++ trunk/templates-contrib/tabbed/templates/include/dir_header.ezt Mon Nov 3 09:57:02 2008
@@ -40,22 +40,24 @@
<td><a href="[queryform_href]">Query revision history</a></td>
</tr>
[end]
-</table>
- [is cfg.options.use_pagesize "0"]
- [else]
- [is picklist_len "1"]
- [else]
- <form method="get" action="[dir_paging_action]">
- [dir_paging_hidden_values]
- <input type="submit" value="Go to:" />
+
+[is cfg.options.use_pagesize "0"][else][is picklist_len "1"][else]
+<tr>
+ <td>Jump to page:</td>
+ <td><form method="get" action="[dir_paging_action]">
+ [for dir_paging_hidden_values]<input type="hidden" name="[dir_paging_hidden_values.name]" value="[dir_paging_hidden_values.value]"/>[end]
<select name="dir_pagestart" onchange="submit()">
[for picklist]
<option [is picklist.count dir_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] to [picklist.end]</option>
[end]
</select>
+ <input type="submit" value="Go" />
</form>
- [end]
- [end]
+ </td>
+</tr>
+[end][end]
+
+</table>
<div id="vc_main_body">
<!-- ************************************************************** -->
Modified: trunk/templates-contrib/tabbed/templates/include/header.ezt
==============================================================================
--- trunk/templates-contrib/tabbed/templates/include/header.ezt (original)
+++ trunk/templates-contrib/tabbed/templates/include/header.ezt Mon Nov 3 09:57:02 2008
@@ -22,43 +22,10 @@
width="150" height="60" /></a>
</div>
-[if-any roots]
- <form method="get" style="display: inline" action="[change_root_action]">
- [change_root_hidden_values]
- <strong>Repository:</strong>
- <select name="root" onchange="submit()">
- [define cvs_root_options][end]
- [define svn_root_options][end]
- <option value="*viewroots*"[is view "roots"] selected="selected"[else][end]>Repository Listing</option>
- [for roots]
- [define root_option][end]
- [is roots.name rootname]
- [define root_option]<option selected="selected">[roots.name]</option>[end]
- [else]
- [define root_option]<option>[roots.name]</option>[end]
- [end]
- [is roots.type "cvs"]
- [define cvs_root_options][cvs_root_options][root_option][end]
- [else]
- [is roots.type "svn"]
- [define svn_root_options][svn_root_options][root_option][end]
- [end]
- [end]
- [end]
- [is cvs_root_options ""][else]
- <optgroup label="CVS Repositories">[cvs_root_options]</optgroup>
- [end]
- [is svn_root_options ""][else]
- <optgroup label="Subversion Repositories">[svn_root_options]</optgroup>
- [end]
- </select>
- <input type="submit" value="Go" />
- </form>
-[end]
-
<div id="vc_current_path">
<strong>[page_title]</strong>
[if-any nav_path]
+ [if-any roots_href]<a href="[roots_href]">/</a>[else]/[end]
[for nav_path]
[if-any nav_path.href]<a href="[nav_path.href]">[end]
[nav_path.name][if-any nav_path.href]</a>[end]
Modified: trunk/templates-contrib/tabbed/templates/include/log_footer.ezt
==============================================================================
--- trunk/templates-contrib/tabbed/templates/include/log_footer.ezt (original)
+++ trunk/templates-contrib/tabbed/templates/include/log_footer.ezt Mon Nov 3 09:57:02 2008
@@ -1,13 +1,9 @@
<!-- ************************************************************** -->
</div>
-[include "paging.ezt"]
-
[is pathtype "file"]
[include "diff_form.ezt"]
[end]
-[include "sort.ezt"]
-
[include "footer.ezt"]
Modified: trunk/templates-contrib/tabbed/templates/include/log_header.ezt
==============================================================================
--- trunk/templates-contrib/tabbed/templates/include/log_header.ezt (original)
+++ trunk/templates-contrib/tabbed/templates/include/log_header.ezt Mon Nov 3 09:57:02 2008
@@ -45,7 +45,42 @@
<td>[include "pathrev_form.ezt"]</td>
</tr>
-[include "paging.ezt"]
+[is cfg.options.use_pagesize "0"][else][is picklist_len "1"][else]
+<tr>
+ <td>Jump to page:</td>
+ <td><form method="get" action="[log_paging_action]">
+ [for log_paging_hidden_values]<input type="hidden" name="[log_paging_hidden_values.name]" value="[log_paging_hidden_values.value]"/>[end]
+ <select name="log_pagestart" onchange="submit()">
+ [for picklist]
+ [if-any picklist.more]
+ <option [is picklist.count log_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] ...</option>
+ [else]
+ <option [is picklist.count log_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] - [picklist.end]</option>
+ [end]
+ [end]
+ </select>
+ <input type="submit" value="Go" />
+ </form>
+ </td>
+</tr>
+[end][end]
+
+<tr>
+ <td>Sort logs by:</td>
+ <td><form method="get" action="[logsort_action]">
+ <div>
+ <a name="logsort"></a>
+ [for logsort_hidden_values]<input type="hidden" name="[logsort_hidden_values.name]" value="[logsort_hidden_values.value]"/>[end]
+ <select name="logsort" onchange="submit()">
+ <option value="cvs" [is logsort "cvs"]selected="selected"[end]>Not sorted</option>
+ <option value="date" [is logsort "date"]selected="selected"[end]>Commit date</option>
+ <option value="rev" [is logsort "rev"]selected="selected"[end]>Revision</option>
+ </select>
+ <input type="submit" value=" Sort " />
+ </div>
+ </form>
+ </td>
+</tr>
</table>
Modified: trunk/templates-contrib/tabbed/templates/include/pathrev_form.ezt
==============================================================================
--- trunk/templates-contrib/tabbed/templates/include/pathrev_form.ezt (original)
+++ trunk/templates-contrib/tabbed/templates/include/pathrev_form.ezt Mon Nov 3 09:57:02 2008
@@ -1,6 +1,6 @@
<form method="get" action="[pathrev_action]" style="display: inline">
<div style="display: inline">
-[pathrev_hidden_values]
+[for pathrev_hidden_values]<input type="hidden" name="[pathrev_hidden_values.name]" value="[pathrev_hidden_values.value]"/>[end]
[is roottype "cvs"]
[define pathrev_selected][pathrev][end]
<select name="pathrev" onchange="submit()">
@@ -41,7 +41,7 @@
[if-any pathrev]
<form method="get" action="[pathrev_clear_action]" style="display: inline">
<div style="display: inline">
-[pathrev_clear_hidden_values]
+[for pathrev_clear_hidden_values]<input type="hidden" name="[pathrev_clear_hidden_values.name]" value="[pathrev_clear_hidden_values.value]"/>[end]
[if-any lastrev]
[is pathrev lastrev][else]<input type="submit" value="Set to [lastrev]" />[end]
(<i>Current path doesn't exist after revision <strong>[lastrev]</strong></i>)
Modified: trunk/templates-contrib/tabbed/templates/log.ezt
==============================================================================
--- trunk/templates-contrib/tabbed/templates/log.ezt (original)
+++ trunk/templates-contrib/tabbed/templates/log.ezt Mon Nov 3 09:57:02 2008
@@ -91,6 +91,10 @@
[end]
[end]
+ [if-any entries.lockinfo]
+ <br />Lock status: <img src="[docroot]/images/lock.png" alt="Locked" width="16" height="16" /> [entries.lockinfo]
+ [end]
+
[is roottype "svn"]
[if-any entries.size]
<br />File length: [entries.size] byte(s)
Modified: trunk/templates-contrib/tabbed/templates/markup.ezt
==============================================================================
--- trunk/templates-contrib/tabbed/templates/markup.ezt (original)
+++ trunk/templates-contrib/tabbed/templates/markup.ezt Mon Nov 3 09:57:02 2008
@@ -3,71 +3,15 @@
[define help_href][docroot]/help_rootview.html[end]
[# end]
[include "include/header.ezt" "markup"]
-
-<table class="auto">
-<tr>
-<td>Revision:</td>
-<td><strong>[if-any revision_href]<a href="[revision_href]">[rev]</a>[else][rev][end]</strong> [if-any vendor_branch] <em>(vendor branch)</em>[end]</td>
-</tr>
-<tr>
-<tr>
-<td>Committed:</td>
-<td>[if-any date]<em>[date]</em> [end][if-any ago]([ago] ago) [end][if-any author]by <em>[author]</em>[end]</td>
-</tr>
-[if-any orig_path]
-<tr>
-<td>Original Path:</td>
-<td><strong><a href="[orig_href]"><em>[orig_path]</em></a></strong></td>
-</tr>
-[end]
-[if-any branches]
-<tr>
-<td>Branch:</td>
-<td><strong>[branches]</strong></td>
-</tr>
-[end]
-[if-any tags]
-<tr>
-<td>CVS Tags:</td>
-<td><strong>[tags]</strong></td>
-</tr>
-[end]
-[if-any branch_points]
-<tr>
-<td>Branch point for:</td>
-<td><strong>[branch_points]</strong></td>
-</tr>
-[end]
-[is roottype "cvs"][if-any changed]
-<tr>
-<td>Changes since <strong>[prev]</strong>:</td>
-<td><strong>[changed] lines</strong></td>
-</tr>
-[end][end]
-[is roottype "svn"][if-any size]
-<td>File size:</td>
-<td>[size] byte(s)</td>
-</tr>
-[end][end]
-[is state "dead"]
-<tr>
-<td>State:</td>
-<td><strong><em>FILE REMOVED</em></strong></td>
-</tr>
-[end]
-[if-any log]
-<tr>
-<td>Log Message:</td>
-<td><pre class="vc_log">[log]</span></td>
-</tr>
-[end]
-</table>
+[include "include/fileview.ezt"]
<div id="vc_main_body">
<!-- ************************************************************** -->
<div id="vc_markup"><pre>[markup]</pre></div>
+[include "include/props.ezt"]
+
<!-- ************************************************************** -->
</div>
Modified: trunk/templates-contrib/tabbed/templates/query_form.ezt
==============================================================================
--- trunk/templates-contrib/tabbed/templates/query_form.ezt (original)
+++ trunk/templates-contrib/tabbed/templates/query_form.ezt Mon Nov 3 09:57:02 2008
@@ -7,7 +7,7 @@
<form action="[query_action]" method="get">
<div class="vc_query_form">
- [query_hidden_values]
+ [for query_hidden_values]<input type="hidden" name="[query_hidden_values.name]" value="[query_hidden_values.value]"/>[end]
<table cellspacing="0" cellpadding="5" class="auto">
[is roottype "cvs"]
[# For subversion, the branch field is not used ]
Modified: trunk/templates-contrib/tabbed/templates/query_results.ezt
==============================================================================
--- trunk/templates-contrib/tabbed/templates/query_results.ezt (original)
+++ trunk/templates-contrib/tabbed/templates/query_results.ezt Mon Nov 3 09:57:02 2008
@@ -1,5 +1,5 @@
[# setup page definitions]
- [define page_title]Query results on /[where][end]
+ [define page_title]Query results in:[end]
[define help_href][docroot]/help_rootview.html[end]
[# end]
Modified: trunk/templates-contrib/tabbed/templates/revision.ezt
==============================================================================
--- trunk/templates-contrib/tabbed/templates/revision.ezt (original)
+++ trunk/templates-contrib/tabbed/templates/revision.ezt Mon Nov 3 09:57:02 2008
@@ -9,7 +9,7 @@
<tr align="left">
<th>Jump to revision:</th>
<td>
- [jump_rev_hidden_values]
+ [for jump_rev_hidden_values]<input type="hidden" name="[jump_rev_hidden_values.name]" value="[jump_rev_hidden_values.value]"/>[end]
<input type="text" name="revision" value="[rev]" />
<input type="submit" value="Go" />
[if-any prev_href]
Modified: trunk/templates/diff.ezt
==============================================================================
--- trunk/templates/diff.ezt (original)
+++ trunk/templates/diff.ezt Mon Nov 3 09:57:02 2008
@@ -196,7 +196,7 @@
<td>
<form method="get" action="[diff_format_action]">
<div>
- [diff_format_hidden_values]
+ [for diff_format_hidden_values]<input type="hidden" name="[diff_format_hidden_values.name]" value="[diff_format_hidden_values.value]"/>[end]
<select name="diff_format" onchange="submit()">
<option value="h" [is diff_format "h"]selected="selected"[end]>Colored Diff</option>
<option value="l" [is diff_format "l"]selected="selected"[end]>Long Colored Diff</option>
Modified: trunk/templates/dir_new.ezt
==============================================================================
--- trunk/templates/dir_new.ezt (original)
+++ trunk/templates/dir_new.ezt Mon Nov 3 09:57:02 2008
@@ -43,6 +43,7 @@
<a name="[entries.anchor]" href="[is entries.pathtype "dir"][entries.view_href][else][if-any entries.prefer_markup][entries.view_href][else][entries.download_href][end][end]" title="[is entries.pathtype "dir"]View Directory Contents[else][if-any entries.prefer_markup]View[else]Download[end] File Contents[end]">
<img src="[docroot]/images/[is entries.pathtype "dir"]dir[else][is entries.state "dead"]broken[else]text[end][end].png" alt="" class="vc_icon" />
[entries.name][is entries.pathtype "dir"]/[end]</a>
+ [if-any entries.lockinfo]<img src="[docroot]/images/lock.png" alt="locked" class="vc_icon" title="Locked by [entries.lockinfo]" />[end]
[is entries.state "dead"](dead)[end]
</td>
Modified: trunk/templates/directory.ezt
==============================================================================
--- trunk/templates/directory.ezt (original)
+++ trunk/templates/directory.ezt Mon Nov 3 09:57:02 2008
@@ -97,7 +97,9 @@
<td> [if-any entries.rev]<a href="[entries.log_href]" title="View directory revision log"><strong>[entries.rev]</strong></a>[end]</td>
[else]
[define rev_href][if-any entries.prefer_markup][entries.view_href][else][if-any entries.download_href][entries.download_href][end][end][end]
- <td> [if-any entries.rev][if-any rev_href]<a href="[rev_href]" title="[if-any entries.prefer_markup]View[else]Download[end] file contents">[end]<strong>[entries.rev]</strong>[if-any rev_href]</a>[end][end]</td>
+ <td style="white-space: nowrap;"> [if-any entries.rev][if-any rev_href]<a href="[rev_href]" title="[if-any entries.prefer_markup]View[else]Download[end] file contents">[end]<strong>[entries.rev]</strong>[if-any rev_href]</a>[end][end]
+ [if-any entries.lockinfo]<img src="[docroot]/images/lock.png" alt="locked" class="vc_icon" title="Locked by [entries.lockinfo]" />[end]
+ </td>
[end]
<td> [entries.ago]</td>
<td> [entries.author]</td>
Modified: trunk/templates/docroot/help_dirview.html
==============================================================================
--- trunk/templates/docroot/help_dirview.html (original)
+++ trunk/templates/docroot/help_dirview.html Mon Nov 3 09:57:02 2008
@@ -4,31 +4,23 @@
<head>
<title>ViewVC Help: Directory View</title>
<link rel="stylesheet" href="help.css" type="text/css" />
+ <link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon" />
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
+ <div><a href="http://viewvc.org/index.html"><img src="images/viewvc-logo.png" alt="ViewVC logotype" /></a></div>
<table>
<col class="menu" />
<col />
- <tr>
- <td><a href="http://viewvc.org/index.html"><img
- src="images/logo.png" alt="ViewVC logotype" /></a>
- </td>
- <td>
- <h1>ViewVC Help: Directory View</h1>
- </td>
- </tr>
<tr><td>
<h3>Help</h3>
<a href="help_rootview.html">General</a><br />
<strong>Directory View</strong><br />
<a href="help_log.html">Log View</a><br />
+ <a href="help_query.html">Query Database</a><br />
+ </td><td>
- <h3>Internet</h3>
- <a href="http://viewvc.org/index.html">Home</a><br />
- <a href="http://viewvc.org/upgrading.html">Upgrading</a><br />
- <a href="http://viewvc.org/contributing.html">Contributing</a><br />
- <a href="http://viewvc.org/license-1.html">License</a><br />
- </td><td colspan="2">
+ <h1>ViewVC Help: Directory View</h1>
<p>The directory listing view should be a familiar sight to any
computer user. It shows the path of the current directory being viewed
Modified: trunk/templates/docroot/help_log.html
==============================================================================
--- trunk/templates/docroot/help_log.html (original)
+++ trunk/templates/docroot/help_log.html Mon Nov 3 09:57:02 2008
@@ -4,32 +4,24 @@
<head>
<title>ViewVC Help: Log View</title>
<link rel="stylesheet" href="help.css" type="text/css" />
+ <link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
+ <div><a href="http://viewvc.org/index.html"><img src="images/viewvc-logo.png" alt="ViewVC logotype" /></a></div>
<table>
<col class="menu" />
<col />
- <tr>
- <td><a href="http://viewvc.org/index.html"><img
- src="images/logo.png" alt="ViewVC logotype" /></a>
- </td>
- <td>
- <h1>ViewVC Help: Log View</h1>
- </td>
- </tr>
<tr><td>
<h3>Help</h3>
<a href="help_rootview.html">General</a><br />
<a href="help_dirview.html">Directory View</a><br />
<strong>Log View</strong><br />
+ <a href="help_query.html">Query Database</a><br />
+ </td><td>
+
+ <h1>ViewVC Help: Log View</h1>
- <h3>Internet</h3>
- <a href="http://viewvc.org/index.html">Home</a><br />
- <a href="http://viewvc.org/upgrading.html">Upgrading</a><br />
- <a href="http://viewvc.org/contributing.html">Contributing</a><br />
- <a href="http://viewvc.org/license-1.html">License</a><br />
- </td><td colspan="2">
<p>
The log view displays the revision history of the selected source
file or directory. For each revision the following information is
Modified: trunk/templates/docroot/help_query.html
==============================================================================
--- trunk/templates/docroot/help_query.html (original)
+++ trunk/templates/docroot/help_query.html Mon Nov 3 09:57:02 2008
@@ -4,64 +4,59 @@
<head>
<title>ViewVC Help: Query The Commit Database</title>
<link rel="stylesheet" href="help.css" type="text/css" />
+ <link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon" />
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
-<table>
- <col class="menu" />
- <col />
- <tr>
- <td><a href=".."><img
- src="images/logo.png" alt="ViewVC logotype" /></a>
- </td>
- <td><h1>ViewVC Help: Query The Commit Database</h1></td>
- </tr>
- <tr><td>
- <h3>Other Help:</h3>
- <a href="help_rootview.html">General</a><br />
- <a href="help_dirview.html">Directory View</a><br />
- <a href="help_log.html">Classic Log View</a><br />
- <a href="help_logtable.html">Alternative Log View</a><br />
- <strong>Query Database</strong>
-
- <h3>Internet</h3>
- <a href="http://viewvc.org/index.html">Home</a><br />
- <a href="http://viewvc.org/upgrading.html">Upgrading</a><br />
- <a href="http://viewvc.org/contributing.html">Contributing</a><br />
- <a href="http://viewvc.org/license-1.html">License</a><br />
- </td><td colspan="2">
-
- <p>
- Select your parameters for querying the CVS commit database in the
- form at the top of the page. You
- can search for multiple matches by typing a comma-seperated list
- into the text fields. Regular expressions, and wildcards are also
- supported. Blank text input fields are treated as wildcards.
- </p>
- <p>
- Any of the text entry fields can take a comma-seperated list of
- search arguments. For example, to search for all commits from
- authors <em>jpaint</em> and <em>gstein</em>, just type: <code>jpaint,
- gstein</code> in the <em>Author</em> input box. If you are searching
- for items containing spaces or quotes, you will need to quote your
- request. For example, the same search above with quotes is:
- <code>"jpaint", "gstein"</code>.
- </p>
- <p>
- Wildcard and regular expression searches are entered in a similar
- way to the quoted requests. You must quote any wildcard or
- regular expression request, and a command character preceeds the
- first quote. The command character <code>l</code>(lowercase L) is for wildcard
- searches, and the wildcard character is a percent (<code>%</code>). The
- command character for regular expressions is <code>r</code>, and is
- passed directly to MySQL, so you'll need to refer to the MySQL
- manual for the exact regex syntax. It is very similar to Perl. A
- wildard search for all files with a <em>.py</em> extention is:
- <code>l"%.py"</code> in the <em>File</em> input box. The same search done
- with a regular expression is: <code>r".*\.py"</code>.
- </p>
- <p>
- All search types can be mixed, as long as they are seperated by
- commas.
- </p>
- </td></tr></table>
-</body></html>
+ <div><a href="http://viewvc.org/index.html"><img src="images/viewvc-logo.png" alt="ViewVC logotype" /></a></div>
+ <table>
+ <col class="menu" />
+ <col />
+ <tr><td>
+ <h3>Help:</h3>
+ <a href="help_rootview.html">General</a><br />
+ <a href="help_dirview.html">Directory View</a><br />
+ <a href="help_log.html">Log View</a><br />
+ <strong>Query Database</strong>
+ </td><td>
+
+ <h1>ViewVC Help: Query The Commit Database</h1>
+
+ <p>
+ Select your parameters for querying the CVS commit database in the
+ form at the top of the page. You
+ can search for multiple matches by typing a comma-seperated list
+ into the text fields. Regular expressions, and wildcards are also
+ supported. Blank text input fields are treated as wildcards.
+ </p>
+ <p>
+ Any of the text entry fields can take a comma-seperated list of
+ search arguments. For example, to search for all commits from
+ authors <em>jpaint</em> and <em>gstein</em>, just type: <code>jpaint,
+ gstein</code> in the <em>Author</em> input box. If you are searching
+ for items containing spaces or quotes, you will need to quote your
+ request. For example, the same search above with quotes is:
+ <code>"jpaint", "gstein"</code>.
+ </p>
+ <p>
+ Wildcard and regular expression searches are entered in a similar
+ way to the quoted requests. You must quote any wildcard or
+ regular expression request, and a command character preceeds the
+ first quote. The command character <code>l</code>(lowercase L) is for wildcard
+ searches, and the wildcard character is a percent (<code>%</code>). The
+ command character for regular expressions is <code>r</code>, and is
+ passed directly to MySQL, so you'll need to refer to the MySQL
+ manual for the exact regex syntax. It is very similar to Perl. A
+ wildard search for all files with a <em>.py</em> extention is:
+ <code>l"%.py"</code> in the <em>File</em> input box. The same search done
+ with a regular expression is: <code>r".*\.py"</code>.
+ </p>
+ <p>
+ All search types can be mixed, as long as they are seperated by
+ commas.
+ </p>
+ </td></tr></table>
+ <hr />
+ <address><a href="mailto:users viewvc tigris org">ViewVC Users Mailinglist</a></address>
+ </body>
+</html>
Modified: trunk/templates/docroot/help_rootview.html
==============================================================================
--- trunk/templates/docroot/help_rootview.html (original)
+++ trunk/templates/docroot/help_rootview.html Mon Nov 3 09:57:02 2008
@@ -4,164 +4,152 @@
<head>
<title>ViewVC Help: General</title>
<link rel="stylesheet" href="help.css" type="text/css" />
+ <link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon" />
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
+ <div><a href="http://viewvc.org/index.html"><img src="images/viewvc-logo.png" alt="ViewVC logotype" /></a></div>
<table>
<col class="menu" />
<col />
- <tr>
- <td><a href=".."><img
- src="images/logo.png" alt="ViewVC logotype" /></a>
- </td>
- <td>
- <h1>ViewVC Help: General</h1>
- </td>
- </tr>
<tr><td>
<h3>Help</h3>
<strong>General</strong><br />
<a href="help_dirview.html">Directory View</a><br />
<a href="help_log.html">Log View</a><br />
+ <a href="help_query.html">Query Database</a><br />
+ </td><td>
- <h3>Internet</h3>
- <a href="http://viewvc.org/index.html">Home</a><br />
- <a href="http://viewvc.org/upgrading.html">Upgrading</a><br />
- <a href="http://viewvc.org/contributing.html">Contributing</a><br />
- <a href="http://viewvc.org/license-1.html">License</a><br />
- </td><td colspan="2">
-
- <p><em>ViewVC</em> is a WWW interface for CVS and Subversion
- repositories. It allows you to browse the files and directories in a
- repository while showing you metadata from the repository history: log
- messages, modification dates, author names, revision numbers, copy
- history, and so on. It provides several different views of repository
- data to help you find the information you are looking for:</p>
-
- <ul>
- <li><a name="view-dir" href="help_dirview.html"><strong>Directory
- View</strong></a> - Shows a list of files and subdirectories in a
- directory of the repository, along with metadata like author names and
- log entries.</li>
-
- <li><a name="view-log" href="help_log.html"><strong>Log
- View</strong></a> - Shows a revision by revision list of all the
- changes that have made to a file or directory in the repository, with
- metadata and links to views of each revision.</li>
-
- <li><a name="view-markup"><strong>File Contents View (Markup
- View)</strong></a> - Shows the contents of a file at a particular
- revision, with revision information at the top of the page. File
- revisions which are GIF, PNG, or JPEG images are displayed inline on
- the page. Other file types are displayed as marked up text. The markup
- may be limited to turning URLs and email addresses into links, or
- configured to show colorized source code.</li>
-
- <li><a name="view-checkout"><strong>File Download (Checkout
- View)</strong></a> - Retrieves the unaltered contents of a file
- revision. Browsers may try to display the file, or just save it to
- disk.</li>
-
- <li><a name="view-annotate"><strong>File Annotate View</strong></a> -
- Shows the contents of a file revision and breaks it down line by line,
- showing the revision number where each one was last modified, along
- with links and other information. <em>This view is disabled in some
- ViewVC configurations</em></li>
-
- <li><a name="view-diff"><strong>File Diff View</strong></a> - Shows
- the changes made between two revisions of a file</li>
-
- <li><a name="view-tarball"><strong>Directory Tarball View</strong> -
- Retrieves a gzipped tar archive containing the contents of a
- directory.<em>This view is disabled in the default ViewVC
- configuration.</em></li>
-
- <li><a name="view-query"><strong>Directory Query View</strong></a> -
- Shows information about changes made to all subdirectories and files
- under a parent directory, sorted and filtered by criteria you specify.
- <em>This view is disabled in the default ViewVC configuration.</em>
- </li>
-
- <li><a name="view-rev"><strong>Revision View</strong> - Shows
- information about a revision including log message, author, and a list
- of changed paths. <em>For Subversion repositories only.</em></li>
-
- <li><a name="view-graph"><strong>Graph View</strong></a> - Shows a
- graphical representation of a file's revisions and branches complete
- with tag and author names and links to markup and diff pages.
- <em>For CVS repositories only, and disabled in the default
- configuration.</em></li>
- </ul>
-
- <h3><a name="multiple-repositories">Multiple Repositories</a></h3>
-
- <p>A single installation of ViewVC is often used to provide access to
- more than one repository. In these installations, ViewVC shows a
- <em>Project Root</em> drop down box in the top right corner of every
- generated page to allow for quick access to any repository.</p>
-
- <h3><a name="sticky-revision-tag">Sticky Revision and Tag</a></h3>
-
- <p>By default, ViewVC will show the files and directories and revisions
- that currently exist in the repository. But it's also possible to browse
- the contents of a repository at a point in its past history by choosing
- a "sticky tag" (in CVS) or a "sticky revision" (in Subversion) from the
- forms at the top of directory and log pages. They're called sticky
- because once they're chosen, they stick around when you navigate to
- other pages, until you reset them. When they're set, directory and log
- pages only show revisions preceding the specified point in history. In
- CVS, when a tag refers to a branch or a revision on a branch, only
- revisions from the branch history are shown, including branch points and
- their preceding revisions.</p>
-
- <h3><a name="dead-files">Dead Files</a></h3>
-
- <p>In CVS directory listings, ViewVC can optionally display dead files.
- Dead files are files which used to be in a directory but are currently
- deleted, or files which just don't exist in the currently selected
- <a href="#sticky-revision-tag">sticky tag</a>. Dead files cannot be
- shown in Subversion repositories. The only way to see a deleted file in
- a Subversion directory is to navigate to a sticky revision where the
- file previously existed.</p>
-
- <h3><a name="artificial-tags">Artificial Tags</a></h3>
-
- <p>In CVS Repositories, ViewVC adds artificial tags <em>HEAD</em> and
- <em>MAIN</em> to tag listings and accepts them in place of revision
- numbers and real tag names in all URLs. <em>MAIN</em> acts like a branch
- tag pointing at the default branch, while <em>HEAD</em> acts like a
- revision tag pointing to the latest revision on the default branch. The
- default branch is usually just the trunk, but may be set to other
- branches inside individual repository files. CVS will always check out
- revisions from a file's default branch when no other branch is specified
- on the command line.</p>
-
- <h3><a name="more-information">More Information</a></h3>
-
- <p>More information about <em>ViewVC</em> is available from
- <a href="http://viewvc.org/">viewvc.org</a>.
- See the links below for guides to CVS and Subversion</p>
-
- <h4>Documentation about CVS</h4>
- <blockquote>
- <p>
- <a href="http://cvsbook.red-bean.com/"><em>Open Source
- Development with CVS</em></a><br />
- <a href="http://www.loria.fr/~molli/cvs/doc/cvs_toc.html">CVS
- User's Guide</a><br />
- <a href="http://cellworks.washington.edu/pub/docs/cvs/tutorial/cvs_tutorial_1.html">Another CVS tutorial</a><br />
- <a href="http://www.csc.calpoly.edu/~dbutler/tutorials/winter96/cvs/">Yet another CVS tutorial (a little old, but nice)</a><br />
- <a href="http://www.cs.utah.edu/dept/old/texinfo/cvs/FAQ.txt">An old but very useful FAQ about CVS</a>
- </p>
- </blockquote>
-
- <h4>Documentation about Subversion</h3>
- <blockquote>
- <p>
- <a href="http://svnbook.red-bean.com/"><em>Version Control with
- Subversion</em></a><br />
- </p>
- </blockquote>
+ <h1>ViewVC Help: General</h1>
+ <p><em>ViewVC</em> is a WWW interface for CVS and Subversion
+ repositories. It allows you to browse the files and directories in a
+ repository while showing you metadata from the repository history: log
+ messages, modification dates, author names, revision numbers, copy
+ history, and so on. It provides several different views of repository
+ data to help you find the information you are looking for:</p>
+
+ <ul>
+ <li><a name="multiple-repositories"><strong>Root Listing
+ View</strong></a> - Show a list of repositories configured for
+ display in ViewVC.</li>
+
+ <li><a name="view-dir" href="help_dirview.html"><strong>Directory
+ View</strong></a> - Shows a list of files and subdirectories in a
+ directory of the repository, along with metadata like author names and
+ log entries.</li>
+
+ <li><a name="view-log" href="help_log.html"><strong>Log
+ View</strong></a> - Shows a revision by revision list of all the
+ changes that have made to a file or directory in the repository, with
+ metadata and links to views of each revision.</li>
+
+ <li><a name="view-checkout"><strong>File Download (Checkout
+ View)</strong></a> - Retrieves the unaltered contents of a file
+ revision. Browsers may try to display the file, or just save it
+ to disk. <em>This view is disabled in the default ViewVC
+ configuration.</em></li>
+
+ <li><a name="view-annotate"><a name="view-markup"><strong>File
+ Contents View</strong></a></a> - Shows the contents of a file at
+ a particular revision, with revision information at the top of
+ the page. File revisions which are GIF, PNG, or JPEG images are
+ displayed inline on the page. Other file types are displayed as
+ marked up text. The markup may be limited to turning URLs and
+ email addresses into links, or configured to show colorized
+ source code. This view can optionally show line-based
+ annotation data for the file, containing the revision number
+ where each line was last modified, along with links and other
+ information. <em>This view is disabled in some ViewVC
+ configurations.</em></li>
+
+ <li><a name="view-diff"><strong>File Diff View</strong></a> - Shows
+ the changes made between two revisions of a file</li>
+
+ <li><a name="view-tarball"><strong>Directory Tarball View</strong> -
+ Retrieves a gzipped tar archive containing the contents of a
+ directory.<em>This view is disabled in the default ViewVC
+ configuration.</em></li>
+
+ <li><a name="view-query"><strong>Directory Query View</strong></a> -
+ Shows information about changes made to all subdirectories and files
+ under a parent directory, sorted and filtered by criteria you specify.
+ <em>This view is disabled in the default ViewVC configuration.</em>
+ </li>
+
+ <li><a name="view-rev"><strong>Revision View</strong> - Shows
+ information about a revision including log message, author, and a list
+ of changed paths. <em>For Subversion repositories only.</em></li>
+
+ <li><a name="view-graph"><strong>Graph View</strong></a> - Shows a
+ graphical representation of a file's revisions and branches complete
+ with tag and author names and links to markup and diff pages.
+ <em>For CVS repositories only, and disabled in the default
+ configuration.</em></li>
+ </ul>
+
+ <h3><a name="sticky-revision-tag">Sticky Revision and Tag</a></h3>
+
+ <p>By default, ViewVC will show the files and directories and revisions
+ that currently exist in the repository. But it's also possible to browse
+ the contents of a repository at a point in its past history by choosing
+ a "sticky tag" (in CVS) or a "sticky revision" (in Subversion) from the
+ forms at the top of directory and log pages. They're called sticky
+ because once they're chosen, they stick around when you navigate to
+ other pages, until you reset them. When they're set, directory and log
+ pages only show revisions preceding the specified point in history. In
+ CVS, when a tag refers to a branch or a revision on a branch, only
+ revisions from the branch history are shown, including branch points and
+ their preceding revisions.</p>
+
+ <h3><a name="dead-files">Dead Files</a></h3>
+
+ <p>In CVS directory listings, ViewVC can optionally display dead files.
+ Dead files are files which used to be in a directory but are currently
+ deleted, or files which just don't exist in the currently selected
+ <a href="#sticky-revision-tag">sticky tag</a>. Dead files cannot be
+ shown in Subversion repositories. The only way to see a deleted file in
+ a Subversion directory is to navigate to a sticky revision where the
+ file previously existed.</p>
+
+ <h3><a name="artificial-tags">Artificial Tags</a></h3>
+
+ <p>In CVS Repositories, ViewVC adds artificial tags <em>HEAD</em> and
+ <em>MAIN</em> to tag listings and accepts them in place of revision
+ numbers and real tag names in all URLs. <em>MAIN</em> acts like a branch
+ tag pointing at the default branch, while <em>HEAD</em> acts like a
+ revision tag pointing to the latest revision on the default branch. The
+ default branch is usually just the trunk, but may be set to other
+ branches inside individual repository files. CVS will always check out
+ revisions from a file's default branch when no other branch is specified
+ on the command line.</p>
+
+ <h3><a name="more-information">More Information</a></h3>
+
+ <p>More information about <em>ViewVC</em> is available from
+ <a href="http://viewvc.org/">viewvc.org</a>.
+ See the links below for guides to CVS and Subversion</p>
+
+ <h4>Documentation about CVS</h4>
+ <blockquote>
+ <p>
+ <a href="http://cvsbook.red-bean.com/"><em>Open Source
+ Development with CVS</em></a><br />
+ <a href="http://www.loria.fr/~molli/cvs/doc/cvs_toc.html">CVS
+ User's Guide</a><br />
+ <a href="http://cellworks.washington.edu/pub/docs/cvs/tutorial/cvs_tutorial_1.html">Another CVS tutorial</a><br />
+ <a href="http://www.csc.calpoly.edu/~dbutler/tutorials/winter96/cvs/">Yet another CVS tutorial (a little old, but nice)</a><br />
+ <a href="http://www.cs.utah.edu/dept/old/texinfo/cvs/FAQ.txt">An old but very useful FAQ about CVS</a>
+ </p>
+ </blockquote>
+
+ <h4>Documentation about Subversion</h3>
+ <blockquote>
+ <p>
+ <a href="http://svnbook.red-bean.com/"><em>Version Control with
+ Subversion</em></a><br />
+ </p>
+ </blockquote>
</td></tr></table>
<hr />
<address><a href="mailto:users viewvc tigris org">ViewVC Users Mailinglist</a></address>
Modified: trunk/templates/docroot/styles.css
==============================================================================
--- trunk/templates/docroot/styles.css (original)
+++ trunk/templates/docroot/styles.css Mon Nov 3 09:57:02 2008
@@ -6,6 +6,7 @@
#body {
margin: 90px 10px 0px 10px;
padding: 0px;
+ font-family: sans-serif;
}
a:link { color: #0000ff; }
@@ -31,8 +32,10 @@
white-space: nowrap;
}
tr, td, th { vertical-align: top; }
+th { white-space: nowrap; }
form { margin: 0; }
+
/*** Icons ***/
.vc_icon {
width: 16px;
@@ -48,6 +51,10 @@
margin: 0.25em;
-moz-border-radius: 15px;
background: #dddddd;
+ padding: .25em;
+}
+.vc_navheader .pathdiv {
+ padding: 0 3px;
}
@@ -68,7 +75,7 @@
background-color: #ffffff;
}
.vc_row_odd {
- background-color: #eeeeee;
+ background-color: #f0f0f0;
}
.vc_row_special {
background-color: #ffff7f;
@@ -86,52 +93,108 @@
}
-/*** Markup Summary Header ***/
+/*** Properties Listing ***/
+.vc_properties {
+ margin: 1em 0;
+}
+.vc_properties h2 {
+ font-size: 115%;
+}
+
+
+/*** File Content Markup Styles ***/
.vc_summary {
background-color: #ececec;
border: 1px solid #807d74;
padding: 2px;
margin: 0.25em;
}
-
-#vc_markup {
- font-family: monospace;
-}
-
-/*** Highlight Markup Styles ***/
-#vc_markup .num { color: #000000; }
-#vc_markup .esc { color: #bd8d8b; }
-#vc_markup .str { color: #bd8d8b; }
-#vc_markup .dstr { color: #bd8d8b; }
-#vc_markup .slc { color: #ac2020; font-style: italic; }
-#vc_markup .com { color: #ac2020; font-style: italic; }
-#vc_markup .dir { color: #000000; }
-#vc_markup .sym { color: #000000; }
-#vc_markup .line { color: #555555; }
-#vc_markup .kwa { color: #9c20ee; font-weight: bold; }
-#vc_markup .kwb { color: #208920; }
-#vc_markup .kwc { color: #0000ff; }
-#vc_markup .kwd { color: #404040; }
-
-/*** Py2html Markup Styles ***/
-#vc_markup .PY_STRING { color: #bd8d8b; }
-#vc_markup .PY_COMMENT { color: #ac2020; font-style: italic; }
-#vc_markup .PY_KEYWORD { color: #9c20ee; font-weight: bold; }
-#vc_markup .PY_IDENTIFIER { color: #404040; }
-
-/*** Line numbers outputted by highlight colorizer ***/
-.line {
- border-right-width: 1px;
+#vc_file td {
border-right-style: solid;
border-right-color: #505050;
- padding: 1px;
- background-color: #eeeeee;
- color: #505050;
text-decoration: none;
font-weight: normal;
font-style: normal;
+ padding: 1px 5px;
+}
+.vc_file_line_number {
+ border-right-width: 1px;
+ background-color: #eeeeee;
+ color: #505050;
text-align: right;
}
+.vc_file_line_author, .vc_file_line_rev {
+ border-right-width: 1px;
+ text-align: right;
+}
+.vc_file_line_text {
+ border-right-width: 0px;
+ background-color: white;
+ font-family: monospace;
+ text-align: left;
+ white-space: pre;
+ width: 100%;
+}
+.pygments-c { color: #408080; font-style: italic } /* Comment */
+.pygments-err { border: 1px solid #FF0000 } /* Error */
+.pygments-k { color: #008000; font-weight: bold } /* Keyword */
+.pygments-o { color: #666666 } /* Operator */
+.pygments-cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.pygments-cp { color: #BC7A00 } /* Comment.Preproc */
+.pygments-c1 { color: #408080; font-style: italic } /* Comment.Single */
+.pygments-cs { color: #408080; font-style: italic } /* Comment.Special */
+.pygments-gd { color: #A00000 } /* Generic.Deleted */
+.pygments-ge { font-style: italic } /* Generic.Emph */
+.pygments-gr { color: #FF0000 } /* Generic.Error */
+.pygments-gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.pygments-gi { color: #00A000 } /* Generic.Inserted */
+.pygments-go { color: #808080 } /* Generic.Output */
+.pygments-gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.pygments-gs { font-weight: bold } /* Generic.Strong */
+.pygments-gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.pygments-gt { color: #0040D0 } /* Generic.Traceback */
+.pygments-kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.pygments-kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.pygments-kp { color: #008000 } /* Keyword.Pseudo */
+.pygments-kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.pygments-kt { color: #B00040 } /* Keyword.Type */
+.pygments-m { color: #666666 } /* Literal.Number */
+.pygments-s { color: #BA2121 } /* Literal.String */
+.pygments-na { color: #7D9029 } /* Name.Attribute */
+.pygments-nb { color: #008000 } /* Name.Builtin */
+.pygments-nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.pygments-no { color: #880000 } /* Name.Constant */
+.pygments-nd { color: #AA22FF } /* Name.Decorator */
+.pygments-ni { color: #999999; font-weight: bold } /* Name.Entity */
+.pygments-ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.pygments-nf { color: #0000FF } /* Name.Function */
+.pygments-nl { color: #A0A000 } /* Name.Label */
+.pygments-nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.pygments-nt { color: #008000; font-weight: bold } /* Name.Tag */
+.pygments-nv { color: #19177C } /* Name.Variable */
+.pygments-ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.pygments-w { color: #bbbbbb } /* Text.Whitespace */
+.pygments-mf { color: #666666 } /* Literal.Number.Float */
+.pygments-mh { color: #666666 } /* Literal.Number.Hex */
+.pygments-mi { color: #666666 } /* Literal.Number.Integer */
+.pygments-mo { color: #666666 } /* Literal.Number.Oct */
+.pygments-sb { color: #BA2121 } /* Literal.String.Backtick */
+.pygments-sc { color: #BA2121 } /* Literal.String.Char */
+.pygments-sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.pygments-s2 { color: #BA2121 } /* Literal.String.Double */
+.pygments-se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.pygments-sh { color: #BA2121 } /* Literal.String.Heredoc */
+.pygments-si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.pygments-sx { color: #008000 } /* Literal.String.Other */
+.pygments-sr { color: #BB6688 } /* Literal.String.Regex */
+.pygments-s1 { color: #BA2121 } /* Literal.String.Single */
+.pygments-ss { color: #19177C } /* Literal.String.Symbol */
+.pygments-bp { color: #008000 } /* Name.Builtin.Pseudo */
+.pygments-vc { color: #19177C } /* Name.Variable.Class */
+.pygments-vg { color: #19177C } /* Name.Variable.Global */
+.pygments-vi { color: #19177C } /* Name.Variable.Instance */
+.pygments-il { color: #666666 } /* Literal.Number.Integer.Long */
+
/*** Diff Styles ***/
.vc_diff_header {
@@ -171,8 +234,8 @@
font-family: monospace;
}
-/*** Intraline Diff Styles ***/
+/*** Intraline Diff Styles ***/
.vc_idiff_add {
background-color: #aaffaa;
}
@@ -185,7 +248,6 @@
.vc_idiff_empty {
background-color:#e0e0e0;
}
-
table.vc_idiff col.content {
width: 50%;
}
@@ -203,39 +265,6 @@
text-align:right;
}
-/*** Annotate Styles ***/
-div.vc_blame {
- margin: 1em 0;
-}
-
-#vc_blame td {
- border-right-width: 1px;
- border-right-style: solid;
- border-right-color: #505050;
- text-decoration: none;
- font-weight: normal;
- font-style: normal;
-}
-.vc_blame_line {
- background-color: #eeeeee;
- color: #505050;
- padding: 1px 1px;
- font-size: 80%;
-}
-.vc_blame_author, .vc_blame_rev, .vc_blame_line {
- text-align: right;
- font-size: smaller;
-}
-.vc_blame_rev, .vc_blame_line {
- padding: 1px 5px;
-}
-.vc_blame_text {
- font-family: monospace;
- text-align: left;
- white-space: pre;
- width: 100%;
-}
-
/*** Query Form ***/
.vc_query_form {
background-color: #e6e6e6;
Modified: trunk/templates/include/diff_form.ezt
==============================================================================
--- trunk/templates/include/diff_form.ezt (original)
+++ trunk/templates/include/diff_form.ezt Mon Nov 3 09:57:02 2008
@@ -15,7 +15,7 @@
<tr>
<td> </td>
<td>
- [diff_select_hidden_values]
+ [for diff_select_hidden_values]<input type="hidden" name="[diff_select_hidden_values.name]" value="[diff_select_hidden_values.value]"/>[end]
Diffs between
[if-any tags]
<select name="r1">
Modified: trunk/templates/include/dir_footer.ezt
==============================================================================
--- trunk/templates/include/dir_footer.ezt (original)
+++ trunk/templates/include/dir_footer.ezt Mon Nov 3 09:57:02 2008
@@ -1,38 +1,9 @@
-[if-any search_re_form]
- <hr />
- [# this table holds the selectors on the left, and reset on the right ]
- <table class="auto">
- <tr>
- <td>Show files containing the regular expression:</td>
- <td>
- <form method="get" action="[search_re_action]">
- <div>
- [search_re_hidden_values]
- <input type="text" name="search" value="[search_re]" />
- <input type="submit" value="Show" />
- </div>
- </form>
- </td>
- </tr>
- [if-any search_re]
- <tr>
- <td> </td>
- <td>
- <form method="get" action="[search_tag_action]">
- <div>
- [search_tag_hidden_values]
- <input type="submit" value="Show all files" />
- </div>
- </form>
- </td>
- </tr>
- [end]
- </table>
-[end]
-
[# if you want to disable tarball generation remove the following: ]
[if-any tarball_href]
- <p style="margin:0;"><a href="[tarball_href]">Download GNU tarball</a></p>
+<hr/>
+<p style="margin:0;"><a href="[tarball_href]">Download GNU tarball</a></p>
[end]
+[include "props.ezt"]
[include "footer.ezt"]
+
Modified: trunk/templates/include/dir_header.ezt
==============================================================================
--- trunk/templates/include/dir_header.ezt (original)
+++ trunk/templates/include/dir_header.ezt Mon Nov 3 09:57:02 2008
@@ -31,8 +31,27 @@
<td>Sticky [is roottype "cvs"]Tag[else]Revision[end]:</td>
<td>[include "pathrev_form.ezt"]</td>
</tr>
-[if-any search_re]
-<tr><td>Current search:</td><td><strong>[search_re]</strong></td></tr>
+
+[if-any search_re_form]
+<tr>
+ <td>Filter files by content:</td>
+ <td><form method="get" action="[search_re_action]" style="display: inline;">
+ <div style="display: inline;">
+ [for search_re_hidden_values]<input type="hidden" name="[search_re_hidden_values.name]" value="[search_re_hidden_values.value]"/>[end]
+ <input type="text" name="search" value="[search_re]" />
+ <input type="submit" value="Search Regexp" />
+ </div>
+ </form>
+ [if-any search_re]
+ <form method="get" action="[search_re_action]" style="display: inline;">
+ <div style="display: inline;">
+ [for search_re_hidden_values]<input type="hidden" name="[search_re_hidden_values.name]" value="[search_re_hidden_values.value]"/>[end]
+ <input type="submit" value="Show All Files" />
+ </div>
+ </form>
+ [end]
+ </td>
+</tr>
[end]
[if-any queryform_href]
@@ -41,24 +60,25 @@
<td><a href="[queryform_href]">Query revision history</a></td>
</tr>
[end]
+
</table>
- [is cfg.options.use_pagesize "0"]
+
+[is cfg.options.use_pagesize "0"]
+[else]
+ [is picklist_len "1"]
[else]
- [is picklist_len "1"]
- [else]
- <form method="get" action="[dir_paging_action]">
- [dir_paging_hidden_values]
- <input type="submit" value="Go to:" />
- <select name="dir_pagestart" onchange="submit()">
- [for picklist]
- <option [is picklist.count dir_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] to [picklist.end]</option>
- [end]
- </select>
- </form>
- [end]
+ <form method="get" action="[dir_paging_action]">
+ [for dir_paging_hidden_values]<input type="hidden" name="[dir_paging_hidden_values.name]" value="[dir_paging_hidden_values.value]"/>[end]
+ <input type="submit" value="Go to:" />
+ <select name="dir_pagestart" onchange="submit()">
+ [for picklist]
+ <option [is picklist.count dir_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] to [picklist.end]</option>
+ [end]
+ </select>
+ </form>
[end]
+[end]
<p><a name="dirlist"></a></p>
-
<hr />
Modified: trunk/templates/include/header.ezt
==============================================================================
--- trunk/templates/include/header.ezt (original)
+++ trunk/templates/include/header.ezt Mon Nov 3 09:57:02 2008
@@ -59,63 +59,10 @@
<div id="content">
<div class="vc_navheader">
-[if-any roots]
- <form method="get" action="[change_root_action]">
-[end]
-<table style="padding:0.1em;">
-<tr>
- <td>
- [if-any nav_path]<strong>
- [for nav_path]
- [if-any nav_path.href]<a href="[nav_path.href]">[end]
- [if-index nav_path first]
- [[][nav_path.name]][else]
- [nav_path.name][end][if-any nav_path.href]</a>[end]
- [if-index nav_path last][else]/[end]
- [end]
- </strong>
- [end]
- </td>
- <td style="text-align:right;">
- [if-any roots]
- [change_root_hidden_values]
- <strong>Repository:</strong>
- <select name="root" onchange="submit()">
- [define cvs_root_options][end]
- [define svn_root_options][end]
- <option value="*viewroots*"[is view "roots"] selected="selected"[else][end]>Repository Listing</option>
- [for roots]
- [define root_option][end]
- [is roots.name rootname]
- [define root_option]<option selected="selected">[roots.name]</option>[end]
- [else]
- [define root_option]<option>[roots.name]</option>[end]
- [end]
- [is roots.type "cvs"]
- [define cvs_root_options][cvs_root_options][root_option][end]
- [else]
- [is roots.type "svn"]
- [define svn_root_options][svn_root_options][root_option][end]
- [end]
- [end]
- [end]
- [is cvs_root_options ""][else]
- <optgroup label="CVS Repositories">[cvs_root_options]</optgroup>
- [end]
- [is svn_root_options ""][else]
- <optgroup label="Subversion Repositories">[svn_root_options]</optgroup>
- [end]
- </select>
- <input type="submit" value="Go" />
- [else]
-
- [end]
- </td>
-</tr>
-</table>
-[if-any roots]
-</form>
-[end]
+<table><tr>
+<td><strong>[if-any roots_href]<a href="[roots_href]"><span class="pathdiv">/</span></a>[else]<span class="pathdiv">/</span>[end][if-any nav_path][for nav_path][if-any nav_path.href]<a href="[nav_path.href]">[end][if-index nav_path first][[][nav_path.name]][else][nav_path.name][end][if-any nav_path.href]</a>[end][if-index nav_path last][else]<span class="pathdiv">/</span>[end][end][end]</strong></td>
+<td style="text-align: right;">[if-any username]Logged in as: <strong>[username]</strong>[end]</td>
+</tr></table>
</div>
Modified: trunk/templates/include/log_header.ezt
==============================================================================
--- trunk/templates/include/log_header.ezt (original)
+++ trunk/templates/include/log_header.ezt Mon Nov 3 09:57:02 2008
@@ -19,14 +19,14 @@
[end]
[is pathtype "file"]
-[if-any view_href]
+[if-any head_view_href]
<tr>
<td>Links to HEAD:</td>
<td>
- (<a href="[view_href]">view</a>)
- [if-any download_href](<a href="[download_href]">download</a>)[end]
- [if-any download_text_href](<a href="[download_text_href]">as text</a>)[end]
- [if-any annotate_href](<a href="[annotate_href]">annotate</a>)[end]
+ (<a href="[head_view_href]">view</a>)
+ [if-any head_download_href](<a href="[head_download_href]">download</a>)[end]
+ [if-any head_download_text_href](<a href="[head_download_text_href]">as text</a>)[end]
+ [if-any head_annotate_href](<a href="[head_annotate_href]">annotate</a>)[end]
</td>
</tr>
[end]
Modified: trunk/templates/include/paging.ezt
==============================================================================
--- trunk/templates/include/paging.ezt (original)
+++ trunk/templates/include/paging.ezt Mon Nov 3 09:57:02 2008
@@ -4,11 +4,15 @@
[else]
<hr />
<form method="get" action="[log_paging_action]">
- [log_paging_hidden_values]
+ [for log_paging_hidden_values]<input type="hidden" name="[log_paging_hidden_values.name]" value="[log_paging_hidden_values.value]"/>[end]
<input type="submit" value="Go to:">
<select name="log_pagestart" onchange="submit()">
[for picklist]
+ [if-any picklist.more]
+ <option [is picklist.count log_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] ...</option>
+ [else]
<option [is picklist.count log_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] - [picklist.end]</option>
+ [end]
[end]
</select>
</form>
Modified: trunk/templates/include/pathrev_form.ezt
==============================================================================
--- trunk/templates/include/pathrev_form.ezt (original)
+++ trunk/templates/include/pathrev_form.ezt Mon Nov 3 09:57:02 2008
@@ -1,6 +1,6 @@
<form method="get" action="[pathrev_action]" style="display: inline">
<div style="display: inline">
-[pathrev_hidden_values]
+[for pathrev_hidden_values]<input type="hidden" name="[pathrev_hidden_values.name]" value="[pathrev_hidden_values.value]"/>[end]
[is roottype "cvs"]
[define pathrev_selected][pathrev][end]
<select name="pathrev" onchange="submit()">
@@ -41,7 +41,7 @@
[if-any pathrev]
<form method="get" action="[pathrev_clear_action]" style="display: inline">
<div style="display: inline">
-[pathrev_clear_hidden_values]
+[for pathrev_clear_hidden_values]<input type="hidden" name="[pathrev_clear_hidden_values.name]" value="[pathrev_clear_hidden_values.value]"/>[end]
[if-any lastrev]
[is pathrev lastrev][else]<input type="submit" value="Set to [lastrev]" />[end]
(<i>Current path doesn't exist after revision <strong>[lastrev]</strong></i>)
Modified: trunk/templates/include/sort.ezt
==============================================================================
--- trunk/templates/include/sort.ezt (original)
+++ trunk/templates/include/sort.ezt Mon Nov 3 09:57:02 2008
@@ -1,8 +1,10 @@
+[is roottype "svn"]
+[else]
<form method="get" action="[logsort_action]">
<div>
<hr />
<a name="logsort"></a>
- [logsort_hidden_values]
+ [for logsort_hidden_values]<input type="hidden" name="[logsort_hidden_values.name]" value="[logsort_hidden_values.value]"/>[end]
Sort log by:
<select name="logsort" onchange="submit()">
<option value="cvs" [is logsort "cvs"]selected="selected"[end]>Not sorted</option>
@@ -12,3 +14,4 @@
<input type="submit" value=" Sort " />
</div>
</form>
+[end]
\ No newline at end of file
Modified: trunk/templates/log.ezt
==============================================================================
--- trunk/templates/log.ezt (original)
+++ trunk/templates/log.ezt Mon Nov 3 09:57:02 2008
@@ -6,6 +6,7 @@
[for entries]
[if-index entries first][define first_revision][entries.rev][end][end]
[if-index entries last][define last_revision][entries.rev][end][end]
+
<div>
<hr />
@@ -97,6 +98,10 @@
[end]
[end]
+ [if-any entries.lockinfo]
+ <br />Lock status: <img src="[docroot]/images/lock.png" alt="Locked" width="16" height="16" /> [entries.lockinfo]
+ [end]
+
[is entries.state "dead"]
<br /><strong><em>FILE REMOVED</em></strong>
[else]
Modified: trunk/templates/log_table.ezt
==============================================================================
--- trunk/templates/log_table.ezt (original)
+++ trunk/templates/log_table.ezt Mon Nov 3 09:57:02 2008
@@ -110,7 +110,7 @@
[# Tags ]
[if-any entries.tags]
<form method=get action="[pathrev_action]" >
- [pathrev_hidden_values]
+ [for pathrev_hidden_values]<input type="hidden" name="[pathrev_hidden_values.name]" value="[pathrev_hidden_values.value]"/>[end]
<select name="pathrev" onChange="submit()">
<option value="" [is pathrev ""]selected[end]>Show all tags</option>
[for entries.tags]
@@ -147,9 +147,14 @@
</tr>
<tr class="vc_row_[if-index entries even]even[else]odd[end]">
<td colspan=5>
+
+ [if-any entries.lockinfo]
+ <strong>Lock status</strong>: <img src="[docroot]/images/lock.png" alt="Locked" width="16" height="16" /> [entries.lockinfo]<br />
+ [end]
+
[is roottype "svn"]
[if-any entries.orig_path]
- Original Path: <a href="[entries.orig_href]"><em>[entries.orig_path]</em></a><br />
+ <strong>Original Path</strong>: <a href="[entries.orig_href]"><em>[entries.orig_path]</em></a><br />
[end]
[if-any entries.size]
Modified: trunk/templates/query_form.ezt
==============================================================================
--- trunk/templates/query_form.ezt (original)
+++ trunk/templates/query_form.ezt Mon Nov 3 09:57:02 2008
@@ -12,7 +12,7 @@
<form action="[query_action]" method="get">
<div class="vc_query_form">
- [query_hidden_values]
+ [for query_hidden_values]<input type="hidden" name="[query_hidden_values.name]" value="[query_hidden_values.value]"/>[end]
<table cellspacing="0" cellpadding="5" class="auto">
[is roottype "cvs"]
[# For subversion, the branch field is not used ]
Modified: trunk/templates/revision.ezt
==============================================================================
--- trunk/templates/revision.ezt (original)
+++ trunk/templates/revision.ezt Mon Nov 3 09:57:02 2008
@@ -11,7 +11,7 @@
<tr align="left">
<th>Jump to revision:</th>
<td>
- [jump_rev_hidden_values]
+ [for jump_rev_hidden_values]<input type="hidden" name="[jump_rev_hidden_values.name]" value="[jump_rev_hidden_values.value]"/>[end]
<input type="text" name="revision" value="[rev]" />
<input type="submit" value="Go" />
[if-any prev_href]
Modified: trunk/tparse/tparse.h
==============================================================================
--- trunk/tparse/tparse.h (original)
+++ trunk/tparse/tparse.h Mon Nov 3 09:57:02 2008
@@ -1,5 +1,5 @@
/*
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
Modified: trunk/viewvc-install
==============================================================================
--- trunk/viewvc-install (original)
+++ trunk/viewvc-install Mon Nov 3 09:57:02 2008
@@ -49,8 +49,8 @@
FILE_INFO_LIST = [
("bin/cgi/viewvc.cgi", "bin/cgi/viewvc.cgi", 0755, 1, 0, 0),
("bin/cgi/query.cgi", "bin/cgi/query.cgi", 0755, 1, 0, 0),
- ("bin/mod_python/viewvc_mp.py", "bin/mod_python/viewvc_mp.py", 0755, 1, 0, 0),
- ("bin/mod_python/query_mp.py", "bin/mod_python/query_mp.py", 0755, 1, 0, 0),
+ ("bin/mod_python/viewvc.py", "bin/mod_python/viewvc.py", 0755, 1, 0, 0),
+ ("bin/mod_python/query.py", "bin/mod_python/query.py", 0755, 1, 0, 0),
("bin/mod_python/handler.py", "bin/mod_python/handler.py", 0755, 1, 0, 0),
("bin/mod_python/.htaccess", "bin/mod_python/.htaccess", 0755, 0, 0, 0),
("bin/standalone.py", "bin/standalone.py", 0755, 1, 0, 0),
Modified: trunk/viewvc.conf.dist
==============================================================================
--- trunk/viewvc.conf.dist (original)
+++ trunk/viewvc.conf.dist Mon Nov 3 09:57:02 2008
@@ -68,9 +68,6 @@
# address
# forbidden
#
-# use_enscript
-# use_cvsgraph
-#
# To optimize delivery of ViewVC static files:
#
# docroot
@@ -238,50 +235,16 @@
# Subversion command-line client, used for viewing Subversion repositories
svn =
-# svn_dir = /usr/bin/svn
+# svn = /usr/bin/svn
# GNU diff, used for showing file version differences
diff =
# diff = /usr/bin/diff
-# GNU Enscript, a syntax highlighting program (see options.use_enscript)
-enscript =
-# enscript = /usr/bin/enscript
-
-# Highlight, a syntax highlighting program (see options.use_highlight)
-highlight =
-# highlight = /usr/bin/highlight
-
-# GNU source-highlight, a syntax highlighting program (see
-# options.use_source_highlight)
-source_highlight =
-# source_highlight = /usr/bin/source-highlight
-
-# Marc-Andrew Lemburg's py2html, Python colorizer (see options.use_py2html)
-py2html_dir = .
-# py2html_dir = /usr/local/lib/python1.5/site-python
-
-# PHP, used to colorize PHP files (see options.use_php)
-# (This should be set to the path of a PHP CLI executable, not the path
-# to a CGI executable. If you use a CGI executable, you may see "no input file
-# specified" or "force-cgi-redirect" errors instead of colorized source. The
-# output of "php -v" tells you whether an given executable is CLI or CGI.)
-php = php
-# php = /usr/local/bin/php
-# php = C:\Program Files\php\cli\php.exe
-
# CvsGraph, a graphical CVS version graph generator (see options.use_cvsgraph)
cvsgraph =
# cvsgraph = /usr/local/bin/cvsgraph
-# Gzip, file compression utility (see options.allow_tar)
-gzip =
-# gzip = /usr/bin/gzip
-
-# Sed, stream editor
-sed =
-# sed = /usr/bin/sed
-
#---------------------------------------------------------------------------
[options]
@@ -304,8 +267,8 @@
# 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"
-allowed_views = markup, annotate
+# Possible values: "tar", "annotate", "co", "markup", "roots"
+allowed_views = markup, annotate, roots
# authorizer: The name of the ViewVC authorizer plugin to use when
# authorizing access to repository contents. This value must be the
@@ -315,26 +278,45 @@
# vcauth.GenericViewVCAuthorizer). You can provide custom parameters
# to the authorizer module by defining configuration sections named
# authz-MODULENAME and adding the parameter keys and values there.
-# ViewVC provides the following modules: "svnauthz", "forbidden"
+#
+# ViewVC provides the following modules:
+# svnauthz - based on Subversion authz files
+# forbidden - simple path glob matches against top-level root directories
+# forbiddenre - root and path matches against regular expressions
+#
+# 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
+# hide_cvsroot: Don't show the CVSROOT directory
+# 1 Hide CVSROOT directory
+# 0 Show CVSROOT directory
+# NOTE: Someday this option may be removed in favor of letting
+# individual authorizer plugin hide the CVSROOT.
+hide_cvsroot = 1
+
# mangle_email_addresses: Mangle email addresses in marked-up output.
-# 0 Markup un-mangled email addresses as hyperlinks
-# 1 Mangle (and don't markup as hyperlinks) email addresses
+# There are various levels of mangling available:
+# 0 - No mangling; markup un-mangled email addresses as hyperlinks
+# 1 - Obfuscation (using entity encoding); no hyperlinking
+# 2 - Data-dropping address truncation; no hyperlinking
# Note: this will not effect the display of versioned file contents, only
# addresses that appear in version control metadata (e.g. log messages).
mangle_email_addresses = 0
-# default_file_view: "log" or "co"
+# default_file_view: "log", "co", or "markup"
# Controls whether the default view for file URLs is a checkout view or
# a log view. "log" is the default for backwards compatibility with old
# ViewCVS URLs, but "co" has the advantage that it allows ViewVC to serve
# static HTML pages directly from a repository with working links
# to other repository files
-# Note: Changing this option may cause old ViewCVS URLs that referred
-# to log pages to load checkout pages instead.
-# Also note: If you choose the "co" view, be sure to enable it (via
-# the allowed_views option)
+# Note: Changing this option may break compatibility with existing
+# bookmarked URLs.
+# Also note: If you choose one of the "co" or "markup" views, be sure
+# to enable it (via the allowed_views option)
default_file_view = log
# http_expiration_time: Expiration time (in seconds) for cacheable
@@ -351,6 +333,12 @@
# 0 Don't generate Etags
generate_etags = 1
+# 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
+# the default location(s) ($HOME/.subversion, etc.)
+svn_config_dir =
+
# use the rcsparse Python module to retrieve CVS repository
# information instead of invoking rcs utilities [EXPERIMENTAL]
use_rcsparse = 0
@@ -373,10 +361,17 @@
# 0 Show the files which are inside the Attic subdir
hide_attic = 1
+# hide_errorful_entries: Hide or show errorful directory entries
+# (perhaps due to not being readable, or some other rlog parsing
+# error, etc.)
+# 1 Hide errorful entries from the directory display
+# 0 Show errorful entries (with their errors) in the directory display
+hide_errorful_entries = 0
+
# log_sort: Sort order for log messages
# date Sort revisions by date
# rev Sort revision by revision number
-# cvs Don't sort them. Same order as CVS/RCS shows them.
+# none Use the version control system's ordering
log_sort = date
# diff_format: Default diff format
@@ -385,16 +380,13 @@
# c Context diff
# s Side by side
# l Long human readable (more context)
+# f Full human readable (entire file)
diff_format = h
-# hide_cvsroot: Don't show the CVSROOT directory
-# 1 Hide CVSROOT directory
-# 0 Show CVSROOT directory
-hide_cvsroot = 1
-
-# set to 1 to make lines break at spaces,
-# set to 0 to make no-break lines,
-# set to a positive integer to make the lines cut at that length
+# hr_breakable: Diff view line breaks
+# 1 lines break at spaces
+# 0 no line breaking
+# Or, use a positive integer > 1 to cut lines after that many characters
hr_breakable = 1
# give out function names in human readable diffs
@@ -406,7 +398,7 @@
# ignore whitespaces for human readable diffs
# (indendation and stuff ..)
# ( '-w' option to diff)
-hr_ignore_white = 1
+hr_ignore_white = 0
# ignore diffs which are caused by
# keyword-substitution like $Id - Stuff
@@ -415,13 +407,11 @@
# Enable highlighting of intraline changes in human readable diffs
# this feature is experimental and currently requires python 2.4
-#
hr_intraline = 0
# allow compression with gzip of output if the Browser accepts it
-# (HTTP_ACCEPT_ENCODING=gzip)
-# [make sure to have gzip in the path]
-allow_compress = 1
+# (HTTP_ACCEPT_ENCODING contains "gzip")
+#allow_compress = 1
# The directory which contains the EZT templates used by ViewVC to
# customize the display of the various output views. ViewVC looks in
@@ -433,6 +423,9 @@
# If %lang% occurs in the pathname, then the selected language will be
# substituted.
#
+# See also the [templates] configuration section, where you can
+# override templates on a per-view basis.
+#
template_dir = templates
# Web path to a directory that contains ViewVC static files
@@ -443,17 +436,19 @@
# specified by the "template_dir" option).
#docroot = /docroot
-# Show last changelog message for sub directories
-# The current implementation makes many assumptions and may show the
-# incorrect file at some times. The main assumption is that the last
-# modified file has the newest filedate. But some CVS operations
+# Show last changelog message for CVS subdirectories
+# NOTE: The current implementation makes many assumptions and may show
+# the incorrect file at some times. The main assumption is that the
+# last modified file has the newest filedate. But some CVS operations
# touches the file without even when a new version is not checked in,
# and TAG based browsing essentially puts this out of order, unless
-# the last checkin was on the same tag as you are viewing.
-# Enable this if you like the feature, but don't rely on correct results.
+# the last checkin was on the same tag as you are viewing. Enable
+# this if you like the feature, but don't rely on correct results.
+#
+# ** WARNING: Enabling this will currently leak unauthorized path names **
show_subdir_lastmod = 0
-# show a portion of the most recent log entry in directory listings
+# Show the most recent log entry in directory listings.
show_logs = 1
# Show log when viewing file contents
@@ -466,51 +461,24 @@
use_localtime = 0
#use_localtime = 1
-# == Configuration defaults ==
-# Defaults for configuration variables that shouldn't need
-# to be configured..
+### CONFIGURATION DEFAULTS ###
+###
+### Defaults for configuration variables that shouldn't need
+### to be configured..
# the length to which the most recent log entry should be truncated when
# shown in the directory view
short_log_len = 80
-# should we use Marc-Andrew Lemburg's py2html (and Just van Rossum's
-# PyFontify) to colorize Python files?
-use_py2html = 0
-
-# should we use 'enscript' for syntax coloring?
-use_enscript = 1
-
-# should we use 'highlight' for syntax coloring?
-# NOTE: use_enscript has to be 0 or enscript will be used instead
-use_highlight = 0
-
-# should we add line numbers?
-highlight_line_numbers = 1
+# should we colorize known file content syntaxes? (requires Pygments module)
+enable_syntax_coloration = 1
-# convert tabs to ## spaces (use 0 for no conversion)
-highlight_convert_tabs = 2
-
-# should we use 'source-highlight' for syntax coloring?
-# NOTE: use_enscript and use_highlight have to be 0
-use_source_highlight = 0
-
-# should we add line numbers?
-source_highlight_line_numbers = 1
-
-# use php to colorize .php and .inc files?
-use_php = 0
-
-#
# Use CvsGraph. See http://www.akhphd.au.dk/~bertho/cvsgraph/ for
# documentation and download.
-#
use_cvsgraph = 0
-# use_cvsgraph = 1
+#use_cvsgraph = 1
-#
# Location of the customized cvsgraph configuration file.
-#
cvsgraph_conf = cvsgraph.conf
#
@@ -566,8 +534,9 @@
# appropriate option below and specify the currect location of the EZT
# template file you wish to use for that view.
#
-# Templates are specified relative to the directory where this config
-# file resides, but absolute paths may also be used as well.
+# Templates are specified relative to the configured template
+# directory (see the "template_dir" option), but absolute paths may
+# also be used as well.
#
# If %lang% occurs in the pathname, then the selected language will be
# substituted.
@@ -576,22 +545,21 @@
# [general] section, and based on the request's Accept-Language
# header.
#
-#annotate = templates/annotate.ezt
-#diff = templates/diff.ezt
-#directory = templates/directory.ezt
+#diff = diff.ezt
+#directory = directory.ezt
### an alternative directory view
-#directory = templates/dir_new.ezt
-#error = templates/error.ezt
-#graph = templates/graph.ezt
-#log = templates/log.ezt
+#directory = dir_new.ezt
+#error = error.ezt
+#file = file.ezt
+#graph = graph.ezt
+#log = log.ezt
### a table-based alternative log view
-#log = templates/log_table.ezt
-#markup = templates/markup.ezt
-#query = templates/query.ezt
-#query_form = templates/query_form.ezt
-#query_results = templates/query_results.ezt
-#revision = templates/revision.ezt
-#roots = templates/roots.ezt
+#log = log_table.ezt
+#query = query.ezt
+#query_form = query_form.ezt
+#query_results = query_results.ezt
+#revision = revision.ezt
+#roots = roots.ezt
#---------------------------------------------------------------------------
[cvsdb]
@@ -632,6 +600,17 @@
# to a conservative number.)
#rss_row_limit = 100
+# Check if the repository is found in the database before showing
+# the query link and RSS feeds. Set to 1 to enable check.
+#
+# WARNING: Enabling this check adds the cost of a database connection
+# and query to most ViewVC requests. If all your roots are represented
+# in the commits database, or if you don't care about the creation of
+# RSS and query links that might lead ultimately to error pages for
+# certain of your roots, or if you simply don't want to add this extra
+# cost to your ViewVC requests, leave this disabled.
+#check_database_for_root = 0
+
#---------------------------------------------------------------------------
[vhosts]
@@ -699,6 +678,27 @@
#---------------------------------------------------------------------------
+# ViewVC recognizes per-root configuration overrides, too. To
+# override the value of a configuration parameter only for a single
+# root, create a configuration section whose names is of the form
+# root-ROOTNAME/CONFIGSECTION. ROOTNAME here is the name of the root
+# as defined explicitly in cvs_roots or svn_roots or implicitly as the
+# basename of a root path in root_parents. Options found in this new
+# configuration section override for this one root the corresponding
+# options found in the base configuration section CONFIGSECTION
+# ("options", "authz-*", etc.)
+#
+# Here is an example showing how to enable Subversion authz-based
+# authorization for only the single root named "svnroot":
+#
+# [root-svnroot/options]
+# authorizer = svnauthz
+#
+# [root-svnroot/authz-svnauthz]
+# authzfile = /path/to/authzfile
+#
+
+#---------------------------------------------------------------------------
[authz-forbidden]
# The "forbidden" authorizer forbids access to repository modules,
@@ -745,6 +745,49 @@
forbidden =
#---------------------------------------------------------------------------
+[authz-forbiddenre]
+
+# The "forbiddenre" authorizer forbids access to repositories and
+# repository paths by comparing a list of regular expressions
+# (separated by commas) against paths consisting of the repository (or
+# root) name plus the path of the versioned file or directory to be
+# tested. For example, to see if the user is authorized to see the
+# path "/trunk/www/index.html" in the repository whose root name is
+# "svnrepos", this authorizer will check the path
+# "svnrepos/trunk/www/index.html" against the list of forbidden
+# regular expressions. Directory paths will be terminated by a forward
+# slash.
+#
+# Like the "forbidden" authorizer...
+#
+# *) The "!" can be used before a module to explicitly state that it
+# is NOT forbidden. Whenever this form is seen, then all modules will
+# be forbidden unless one of the "!" modules match.
+#
+# *) Tests are performed in sequence. The first match will terminate the
+# testing. This allows for more complex allow/deny patterns.
+#
+# Unlike the "forbidden" authorizer, you can can use this to hide roots, too.
+#
+# Some examples:
+#
+# Disallow files named "PRIVATE", but allow all others:
+# forbiddenre = /PRIVATE$
+#
+# Disallow the "hidden" repository, allowing all others:
+# forbiddenre = ^hidden(/|$)
+#
+# Allow only the "example1" and "example2" roots and the paths inside them,
+# disallowing all others (which can be done in multiple ways):
+# forbiddenre = !^example1(/|$), !^example2(/|$)/
+# forbiddenre = !^example[12](/|$)
+#
+# Only allow visibility of HTML files and the directories that hold them:
+# forbiddenre = !^([^/]+|.*(/|\.html))$
+#
+forbiddenre =
+
+#---------------------------------------------------------------------------
[authz-svnauthz]
# The "svnauthz" authorizer uses a Subversion authz configuration file
Modified: trunk/viewvc.org/contact.html
==============================================================================
--- trunk/viewvc.org/contact.html (original)
+++ trunk/viewvc.org/contact.html Mon Nov 3 09:57:02 2008
@@ -1,10 +1,11 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
+<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>ViewVC: Contact</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" type="text/css" href="./styles.css"/>
+<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
</head>
<body>
@@ -61,19 +62,25 @@
these lists (and other project lists), as well view the list
archives, <a
href="http://viewvc.tigris.org/servlets/ProjectMailingListList"
- >here</a>.</p>
+ >here</a>. If you are having problems with ViewVC, consider
+ checking our <a href="./faq.html">Frequently Asked Questions</a>
+ page and list of <a
+ href="http://viewvc.tigris.org/issues/buglist.cgi?component=viewvc&issue_status=UNCONFIRMED&issue_status=NEW&issue_status=STARTED&issue_status=REOPENED"
+ >open issues</a> before mail our users@ list — perhaps the
+ information you need is already available in one of those
+ places.</p>
-<p>If you're seeking interaction that's a little more real-time, use
- your favorite IRC client to pop into <tt><a
+<p>If you prefer interaction that's a little more real-time, use your
+ favorite IRC client to pop into <tt><a
href="irc://irc.freenode.net/viewvc">#viewvc</a></tt> on
irc.freenode.net.</p>
<p>So, to summarize:</p>
<ul>
-<li>Email, developer chatter — dev@viewvc.tigris.org</li>
-<li>Email, user chatter — users@viewvc.tigris.org</li>
-<li>IRC — irc.freenode.net, #viewvc</li>
+<li>To discuss ViewVC installation, configuration, and behavior: users@viewvc.tigris.org</li>
+<li>To discuss the development of ViewVC itself or submit patches: dev@viewvc.tigris.org</li>
+<li>To discussion anything ViewVC-related in real time: irc.freenode.net, #viewvc</li>
</ul>
</div> <!-- section-body -->
Modified: trunk/viewvc.org/contributing.html
==============================================================================
--- trunk/viewvc.org/contributing.html (original)
+++ trunk/viewvc.org/contributing.html Mon Nov 3 09:57:02 2008
@@ -1,10 +1,11 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
+<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>ViewVC: Contributing</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" type="text/css" href="./styles.css"/>
+<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
</head>
<body>
Modified: trunk/viewvc.org/download.html
==============================================================================
--- trunk/viewvc.org/download.html (original)
+++ trunk/viewvc.org/download.html Mon Nov 3 09:57:02 2008
@@ -1,10 +1,11 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
+<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>ViewVC: Download</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" type="text/css" href="./styles.css"/>
+<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
</head>
<body>
@@ -74,7 +75,7 @@
<p>The source code for ViewVC is maintained in a Subversion repository
at Tigris.org. You can checkout the trunk of our development tree
from <a href="http://viewvc.tigris.org/svn/viewvc/trunk/"
- ><tt>http://viewvc.tigris.org/svn/viewvc/trunk/</tt></a>. You'll
+ >http://viewvc.tigris.org/svn/viewvc/trunk/</a>. You'll
need to provide your Tigris.org username and password when so
prompted, or, if you don't have a Tigris.org account, use "guest"
as the username (with no, or an empty, password).</p>
Modified: trunk/viewvc.org/faq.html
==============================================================================
--- trunk/viewvc.org/faq.html (original)
+++ trunk/viewvc.org/faq.html Mon Nov 3 09:57:02 2008
@@ -1,10 +1,11 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
+<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>ViewVC: Frequently Asked Questions (FAQ)</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" type="text/css" href="./styles.css"/>
+<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
</head>
<body>
@@ -45,26 +46,23 @@
</td>
<td id="pagecolumn2">
-<div class="notice">
-<p>This FAQ is, shall we say, a work in progress. At the moment, it's
- pretty bare. Please bare — er, <strong>bear</strong> with us
- as we slowly populate this document.</p>
-</div>
-
<div class="section">
-<!-- ###################################################################### -->
+<!-- ##################################################################### -->
<h2 id="faq-q">Questions</h2>
-<!-- ###################################################################### -->
+<!-- ##################################################################### -->
<div class="section-body">
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
<h3 class="faq-section" id="faq-q-general">General Usage</h3>
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
<ul>
+<li><a href="#installation">Where does the installation documentation,
+ if any, live?</a></li>
+
<li><a href="#authz-support">Does ViewVC support path-based
authorization, such as Subversion's authz-file mechanism?</a></li>
@@ -80,9 +78,9 @@
</ul>
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
<h3 class="faq-section" id="faq-q-cvs">CVS Browsing</h3>
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
<ul>
@@ -92,7 +90,8 @@
<li><a href="#comalformedoutput">What causes "Error: COMalformedOutput: Unable to
find filename in co output stream"?</a></li>
-<li><a href="#">What causes "Error: error during rlog: 0x100"?</a></li>
+<li><a href="#error-during-rlog">What causes "Error: error during
+ rlog: 0x100"?</a></li>
<li><a href="#missing-files">Why do my directories have no files in them?</a></li>
@@ -102,9 +101,9 @@
</ul>
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
<h3 class="faq-section" id="faq-q-svn">Subversion Browsing</h3>
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
<ul>
@@ -116,21 +115,37 @@
</ul>
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
</div>
</div>
<div class="section">
-<!-- ###################################################################### -->
+<!-- ##################################################################### -->
<h2 id="faq-a">Answers</h2>
-<!-- ###################################################################### -->
+<!-- ##################################################################### -->
<div class="section-body">
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
<h3 class="faq-section" id="faq-a-general">General Usage</h3>
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
+
+<div id="installation">
+<p class="faq-atitle">Where does the installation documentation, if
+ any, live?</p>
+
+<p>ViewVC's installation how-to documentation lives in the INSTALL
+ file located in the root of the ViewVC source code distribution.
+ The most recent version of this document (which may cover
+ unreleased ViewVC versions) can be found
+ at <a href="http://viewvc.tigris.org/source/browse/*checkout*/viewvc/trunk/INSTALL"
+ >http://viewvc.tigris.org/source/browse/*checkout*/viewvc/trunk/INSTALL</a>.
+ If you are upgrading an existing ViewVC instance, you'll also want
+ to read the upgrade documentation, found
+ at <a href="http://viewvc.tigris.org/source/browse/*checkout*/viewvc/trunk/docs/upgrading-howto.html"
+ >http://viewvc.tigris.org/source/browse/*checkout*/viewvc/trunk/docs/upgrading-howto.html</a>.</p>
+</div>
<div id="authz-support">
<p class="faq-atitle">Does ViewVC support path-based authorization,
@@ -204,9 +219,9 @@
additional configuration.</p>
</div>
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
<h3 class="faq-section" id="faq-a-cvs">CVS Browsing</h3>
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
<div id="rlog-output-ended-early">
@@ -235,7 +250,7 @@
</div>
-<div id="">
+<div id="error-during-rlog">
<p class="faq-atitle">What causes "Error: error during rlog:
0x100"?</p>
@@ -251,7 +266,11 @@
<ul>
<li>Some folks mistakenly point ViewVC's configuration bits to their
CVS working copies. But ViewVC isn't a working copy browser
- — it's a <em>repository</em> browser.</li>
+ — it's a <em>repository</em> browser. If you don't know
+ the difference, here's a tip that might help: CVS repositories
+ are directories trees filled with files that end with
+ "<code>,v</code>". If your directory isn't filled with "comma
+ vee" files, it probably is <em>not</em> a CVS repository.</li>
<li>… <!-- TODO --></li>
</ul>
</div>
@@ -268,11 +287,12 @@
solution is to try to get versions of CVS/CVSNT and ViewVC which
are better aligned, which generally means upgrading ViewVC (which
is probably less disruptive than downgrading your version control
- system).</p> </div>
+ system).</p>
+</div>
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
<h3 class="faq-section" id="faq-a-svn">Subversion Browsing</h3>
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
<div id="no-module-named-svn">
<p class="faq-atitle">What causes "Error: ImportError: No module named
@@ -323,10 +343,10 @@
the remote repository aren't cached in
<code>~VIEWVC_USER/.subversion</code> (where
<code>VIEWVC_USER</code> is the system user as whom ViewVC
- runs), stuff won't work.</p>
+ runs), stuff won't work.</p></li>
</ul>
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
</div>
</div>
Modified: trunk/viewvc.org/images/title.jpg
==============================================================================
Binary files. No diff available.
Modified: trunk/viewvc.org/images/title.xcf
==============================================================================
Binary files. No diff available.
Modified: trunk/viewvc.org/index.html
==============================================================================
--- trunk/viewvc.org/index.html (original)
+++ trunk/viewvc.org/index.html Mon Nov 3 09:57:02 2008
@@ -1,10 +1,11 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
+<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>ViewVC: Repository Browsing</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" type="text/css" href="./styles.css"/>
+<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
</head>
<body>
@@ -75,10 +76,7 @@
href="http://www.akhphd.au.dk/~bertho/cvsgraph/">CvsGraph</a>)
(<em>CVS only</em>).</li>
- <li>Syntax highlighting support (via integration with <a
- href="http://www.codento.com/people/mtr/genscript/">GNU
- enscript</a> or
- <a href="http://www.andre-simon.de/">Highlight</a>).</li>
+ <li>Syntax highlighting support.</li>
<li><a href="http://www.mozilla.org/projects/bonsai/">Bonsai</a>-like
repository query facilities.</li>
Modified: trunk/viewvc.org/nightly/build-viewvc-snapshot
==============================================================================
--- trunk/viewvc.org/nightly/build-viewvc-snapshot (original)
+++ trunk/viewvc.org/nightly/build-viewvc-snapshot Mon Nov 3 09:57:02 2008
@@ -1,37 +1,119 @@
-#!/bin/sh
+#!/usr/bin/env python
-DATE=`date +"%Y%m%d"`
-EXPORTDIR="viewvc-${DATE}"
-PUBLISH_DIR=/www/viewvc/nightly
-
-# export HEAD of trunk
-svn export --quiet http://viewvc.tigris.org/svn/viewvc/trunk ${EXPORTDIR} --username guest --password ""
-
-# use Python to determine the version number, reading it from
-# viewvc.__version__
-cd $EXPORTDIR/lib
-VERSION=`python -c "import viewvc; print viewvc.__version__"`
-TARGET=viewvc-${VERSION}-${DATE}
-
-# make a release
-cd ../tools
-./make-release ${TARGET}
-
-# remove results of last build
-rm -rf ${PUBLISH_DIR}/viewvc*.tar.gz ${PUBLISH_DIR}/viewvc*.zip ${PUBLISH_DIR}/index.html
-
-# publish new build
-mv ${TARGET}.* ${PUBLISH_DIR}
-cd ../..
+import sys
+import os
+import time
+import urllib
+import shutil
+import getopt
+import tempfile
+
+
+class BuildError(Exception):
+ def __init__(self, message):
+ self.message = message
+ def __str__(self):
+ return self.message
+
+
+def make_release(branch, export_dir, publish_dir, root_url, username, password):
+
+ # Export the requested ViewVC source tree.
+ cmd = "svn export --quiet '%s/%s' %s " \
+ "--username '%s' --password '%s' --non-interactive --force" \
+ % (root_url, urllib.quote(branch), export_dir, username, password)
+ sys.stdout.write("Running: %s\n" % (cmd))
+ os.system(cmd)
+
+ # Get the version number from ViewVC itself.
+ sys.path.insert(0, os.path.join(export_dir, 'lib'))
+ try:
+ import viewvc
+ except ImportError:
+ raise BuildError("Unable to import viewvc module; export failed?")
+ version = viewvc.__version__
+ del sys.modules['viewvc']
+ del viewvc
+ del sys.path[0]
+
+ # Now, use ViewVC tools to make the distribution archives.
+ localtime = time.localtime()
+ date = "%4d%02d%02d" % (localtime[0], localtime[1], localtime[2])
+ distversion = "viewvc-%s" % (version)
+ distname = "%s-%s" % (distversion, date)
+ gzip_name = distname + '.tar.gz'
+ zip_name = distname + '.zip'
+ curdir = os.getcwd()
+ try:
+ os.chdir(os.path.join(export_dir, 'tools'))
+ os.system('./make-release %s' % (distname))
+ finally:
+ os.chdir(curdir)
+
+ # Finally, return the locations of the archive files we've built.
+ gzip_file = os.path.join(export_dir, 'tools', gzip_name)
+ if not os.path.exists(gzip_file):
+ gzip_file = None
+ zip_file = os.path.join(export_dir, 'tools', zip_name)
+ if not os.path.exists(zip_file):
+ zip_file = None
+
+ # Remove superceded archives.
+ if gzip_file or zip_file:
+ dirents = os.listdir(publish_dir)
+ for dirent in dirents:
+ if dirent.startswith(distversion) \
+ and ((dirent.endswith('.tar.gz') and gzip_file) \
+ or (dirent.endswith('.zip') and zip_file)):
+ os.unlink(dirent)
+
+ # Install the new archives.
+ if gzip_file:
+ os.rename(gzip_file, os.path.join(publish_dir, gzip_name))
+ if zip_file:
+ os.rename(zip_file, os.path.join(publish_dir, zip_name))
+
+ # Return our archive names.
+ return gzip_file and gzip_name or None, zip_file and zip_name or None
+
+
+def publish_releases(branches, publish_dir, root_url, username, password):
+ new_index_contents = get_html_index_header()
+ for branch in branches:
+ sys.stdout.write("Beginning build for branch '%s'.\n" % (branch))
+ export_dir = None
+ try:
+ export_dir = tempfile.mkdtemp("", "viewvc-nightly-")
+ gzip_file, zip_file = make_release(branch, export_dir, publish_dir,
+ root_url, username, password)
+ new_index_contents = new_index_contents + """
+<p>Build of %s:</p>
+<ul>
+<li><a href="%s">%s</a></li>
+<li><a href="%s">%s</a></li>
+</ul>
+""" % (branch, urllib.quote(gzip_file), gzip_file,
+ urllib.quote(zip_file), zip_file)
+ finally:
+ if export_dir:
+ sys.stdout.write("Removing temporary directory '%s'.\n" % (export_dir))
+ shutil.rmtree(export_dir)
+ sys.stdout.write("Finished build for branch '%s'.\n" % (branch))
+
+ new_index_contents = new_index_contents + get_html_index_footer()
+ open(os.path.join(publish_dir, 'index.html'), 'w').write(new_index_contents)
+
-cat > ${PUBLISH_DIR}/index.html <<EOF
+def get_html_index_header():
+ return """
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
+<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>ViewVC: Nightly Snapshots</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" type="text/css" href="../styles.css"/>
+<link rel="shortcut icon" href="../favicon.ico" type="image/x-icon" />
</head>
<body>
@@ -60,7 +142,7 @@
<h4>On this page:</h4>
<ul id="bookmarks">
- <li><a href="#sec-snapshots">Snapshots</a></li>
+ <li><a href="%s">Snapshots</a></li>
</ul>
<p><a href="http://validator.w3.org/check?uri=referer"><img
@@ -72,19 +154,13 @@
<td id="pagecolumn2">
<div class="section">
-
<h2 id="sec-snapshots">Snapshots</h2>
-
<div class="section-body">
-<ul>
-EOF
+""" % ("#sec-snapshots")
-echo "<li><a href=\"${TARGET}.tar.gz\">${TARGET}.tar.gz</a></li>" >> ${PUBLISH_DIR}/index.html
-echo "<li><a href=\"${TARGET}.zip\">${TARGET}.zip</a></li>" >> ${PUBLISH_DIR}/index.html
-
-cat >> ${PUBLISH_DIR}/index.html <<EOF
-</ul>
+def get_html_index_footer():
+ return """
</div> <!-- section-body -->
</div> <!-- section -->
@@ -93,7 +169,51 @@
</table>
</body>
</html>
-EOF
+"""
+
-# more cleanup
-rm -rf ${EXPORTDIR}
+def usage_and_exit(errmsg=None):
+ stream = errmsg and sys.stderr or sys.stdout
+ progname = os.path.basename(sys.argv[0])
+ stream.write("""%s -- nightly ViewVC build generation
+
+Usage: %s [OPTIONS] PUBLISH-DIR BRANCH ...
+
+Build an archive from one or more BRANCH in the ViewVC source
+repository, dropping them into PUBLISH-DIR alongside an index.html
+file that name and links to them.
+
+Options:
+ --help (-h, -?) : Show this usage message
+ --username : Username used for source export
+ --password : Password used for source export
+ --root-url : Alternative source repository root URL
+
+""" % (progname, progname))
+ if errmsg:
+ stream.write("ERROR: %s\n" % (errmsg))
+ sys.exit(errmsg and 1 or 0)
+
+
+if __name__ == "__main__":
+ root_url = "http://viewvc.tigris.org/svn/viewvc"
+ username = password = ""
+ opts, args = getopt.getopt(sys.argv[1:], 'h?',
+ ['help', 'username=', 'password=', 'root-url='])
+ for name, value in opts:
+ if name == '-h' or name == '-?' or name == '--help':
+ usage_and_exit()
+ elif name == '--username':
+ username = value
+ elif name == '--password':
+ password = value
+ elif name == '--root-url':
+ root_url = value
+ argc = len(args)
+ if argc < 2:
+ usage_and_exit("Not enough arguments")
+ try:
+ publish_releases(args[1:], args[0], root_url, username, password)
+ except BuildError, e:
+ sys.stderr.write(str(e) + "\n")
+ sys.exit(1)
Modified: trunk/viewvc.org/styles.css
==============================================================================
--- trunk/viewvc.org/styles.css (original)
+++ trunk/viewvc.org/styles.css Mon Nov 3 09:57:02 2008
@@ -1,15 +1,13 @@
body {
- background-color: rgb(180,193,205);
- background-image: url('./images/bg-grad.jpg');
- background-repeat: repeat-x;
+ background-color: #b2d388;
color: black;
font-family: trebuchet ms, arial, sans-serif;
margin: 0;
}
#title {
- background-color: rgb(100,128,150);
- height: 60px;
+ background-color: #739c3e;
+ height: 70px;
}
img {
@@ -27,7 +25,7 @@
}
h2 {
- background-color: rgb(204,213,221);
+ background-color: #94bd5e;
padding: 2px 0.5em 2px 0.5em;
margin: 0;
border-bottom: dotted 1px rgb(180,193,205);
Modified: trunk/viewvc.org/who.html
==============================================================================
--- trunk/viewvc.org/who.html (original)
+++ trunk/viewvc.org/who.html Mon Nov 3 09:57:02 2008
@@ -1,10 +1,11 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
+<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>ViewVC: About</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" type="text/css" href="./styles.css"/>
+<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
</head>
<body>
@@ -166,9 +167,9 @@
<p>The ViewVC website was designed by <a
href="http://www.cmichaelpilato.com/">C. Michael Pilato</a>. All
HTML was hand-edited in Emacs, and the little splashes of graphical
- goodness owe their existence to Adobe PhotoShop. Textual content
- for the site is mostly the work of Greg Stein, but has been tweaked
- through the ages by various ViewVC contributors.</p>
+ goodness owe their existence to Open Office and the Gimp. Textual
+ content for the site is mostly the work of Greg Stein, but has been
+ tweaked through the ages by various ViewVC contributors.</p>
</div> <!-- section-body -->
</div> <!-- section -->
Modified: trunk/windows/README
==============================================================================
--- trunk/windows/README (original)
+++ trunk/windows/README Mon Nov 3 09:57:02 2008
@@ -1,301 +1,324 @@
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DESCRIPTION
-This file contains special instructions for setting up ViewVC on Windows. It
-will take you through a basic installation and tell you how to set up optional
-features like code colorizing and the MySQL commit database.
+This file contains special instructions for setting up ViewVC on
+Windows. It will take you through a basic installation and tell you
+how to set up optional features like code colorizing and the MySQL
+commit database.
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
REQUIREMENTS
ViewVC requires the Python interpreter which you can download from
- http://python.org/
+ http://python.org/
and the Python for Windows Extensions which are at
- http://sourceforge.net/projects/pywin32/
+ http://sourceforge.net/projects/pywin32/
-For CVS support, ViewVC also requires that the CVSNT client (cvs.exe) OR the
-RCS tools (rlog.exe, rcsdiff.exe, and co.exe) be installed on your computer.
-CVSNT is available from
+For CVS support, ViewVC also requires that the CVSNT client (cvs.exe)
+OR the RCS tools (rlog.exe, rcsdiff.exe, and co.exe) be installed on
+your computer. CVSNT is available from
- http://www.cvsnt.org/wiki
+ http://www.cvsnt.org/wiki
and RCS can be obtained from:
- http://www.cs.purdue.edu/homes/trinkle/RCS/
+ http://www.cs.purdue.edu/homes/trinkle/RCS/
-For Subversion support, you'll need to have the Subversion Python bindings
-installed. Binaries are available from the Subversion website at:
+For Subversion support, you'll need to have the Subversion Python
+bindings installed. Binaries are available from the Subversion website
+at:
- http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91
+ http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91
-Note that if you use binaries, you have to be running the same version of
-python as the binaries were built for. For example, you cannot use Subversion
-bindings built for Python 2.3 with Python 2.4. Instructions for building
-the binaries from source are available here:
+Note that if you use binaries, you have to be running the same version
+of python as the binaries were built for. For example, you cannot use
+Subversion bindings built for Python 2.3 with Python 2.4. Instructions
+for building the binaries from source are available here:
- http://svn.collab.net/repos/svn/trunk/subversion/bindings/swig/INSTALL
+ http://svn.collab.net/repos/svn/trunk/subversion/bindings/swig/INSTALL
-The Subversion bindings also require you to have diff.exe installed in a
-directory on your system PATH. diff.exe is available as part of the GnuWin32
-project's DiffUtils package at http://gnuwin32.sf.net/.
+The Subversion bindings also require you to have diff.exe installed in
+a directory on your system PATH. diff.exe is available as part of the
+GnuWin32 project's DiffUtils package at http://gnuwin32.sf.net/.
-Once you've got Python and CVSNT or RCS or the Subversion bindings installed,
-you can test out ViewVC before you install it by running:
+Once you've got Python and CVSNT or RCS or the Subversion bindings
+installed, you can test out ViewVC before you install it by running:
- python bin\standalone.py -r <PATH_TO_REPOSITORY>
+ python bin\standalone.py -r <PATH_TO_REPOSITORY>
-The standalone server has a number of features (including a GUI interface)
-which you can find out about by running
+The standalone server has a number of features (including a GUI
+interface) which you can find out about by running
- python bin\standalone.py --help
+ python bin\standalone.py --help
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BASIC INSTALLATION
Run the ViewVC install script with
- python viewvc-install
+ python viewvc-install
-The script will copy the source files into an installation directory that you
-specify, store some path information, and compile the ViewVC library files into
-Python bytecode.
-
-After the installation is finished you will need to edit the viewvc.conf file
-in the folder you installed to. The comments in that file tell you exactly what
-to do.
-
-With the config file set up you should be able to double-click standalone.py
-and access your repository with a web browser.
-
-See the sections below for information on setting up optional features and
-troubleshooting. From here on <PYTHON_DIR> will stand for the Python root
-directory (usually something like C:\Python22) and <VIEWVC_INSTALL_DIR> will
-represent the directory where ViewVC has been installed to (default is
-C:\Program Files\viewvc-VERSION).
+The script will copy the source files into an installation directory
+that you specify, store some path information, and compile the ViewVC
+library files into Python bytecode.
+
+After the installation is finished you will need to edit the
+viewvc.conf file in the folder you installed to. The comments in that
+file tell you exactly what to do.
+
+With the config file set up you should be able to double-click
+standalone.py and access your repository with a web browser.
+
+See the sections below for information on setting up optional features
+and troubleshooting. From here on <PY_DIR> will stand for the Python
+root directory (usually something like C:\Python22) and
+<VIEWVC_INSTALL_DIR> will represent the directory where ViewVC has
+been installed to (default is C:\Program Files\viewvc-VERSION).
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SERVER CONFIGURATION
-If you want to make ViewVC available to a network (rather than using it on a
-standalone machine), you will need to configure a web server to host it. This
-section includes instructions for setting up ViewVC on two commonly used
-Windows web servers, IIS and Apache.
-
-With IIS, you can run ViewVC in CGI mode or ASP mode (or both modes). ASP mode
-gives better performance (faster page loads), but is harder to set up and may
-be less stable. CGI mode is stable and easy to set up but slower.
+If you want to make ViewVC available to a network (rather than using
+it on a standalone machine), you will need to configure a web server
+to host it. This section includes instructions for setting up ViewVC
+on two commonly used Windows web servers, IIS and Apache.
+
+With IIS, you can run ViewVC in CGI mode or ASP mode (or both
+modes). ASP mode gives better performance (faster page loads), but is
+harder to set up and may be less stable. CGI mode is stable and easy
+to set up but slower.
-On Apache, you can use CGI mode or Mod_Python mode or both modes at once.
-Mod_Python mode is faster than CGI mode.
+On Apache, you can use CGI mode or Mod_Python mode or both modes at
+once. Mod_Python mode is faster than CGI mode.
CGI Mode On IIS
- 1) Copy viewvc.cgi and query.cgi from <VIEWVC_INSTALL_DIR>\bin\cgi to a
- folder that is accessible through your web server.
+ 1) Copy viewvc.cgi and query.cgi from <VIEWVC_INSTALL_DIR>\bin\cgi to a
+ folder that is accessible through your web server.
- 2) Start up the IIS "Internet Services Manager" and right click a virtual
- server or virtual directory that contains the files you just copied. Choose
- "Properties" from the context menu that appears.
-
- 3) On the properties dialog that appears, navigate to [Home | Virtual]
- Directory -> Application Settings -> Configuration. This will bring up
- another dialog box called "Application Configuration".
-
- 4) On the "App Mappings" tab choose "Add". Fill in the following information
-
- Executable: <PYTHON_DIR>\python.exe "%s"
- Extension: cgi
- Script Engine: checked
- Check that file exists: unchecked
-
- That is all. Assuming you've set up viewvc.conf to point to your
- repositories, the CGI pages should run. See the Troubleshooting section below
- if there are any problems.
+ 2) Start up the IIS "Internet Services Manager" and right click a
+ virtual server or virtual directory that contains the files you
+ just copied. Choose "Properties" from the context menu that
+ appears.
+
+ 3) On the properties dialog that appears, navigate to [Home |
+ Virtual] Directory -> Application Settings ->
+ Configuration. This will bring up another dialog box called
+ "Application Configuration".
+
+ 4) On the "App Mappings" tab choose "Add". Fill in the following
+ information:
+
+ Executable: <PY_DIR>\python.exe "%s"
+ Extension: cgi
+ Script Engine: checked
+ Check that file exists: unchecked
+
+ That is all. Assuming you've set up viewvc.conf to point to your
+ repositories, the CGI pages should run. See the Troubleshooting
+ section below if there are any problems.
ASP Mode On IIS
- In order to run ViewVC with ASP, you will need to enable Python ActiveX
- scripting and to install the included Aspfool ISAPI filter on whatever
- virtual server is being used to serve the viewvc pages. Step by step
- instructions follow below. Aspfool is located in the windows\aspfool folder.
-
- To set up ASP mode, follow these steps:
-
- 1) Run <PYTHON_DIR>\Lib\site-packages\win32comext\axscript\client\pyscript.py
- to register Python as an ASP scripting language. (More documentation on this
- is at http://www.python.org/windows/win32com/ActiveXScripting.html)
-
- 2) Copy the viewvc.asp and query.asp files from
- <VIEWVC_INSTALL_DIR>\bin\asp to a folder that is accessible through your web
- server.
+ In order to run ViewVC with ASP, you will need to enable Python
+ ActiveX scripting and to install the included Aspfool ISAPI filter
+ on whatever virtual server is being used to serve the viewvc
+ pages. Step by step instructions follow below. Aspfool is located
+ in the windows\aspfool folder.
+
+ To set up ASP mode, follow these steps:
+
+ 1) Run <PY_DIR>\Lib\site-packages\win32comext\axscript\client\pyscript.py
+ to register Python as an ASP scripting language. (More
+ documentation on this is at
+ http://www.python.org/windows/win32com/ActiveXScripting.html)
+
+ 2) Copy the viewvc.asp and query.asp files from
+ <VIEWVC_INSTALL_DIR>\bin\asp to a folder that is accessible
+ through your web server.
+
+ 3) Start up the IIS "Internet Services Manager" and right click on
+ the virtual server that contains the files you just
+ copied. Choose "Properties" from the context menu that appears.
+
+ 4) On the properties dialog that appears, click the "ISAPI Filters"
+ tab. Click the "add" button and enter the following
+ information:
- 3) Start up the IIS "Internet Services Manager" and right click on the
- virtual server that contains the files you just copied. Choose "Properties"
- from the context menu that appears.
+ Filter Name: aspfool
+ Executable: aspfool.dll
- 4) On the properties dialog that appears, click the "ISAPI Filters" tab.
- Click the "add" button and enter the following information:
-
- Filter Name: aspfool
- Executable: aspfool.dll
-
- After you save these changes, the ViewVC ASP pages should begin to work.
+ After you save these changes, the ViewVC ASP pages should begin to
+ work.
CGI Mode on Apache
- Follow the instructions under "Apache Configuration" in the ViewVC INSTALL
- file.
+ Follow the instructions under "Apache Configuration" in the ViewVC
+ INSTALL file.
Mod_Python Mode on Apache
- There are probably ten thousand different ways to set up Apache, mod_python,
- and ViewVC together. Here are some instructions that work for me using
- Mod_Python 3.0.3 and Apache 2.0.46. If any Apache gurus want to contribute
- better instructions, I'd be happy to include them here.
-
- 1) Run the win32 mod_python installer from www.modpython.org.
-
- 2) Add the following line to the "Global Environment" section of httpd.conf
+ There are probably ten thousand different ways to set up Apache,
+ mod_python, and ViewVC together. Here are some instructions that
+ work for me using Mod_Python 3.0.3 and Apache 2.0.46. If any Apache
+ gurus want to contribute better instructions, I'd be happy to
+ include them here.
+
+ 1) Run the win32 mod_python installer from www.modpython.org.
+
+ 2) Add the following line to the "Global Environment" section of
+ httpd.conf:
+
+ LoadModule python_module modules/mod_python.so
+
+ 3) Copy viewvc.py, query.py, handler.py, and .htaccess from
+ <VIEWVC_INSTALL_DIR>\bin\mod_python to a folder being served by
+ apache. Make sure overrides are allowed in this folder. The
+ relevant parent directory in httpd.conf should have
+ "AllowOverride All" set, or at least "AllowOverride FileInfo
+ Options".
- LoadModule python_module modules/mod_python.so
-
- 3) Copy viewvc.py, query.py, handler.py, and .htaccess from
- <VIEWVC_INSTALL_DIR>\bin\mod_python to a folder being served by apache. Make
- sure overrides are allowed in this folder. The relevant parent directory in
- httpd.conf should have "AllowOverride All" set, or at least "AllowOverride
- FileInfo Options".
-
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ENSCRIPT HIGHLIGHTING
-To use enscript, you'll have to install the enscript, libintl, libiconv, and
-sed packages from the gnuwin32 project (http://gnuwin32.sourceforge.net/).
-Detailed instructions are on their site, but here is the basic procedure.
-
-1) Extract all packages to a folder on your hard drive, for example c:\gnuwin32
-
-2) Add "c:\gnuwin32\bin" to the system "PATH" environment variable. If ViewVC
-is running as part of a system service like IIS you will need to reboot the
-computer so it is able to see the value. See the "Troubleshooting" section
-below for specific information on when a reboot is neccessary.
+To use enscript, you'll have to install the enscript, libintl,
+libiconv, and sed packages from the gnuwin32 project
+(http://gnuwin32.sourceforge.net/). Detailed instructions are on
+their site, but here is the basic procedure.
+
+1) Extract all packages to a folder on your hard drive, for example
+ c:\gnuwin32
+
+2) Add "c:\gnuwin32\bin" to the system "PATH" environment variable. If
+ ViewVC is running as part of a system service like IIS you will
+ need to reboot the computer so it is able to see the value. See the
+ "Troubleshooting" section below for specific information on when a
+ reboot is neccessary.
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BONSAI-LIKE CHECKIN DATABASE
-To use the checkin database, you'll need to install MySQL and the MySQL-Python
-interface. MySQL can be downloaded from www.mysql.com. The MySql-Python adapter
-is available from http://sf.net/projects/mysql-python/. Make sure to grab the
-the latest version from the "Files" section. (The "Home Page" link takes you to
-an outdated page that only links to very old versions.) Both packages come with
-GUI installers. Once you have MySQL running and set up with a username and
-password, follow these instructions to set up ViewVC.
+To use the checkin database, you'll need to install MySQL and the
+MySQL-Python interface. MySQL can be downloaded from
+www.mysql.com. The MySql-Python adapter is available from
+http://sf.net/projects/mysql-python/. Make sure to grab the the latest
+version from the "Files" section. (The "Home Page" link takes you to
+an outdated page that only links to very old versions.) Both packages
+come with GUI installers. Once you have MySQL running and set up with
+a username and password, follow these instructions to set up ViewVC.
1) Open a command prompt and type these commands:
- cd /d <VIEWVC_INSTALL_DIR>
- python bin\make-database
+ cd /d <VIEWVC_INSTALL_DIR>
+ python bin\make-database
-The script that comes up will prompt you for the MySQL username and password
-(you should have created these during the MySQL installation), and the name of
-the database to create. The default database name "ViewVC" should be fine
-unless for some reason a database with that name already exists.
+ The script that comes up will prompt you for the MySQL username and
+ password (you should have created these during the MySQL
+ installation), and the name of the database to create. The default
+ database name "ViewVC" should be fine unless for some reason a
+ database with that name already exists.
-2) Enter the username, password, and database name into the [cvsdb] section of
-the <VIEWVC_INSTALL_DIR>\viewvc.conf file.
+2) Enter the username, password, and database name into the [cvsdb]
+ section of the <VIEWVC_INSTALL_DIR>\viewvc.conf file.
3) At the command prompt run
- python bin\cvsdbadmin rebuild <repository>
+ python bin\cvsdbadmin rebuild <REPOSITORY>
-where <repository> is the path to your CVS repository.
+ where <REPOSITORY> is the path to your CVS repository.
-4) If you want the checkin database to be dynamically updated with every
-checkin, add the following line to your CVSROOT/loginfo file:
+4) If you want the checkin database to be dynamically updated with
+ every checkin, add the following line to your CVSROOT/loginfo file:
- ALL python "<VIEWVC_INSTALL_DIR>\bin\loginfo-handler" %{sVv}
+ ALL python "<VIEWVC_INSTALL_DIR>\bin\loginfo-handler" %{sVv}
-If you decide not to enable dynamic updates, you can periodically refresh the
-database with "python bin\cvsdbadmin update <repository>"
+ If you decide not to enable dynamic updates, you can periodically
+ refresh the database with "python bin\cvsdbadmin update <REPOSITORY>"
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CVSGRAPH
-To use CvsGraph with ViewVC, just put cvsgraph.exe in a directory on your
-system PATH and set the use_cvsgraph option to 1 in your viewvc.conf file.
+To use CvsGraph with ViewVC, just put cvsgraph.exe in a directory on
+your system PATH and set the use_cvsgraph option to 1 in your
+viewvc.conf file.
The CvsGraph home page is http://www.akhphd.au.dk/~bertho/cvsgraph/.
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DOCROOT OPTIMIZATION
By default ViewVC serves up image and stylesheet files in
-<VIEWVC_INSTALL_DIR>\templates\docroot\ on its own instead of relying on the
-webserver to deliver them. This simplifies web server configuration, but is
-inefficient because it means the Python interpreter has to run each time one of
-these files is downloaded. This causes ViewVC pages to load more slowly,
-especially when ViewVC is running under CGI on Windows.
+<VIEWVC_INSTALL_DIR>\templates\docroot\ on its own instead of relying
+on the webserver to deliver them. This simplifies web server
+configuration, but is inefficient because it means the Python
+interpreter has to run each time one of these files is
+downloaded. This causes ViewVC pages to load more slowly, especially
+when ViewVC is running under CGI on Windows.
To make things more efficient, you can make the
-<VIEWVC_INSTALL_DIR>\templates\docroot directory available on your web server
-and then set the "docroot" value in viewvc.conf to point to the web address of
-the directory.
+<VIEWVC_INSTALL_DIR>\templates\docroot directory available on your web
+server and then set the "docroot" value in viewvc.conf to point to the
+web address of the directory.
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TROUBLESHOOTING
-- By far the most common cause of errors in ViewVC is failure to successfully
- execute the programs it depends on (cvs, rlog, rcsdiff, co, enscript, sed,
- and cvsgraph). To help deal with this problem, ViewVC includes a special
- debugging mode that displays output from the programs it executes on every
- web page. This allows you to see error messages and other information that
- isn't normally visible. To enable the debugging mode, change line 23 of
+- By far the most common cause of errors in ViewVC is failure to
+ successfully execute the programs it depends on (cvs, rlog, rcsdiff,
+ co, enscript, sed, and cvsgraph). To help deal with this problem,
+ ViewVC includes a special debugging mode that displays output from
+ the programs it executes on every web page. This allows you to see
+ error messages and other information that isn't normally visible. To
+ enable the debugging mode, change line 23 of
<VIEWVC_INSTALL_DIR>\lib\debug.py from:
- SHOW_CHILD_PROCESSES = 0
+ SHOW_CHILD_PROCESSES = 0
to:
- SHOW_CHILD_PROCESSES = 1
+ SHOW_CHILD_PROCESSES = 1
- Important: You may need to restart your web server before this change takes
- effect. See "Changes made to..." later in this section.
+ Important: You may need to restart your web server before this
+ change takes effect. See "Changes made to..." later in this section.
- If you see the following error:
- error: (2, 'CreateProcess', The system cannot find the file specified.')
+ error: (2, 'CreateProcess', The system cannot find the file specified.')
- it means that a program ViewVC has tried to execute could not be found by
- Windows. The fix to this is usually to install the program if it isn't
- already installed or to update the path to the program in viewvc.conf.
- Enabling the SHOW_CHILD_PROCESSES mode as described above can provide helpful
- diagnostic information such as the command line ViewVC is using to invoke the
- program and the value of the PATH environment variable in the environment
- ViewVC is running under.
-
-- A common cause of server errors under IIS is permissions problems. You need
- to make sure that the virtual directory containing the CGI or ASP files has
- script execution enabled. You also need to make sure that the web server user
- accounts (IUSR_machine_name and IWAM_machine_name, where machine_name is your
- computer name) have read and execute access to the .asp or .cgi stub scripts,
- the ViewVC lib/ folder, the paths where external tools like cvs, rcs,
- enscript, sed, and cvsgraph live, and the CVS repositories. NTFS auditing
- makes it very easy to track down permissions problems. Also look for IIS
- messages in the event log.
-
-- Certain Apache configurations may hide some environment variables from the
- ViewVC CGI scripts and the programs they launch. You can see whether an
- environment variable is visible from the CGI environment by enabling the
- SHOW_CHILD_PROCESSES debug mode described above. You can force Apache to let
- variables through with the PassEnv directive
+ it means that a program ViewVC has tried to execute could not be
+ found by Windows. The fix to this is usually to install the program
+ if it isn't already installed or to update the path to the program
+ in viewvc.conf. Enabling the SHOW_CHILD_PROCESSES mode as described
+ above can provide helpful diagnostic information such as the command
+ line ViewVC is using to invoke the program and the value of the PATH
+ environment variable in the environment ViewVC is running under.
+
+- A common cause of server errors under IIS is permissions
+ problems. You need to make sure that the virtual directory
+ containing the CGI or ASP files has script execution enabled. You
+ also need to make sure that the web server user accounts
+ (IUSR_machine_name and IWAM_machine_name, where machine_name is your
+ computer name) have read and execute access to the .asp or .cgi stub
+ scripts, the ViewVC lib/ folder, the paths where external tools like
+ cvs, rcs, enscript, sed, and cvsgraph live, and the CVS
+ repositories. NTFS auditing makes it very easy to track down
+ permissions problems. Also look for IIS messages in the event log.
+
+- Certain Apache configurations may hide some environment variables
+ from the ViewVC CGI scripts and the programs they launch. You can
+ see whether an environment variable is visible from the CGI
+ environment by enabling the SHOW_CHILD_PROCESSES debug mode
+ described above. You can force Apache to let variables through with
+ the PassEnv directive
(http://httpd.apache.org/docs/mod/mod_env.html#passenv).
-- Changes made to environment variables, ViewVC source files and the ViewVC
- configuration file do not always take effect immediately. The table below
- shows what actions you need to take after changing any of these things before
- they will have an effect.
+- Changes made to environment variables, ViewVC source files and the
+ ViewVC configuration file do not always take effect immediately. The
+ table below shows what actions you need to take after changing any
+ of these things before they will have an effect.
+----------------+----------------+----------------+-------------------------+
| | Environment | ViewVC | ViewVC |
@@ -317,164 +340,182 @@
| | | | OR |
| | | | reload(viewvc) in stub |
+----------------+----------------+----------------+-------------------------+
- * If standalone.py was launched from a command prompt and you set the
- environment variable through the control panel, you'll need to open a new
- command prompt.
+ * If standalone.py was launched from a command prompt and you set
+ the environment variable through the control panel, you'll need to
+ open a new command prompt.
Notes:
- Under ASP, changes made to the stub scripts inside the web root do take
- effect immediately, you only need to take additional action when you make
- changes to the main source files in <VIEWVC_INSTALL_DIR>\lib
-
- To "Unload ASP App", go to the IIS properties dialog for the application
- directory containing the ViewVC .asp files (in Internet Services Manager).
- Switch to the [Home] | [Virtual] Directory tab and click the "Unload" button
- under "Application Settings".
+ Under ASP, changes made to the stub scripts inside the web root do
+ take effect immediately, you only need to take additional action
+ when you make changes to the main source files in <VIEWVC_INSTALL_DIR>\lib
+
+ To "Unload ASP App", go to the IIS properties dialog for the
+ application directory containing the ViewVC .asp files (in Internet
+ Services Manager). Switch to the [Home] | [Virtual] Directory tab
+ and click the "Unload" button under "Application Settings".
- To "reload(viewvc) in stub", put these lines in one of the ASP or Mod_Python
- stub scripts:
+ To "reload(viewvc) in stub", put these lines in one of the ASP or
+ Mod_Python stub scripts:
- import viewvc
- reload (viewvc)
+ import viewvc
+ reload (viewvc)
then load the page in a web browser.
-- If you have problems getting ViewVC to work with mod_python, you can first
- make sure mod_python works standalone with the testing instructions at
+- If you have problems getting ViewVC to work with mod_python, you can
+ first make sure mod_python works standalone with the testing
+ instructions at
http://www.modpython.org/live/current/doc-html/inst-testing.html.
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KNOWN ISSUES
- If you see ViewVC errors like
- Error parsing rlog output. Expected RCS file "c:\cvsroot\dir\file,v", found
- "c:\cvsroot\dir\RCS/file,v"
+ Error parsing rlog output. Expected RCS file
+ "c:\cvsroot\dir\file,v", found "c:\cvsroot\dir\RCS/file,v"
- it's because your RCS utilities don't recognize the RCS file suffix and are
- treating all files specified on the command line like working copies even
- when they end in ",v". You can fix this by including the following string in
- your RCSINIT environment variable:
+ it's because your RCS utilities don't recognize the RCS file suffix
+ and are treating all files specified on the command line like
+ working copies even when they end in ",v". You can fix this by
+ including the following string in your RCSINIT environment variable:
-x,v
- Important: You may need to reboot your computer before the environment
- variable has an effect. See "Changes made to..." in the TROUBLESHOOTING
- section.
-
-- The GNU RCS utilities won't work with repository files that use CVSNT's
- unicode expansion mode (-ku). Files that use this mode will show up with an
- "rlog error: unknown expand mode u" error message in ViewVC directory
- listings. To work around this, you can set up ViewVC to use the CVSNT
- executable (cvs.exe) or CVSNT RCS tools (co.exe, rlog.exe, and rcsdiff.exe)
- instead of the GNU tools.
-
-- The standalone server will not run under Cygwin Python because it does not
- support threads. ASP pages can't be run with Cygwin Python because it does
- not support ActiveX. To use either of these features you should install a
- native Python interpreter.
-
-- On Windows XP and Windows 2003 Server under IIS, enscript might give an error
- like:
-
- enscript: couldn't open input filter "states -f
- "K:/gnuwin32/share/enscript/hl/enscript.st" -p
- "C://.enscript;K:/gnuwin32/share/enscript/hl" -shtml -Dcolor=1
- -Dstyle=emacs -Dlanguage=html -Dnum_input_files=1
- -Ddocument_title="Enscript Output" -Dtoc=0 -" for file "": No error
- no output generated
+ Important: You may need to reboot your computer before the
+ environment variable has an effect. See "Changes made to..." in the
+ TROUBLESHOOTING section.
+
+- The GNU RCS utilities won't work with repository files that use
+ CVSNT's unicode expansion mode (-ku). Files that use this mode will
+ show up with an "rlog error: unknown expand mode u" error message in
+ ViewVC directory listings. To work around this, you can set up
+ ViewVC to use the CVSNT executable (cvs.exe) or CVSNT RCS tools
+ (co.exe, rlog.exe, and rcsdiff.exe) instead of the GNU tools.
+
+- The standalone server will not run under Cygwin Python because it
+ does not support threads. ASP pages can't be run with Cygwin Python
+ because it does not support ActiveX. To use either of these features
+ you should install a native Python interpreter.
+
+- On Windows XP and Windows 2003 Server under IIS, enscript might give
+ an error like:
+
+ enscript: couldn't open input filter "states -f
+ "K:/gnuwin32/share/enscript/hl/enscript.st" -p
+ "C://.enscript;K:/gnuwin32/share/enscript/hl" -shtml -Dcolor=1
+ -Dstyle=emacs -Dlanguage=html -Dnum_input_files=1
+ -Ddocument_title="Enscript Output" -Dtoc=0 -" for file "": No error
+ no output generated
The solution is to give read & execute permissions on cmd.exe to the
- IUSR_computername and IWAM_computername user accounts. (Enscript uses cmd.exe
- internally to launch its little helper program, states.exe).
-
-- By default, ASP will set session cookies at each page load. ViewVC does not
- use these cookies and they can be safely disabled. You can do this by opening
- the IIS properties dialog for the application directory containing the ViewVC
- .asp files. Go to the [Home] | [Virtual] Directory tab and click the
- "Configuration" button under "Application Settings". On the dialog that comes
- up, uncheck "Enable Session State" under "App Options" -> "Application
- Configuration".
-
-- Python support for ASP can be a little flaky. If you get strange errors, it
- can sometimes help to uninstall and reinstall it with pyscript.py. A number
- of people have also encountered a problem in ActivePython 2.2 where the first
- loads of any Python ASP page would work, but subsequent loads of the same
- page would always return nothing (leaving the screen blank). There were a
- number of workarounds for this problem, but the fix is to download and
- install the latest python win32 extensions from
+ IUSR_computername and IWAM_computername user accounts. (Enscript
+ uses cmd.exe internally to launch its little helper program,
+ states.exe).
+
+- By default, ASP will set session cookies at each page load. ViewVC
+ does not use these cookies and they can be safely disabled. You can
+ do this by opening the IIS properties dialog for the application
+ directory containing the ViewVC .asp files. Go to the [Home] |
+ [Virtual] Directory tab and click the "Configuration" button under
+ "Application Settings". On the dialog that comes up, uncheck "Enable
+ Session State" under "App Options" -> "Application Configuration".
+
+- Python support for ASP can be a little flaky. If you get strange
+ errors, it can sometimes help to uninstall and reinstall it with
+ pyscript.py. A number of people have also encountered a problem in
+ ActivePython 2.2 where the first loads of any Python ASP page would
+ work, but subsequent loads of the same page would always return
+ nothing (leaving the screen blank). There were a number of
+ workarounds for this problem, but the fix is to download and install
+ the latest python win32 extensions from
http://sourceforge.net/projects/pywin32/
-- ViewVC can't convert timestamps on diff pages to local time when it is used
- with CVSNT. This is caused by a CVSNT bug, which is described at
+- ViewVC can't convert timestamps on diff pages to local time when it
+ is used with CVSNT. This is caused by a CVSNT bug, which is
+ described at
http://www.cvsnt.org/mantis/bug_view_page.php?bug_id=0000110
-- Old versions of CVSNT (2.0.11 and earlier) have a bug in their rlog emulation
- which causes them to output truncated paths to RCS files. In ViewVC, this
- causes errors like
-
- Error parsing rlog output. Expected RCS file "c:\cvsroot\dir\file,v", found
- "file,v"
-
-- Old versions of CVSNT (2.0.11 and earlier) have a bug in their standalone RCS
- tools (rlog.exe, co.exe, and rcsdiff.exe) which causes them not to properly
- interpret arguments with spaces. This can result in ViewVC errors in
- repositories that have spaces in file or directory names. This bug only
- occurs when ViewVC is configured to use the standalone utilities, not when it
- uses cvs.exe directly as it does by default.
-
-- Old versions of CVSNT (1.11.1.3-76 and earlier) don't have any RCS emulation,
- so they can't be used as RCS parsers for ViewVC.
-
-- Very old versions of CVSNT (1.11.1.3-57g and earlier) won't work reliably
- with our loginfo handler because they have a bug which makes them escape
- spaces and other special characters in filenames twice. This bug can result
- in loginfo errors or invalid data being inserted into the database.
+- Old versions of CVSNT (2.0.11 and earlier) have a bug in their rlog
+ emulation which causes them to output truncated paths to RCS
+ files. In ViewVC, this causes errors like
+
+ Error parsing rlog output. Expected RCS file
+ "c:\cvsroot\dir\file,v", found "file,v"
+
+- Old versions of CVSNT (2.0.11 and earlier) have a bug in their
+ standalone RCS tools (rlog.exe, co.exe, and rcsdiff.exe) which
+ causes them not to properly interpret arguments with spaces. This
+ can result in ViewVC errors in repositories that have spaces in file
+ or directory names. This bug only occurs when ViewVC is configured
+ to use the standalone utilities, not when it uses cvs.exe directly
+ as it does by default.
+
+- Old versions of CVSNT (1.11.1.3-76 and earlier) don't have any RCS
+ emulation, so they can't be used as RCS parsers for ViewVC.
+
+- Very old versions of CVSNT (1.11.1.3-57g and earlier) won't work
+ reliably with our loginfo handler because they have a bug which
+ makes them escape spaces and other special characters in filenames
+ twice. This bug can result in loginfo errors or invalid data being
+ inserted into the database.
-- Old versions of Highlight (2.4.3 and earlier) will not show line numbers
- for .txt files or files of unknown type even when the
+- Old versions of Highlight (2.4.3 and earlier) will not show line
+ numbers for .txt files or files of unknown type even when the
"highlight_line_numbers" option is enabled.
-- Highlight versions 2.4.2 and 2.4.3 start line numbering for all file types
- at 0 instead of 1 by default. A workaround is to make ViewVC pass an
- explicit --line-number-start=1 option to Highlight
-
-- Highlight version 2.4.4 starts line numbering for .txt files at 0 instead of
- 1. It also misinterprets the --line-number-start option for those files,
- starting numbering one number before whatever number is specified. Since this
- behavior does not affect unknown file types, a simple workaround is just to
- not pass a --syntax option to Highlight for plain text files (instead of
- passing --syntax=txt).
+- Highlight versions 2.4.2 and 2.4.3 start line numbering for all file
+ types at 0 instead of 1 by default. A workaround is to make ViewVC
+ pass an explicit --line-number-start=1 option to Highlight
+
+- Highlight version 2.4.4 starts line numbering for .txt files at 0
+ instead of 1. It also misinterprets the --line-number-start option
+ for those files, starting numbering one number before whatever
+ number is specified. Since this behavior does not affect unknown
+ file types, a simple workaround is just to not pass a --syntax
+ option to Highlight for plain text files (instead of passing
+ --syntax=txt).
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
THANKS
-- Bryan T. Vold for improving the original ViewCVS patch by adding support for
- enscript and tarball generation.
+- Bryan T. Vold for improving the original ViewCVS patch by adding
+ support for enscript and tarball generation.
+
- David Resnick for tracking down the cause of re_search failures in
repositories with non-rcs files and for bringing a bug in
sapi.AspFile.header() to my attention
-- Matt Bunch for finding a better way to address the ASP blank page problem,
- and Keith D. Zimmerman for finding another workaround.
-- Rü Koch for reporting a bug in viewvc PATH_INFO parsing code with
- Apache for Windows as well as Jelle Ouwerkerk and Steffen Yount for providing
- fixes.
-- Nick Minutello and Rü Koch for providing workarounds for setting
- enscript_library environment variable with apache. David Duminy for providing
- the first bug report on this.
-- Gyula Faller and Tony Cook for independently coming up with CVSNT loginfo
- handlers that accept spaces and don't rely on unix-style echo commands. Tony
- Cook's patch also eliminated the dependency on cat.exe.
-- Mathieu Mazerolle for making the unix loginfo handler handle spaces in
- filenames
-- Paul Russell for analyzing problems with new fields in CVSNT RCS files.
- Terry Ninnis pgen com for coming up with a partial solution
-- Bo Berglund for tracking down the cause of a case-sensitivity issue that
- could lead to problems in the commit database and for patiently working with
- me to finally fix the CVSNT RCS fields problem and another problem with
- enscript.
-- Ivo Roessling for finding and fixing a bug in the query page's commit
- grouping code.
-- Keith D. Zimmerman for experimenting with enscript and finding some new ways
- to make it work.
+
+- Matt Bunch for finding a better way to address the ASP blank page
+ problem, and Keith D. Zimmerman for finding another workaround.
+
+- Rü Koch for reporting a bug in viewvc PATH_INFO parsing code
+ with Apache for Windows as well as Jelle Ouwerkerk and Steffen Yount
+ for providing fixes.
+
+- Nick Minutello and Rü Koch for providing workarounds for
+ setting enscript_library environment variable with apache. David
+ Duminy for providing the first bug report on this.
+
+- Gyula Faller and Tony Cook for independently coming up with CVSNT
+ loginfo handlers that accept spaces and don't rely on unix-style
+ echo commands. Tony Cook's patch also eliminated the dependency on
+ cat.exe.
+
+- Mathieu Mazerolle for making the unix loginfo handler handle spaces
+ in filenames.
+
+- Paul Russell for analyzing problems with new fields in CVSNT RCS
+ files. Terry Ninnis pgen com for coming up with a partial solution
+
+- Bo Berglund for tracking down the cause of a case-sensitivity issue
+ that could lead to problems in the commit database and for patiently
+ working with me to finally fix the CVSNT RCS fields problem and
+ another problem with enscript.
+
+- Ivo Roessling for finding and fixing a bug in the query page's
+ commit grouping code.
+
+- Keith D. Zimmerman for experimenting with enscript and finding some
+ new ways to make it work.
Modified: trunk/www/index.html
==============================================================================
--- trunk/www/index.html (original)
+++ trunk/www/index.html Mon Nov 3 09:57:02 2008
@@ -21,16 +21,7 @@
<div class="h2">
<h2>Latest Release</h2>
-<p>The most recent release of ViewVC is: <strong>1.0.4</strong></p>
-
-</div>
-
-<div class="h2">
-<h2>New IRC Channel for ViewVC</h2>
-
-<p>Use your favorite IRC client to pop into <tt><a
- href="irc://irc.freenode.net/viewvc">#viewvc</a></tt> on
- irc.freenode.net.</p>
+<p>The most recent release of ViewVC is: <strong>1.0.7</strong></p>
</div>
@@ -73,6 +64,26 @@
</div>
<div class="h2">
+<h2>Wanna Talk About ViewVC?</h2>
+
+<p>If you have questions about ViewVC — how to configure it, if
+ some behavior you are seeing is expected or not, and so on —
+ send email to our users list: <a
+ href="mailto:users viewvc tigris org"
+ >users viewvc tigris org</a>.</p>
+
+<p>If you'd like to discuss the actual development of ViewVC itself,
+ or submit a patch to ViewVC's sources, you can do so on our
+ development list: <a href="mailto:dev viewvc tigris org"
+ >dev viewvc tigris org</a>.</p>
+
+<p>Finally, if you prefer realtime chatter, use your favorite IRC
+ client to pop into <tt><a href="irc://irc.freenode.net/viewvc"
+ >#viewvc</a></tt> on irc.freenode.net.</p>
+
+</div>
+
+<div class="h2">
<h2>Screenshots</h2>
<p>Who needs screenshots when you can visit and interact with running
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]