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

Compare commits

..

2 Commits
1.0.7 ... 1.0.1

Author SHA1 Message Date
cmpilato
a67b467261 Oops. Stick a datestamp in the CHANGES file.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/tags/1.0.1@1389 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-20 22:15:26 +00:00
cmpilato
5135318425 Tag the 1.0.1 final release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/tags/1.0.1@1388 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-20 22:11:36 +00:00
50 changed files with 1224 additions and 1931 deletions

61
CHANGES
View File

@@ -1,64 +1,3 @@
Version 1.0.7 (released 14-Oct-2008)
* fix regression in the 'as text' download view (issue #373)
Version 1.0.6 (released 16-Sep-2008)
* security fix: ignore arbitrary user-provided MIME types (issue #354)
* fix bug in regexp search filter when used with sticky tag (issue #346)
* fix bug in handling of certain 'co' output (issue #348)
* fix regexp search filter template bug
* fix annotate code syntax error
* fix mod_python import cycle (issue #369)
Version 1.0.5 (released 28-Feb-2008)
* security fix: omit commits of all-forbidden files from query results
* security fix: disallow direct URL navigation to hidden CVSROOT folder
* security fix: strip forbidden paths from revision view
* security fix: don't traverse log history thru forbidden locations
* security fix: honor forbiddenness via diff view path parameters
* new 'forbiddenre' regexp-based path authorization feature
* fix root name conflict resolution inconsistencies (issue #287)
* fix an oversight in the CVS 1.12.9 loginfo-handler support
* fix RSS feed content type to be more specific (issue #306)
* fix entity escaping problems in RSS feed data (issue #238)
* fix bug in tarball generation for remote Subversion repositories
* fix query interface file-count-limiting logic
* fix query results plus/minus count to ignore forbidden files
* fix blame error caused by 'svn' unable to create runtime config dir
Version 1.0.4 (released 10-Apr-2007)
* fix some markup bugs in query views (issue #266)
* fix loginfo-handler's support for CVS 1.12.9 (issues #151, #257)
* make viewvc-install able to run from an arbitrary location
* update viewvc-install's output for readability
* fix bug writing commits to non-MyISAM databases (issue #262)
* allow long paths in generated tarballs (issue #12)
* fix bug interpreting EZT substitute patterns
* fix broken markup view disablement
* fix broken directory view link generation in directory log view
* fix Windows-specific viewvc-install bugs
* fix broke query result links for Subversion deleted items (issue #296)
* fix some output XHTML validation buglets
* fix database query cache staleness problems (issue #180)
Version 1.0.3 (released 13-Oct-2006)
* fix bug in path shown for Subversion deleted-under-copy items (issue #265)
* security fix: declare charset for views to avoid IE UTF7 XSS attack
Version 1.0.2 (released 29-Sep-2006)
* minor documentation fixes
* fix Subversion annotate functionality on Windows (issue #18)
* fix annotate assertions on uncanonicalized #include paths (issue #208)
* make RSS URL method match the method used to generate it (issue #245)
* fix Subversion annotation to run non-interactively, preventing hangs
* fix bug in custom syntax highlighter fallback logic
* fix bug in PHP CGI hack to avoid force-cgi-redirect errors
Version 1.0.1 (released 20-Jul-2006)
* fix exception on log page when use_pagesize is enabled

346
INSTALL
View File

@@ -1,12 +1,11 @@
CONTENTS
--------
TO THE IMPATIENT
SECURITY INFORMATION
INSTALLING VIEWVC
APACHE CONFIGURATION
UPGRADING VIEWVC
SQL CHECKIN DATABASE
ENABLING SYNTAX COLORATION
ENSCRIPT AND HIGHLIGHT CONFIGURATION
CVSGRAPH CONFIGURATION
IF YOU HAVE PROBLEMS...
@@ -51,58 +50,24 @@ Congratulations on getting this far. :-)
* CvsGraph 1.5.0 or later, graphical CVS revision tree generator
(http://www.akhphd.au.dk/~bertho/cvsgraph/)
Quick sanity check:
GUI Operation:
If you just want to see what your repository looks like when seen
through ViewVC, type:
If you just want to see what your CVS repository looks like with
ViewVC, type "bin/standalone.py -g -r /PATH/TO/CVS/ROOT". This
will start a tiny webserver serving at http://localhost:7467/.
PLEASE NOTE: This requires Python with thread support enabled and
the Tkinter GUI. If you don't have one of these, omit the '-g' option.
$ bin/standalone.py -r /PATH/TO/REPOSITORY
This will start a tiny ViewVC server at http://localhost:7467/viewvc/,
to which you can connect with your browser.
Standard operation:
To start installing right away (on UNIX): type "./viewvc-install"
in the current directory and answer the prompts. When it
finishes, edit the file viewvc.conf in the installation directory
to tell ViewVC the paths to your CVS and Subversion repositories.
Next, configure your web server (in the way appropriate to that browser)
to run <VIEWVC_INSTALLATION_DIRECTORY>/bin/cgi/viewvc.cgi. The section
`INSTALLING VIEWVC' below is still recommended reading.
SECURITY INFORMATION
--------------------
ViewVC provides a feature which allows version controlled content to
be served to web browsers just like static web server content. So, if
you have a directory full of interrelated HTML files that is housed in
your version control repository, ViewVC can serve those files as HTML.
You'll see in your web browser what you'd see if the files were part
of your website, with working references to stylesheets and images and
links to other pages.
It is important to realize, however, that as useful as that feature
is, there is some risk security-wise in its use. Essentially, anyone
with commit access to the CVS or Subversion repositories served by
ViewVC has the ability to affect site content. If a discontented or
ignorant user commits malicious HTML to a version controlled file
(perhaps just by way of documenting examples of such), that malicious
HTML is effectively published and live on your ViewVC instance.
Visitors viewing those versioned controlled documents get the
malicious code, too, which might not be what the original author
intended.
If you wish to disable ViewVC's "checkout" view which implements this
feature, you can do so by editing lib/viewvc.py, and modifying the
function view_checkout() like so, adding the lines indicated:
def view_checkout(request):
>> raise debug.ViewVCException('Checkout view is disabled',
>> '403 Forbidden')
path, rev = _orig_path(request)
fp, revision = request.repos.openfile(path, rev)
to tell viewvc the paths to your CVS and Subversion repositories. Next,
configure your web server to run <INSTALL>/cgi/viewvc.cgi, as
appropriate for your web server. The section `INSTALLING VIEWVC'
below is still recommended reading.
INSTALLING VIEWVC
@@ -142,11 +107,8 @@ installation instructions.
3) Edit <VIEWVC_INSTALLATION_DIRECTORY>/viewvc.conf for your specific
configuration. In particular, examine the following configuration options:
cvs_roots (for CVS)
svn_roots (for Subversion)
root_parents (for CVS or Subversion)
cvs_roots
default_root
root_as_url_component
rcs_path
mime_types_file
@@ -156,22 +118,22 @@ installation instructions.
then edit the files in <VIEWVC_INSTALLATION_DIRECTORY>/templates.
You need knowledge about HTML to edit the templates.
4) The CGI programs are in <VIEWVC_INSTALLATION_DIRECTORY>/bin/cgi/. You can
4) The CGI programs are in <VIEWVC_INSTALLATION_DIRECTORY>/www/cgi/. You can
symlink to this directory from somewhere in your published HTTP server
path if your webserver is configured to follow symbolic links. You can
also copy the installed <VIEWVC_INSTALLATION_DIRECTORY>/bin/cgi/*.cgi
also copy the installed <VIEWVC_INSTALLATION_DIRECTORY>/www/cgi/*.cgi
scripts after the install (unlike the other files in ViewVC, the scripts
under bin/ can be moved).
under www/ can be moved).
If you are using Apache, then see below at the section titled
APACHE CONFIGURATION.
If you are using Apache, then see below at the section
titled APACHE CONFIGURATION.
NOTE: for security reasons, it is not advisable to install ViewVC
directly into your published HTTP directory tree (due to the MySQL
passwords in viewvc.conf).
That's it for repository browsing. Instructions for getting the SQL
checkin database working are below.
5) That's it for repository browsing. Instructions for getting the
SQL checkin database working are below.
APACHE CONFIGURATION
@@ -187,26 +149,26 @@ Either METHOD A:
2) The ScriptAlias directive is very useful for pointing
directly to the viewvc.cgi script. Simply insert a line containing
ScriptAlias /viewvc <VIEWVC_INSTALLATION_DIRECTORY>/bin/cgi/viewvc.cgi
ScriptAlias /viewvc <VIEWVC_INSTALLATION_DIRECTORY>/www/cgi/viewvc.cgi
into your httpd.conf file. Choose the location in httpd.conf where
also the other ScriptAlias lines reside. Some examples:
ScriptAlias /viewvc /usr/local/viewvc-1.0/bin/cgi/viewvc.cgi
ScriptAlias /query /usr/local/viewvc-1.0/bin/cgi/query.cgi
ScriptAlias /viewvc /usr/local/viewvc-1.0/www/cgi/viewvc.cgi
ScriptAlias /query /usr/local/viewvc-1.0/www/cgi/query.cgi
continue with step 3).
or alternatively METHOD B:
2) Copy the CGI scripts from
<VIEWVC_INSTALLATION_DIRECTORY>/bin/cgi/*.cgi
<VIEWVC_INSTALLATION_DIRECTORY>/www/cgi/*.cgi
to the /cgi-bin/ directory configured in your httpd.conf file.
continue with step 3).
and then there's METHOD C:
2) Copy the CGI scripts from
<VIEWVC_INSTALLATION_DIRECTORY>/bin/cgi/*.cgi
<VIEWVC_INSTALLATION_DIRECTORY>/www/cgi/*.cgi
to the directory of your choosing in the Document Root adding the following
apache directives for the directory in httpd.conf or an .htaccess file:
@@ -221,7 +183,7 @@ and then there's METHOD C:
or if you've got Mod_Python installed you can use METHOD D:
2) Copy the Python scripts and .htaccess file from
<VIEWVC_INSTALLATION_DIRECTORY>/bin/mod_python/
<VIEWVC_INSTALLATION_DIRECTORY>/www/mod_python/
to a directory being served by apache.
In httpd.conf, make sure that "AllowOverride All" or at least
@@ -244,37 +206,28 @@ or if you've got Mod_Python installed you can use METHOD D:
In your httpd.conf you can control access to certain modules by adding
directives like this:
<Location "<url to viewvc.cgi>/<modname_you_wish_to_access_ctl>">
AllowOverride None
AuthUserFile /path/to/passwd/file
AuthName "Client Access"
AuthType Basic
require valid-user
</Location>
<Location "<url to viewvc.cgi>/<modname_you_wish_to_access_ctl>">
AllowOverride None
AuthUserFile /path/to/passwd/file
AuthName "Client Access"
AuthType Basic
require valid-user
</Location>
WARNING: If you enable the "checkout_magic" or "allow_tar" options, you
will need to add additional location directives to prevent people
from sneaking in with URLs like:
http://<server_name>/viewvc/*checkout*/<module_name>
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.
http://<server_name>/viewvc/*checkout*/<module_name>
http://<server_name>/viewvc/~checkout~/<module_name>
http://<server_name>/viewvc/<module_name>.tar.gz?view=tar
UPGRADING VIEWVC
-----------------
Please read the file upgrading-howto.html in the docs/ subdirectory.
Please read the file upgrading.html in the viewvc.org/ subdirectory or
at <http://viewvc.org/upgrading.html>.
SQL CHECKIN DATABASE
@@ -293,7 +246,7 @@ there are some additional steps required to get the database working.
Optionally, you can create a second user with read-only access to the
database.
3) Run the <VIEWVC_INSTALLATION_DIRECTORY>/bin/make-database script. It will
3) Run the <VIEWVC_INSTALLATION_DIRECTORY>/make-database script. It will
prompt you for your MySQL user, password, and the name of database you
want to create. The database name defaults to "ViewVC". This script
creates the database and sets up the empty tables. If you run this on a
@@ -305,105 +258,91 @@ there are some additional steps required to get the database working.
enabled = 1 # Whether to enable query support in viewvc.cgi
host = # MySQL database server host
port = # MySQL database server port (default is 3306)
database_name = # name of database you created with make-database
user = # read/write database user
database_name = # the name of the database you created with
# make-database
user = # the read/write database user
passwd = # password for read/write database user
readonly_user = # read-only database user
readonly_passwd = # password for the read-only user
readonly_user = # the readonly database user -- it's pretty
# safe to use the read/write user here
readonly_passwd = # password for the readonly user
Note that it's pretty safe in this instance for your read-only user
and your read-write user to be the same.
5) Two programs are provided for updating the checkin database from a
CVS repository, cvsdbadmin and loginfo-handler. They serve two
different purposes. The cvsdbadmin program walks through your CVS
repository and adds every commit in every file. This is commonly
used for initializing the database from a repository which has been
in use. The loginfo-handler script is executed by the CVS server's
CVSROOT/loginfo system upon each commit. It makes real-time
updates to the checkin database as commits are made to the
repository.
5) At this point, you need to tell your version control system(s) to
publish their commit information to the database. This is done
using utilities that ViewVC provides.
To build a database of all the commits in the CVS repository /home/cvs,
invoke: "./cvsdbadmin rebuild /home/cvs". If you want to update
the checkin database, invoke: "./cvsdbadmin update /home/cvs". The
update mode checks to see if a commit is already in the database,
and only adds it if it is absent.
To publish CVS commits into the database:
To get real-time updates, you'll want to checkout the CVSROOT module
from your CVS repository and edit CVSROOT/loginfo. Add the line:
Two programs are provided for updating the checkin database from
a CVS repository, cvsdbadmin and loginfo-handler. They serve
two different purposes. The cvsdbadmin program walks through
your CVS repository and adds every commit in every file. This
is commonly used for initializing the database from a repository
which has been in use. The loginfo-handler script is executed
by the CVS server's CVSROOT/loginfo system upon each commit. It
makes real-time updates to the checkin database as commits are
made to the repository.
ALL <VIEWVC_INSTALLATION_DIRECTORY>/loginfo-handler %{sVv}
To build a database of all the commits in the CVS repository
/home/cvs, invoke: "./cvsdbadmin rebuild /home/cvs". If you
want to update the checkin database, invoke: "./cvsdbadmin
update /home/cvs". The update mode checks to see if a commit is
already in the database, and only adds it if it is absent.
If you have other scripts invoked by CVSROOT/loginfo, you will want
to make sure to change any running under the "DEFAULT" keyword to
"ALL" like the loginfo handler, and probably carefully read the
execution rules for CVSROOT/loginfo from the CVS manual.
To get real-time updates, you'll want to checkout the CVSROOT
module from your CVS repository and edit CVSROOT/loginfo. For
folks running CVS 1.12 or better, add this line:
ALL <VIEWVC_INSTALLATION_DIRECTORY>/bin/loginfo-handler %p %{sVv}
If you are running CVS 1.11 or earlier, you'll want a slightly
different command line in CVSROOT/loginfo:
ALL <VIEWVC_INSTALLATION_DIRECTORY>/bin/loginfo-handler %{sVv}
If you are running the Unix port of CVS-NT, you'll need to use a
slightly different command line:
If you have other scripts invoked by CVSROOT/loginfo, you will
want to make sure to change any running under the "DEFAULT"
keyword to "ALL" like the loginfo handler, and probably
carefully read the execution rules for CVSROOT/loginfo from the
CVS manual.
If you are running the Unix port of CVS-NT, the handler script
need to know about it. CVS-NT delivers commit information to
loginfo scripts differently than the way mainstream CVS does.
Your command line should look like this:
ALL <VIEWVC_INSTALLATION_DIRECTORY>/bin/loginfo-handler %{sVv} cvsnt
ALL <VIEWVC_INSTALLATION_DIRECTORY>/loginfo-handler %{sVv} cvsnt
The extra 'cvsnt' parameter tells the handler script to parse the
commit information in a different way.
To publish Subversion commits into the database:
For Subversion repositories, there is a single script called
svndbadmin that performs both of the above tasks.
To build a database of all the commits in the Subversion
repository /home/svn, invoke: "./svndbadmin rebuild /home/svn".
If you want to update the checkin database, invoke:
"./svndbadmin update /home/svn".
To build a database of all the commits in the Subversion repository
/home/svn, invoke: "./svndbadmin rebuild /home/svn". If you want
to update the checkin database, invoke: "./svndbadmin update
/home/svn".
To get real time updates, you will need to add a post-commit
hook (for the repository example above, the script should go in
/home/svn/hooks/post-commit). The script should look something
like this:
To get real time updates, you will need to add a post-commit hook
(for the repository example above, the script should go in
/home/svn/hooks/post-commit). The script should look something
like this:
#!/bin/sh
REPOS="$1"
REV="$2"
<VIEWVC_INSTALLATION_DIRECTORY>/bin/svndbadmin rebuild "$REPOS" "$REV"
#!/bin/sh
REPOS="$1"
REV="$2"
<VIEWVC_INSTALLATION_DIRECTORY>/svndbadmin rebuild "$REPOS" "$REV"
If you allow revision property changes in your repository,
create a post-revprop-change hook script containing the same
commands as the post-commit one. This will make sure that the
checkin database stays consistent when you change the svn:log,
svn:author or svn:date revision properties.
If you allow revision property changes in your repository, create a
post-revprop-change hook script containing the same commands as the
post-commit one. This will make sure that the checkin database
stays consistent when you change the svn:log, svn:author or
svn:date revision properties.
You should be ready to go. Click one of the "Query revision history"
links in ViewVC directory listings and give it a try.
6) You should be ready to go. Click one of the "Query revision history"
links in ViewVC directory listings and give it a try.
ENABLING SYNTAX COLORATION
--------------------------
ENSCRIPT AND HIGHLIGHT CONFIGURATION
------------------------------------
Enscript and Highlight are two programs that can colorize source code
for a lot of languages. ViewVC can be configured to use either one.
Enscript and Highlight are programs that can colorize source code for
a lot of languages. ViewVC can be configured to use either one.
1) Install Enscript or Highlight using your system's package manager
or downloading from the project home pages.
2) Set either the 'use_enscript' or 'use_highlight' options in
viewvc.conf to 1.
2) Set the 'use_enscript' or 'use_highlight' options in viewvc.conf to 1.
3) You may also need to set 'enscript_path' or 'highlight_path' option
3) You may also need to set 'enscript_path' and 'highlight_path' options
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.
4) That's it!
CVSGRAPH CONFIGURATION
@@ -432,50 +371,36 @@ a reasonable number of revisions and branches.
4) There is a file <VIEWVC_INSTALLATION_DIRECTORY>/cvsgraph.conf that
you may want to edit if desired to set color and font characteristics.
See the cvsgraph.conf documentation. No edits are required in
cvsgraph.conf for operation with ViewVC.
cvsgraph.conf for operation with viewvc.
SUBVERSION INTEGRATION
----------------------
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.
ViewVC supports browsing of Subversion repositories. 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.
Generally speaking, you'll know when your installation of Subversion's
bindings has been successful if you can import the 'svn.core' module
from within your Python interpreter. Here's an example of doing so
which doubles as a quick way to check what version of the Subversion
Python binding you have:
bindings has been successful if you can import the 'svn.repos' module
from within your Python interpreter:
% python
Python 2.2.2 (#1, Oct 29 2002, 02:47:30)
[GCC 2.96 20000731 (Red Hat Linux 7.2 2.96-108.7.2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from svn.core import *
>>> "%s.%s.%s" % (SVN_VER_MAJOR, SVN_VER_MINOR, SVN_VER_PATCH)
'1.2.0'
>>>
>>> import svn.repos
>>>
Note that by default, Subversion installs its bindings in a location
that is not in Python's default module search path (for example, on
Linux systems the default is usually /usr/local/lib/svn-python). You
need to remedy this, either by adding this path to Python's module
search path, or by relocating the bindings to some place in that
search path, or by relocation the bindings to some place in that
search path.
For example, you might want to create .pth file in your Python
installation directory's site-packages area which tells Python where
to find additional modules (in this case, you Subversion Python
bindings). You would do this as follows (and as root):
$ echo "/path/to/svn/bindings" > /path/to/python/site-packages/svn.pth
(Though, obviously, with the correct paths specified.)
Configuration of the Subversion repositories happens in much the same
way as with CVS repositories, only with the 'svn_roots' configuration
variable instead of the 'cvs_roots' one.
@@ -484,42 +409,39 @@ variable instead of the 'cvs_roots' one.
IF YOU HAVE PROBLEMS ...
------------------------
If nothing seems to work:
If you've trouble to make viewvc.cgi work:
* Check if you can execute CGI-scripts (Apache needs to have an
ScriptAlias /cgi-bin or cgi-script Handler defined). Try to
execute a simple CGI-script that often comes with the distribution
of the webserver; locate the logfiles and try to find hints which
explain the malfunction
=== If nothing seems to work:
* View the entries in the webserver's error.log
o check if you can execute CGI-scripts (Apache needs to have an
ScriptAlias /cgi-bin or cgi-script Handler defined). Try to
execute a simple CGI-script that often comes with the distribution
of the webserver; locate the logfiles and try to find hints
which explain the malfunction
o view the entries in the webserver's error.log
If ViewVC seems to work but doesn't show the expected result (Typical
error: you can't see any files)
=== If viewvc seems to work but doesn't show the expected result
(Typical error: you can't see any files)
* Check whether the CGI-script has read-permissions to your
CVS-Repository. The CGI-script generally runs as the same user
that the web server does, often user 'nobody' or 'httpd'.
o check whether the CGI-script has read-permissions to your
CVS-Repository. The CGI-script often runs as the user 'nobody'
or 'httpd' ..
* Does ViewVC find your RCS utilities? (edit rcs_path)
o does viewvc find your RCS utilities? (edit rcs_path)
If something else happens or you can't get it to work:
=== If something else happens or you can't get it to work:
* Check the ViewVC home page:
o check the ViewVC home page:
http://viewvc.org/
http://viewvc.org/
* Review the ViewVC mailing list archive to see if somebody else had
the same problem, and it was solved:
o review the ViewVC mailing list archive to see if somebody else had
the same problem, and it was solved:
http://viewvc.tigris.org/servlets/SummarizeList?listName=users
http://viewvc.tigris.org/servlets/SummarizeList?listName=users
* Check the ViewVC issue database to see if the problem you are
seeing is the result of a known bug:
o send mail to the ViewVC mailing list: users@viewvc.tigris.org
http://viewvc.tigris.org/issues/query.cgi
* Send mail to the ViewVC mailing list, users@viewvc.tigris.org.
NOTE: make sure you provide an accurate description of the problem
-- including the version of ViewVC you are using -- and any
relevant tracebacks or error logs.
NOTE: make sure you provide an accurate description of the problem
and any relevant tracebacks or error logs.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2006 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
@@ -32,9 +32,9 @@ import sys
import os
if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
sys.path.insert(0, LIBRARY_DIR)
else:
sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0], "../../lib")))
sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0], "../../lib")))
#########################################################################
@@ -49,13 +49,9 @@ import vclib.bincvs
DEBUG_FLAG = 0
## output functions
def debug(text):
def debug(text):
if DEBUG_FLAG:
if type(text) != (type([])):
text = [text]
for line in text:
line = line.rstrip('\n\r')
print 'DEBUG(viewvc-loginfo):', line
print 'DEBUG(viewvc-loginfo):', text
def warning(text):
print 'WARNING(viewvc-loginfo):', text
@@ -65,160 +61,139 @@ def error(text):
sys.exit(1)
_re_revisions = re.compile(
r",(?P<old>(?:\d+\.\d+)(?:\.\d+\.\d+)*|NONE)" # comma and first revision
r",(?P<new>(?:\d+\.\d+)(?:\.\d+\.\d+)*|NONE)" # comma and second revision
r"(?:$| )" # space or end of string
r",(?P<old>(?:\d+\.\d+)(?:\.\d+\.\d+)*|NONE)" # comma and first revision number
r",(?P<new>(?:\d+\.\d+)(?:\.\d+\.\d+)*|NONE)" # comma and second revision number
r"(?:$| )" # space or end of string
)
def Cvs1Dot12ArgParse(args):
"""CVS 1.12 introduced a new loginfo format while provides the various
pieces of interesting version information to the handler script as
individual arguments instead of as a single string."""
if args[1] == '- New directory':
return None, None
elif args[1] == '- Imported sources':
return None, None
else:
directory = args.pop(0)
files = []
while len(args) >= 3:
files.append(args[0:3])
args = args[3:]
return directory, files
def HeuristicArgParse(s, repository):
"""Older versions of CVS (except for CVSNT) do not escape spaces in file
and directory names that are passed to the loginfo handler. Since the input
to loginfo is a space separated string, this can lead to ambiguities. This
function attempts to guess intelligently which spaces are separators and
which are part of file or directory names. It disambiguates spaces in
filenames from the separator spaces between files by assuming that every
space which is preceded by two well-formed revision numbers is in fact a
separator. It disambiguates the first separator space from spaces in the
directory name by choosing the longest possible directory name that
actually exists in the repository"""
"""Current versions of CVS (except for CVSNT) do not escape spaces in file
and directory names that are passed to the loginfo handler. Since the input
to loginfo is a space separated string, this can lead to ambiguities. This
function attempts to guess intelligently which spaces are separators and
which are part of file or directory names. It disambiguates spaces in
filenames from the separator spaces between files by assuming that every
space which is preceded by two well-formed revision numbers is in fact a
separator. It disambiguates the first separator space from spaces in the
directory name by choosing the longest possible directory name that actually
exists in the repository"""
if (s[-16:] == ' - New directory'
or s[:26] == ' - New directory,NONE,NONE'):
return None, None
if (s[-19:] == ' - Imported sources'
or s[-29:] == ' - Imported sources,NONE,NONE'):
return None, None
file_data_list = []
start = 0
while 1:
m = _re_revisions.search(s, start)
if start == 0:
if m is None:
error('Argument "%s" does not contain any revision numbers' \
% s)
directory, filename = FindLongestDirectory(s[:m.start()],
repository)
if directory is None:
error('Argument "%s" does not start with a valid directory' \
% s)
debug('Directory name is "%s"' % directory)
else:
if m is None:
warning('Failed to interpret past position %i in the loginfo '
'argument, leftover string is "%s"' \
% start, pos[start:])
filename = s[start:m.start()]
old_version, new_version = m.group('old', 'new')
file_data_list.append((filename, old_version, new_version))
debug('File "%s", old revision %s, new revision %s'
% (filename, old_version, new_version))
start = m.end()
if start == len(s): break
return directory, file_data_list
def FindLongestDirectory(s, repository):
"""Splits the first part of the argument string into a directory name
and a file name, either of which may contain spaces. Returns the longest
possible directory name that actually exists"""
parts = string.split(s, " ")
for i in range(len(parts)-1, 0, -1):
directory = string.join(parts[:i])
filename = string.join(parts[i:])
if os.path.isdir(os.path.join(repository, directory)):
return directory, filename
if s[-16:] == ' - New directory':
return None, None
if s[-19:] == r' - Imported sources':
return None, None
file_data_list = []
start = 0
while 1:
m = _re_revisions.search(s, start)
if start == 0:
if m is None:
error('Argument "%s" does not contain any revision numbers' % s)
directory, filename = FindLongestDirectory(s[:m.start()], repository)
if directory is None:
error('Argument "%s" does not start with a valid directory' % s)
debug('Directory name is "%s"' % directory)
else:
if m is None:
warning('Failed to interpret past position %i in the loginfo argument, '
'leftover string is "%s"' % start, pos[start:])
filename = s[start:m.start()]
old_version, new_version = m.group('old', 'new')
file_data_list.append((filename, old_version, new_version))
debug('File "%s", old revision %s, new revision %s'
% (filename, old_version, new_version))
start = m.end()
if start == len(s): break
return directory, file_data_list
def FindLongestDirectory(s, repository):
"""Splits the first part of the argument string into a directory name
and a file name, either of which may contain spaces. Returns the longest
possible directory name that actually exists"""
parts = string.split(s, " ")
for i in range(len(parts)-1, 0, -1):
directory = string.join(parts[:i])
filename = string.join(parts[i:])
if os.path.isdir(os.path.join(repository, directory)):
return directory, filename
return None, None
_re_cvsnt_revisions = re.compile(
r"(?P<filename>.*)" # comma and first revision
r",(?P<old>(?:\d+\.\d+)(?:\.\d+\.\d+)*|NONE)" # comma and first revision
r",(?P<new>(?:\d+\.\d+)(?:\.\d+\.\d+)*|NONE)" # comma and second revision
r"$" # end of string
r"(?P<filename>.*)" # comma and first revision number
r",(?P<old>(?:\d+\.\d+)(?:\.\d+\.\d+)*|NONE)" # comma and first revision number
r",(?P<new>(?:\d+\.\d+)(?:\.\d+\.\d+)*|NONE)" # comma and second revision number
r"$" # end of string
)
def CvsNtArgParse(s, repository):
"""CVSNT escapes all spaces in filenames and directory names with
backslashes"""
"""CVSNT escapes all spaces in filenames and directory names with
backslashes"""
if s[-18:] == r' -\ New\ directory':
return None, None
if s[-18:] == r' -\ New\ directory':
return None, None
if s[-21:] == r' -\ Imported\ sources':
return None, None
if s[-21:] == r' -\ Imported\ sources':
return None, None
file_data_list = []
directory, pos = NextFile(s)
debug('Directory name is "%s"' % directory)
file_data_list = []
while 1:
fileinfo, pos = NextFile(s, pos)
if fileinfo is None:
break
directory, pos = NextFile(s)
debug('Directory name is "%s"' % directory)
m = _re_cvsnt_revisions.match(fileinfo)
if m is None:
warning('Can\'t parse file information in "%s"' % fileinfo)
continue
while 1:
fileinfo, pos = NextFile(s, pos)
if fileinfo is None:
break
file_data = m.group('filename', 'old', 'new')
file_data_list.append(file_data)
m = _re_cvsnt_revisions.match(fileinfo)
if m is None:
warning('Can\'t parse file information in "%s"' % fileinfo)
continue
debug('File "%s", old revision %s, new revision %s' % file_data)
file_data = m.group('filename', 'old', 'new')
return directory, file_data_list
debug('File "%s", old revision %s, new revision %s' % file_data)
file_data_list.append(file_data)
return directory, file_data_list
def NextFile(s, pos = 0):
escaped = 0
ret = ''
i = pos
while i < len(s):
c = s[i]
if escaped:
ret += c
escaped = 0
elif c == '\\':
escaped = 1
elif c == ' ':
return ret, i + 1
else:
ret += c
i += 1
escaped = 0
ret = ''
i = pos
while i < len(s):
c = s[i]
if escaped:
ret += c
escaped = 0
elif c == '\\':
escaped = 1
elif c == ' ':
return ret, i + 1
else:
ret += c
i += 1
return ret or None, i
return ret or None, i
def ProcessLoginfo(rootpath, directory, files):
cfg = viewvc.load_config(CONF_PATHNAME)
@@ -260,58 +235,41 @@ if __name__ == '__main__':
debug('Repository name is "%s"' % repository)
## parse arguments
argc = len(sys.argv)
debug('Got %d arguments:' % (argc))
debug(map(lambda x: ' ' + x, sys.argv))
# if we have more than 3 arguments, we are likely using the
# newer loginfo format introduced in CVS 1.12:
#
# ALL <path>/bin/loginfo-handler %p %{sVv}
if argc > 3:
directory, files = Cvs1Dot12ArgParse(sys.argv[1:])
if len(sys.argv) > 1:
# the first argument should contain file version information
arg = sys.argv[1]
else:
if len(sys.argv) > 1:
# the first argument should contain file version information
arg = sys.argv[1]
# if there are no arguments, read version information from first line
# of input like old versions of viewcvs
arg = string.rstrip(sys.stdin.readline())
if len(sys.argv) > 2:
# if there is a second argument it indicates which parser should be
# used to interpret the version information
if sys.argv[2] == 'cvs':
fun = HeuristicArgParse
elif sys.argv[2] == 'cvsnt':
fun = CvsNtArgParse
else:
# if there are no arguments, read version information from
# first line of input like old versions of ViewCVS did
arg = string.rstrip(sys.stdin.readline())
if len(sys.argv) > 2:
# if there is a second argument it indicates which parser
# should be used to interpret the version information
if sys.argv[2] == 'cvs':
fun = HeuristicArgParse
elif sys.argv[2] == 'cvsnt':
fun = CvsNtArgParse
else:
error('Bad arguments')
error('Bad arguments')
else:
# if there is no second argument, guess which parser to use based
# on the operating system. Since CVSNT now runs on Windows and
# Linux, the guess isn't neccessarily correct
if sys.platform == "win32":
fun = CvsNtArgParse
else:
# if there is no second argument, guess which parser to use based
# on the operating system. Since CVSNT now runs on Windows and
# Linux, the guess isn't necessarily correct
if sys.platform == "win32":
fun = CvsNtArgParse
else:
fun = HeuristicArgParse
directory, files = fun(arg, repository)
fun = HeuristicArgParse
debug('Discarded from stdin:')
debug(map(lambda x: ' ' + x, sys.stdin.readlines())) # consume stdin
if len(sys.argv) > 3:
error('Bad arguments')
repository = cvsdb.CleanRepository(repository)
debug('Repository: %s' % (repository))
debug('Directory: %s' % (directory))
debug('Files: %s' % (str(files)))
directory, files = fun(arg, repository)
if files is None:
debug('Not a checkin, nothing to do')
debug('Not a checkin, nothing to do')
else:
ProcessLoginfo(repository, directory, files)
ProcessLoginfo(repository, directory, files)
sys.exit(0)

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -39,7 +39,7 @@ CREATE TABLE branches (
branch varchar(64) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE branch (branch)
) TYPE=MyISAM;
);
DROP TABLE IF EXISTS checkins;
CREATE TABLE checkins (
@@ -62,7 +62,7 @@ CREATE TABLE checkins (
KEY dirid (dirid),
KEY fileid (fileid),
KEY branchid (branchid)
) TYPE=MyISAM;
);
DROP TABLE IF EXISTS descs;
CREATE TABLE descs (
@@ -71,7 +71,7 @@ CREATE TABLE descs (
hash bigint(20) DEFAULT '0' NOT NULL,
PRIMARY KEY (id),
KEY hash (hash)
) TYPE=MyISAM;
);
DROP TABLE IF EXISTS dirs;
CREATE TABLE dirs (
@@ -79,7 +79,7 @@ CREATE TABLE dirs (
dir varchar(255) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE dir (dir)
) TYPE=MyISAM;
);
DROP TABLE IF EXISTS files;
CREATE TABLE files (
@@ -87,7 +87,7 @@ CREATE TABLE files (
file varchar(255) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE file (file)
) TYPE=MyISAM;
);
DROP TABLE IF EXISTS people;
CREATE TABLE people (
@@ -95,7 +95,7 @@ CREATE TABLE people (
who varchar(32) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE who (who)
) TYPE=MyISAM;
);
DROP TABLE IF EXISTS repositories;
CREATE TABLE repositories (
@@ -103,7 +103,7 @@ CREATE TABLE repositories (
repository varchar(64) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE repository (repository)
) TYPE=MyISAM;
);
DROP TABLE IF EXISTS tags;
CREATE TABLE tags (
@@ -117,7 +117,7 @@ CREATE TABLE tags (
KEY dirid (dirid),
KEY fileid (fileid),
KEY branchid (branchid)
) TYPE=MyISAM;
);
"""
if __name__ == "__main__":

View File

@@ -42,23 +42,9 @@ if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
import sapi
import imp
# Import real ViewVC module
fp, pathname, description = imp.find_module('viewvc', [LIBRARY_DIR])
try:
viewvc = imp.load_module('viewvc', fp, pathname, description)
finally:
if fp:
fp.close()
# Import real ViewVC Query modules
fp, pathname, description = imp.find_module('query', [LIBRARY_DIR])
try:
query = imp.load_module('query', fp, pathname, description)
finally:
if fp:
fp.close()
import viewvc
import query
reload(query) # need reload because initial import loads this stub file
cfg = viewvc.load_config(CONF_PATHNAME)

View File

@@ -42,15 +42,9 @@ if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
import sapi
import imp
import viewvc
reload(viewvc) # need reload because initial import loads this stub file
# Import real ViewVC module
fp, pathname, description = imp.find_module('viewvc', [LIBRARY_DIR])
try:
viewvc = imp.load_module('viewvc', fp, pathname, description)
finally:
if fp:
fp.close()
def index(req):
server = sapi.ModPythonServer(req)

View File

@@ -51,12 +51,16 @@ keywordsList = ["and", "assert", "break", "class", "continue", "def",
"return", "try", "while",
]
# First a little helper, since I don't like to repeat things. (Tismer speaking)
def replace(where, what, with):
return string.join(string.split(where, what), with)
# A regexp for matching Python comments.
commentPat = "#.*"
# A regexp for matching simple quoted strings.
pat = "q[^q\\n]*(\\[\000-\377][^q\\n]*)*q"
quotePat = string.replace(pat, "q", "'") + "|" + string.replace(pat, 'q', '"')
quotePat = replace(pat, "q", "'") + "|" + replace(pat, 'q', '"')
# A regexp for matching multi-line tripled-quoted strings. (Way to go, Tim!)
pat = """
@@ -78,8 +82,7 @@ pat = """
qqq
"""
pat = string.join(string.split(pat), '') # get rid of whitespace
tripleQuotePat = string.replace(pat, "q", "'") + "|" \
+ string.replace(pat, 'q', '"')
tripleQuotePat = replace(pat, "q", "'") + "|" + replace(pat, 'q', '"')
# A regexp which matches all and only Python keywords. This will let
# us skip the uninteresting identifier references.

View File

@@ -33,6 +33,7 @@ import time
import math
import cgi
import vclib
import vclib.ccvs.blame
re_includes = re.compile('\\#(\\s*)include(\\s*)"(.*?)"')
@@ -41,28 +42,25 @@ def link_includes(text, repos, path_parts, include_url):
match = re_includes.match(text)
if match:
incfile = match.group(3)
include_path_parts = path_parts[:-1]
for part in filter(None, string.split(incfile, '/')):
if part == "..":
if not include_path_parts:
# nothing left to pop; don't bother marking up this include.
return text
include_path_parts.pop()
elif part and part != ".":
include_path_parts.append(part)
include_path = None
try:
if repos.itemtype(include_path_parts, None) == vclib.FILE:
include_path = string.join(include_path_parts, '/')
except vclib.ItemNotFound:
pass
# check current directory and parent directory for file
for depth in (-1, -2):
include_path = path_parts[:depth] + [incfile]
try:
# will throw if path doesn't exist
if repos.itemtype(include_path, None) == vclib.FILE:
break
except vclib.ItemNotFound:
pass
else:
include_path = None
if include_path:
return '#%sinclude%s<a href="%s">"%s"</a>' % \
(match.group(1), match.group(2),
string.replace(include_url, '/WHERE/', include_path), incfile)
url = string.replace(include_url, '/WHERE/',
string.join(include_path, '/'))
return '#%sinclude%s<a href="%s">"%s"</a>' % \
(match.group(1), match.group(2), url, incfile)
return text
@@ -99,7 +97,6 @@ class _item:
def make_html(root, rcs_path):
import vclib.ccvs.blame
bs = vclib.ccvs.blame.BlameSource(os.path.join(root, rcs_path))
count = bs.num_lines
@@ -161,9 +158,9 @@ def make_html(root, rcs_path):
# Close the highlighted section
#if (defined $mark_cmd and mark_cmd != 'begin'):
# chop($output)
# output = output + endOfRow + (startOfRow % row_color)
# inMark = 0
# chop($output)
# output = output + endOfRow + (startOfRow % row_color)
# inMark = 0
print output
print endOfRow + '</table>'

View File

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

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2006 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
@@ -23,6 +23,11 @@ import dbi
## error
error = "cvsdb error"
## cached (active) database connections
gCheckinDatabase = None
gCheckinDatabaseReadOnly = None
## CheckinDatabase provides all interfaces needed to the SQL database
## back-end; it needs to be subclassed, and have its "Connect" method
## defined to actually be complete; it should run well off of any DBI 2.0
@@ -45,8 +50,6 @@ class CheckinDatabase:
def Connect(self):
self.db = dbi.connect(
self._host, self._port, self._user, self._passwd, self._database)
cursor = self.db.cursor()
cursor.execute("SET AUTOCOMMIT=1")
def sql_get_id(self, table, column, value, auto_set):
sql = "SELECT id FROM %s WHERE %s=%%s" % (table, column)
@@ -246,8 +249,8 @@ class CheckinDatabase:
revision = commit.GetRevision()
sticky_tag = "NULL"
branch_id = self.GetBranchID(commit.GetBranch())
plus_count = commit.GetPlusCount() or '0'
minus_count = commit.GetMinusCount() or '0'
plus_count = commit.GetPlusCount()
minus_count = commit.GetMinusCount()
description_id = self.GetDescriptionID(commit.GetDescription())
sql = "REPLACE INTO checkins"\
@@ -674,20 +677,39 @@ def CreateCommit():
def CreateCheckinQuery():
return CheckinDatabaseQuery()
def ConnectDatabase(cfg, readonly=0):
if readonly:
user = cfg.cvsdb.readonly_user
passwd = cfg.cvsdb.readonly_passwd
else:
user = cfg.cvsdb.user
passwd = cfg.cvsdb.passwd
db = CheckinDatabase(cfg.cvsdb.host, cfg.cvsdb.port, user, passwd,
cfg.cvsdb.database_name, cfg.cvsdb.row_limit)
db.Connect()
return db
def ConnectDatabaseReadOnly(cfg):
return ConnectDatabase(cfg, 1)
global gCheckinDatabaseReadOnly
if gCheckinDatabaseReadOnly:
return gCheckinDatabaseReadOnly
gCheckinDatabaseReadOnly = CheckinDatabase(
cfg.cvsdb.host,
cfg.cvsdb.port,
cfg.cvsdb.readonly_user,
cfg.cvsdb.readonly_passwd,
cfg.cvsdb.database_name,
cfg.cvsdb.row_limit)
gCheckinDatabaseReadOnly.Connect()
return gCheckinDatabaseReadOnly
def ConnectDatabase(cfg):
global gCheckinDatabase
if gCheckinDatabase:
return gCheckinDatabase
gCheckinDatabase = CheckinDatabase(
cfg.cvsdb.host,
cfg.cvsdb.port,
cfg.cvsdb.user,
cfg.cvsdb.passwd,
cfg.cvsdb.database_name,
cfg.cvsdb.row_limit)
gCheckinDatabase.Connect()
return gCheckinDatabase
def GetCommitListFromRCSFile(repository, path_parts, revision=None):
commit_list = []

View File

@@ -200,7 +200,7 @@ Directives
equivalent to "[CALLBACK QUAL_NAME]"
"""
#
# Copyright (C) 2001-2007 Greg Stein. All Rights Reserved.
# Copyright (C) 2001-2005 Greg Stein. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -659,7 +659,7 @@ def _write_value(value, args, ctx):
piece = args[idx]
else:
piece = '<undef>'
printer(ctx, piece)
printer(ctx, piece)
# plain old value, write to output
else:

View File

@@ -364,11 +364,11 @@ class _pipe:
else:
if self.thread:
self.thread.join()
if type(self.child_pid) == type([]):
if type(self.child_pid) == type([]):
for pid in self.child_pid:
exit = os.waitpid(pid, 0)[1]
return exit
else:
else:
return os.waitpid(self.child_pid, 0)[1]
return None

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -25,7 +25,6 @@ import time
import cvsdb
import viewvc
import vclib
import ezt
import debug
import urllib
@@ -283,8 +282,10 @@ def build_commit(server, cfg, desc, files, cvsroots, viewvc_link):
ob.log = '&nbsp;'
for commit in files:
parts = filter(None, string.split(commit.GetDirectory(), '/'))
if parts and cfg.options.hide_cvsroot and parts[0] == 'CVSROOT':
dir_parts = filter(None, string.split(commit.GetDirectory(), '/'))
if dir_parts \
and ((dir_parts[0] == 'CVSROOT' and cfg.options.hide_cvsroot) \
or cfg.is_forbidden(dir_parts[0])):
continue
ctime = commit.GetTime()
@@ -303,11 +304,6 @@ def build_commit(server, cfg, desc, files, cvsroots, viewvc_link):
file = (directory and directory + "/") + commit.GetFile()
cvsroot_name = cvsroots.get(repository)
## skip forbidden files
if cfg.is_forbidden(cvsroot_name,
filter(None, string.split(file, "/")), vclib.FILE):
continue
## if we couldn't find the cvsroot path configured in the
## viewvc.conf file, then don't make the link
if cvsroot_name:
@@ -349,7 +345,7 @@ def run_query(server, cfg, form_data, viewvc_link):
files = [ ]
cvsroots = {}
rootitems = cfg.general.svn_roots.items() + cfg.general.cvs_roots.items()
rootitems = cfg.general.cvs_roots.items() + cfg.general.svn_roots.items()
for key, value in rootitems:
cvsroots[cvsdb.CleanRepository(value)] = key
@@ -370,13 +366,6 @@ def run_query(server, cfg, form_data, viewvc_link):
commits.append(build_commit(server, cfg, current_desc, files,
cvsroots, viewvc_link))
# Strip out commits that don't have any files attached to them. The
# files probably aren't present because they've been blocked via
# forbiddenness.
def _only_with_files(commit):
return len(commit.files) > 0
commits = filter(_only_with_files, commits)
return commits
def main(server, cfg, viewvc_link):

View File

@@ -135,7 +135,7 @@ class CgiServer(Server):
def addheader(self, name, value):
self.headers.append((name, value))
def header(self, content_type='text/html; charset=UTF-8', status=None):
def header(self, content_type='text/html', status=None):
if not self.headerSent:
self.headerSent = 1
@@ -209,10 +209,7 @@ class AspServer(ThreadedServer):
if not self.headerSent:
try:
self.headerSent = 1
if content_type is None:
self.response.ContentType = 'text/html; charset=UTF-8'
else:
self.response.ContentType = content_type
if content_type is not None: self.response.ContentType = content_type
if status is not None: self.response.Status = status
except AttributeError:
pass
@@ -293,7 +290,7 @@ class ModPythonServer(ThreadedServer):
def header(self, content_type=None, status=None):
if content_type is None:
self.request.content_type = 'text/html; charset=UTF-8'
self.request.content_type = 'text/html'
else:
self.request.content_type = content_type
self.headerSent = 1

View File

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

View File

@@ -346,7 +346,7 @@ class CVSParser(rcsparse.Sink):
is_trunk_revision = self.trunk_rev.match(revision) is not None
if is_trunk_revision:
diffs = self.deltatext_split(last_revision)
diffs = self.deltatext_split(last_revision)
# Revisions on the trunk specify deltas that transform a
# revision into an earlier revision, so invert the translation
@@ -379,7 +379,7 @@ class CVSParser(rcsparse.Sink):
# the trunk. They specify deltas that transform a revision
# into a later revision.
adjust = 0
diffs = self.deltatext_split(revision)
diffs = self.deltatext_split(revision)
for command in diffs:
if skip > 0:
skip = skip - 1

View File

@@ -78,7 +78,7 @@ class RCSStopParser(Exception):
#
class _Parser:
stream_class = None # subclasses need to define this
stream_class = None # subclasses need to define this
def parse_rcs_admin(self):
while 1:
@@ -196,7 +196,7 @@ class _Parser:
if token == ';':
break
author = author + token + ' '
author = author[:-1] # toss the trailing space
author = author[:-1] # toss the trailing space
# Parse state
self.ts.match('state')
@@ -206,7 +206,7 @@ class _Parser:
if token == ';':
break
state = state + token + ' '
state = state[:-1] # toss the trailing space
state = state[:-1] # toss the trailing space
# Parse branches
self.ts.match('branches')

View File

@@ -26,7 +26,7 @@ class _TokenStream:
# note: we use a multiple of a standard block size
CHUNK_SIZE = 192 * 512 # about 100k
# CHUNK_SIZE = 5 # for debugging, make the function grind...
# CHUNK_SIZE = 5 # for debugging, make the function grind...
def __init__(self, file):
self.rcsfile = file
@@ -51,7 +51,7 @@ class _TokenStream:
buf = self.rcsfile.read(self.CHUNK_SIZE)
if buf == '':
# signal EOF by returning None as the token
del self.buf # so we fail if get() is called again
del self.buf # so we fail if get() is called again
return None
idx = 0

View File

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

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -15,11 +15,9 @@
import vclib
import os
import os.path
import stat
import string
import cStringIO
import signal
import shutil
import time
import tempfile
import popen
@@ -272,70 +270,62 @@ class ChangedPath:
self.is_copy = is_copy
def get_revision_info(svnrepos, rev):
fsroot = svnrepos._getroot(rev)
class ChangedPathSet:
def __init__(self):
self.changes = { }
# Get the changes for the revision
editor = repos.ChangeCollector(svnrepos.fs_ptr, fsroot, svnrepos.pool)
e_ptr, e_baton = delta.make_editor(editor, svnrepos.pool)
repos.svn_repos_replay(fsroot, e_ptr, e_baton, svnrepos.pool)
changes = editor.get_changes()
changedpaths = {}
# Copy the Subversion changes into a new hash, converting them into
# ChangedPath objects.
for path in changes.keys():
change = changes[path]
def add_change(self, change):
if change.path:
change.path = _cleanup_path(change.path)
if change.base_path:
change.base_path = _cleanup_path(change.base_path)
path = change.path
action = 'modified'
is_copy = 0
if not hasattr(change, 'action'): # new to subversion 1.4.0
action = 'modified'
if not change.path:
action = 'deleted'
elif change.added:
action = '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 == 'deleted':
action = 'replaced'
else:
if change.action == repos.CHANGE_ACTION_ADD:
action = 'added'
elif change.action == repos.CHANGE_ACTION_DELETE:
action = 'deleted'
elif change.action == repos.CHANGE_ACTION_REPLACE:
if not change.path:
action = 'deleted'
path = change.base_path
elif change.added:
action = 'added'
replace_check_path = path
if change.base_path and change.base_rev:
is_copy = 1
replace_check_path = change.base_path
if self.changes.has_key(replace_check_path) \
and self.changes[replace_check_path].action == 'deleted':
action = 'replaced'
else:
action = 'modified'
if (action == 'added' or action == '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] = ChangedPath(path, pathtype, change.prop_changes,
self.changes[path] = ChangedPath(path, pathtype, change.prop_changes,
change.text_changed, change.base_path,
change.base_rev, action, is_copy)
# Actually, what we want is a sorted list of ChangedPath objects.
change_items = changedpaths.values()
change_items.sort(lambda a, b: _compare_paths(a.filename, b.filename))
def get_changes(self):
changes = self.changes.values()
changes.sort(lambda a, b: _compare_paths(a.filename, b.filename))
return changes
def get_revision_info(svnrepos, rev):
fsroot = svnrepos._getroot(rev)
# Get the changes for the revision
cps = ChangedPathSet()
editor = repos.ChangeCollector(svnrepos.fs_ptr, fsroot,
svnrepos.pool, cps.add_change)
e_ptr, e_baton = delta.make_editor(editor, svnrepos.pool)
repos.svn_repos_replay(fsroot, e_ptr, e_baton, svnrepos.pool)
# Now get the revision property info. Would use
# editor.get_root_props(), but something is broken there...
datestr, author, msg = _fs_rev_props(svnrepos.fs_ptr, rev, svnrepos.pool)
date = _datestr_to_date(datestr, svnrepos.pool)
return date, author, msg, change_items
return date, author, msg, cps.get_changes()
def _log_helper(svnrepos, rev, path, pool):
@@ -493,43 +483,12 @@ class BlameSource:
self.last = None
self.first_rev = first_rev
# Do a little dance to get a URL that works in both Unix-y and
# Windows worlds.
rootpath = os.path.abspath(rootpath)
if rootpath and rootpath[0] != '/':
rootpath = '/' + rootpath
if os.sep != '/':
rootpath = string.replace(rootpath, os.sep, '/')
# Make a read-only temporary directory for Subversion to use as
# its runtime config dir. (Read-only because that will prevent
# Subversion from fleshing out all the default runtime config
# contents.)
self.config_dir = self._mkdtemp()
os.chmod(self.config_dir, stat.S_IRUSR | stat.S_IXUSR)
url = 'file://' + string.join([rootpath, fs_path], "/")
fp = popen.popen(svn_client_path,
("blame",
"-r%d" % int(rev),
"--non-interactive",
"--config-dir", self.config_dir,
"%s@%d" % (url, int(rev))),
('blame', "-r%d" % int(rev), "%s@%d" % (url, int(rev))),
'rb', 1)
self.fp = fp
def _mkdtemp(self):
### FIXME: When we require Python 2.3, this can go away.
for i in range(10):
dir = tempfile.mktemp()
try:
os.mkdir(dir, 0700)
return dir
except OSError, e:
if e.errno == errno.EEXIST:
continue # try again
raise
raise IOError, (errno.EEXIST, "No usable temporary directory name found")
def __getitem__(self, idx):
if idx == self.idx:
@@ -554,13 +513,6 @@ class BlameSource:
self.last = item
self.idx = idx
return item
def __del__(self):
try:
if self.config_dir:
shutil.rmtree(self.config_dir)
except:
pass
class BlameSequencingError(Exception):

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2006 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
@@ -100,12 +100,8 @@ def created_rev(svnrepos, full_name, rev):
kind = ra.svn_ra_check_path(svnrepos.ra_session, full_name, rev,
svnrepos.pool)
if kind == core.svn_node_dir:
retval = ra.svn_ra_get_dir(svnrepos.ra_session, full_name,
rev, svnrepos.pool)
if type(retval) == type([]) and len(retval) == 3:
props = retval[2]
else: # compat with older (broken) bindings
props = retval
props = ra.svn_ra_get_dir(svnrepos.ra_session, full_name,
rev, svnrepos.pool)
return int(props[core.SVN_PROP_ENTRY_COMMITTED_REV])
return core.SVN_INVALID_REVNUM
@@ -180,14 +176,12 @@ class LogCollector:
# Changed paths have leading slashes
changed_paths = paths.keys()
changed_paths.sort(lambda a, b: _compare_paths(a, b))
copyfrom_path = copyfrom_rev = this_path = None
this_path = None
if self.path in changed_paths:
this_path = self.path
change = paths[self.path]
if change.copyfrom_path:
this_path = change.copyfrom_path
copyfrom_path = change.copyfrom_path[1:]
copyfrom_rev = change.copyfrom_rev
for changed_path in changed_paths:
if changed_path != self.path:
# If a parent of our path was copied, our "next previous"
@@ -200,7 +194,7 @@ class LogCollector:
if self.show_all_logs or this_path:
date = _datestr_to_date(date, pool)
entry = Revision(revision, date, author, message, None,
self.path[1:], copyfrom_path, copyfrom_rev)
self.path[1:], None, None)
self.logs.append(entry)
if this_path:
self.path = this_path
@@ -246,7 +240,7 @@ class SelfCleanFP:
self._path = path
self._eof = 0
def read(self, len=None):
def read(self, len):
if len:
chunk = self._fp.read(len)
else:

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -14,7 +14,7 @@
#
# -----------------------------------------------------------------------
__version__ = '1.0.7'
__version__ = '1.0.1'
# this comes from our library; measure the startup time
import debug
@@ -160,15 +160,6 @@ class Request:
# 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]
@@ -200,7 +191,7 @@ class Request:
# handle tarball magic suffixes
if self.view_func is download_tarball:
if (self.query_dict.get('parent')):
del path_parts[-1]
del path_parts[-1]
elif path_parts[-1][-7:] == ".tar.gz":
path_parts[-1] = path_parts[-1][:-7]
@@ -292,19 +283,13 @@ class Request:
needs_redirect = 1
if self.repos and self.view_func is not redirect_pathrev:
# If this is an intended-to-be-hidden CVSROOT path, complain.
if cfg.options.hide_cvsroot \
and is_cvsroot_path(self.roottype, path_parts):
raise debug.ViewVCException('%s: unknown location'
% self.where, '404 Not Found')
# Make sure path exists
self.pathrev = pathrev = self.query_dict.get('pathrev')
self.pathtype = _repos_pathtype(self.repos, path_parts, pathrev)
if self.pathtype is None:
# Path doesn't exist, see if it could be an old-style ViewVC URL
# with a fake suffix.
# path doesn't exist, see if it could be an old-style ViewVC URL
# with a fake suffix
result = _strip_suffix('.diff', path_parts, pathrev, vclib.FILE, \
self.repos, view_diff) or \
_strip_suffix('.tar.gz', path_parts, pathrev, vclib.DIR, \
@@ -323,7 +308,7 @@ class Request:
if result:
self.path_parts, self.pathtype, self.view_func = result
self.where = _path_join(self.path_parts)
needs_redirect = 1
needs_redirect = 1
else:
raise debug.ViewVCException('%s: unknown location'
% self.where, '404 Not Found')
@@ -342,11 +327,11 @@ class Request:
self.where = _path_join(attic_parts)
needs_redirect = 1
# If this is a forbidden location, stop now
if cfg.is_forbidden(self.rootname, self.path_parts, self.pathtype):
raise debug.ViewVCException('%s: unknown location' \
% _path_join(self.path_parts),
'404 Not Found')
# If this is a forbidden directory, stop now
if self.path_parts and self.pathtype == vclib.DIR \
and cfg.is_forbidden(self.path_parts[0]):
raise debug.ViewVCException('%s: unknown location' % path_parts[0],
'404 Not Found')
if self.view_func is None:
# view parameter is not set, try looking at pathtype and the
@@ -355,7 +340,7 @@ class Request:
self.view_func = view_roots
elif self.pathtype == vclib.DIR:
# ViewCVS 0.9.2 used to put ?tarball=1 at the end of tarball urls
if self.query_dict.has_key('tarball'):
if self.query_dict.has_key('tarball'):
self.view_func = download_tarball
else:
self.view_func = view_directory
@@ -514,7 +499,7 @@ class Request:
if view_func is download_tarball:
if not where and not cfg.options.root_as_url_component:
url = url + '/' + rootname + '-root'
params['parent'] = '1'
params['parent'] = '1'
url = url + '.tar.gz'
# add trailing slash for a directory
@@ -763,11 +748,8 @@ def _orig_path(request, rev_param='revision', path_param=None):
path = request.query_dict.get(path_param, request.where)
if rev is not None and hasattr(request.repos, '_getrev'):
try:
pathrev = request.repos._getrev(request.pathrev)
rev = request.repos._getrev(rev)
except vclib.InvalidRevision:
raise debug.ViewVCException('Invalid revision', '404 Not Found')
pathrev = request.repos._getrev(request.pathrev)
rev = request.repos._getrev(rev)
return _path_parts(vclib.svn.get_location(request.repos, path,
pathrev, rev)), rev
return _path_parts(path), rev
@@ -921,9 +903,6 @@ def is_viewable_image(mime_type):
def is_text(mime_type):
return not mime_type or mime_type[:5] == 'text/'
def is_cvsroot_path(roottype, path_parts):
return roottype == 'cvs' and path_parts and path_parts[0] == 'CVSROOT'
def is_plain_text(mime_type):
return not mime_type or mime_type == 'text/plain'
@@ -997,13 +976,8 @@ def htmlify(html):
html = re.sub(_re_rewrite_email, r'<a href="mailto:\1&#64;\2">\1&#64;\2</a>', html)
return html
def format_log(log, cfg, htmlize=1):
if not log:
return log
if htmlize:
s = htmlify(log[:cfg.options.short_log_len])
else:
s = cgi.escape(log[:cfg.options.short_log_len])
def format_log(log, cfg):
s = htmlify(log[:cfg.options.short_log_len])
if len(log) > cfg.options.short_log_len:
s = s + '...'
return s
@@ -1339,15 +1313,18 @@ 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")
sys.stdout.flush()
# clearing the following environment variables prevents a
# "No input file specified" error from the php cgi executable
# when ViewVC is running under a cgi environment. when the
# php cli executable is used they can be left alone
#
#os.putenv("GATEWAY_INTERFACE", "")
#os.putenv("PATH_TRANSLATED", "")
#os.putenv("REQUEST_METHOD", "")
#os.putenv("SERVER_NAME", "")
#os.putenv("SERVER_SOFTWARE", "")
return MarkupPHP(cfg.options.php_exe_path, fp)
@@ -1382,10 +1359,6 @@ def make_rss_time_string(date, cfg):
return time.strftime("%a, %d %b %Y %H:%M:%S", time.gmtime(date)) + ' UTC'
def view_markup(request):
if not request.cfg.options.allow_markup:
raise debug.ViewVCException('Markup view is disabled',
'403 Forbidden')
cfg = request.cfg
path, rev = _orig_path(request)
fp, revision = request.repos.openfile(path, rev)
@@ -1452,17 +1425,14 @@ def view_markup(request):
streamer = markup_streamers.get(ext)
if streamer:
markup_fp = streamer(fp, cfg)
elif 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])
# 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])
else:
# If no one has a suitable markup handler, we'll use the default.
markup_fp = MarkupPipeWrapper(fp)
# If no one has a suitable markup handler, we'll use the default.
if not markup_fp:
markup_fp = MarkupPipeWrapper(fp)
data['markup'] = markup_fp
@@ -1544,10 +1514,7 @@ def view_directory(request):
# the directory listing (to take into account template changes or
# revision property changes).
if request.roottype == 'svn':
try:
rev = request.repos._getrev(request.pathrev)
except vclib.InvalidRevision:
raise debug.ViewVCException('Invalid revision', '404 Not Found')
rev = request.repos._getrev(request.pathrev)
tree_rev = vclib.svn.created_rev(request.repos, request.where, rev)
if check_freshness(request, None, str(tree_rev), weak=1):
return
@@ -1560,9 +1527,16 @@ def view_directory(request):
cfg.options.hide_attic))
options["cvs_subdirs"] = (cfg.options.show_subdir_lastmod and
cfg.options.show_logs)
file_data = request.repos.listdir(request.path_parts, request.pathrev,
options)
# Filter file list if a regex is specified
search_re = request.query_dict.get('search', '')
if cfg.options.use_re_search and search_re:
file_data = search_files(request.repos, request.path_parts, request.pathrev,
file_data, search_re)
# Retrieve log messages, authors, revision numbers, timestamps
request.repos.dirlogs(request.path_parts, request.pathrev, file_data, options)
@@ -1572,12 +1546,6 @@ def view_directory(request):
sort_file_data(file_data, request.roottype, sortdir, sortby,
cfg.options.sort_group_dirs)
# If a regex is specified, build a compiled form thereof for filtering
searchstr = None
search_re = request.query_dict.get('search', '')
if cfg.options.use_re_search and search_re:
searchstr = re.compile(search_re)
# loop through entries creating rows and changing these values
rows = [ ]
num_displayed = 0
@@ -1609,14 +1577,13 @@ def view_directory(request):
(file.kind == vclib.DIR and 'dir')
row.errors = file.errors
if cfg.is_forbidden(request.rootname, request.path_parts + [file.name],
file.kind):
continue
if file.kind == vclib.DIR:
if cfg.options.hide_cvsroot \
and is_cvsroot_path(request.roottype,
request.path_parts + [file.name]):
if (where == '') and (cfg.is_forbidden(file.name)):
continue
if (request.roottype == 'cvs' and cfg.options.hide_cvsroot
and where == '' and file.name == 'CVSROOT'):
continue
row.view_href = request.get_url(view_func=view_directory,
@@ -1644,17 +1611,10 @@ def view_directory(request):
escape=1)
elif file.kind == vclib.FILE:
if searchstr is not None:
if request.roottype == 'cvs' and (file.errors or file.dead):
continue
if not search_file(request.repos, request.path_parts + [file.name],
request.pathrev, searchstr):
continue
if request.roottype == 'cvs' and file.dead:
num_dead = num_dead + 1
if hideattic:
continue
num_displayed = num_displayed + 1
file_where = where_prefix + file.name
@@ -1865,7 +1825,7 @@ def redirect_pathrev(request):
try:
new_pathrev = int(new_pathrev)
except ValueError:
new_pathrev = youngest
pass
except TypeError:
pass
else:
@@ -1921,12 +1881,10 @@ def view_log(request):
# selected revision
selected_rev = request.query_dict.get('r1')
paths_forbidden = {}
entries = [ ]
name_printed = { }
cvs = request.roottype == 'cvs'
for rev in show_revs:
last_one = 0
entry = _item()
entry.rev = rev.string
entry.state = (cvs and rev.dead and 'dead')
@@ -1991,27 +1949,8 @@ def view_log(request):
entry.vendor_branch = None
if rev.filename != request.where:
entry.orig_path = rev.filename
# If this path has been copied, check the copy source for
# forbiddenness. If it's forbidden, we'll a) pretend this is a
# regular add (instead of a copy), and b) stop traversing history.
if rev.copy_path:
if not paths_forbidden.has_key(rev.copy_path):
paths_forbidden[rev.copy_path] = \
cfg.is_forbidden(request.rootname,
_path_parts(rev.copy_path), pathtype)
if paths_forbidden[rev.copy_path]:
entry.prev = None
last_one = 1
else:
entry.copy_path = rev.copy_path
entry.copy_rev = rev.copy_rev
entry.copy_href = request.get_url(view_func=view_log,
where=rev.copy_path,
pathtype=vclib.FILE,
params={'pathrev': rev.copy_rev},
escape=1)
entry.copy_path = rev.copy_path
entry.copy_rev = rev.copy_rev
if entry.orig_path:
entry.orig_href = request.get_url(view_func=view_log,
@@ -2020,6 +1959,14 @@ def view_log(request):
params={'pathrev': rev.string},
escape=1)
if rev.copy_path:
entry.copy_href = request.get_url(view_func=view_log,
where=rev.copy_path,
pathtype=vclib.FILE,
params={'pathrev': rev.copy_rev},
escape=1)
# view/download links
if pathtype is vclib.FILE:
entry.view_href, entry.download_href, entry.download_text_href, \
@@ -2076,12 +2023,10 @@ def view_log(request):
# Save our escaping until the end so stuff above works
if entry.orig_path:
entry.orig_path = request.server.escape(entry.orig_path)
entry.orig_path = request.server.escape(entry.orig_path)
if entry.copy_path:
entry.copy_path = request.server.escape(entry.copy_path)
entries.append(entry)
if last_one:
break
data = common_template_data(request)
data.update({
@@ -2145,8 +2090,9 @@ def view_log(request):
'tag_prefer_markup': prefer_markup,
})
else:
data['view_href'] = request.get_url(view_func=view_directory,
params={}, escape=1)
if not request.pathrev:
data['view_href'] = request.get_url(view_func=view_directory,
params={}, escape=1)
taginfo = options.get('cvs_tags', {})
tagitems = taginfo.items()
@@ -2205,7 +2151,7 @@ def view_annotate(request):
diff_url = request.get_url(view_func=view_diff,
params={'r1': None, 'r2': None},
escape=1, partial=1)
escape=1, partial=1)
include_url = request.get_url(view_func=view_log, where='/WHERE/',
pathtype=vclib.FILE, params={}, escape=1)
@@ -2287,23 +2233,58 @@ def view_cvsgraph(request):
request.server.header()
generate_page(request, "graph", data)
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."""
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
# 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.
@@ -2572,29 +2553,21 @@ def diff_parse_headers(fp, diff_type, rev1, rev2, sym1=None, sym2=None):
return date1, date2, flag, string.join(header_lines, '')
def _get_svn_location(request, base_rev, rev):
repos = request.repos
try:
parts = _path_parts(vclib.svn.get_location(repos, request.where,
repos._getrev(base_rev),
repos._getrev(rev)))
except vclib.InvalidRevision:
raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
'to diff', '400 Bad Request')
except vclib.ItemNotFound:
raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
'to diff', '400 Bad Request')
if request.cfg.is_forbidden(request.rootname, parts, vclib.FILE):
raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
'to diff', '400 Bad Request')
return parts
def _get_diff_path_parts(request, query_key, rev, base_rev):
if request.query_dict.has_key(query_key):
parts = _path_parts(request.query_dict[query_key])
elif request.roottype == 'svn':
parts = _get_svn_location(request, base_rev, rev)
try:
repos = request.repos
parts = _path_parts(vclib.svn.get_location(repos, request.where,
repos._getrev(base_rev),
repos._getrev(rev)))
except vclib.InvalidRevision:
raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
'to diff', '400 Bad Request')
except vclib.ItemNotFound:
raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
'to diff', '400 Bad Request')
else:
parts = request.path_parts
return parts
@@ -2636,12 +2609,8 @@ def setup_diff(request):
sym2 = r2[idx+1:]
if request.roottype == 'svn':
try:
rev1 = str(request.repos._getrev(rev1))
rev2 = str(request.repos._getrev(rev2))
except vclib.InvalidRevision:
raise debug.ViewVCException('Invalid revision(s) passed to diff',
'400 Bad Request')
rev1 = str(request.repos._getrev(rev1))
rev2 = str(request.repos._getrev(rev2))
p1 = _get_diff_path_parts(request, 'p1', rev1, request.pathrev)
p2 = _get_diff_path_parts(request, 'p2', rev2, request.pathrev)
@@ -2814,7 +2783,7 @@ def generate_tarball_header(out, name, size=0, mode=None, mtime=0,
uid=0, gid=0, typefrag=None, linkname='',
uname='viewvc', gname='viewvc',
devmajor=1, devminor=0, prefix=None,
magic='ustar', version='00', chksum=None):
magic='ustar', version='', chksum=None):
if not mode:
if name[-1:] == '/':
mode = 0755
@@ -2830,12 +2799,6 @@ def generate_tarball_header(out, name, size=0, mode=None, mtime=0,
if not prefix:
prefix = ''
# 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')
out.write(name)
out.write('\0' * (511 - ((len(name) + 511) % 512)))
block1 = struct.pack('100s 8s 8s 8s 12s 12s',
name,
'%07o' % mode,
@@ -2914,11 +2877,6 @@ def generate_tarball(out, request, reldir, stack, dir_mtime=None):
if cvs and (file.rev is None or file.dead):
continue
# Skip forbidden files.
if request.cfg.is_forbidden(request.rootname, rep_path + [file.name],
file.kind):
continue
# If we get here, we've seen at least one valid file in the
# current directory. For CVS, we need to make sure there are
# directory parents to contain it, so we flush the stack.
@@ -2949,16 +2907,13 @@ def generate_tarball(out, request, reldir, stack, dir_mtime=None):
if file.errors or file.kind != vclib.DIR:
continue
# Skip hidden directories (top-level only).
if request.cfg.options.hide_cvsroot \
and is_cvsroot_path(request.roottype, rep_path + [file.name]):
continue
# Skip forbidden/hidden directories (top-level only).
if not rep_path:
if (request.cfg.is_forbidden(file.name)
or (cvs and request.cfg.options.hide_cvsroot
and file.name == 'CVSROOT')):
continue
# Skip forbidden subdirs.
if request.cfg.is_forbidden(request.rootname, rep_path + [file.name],
file.kind):
continue
mtime = request.roottype == 'svn' and file.date or None
generate_tarball(out, request, reldir + [file.name], stack, mtime)
@@ -2990,11 +2945,7 @@ def view_revision(request):
data = common_template_data(request)
query_dict = request.query_dict
try:
rev = request.repos._getrev(query_dict.get('revision'))
except vclib.InvalidRevision:
raise debug.ViewVCException('Invalid revision', '404 Not Found')
rev = request.repos._getrev(query_dict.get('revision'))
date, author, msg, changes = vclib.svn.get_revision_info(request.repos, rev)
date_str = make_time_string(date, request.cfg)
@@ -3002,14 +2953,6 @@ def view_revision(request):
if check_freshness(request, None, str(rev), weak=1):
return
# Strip forbidden changed paths (we allow forbidden copyfrom-paths
# to leak through, though).
def _only_allowed(change):
return not request.cfg.is_forbidden(request.rootname,
_path_parts(change.filename),
change.pathtype)
changes = filter(_only_allowed, changes)
# Handle limit_changes parameter
cfg_limit_changes = request.cfg.options.limit_changes
limit_changes = int(query_dict.get('limit_changes', cfg_limit_changes))
@@ -3035,24 +2978,10 @@ def view_revision(request):
pathtype = (change.pathtype == vclib.FILE and 'file') \
or (change.pathtype == vclib.DIR and 'dir') \
or None
# If this is an add or a replacement, we'll verify that copyfrom
# paths are readable (if this is a copy), and if not claim this
# isn't a copy after all. And if it ain't a copy (now or "after
# all"), we'll clear the text_mods and prop_mods flags.
if (change.action == 'added' or change.action == 'replaced'):
if change.is_copy \
and request.cfg.is_forbidden(request.rootname,
_path_parts(change.base_path),
change.pathtype):
change.is_copy = 0
if change.action == 'added':
change.base_path = None
change.base_rev = None
if not change.is_copy:
change.text_mods = 0
change.prop_mods = 0
if (change.action == 'added' or change.action == 'replaced') \
and not change.is_copy:
change.text_mods = 0
change.prop_mods = 0
view_func = None
if change.pathtype is vclib.FILE:
@@ -3217,23 +3146,22 @@ def english_query(request):
ret.append('subdirectories')
else:
ret.append('subdirectory')
ret.append(' <em>%s</em> ' % request.server.escape(dir))
ret.append(' <em>%s</em> ' % htmlify(dir))
file = request.query_dict.get('file', '')
if file:
if len(ret) != 1: ret.append('and ')
ret.append('to file <em>%s</em> ' % request.server.escape(file))
ret.append('to file <em>%s</em> ' % htmlify(file))
who = request.query_dict.get('who', '')
branch = request.query_dict.get('branch', '')
if branch:
ret.append('on branch <em>%s</em> ' % request.server.escape(branch))
ret.append('on branch <em>%s</em> ' % htmlify(branch))
else:
ret.append('on all branches ')
if who:
ret.append('by <em>%s</em> ' % request.server.escape(who))
ret.append('by <em>%s</em> ' % htmlify(who))
date = request.query_dict.get('date', 'hours')
if date == 'hours':
ret.append('in the last %s hours' \
% request.server.escape(request.query_dict.get('hours', '2')))
ret.append('in the last %s hours' % htmlify(request.query_dict.get('hours', '2')))
elif date == 'day':
ret.append('in the last day')
elif date == 'week':
@@ -3267,135 +3195,92 @@ def prev_rev(rev):
r = r[:-2]
return string.join(r, '.')
def build_commit(request, files, max_files, dir_strip, format):
"""Return a commit object build from the information in FILES, or
None if no allowed files are present in the set. DIR_STRIP is the
path prefix to remove from the commit object's set of files. If
MAX_FILES is non-zero, it is used to limit the number of files
returned in the commit object. FORMAT is the requested output
format of the query request."""
author = files[0].GetAuthor()
date = files[0].GetTime()
def build_commit(request, files, limited_files, dir_strip):
commit = _item(num_files=len(files), files=[])
commit.limited_files = ezt.boolean(limited_files)
desc = files[0].GetDescription()
commit_rev = files[0].GetRevision()
len_strip = len(dir_strip)
commit_files = []
num_allowed = 0
plus_count = 0
minus_count = 0
for f in files:
commit_time = f.GetTime()
if commit_time:
commit_time = make_time_string(commit_time, request.cfg)
else:
commit_time = '&nbsp;'
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:]
where = dirname and ("%s/%s" % (dirname, filename)) or filename
# skip files in forbidden or hidden modules
path_parts = _path_parts(where)
if request.cfg.is_forbidden(request.rootname, path_parts, vclib.FILE):
continue
if request.cfg.options.hide_cvsroot \
and is_cvsroot_path(request.roottype, path_parts):
continue
# In CVS, we can actually look at deleted revisions; in Subversion
# we can't -- we'll look at the previous revision instead.
if request.roottype == 'svn':
if change_type == 'Remove':
params = { 'pathrev': rev_prev }
else:
params = { 'pathrev': rev }
else:
params = { 'revision': 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=where, pathtype=vclib.FILE,
params=params, escape=1)
diff_href = view_href = download_href = None
view_href = request.get_url(view_func=view_markup,
where=where, pathtype=vclib.FILE,
params=params, escape=1)
download_href = request.get_url(view_func=view_checkout,
where=where, pathtype=vclib.FILE,
params=params, escape=1)
if change_type == 'Change':
diff_href_params = params.copy()
diff_href_params.update({
'r1': rev_prev,
'r2': rev,
'diff_format': None
})
diff_href = request.get_url(view_func=view_diff,
where=where, pathtype=vclib.FILE,
params=diff_href_params, escape=1)
prefer_markup = ezt.boolean(default_view(guess_mime(filename),
request.cfg) == view_markup)
# 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,
dir=request.server.escape(dirname),
file=request.server.escape(filename),
author=request.server.escape(f.GetAuthor()),
rev=rev,
branch=f.GetBranch(),
plus=plus,
minus=minus,
type=change_type,
dir_href=dir_href,
log_href=log_href,
view_href=view_href,
download_href=download_href,
prefer_markup=prefer_markup,
diff_href=diff_href))
# No files survived forbiddenness checks? Let's just pretend this
# little commit didn't happen, shall we?
if not len(commit_files):
return None
commit = _item(num_files=len(commit_files), files=commit_files,
plus=plus_count, minus=minus_count)
commit.limited_files = ezt.boolean(num_allowed > len(commit_files))
commit.log = htmlify(desc)
commit.short_log = format_log(desc, request.cfg, format != 'rss')
commit.author = request.server.escape(author)
commit.rss_date = make_rss_time_string(date, request.cfg)
commit.short_log = format_log(desc, request.cfg)
commit.author = htmlify(files[0].GetAuthor())
commit.rss_date = make_rss_time_string(files[0].GetTime(), 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"),
commit.rev = files[0].GetRevision()
commit.rss_url = 'http://%s%s' % \
(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
len_strip = len(dir_strip)
for f in files:
commit_time = f.GetTime()
if commit_time:
commit_time = make_time_string(commit_time, request.cfg)
else:
commit_time = '&nbsp;'
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
params = { 'revision': f.GetRevision() }
if f.GetBranch(): params['pathrev'] = f.GetBranch()
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,
params=params,
escape=1)
view_href = request.get_url(view_func=view_markup,
where=filename, pathtype=vclib.FILE,
params={'revision': f.GetRevision() },
escape=1)
download_href = request.get_url(view_func=view_checkout,
where=filename, pathtype=vclib.FILE,
params={'revision': f.GetRevision() },
escape=1)
diff_href = request.get_url(view_func=view_diff,
where=filename, pathtype=vclib.FILE,
params={'r1': prev_rev(f.GetRevision()),
'r2': f.GetRevision(),
'diff_format': None},
escape=1)
# skip files in forbidden or hidden modules
dir_parts = filter(None, string.split(dirname, '/'))
if dir_parts \
and ((dir_parts[0] == 'CVSROOT'
and request.cfg.options.hide_cvsroot) \
or request.cfg.is_forbidden(dir_parts[0])):
continue
commit.files.append(_item(date=commit_time,
dir=htmlify(dirname),
file=htmlify(f.GetFile()),
author=htmlify(f.GetAuthor()),
rev=f.GetRevision(),
branch=f.GetBranch(),
plus=int(f.GetPlusCount()),
minus=int(f.GetMinusCount()),
type=f.GetTypeString(),
dir_href=dir_href,
log_href=log_href,
view_href=view_href,
download_href=download_href,
prefer_markup=ezt.boolean
(default_view(guess_mime(filename), request.cfg)
== view_markup),
diff_href=diff_href))
return commit
def query_backout(request, commits):
@@ -3443,7 +3328,7 @@ def view_query(request):
format = request.query_dict.get('format')
limit = int(request.query_dict.get('limit', 0))
limit_changes = int(request.query_dict.get('limit_changes',
request.cfg.options.limit_changes))
request.cfg.options.limit_changes))
match_types = { 'exact':1, 'like':1, 'glob':1, 'regex':1, 'notregex':1 }
sort_types = { 'date':1, 'author':1, 'file':1 }
@@ -3516,7 +3401,7 @@ def view_query(request):
# run the query
db.RunQuery(query)
sql = request.server.escape(db.CreateSQLQueryString(query))
sql = htmlify(db.CreateSQLQueryString(query))
# gather commits
commits = []
@@ -3529,49 +3414,46 @@ def view_query(request):
current_desc = query.commit_list[0].GetDescriptionID()
current_rev = query.commit_list[0].GetRevision()
dir_strip = _path_join(repos_dir)
for commit in query.commit_list:
commit_desc = commit.GetDescriptionID()
commit_rev = commit.GetRevision()
# base modification time on the newest commit
if commit.GetTime() > mod_time:
mod_time = commit.GetTime()
# 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 == commit_desc:
files.append(commit)
if current_desc == desc:
if not limit_changes or len(files) < limit_changes:
files.append(commit)
else:
limited_files = 1
continue
else:
if current_rev == commit_rev:
files.append(commit)
if current_rev == commit.GetRevision():
if not limit_changes or len(files) < limit_changes:
files.append(commit)
else:
limited_files = 1
continue
# 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)
# 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))
files = [ commit ]
limited_files = 0
current_desc = commit_desc
current_rev = commit_rev
current_desc = desc
current_rev = commit.GetRevision()
# 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)
# 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))
# 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
@@ -3615,7 +3497,7 @@ def view_query(request):
})
if format == 'rss':
request.server.header("application/rss+xml")
request.server.header("text/xml")
generate_page(request, "rss", data)
else:
request.server.header()
@@ -3645,10 +3527,10 @@ for code, view in _views.items():
def list_roots(cfg):
allroots = { }
for root in cfg.general.svn_roots.keys():
allroots[root] = [cfg.general.svn_roots[root], 'svn']
for root in cfg.general.cvs_roots.keys():
allroots[root] = [cfg.general.cvs_roots[root], 'cvs']
for root in cfg.general.svn_roots.keys():
allroots[root] = [cfg.general.svn_roots[root], 'svn']
return allroots
def load_config(pathname=None, server=None):

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -15,18 +15,8 @@
# -----------------------------------------------------------------------
import os, sys, traceback, string, thread
try:
import win32api
except ImportError, e:
raise ImportError, str(e) + """
Did you install the Python for Windows Extensions?
http://sourceforge.net/projects/pywin32/
"""
import win32process, win32pipe, win32con
import win32event, win32file, winerror
import win32event, win32file, win32api, winerror
import pywintypes, msvcrt
# Buffer size for spooling

View File

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

View File

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

View File

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

View File

@@ -9,7 +9,7 @@
enter a numeric revision.
[end]
</p>
<form method="get" action="[diff_select_action]" id="diff_select">
<form method="get" action="[diff_select_action]" name="diff_select">
<table cellpadding="2" cellspacing="0" class="auto">
<tr>
@@ -26,7 +26,7 @@
</select>
<input type="text" size="12" name="tr1"
value="[if-any rev_selected][rev_selected][else][first_revision][end]"
onchange="document.getElementById('diff_select').r1.selectedIndex=0" />
onchange="document.diff_select.r1.selectedIndex=0" />
[else]
<input type="text" size="12" name="r1"
value="[if-any rev_selected][rev_selected][else][first_revision][end]" />
@@ -42,7 +42,7 @@
</select>
<input type="text" size="12" name="tr2"
value="[last_revision]"
onchange="document.getElementById('diff_select').r2.selectedIndex=0" />
onchange="document.diff_select.r1.selectedIndex=0" />
[else]
<input type="text" size="12" name="r2" value="[last_revision]" />
[end]

View File

@@ -1,28 +1,38 @@
[if-any search_re_form]
<hr />
<div>
Show files containing the regular expression:
<form method="get" action="[search_re_action]" style="display: inline;">
<div style="display: inline;">
[search_re_hidden_values]
<input type="text" name="search" value="[search_re]" />
<input type="submit" value="Show" />
</div>
</form>
[if-any search_re]
<form method="get" action="[search_re_action]" style="display: inline;">
<div style="display: inline;">
[search_re_hidden_values]
<input type="submit" value="Show all files" />
</div>
</form>
<hr />
[# this table holds the selectors on the left, and reset on the right ]
<table class="auto">
<tr>
<td>Show files containing the regular expression:</td>
<td>
<form method="get" action="[search_re_action]">
<div>
[search_re_hidden_values]
<input type="text" name="search" value="[search_re]" />
<input type="submit" value="Show" />
</div>
</form>
</td>
</tr>
[if-any search_re]
<tr>
<td>&nbsp;</td>
<td>
<form method="get" action="[search_tag_action]">
<div>
[search_tag_hidden_values]
<input type="submit" value="Show all files" />
</div>
</form>
</td>
</tr>
[end]
</table>
[end]
[end]
</div>
[# 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>
<p style="margin:0;"><a href="[tarball_href]">Download tarball</a></p>
[end]
[include "footer.ezt"]

View File

@@ -9,7 +9,7 @@
</tr>
<tr>
<td>Powered by <a href="http://viewvc.tigris.org/">ViewVC [vsn]</a></td>
<td style="text-align: right;">[if-any rss_href]<a href="[rss_href]" title="RSS 2.0 feed"><img src="[docroot]/images/feed-icon-16x16.jpg" alt="RSS 2.0 feed"/></a>[else]&nbsp;[end]</td>
<td style="text-align: right;">[if-any rss_href]<a href="[rss_href]" title="RSS 2.0 feed"><img src="[docroot]/images/feed-icon-16x16.jpg"/>[else]&nbsp;[end]</td>
</tr>
</table>

View File

@@ -6,7 +6,7 @@
<title>[if-any rootname][[][rootname]][else]ViewVC[end] [page_title]</title>
<meta name="generator" content="ViewVC [vsn]" />
<link rel="stylesheet" href="[docroot]/styles.css" type="text/css" />
[if-any rss_href]<link rel="alternate" type="application/rss+xml" title="RSS [[][rootname]][where]" href="[rss_href]" />[end]
[if-any rss_href]<link rel="alternate" type="application/rss+xml" title="RSS [[][rootname]][where]" HREF="[rss_href]">[end]
</head>
<body>
<div class="vc_navheader">

View File

@@ -1,5 +1,4 @@
<form method="get" action="[pathrev_action]" style="display: inline">
<div style="display: inline">
[pathrev_hidden_values]
[is roottype "cvs"]
[define pathrev_selected][pathrev][end]
@@ -35,19 +34,16 @@
<input type="text" name="pathrev" value="[pathrev]" size="6"/>
[end]
<input type="submit" value="Set" />
</div>
</form>
[if-any pathrev]
<form method="get" action="[pathrev_clear_action]" style="display: inline">
<div style="display: inline">
[pathrev_clear_hidden_values]
[if-any lastrev]
[is pathrev lastrev][else]<input type="submit" value="Set to [lastrev]" />[end]
[is pathrev lastrev][else]<input type="submit" value="Set to [lastrev]">[end]
(<i>Current path doesn't exist after revision <strong>[lastrev]</strong></i>)
[else]
<input type="submit" value="Clear" />
<input type="submit" value="Clear">
[end]
</div>
</form>
[end]

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- Mode: python -*-
#
# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2006 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
@@ -11,7 +11,10 @@
#
# -----------------------------------------------------------------------
#
# Install script for ViewVC
# install script for viewvc -- temporary?
#
# ### this will eventually be replaced by autoconf plus tools. an
# ### interactive front-end to ./configure may be provided.
#
# -----------------------------------------------------------------------
@@ -24,7 +27,7 @@ import py_compile
import getopt
import StringIO
# Get access to our library modules.
# get access to our library modules
sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), 'lib'))
import compat
@@ -33,441 +36,324 @@ import compat_ndiff
version = viewvc.__version__
## Installer defaults.
## installer text
INFO_TEXT = """
This is the ViewVC %s installer.
It will allow you to choose the install path for ViewVC. You will
now be asked some installation questions.
Defaults are given in square brackets. Just hit [Enter] if a default
is okay.
""" % version
## installer defaults
DESTDIR = None
ROOT_DIR = None
CLEAN_MODE = None
## List of files for installation.
## tuple (source path,
## destination path,
## mode,
## boolean -- search-and-replace?
## boolean -- prompt before replacing?
## boolean -- compile?)
## list of files for installation
## tuple (source path, destination path, install mode, true/false flag for
## search-and-replace, flag or text for prompt before replace,
## compile_it)
##
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.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/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.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),
("bin/loginfo-handler", "bin/loginfo-handler", 0755, 1, 0, 0),
("bin/cvsdbadmin", "bin/cvsdbadmin", 0755, 1, 0, 0),
("bin/svndbadmin", "bin/svndbadmin", 0755, 1, 0, 0),
("bin/make-database", "bin/make-database", 0755, 1, 0, 0),
("viewvc.conf.dist", "viewvc.conf.dist", 0644, 0, 0, 0),
("viewvc.conf.dist", "viewvc.conf", 0644, 0, 1, 0),
("cvsgraph.conf.dist", "cvsgraph.conf.dist", 0644, 0, 0, 0),
("cvsgraph.conf.dist", "cvsgraph.conf", 0644, 0, 1, 0),
("bin/mod_python/.htaccess", "bin/mod_python/.htaccess", 0755, 0, 0, 0),
("bin/standalone.py", "bin/standalone.py", 0755, 1, 0, 0),
("viewvc.conf.dist", "viewvc.conf", 0644, 0,
"""Note: If you are upgrading from viewcvs-0.7 or earlier:
The section [text] has been removed from viewcvs.conf. The functionality
went into the new files in subdirectory templates.""", 0),
("cvsgraph.conf.dist", "cvsgraph.conf", 0644, 0, 1, 0),
("bin/loginfo-handler", "bin/loginfo-handler", 0755, 1, 0, 0),
("bin/cvsdbadmin", "bin/cvsdbadmin", 0755, 1, 0, 0),
("bin/svndbadmin", "bin/svndbadmin", 0755, 1, 0, 0),
("bin/make-database", "bin/make-database", 0755, 1, 0, 0),
]
if sys.platform == "win32":
FILE_INFO_LIST.extend([
("bin/asp/viewvc.asp", "bin/asp/viewvc.asp", 0755, 1, 0, 0),
("bin/asp/query.asp", "bin/asp/query.asp", 0755, 1, 0, 0),
("bin/asp/viewvc.asp", "bin/asp/viewvc.asp", 0755, 1, 0, 0),
("bin/asp/query.asp", "bin/asp/query.asp", 0755, 1, 0, 0),
])
## List of directories for installation.
## type (source path,
## destination path,
## boolean -- prompt before replacing?)
TREE_LIST = [
("lib", "lib", 0),
("templates", "templates", 1),
("templates-contrib", "templates-contrib", 1),
]
("lib", "lib", 0),
("templates", "templates", 1),
]
# used to escape substitution strings passed to re.sub(). re.escape() is no
# good because it blindly puts backslashes in front of anything that is not
# a number or letter regardless of whether the resulting sequence will be
# interpreted.
def ReEscape(str):
return string.replace(str, "\\", "\\\\")
## List of file extensions we can't show diffs for.
BINARY_FILE_EXTS = [
'.png',
'.gif',
'.jpg',
]
def _escape(str):
"""Callback function for re.sub().
re.escape() is no good because it blindly puts backslashes in
front of anything that is not a number or letter regardless of
whether the resulting sequence will be interpreted."""
return string.replace(str, "\\", "\\\\")
def _actual_src_path(path):
"""Return the real on-disk location of PATH, which is relative to
the ViewVC source directory."""
return os.path.join(os.path.dirname(sys.argv[0]),
string.replace(path, '/', os.sep))
def error(text, etype=None, evalue=None):
"""Print error TEXT to stderr, pretty printing the optional
exception type and value (ETYPE and EVALUE, respective), and then
exit the program with an errorful code."""
sys.stderr.write("\n[ERROR] %s\n" % (text))
def Error(text, etype=None, evalue=None):
print
print "[ERROR] %s" % text
if etype:
traceback.print_exception(etype, evalue, None, file=sys.stderr)
print '[ERROR] ',
traceback.print_exception(etype, evalue, None, file=sys.stdout)
sys.exit(1)
def replace_var(contents, var, value):
"""Replace instances of the variable VAR as found in file CONTENTS
with VALUE."""
def MkDir(path):
try:
compat.makedirs(path)
except os.error, e:
if e[0] == 17:
# EEXIST: file exists
return
if e[0] == 13:
# EACCES: permission denied
Error("You do not have permission to create directory %s" % path)
Error("Unknown error creating directory %s" % path, OSError, e)
def SetOnePath(contents, var, value):
pattern = re.compile('^' + var + r'\s*=\s*.*$', re.MULTILINE)
repl = '%s = r"%s"' % (var, os.path.join(ROOT_DIR, value))
return re.sub(pattern, _escape(repl), contents)
return re.sub(pattern, ReEscape(repl), contents)
def replace_paths(contents):
"""Replace all ViewVC path placeholders found in file CONTENTS."""
def SetPythonPaths(contents):
if contents[:2] == '#!':
shbang = '#!' + sys.executable
contents = re.sub('^#![^\n]*', _escape(shbang), contents)
contents = replace_var(contents, 'LIBRARY_DIR', 'lib')
contents = replace_var(contents, 'CONF_PATHNAME', 'viewvc.conf')
contents = re.sub('^#![^\n]*', ReEscape(shbang), contents)
contents = SetOnePath(contents, 'LIBRARY_DIR', 'lib')
contents = SetOnePath(contents, 'CONF_PATHNAME', 'viewvc.conf')
return contents
def install_file(src_path, dst_path, mode, subst_path_vars,
prompt_replace, compile_it):
"""Install a single file whose source is at SRC_PATH (which is
relative to the ViewVC source directory) into the location
DST_PATH (which is relative both to the global ROOT_DIR and
DESTDIR settings), and set the file's MODE. If SUBST_PATH_VARS is
set, substitute path variables in the file's contents. If
PROMPT_REPLACE is set (and is not overridden by global setting
CLEAN_MODE), prompt the user for how to deal with already existing
files that differ from the to-be-installed version. If COMPILE_IT
is set, compile the file as a Python module."""
def InstallFile(src_path, dest_path, mode, set_python_paths, prompt_replace,
compile_it):
dest_path = os.path.join(ROOT_DIR, dest_path)
src_path = _actual_src_path(src_path)
dst_path = os.path.join(ROOT_DIR, string.replace(dst_path, '/', os.sep))
destdir_path = DESTDIR + dst_path
if prompt_replace and os.path.exists(DESTDIR + dest_path):
# Collect ndiff output from ndiff
sys.stdout = StringIO.StringIO()
compat_ndiff.main([DESTDIR + dest_path, src_path])
ndiff_output = sys.stdout.getvalue()
overwrite = None
if not (prompt_replace and os.path.exists(destdir_path)):
# If the file doesn't already exist, or we've been instructed to
# replace it without prompting, then drop in the new file and get
# outta here.
overwrite = 1
else:
# If we're here, then the file already exists, and we've possibly
# got to prompt the user for what to do about that.
# Collect ndiff output from ndiff
sys.stdout = StringIO.StringIO()
compat_ndiff.main([destdir_path, src_path])
ndiff_output = sys.stdout.getvalue()
# Return everything to normal
sys.stdout = sys.__stdout__
# Return everything to normal
sys.stdout = sys.__stdout__
# Collect the '+ ' and '- ' lines
# total collects the difference lines to be printed later
total = ""
# I use flag to throw out match lines.
flag = 1
for line in string.split(ndiff_output,'\n'):
# Print line if it is a difference line
if line[:2] == "+ " or line[:2] == "- " or line[:2] == "? ":
total = total + line + "\n"
flag = 1
else:
# Compress lines that are the same to print one blank line
if flag:
total = total + "\n"
flag = 0
# Collect the '+ ' and '- ' lines.
diff_lines = []
looking_at_diff_lines = 0
for line in string.split(ndiff_output, '\n'):
# Print line if it is a difference line
if line[:2] == "+ " or line[:2] == "- " or line[:2] == "? ":
diff_lines.append(line)
looking_at_diff_lines = 1
else:
# Compress lines that are the same to print one blank line
if looking_at_diff_lines:
diff_lines.append("")
looking_at_diff_lines = 0
if total == "\n":
print " File %s exists,\n but there is no difference between target and source files.\n" % (DESTDIR + dest_path)
return
# If there are no differences, we're done here.
if not diff_lines:
overwrite = 1
else:
# If we get here, there are differences.
if CLEAN_MODE == 'true':
overwrite = 1
elif CLEAN_MODE == 'false':
overwrite = 0
else:
print "File %s exists and is different from source file." \
% (destdir_path)
while 1:
name, ext = os.path.splitext(src_path)
if ext in BINARY_FILE_EXTS:
temp = raw_input("Do you want to [O]verwrite or "
"[D]o not overwrite? ")
else:
temp = raw_input("Do you want to [O]verwrite, [D]o "
"not overwrite, or [V]iew "
"differences? ")
temp = string.lower(temp[0])
if temp == "v" and ext not in BINARY_FILE_EXTS:
print """
---------------------------------------------------------------------------"""
print string.join(diff_lines, '\n') + '\n'
print """
LEGEND
A leading '- ' indicates line to remove from installed file
A leading '+ ' indicates line to add to installed file
A leading '? ' shows intraline differences.
---------------------------------------------------------------------------"""
elif temp == "d":
overwrite = 0
elif temp == "o":
overwrite = 1
if type(prompt_replace) == type(""):
print prompt_replace
while 1:
temp = raw_input("""
File %s exists and is different from source file.
DO YOU WANT TO,
overwrite [o]
do not overwrite [d]
view differences [v]: """ % (DESTDIR + dest_path))
print
if overwrite is not None:
break
temp = string.lower(temp[0])
assert overwrite is not None
if not overwrite:
print " preserved %s" % (dst_path)
if temp == "d":
return
### If we get here, we're creating or overwriting the existing file.
if temp == "v":
if string.lower(src_path[-4:]) in [ '.gif', '.png', '.jpg' ]:
print 'Can not print differences between binary files'
else:
print total
print """
LEGEND
A leading '- ' indicates line to remove from installed file
A leading '+ ' indicates line to add to installed file
A leading '? ' shows intraline differences."""
# Read the source file's contents.
try:
contents = open(src_path, "rb").read()
except IOError, e:
error(str(e))
if temp == "o":
ReplaceFile(src_path, dest_path, mode, set_python_paths,
prompt_replace, compile_it)
return
else:
ReplaceFile(src_path, dest_path, mode, set_python_paths,
prompt_replace, compile_it)
return
# (Optionally) substitute ViewVC path variables.
if subst_path_vars:
contents = replace_paths(contents)
def ReplaceFile(src_path, dest_path, mode, set_python_paths,
prompt_replace, compile_it):
try:
contents = open(src_path, "rb").read()
except IOError, e:
Error(str(e))
# Ensure the existence of the containing directories.
dst_parent = os.path.dirname(destdir_path)
if not os.path.exists(dst_parent):
try:
compat.makedirs(dst_parent)
print " created %s%s" % (dst_parent, os.sep)
except os.error, e:
if e.errno == 17: # EEXIST: file exists
return
if e.errno == 13: # EACCES: permission denied
error("You do not have permission to create directory %s" \
% (dst_parent))
error("Unknown error creating directory %s" \
% (dst_parent, OSError, e))
if set_python_paths:
contents = SetPythonPaths(contents)
# Now, write the file contents to their destination.
try:
exists = os.path.exists(destdir_path)
open(destdir_path, "wb").write(contents)
print " %s %s" \
% (exists and 'replaced ' or 'installed', dst_path)
except IOError, e:
if e.errno == 13:
# EACCES: permission denied
error("You do not have permission to write file %s" % (dst_path))
error("Unknown error writing file %s" % (dst_path, IOError, e))
# Set the files's mode.
os.chmod(destdir_path, mode)
# (Optionally) compile the file.
if compile_it:
py_compile.compile(destdir_path, destdir_path + "c" , dst_path)
## write the file to the destination location
path, basename = os.path.split(DESTDIR + dest_path)
MkDir(path)
try:
open(DESTDIR + dest_path, "wb").write(contents)
except IOError, e:
if e[0] == 13:
# EACCES: permission denied
Error("You do not have permission to write file %s" % dest_path)
Error("Unknown error writing file %s" % dest_path, IOError, e)
os.chmod(DESTDIR + dest_path, mode)
if compile_it:
py_compile.compile(DESTDIR + dest_path,
DESTDIR + dest_path + "c" , dest_path)
return
def install_tree(src_path, dst_path, prompt_replace):
"""Install a tree whose source is at SRC_PATH (which is relative
to the ViewVC source directory) into the location DST_PATH (which
is relative both to the global ROOT_DIR and DESTDIR settings). If
PROMPT_REPLACE is set (and is not overridden by global setting
CLEAN_MODE), prompt the user for how to deal with already existing
files that differ from the to-be-installed version."""
files = os.listdir(src_path)
files.sort()
for fname in files:
# eliminate some items which appear in a development area
if fname == 'CVS' or fname == '.svn' or fname == '_svn' \
or fname[-4:] == '.pyc' or fname[-5:] == '.orig' \
or fname[-4:] == '.rej' or fname[0] == '.' \
or fname[-1] == '~':
continue
orig_src_path = src_path
orig_dst_path = dst_path
src_path = _actual_src_path(src_path)
dst_path = os.path.join(ROOT_DIR, string.replace(dst_path, '/', os.sep))
destdir_path = os.path.join(DESTDIR + dst_path)
# Get a list of items in the directory.
files = os.listdir(src_path)
files.sort()
for fname in files:
# Ignore some stuff found in development directories, but not
# intended for installation.
if fname == 'CVS' or fname == '.svn' or fname == '_svn' \
or fname[-4:] == '.pyc' or fname[-5:] == '.orig' \
or fname[-4:] == '.rej' or fname[0] == '.' \
or fname[-1] == '~':
continue
orig_src_child = orig_src_path + '/' + fname
orig_dst_child = orig_dst_path + '/' + fname
# If the item is a subdirectory, recurse. Otherwise, install the file.
if os.path.isdir(os.path.join(src_path, fname)):
install_tree(orig_src_child, orig_dst_child, prompt_replace)
else:
set_paths = 0
compile_it = fname[-3:] == '.py'
install_file(orig_src_child, orig_dst_child, 0644,
set_paths, prompt_replace, compile_it)
# Check for .py and .pyc files that don't belong in installation.
for fname in os.listdir(destdir_path):
if not os.path.isfile(os.path.join(destdir_path, fname)) or \
not ((fname[-3:] == '.py' and fname not in files) or
(fname[-4:] == '.pyc' and fname[:-1] not in files)):
continue
# If we get here, there's cruft.
delete = None
if CLEAN_MODE == 'true':
delete = 1
elif CLEAN_MODE == 'false':
delete = 0
else:
print "File %s does not belong in ViewVC %s." \
% (dst_path, version)
while 1:
temp = raw_input("Do you want to [D]elete it, or [L]eave "
"it as is? ")
temp = string.lower(temp[0])
if temp == "l":
delete = 0
elif temp == "d":
delete = 1
if delete is not None:
break
assert delete is not None
if delete:
print " deleted %s" % (os.path.join(dst_path, fname))
os.unlink(os.path.join(destdir_path, fname))
else:
print " preserved %s" % (os.path.join(dst_path, fname))
def usage_and_exit(errstr=None):
stream = errstr and sys.stderr or sys.stdout
stream.write("""Usage: %s [OPTIONS]
Installs the ViewVC web-based version control repository browser.
Options:
--help, -h, -? Show this usage message and exit.
--prefix=DIR Install ViewVC into the directory DIR. If not provided,
the script will prompt for this information.
--destdir=DIR Use DIR as the DESTDIR. This is generally only used
by package maintainers. If not provided, the script will
prompt for this information.
--clean-mode= If 'true', overwrite existing ViewVC configuration files
found in the target directory, and purge Python modules
from the target directory that aren't part of the ViewVC
distribution. If 'false', do not overwrite configuration
files, and do not purge any files from the target
directory. If not specified, the script will prompt
for the appropriate action on a per-file basis.
""" % (os.path.basename(sys.argv[0])))
if errstr:
stream.write("ERROR: %s\n\n" % (errstr))
sys.exit(1)
src = os.path.join(src_path, fname)
dst = os.path.join(dst_path, fname)
if os.path.isdir(src):
install_tree(src, dst, prompt_replace)
else:
sys.exit(0)
print " ", src
set_paths = 0
compile_it = fname[-3:] == '.py'
InstallFile(src, dst, 0644, set_paths, prompt_replace, compile_it)
# prompt to delete all .py and .pyc files that don't belong in installation
full_dst_path = os.path.join(DESTDIR + ROOT_DIR, dst_path)
for fname in os.listdir(full_dst_path):
if not os.path.isfile(os.path.join(full_dst_path, fname)) or \
not ((fname[-3:] == '.py' and fname not in files) or
(fname[-4:] == '.pyc' and fname[:-1] not in files)):
continue
while 1:
temp = raw_input("""
File %s does not belong in ViewVC %s.
DO YOU WANT TO,
delete [d]
leave as is [l]: """ % (os.path.join(dst_path, fname), version))
print
temp = string.lower(temp[0])
if temp == "l":
break
if temp == "d":
os.unlink(os.path.join(full_dst_path, fname))
break
## MAIN
if __name__ == "__main__":
# Option parsing.
# option parsing
try:
optlist, args = getopt.getopt(sys.argv[1:], "h?",
['prefix=',
'destdir=',
'clean-mode=',
'help'])
optlist, args = getopt.getopt(sys.argv[1:], "", ['prefix=', 'destdir='])
except getopt.GetoptError, e:
usage_and_exit(str(e))
Error("Invalid option", getopt.GetoptError, e)
for opt, arg in optlist:
if opt == '--help' or opt == '-h' or opt == '-?':
usage_and_exit()
if opt == '--prefix':
ROOT_DIR = arg
if opt == '--destdir':
DESTDIR = arg
if opt == '--clean-mode':
arg = arg.lower()
if arg not in ('true', 'false'):
usage_and_exit("Invalid value for --overwrite parameter.")
CLEAN_MODE = arg
if opt == '--prefix':
ROOT_DIR = arg
if opt == '--destdir':
DESTDIR = arg
# Print the header greeting.
print """This is the ViewVC %s installer.
## print greeting
print INFO_TEXT
It will allow you to choose the install path for ViewVC. You will now
be asked some installation questions. Defaults are given in square brackets.
Just hit [Enter] if a default is okay.
""" % version
# Prompt for ROOT_DIR if none provided.
## prompt for ROOT_DIR if none provided
if ROOT_DIR is None:
if sys.platform == "win32":
pf = os.getenv("ProgramFiles", "C:\\Program Files")
default = os.path.join(pf, "viewvc-" + version)
else:
default = "/usr/local/viewvc-" + version
temp = string.strip(raw_input("Installation path [%s]: " \
% default))
print
if len(temp):
ROOT_DIR = temp
else:
ROOT_DIR = default
# Prompt for DESTDIR if none provided.
if DESTDIR is None:
default = ''
temp = string.strip(raw_input(
"DESTDIR path (generally only used by package "
"maintainers) [%s]: " \
% default))
print
if len(temp):
DESTDIR = temp
else:
DESTDIR = default
# Install the files.
print "Installing ViewVC to %s%s:" \
% (ROOT_DIR, DESTDIR and " (DESTDIR = %s)" % (DESTDIR) or "")
for args in FILE_INFO_LIST:
apply(install_file, args)
for args in TREE_LIST:
apply(install_tree, args)
if sys.platform == "win32":
pf = os.getenv("ProgramFiles", "C:\\Program Files")
default = os.path.join(pf, "viewvc-" + version)
else:
default = "/usr/local/viewvc-" + version
temp = string.strip(raw_input("Installation path [%s]: " % default))
print
if len(temp):
ROOT_DIR = temp
else:
ROOT_DIR = default
# Print some final thoughts.
## prompt for DESTDIR if none provided
if DESTDIR is None:
default = ''
temp = string.strip(raw_input(
"DESTDIR path (generally, only package maintainers will need "
"to change\nthis) [%s]: " % default))
print
if len(temp):
DESTDIR = temp
else:
DESTDIR = default
## install the files
print "Installing ViewVC to:", ROOT_DIR,
if DESTDIR:
print "(DESTDIR = %s)" % (DESTDIR)
else:
print
for args in FILE_INFO_LIST:
print " ", args[0]
apply(InstallFile, args)
for args in TREE_LIST:
apply(install_tree, args)
print """
ViewVC file installation complete.
ViewVC File Installation Complete
Consult the INSTALL document for detailed information on completing the
installation and configuration of ViewVC on your system. Here's a brief
overview of the remaining steps:
Consult INSTALL for detailed information to finish the installation
and configure ViewVC for your system.
1) Edit the %s file.
Overview of remaining steps:
2) Either configure an existing web server to run
%s.
Or, copy %s to an
already-configured cgi-bin directory.
Or, use the standalone server provided by this distribution at
%s.
""" % (os.path.join(ROOT_DIR, 'viewvc.conf'),
os.path.join(ROOT_DIR, 'bin', 'cgi', 'viewvc.cgi'),
os.path.join(ROOT_DIR, 'bin', 'cgi', 'viewvc.cgi'),
os.path.join(ROOT_DIR, 'bin', 'standalone.py'))
1) Edit the %s file.
2) Configure an existing web server to run (or copy to cgi-bin)
%s.
OR
Run the web server that comes with ViewVC at
%s.
""" % (
os.path.join(ROOT_DIR, 'viewvc.conf'),
os.path.join(ROOT_DIR, 'bin', 'cgi', 'viewvc.cgi'),
os.path.join(ROOT_DIR, 'standalone.py'))

View File

@@ -142,9 +142,8 @@ use_rcsparse = 0
address = <a href="mailto:cvs-admin@insert.your.domain.here">No admin address has been configured</a>
#
# This should contain a list of modules (that is, top-level directories within
# repositories) that should not be displayed (by default or by explicit path
# specification).
# This should contain a list of modules in the repository that should not be
# displayed (by default or by explicit path specification).
#
# This configuration can be a simple list of modules, or it can get quite
# complex:
@@ -163,9 +162,8 @@ address = <a href="mailto:cvs-admin@insert.your.domain.here">No admin address ha
#
# Tests are case-sensitive.
#
# NOTE: This is for the hiding of modules within repositories, *not*
# for the hiding of repositories (roots) themselves.
#
forbidden =
# Some examples:
#
# Disallow "example" but allow all others:
@@ -186,40 +184,6 @@ address = <a href="mailto:cvs-admin@insert.your.domain.here">No admin address ha
# Allow "xml", forbid other modules starting with "x", and allow the rest:
# forbidden = !xml, x*, !*
#
forbidden =
#
# This is similar to 'forbidden', but differs in some key ways:
#
# *) Rather than shell-style "glob" expressions, the values in this
# list are regular expressions. You can still prepend a ! character
# to each regular expression to invert its meaning, though.
#
# *) It compares not against modules only, but against paths consisting
# of the repository (or root) name plus the path of the versioned file
# or directory to be tested. For example, to see if the user is
# authorized to see the path "/trunk/www/index.html" in the repository
# whose root name is "svnrepos", this authorizer will test the path
# "svnrepos/trunk/www/index.html" against the list of forbidden regular
# expressions. Directory paths will be terminated by a forward slash.
#
# NOTE: Use of this configuration option will *disable* any configuration of
# the 'forbidden' option -- they cannot be used simultaneously.
#
# Some examples:
#
# Disallow files named "PRIVATE", but allow all others:
# forbiddenre = /PRIVATE$
#
# Allow only the "example1" and "example2" roots and the paths inside them,
# disallowing all others (which can be done in multiple ways):
# forbiddenre = !^example1(/|$), !^example2(/|$)/
# forbiddenre = !^example[12](/|$)
#
# Only allow visibility of HTML files and the directories that hold them:
# forbiddenre = !^.*(/|\.html)$
#
forbiddenre =
#
# This option provides a mechanism for custom key/value pairs to be
@@ -395,9 +359,6 @@ hr_ignore_keyword_subst = 1
#
hr_intraline = 0
# allow on-the-fly generation of repository tarballs
allow_tar = 0
# allow annotation of files.
allow_annotate = 1
@@ -498,14 +459,16 @@ highlight_convert_tabs = 2
use_php = 0
# path to php executable
# (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_exe_path = php
# php_exe_path = /usr/local/bin/php
# php_exe_path = C:\Program Files\php\cli\php.exe
#
# ViewVC can generate tarball from a repository on the fly.
#
allow_tar = 0
# allow_tar = 1
#
# Use CvsGraph. See http://www.akhphd.au.dk/~bertho/cvsgraph/ for
# documentation and download.

View File

@@ -18,7 +18,7 @@
<a href="./download.html">Download</a> |
<a href="./upgrading.html">Upgrading</a> |
<a href="./contributing.html">Contributing</a> |
<a href="http://viewvc.tigris.org/nonav/source/browse/*checkout*/viewvc/trunk/LICENSE.html">License</a> |
<a href="./license-1.html">License</a> |
<a href="./contact.html">Contact</a> |
<a href="./who.html">About</a>
</p>

View File

@@ -18,7 +18,7 @@
<a href="./download.html">Download</a> |
<a href="./upgrading.html">Upgrading</a> |
<a href="./contributing.html">Contributing</a> |
<a href="http://viewvc.tigris.org/nonav/source/browse/*checkout*/viewvc/trunk/LICENSE.html">License</a> |
<a href="./license-1.html">License</a> |
<a href="./contact.html">Contact</a> |
<a href="./who.html">About</a>
</p>

View File

@@ -18,7 +18,7 @@
<a href="./download.html">Download</a> |
<a href="./upgrading.html">Upgrading</a> |
<a href="./contributing.html">Contributing</a> |
<a href="http://viewvc.tigris.org/nonav/source/browse/*checkout*/viewvc/trunk/LICENSE.html">License</a> |
<a href="./license-1.html">License</a> |
<a href="./contact.html">Contact</a> |
<a href="./who.html">About</a>
</p>

View File

@@ -18,7 +18,7 @@
<a href="./download.html">Download</a> |
<a href="./upgrading.html">Upgrading</a> |
<a href="./contributing.html">Contributing</a> |
<a href="http://viewvc.tigris.org/nonav/source/browse/*checkout*/viewvc/trunk/LICENSE.html">License</a> |
<a href="./license-1.html">License</a> |
<a href="./contact.html">Contact</a> |
<a href="./who.html">About</a>
</p>

View File

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

View File

@@ -1,95 +0,0 @@
#!/bin/sh
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 ../..
cat > ${PUBLISH_DIR}/index.html <<EOF
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<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"/>
</head>
<body>
<div id="title">
<a href="http://www.viewvc.org/"><img
src="../images/title.jpg" alt="ViewVC: Repository Browsing"/></a>
</div>
<div id="menu">
<p><a href="../index.html">Home</a> |
<a href="http://viewvc.tigris.org/">Project Page</a> |
<a href="../download.html">Download</a> |
<a href="../contributing.html">Contributing</a> |
<a href="http://viewvc.tigris.org/nonav/source/browse/*checkout*/viewvc/trunk/LICENSE.html">License</a> |
<a href="../contact.html">Contact</a> |
<a href="../who.html">About</a>
</p>
</div>
<table id="pagetable">
<tr>
<td id="pagecolumn1">
<h4>On this page:</h4>
<ul id="bookmarks">
<li><a href="#sec-snapshots">Snapshots</a></li>
</ul>
<p><a href="http://validator.w3.org/check?uri=referer"><img
src="http://www.w3.org/Icons/valid-xhtml10"
alt="Valid XHTML 1.0 Strict" height="31" width="88" /></a>
</p>
</td>
<td id="pagecolumn2">
<div class="section">
<h2 id="sec-snapshots">Snapshots</h2>
<ul>
EOF
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>
</div>
</td>
</tr>
</table>
</body>
</html>
EOF
# more cleanup
rm -rf ${EXPORTDIR}

View File

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

View File

@@ -89,7 +89,7 @@ th.caption {
<li><a href="#compat-tarball">'<code>tarball=1</code>' Parameter &rArr; '<code>view=tar</code>'</a></li>
<li><a href="#compat-graph">'<code>graph=1</code>' Parameter &rArr; '<code>view=graph</code>'</a></li>
<li><a href="#compat-makeimage">'<code>graph=1&makeimage=1</code>' Parameters &rArr; '<code>view=graphimg</code>'</a></li>
<li><a href="#compat-content_type">'<code>content-type=text/vnd.viewcvs-markup</code>' and '<code>content-type=text/x-cvsweb-markup</code>' Parameters&rArr; '<code>view=markup</code>'
<li><a href="#compat-content_type">'<code>content_type=text/vnd.viewcvs-markup</code>' and '<code>content_type=text/x-cvsweb-markup</code>' Parameters&rArr; '<code>view=markup</code>'
<li><a href="#compat-attic">'<code>Attic/FILE</code>' Paths &rArr; '<code>FILE</code>'</a></li>
</ul>
</div>
@@ -284,6 +284,11 @@ th.caption {
<td>depends</td>
<td><a href="#view-param"><code>view</code> parameter</a>, not needed if the <code>default_file_view</code> configuration variable is set to <code>co</code>, since that makes the checkout view the default view for file paths. Also not needed if the <code>/*checkout*</code> magic prefix or the <code>revision</code> parameter is present.
</tr>
<tr>
<td><code>content-type=<var>TYPE</var></code></td>
<td>optional</td>
<td>MIME type to send with checked out file, default is a guess based on file extension</td>
</tr>
<tr>
<td><code>revision=<var>REVISION</var></code></td>
<td>optional</td>
@@ -1228,8 +1233,8 @@ th.caption {
<h3 id="compat-makeimage">'<code>graph=1&amp;makeimage=1</code>' Parameters &rArr; '<code>view=graphimg</code>'</h3>
<p>A <code>graph=1&amp;makeimage=1</code> parameter is treated like a <code>view=graph</code> parameter. There is currently no redirect when it is encountered, but there could be one in the future.</p>
<h3 id="compat-content_type">'<code>content-type=text/vnd.viewcvs-markup</code>' and '<code>content-type=text/x-cvsweb-markup</code>' Parameters&rArr; '<code>view=markup</code>'; other values ignored</h3>
<p><code>content-type=text/vnd.viewcvs-markup</code> and <code>content-type=text/x-cvsweb-markup</code> parameters are treated like a <code>view=markup</code> parameter. There is currently no redirect when it is encountered, but there could be one in the future. Other values of the <code>content-type</code> parameter, which were used to dictate the MIME type of files displayed in the checkout/download view prior to ViewVC 1.0.6, are ignored.</p>
<h3 id="compat-content_type">'<code>content_type=text/vnd.viewcvs-markup</code>' and '<code>content_type=text/x-cvsweb-markup</code>' Parameters&rArr; '<code>view=markup</code>'</h3>
<p><code>content_type=text/vnd.viewcvs-markup</code> and <code>content_type=text/x-cvsweb-markup</code> parameters are treated like a <code>view=markup</code> parameter. There is currently no redirect when it is encountered, but there could be one in the future.</p>
<h3 id="compat-attic">'<code>Attic/FILE</code>' Paths &rArr; '<code>FILE</code>'</h3>
<p>When ViewVC encounters an invalid repository path whose last or second-to-last component is named <code>Attic</code>, and stripping the component yields a valid path, it will redirect to a URL with that path.</p>

View File

@@ -18,7 +18,7 @@
<a href="./download.html">Download</a> |
<a href="./upgrading.html">Upgrading</a> |
<a href="./contributing.html">Contributing</a> |
<a href="http://viewvc.tigris.org/nonav/source/browse/*checkout*/viewvc/trunk/LICENSE.html">License</a> |
<a href="./license-1.html">License</a> |
<a href="./contact.html">Contact</a> |
<a href="./who.html">About</a>
</p>

View File

@@ -14,7 +14,7 @@ ViewVC requires the Python interpreter which you can download from
and the Python for Windows Extensions which are at
http://sourceforge.net/projects/pywin32/
http://starship.python.net/crew/mhammond/win32/
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.
@@ -404,7 +404,7 @@ KNOWN ISSUES
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/
http://starship.python.net/crew/mhammond/win32/Downloads.html
- 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

70
www/index.html Normal file
View File

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

30
www/project_tools.html Normal file
View File

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