mirror of
https://github.com/vitalif/viewvc-4intranet
synced 2019-04-16 04:14:59 +03:00
Compare commits
208 Commits
orig-r2243
...
1.1.12
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3af8715ce8 | ||
![]() |
97c5a82b7b | ||
![]() |
21bd391d62 | ||
![]() |
9d1476ef1d | ||
![]() |
151fcd05e6 | ||
![]() |
22400ddcfb | ||
![]() |
ae55530edc | ||
![]() |
112700a12c | ||
![]() |
cecffecf39 | ||
![]() |
bdac8697fe | ||
![]() |
3d9404b67d | ||
![]() |
7c50f55153 | ||
![]() |
368e4dc360 | ||
![]() |
964d8bb5f9 | ||
![]() |
846e8e46c5 | ||
![]() |
75c719bcde | ||
![]() |
fc8793bf15 | ||
![]() |
65935c40fd | ||
![]() |
a30d0b44cc | ||
![]() |
fded8462d2 | ||
![]() |
b1095ac763 | ||
![]() |
e54399a169 | ||
![]() |
4cc0db75be | ||
![]() |
74a9cbb2a0 | ||
![]() |
390e337a8e | ||
![]() |
ecdac77d5f | ||
![]() |
79158c2ee7 | ||
![]() |
96fdfbdbcf | ||
![]() |
361538da21 | ||
![]() |
6250d4134b | ||
![]() |
8589949521 | ||
![]() |
f12e262fa5 | ||
![]() |
f379070697 | ||
![]() |
d47fc0ff3b | ||
![]() |
f2b6f0ba86 | ||
![]() |
ddbe150be1 | ||
![]() |
6b5ed7c857 | ||
![]() |
391f7d8237 | ||
![]() |
141cf5ff10 | ||
![]() |
bfe148eb45 | ||
![]() |
6fb28f2198 | ||
![]() |
02cc53d34b | ||
![]() |
5928918da4 | ||
![]() |
2e9f84427c | ||
![]() |
df599031a0 | ||
![]() |
6311c93298 | ||
![]() |
b982cccbcd | ||
![]() |
33b8224714 | ||
![]() |
2f05f570b1 | ||
![]() |
d737657e1d | ||
![]() |
3d5294635e | ||
![]() |
75c3fc2346 | ||
![]() |
80bce159af | ||
![]() |
7ff9b84ee1 | ||
![]() |
b6acd3c114 | ||
![]() |
fa5d40caa3 | ||
![]() |
a9cbd4c6a6 | ||
![]() |
882cdaa46b | ||
![]() |
58e64cb28d | ||
![]() |
779e67653b | ||
![]() |
0381a772b7 | ||
![]() |
048b2c8033 | ||
![]() |
e354ab302c | ||
![]() |
5f931c6cf1 | ||
![]() |
576837351a | ||
![]() |
6084ccf877 | ||
![]() |
514da91629 | ||
![]() |
d2c8bb9878 | ||
![]() |
fe274e9b9c | ||
![]() |
6603a67a91 | ||
![]() |
b50de1c92e | ||
![]() |
dfd8dc82f6 | ||
![]() |
1a942d1062 | ||
![]() |
289a78eb99 | ||
![]() |
2897763020 | ||
![]() |
47886423e5 | ||
![]() |
0890821839 | ||
![]() |
2903389d3e | ||
![]() |
5bdea369e8 | ||
![]() |
3699e8e0c7 | ||
![]() |
55c0b30bc0 | ||
![]() |
6fd321529a | ||
![]() |
531877db4a | ||
![]() |
51df003d8e | ||
![]() |
7d05859d7e | ||
![]() |
2e48cd2ba1 | ||
![]() |
267b61f347 | ||
![]() |
7f53d5cc3c | ||
![]() |
af591ed9f7 | ||
![]() |
17492a3856 | ||
![]() |
e990ff9f2f | ||
![]() |
d832930c8d | ||
![]() |
8a0c66c7cf | ||
![]() |
292c2d7ce0 | ||
![]() |
16937af30f | ||
![]() |
d067d49afa | ||
![]() |
132a01a88f | ||
![]() |
4db5103ff1 | ||
![]() |
41943f67c5 | ||
![]() |
1f37623526 | ||
![]() |
7e92babad8 | ||
![]() |
97e45101d9 | ||
![]() |
62d5a3b649 | ||
![]() |
c96c585b39 | ||
![]() |
136063e5a7 | ||
![]() |
f59db1597d | ||
![]() |
c6c3f55c2c | ||
![]() |
8063d46a53 | ||
![]() |
fbc7737465 | ||
![]() |
23f3f3ad55 | ||
![]() |
0efc53a373 | ||
![]() |
0cfe027753 | ||
![]() |
df3b75cdb0 | ||
![]() |
24dd18bf0f | ||
![]() |
bbf27f4afd | ||
![]() |
d4ac97de3c | ||
![]() |
3039b1f43b | ||
![]() |
13597f89cd | ||
![]() |
870ae9aecc | ||
![]() |
c94b0709ec | ||
![]() |
5632e63bcb | ||
![]() |
ae7b1103f6 | ||
![]() |
2882178be7 | ||
![]() |
bfc59256ca | ||
![]() |
3abe695c3c | ||
![]() |
624dfdf0f8 | ||
![]() |
28bf22f279 | ||
![]() |
830a48f88c | ||
![]() |
a23543d763 | ||
![]() |
586a183d5c | ||
![]() |
7ae02a5887 | ||
![]() |
4020fd2e5f | ||
![]() |
af871d59ce | ||
![]() |
b8d36c8c14 | ||
![]() |
4b5721a3d7 | ||
![]() |
10235b8fdf | ||
![]() |
45332f577a | ||
![]() |
148fd7b462 | ||
![]() |
6f66313b51 | ||
![]() |
cf32af4816 | ||
![]() |
df3addacdb | ||
![]() |
a1428600b7 | ||
![]() |
4a4a3b1d61 | ||
![]() |
8c65f1b2c5 | ||
![]() |
55046f2261 | ||
![]() |
b6cedd7c1a | ||
![]() |
771d6736fb | ||
![]() |
455157e413 | ||
![]() |
c875582cfe | ||
![]() |
c3d896d5a8 | ||
![]() |
236069b068 | ||
![]() |
6de96c4fc6 | ||
![]() |
e45c2fcf6e | ||
![]() |
8c620c8c1a | ||
![]() |
c6d6dc4bdf | ||
![]() |
355fac5da1 | ||
![]() |
77d0c3dd06 | ||
![]() |
d95cb540f5 | ||
![]() |
98b757de23 | ||
![]() |
efb811d20c | ||
![]() |
a57e6b7054 | ||
![]() |
fe52bbb079 | ||
![]() |
76d6b541c3 | ||
![]() |
269a9ca864 | ||
![]() |
a5aafe3172 | ||
![]() |
d30bd89c42 | ||
![]() |
d76ce85625 | ||
![]() |
b2b247f417 | ||
![]() |
3ab2ec665b | ||
![]() |
2806f0e9a2 | ||
![]() |
8b426f6fb3 | ||
![]() |
19ee8b32df | ||
![]() |
a5389019fa | ||
![]() |
7f272fbe04 | ||
![]() |
89edf0ac04 | ||
![]() |
71fbec8871 | ||
![]() |
504b1e1a8a | ||
![]() |
cf9381e0ee | ||
![]() |
3907172131 | ||
![]() |
c34752ce92 | ||
![]() |
40cc23f12a | ||
![]() |
9b7fea99d4 | ||
![]() |
85949a6464 | ||
![]() |
d5291a6b98 | ||
![]() |
9e41d171c9 | ||
![]() |
da54e91dea | ||
![]() |
41b2ae2c7a | ||
![]() |
1815220abe | ||
![]() |
a080d8eef4 | ||
![]() |
8c4af42d56 | ||
![]() |
7f1d0952fc | ||
![]() |
222aa4ec1f | ||
![]() |
c03bfd4b89 | ||
![]() |
6fa8cdf117 | ||
![]() |
c4c777ffe6 | ||
![]() |
3680903ed4 | ||
![]() |
6fe61a11bb | ||
![]() |
437975652f | ||
![]() |
7ff75bec7b | ||
![]() |
ea03f20f46 | ||
![]() |
a5df515d79 | ||
![]() |
fabe8e8a66 | ||
![]() |
f01fcc4ec4 | ||
![]() |
05e99f4c7b | ||
![]() |
d8aff4e58f | ||
![]() |
e8d3d6ad89 | ||
![]() |
1317088e3c | ||
![]() |
fe81ee5969 |
93
CHANGES
93
CHANGES
@@ -1,6 +1,95 @@
|
|||||||
Version 1.2.0 (released ??-???-????)
|
Version 1.1.12 (released 03-Nov-2011)
|
||||||
|
|
||||||
* allow user-configurable cvsgraph display (issue #336)
|
* fix path display in patch and certain diff views (issue #485)
|
||||||
|
* fix broken cvsdb glob searching (issue 486)
|
||||||
|
* allow svn revision specifiers to have leading r's (issue #441, #448)
|
||||||
|
* allow environmental override of configuration location (issue #494)
|
||||||
|
* fix exception HTML-escaping non-string data under WSGI (issue #454)
|
||||||
|
* add links to root logs from roots view (issue #470)
|
||||||
|
* use Pygments lexer-guessing functionality (issue #495)
|
||||||
|
|
||||||
|
Version 1.1.11 (released 17-May-2011)
|
||||||
|
|
||||||
|
* security fix: remove user-reachable override of cvsdb row limit
|
||||||
|
* fix broken standalone.py -c and -d options handling
|
||||||
|
* add --help option to standalone.py
|
||||||
|
* fix stack trace when asked to checkout a directory (issue #478)
|
||||||
|
* improve memory usage and speed of revision log markup (issue #477)
|
||||||
|
* fix broken annotation view in CVS keyword-bearing files (issue #479)
|
||||||
|
* warn users when query results are incomplete (issue #433)
|
||||||
|
* avoid parsing errors on RCS newphrases in the admin section (issue #483)
|
||||||
|
* make rlog parsing code more robust in certain error cases (issue #444)
|
||||||
|
|
||||||
|
Version 1.1.10 (released 15-Mar-2011)
|
||||||
|
|
||||||
|
* fix stack trace in Subversion revision info logic (issue #475, issue #476)
|
||||||
|
|
||||||
|
Version 1.1.9 (released 18-Feb-2011)
|
||||||
|
|
||||||
|
* vcauth universal access determinations (issue #425)
|
||||||
|
* rework svn revision info cache for performance
|
||||||
|
* make revision log "extra pages" count configurable
|
||||||
|
* fix Subversion 1.4.x revision log compatibility code regression
|
||||||
|
* display sanitized error when authzfile is malformed
|
||||||
|
* handle file:/// Subversion rootpaths as local roots (issue #446)
|
||||||
|
* restore markup of URLs in file contents (issue #455)
|
||||||
|
* optionally display last-committed metadata in roots view (issue #457)
|
||||||
|
|
||||||
|
Version 1.1.8 (released 02-Dec-2010)
|
||||||
|
|
||||||
|
* fix slowness triggered by allow_compress=1 configuration (issue #467)
|
||||||
|
* allow use of 'fcrypt' for Windows standalone.py authn support (issue #471)
|
||||||
|
* yield more useful error on directory markup/annotate request (issue #472)
|
||||||
|
|
||||||
|
Version 1.1.7 (released 09-Sep-2010)
|
||||||
|
|
||||||
|
* display Subversion revision properties in the revision view (issue #453)
|
||||||
|
* fix exception in 'standalone.py -r REPOS' when run without a config file
|
||||||
|
* fix standalone.py server root deployments (--script-alias='')
|
||||||
|
* add Basic authentication support to standalone.py (Unix only) (issue #49)
|
||||||
|
* fix obscure "unexpected NULL parent pool" Subversion bindings error
|
||||||
|
* enable path info / link display in remote Subversion root revision view
|
||||||
|
* fix vhost name case handling inconsistency (issue #466)
|
||||||
|
* use svn:mime-type property charset param as encoding hint
|
||||||
|
* markup Subversion revision references in log messages (issue #313)
|
||||||
|
* add rudimentary support for FastCGI-based deployments (issue #464)
|
||||||
|
* fix query script WSGI deployment
|
||||||
|
* add configuration to fix query script cross-linking to ViewVC
|
||||||
|
|
||||||
|
Version 1.1.6 (released 02-Jun-2010)
|
||||||
|
|
||||||
|
* add rudimentary support for WSGI-based deployments (issue #397)
|
||||||
|
* fix exception caused by trying to HTML-escape non-string data (issue #454)
|
||||||
|
* fix incorrect RSS feed Content-Type header (issue #449)
|
||||||
|
* fix RSS <title> encoding problem (issue #451)
|
||||||
|
* allow 'svndbadmin purge' to work on missing repositories (issue #452)
|
||||||
|
|
||||||
|
Version 1.1.5 (released 29-Mar-2010)
|
||||||
|
|
||||||
|
* security fix: escape user-provided search_re input to avoid XSS attack
|
||||||
|
|
||||||
|
Version 1.1.4 (released 10-Mar-2010)
|
||||||
|
|
||||||
|
* security fix: escape user-provided query form input to avoid XSS attack
|
||||||
|
* fix standalone.py failure (when per-root options aren't used) (issue #445)
|
||||||
|
* fix annotate failure caused by ignored svn_config_dir (issue #447)
|
||||||
|
|
||||||
|
Version 1.1.3 (released 22-Dec-2009)
|
||||||
|
|
||||||
|
* security fix: add root listing support of per-root authz config
|
||||||
|
* security fix: query.py requires 'forbidden' authorizer (or none) in config
|
||||||
|
* fix URL-ification of truncated log messages (issue #3)
|
||||||
|
* fix regexp input validation (issue #426, #427, #440)
|
||||||
|
* add support for configurable tab-to-spaces conversion
|
||||||
|
* fix not-a-sequence error in diff view
|
||||||
|
* allow viewvc-install to work when templates-contrib is absent
|
||||||
|
* minor template improvements/corrections
|
||||||
|
* expose revision metadata in diff view (issue #431)
|
||||||
|
* markup file/directory item property URLs and email addresses (issue #434)
|
||||||
|
* make ViewVC cross copies in Subversion history by default
|
||||||
|
* fix bug that caused standalone.py failure under Python 1.5.2 (issue #442)
|
||||||
|
* fix support for per-vhost overrides of authorizer parameters (issue #411)
|
||||||
|
* fix root name identification in query.py interface
|
||||||
|
|
||||||
Version 1.1.2 (released 11-Aug-2009)
|
Version 1.1.2 (released 11-Aug-2009)
|
||||||
|
|
||||||
|
158
INSTALL
158
INSTALL
@@ -19,7 +19,7 @@ Congratulations on getting this far. :-)
|
|||||||
|
|
||||||
For CVS Support:
|
For CVS Support:
|
||||||
|
|
||||||
* Python 1.5.2 or later
|
* Python 1.5.2 or later (sorry, no 3.x support yet)
|
||||||
(http://www.python.org/)
|
(http://www.python.org/)
|
||||||
* RCS, Revision Control System
|
* RCS, Revision Control System
|
||||||
(http://www.cs.purdue.edu/homes/trinkle/RCS/)
|
(http://www.cs.purdue.edu/homes/trinkle/RCS/)
|
||||||
@@ -30,11 +30,11 @@ Congratulations on getting this far. :-)
|
|||||||
|
|
||||||
For Subversion Support:
|
For Subversion Support:
|
||||||
|
|
||||||
* Python 2.0 or later
|
* Python 2.0 or later (sorry, no 3.x support yet)
|
||||||
(http://www.python.org/)
|
(http://www.python.org/)
|
||||||
* Subversion, Version Control System, 1.3.1 or later
|
* Subversion, Version Control System, 1.3.1 or later
|
||||||
(binary installation and Python bindings)
|
(binary installation and Python bindings)
|
||||||
(http://subversion.tigris.org/)
|
(http://subversion.apache.org/)
|
||||||
|
|
||||||
Optional:
|
Optional:
|
||||||
|
|
||||||
@@ -168,72 +168,145 @@ checkin database working are below.
|
|||||||
APACHE CONFIGURATION
|
APACHE CONFIGURATION
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
1) Find out where the web server configuration file is kept. Typical
|
1) Locate your Apache configuration file(s).
|
||||||
locations are /etc/httpd/httpd.conf, /etc/httpd/conf/httpd.conf,
|
|
||||||
and /etc/apache/httpd.conf. Depending on how apache was installed,
|
|
||||||
you may also look under /usr/local/etc or /etc/local. Use the vendor
|
|
||||||
documentation or the find utility if in doubt.
|
|
||||||
|
|
||||||
Either METHOD A:
|
Typical locations are /etc/httpd/httpd.conf,
|
||||||
2) The ScriptAlias directive is very useful for pointing
|
/etc/httpd/conf/httpd.conf, and /etc/apache/httpd.conf. Depending
|
||||||
|
on how Apache was installed, you may also look under /usr/local/etc
|
||||||
|
or /etc/local. Use the vendor documentation or the find utility if
|
||||||
|
in doubt.
|
||||||
|
|
||||||
|
2) Depending on how your Apache configuration is setup by default, you
|
||||||
|
might need to explicitly allow high-level access to the ViewVC
|
||||||
|
install location.
|
||||||
|
|
||||||
|
<Directory <VIEWVC_INSTALLATION_DIRECTORY>>
|
||||||
|
Order allow,deny
|
||||||
|
Allow from all
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
For example, if ViewVC is installed in /usr/local/viewvc-1.0 on
|
||||||
|
your system:
|
||||||
|
|
||||||
|
<Directory /usr/local/viewvc-1.0>
|
||||||
|
Order allow,deny
|
||||||
|
Allow from all
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
3) Configure Apache to expose ViewVC to users at the URL of your choice.
|
||||||
|
|
||||||
|
ViewVC provides several different ways to do this. Choose one of
|
||||||
|
the following methods:
|
||||||
|
|
||||||
|
-----------------------------------
|
||||||
|
METHOD A: CGI mode via ScriptAlias
|
||||||
|
-----------------------------------
|
||||||
|
The ScriptAlias directive is very useful for pointing
|
||||||
directly to the viewvc.cgi script. Simply insert a line containing
|
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>/bin/cgi/viewvc.cgi
|
||||||
|
|
||||||
into your httpd.conf file. Choose the location in httpd.conf where
|
into your httpd.conf file. Choose the location in httpd.conf where
|
||||||
also the other ScriptAlias lines reside. Some examples:
|
also the other ScriptAlias lines reside. Some examples:
|
||||||
|
|
||||||
ScriptAlias /viewvc /usr/local/viewvc-1.0/bin/cgi/viewvc.cgi
|
ScriptAlias /viewvc /usr/local/viewvc-1.0/bin/cgi/viewvc.cgi
|
||||||
ScriptAlias /query /usr/local/viewvc-1.0/bin/cgi/query.cgi
|
ScriptAlias /query /usr/local/viewvc-1.0/bin/cgi/query.cgi
|
||||||
|
|
||||||
continue with step 3).
|
----------------------------------------
|
||||||
|
METHOD B: CGI mode in cgi-bin directory
|
||||||
or alternatively METHOD B:
|
----------------------------------------
|
||||||
2) Copy the CGI scripts from
|
Copy the CGI scripts from
|
||||||
<VIEWVC_INSTALLATION_DIRECTORY>/bin/cgi/*.cgi
|
<VIEWVC_INSTALLATION_DIRECTORY>/bin/cgi/*.cgi
|
||||||
to the /cgi-bin/ directory configured in your httpd.conf file.
|
to the /cgi-bin/ directory configured in your httpd.conf file.
|
||||||
|
|
||||||
continue with step 3).
|
You can override configuration file location using:
|
||||||
|
|
||||||
|
SetEnv VIEWVC_CONF_PATHNAME /etc/viewvc.conf
|
||||||
|
|
||||||
and then there's METHOD C:
|
------------------------------------------
|
||||||
2) Copy the CGI scripts from
|
METHOD C: CGI mode in ExecCGI'd directory
|
||||||
|
------------------------------------------
|
||||||
|
Copy the CGI scripts from
|
||||||
<VIEWVC_INSTALLATION_DIRECTORY>/bin/cgi/*.cgi
|
<VIEWVC_INSTALLATION_DIRECTORY>/bin/cgi/*.cgi
|
||||||
to the directory of your choosing in the Document Root adding the following
|
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:
|
Apache directives for the directory in httpd.conf or an .htaccess file:
|
||||||
|
|
||||||
Options +ExecCGI
|
Options +ExecCGI
|
||||||
AddHandler cgi-script .cgi
|
AddHandler cgi-script .cgi
|
||||||
|
|
||||||
(Note: For this to work mod_cgi has to be loaded. And for the .htaccess file
|
Note: For this to work mod_cgi has to be loaded. And for the .htaccess file
|
||||||
to be effective, "AllowOverride All" or "AllowOverride Options FileInfo"
|
to be effective, "AllowOverride All" or "AllowOverride Options FileInfo"
|
||||||
need to have been specified for the directory.)
|
needs to have been specified for the directory.
|
||||||
|
|
||||||
continue with step 3).
|
------------------------------------------
|
||||||
|
METHOD D: Using mod_python (if installed)
|
||||||
or if you've got Mod_Python installed you can use METHOD D:
|
------------------------------------------
|
||||||
2) Copy the Python scripts and .htaccess file from
|
Copy the Python scripts and .htaccess file from
|
||||||
<VIEWVC_INSTALLATION_DIRECTORY>/bin/mod_python/
|
<VIEWVC_INSTALLATION_DIRECTORY>/bin/mod_python/
|
||||||
to a directory being served by apache.
|
to a directory being served by Apache.
|
||||||
|
|
||||||
In httpd.conf, make sure that "AllowOverride All" or at least
|
In httpd.conf, make sure that "AllowOverride All" or at least
|
||||||
"AllowOverride FileInfo Options" are enabled for the directory
|
"AllowOverride FileInfo Options" are enabled for the directory
|
||||||
you copied the files to.
|
you copied the files to.
|
||||||
|
|
||||||
|
You can override configuration file location using:
|
||||||
|
|
||||||
|
SetEnv VIEWVC_CONF_PATHNAME /etc/viewvc.conf
|
||||||
|
|
||||||
Note: If you are using Mod_Python under Apache 1.3 the tarball generation
|
Note: If you are using Mod_Python under Apache 1.3 the tarball generation
|
||||||
feature may not work because it uses multithreading. This works fine
|
feature may not work because it uses multithreading. This works fine
|
||||||
under Apache 2.
|
under Apache 2.
|
||||||
|
|
||||||
continue with step 3).
|
----------------------------------------
|
||||||
|
METHOD E: Using mod_wsgi (if installed)
|
||||||
|
----------------------------------------
|
||||||
|
Copy the Python scripts file from
|
||||||
|
<VIEWVC_INSTALLATION_DIRECTORY>/bin/mod_python/
|
||||||
|
to the directory of your choosing. Modify httpd.conf with the
|
||||||
|
following directives:
|
||||||
|
|
||||||
3) Restart apache. The commands to do this vary. "httpd -k restart" and
|
WSGIScriptAlias /viewvc <VIEWVC_INSTALLATION_DIRECTORY>/bin/wsgi/viewvc.wsgi
|
||||||
"apache -k restart" are two common variants. On RedHat Linux it is
|
WSGIScriptAlias /query <VIEWVC_INSTALLATION_DIRECTORY>/bin/wsgi/query.wsgi
|
||||||
done using the command "/sbin/service httpd restart" and on SuSE Linux
|
|
||||||
it is done with "rcapache restart"
|
|
||||||
|
|
||||||
4) Optional: Add access control.
|
You'll probably also need the following directive because of the
|
||||||
|
not-quite-sanctioned way that ViewVC manipulates Python objects.
|
||||||
|
|
||||||
In your httpd.conf you can control access to certain modules by adding
|
WSGIApplicationGroup %{GLOBAL}
|
||||||
directives like this:
|
|
||||||
|
Note: WSGI support in ViewVC is at this time quite rudimentary,
|
||||||
|
bordering on downright experimental. Your mileage may vary.
|
||||||
|
|
||||||
|
-----------------------------------------
|
||||||
|
METHOD F: Using mod_fcgid (if installed)
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
This uses ViewVC's WSGI support (from above), but supports using FastCGI,
|
||||||
|
and is a somewhat hybrid approach of several of the above methods.
|
||||||
|
|
||||||
|
Especially if fcgi is already being used for other purposes, e.g. PHP,
|
||||||
|
also using fcgi can prevent the need for including additional modules
|
||||||
|
(e.g. mod_python or mod_wsgi) within Apache, which may help lessen Apache's
|
||||||
|
memory usage and/or help improve performance.
|
||||||
|
|
||||||
|
This depends on mod_fcgid:
|
||||||
|
|
||||||
|
http://httpd.apache.org/mod_fcgid/
|
||||||
|
|
||||||
|
as well as the fcgi server from Python's flup package:
|
||||||
|
|
||||||
|
http://pypi.python.org/pypi/flup
|
||||||
|
http://trac.saddi.com/flup
|
||||||
|
|
||||||
|
The following are some example httpd.conf fragments you can use to
|
||||||
|
support this configuration:
|
||||||
|
|
||||||
|
ScriptAlias /viewvc /usr/local/viewvc/bin/wsgi/viewvc.fcgi
|
||||||
|
ScriptAlias /query /usr/local/viewvc/bin/wsgi/query.fcgi
|
||||||
|
|
||||||
|
4) [Optional] Add access control.
|
||||||
|
|
||||||
|
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>">
|
<Location "<url to viewvc.cgi>/<modname_you_wish_to_access_ctl>">
|
||||||
AllowOverride None
|
AllowOverride None
|
||||||
@@ -251,7 +324,14 @@ or if you've got Mod_Python installed you can use METHOD D:
|
|||||||
http://<server_name>/viewvc/~checkout~/<module_name>
|
http://<server_name>/viewvc/~checkout~/<module_name>
|
||||||
http://<server_name>/viewvc/<module_name>.tar.gz?view=tar
|
http://<server_name>/viewvc/<module_name>.tar.gz?view=tar
|
||||||
|
|
||||||
5) Optional: Protect your ViewVC instance from server-whacking webcrawlers.
|
5) Restart Apache.
|
||||||
|
|
||||||
|
The commands to do this vary. "httpd -k restart" and "apache -k
|
||||||
|
restart" are two common variants. On RedHat Linux it is done using
|
||||||
|
the command "/sbin/service httpd restart" and on SuSE Linux it is
|
||||||
|
done with "rcapache restart". Other systems use "apachectl restart".
|
||||||
|
|
||||||
|
6) Optional: Protect your ViewVC instance from server-whacking webcrawlers.
|
||||||
|
|
||||||
As ViewVC is a web-based application which each page containing various
|
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
|
links to other pages and views, you can expect your server's performance
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
|
|
||||||
<p><strong>Copyright © 1999-2009 The ViewCVS Group. All rights
|
<p><strong>Copyright © 1999-2011 The ViewCVS Group. All rights
|
||||||
reserved.</strong></p>
|
reserved.</strong></p>
|
||||||
|
|
||||||
<p>By using ViewVC, you agree to the terms and conditions set forth
|
<p>By using ViewVC, you agree to the terms and conditions set forth
|
||||||
@@ -60,6 +60,8 @@
|
|||||||
<li>April 10, 2007 — copyright years updated</li>
|
<li>April 10, 2007 — copyright years updated</li>
|
||||||
<li>February 22, 2008 — copyright years updated</li>
|
<li>February 22, 2008 — copyright years updated</li>
|
||||||
<li>March 18, 2009 — copyright years updated</li>
|
<li>March 18, 2009 — copyright years updated</li>
|
||||||
|
<li>March 29, 2010 — copyright years updated</li>
|
||||||
|
<li>February 18, 2011 — copyright years updated</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
@@ -54,7 +54,10 @@ import query
|
|||||||
server = sapi.AspServer(Server, Request, Response, Application)
|
server = sapi.AspServer(Server, Request, Response, Application)
|
||||||
try:
|
try:
|
||||||
cfg = viewvc.load_config(CONF_PATHNAME, server)
|
cfg = viewvc.load_config(CONF_PATHNAME, server)
|
||||||
query.main(server, cfg, "viewvc.asp")
|
viewvc_base_url = cfg.query.viewvc_base_url
|
||||||
|
if viewvc_base_url is None:
|
||||||
|
viewvc_base_url = "viewvc.asp"
|
||||||
|
query.main(server, cfg, viewvc_base_url)
|
||||||
finally:
|
finally:
|
||||||
s.close()
|
s.close()
|
||||||
|
|
||||||
|
@@ -54,4 +54,7 @@ import query
|
|||||||
|
|
||||||
server = sapi.CgiServer()
|
server = sapi.CgiServer()
|
||||||
cfg = viewvc.load_config(CONF_PATHNAME, server)
|
cfg = viewvc.load_config(CONF_PATHNAME, server)
|
||||||
query.main(server, cfg, "viewvc.cgi")
|
viewvc_base_url = cfg.query.viewvc_base_url
|
||||||
|
if viewvc_base_url is None:
|
||||||
|
viewvc_base_url = "viewvc.cgi"
|
||||||
|
query.main(server, cfg, viewvc_base_url)
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# 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
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -65,7 +65,10 @@ cfg = viewvc.load_config(CONF_PATHNAME)
|
|||||||
def index(req):
|
def index(req):
|
||||||
server = sapi.ModPythonServer(req)
|
server = sapi.ModPythonServer(req)
|
||||||
try:
|
try:
|
||||||
query.main(server, cfg, "viewvc.py")
|
viewvc_base_url = cfg.query.viewvc_base_url
|
||||||
|
if viewvc_base_url is None:
|
||||||
|
viewvc_base_url = "viewvc.py"
|
||||||
|
query.main(server, cfg, viewvc_base_url)
|
||||||
finally:
|
finally:
|
||||||
server.close()
|
server.close()
|
||||||
|
|
||||||
|
1295
bin/standalone.py
1295
bin/standalone.py
File diff suppressed because it is too large
Load Diff
@@ -242,6 +242,7 @@ def main(command, repository, revs=[], verbose=0, force=0):
|
|||||||
cfg = viewvc.load_config(CONF_PATHNAME)
|
cfg = viewvc.load_config(CONF_PATHNAME)
|
||||||
db = cvsdb.ConnectDatabase(cfg)
|
db = cvsdb.ConnectDatabase(cfg)
|
||||||
|
|
||||||
|
# Purge what must be purged.
|
||||||
if command in ('rebuild', 'purge'):
|
if command in ('rebuild', 'purge'):
|
||||||
if verbose:
|
if verbose:
|
||||||
print "Purging commit info for repository root `%s'" % repository
|
print "Purging commit info for repository root `%s'" % repository
|
||||||
@@ -252,18 +253,24 @@ def main(command, repository, revs=[], verbose=0, force=0):
|
|||||||
sys.stderr.write("ERROR: " + str(e) + "\n")
|
sys.stderr.write("ERROR: " + str(e) + "\n")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
repo = SvnRepo(repository)
|
# Record what must be recorded.
|
||||||
if command == 'rebuild' or (command == 'update' and not revs):
|
if command in ('rebuild', 'update'):
|
||||||
for rev in range(repo.rev_max+1):
|
if not os.path.exists(repository):
|
||||||
handle_revision(db, command, repo, rev, verbose)
|
sys.stderr.write('ERROR: could not find repository %s\n'
|
||||||
elif command == 'update':
|
% (repository))
|
||||||
if revs[0] is None:
|
sys.exit(1)
|
||||||
revs[0] = repo.rev_max
|
repo = SvnRepo(repository)
|
||||||
if revs[1] is None:
|
if command == 'rebuild' or (command == 'update' and not revs):
|
||||||
revs[1] = repo.rev_max
|
for rev in range(repo.rev_max+1):
|
||||||
revs.sort()
|
handle_revision(db, command, repo, rev, verbose)
|
||||||
for rev in range(revs[0], revs[1]+1):
|
elif command == 'update':
|
||||||
handle_revision(db, command, repo, rev, verbose, force)
|
if revs[0] is None:
|
||||||
|
revs[0] = repo.rev_max
|
||||||
|
if revs[1] is None:
|
||||||
|
revs[1] = repo.rev_max
|
||||||
|
revs.sort()
|
||||||
|
for rev in range(revs[0], revs[1]+1):
|
||||||
|
handle_revision(db, command, repo, rev, verbose, force)
|
||||||
|
|
||||||
def _rev2int(r):
|
def _rev2int(r):
|
||||||
if r == 'HEAD':
|
if r == 'HEAD':
|
||||||
@@ -281,7 +288,7 @@ def usage():
|
|||||||
located at REPOS-PATH.
|
located at REPOS-PATH.
|
||||||
|
|
||||||
Usage: 1. %s [-v] rebuild REPOS-PATH
|
Usage: 1. %s [-v] rebuild REPOS-PATH
|
||||||
2. %s [-v] update REPOS-PATH [REV:[REV2]] [--force]
|
2. %s [-v] update REPOS-PATH [REV[:REV2]] [--force]
|
||||||
3. %s [-v] purge REPOS-PATH
|
3. %s [-v] purge REPOS-PATH
|
||||||
|
|
||||||
1. Rebuild the commit database information for the repository located
|
1. Rebuild the commit database information for the repository located
|
||||||
@@ -330,12 +337,6 @@ if __name__ == '__main__':
|
|||||||
sys.stderr.write('ERROR: unknown command %s\n' % command)
|
sys.stderr.write('ERROR: unknown command %s\n' % command)
|
||||||
usage()
|
usage()
|
||||||
|
|
||||||
repository = args[2]
|
|
||||||
if not os.path.exists(repository):
|
|
||||||
sys.stderr.write('ERROR: could not find repository %s\n' % args[2])
|
|
||||||
usage()
|
|
||||||
repository = vclib.svn.canonicalize_rootpath(repository)
|
|
||||||
|
|
||||||
revs = []
|
revs = []
|
||||||
if len(sys.argv) > 3:
|
if len(sys.argv) > 3:
|
||||||
if command == 'rebuild':
|
if command == 'rebuild':
|
||||||
@@ -358,6 +359,7 @@ if __name__ == '__main__':
|
|||||||
rev = None
|
rev = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
repository = vclib.svn.canonicalize_rootpath(args[2])
|
||||||
repository = cvsdb.CleanRepository(os.path.abspath(repository))
|
repository = cvsdb.CleanRepository(os.path.abspath(repository))
|
||||||
main(command, repository, revs, verbose, force)
|
main(command, repository, revs, verbose, force)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
54
bin/wsgi/query.fcgi
Normal file
54
bin/wsgi/query.fcgi
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*-python-*-
|
||||||
|
#
|
||||||
|
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
# distribution or at http://viewvc.org/license-1.html.
|
||||||
|
#
|
||||||
|
# For more information, visit http://viewvc.org/
|
||||||
|
#
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# viewvc: View CVS/SVN repositories via a web browser
|
||||||
|
#
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# This is a fcgi entry point for the query ViewVC app. It's appropriate
|
||||||
|
# for use with mod_fcgid and flup. It defines a single application function
|
||||||
|
# that is a valid fcgi entry point.
|
||||||
|
#
|
||||||
|
# mod_fcgid: http://httpd.apache.org/mod_fcgid/
|
||||||
|
# flup:
|
||||||
|
# http://pypi.python.org/pypi/flup
|
||||||
|
# http://trac.saddi.com/flup
|
||||||
|
#
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
import sys, os
|
||||||
|
|
||||||
|
LIBRARY_DIR = None
|
||||||
|
CONF_PATHNAME = None
|
||||||
|
|
||||||
|
if LIBRARY_DIR:
|
||||||
|
sys.path.insert(0, LIBRARY_DIR)
|
||||||
|
else:
|
||||||
|
sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0],
|
||||||
|
"../../../lib")))
|
||||||
|
|
||||||
|
import sapi
|
||||||
|
import viewvc
|
||||||
|
import query
|
||||||
|
from flup.server import fcgi
|
||||||
|
|
||||||
|
def application(environ, start_response):
|
||||||
|
server = sapi.WsgiServer(environ, start_response)
|
||||||
|
cfg = viewvc.load_config(CONF_PATHNAME, server)
|
||||||
|
viewvc_base_url = cfg.query.viewvc_base_url
|
||||||
|
if viewvc_base_url is None:
|
||||||
|
viewvc_base_url = "viewvc.fcgi"
|
||||||
|
query.main(server, cfg, viewvc_base_url)
|
||||||
|
return []
|
||||||
|
|
||||||
|
fcgi.WSGIServer(application).run()
|
45
bin/wsgi/query.wsgi
Normal file
45
bin/wsgi/query.wsgi
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# -*-python-*-
|
||||||
|
#
|
||||||
|
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
# distribution or at http://viewvc.org/license-1.html.
|
||||||
|
#
|
||||||
|
# For more information, visit http://viewvc.org/
|
||||||
|
#
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# viewvc: View CVS/SVN repositories via a web browser
|
||||||
|
#
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# This is a wsgi entry point for the query ViewVC app. It's appropriate
|
||||||
|
# for use with mod_wsgi. It defines a single application function that
|
||||||
|
# is a valid wsgi entry point.
|
||||||
|
#
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
import sys, os
|
||||||
|
|
||||||
|
LIBRARY_DIR = None
|
||||||
|
CONF_PATHNAME = None
|
||||||
|
|
||||||
|
if LIBRARY_DIR:
|
||||||
|
sys.path.insert(0, LIBRARY_DIR)
|
||||||
|
else:
|
||||||
|
sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0],
|
||||||
|
"../../../lib")))
|
||||||
|
|
||||||
|
import sapi
|
||||||
|
import viewvc
|
||||||
|
import query
|
||||||
|
|
||||||
|
def application(environ, start_response):
|
||||||
|
server = sapi.WsgiServer(environ, start_response)
|
||||||
|
cfg = viewvc.load_config(CONF_PATHNAME, server)
|
||||||
|
viewvc_base_url = cfg.query.viewvc_base_url
|
||||||
|
if viewvc_base_url is None:
|
||||||
|
viewvc_base_url = "viewvc.wsgi"
|
||||||
|
query.main(server, cfg, viewvc_base_url)
|
||||||
|
return []
|
50
bin/wsgi/viewvc.fcgi
Normal file
50
bin/wsgi/viewvc.fcgi
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*-python-*-
|
||||||
|
#
|
||||||
|
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
# distribution or at http://viewvc.org/license-1.html.
|
||||||
|
#
|
||||||
|
# For more information, visit http://viewvc.org/
|
||||||
|
#
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# viewvc: View CVS/SVN repositories via a web browser
|
||||||
|
#
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# This is a fcgi entry point for the main ViewVC app. It's appropriate
|
||||||
|
# for use with mod_fcgid and flup. It defines a single application function
|
||||||
|
# that is a valid fcgi entry point.
|
||||||
|
#
|
||||||
|
# mod_fcgid: http://httpd.apache.org/mod_fcgid/
|
||||||
|
# flup:
|
||||||
|
# http://pypi.python.org/pypi/flup
|
||||||
|
# http://trac.saddi.com/flup
|
||||||
|
#
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
import sys, os
|
||||||
|
|
||||||
|
LIBRARY_DIR = None
|
||||||
|
CONF_PATHNAME = None
|
||||||
|
|
||||||
|
if LIBRARY_DIR:
|
||||||
|
sys.path.insert(0, LIBRARY_DIR)
|
||||||
|
else:
|
||||||
|
sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0],
|
||||||
|
"../../../lib")))
|
||||||
|
|
||||||
|
import sapi
|
||||||
|
import viewvc
|
||||||
|
from flup.server import fcgi
|
||||||
|
|
||||||
|
def application(environ, start_response):
|
||||||
|
server = sapi.WsgiServer(environ, start_response)
|
||||||
|
cfg = viewvc.load_config(CONF_PATHNAME, server)
|
||||||
|
viewvc.main(server, cfg)
|
||||||
|
return []
|
||||||
|
|
||||||
|
fcgi.WSGIServer(application).run()
|
41
bin/wsgi/viewvc.wsgi
Normal file
41
bin/wsgi/viewvc.wsgi
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# -*-python-*-
|
||||||
|
#
|
||||||
|
# Copyright (C) 1999-2009 The ViewCVS Group. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
|
# distribution or at http://viewvc.org/license-1.html.
|
||||||
|
#
|
||||||
|
# For more information, visit http://viewvc.org/
|
||||||
|
#
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# viewvc: View CVS/SVN repositories via a web browser
|
||||||
|
#
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# This is a wsgi entry point for the main ViewVC app. It's appropriate
|
||||||
|
# for use with mod_wsgi. It defines a single application function that
|
||||||
|
# is a valid wsgi entry point.
|
||||||
|
#
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
import sys, os
|
||||||
|
|
||||||
|
LIBRARY_DIR = None
|
||||||
|
CONF_PATHNAME = None
|
||||||
|
|
||||||
|
if LIBRARY_DIR:
|
||||||
|
sys.path.insert(0, LIBRARY_DIR)
|
||||||
|
else:
|
||||||
|
sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0],
|
||||||
|
"../../../lib")))
|
||||||
|
|
||||||
|
import sapi
|
||||||
|
import viewvc
|
||||||
|
|
||||||
|
def application(environ, start_response):
|
||||||
|
server = sapi.WsgiServer(environ, start_response)
|
||||||
|
cfg = viewvc.load_config(CONF_PATHNAME, server)
|
||||||
|
viewvc.main(server, cfg)
|
||||||
|
return []
|
@@ -106,27 +106,47 @@
|
|||||||
##
|
##
|
||||||
#svn_roots =
|
#svn_roots =
|
||||||
|
|
||||||
## root_parents: Specifies a list of directories in which any number of
|
## root_parents: Specifies a list of directories under which any
|
||||||
## repositories may reside. Rather than force you to add a new entry
|
## number of repositories may reside. You can specify multiple root
|
||||||
## to 'cvs_roots' or 'svn_roots' each time you create a new repository,
|
## parents separated by commas or new lines, each of which is of the
|
||||||
## ViewVC rewards you for organising all your repositories under a few
|
## form "path: type" (where type is either "cvs" or "svn").
|
||||||
## parent directories by allowing you to simply specifiy just those
|
|
||||||
## parent directories. ViewVC will then notice each repository in that
|
|
||||||
## directory as a new root whose name is the subdirectory of the parent
|
|
||||||
## path in which that repository lives.
|
|
||||||
##
|
##
|
||||||
## You can specify multiple parent paths separated by commas or new lines.
|
## Rather than force you to add a new entry to 'cvs_roots' or
|
||||||
|
## 'svn_roots' each time you create a new repository, ViewVC rewards
|
||||||
|
## you for organizing all your repositories under a few parent
|
||||||
|
## directories by allowing you to simply tell it about those parent
|
||||||
|
## directories. ViewVC will then notice each repository of the
|
||||||
|
## specified type in that directory as a root whose name is the
|
||||||
|
## subdirectory in which that repository lives.
|
||||||
##
|
##
|
||||||
## WARNING: these names can, of course, clash with names you have
|
## For example, if you have three Subversion repositories located at
|
||||||
## defined in your cvs_roots or svn_roots configuration items. If this
|
## /opt/svn/projects, /opt/svn/websites, and /opt/svn/devstuff, you
|
||||||
## occurs, you can either rename the offending repository on disk, or
|
## could list them individually in svn_roots like so:
|
||||||
## grant new names to the clashing item in cvs_roots or svn_roots.
|
##
|
||||||
## Each parent path is processed sequentially, so repositories under
|
## svn_roots = projects: /opt/svn/projects,
|
||||||
## later parent paths may override earlier ones.
|
## websites: /opt/svn/websites,
|
||||||
|
## devstuff: /opt/svn/devstuff
|
||||||
|
##
|
||||||
|
## or you could instead use the root_parents configuration option:
|
||||||
|
##
|
||||||
|
## root_parents = /opt/svn: svn
|
||||||
|
##
|
||||||
|
## The benefit of this latter approach is that, as you add new
|
||||||
|
## repositories to your /opt/svn directory, they automatically become
|
||||||
|
## available for display in ViewVC without additional configuration.
|
||||||
|
##
|
||||||
|
## WARNING: the root names derived for repositories configured via the
|
||||||
|
## root_parents option can, of course, clash with names you have
|
||||||
|
## defined in your cvs_roots or svn_roots configuration items. If
|
||||||
|
## this occurs, you can either rename the offending repository on
|
||||||
|
## disk, or grant new names to the clashing item in cvs_roots or
|
||||||
|
## svn_roots. Each parent path is processed sequentially, so the
|
||||||
|
## names of repositories under later parent paths may override earlier
|
||||||
|
## ones.
|
||||||
##
|
##
|
||||||
## Example:
|
## Example:
|
||||||
## root_parents = /opt/svn : svn,
|
## root_parents = /opt/svn: svn,
|
||||||
## /opt/cvs : cvs
|
## /opt/cvs: cvs
|
||||||
##
|
##
|
||||||
#root_parents =
|
#root_parents =
|
||||||
|
|
||||||
@@ -136,7 +156,7 @@
|
|||||||
## virtue of being the basenames of repositories found in the
|
## virtue of being the basenames of repositories found in the
|
||||||
## root_parents option locations.
|
## root_parents option locations.
|
||||||
##
|
##
|
||||||
## Note: This setting is ignored when root_as_url_component is enabled.
|
## NOTE: This setting is ignored when root_as_url_component is enabled.
|
||||||
##
|
##
|
||||||
## Example:
|
## Example:
|
||||||
## default_root = cvsroot
|
## default_root = cvsroot
|
||||||
@@ -243,9 +263,14 @@
|
|||||||
## aren't installed in the executable search path, so here's where you can
|
## aren't installed in the executable search path, so here's where you can
|
||||||
## tell ViewVC where to find them.
|
## tell ViewVC where to find them.
|
||||||
##
|
##
|
||||||
## NOTE: Options with a "_dir" suffix are for configuring the directories
|
## NOTE: Options with a "_dir" suffix are for configuring the
|
||||||
## in which certain programs live; otherwise, the option value should
|
## directories in which certain programs live. Note that this might
|
||||||
## point to the actual program.
|
## not be the same directory into which the program's installer dumped
|
||||||
|
## the whole program package -- we want the deepest directory in which
|
||||||
|
## the executable program itself resides ("C:\rcstools\bin\win32"
|
||||||
|
## rather than just "C:\rcstools", for example). The values of options
|
||||||
|
## whose names lack the "_dir" suffix should point to the actual
|
||||||
|
## program itself (such as "C:\Program Files\cvsnt\cvs.exe").
|
||||||
|
|
||||||
|
|
||||||
## rcs_dir: Directory in which the RCS utilities are installed, used
|
## rcs_dir: Directory in which the RCS utilities are installed, used
|
||||||
@@ -303,14 +328,16 @@
|
|||||||
## alternative to using the "root=" query key. If ViewVC is configured
|
## alternative to using the "root=" query key. If ViewVC is configured
|
||||||
## with multiple repositories, this results in more natural looking
|
## with multiple repositories, this results in more natural looking
|
||||||
## ViewVC URLs.
|
## ViewVC URLs.
|
||||||
## Note: Enabling this option will break backwards compatibility with
|
##
|
||||||
|
## NOTE: Enabling this option will break backwards compatibility with
|
||||||
## any old ViewCVS URL which doesn't have an explicit "root" parameter.
|
## any old ViewCVS URL which doesn't have an explicit "root" parameter.
|
||||||
##
|
##
|
||||||
#root_as_url_component = 1
|
#root_as_url_component = 1
|
||||||
|
|
||||||
## checkout_magic: Use checkout links with magic /*checkout*/ prefixes so
|
## checkout_magic: Use checkout links with magic /*checkout*/ prefixes so
|
||||||
## checked out HTML pages can have working links to other repository files
|
## checked out HTML pages can have working links to other repository files
|
||||||
## Note: This option is DEPRECATED and should not be used in new ViewVC
|
##
|
||||||
|
## NOTE: This option is DEPRECATED and should not be used in new ViewVC
|
||||||
## installations. Setting "default_file_view = co" achieves the same effect
|
## installations. Setting "default_file_view = co" achieves the same effect
|
||||||
##
|
##
|
||||||
#checkout_magic = 0
|
#checkout_magic = 0
|
||||||
@@ -318,7 +345,43 @@
|
|||||||
## allowed_views: List the ViewVC views which are enabled. Views not
|
## allowed_views: List the ViewVC views which are enabled. Views not
|
||||||
## in this comma-delited list will not be served (or, will return an
|
## in this comma-delited list will not be served (or, will return an
|
||||||
## error on attempted access).
|
## error on attempted access).
|
||||||
## Possible values: "annotate", "co", "diff", "markup", "roots", "tar"
|
##
|
||||||
|
## Valid items for this list include: "annotate", "co", "diff", "markup",
|
||||||
|
## "roots", "tar".
|
||||||
|
##
|
||||||
|
## ----------+---------------------------------------------------------
|
||||||
|
## VIEW | DESCRIPTION
|
||||||
|
## ----------+---------------------------------------------------------
|
||||||
|
## annotate | The 'annotate' view shows the contents of a single
|
||||||
|
## | revision of a versioned file in exactly the same way as
|
||||||
|
## | the markup view, but with additional line-by-line
|
||||||
|
## | change attribution (the revision number, author, etc.
|
||||||
|
## | the most recent edit to that line of text as of the
|
||||||
|
## | displayed version).
|
||||||
|
## ----------+---------------------------------------------------------
|
||||||
|
## co | The 'co' (aka "checkout" or "download") view isn't
|
||||||
|
## | really a branded view at all, but allows for direct
|
||||||
|
## | downloading of the contents of a single revision of a
|
||||||
|
## | versioned file.
|
||||||
|
## ----------+---------------------------------------------------------
|
||||||
|
## diff | The 'diff' view displays line-based differences between
|
||||||
|
## | two revisions of a versioned file in a variety of
|
||||||
|
## | different user-selectable formats.
|
||||||
|
## ----------+---------------------------------------------------------
|
||||||
|
## markup | The 'markup' view shows the contents of a single
|
||||||
|
## | revision of a versioned file, with syntax highlighting
|
||||||
|
## | where possible and enabled. It can also optionally
|
||||||
|
## | show change log information for that revision of the
|
||||||
|
## | file.
|
||||||
|
## ----------+---------------------------------------------------------
|
||||||
|
## roots | The 'roots' view is a simple listing of the various
|
||||||
|
## | repositories which ViewVC has been configured to serve
|
||||||
|
## | to users.
|
||||||
|
## ----------+---------------------------------------------------------
|
||||||
|
## tar | The 'tar' view isn't a branded view, but generates
|
||||||
|
## | a GNU Tar archive file containing a single versioned
|
||||||
|
## | directory and its contents (recursively).
|
||||||
|
## ----------+---------------------------------------------------------
|
||||||
##
|
##
|
||||||
#allowed_views = annotate, diff, markup, roots
|
#allowed_views = annotate, diff, markup, roots
|
||||||
|
|
||||||
@@ -347,6 +410,7 @@
|
|||||||
## hide_cvsroot: Don't show the CVSROOT directory
|
## hide_cvsroot: Don't show the CVSROOT directory
|
||||||
## 1 Hide CVSROOT directory
|
## 1 Hide CVSROOT directory
|
||||||
## 0 Show CVSROOT directory
|
## 0 Show CVSROOT directory
|
||||||
|
##
|
||||||
## NOTE: Someday this option may be removed in favor of letting
|
## NOTE: Someday this option may be removed in favor of letting
|
||||||
## individual authorizer plugin hide the CVSROOT.
|
## individual authorizer plugin hide the CVSROOT.
|
||||||
##
|
##
|
||||||
@@ -357,7 +421,8 @@
|
|||||||
## 0 - No mangling; markup un-mangled email addresses as hyperlinks
|
## 0 - No mangling; markup un-mangled email addresses as hyperlinks
|
||||||
## 1 - Obfuscation (using entity encoding); no hyperlinking
|
## 1 - Obfuscation (using entity encoding); no hyperlinking
|
||||||
## 2 - Data-dropping address truncation; no hyperlinking
|
## 2 - Data-dropping address truncation; no hyperlinking
|
||||||
## Note: this will not effect the display of versioned file contents, only
|
##
|
||||||
|
## NOTE: this will not effect the display of versioned file contents, only
|
||||||
## addresses that appear in version control metadata (e.g. log messages).
|
## addresses that appear in version control metadata (e.g. log messages).
|
||||||
##
|
##
|
||||||
#mangle_email_addresses = 0
|
#mangle_email_addresses = 0
|
||||||
@@ -368,9 +433,11 @@
|
|||||||
## ViewCVS URLs, but "co" has the advantage that it allows ViewVC to serve
|
## ViewCVS URLs, but "co" has the advantage that it allows ViewVC to serve
|
||||||
## static HTML pages directly from a repository with working links
|
## static HTML pages directly from a repository with working links
|
||||||
## to other repository files
|
## to other repository files
|
||||||
## Note: Changing this option may break compatibility with existing
|
##
|
||||||
|
## NOTE: Changing this option may break compatibility with existing
|
||||||
## bookmarked URLs.
|
## bookmarked URLs.
|
||||||
## Also note: If you choose one of the "co" or "markup" views, be sure
|
##
|
||||||
|
## ALSO NOTE: If you choose one of the "co" or "markup" views, be sure
|
||||||
## to enable it (via the allowed_views option)
|
## to enable it (via the allowed_views option)
|
||||||
##
|
##
|
||||||
#default_file_view = log
|
#default_file_view = log
|
||||||
@@ -490,7 +557,7 @@
|
|||||||
## allow_compress: Allow compression via gzip of output if the Browser
|
## allow_compress: Allow compression via gzip of output if the Browser
|
||||||
## accepts it (HTTP_ACCEPT_ENCODING contains "gzip").
|
## accepts it (HTTP_ACCEPT_ENCODING contains "gzip").
|
||||||
##
|
##
|
||||||
## Note: this relies on Python's gzip module, which has proven to be
|
## NOTE: this relies on Python's gzip module, which has proven to be
|
||||||
## not-so-performant. Enabling this feature should reduce the overall
|
## not-so-performant. Enabling this feature should reduce the overall
|
||||||
## transfer size of ViewVC's responses to the client's request, but
|
## transfer size of ViewVC's responses to the client's request, but
|
||||||
## will do so with a speed penalty.
|
## will do so with a speed penalty.
|
||||||
@@ -505,7 +572,8 @@
|
|||||||
## this config file resides; absolute paths may be used as well. If
|
## this config file resides; absolute paths may be used as well. If
|
||||||
## %lang% occurs in the pathname, then the selected language will be
|
## %lang% occurs in the pathname, then the selected language will be
|
||||||
## substituted.
|
## substituted.
|
||||||
## See Also: the [templates] configuration section, where you can
|
##
|
||||||
|
## SEE ALSO: the [templates] configuration section, where you can
|
||||||
## override templates on a per-view basis.
|
## override templates on a per-view basis.
|
||||||
##
|
##
|
||||||
#template_dir = templates
|
#template_dir = templates
|
||||||
@@ -517,9 +585,16 @@
|
|||||||
## penalty, and from the "docroot" subdirectory of the directory
|
## penalty, and from the "docroot" subdirectory of the directory
|
||||||
## specified by the "template_dir" option).
|
## specified by the "template_dir" option).
|
||||||
##
|
##
|
||||||
|
## NOTE: This option is evaluated outside the context of a particular
|
||||||
|
## root. Be careful when using per-root configuration to select an
|
||||||
|
## alternate template set as the default value for this option will
|
||||||
|
## still be based on the global default template set per 'template_dir'
|
||||||
|
## above, not on 'template_dir' as overridden for a given root.
|
||||||
|
##
|
||||||
#docroot =
|
#docroot =
|
||||||
|
|
||||||
## show_subdir_lastmod: Show last changelog message for CVS subdirectories
|
## show_subdir_lastmod: Show last changelog message for CVS subdirectories
|
||||||
|
##
|
||||||
## NOTE: The current implementation makes many assumptions and may show
|
## NOTE: The current implementation makes many assumptions and may show
|
||||||
## the incorrect file at some times. The main assumption is that the
|
## the incorrect file at some times. The main assumption is that the
|
||||||
## last modified file has the newest filedate. But some CVS operations
|
## last modified file has the newest filedate. But some CVS operations
|
||||||
@@ -528,10 +603,19 @@
|
|||||||
## the last checkin was on the same tag as you are viewing. Enable
|
## the last checkin was on the same tag as you are viewing. Enable
|
||||||
## this if you like the feature, but don't rely on correct results.
|
## this if you like the feature, but don't rely on correct results.
|
||||||
##
|
##
|
||||||
## ** WARNING: Enabling this will currently leak unauthorized path names **
|
## SECURITY WARNING: Enabling this will currently leak unauthorized
|
||||||
|
## path names.
|
||||||
##
|
##
|
||||||
#show_subdir_lastmod = 0
|
#show_subdir_lastmod = 0
|
||||||
|
|
||||||
|
## show_roots_lastmod: In the root listing view, show the most recent
|
||||||
|
## modifications made to the root. (Subversion roots only.)
|
||||||
|
##
|
||||||
|
## NOTE: Enabling this feature will significantly reduce the
|
||||||
|
## performance of the root listing view.
|
||||||
|
##
|
||||||
|
#show_roots_lastmod = 0
|
||||||
|
|
||||||
## show_logs: Show the most recent log entry in directory listings.
|
## show_logs: Show the most recent log entry in directory listings.
|
||||||
##
|
##
|
||||||
#show_logs = 1
|
#show_logs = 1
|
||||||
@@ -555,10 +639,21 @@
|
|||||||
#short_log_len = 80
|
#short_log_len = 80
|
||||||
|
|
||||||
## enable_syntax_coloration: Should we colorize known file content
|
## enable_syntax_coloration: Should we colorize known file content
|
||||||
## syntaxes? [Requires Pygments Python module]
|
## syntaxes?
|
||||||
|
##
|
||||||
|
## NOTE: This feature requires the Pygments Python module
|
||||||
|
## (http://pygments.org) and works only when ViewVC can determine the
|
||||||
|
## MIME content type of the file whose contents it wishes to colorize.
|
||||||
|
## Use the 'mime_types_files' configuration option to specify MIME
|
||||||
|
## type mapping files useful for making that determination.
|
||||||
##
|
##
|
||||||
#enable_syntax_coloration = 1
|
#enable_syntax_coloration = 1
|
||||||
|
|
||||||
|
## tabsize: The number of spaces into which tabstops are converted
|
||||||
|
## when viewing file contents.
|
||||||
|
##
|
||||||
|
#tabsize = 8
|
||||||
|
|
||||||
## detect_encoding: Should we attempt to detect versioned file
|
## detect_encoding: Should we attempt to detect versioned file
|
||||||
## character encodings? [Requires 'chardet' module, and is currently
|
## character encodings? [Requires 'chardet' module, and is currently
|
||||||
## used only by the syntax coloration logic -- if enabled -- for the
|
## used only by the syntax coloration logic -- if enabled -- for the
|
||||||
@@ -576,28 +671,6 @@
|
|||||||
##
|
##
|
||||||
#cvsgraph_conf = cvsgraph.conf
|
#cvsgraph_conf = cvsgraph.conf
|
||||||
|
|
||||||
## allowed_cvsgraph_useropts: A list of settings used for cvsgraph's
|
|
||||||
## user-modifiable behavior which can be changed in the graph display.
|
|
||||||
## This value is a comma-delimited list of features, taken from the
|
|
||||||
## following set:
|
|
||||||
## invert - Display graph upside down
|
|
||||||
## branchbox - Add a branchbox at the tip of each branch
|
|
||||||
## show - Display user-selected classes of revisions
|
|
||||||
## rotate - Draw the tree left-to-right or top-to-bottom [*]
|
|
||||||
## limittags - Allow limit on the maximum number of tags displayed
|
|
||||||
##
|
|
||||||
## If this option is left unset, users will not be permitted to modify
|
|
||||||
## the graph display behavior.
|
|
||||||
##
|
|
||||||
## [*] WARNING: The 'rotate' option is known to cause some browsers to
|
|
||||||
## crash due, presumably, to the display of excessively wide images.
|
|
||||||
##
|
|
||||||
## Example:
|
|
||||||
## allowed_cvsgraph_useropts = limittags, show
|
|
||||||
##
|
|
||||||
##
|
|
||||||
#allowed_cvsgraph_useropts =
|
|
||||||
|
|
||||||
## use_re_search: Enable regular expression search of files in a directory.
|
## use_re_search: Enable regular expression search of files in a directory.
|
||||||
##
|
##
|
||||||
## WARNING: Enabling this option can consume HUGE amounts of server
|
## WARNING: Enabling this option can consume HUGE amounts of server
|
||||||
@@ -626,6 +699,26 @@
|
|||||||
##
|
##
|
||||||
#log_pagesize = 0
|
#log_pagesize = 0
|
||||||
|
|
||||||
|
## log_pagesextra: Maximum number of extra pages (based on
|
||||||
|
## log_pagesize) of revision log data to fetch and present to the user
|
||||||
|
## as additional options for display. Revision log information
|
||||||
|
## "beyond" this window is still accessible, but must be navigated to
|
||||||
|
## in multiple steps.
|
||||||
|
##
|
||||||
|
## Example:
|
||||||
|
## log_pagesize = 100
|
||||||
|
## log_pagesextra = 3
|
||||||
|
##
|
||||||
|
## For a versioned file with 1000 revisions, the above settings would
|
||||||
|
## present to the user the first 100 of those 1000 revisions, with
|
||||||
|
## links to three additional pages (the 200-299th revisions, 300-399th
|
||||||
|
## revisions, and 400-499th revisions) plus a link to the 500th
|
||||||
|
## revision. Following these links slides the display "window",
|
||||||
|
## showing the requested set of revisions plus links to three
|
||||||
|
## additional pages beyond those, and so on.
|
||||||
|
##
|
||||||
|
#log_pagesextra = 3
|
||||||
|
|
||||||
## limit_changes: Maximum number of changed paths shown per commit in
|
## limit_changes: Maximum number of changed paths shown per commit in
|
||||||
## the Subversion revision view and in query results. This is not a
|
## the Subversion revision view and in query results. This is not a
|
||||||
## hard limit (the UI provides options to show all changed paths), but
|
## hard limit (the UI provides options to show all changed paths), but
|
||||||
@@ -654,7 +747,7 @@
|
|||||||
## If %lang% occurs in the pathname, then the selected language will be
|
## If %lang% occurs in the pathname, then the selected language will be
|
||||||
## substituted.
|
## substituted.
|
||||||
##
|
##
|
||||||
## Note: the selected language is defined by the "languages" item in the
|
## NOTE: the selected language is defined by the "languages" item in the
|
||||||
## [general] section, and based on the request's Accept-Language
|
## [general] section, and based on the request's Accept-Language
|
||||||
## header.
|
## header.
|
||||||
##
|
##
|
||||||
@@ -720,7 +813,8 @@
|
|||||||
#port = 3306
|
#port = 3306
|
||||||
|
|
||||||
## database_name: ViewVC database name.
|
## database_name: ViewVC database name.
|
||||||
##database_name = ViewVC
|
##
|
||||||
|
#database_name = ViewVC
|
||||||
|
|
||||||
## user: Username of user with read/write privileges to the database
|
## user: Username of user with read/write privileges to the database
|
||||||
## specified by the 'database_name' configuration option.
|
## specified by the 'database_name' configuration option.
|
||||||
@@ -745,6 +839,14 @@
|
|||||||
## row_limit: Maximum number of rows returned by a given normal query
|
## row_limit: Maximum number of rows returned by a given normal query
|
||||||
## to the database.
|
## to the database.
|
||||||
##
|
##
|
||||||
|
## NOTE: This limits the amount of data provided to ViewVC by the
|
||||||
|
## database. It is from this already-reduced data set that ViewVC
|
||||||
|
## builds the query response it presents to the user, which may or may
|
||||||
|
## not include still more limiting via the query form's 'limit'
|
||||||
|
## parameter. In other words, there is no value which the user can use
|
||||||
|
## in the query form's 'limit' parameter which will cause more data to
|
||||||
|
## be returned by the database for ViewVC to process.
|
||||||
|
##
|
||||||
#row_limit = 1000
|
#row_limit = 1000
|
||||||
|
|
||||||
## rss_row_limit: Maximum number of rows returned by a given query to
|
## rss_row_limit: Maximum number of rows returned by a given query to
|
||||||
@@ -752,6 +854,9 @@
|
|||||||
## that RSS readers tend to poll regularly for new data, you might want
|
## that RSS readers tend to poll regularly for new data, you might want
|
||||||
## to keep this set to a conservative number.)
|
## to keep this set to a conservative number.)
|
||||||
##
|
##
|
||||||
|
## See also the `NOTE' for the 'row_limit' option, which applies here
|
||||||
|
## as well.
|
||||||
|
##
|
||||||
#rss_row_limit = 100
|
#rss_row_limit = 100
|
||||||
|
|
||||||
## check_database_for_root: Check if the repository is found in the
|
## check_database_for_root: Check if the repository is found in the
|
||||||
@@ -805,6 +910,16 @@
|
|||||||
## ViewVC options typically found in the base configuration section
|
## ViewVC options typically found in the base configuration section
|
||||||
## named CONFIGSECTION ("general", "option", etc.)
|
## named CONFIGSECTION ("general", "option", etc.)
|
||||||
##
|
##
|
||||||
|
## NOTE: Per-vhost overrides may only be applied to the following
|
||||||
|
## sections:
|
||||||
|
##
|
||||||
|
## general
|
||||||
|
## options
|
||||||
|
## utilities
|
||||||
|
## templates
|
||||||
|
## cvsdb
|
||||||
|
## authz-*
|
||||||
|
##
|
||||||
## Here is an example:
|
## Here is an example:
|
||||||
##
|
##
|
||||||
## [vhosts]
|
## [vhosts]
|
||||||
@@ -834,7 +949,19 @@
|
|||||||
## basename of a root path in root_parents. Options found in this new
|
## basename of a root path in root_parents. Options found in this new
|
||||||
## configuration section override for this one root the corresponding
|
## configuration section override for this one root the corresponding
|
||||||
## options found in the base configuration section CONFIGSECTION
|
## options found in the base configuration section CONFIGSECTION
|
||||||
## ("options", "authz-*", etc.)
|
## ("options", "authz-*", etc.) as interpreted after per-vhost
|
||||||
|
## overrides (if any) have been applied.
|
||||||
|
##
|
||||||
|
## NOTE: Per-root overrides may only be applied to the following
|
||||||
|
## sections:
|
||||||
|
##
|
||||||
|
## options
|
||||||
|
## utilities
|
||||||
|
## authz-*
|
||||||
|
##
|
||||||
|
## WARNING: Do not use per-root overrides if your ViewVC instance is
|
||||||
|
## served via the standalone.py server option! Doing so could cause
|
||||||
|
## ViewVC to be unable to function properly (or at all).
|
||||||
##
|
##
|
||||||
## Here is an example showing how to enable Subversion authz-based
|
## Here is an example showing how to enable Subversion authz-based
|
||||||
## authorization for only the single root named "svnroot":
|
## authorization for only the single root named "svnroot":
|
||||||
@@ -850,8 +977,15 @@
|
|||||||
[authz-forbidden]
|
[authz-forbidden]
|
||||||
|
|
||||||
## The "forbidden" authorizer forbids access to repository modules,
|
## The "forbidden" authorizer forbids access to repository modules,
|
||||||
## defined to be top-level subdirectories in a repository. You can use
|
## defined to be top-level subdirectories in a repository.
|
||||||
## a simple list of modules, or something more complex:
|
##
|
||||||
|
## NOTE: The options in this section apply only when the 'authorizer'
|
||||||
|
## option (in the [options] section) is set to 'forbidden'.
|
||||||
|
|
||||||
|
## forbidden: A comma-delimited list of patterns which match modules
|
||||||
|
## that ViewVC should hide from users.
|
||||||
|
##
|
||||||
|
## You can use a simple list of modules, or something more complex:
|
||||||
##
|
##
|
||||||
## *) The "!" can be used before a module to explicitly state that it
|
## *) The "!" can be used before a module to explicitly state that it
|
||||||
## is NOT forbidden. Whenever this form is seen, then all modules will
|
## is NOT forbidden. Whenever this form is seen, then all modules will
|
||||||
@@ -906,6 +1040,12 @@
|
|||||||
## regular expressions. Directory paths will be terminated by a forward
|
## regular expressions. Directory paths will be terminated by a forward
|
||||||
## slash.
|
## slash.
|
||||||
##
|
##
|
||||||
|
## NOTE: The options in this section apply only when the 'authorizer'
|
||||||
|
## option (in the [options] section) is set to 'forbiddenre'.
|
||||||
|
|
||||||
|
## forbiddenre: A comma-delimited list of regular expressions which
|
||||||
|
## match paths that ViewVC should hide from users.
|
||||||
|
##
|
||||||
## Like the "forbidden" authorizer...
|
## Like the "forbidden" authorizer...
|
||||||
##
|
##
|
||||||
## *) The "!" can be used before a module to explicitly state that it
|
## *) The "!" can be used before a module to explicitly state that it
|
||||||
@@ -940,6 +1080,9 @@
|
|||||||
|
|
||||||
## The "svnauthz" authorizer uses a Subversion authz configuration file
|
## The "svnauthz" authorizer uses a Subversion authz configuration file
|
||||||
## to determine access to repository paths.
|
## to determine access to repository paths.
|
||||||
|
##
|
||||||
|
## NOTE: The options in this section apply only when the 'authorizer'
|
||||||
|
## option (in the [options] section) is set to 'svnauthz'.
|
||||||
|
|
||||||
## authzfile: Specifies the location of the authorization rules file
|
## authzfile: Specifies the location of the authorization rules file
|
||||||
## (using an absolute path).
|
## (using an absolute path).
|
||||||
@@ -955,3 +1098,30 @@
|
|||||||
#force_username_case =
|
#force_username_case =
|
||||||
|
|
||||||
##---------------------------------------------------------------------------
|
##---------------------------------------------------------------------------
|
||||||
|
[query]
|
||||||
|
|
||||||
|
## The configuration items in this section are used exclusively by the
|
||||||
|
## 'query' script, a separate script from ViewVC itself that ships
|
||||||
|
## with ViewVC and allows for queries into the ViewVC commits
|
||||||
|
## database. If you aren't using this separate script (which was made
|
||||||
|
## largely irrelevant by the introduction of an integrated "query"
|
||||||
|
## view in ViewVC itself, or aren't using the ViewVC commits database
|
||||||
|
## functionality at all, you can ignore these configurations items
|
||||||
|
## altogether.
|
||||||
|
|
||||||
|
## viewvc_base_url: Base URL at which ViewVC may be accessed on this
|
||||||
|
## server. The default value for this option is determined at
|
||||||
|
## run-time by the various front-ends to the query script.
|
||||||
|
##
|
||||||
|
## Examples:
|
||||||
|
## viewvc_base_url = /viewvc.py
|
||||||
|
## viewvc_base_url = /viewvc.wsgi
|
||||||
|
## viewvc_base_url = /cgi-bin/viewvc
|
||||||
|
## viewvc_base_url = viewvc
|
||||||
|
##
|
||||||
|
## To disable cross-linking between the query script and ViewVC,
|
||||||
|
## uncomment this option and leave its value empty.
|
||||||
|
##
|
||||||
|
#viewvc_base_url =
|
||||||
|
|
||||||
|
##---------------------------------------------------------------------------
|
||||||
|
@@ -1,211 +0,0 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>ViewVC: 1.1.0 Release Notes</title>
|
|
||||||
<style>
|
|
||||||
.h2, .h3 {
|
|
||||||
padding: 0.25em 0em;
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
.warning {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<h1>ViewVC 1.1.0 Release Notes</h1>
|
|
||||||
|
|
||||||
<div class="h2">
|
|
||||||
<h2 id="introduction">Introduction</h2>
|
|
||||||
|
|
||||||
<p>ViewVC 1.1.0 is the superset of all previous ViewVC releases.</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="h2">
|
|
||||||
<h2 id="compatibility">Compatibility</h2>
|
|
||||||
|
|
||||||
<p>Each ViewVC release strives to maintain URL stability with previous
|
|
||||||
releases, and 1.1.0 is no exception. All URLs considered valid for
|
|
||||||
previous ViewVC releases should continue to work correctly in this
|
|
||||||
release, though possibly only via the use of HTTP redirects
|
|
||||||
(generated by ViewVC itself).</p>
|
|
||||||
|
|
||||||
<p>The commits database functionality has changed in ViewVC 1.1.0 in
|
|
||||||
way that breaks compatibility with prior ViewVC releases, but only
|
|
||||||
for new database instantiations. ViewVC 1.1.0 will continue to
|
|
||||||
understand (for both read and write operations) the previous
|
|
||||||
schema, so you are not required to rebuild your commits database
|
|
||||||
for ViewVC 1.1.0 compatibility. By default, new commits databases
|
|
||||||
created using the 1.1.0 version of the <code>make-database</code>
|
|
||||||
script will use a new database schema that is unreadable by
|
|
||||||
previous ViewVC versions. However, if you need a database which
|
|
||||||
can co-exist with a previous ViewVC version, you can use
|
|
||||||
the <code>--version=1.0</code> option
|
|
||||||
to <code>make-database</code>.</p>
|
|
||||||
|
|
||||||
<p>The ViewVC configuration files and template language have changed
|
|
||||||
dramatically. See the file <code>docs/upgrading-howto.html</code>
|
|
||||||
in the release for information on porting existing versions of
|
|
||||||
those items for use with ViewVC 1.1.0.</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="h2">
|
|
||||||
<h2 id="compatibility">Features and Fixes</h2>
|
|
||||||
|
|
||||||
<div class="h3">
|
|
||||||
<h3 id="">Extensible path-based authorization w/ Subversion authz support</h3>
|
|
||||||
|
|
||||||
<p>In a nutshell, ViewVC is now able to do path-based authorization.
|
|
||||||
ViewVC 1.0 has a configuration option for naming 'forbidden'
|
|
||||||
modules, but it is really limited — it basically just makes a
|
|
||||||
universal decision about which top-level directories in every
|
|
||||||
hosted repository should be hidden by ViewVC. People want
|
|
||||||
more, and specifically requested that ViewVC learn how to honor
|
|
||||||
Subversion's authz files and semantics. So, along with some other
|
|
||||||
types of authorization approaches, that's what ViewVC 1.1 can now
|
|
||||||
do. If you are using mod_authz_svn with Apache today, or
|
|
||||||
svnserve's built-in authorization support, then you can now point
|
|
||||||
ViewVC to the same authz configuration file and have it honor the
|
|
||||||
access rules you've defined for your repositories.</p>
|
|
||||||
|
|
||||||
<p>Note that ViewVC does <strong>not</strong> handle authentication,
|
|
||||||
though. You'll need to configure your web server to demand login
|
|
||||||
credentials from users, which the web server itself can then hand
|
|
||||||
off to ViewVC for application against the authorization rules
|
|
||||||
you've defined.</p>
|
|
||||||
|
|
||||||
<p class="warning">WARNING: The root listing view does not consult the
|
|
||||||
authorization subsystem when deciding what roots to display to a
|
|
||||||
given user. If you need to protect your root names, consider
|
|
||||||
disabling it by removing <code>roots</code> from the set of views
|
|
||||||
listed in the
|
|
||||||
<code>allowed_views</code> configuration option.</p>
|
|
||||||
|
|
||||||
<p class="warning">WARNING: Support for path-based authorization is
|
|
||||||
incomplete in the experimental version control backend modules,
|
|
||||||
including the one that permits display of remote Subversion
|
|
||||||
repositories.</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="h3">
|
|
||||||
<h3 id="">Subversion versioned properties display</h3>
|
|
||||||
|
|
||||||
<p>ViewVC 1.1 displays the properties that Subversion lets you store
|
|
||||||
on files and directories
|
|
||||||
(<code>svn:mime-type</code>, <code>svn:mergeinfo</code>,
|
|
||||||
<code>svn:ignore</code>, etc.). Directory properties are shown by
|
|
||||||
default at the bottom of that directory's entry listing. File
|
|
||||||
properties are displayed at the bottom of that file's
|
|
||||||
markup/annotate view.</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="h3">
|
|
||||||
<h3 id="">Unified markup and annotation views</h3>
|
|
||||||
|
|
||||||
<p>The "markup" and "annotate" views in ViewVC now have a unified look
|
|
||||||
and feel (driven by a single EZT template). Both views support
|
|
||||||
syntax highlighting and Subversion file property display.</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="h3">
|
|
||||||
<h3 id="">Unified, hassle-free Pygments-based syntax highlighting</h3>
|
|
||||||
|
|
||||||
<p>ViewVC 1.0 does syntax highlighting by working with GNU enscript, or
|
|
||||||
highlight, or php, or py2html — all these external tools just
|
|
||||||
to accomplish a single task. But they all do things in slightly
|
|
||||||
different ways. And if you configure them wrongly, you get strange
|
|
||||||
errors. <a href="http://www.pygments.org/">Pygments</a> (which is
|
|
||||||
also used by <a href="http://trac.edgewall.org/">Trac</a> for
|
|
||||||
syntax highlighting) is a Python package that requires no
|
|
||||||
configuration, is easier to use inside ViewVC, and so on. So
|
|
||||||
ViewVC 1.1 drops support for all those various old integrations,
|
|
||||||
and just uses Pygments for everything now. This change was about
|
|
||||||
developer and administrator sanity. There will be complaints, to
|
|
||||||
be sure, about how various color schemes differ and what file types
|
|
||||||
now are and aren't understood by the syntax highlighting engine,
|
|
||||||
but this change should vastly simplify the discussions of such
|
|
||||||
things.</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="h3">
|
|
||||||
<h3 id="">Better MIME detection and handling</h3>
|
|
||||||
|
|
||||||
<p>ViewVC typically consults a MIME types file to determine what kind
|
|
||||||
of file a given document is, based on its filename extension
|
|
||||||
(<code>.jpg</code> = <code>image/jpeg</code>, …). But
|
|
||||||
Subversion lets you dictate a file's MIME type using
|
|
||||||
the <code>svn:mime-type</code> property. ViewVC now recognizes and
|
|
||||||
honors that property as the preferred source of a file's MIME type.
|
|
||||||
This can be disabled in the configuration, though, which might be
|
|
||||||
desirable if many of your Subversion-versioned files carry the
|
|
||||||
generic <code>application/octet-stream</code> MIME type that
|
|
||||||
Subversion uses by default for non-human-readable files.</p>
|
|
||||||
|
|
||||||
<p>Also, ViewVC now allows you to specify multiple MIME type mapping
|
|
||||||
files that you'd like it to consult when determine the MIME type of
|
|
||||||
files based on their extensions. This allows administrators to
|
|
||||||
easily define their own custom mappings for ViewVC's benefit
|
|
||||||
without potentially affecting the mappings used by other site
|
|
||||||
services.</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="h3">
|
|
||||||
<h3 id="">Support for full content diffs</h3>
|
|
||||||
|
|
||||||
<p>ViewVC 1.1 expands the previously existing options of "colored
|
|
||||||
diff" and "long colored diff" with a new "full colored diff", which
|
|
||||||
shows the full contents of the changed file (instead of only the 3
|
|
||||||
or 15 lines of context shown via the older diff display types).</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="h3">
|
|
||||||
<h3 id="">Support for per-root configuration overrides</h3>
|
|
||||||
|
|
||||||
<p>In ViewVC 1.1, you can setup configuration option overrides on a
|
|
||||||
per-root (per-repository) basis (if you need/care to do so). See
|
|
||||||
the comments in the <code>viewvc.conf.dist</code> file for more on
|
|
||||||
how to do this.</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="h3">
|
|
||||||
<h3 id="">Optional email address obfuscation/mangling</h3>
|
|
||||||
|
|
||||||
<p>ViewVC can, when displaying revision metadata, munge strings that
|
|
||||||
look like email addresses to protect them from screen-scraping
|
|
||||||
spammers. For example, a log message that says, "Patch by:
|
|
||||||
cmpilato@red-bean.com" can optionally be displayed by ViewVC using
|
|
||||||
HTML entity encoding for the characters (a trick that causes no
|
|
||||||
visible change to the output, but that might confuse
|
|
||||||
unsophisticated spam bot crawlers) or as "Patch by: cmpilato@..."
|
|
||||||
(which isn't a complete email address at all, but might be enough
|
|
||||||
information for the human reading the log message to know who to
|
|
||||||
blame for the patch).</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="h3">
|
|
||||||
<h3 id="">Pagination improvements</h3>
|
|
||||||
|
|
||||||
<p>The way that ViewVC splits directory and log views across pages has
|
|
||||||
been reworked. The old way was "Fetch all the information you can
|
|
||||||
find, then display only one page's worth." The new way is "Fetch
|
|
||||||
only what you need to display the page requested, plus a little bit
|
|
||||||
of border information." This provides a large performance
|
|
||||||
enhancement for the default sort orderings.</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@@ -1,6 +1,6 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>ViewVC 1.0 Template Authoring Guide</title>
|
<title>ViewVC 1.1 Template Authoring Guide</title>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
background-color: rgb(180,193,205);
|
background-color: rgb(180,193,205);
|
||||||
@@ -38,13 +38,13 @@ td {
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<h1>ViewVC 1.0 Template Authoring Guide</h1>
|
<h1>ViewVC 1.1 Template Authoring Guide</h1>
|
||||||
|
|
||||||
<div class="h2">
|
<div class="h2">
|
||||||
<h2 id="introduction">Introduction</h2>
|
<h2 id="introduction">Introduction</h2>
|
||||||
|
|
||||||
<p>This document represents an (unfinished) attempt at providing
|
<p>This document represents an (unfinished) attempt at providing
|
||||||
documentation for how to customize ViewVC 1.0-dev's HTML output via
|
instructions for how to customize ViewVC's HTML output via
|
||||||
modification of its templates.</p>
|
modification of its templates.</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -598,45 +598,6 @@ td {
|
|||||||
<td colspan="3">Includes all variables from the
|
<td colspan="3">Includes all variables from the
|
||||||
<a href="#variables-common">COMMON</a> variable set</td>
|
<a href="#variables-common">COMMON</a> variable set</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="varlevel1">
|
|
||||||
<td class="varname">gbbox</td>
|
|
||||||
<td>Boolean</td>
|
|
||||||
<td>Toggle generation of a branch box at the tip of all branches in
|
|
||||||
the revision graph.</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="varlevel1">
|
|
||||||
<td class="varname">gflip</td>
|
|
||||||
<td>Boolean</td>
|
|
||||||
<td>Toggle the direction of the revision graph.</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="varlevel1">
|
|
||||||
<td class="varname">gleft</td>
|
|
||||||
<td>Boolean</td>
|
|
||||||
<td>Toggle the orientation of the revision graph.</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="varlevel1">
|
|
||||||
<td class="varname">gmaxtag</td>
|
|
||||||
<td>String</td>
|
|
||||||
<td>Number of tags per revision to display in the revision graph.</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="varlevel1">
|
|
||||||
<td class="varname">graph_action</td>
|
|
||||||
<td>String</td>
|
|
||||||
<td>Form action URL for the graph customization form.</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="varlevel1">
|
|
||||||
<td class="varname">graph_hidden_values</td>
|
|
||||||
<td>String</td>
|
|
||||||
<td>Hidden value name/value pairs for the graph customization form.</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="varlevel1">
|
|
||||||
<td class="varname">gshow</td>
|
|
||||||
<td>String</td>
|
|
||||||
<td>Classes of revisions to show in the revision graph. Valid values
|
|
||||||
are <tt>all</tt> (all revision), <tt>inittagged</tt> (initial
|
|
||||||
revision(s) and tagged revisions), and <tt>tagged</tt> (tagged
|
|
||||||
revisions only).</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="varlevel1">
|
<tr class="varlevel1">
|
||||||
<td class="varname">imagemap</td>
|
<td class="varname">imagemap</td>
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
@@ -649,37 +610,6 @@ td {
|
|||||||
<td>URL of the ViewVC revision graph image for the current
|
<td>URL of the ViewVC revision graph image for the current
|
||||||
resource.</td>
|
resource.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="varlevel1">
|
|
||||||
<td class="varname">opt_gbbox</td>
|
|
||||||
<td>Boolean</td>
|
|
||||||
<td>Specifies whether the user is allowed to toggle the generation
|
|
||||||
of branch boxes at the tip of all branches in the revision
|
|
||||||
graph.</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="varlevel1">
|
|
||||||
<td class="varname">opt_gflip</td>
|
|
||||||
<td>Boolean</td>
|
|
||||||
<td>Specifies whether the user is allowed to toggle the direction
|
|
||||||
of the revision graph.</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="varlevel1">
|
|
||||||
<td class="varname">opt_gleft</td>
|
|
||||||
<td>Boolean</td>
|
|
||||||
<td>Specifies whether the user is allowed to toggle the orientation
|
|
||||||
of the revision graph.</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="varlevel1">
|
|
||||||
<td class="varname">opt_gmaxtag</td>
|
|
||||||
<td>Boolean</td>
|
|
||||||
<td>Specifies whether the user is allowed to configure the maximum
|
|
||||||
number of tags per revision show in the revision graph.</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="varlevel1">
|
|
||||||
<td class="varname">opt_gshow</td>
|
|
||||||
<td>Boolean</td>
|
|
||||||
<td>Specifies whether the user is allowed to configure which
|
|
||||||
classes of revisions are shown in the revision graph.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@@ -796,12 +726,22 @@ td {
|
|||||||
<td>Container</td>
|
<td>Container</td>
|
||||||
<td>Container object for grouping information about the left file.</td>
|
<td>Container object for grouping information about the left file.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr class="varlevel2">
|
||||||
|
<td class="varname">left.ago</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>Text description of the time elapsed since <var>left.date</date>.</td>
|
||||||
|
</tr>
|
||||||
<tr class="varlevel2">
|
<tr class="varlevel2">
|
||||||
<td class="varname">left.annotate_href</td>
|
<td class="varname">left.annotate_href</td>
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
<td>URL of the ViewVC annotation view for the left file.
|
<td>URL of the ViewVC annotation view for the left file.
|
||||||
Valid only when <var>entries.pathtype</var> is <tt>file</tt>.</td>
|
Valid only when <var>entries.pathtype</var> is <tt>file</tt>.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr class="varlevel2">
|
||||||
|
<td class="varname">left.author</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>Author of the revision of the left file.</td>
|
||||||
|
</tr>
|
||||||
<tr class="varlevel2">
|
<tr class="varlevel2">
|
||||||
<td class="varname">left.date</td>
|
<td class="varname">left.date</td>
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
@@ -819,6 +759,11 @@ td {
|
|||||||
<td>URL to download the HEAD revision of the left file as
|
<td>URL to download the HEAD revision of the left file as
|
||||||
<tt>text/plain</tt>.</td>
|
<tt>text/plain</tt>.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr class="varlevel2">
|
||||||
|
<td class="varname">left.log</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>Log message of the left file revision.</td>
|
||||||
|
</tr>
|
||||||
<tr class="varlevel2">
|
<tr class="varlevel2">
|
||||||
<td class="varname">left.path</td>
|
<td class="varname">left.path</td>
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
@@ -842,6 +787,11 @@ td {
|
|||||||
current revision. Valid only when <var>roottype</var> is
|
current revision. Valid only when <var>roottype</var> is
|
||||||
<tt>svn</tt>.</td>
|
<tt>svn</tt>.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr class="varlevel2">
|
||||||
|
<td class="varname">left.size</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>Size of the left file revision, in bytes. Subversion only.</td>
|
||||||
|
</tr>
|
||||||
<tr class="varlevel2">
|
<tr class="varlevel2">
|
||||||
<td class="varname">left.tag</td>
|
<td class="varname">left.tag</td>
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
@@ -852,6 +802,11 @@ td {
|
|||||||
<td>String</td>
|
<td>String</td>
|
||||||
<td>This is a URL for the markup view of the left file.</td>
|
<td>This is a URL for the markup view of the left file.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr class="varlevel1">
|
||||||
|
<td class="varname">patch_href</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>URL of the patch view for the file.</td>
|
||||||
|
</tr>
|
||||||
<tr class="varlevel1">
|
<tr class="varlevel1">
|
||||||
<td class="varname">raw_diff</td>
|
<td class="varname">raw_diff</td>
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
@@ -863,12 +818,22 @@ td {
|
|||||||
<td>Container</td>
|
<td>Container</td>
|
||||||
<td>Container object for grouping information about the right file.</td>
|
<td>Container object for grouping information about the right file.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr class="varlevel2">
|
||||||
|
<td class="varname">right.author</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>Author of the revision of the right file.</td>
|
||||||
|
</tr>
|
||||||
<tr class="varlevel2">
|
<tr class="varlevel2">
|
||||||
<td class="varname">right.annotate_href</td>
|
<td class="varname">right.annotate_href</td>
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
<td>URL of the ViewVC annotation view for the right file.
|
<td>URL of the ViewVC annotation view for the right file.
|
||||||
Valid only when <var>entries.pathtype</var> is <tt>file</tt>.</td>
|
Valid only when <var>entries.pathtype</var> is <tt>file</tt>.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr class="varlevel2">
|
||||||
|
<td class="varname">right.author</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>Author of the revision of the right file.</td>
|
||||||
|
</tr>
|
||||||
<tr class="varlevel2">
|
<tr class="varlevel2">
|
||||||
<td class="varname">right.date</td>
|
<td class="varname">right.date</td>
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
@@ -886,6 +851,11 @@ td {
|
|||||||
<td>URL to download the HEAD revision of the right file as
|
<td>URL to download the HEAD revision of the right file as
|
||||||
<tt>text/plain</tt>.</td>
|
<tt>text/plain</tt>.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr class="varlevel2">
|
||||||
|
<td class="varname">right.log</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>Log message of the right file revision.</td>
|
||||||
|
</tr>
|
||||||
<tr class="varlevel2">
|
<tr class="varlevel2">
|
||||||
<td class="varname">right.path</td>
|
<td class="varname">right.path</td>
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
@@ -909,6 +879,11 @@ td {
|
|||||||
current revision. Valid only when <var>roottype</var> is
|
current revision. Valid only when <var>roottype</var> is
|
||||||
<tt>svn</tt>.</td>
|
<tt>svn</tt>.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr class="varlevel2">
|
||||||
|
<td class="varname">right.size</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>Size of the right file revision, in bytes. Subversion only.</td>
|
||||||
|
</tr>
|
||||||
<tr class="varlevel2">
|
<tr class="varlevel2">
|
||||||
<td class="varname">right.tag</td>
|
<td class="varname">right.tag</td>
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
@@ -1851,6 +1826,14 @@ td {
|
|||||||
<td>Indicates how query results are being sorted. Possible values:
|
<td>Indicates how query results are being sorted. Possible values:
|
||||||
<tt>date</tt>, <tt>author</tt>, and <tt>file</tt>.</td>
|
<tt>date</tt>, <tt>author</tt>, and <tt>file</tt>.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr class="varlevel1">
|
||||||
|
<td class="varname">row_limit_reached</td>
|
||||||
|
<td>Boolean</td>
|
||||||
|
<td>Indicates whether the internal database row limit threshold (set
|
||||||
|
via the <code>cvsdb.row_limit</code>
|
||||||
|
and <code>cvsdb.rss_row_limit</code> configuration options) was
|
||||||
|
reached by the query.</td>
|
||||||
|
</tr>
|
||||||
<tr class="varlevel1">
|
<tr class="varlevel1">
|
||||||
<td class="varname">show_branch</td>
|
<td class="varname">show_branch</td>
|
||||||
<td>Boolean</td>
|
<td>Boolean</td>
|
||||||
@@ -2174,6 +2157,38 @@ td {
|
|||||||
<td>List</td>
|
<td>List</td>
|
||||||
<td>Set of configured viewable repositories.</td>
|
<td>Set of configured viewable repositories.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr class="varlevel2">
|
||||||
|
<td class="varname">roots.ago</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>Textual description of the time since <var>roots.date</var>.</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="varlevel2">
|
||||||
|
<td class="varname">roots.author</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>Username of the last modifier of the root.</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="varlevel2">
|
||||||
|
<td class="varname">root.date</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>Date (in UTC if not otherwise configured) of the last
|
||||||
|
modification of the root.</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="varlevel2">
|
||||||
|
<td class="varname">roots.href</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>URL of root directory view for a configured repository.</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="varlevel2">
|
||||||
|
<td class="varname">roots.log</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>Log message of last modification to the root.</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="varlevel2">
|
||||||
|
<td class="varname">roots.log_href</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>URL of log revision view for the top-most (root) directory of
|
||||||
|
the root (repository).</td>
|
||||||
|
</tr>
|
||||||
<tr class="varlevel2">
|
<tr class="varlevel2">
|
||||||
<td class="varname">roots.name</td>
|
<td class="varname">roots.name</td>
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
@@ -2187,17 +2202,24 @@ td {
|
|||||||
configuration can have negative security implications. Use this
|
configuration can have negative security implications. Use this
|
||||||
token at your own risk.</td>
|
token at your own risk.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr class="varlevel2">
|
||||||
|
<td class="varname">roots.rev</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>Youngest revision of the root.</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="varlevel2">
|
||||||
|
<td class="varname">roots.short_log</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>Log message of last modification to the root, truncated to
|
||||||
|
contain no more than the number of characters specified by
|
||||||
|
the <code>short_log_len</code> configuration option.</td>
|
||||||
|
</tr>
|
||||||
<tr class="varlevel2">
|
<tr class="varlevel2">
|
||||||
<td class="varname">roots.type</td>
|
<td class="varname">roots.type</td>
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
<td>Version control type of a configured repository. Valid
|
<td>Version control type of a configured repository. Valid
|
||||||
values: <tt>cvs</tt>, <tt>svn</tt>.</td>
|
values: <tt>cvs</tt>, <tt>svn</tt>.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="varlevel2">
|
|
||||||
<td class="varname">roots.href</td>
|
|
||||||
<td>String</td>
|
|
||||||
<td>URL of root directory view for a configured repository.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@@ -348,7 +348,7 @@ td {
|
|||||||
all = viewvc.*
|
all = viewvc.*
|
||||||
|
|
||||||
[all-options]
|
[all-options]
|
||||||
allow_tar = 1
|
allowed_views = annotate, diff, markup, tar
|
||||||
</pre>
|
</pre>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
@@ -358,7 +358,7 @@ allow_tar = 1
|
|||||||
all = viewvc.*
|
all = viewvc.*
|
||||||
|
|
||||||
[vhost-all/options]
|
[vhost-all/options]
|
||||||
allow_tar = 1
|
allowed_views = annotate, diff, markup, tar
|
||||||
</pre>
|
</pre>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
|
@@ -654,35 +654,6 @@ th.caption {
|
|||||||
<td>depends</td>
|
<td>depends</td>
|
||||||
<td><a href="#root-param"><code>root</code> parameter</a></td>
|
<td><a href="#root-param"><code>root</code> parameter</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td><code>gflip=<var>GFLIP</var></code></td>
|
|
||||||
<td>optional</td>
|
|
||||||
<td>"1" if the revisions in the graph should run
|
|
||||||
youngest-to-oldest; "0" for the reverse</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>gbbox=<var>GBBOX</var></code></td>
|
|
||||||
<td>optional</td>
|
|
||||||
<td>"1" if the revision graph should contain branch boxes at the
|
|
||||||
tip of each branch; "0" otherwise</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>gleft=<var>GLEFT</var></code></td>
|
|
||||||
<td>optional</td>
|
|
||||||
<td>"1" if the revision graph should be orientated left-to-right;
|
|
||||||
"0" otherwise</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>gmaxtag=<var>GMAXTAG</var></code></td>
|
|
||||||
<td>optional</td>
|
|
||||||
<td>maximum number of per-revision tags to show in the revision graph</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>gshow=<var>GSHOW</var></code></td>
|
|
||||||
<td>optional</td>
|
|
||||||
<td>"all", "inittagged", or "tagged" — user-selected classes
|
|
||||||
of revision to show in the graph</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<h3 id="graphimg-view">Graph Image View</h3>
|
<h3 id="graphimg-view">Graph Image View</h3>
|
||||||
@@ -729,35 +700,6 @@ th.caption {
|
|||||||
<td>depends</td>
|
<td>depends</td>
|
||||||
<td><a href="#root-param"><code>root</code> parameter</a></td>
|
<td><a href="#root-param"><code>root</code> parameter</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td><code>gflip=<var>GFLIP</var></code></td>
|
|
||||||
<td>optional</td>
|
|
||||||
<td>"1" if the revisions in the graph should run
|
|
||||||
youngest-to-oldest; "0" for the reverse</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>gbbox=<var>GBBOX</var></code></td>
|
|
||||||
<td>optional</td>
|
|
||||||
<td>"1" if the revision graph should contain branch boxes at the
|
|
||||||
tip of each branch; "0" otherwise</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>gleft=<var>GLEFT</var></code></td>
|
|
||||||
<td>optional</td>
|
|
||||||
<td>"1" if the revision graph should be orientated left-to-right;
|
|
||||||
"0" otherwise</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>gmaxtag=<var>GMAXTAG</var></code></td>
|
|
||||||
<td>optional</td>
|
|
||||||
<td>maximum number of per-revision tags to show in the revision graph</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>gshow=<var>GSHOW</var></code></td>
|
|
||||||
<td>optional</td>
|
|
||||||
<td>"all", "inittagged", or "tagged" — user-selected classes
|
|
||||||
of revision to show in the graph</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<h3 id="log-view">Log View</h3>
|
<h3 id="log-view">Log View</h3>
|
||||||
@@ -1250,13 +1192,6 @@ th.caption {
|
|||||||
commands to back out changes instead showing a normal query result
|
commands to back out changes instead showing a normal query result
|
||||||
page</td>
|
page</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td><code>limit=<var>LIMIT</var></code></td>
|
|
||||||
<td>optional</td>
|
|
||||||
<td>maximum number of file-revisions to process during a
|
|
||||||
query. Default is value of <code>row_limit</code> configuration
|
|
||||||
option</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>limit_changes=<var>LIMIT_CHANGES</var></code></td>
|
<td><code>limit_changes=<var>LIMIT_CHANGES</var></code></td>
|
||||||
<td>optional</td>
|
<td>optional</td>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
|
||||||
# Copyright (C) 2000 Curt Hagenlocher <curt@hagenlocher.org>
|
# Copyright (C) 2000 Curt Hagenlocher <curt@hagenlocher.org>
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
@@ -32,9 +32,8 @@ import os
|
|||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
import math
|
import math
|
||||||
import cgi
|
|
||||||
import vclib
|
import vclib
|
||||||
|
import sapi
|
||||||
|
|
||||||
re_includes = re.compile('\\#(\\s*)include(\\s*)"(.*?)"')
|
re_includes = re.compile('\\#(\\s*)include(\\s*)"(.*?)"')
|
||||||
|
|
||||||
@@ -82,7 +81,7 @@ class HTMLBlameSource:
|
|||||||
diff_url = None
|
diff_url = None
|
||||||
if item.prev_rev:
|
if item.prev_rev:
|
||||||
diff_url = '%sr1=%s&r2=%s' % (self.diff_url, item.prev_rev, item.rev)
|
diff_url = '%sr1=%s&r2=%s' % (self.diff_url, item.prev_rev, item.rev)
|
||||||
thisline = link_includes(cgi.escape(item.text), self.repos,
|
thisline = link_includes(sapi.escape(item.text), self.repos,
|
||||||
self.path_parts, self.include_url)
|
self.path_parts, self.include_url)
|
||||||
return _item(text=thisline, line_number=item.line_number,
|
return _item(text=thisline, line_number=item.line_number,
|
||||||
rev=item.rev, prev_rev=item.prev_rev,
|
rev=item.rev, prev_rev=item.prev_rev,
|
||||||
|
294
lib/config.py
294
lib/config.py
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2009 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2011 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# 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
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -24,45 +24,148 @@ import fnmatch
|
|||||||
#########################################################################
|
#########################################################################
|
||||||
#
|
#
|
||||||
# CONFIGURATION
|
# CONFIGURATION
|
||||||
|
# -------------
|
||||||
#
|
#
|
||||||
# There are three forms of configuration:
|
# There are three forms of configuration:
|
||||||
#
|
#
|
||||||
# 1) edit the viewvc.conf created by the viewvc-install(er)
|
# 1. edit the viewvc.conf created by the viewvc-install(er)
|
||||||
# 2) as (1), but delete all unchanged entries from viewvc.conf
|
# 2. as (1), but delete all unchanged entries from viewvc.conf
|
||||||
# 3) do not use viewvc.conf and just edit the defaults in this file
|
# 3. do not use viewvc.conf and just edit the defaults in this file
|
||||||
#
|
#
|
||||||
# Most users will want to use (1), but there are slight speed advantages
|
# Most users will want to use (1), but there are slight speed advantages
|
||||||
# to the other two options. Note that viewvc.conf values are a bit easier
|
# to the other two options. Note that viewvc.conf values are a bit easier
|
||||||
# to work with since it is raw text, rather than python literal values.
|
# to work with since it is raw text, rather than python literal values.
|
||||||
#
|
#
|
||||||
|
#
|
||||||
|
# A WORD ABOUT OPTION LAYERING/OVERRIDES
|
||||||
|
# --------------------------------------
|
||||||
|
#
|
||||||
|
# ViewVC has three "layers" of configuration options:
|
||||||
|
#
|
||||||
|
# 1. base configuration options - very basic configuration bits
|
||||||
|
# found in sections like 'general', 'options', etc.
|
||||||
|
# 2. vhost overrides - these options overlay/override the base
|
||||||
|
# configuration on a per-vhost basis.
|
||||||
|
# 3. root overrides - these options overlay/override the base
|
||||||
|
# configuration and vhost overrides on a per-root basis.
|
||||||
|
#
|
||||||
|
# Here's a diagram of the valid overlays/overrides:
|
||||||
|
#
|
||||||
|
# PER-ROOT PER-VHOST BASE
|
||||||
|
#
|
||||||
|
# ,-----------. ,-----------.
|
||||||
|
# | vhost-*/ | | |
|
||||||
|
# | general | --> | general |
|
||||||
|
# | | | |
|
||||||
|
# `-----------' `-----------'
|
||||||
|
# ,-----------. ,-----------. ,-----------.
|
||||||
|
# | root-*/ | | vhost-*/ | | |
|
||||||
|
# | options | --> | options | --> | options |
|
||||||
|
# | | | | | |
|
||||||
|
# `-----------' `-----------' `-----------'
|
||||||
|
# ,-----------. ,-----------. ,-----------.
|
||||||
|
# | root-*/ | | vhost-*/ | | |
|
||||||
|
# | templates | --> | templates | --> | templates |
|
||||||
|
# | | | | | |
|
||||||
|
# `-----------' `-----------' `-----------'
|
||||||
|
# ,-----------. ,-----------. ,-----------.
|
||||||
|
# | root-*/ | | vhost-*/ | | |
|
||||||
|
# | utilities | --> | utilities | --> | utilities |
|
||||||
|
# | | | | | |
|
||||||
|
# `-----------' `-----------' `-----------'
|
||||||
|
# ,-----------. ,-----------.
|
||||||
|
# | vhost-*/ | | |
|
||||||
|
# | cvsdb | --> | cvsdb |
|
||||||
|
# | | | |
|
||||||
|
# `-----------' `-----------'
|
||||||
|
# ,-----------. ,-----------. ,-----------.
|
||||||
|
# | root-*/ | | vhost-*/ | | |
|
||||||
|
# | authz-* | --> | authz-* | --> | authz-* |
|
||||||
|
# | | | | | |
|
||||||
|
# `-----------' `-----------' `-----------'
|
||||||
|
# ,-----------.
|
||||||
|
# | |
|
||||||
|
# | vhosts |
|
||||||
|
# | |
|
||||||
|
# `-----------'
|
||||||
|
# ,-----------.
|
||||||
|
# | |
|
||||||
|
# | query |
|
||||||
|
# | |
|
||||||
|
# `-----------'
|
||||||
|
#
|
||||||
|
# ### TODO: Figure out what this all means for the 'kv' stuff.
|
||||||
|
#
|
||||||
#########################################################################
|
#########################################################################
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
_sections = ('general', 'utilities', 'options', 'cvsdb', 'templates')
|
_base_sections = (
|
||||||
_force_multi_value = ('cvs_roots', 'svn_roots', 'languages', 'kv_files',
|
# Base configuration sections.
|
||||||
'root_parents', 'allowed_views', 'mime_types_files')
|
'authz-*',
|
||||||
|
'cvsdb',
|
||||||
|
'general',
|
||||||
|
'options',
|
||||||
|
'query',
|
||||||
|
'templates',
|
||||||
|
'utilities',
|
||||||
|
)
|
||||||
|
_force_multi_value = (
|
||||||
|
# Configuration values with multiple, comma-separated values.
|
||||||
|
'allowed_views',
|
||||||
|
'cvs_roots',
|
||||||
|
'kv_files',
|
||||||
|
'languages',
|
||||||
|
'mime_types_files',
|
||||||
|
'root_parents',
|
||||||
|
'svn_roots',
|
||||||
|
)
|
||||||
|
_allowed_overrides = {
|
||||||
|
# Mapping of override types to allowed overridable sections.
|
||||||
|
'vhost' : ('authz-*',
|
||||||
|
'cvsdb',
|
||||||
|
'general',
|
||||||
|
'options',
|
||||||
|
'templates',
|
||||||
|
'utilities',
|
||||||
|
),
|
||||||
|
'root' : ('authz-*',
|
||||||
|
'options',
|
||||||
|
'templates',
|
||||||
|
'utilities',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
for section in self._sections:
|
self.root_options_overlayed = 0
|
||||||
|
for section in self._base_sections:
|
||||||
|
if section[-1] == '*':
|
||||||
|
continue
|
||||||
setattr(self, section, _sub_config())
|
setattr(self, section, _sub_config())
|
||||||
|
|
||||||
def load_config(self, pathname, vhost=None, rootname=None):
|
def load_config(self, pathname, vhost=None):
|
||||||
|
"""Load the configuration file at PATHNAME, applying configuration
|
||||||
|
settings there as overrides to the built-in default values. If
|
||||||
|
VHOST is provided, also process the configuration overrides
|
||||||
|
specific to that virtual host."""
|
||||||
|
|
||||||
self.conf_path = os.path.isfile(pathname) and pathname or None
|
self.conf_path = os.path.isfile(pathname) and pathname or None
|
||||||
self.base = os.path.dirname(pathname)
|
self.base = os.path.dirname(pathname)
|
||||||
self.parser = ConfigParser.ConfigParser()
|
self.parser = ConfigParser.ConfigParser()
|
||||||
|
self.parser.optionxform = lambda x: x # don't case-normalize option names.
|
||||||
self.parser.read(self.conf_path or [])
|
self.parser.read(self.conf_path or [])
|
||||||
|
|
||||||
for section in self._sections:
|
for section in self.parser.sections():
|
||||||
if self.parser.has_section(section):
|
if self._is_allowed_section(section, self._base_sections):
|
||||||
self._process_section(self.parser, section, section)
|
self._process_section(self.parser, section, section)
|
||||||
|
|
||||||
if vhost and self.parser.has_section('vhosts'):
|
if vhost and self.parser.has_section('vhosts'):
|
||||||
self._process_vhost(self.parser, vhost)
|
self._process_vhost(self.parser, vhost)
|
||||||
|
|
||||||
if rootname:
|
|
||||||
self._process_root_options(self.parser, rootname)
|
|
||||||
|
|
||||||
def load_kv_files(self, language):
|
def load_kv_files(self, language):
|
||||||
|
"""Process the key/value (kv) files specified in the
|
||||||
|
configuration, merging their values into the configuration as
|
||||||
|
dotted heirarchical items."""
|
||||||
|
|
||||||
kv = _sub_config()
|
kv = _sub_config()
|
||||||
|
|
||||||
for fname in self.general.kv_files:
|
for fname in self.general.kv_files:
|
||||||
@@ -75,6 +178,7 @@ class Config:
|
|||||||
fname = string.replace(fname, '%lang%', language)
|
fname = string.replace(fname, '%lang%', language)
|
||||||
|
|
||||||
parser = ConfigParser.ConfigParser()
|
parser = ConfigParser.ConfigParser()
|
||||||
|
parser.optionxform = lambda x: x # don't case-normalize option names.
|
||||||
parser.read(os.path.join(self.base, fname))
|
parser.read(os.path.join(self.base, fname))
|
||||||
for section in parser.sections():
|
for section in parser.sections():
|
||||||
for option in parser.options(section):
|
for option in parser.options(section):
|
||||||
@@ -92,10 +196,12 @@ class Config:
|
|||||||
return kv
|
return kv
|
||||||
|
|
||||||
def path(self, path):
|
def path(self, path):
|
||||||
"""Return path relative to the config file directory"""
|
"""Return PATH relative to the config file directory."""
|
||||||
return os.path.join(self.base, path)
|
return os.path.join(self.base, path)
|
||||||
|
|
||||||
def _process_section(self, parser, section, subcfg_name):
|
def _process_section(self, parser, section, subcfg_name):
|
||||||
|
if not hasattr(self, subcfg_name):
|
||||||
|
setattr(self, subcfg_name, _sub_config())
|
||||||
sc = getattr(self, subcfg_name)
|
sc = getattr(self, subcfg_name)
|
||||||
|
|
||||||
for opt in parser.options(section):
|
for opt in parser.options(section):
|
||||||
@@ -108,25 +214,54 @@ class Config:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
### FIXME: This feels like unnecessary depth of knowledge for a
|
||||||
|
### semi-generic configuration object.
|
||||||
if opt == 'cvs_roots' or opt == 'svn_roots':
|
if opt == 'cvs_roots' or opt == 'svn_roots':
|
||||||
value = _parse_roots(opt, value)
|
value = _parse_roots(opt, value)
|
||||||
|
|
||||||
setattr(sc, opt, value)
|
setattr(sc, opt, value)
|
||||||
|
|
||||||
|
def _is_allowed_section(self, section, allowed_sections):
|
||||||
|
"""Return 1 iff SECTION is an allowed section, defined as being
|
||||||
|
explicitly present in the ALLOWED_SECTIONS list or present in the
|
||||||
|
form 'someprefix-*' in that list."""
|
||||||
|
|
||||||
|
for allowed_section in allowed_sections:
|
||||||
|
if allowed_section[-1] == '*':
|
||||||
|
if _startswith(section, allowed_section[:-1]):
|
||||||
|
return 1
|
||||||
|
elif allowed_section == section:
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def _is_allowed_override(self, sectype, secspec, section):
|
||||||
|
"""Test if SECTION is an allowed override section for sections of
|
||||||
|
type SECTYPE ('vhosts' or 'root', currently) and type-specifier
|
||||||
|
SECSPEC (a rootname or vhostname, currently). If it is, return
|
||||||
|
the overridden base section name. If it's not an override section
|
||||||
|
at all, return None. And if it's an override section but not an
|
||||||
|
allowed one, raise IllegalOverrideSection."""
|
||||||
|
|
||||||
|
cv = '%s-%s/' % (sectype, secspec)
|
||||||
|
lcv = len(cv)
|
||||||
|
if section[:lcv] != cv:
|
||||||
|
return None
|
||||||
|
base_section = section[lcv:]
|
||||||
|
if self._is_allowed_section(base_section,
|
||||||
|
self._allowed_overrides[sectype]):
|
||||||
|
return base_section
|
||||||
|
raise IllegalOverrideSection(sectype, section)
|
||||||
|
|
||||||
def _process_vhost(self, parser, vhost):
|
def _process_vhost(self, parser, vhost):
|
||||||
# find a vhost name for this vhost, if any (if not, we've nothing to do)
|
# Find a vhost name for this VHOST, if any (else, we've nothing to do).
|
||||||
canon_vhost = self._find_canon_vhost(parser, vhost)
|
canon_vhost = self._find_canon_vhost(parser, vhost)
|
||||||
if not canon_vhost:
|
if not canon_vhost:
|
||||||
return
|
return
|
||||||
|
|
||||||
# overlay any option sections associated with this vhost name
|
# Overlay any option sections associated with this vhost name.
|
||||||
cv = 'vhost-%s/' % (canon_vhost)
|
|
||||||
lcv = len(cv)
|
|
||||||
for section in parser.sections():
|
for section in parser.sections():
|
||||||
if section[:lcv] == cv:
|
base_section = self._is_allowed_override('vhost', canon_vhost, section)
|
||||||
base_section = section[lcv:]
|
if base_section:
|
||||||
if base_section not in self._sections:
|
|
||||||
raise IllegalOverrideSection('vhost', section)
|
|
||||||
self._process_section(parser, section, base_section)
|
self._process_section(parser, section, base_section)
|
||||||
|
|
||||||
def _find_canon_vhost(self, parser, vhost):
|
def _find_canon_vhost(self, parser, vhost):
|
||||||
@@ -141,26 +276,29 @@ class Config:
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _process_root_options(self, parser, rootname):
|
|
||||||
rn = 'root-%s/' % (rootname)
|
|
||||||
lrn = len(rn)
|
|
||||||
for section in parser.sections():
|
|
||||||
if section[:lrn] == rn:
|
|
||||||
base_section = section[lrn:]
|
|
||||||
if base_section in self._sections:
|
|
||||||
if base_section == 'general':
|
|
||||||
raise IllegalOverrideSection('root', section)
|
|
||||||
self._process_section(parser, section, base_section)
|
|
||||||
elif _startswith(base_section, 'authz-'):
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise IllegalOverrideSection('root', section)
|
|
||||||
|
|
||||||
def overlay_root_options(self, rootname):
|
def overlay_root_options(self, rootname):
|
||||||
"Overly per-root options atop the existing option set."
|
"""Overlay per-root options for ROOTNAME atop the existing option
|
||||||
|
set. This is a destructive change to the configuration."""
|
||||||
|
|
||||||
|
did_overlay = 0
|
||||||
|
|
||||||
if not self.conf_path:
|
if not self.conf_path:
|
||||||
return
|
return
|
||||||
self._process_root_options(self.parser, rootname)
|
|
||||||
|
for section in self.parser.sections():
|
||||||
|
base_section = self._is_allowed_override('root', rootname, section)
|
||||||
|
if base_section:
|
||||||
|
# We can currently only deal with root overlays happening
|
||||||
|
# once, so check that we've not yet done any overlaying of
|
||||||
|
# per-root options.
|
||||||
|
assert(self.root_options_overlayed == 0)
|
||||||
|
self._process_section(self.parser, section, base_section)
|
||||||
|
did_overlay = 1
|
||||||
|
|
||||||
|
# If we actually did any overlaying, remember this fact so we
|
||||||
|
# don't do it again later.
|
||||||
|
if did_overlay:
|
||||||
|
self.root_options_overlayed = 1
|
||||||
|
|
||||||
def _get_parser_items(self, parser, section):
|
def _get_parser_items(self, parser, section):
|
||||||
"""Basically implement ConfigParser.items() for pre-Python-2.3 versions."""
|
"""Basically implement ConfigParser.items() for pre-Python-2.3 versions."""
|
||||||
@@ -171,23 +309,67 @@ class Config:
|
|||||||
for option in parser.options(section):
|
for option in parser.options(section):
|
||||||
d[option] = parser.get(section, option)
|
d[option] = parser.get(section, option)
|
||||||
return d.items()
|
return d.items()
|
||||||
|
|
||||||
def get_authorizer_params(self, authorizer, rootname=None):
|
|
||||||
if not self.conf_path:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
def get_authorizer_and_params_hack(self, rootname):
|
||||||
|
"""Return a 2-tuple containing the name and parameters of the
|
||||||
|
authorizer configured for use with ROOTNAME.
|
||||||
|
|
||||||
|
### FIXME: This whole thing is a hack caused by our not being able
|
||||||
|
### to non-destructively overlay root options when trying to do
|
||||||
|
### something like a root listing (which might need to get
|
||||||
|
### different authorizer bits for each and every root in the list).
|
||||||
|
### Until we have a good way to do that, we expose this function,
|
||||||
|
### which assumes that base and per-vhost configuration has been
|
||||||
|
### absorbed into this object and that per-root options have *not*
|
||||||
|
### been overlayed. See issue #371."""
|
||||||
|
|
||||||
|
# We assume that per-root options have *not* been overlayed.
|
||||||
|
assert(self.root_options_overlayed == 0)
|
||||||
|
|
||||||
|
if not self.conf_path:
|
||||||
|
return None, {}
|
||||||
|
|
||||||
|
# Figure out the authorizer by searching first for a per-root
|
||||||
|
# override, then falling back to the base/vhost configuration.
|
||||||
|
authorizer = None
|
||||||
|
root_options_section = 'root-%s/options' % (rootname)
|
||||||
|
if self.parser.has_section(root_options_section) \
|
||||||
|
and self.parser.has_option(root_options_section, 'authorizer'):
|
||||||
|
authorizer = self.parser.get(root_options_section, 'authorizer')
|
||||||
|
if not authorizer:
|
||||||
|
authorizer = self.options.authorizer
|
||||||
|
|
||||||
|
# No authorizer? Get outta here.
|
||||||
|
if not authorizer:
|
||||||
|
return None, {}
|
||||||
|
|
||||||
|
# Dig up the parameters for the authorizer, starting with the
|
||||||
|
# base/vhost items, then overlaying any root-specific ones we find.
|
||||||
params = {}
|
params = {}
|
||||||
authz_section = 'authz-%s' % (authorizer)
|
authz_section = 'authz-%s' % (authorizer)
|
||||||
|
if hasattr(self, authz_section):
|
||||||
|
sub_config = getattr(self, authz_section)
|
||||||
|
for attr in dir(sub_config):
|
||||||
|
params[attr] = getattr(sub_config, attr)
|
||||||
|
root_authz_section = 'root-%s/authz-%s' % (rootname, authorizer)
|
||||||
for section in self.parser.sections():
|
for section in self.parser.sections():
|
||||||
if section == authz_section:
|
if section == root_authz_section:
|
||||||
for key, value in self._get_parser_items(self.parser, section):
|
for key, value in self._get_parser_items(self.parser, section):
|
||||||
params[key] = value
|
params[key] = value
|
||||||
if rootname:
|
return authorizer, params
|
||||||
root_authz_section = 'root-%s/authz-%s' % (rootname, authorizer)
|
|
||||||
for section in self.parser.sections():
|
def get_authorizer_params(self, authorizer=None):
|
||||||
if section == root_authz_section:
|
"""Return a dictionary of parameter names and values which belong
|
||||||
for key, value in self._get_parser_items(self.parser, section):
|
to the configured authorizer (or AUTHORIZER, if provided)."""
|
||||||
params[key] = value
|
params = {}
|
||||||
|
if authorizer is None:
|
||||||
|
authorizer = self.options.authorizer
|
||||||
|
if authorizer:
|
||||||
|
authz_section = 'authz-%s' % (self.options.authorizer)
|
||||||
|
if hasattr(self, authz_section):
|
||||||
|
sub_config = getattr(self, authz_section)
|
||||||
|
for attr in dir(sub_config):
|
||||||
|
params[attr] = getattr(sub_config, attr)
|
||||||
return params
|
return params
|
||||||
|
|
||||||
def set_defaults(self):
|
def set_defaults(self):
|
||||||
@@ -238,19 +420,21 @@ class Config:
|
|||||||
self.options.template_dir = "templates"
|
self.options.template_dir = "templates"
|
||||||
self.options.docroot = None
|
self.options.docroot = None
|
||||||
self.options.show_subdir_lastmod = 0
|
self.options.show_subdir_lastmod = 0
|
||||||
|
self.options.show_roots_lastmod = 0
|
||||||
self.options.show_logs = 1
|
self.options.show_logs = 1
|
||||||
self.options.show_log_in_markup = 1
|
self.options.show_log_in_markup = 1
|
||||||
self.options.cross_copies = 0
|
self.options.cross_copies = 1
|
||||||
self.options.use_localtime = 0
|
self.options.use_localtime = 0
|
||||||
self.options.short_log_len = 80
|
self.options.short_log_len = 80
|
||||||
self.options.enable_syntax_coloration = 1
|
self.options.enable_syntax_coloration = 1
|
||||||
|
self.options.tabsize = 8
|
||||||
self.options.detect_encoding = 0
|
self.options.detect_encoding = 0
|
||||||
self.options.use_cvsgraph = 0
|
self.options.use_cvsgraph = 0
|
||||||
self.options.cvsgraph_conf = "cvsgraph.conf"
|
self.options.cvsgraph_conf = "cvsgraph.conf"
|
||||||
self.options.allowed_cvsgraph_useropts = []
|
|
||||||
self.options.use_re_search = 0
|
self.options.use_re_search = 0
|
||||||
self.options.dir_pagesize = 0
|
self.options.dir_pagesize = 0
|
||||||
self.options.log_pagesize = 0
|
self.options.log_pagesize = 0
|
||||||
|
self.options.log_pagesextra = 3
|
||||||
self.options.limit_changes = 100
|
self.options.limit_changes = 100
|
||||||
|
|
||||||
self.templates.diff = None
|
self.templates.diff = None
|
||||||
@@ -276,6 +460,8 @@ class Config:
|
|||||||
self.cvsdb.rss_row_limit = 100
|
self.cvsdb.rss_row_limit = 100
|
||||||
self.cvsdb.check_database_for_root = 0
|
self.cvsdb.check_database_for_root = 0
|
||||||
|
|
||||||
|
self.query.viewvc_base_url = None
|
||||||
|
|
||||||
def _startswith(somestr, substr):
|
def _startswith(somestr, substr):
|
||||||
return somestr[:len(substr)] == substr
|
return somestr[:len(substr)] == substr
|
||||||
|
|
||||||
|
79
lib/cvsdb.py
79
lib/cvsdb.py
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2009 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2011 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# 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
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -38,13 +38,12 @@ error = "cvsdb error"
|
|||||||
## complient database interface
|
## complient database interface
|
||||||
|
|
||||||
class CheckinDatabase:
|
class CheckinDatabase:
|
||||||
def __init__(self, host, port, user, passwd, database, row_limit):
|
def __init__(self, host, port, user, passwd, database):
|
||||||
self._host = host
|
self._host = host
|
||||||
self._port = port
|
self._port = port
|
||||||
self._user = user
|
self._user = user
|
||||||
self._passwd = passwd
|
self._passwd = passwd
|
||||||
self._database = database
|
self._database = database
|
||||||
self._row_limit = row_limit
|
|
||||||
self._version = None
|
self._version = None
|
||||||
|
|
||||||
## database lookup caches
|
## database lookup caches
|
||||||
@@ -169,6 +168,9 @@ class CheckinDatabase:
|
|||||||
|
|
||||||
return list
|
return list
|
||||||
|
|
||||||
|
def GetCommitsTable(self):
|
||||||
|
return self._version >= 1 and 'commits' or 'checkins'
|
||||||
|
|
||||||
def GetTableList(self):
|
def GetTableList(self):
|
||||||
sql = "SHOW TABLES"
|
sql = "SHOW TABLES"
|
||||||
cursor = self.db.cursor()
|
cursor = self.db.cursor()
|
||||||
@@ -309,8 +311,7 @@ class CheckinDatabase:
|
|||||||
minus_count = commit.GetMinusCount() or '0'
|
minus_count = commit.GetMinusCount() or '0'
|
||||||
description_id = self.GetDescriptionID(commit.GetDescription())
|
description_id = self.GetDescriptionID(commit.GetDescription())
|
||||||
|
|
||||||
commits_table = self._version >= 1 and 'commits' or 'checkins'
|
sql = "REPLACE INTO %s" % (self.GetCommitsTable())
|
||||||
sql = "REPLACE INTO %s" % (commits_table)
|
|
||||||
sql = sql + \
|
sql = sql + \
|
||||||
" (type,ci_when,whoid,repositoryid,dirid,fileid,revision,"\
|
" (type,ci_when,whoid,repositoryid,dirid,fileid,revision,"\
|
||||||
" stickytag,branchid,addedlines,removedlines,descid)"\
|
" stickytag,branchid,addedlines,removedlines,descid)"\
|
||||||
@@ -351,9 +352,17 @@ class CheckinDatabase:
|
|||||||
match = " LIKE "
|
match = " LIKE "
|
||||||
elif query_entry.match == "glob":
|
elif query_entry.match == "glob":
|
||||||
match = " REGEXP "
|
match = " REGEXP "
|
||||||
# use fnmatch to translate the glob into a regexp
|
# Use fnmatch to translate the glob into a regular
|
||||||
|
# expression. Sadly, we have to account for the fact
|
||||||
|
# that in Python 2.6, fnmatch.translate() started
|
||||||
|
# sticking '\Z(?ms)' at the end of the regular
|
||||||
|
# expression instead of just '$', and doesn't prepend
|
||||||
|
# the '^'.
|
||||||
data = fnmatch.translate(data)
|
data = fnmatch.translate(data)
|
||||||
if data[0] != '^': data = '^' + data
|
if data[0] != '^':
|
||||||
|
data = '^' + data
|
||||||
|
if data[-7:] == '\Z(?ms)':
|
||||||
|
data = data[:-7] + '$'
|
||||||
elif query_entry.match == "regex":
|
elif query_entry.match == "regex":
|
||||||
match = " REGEXP "
|
match = " REGEXP "
|
||||||
elif query_entry.match == "notregex":
|
elif query_entry.match == "notregex":
|
||||||
@@ -363,8 +372,8 @@ class CheckinDatabase:
|
|||||||
|
|
||||||
return "(%s)" % (string.join(sqlList, " OR "))
|
return "(%s)" % (string.join(sqlList, " OR "))
|
||||||
|
|
||||||
def CreateSQLQueryString(self, query):
|
def CreateSQLQueryString(self, query, detect_leftover=0):
|
||||||
commits_table = self._version >= 1 and 'commits' or 'checkins'
|
commits_table = self.GetCommitsTable()
|
||||||
tableList = [(commits_table, None)]
|
tableList = [(commits_table, None)]
|
||||||
condList = []
|
condList = []
|
||||||
|
|
||||||
@@ -444,13 +453,14 @@ class CheckinDatabase:
|
|||||||
conditions = string.join(joinConds + condList, " AND ")
|
conditions = string.join(joinConds + condList, " AND ")
|
||||||
conditions = conditions and "WHERE %s" % conditions
|
conditions = conditions and "WHERE %s" % conditions
|
||||||
|
|
||||||
## limit the number of rows requested or we could really slam
|
## apply the query's row limit, if any (so we avoid really
|
||||||
## a server with a large database
|
## slamming a server with a large database)
|
||||||
limit = ""
|
limit = ""
|
||||||
if query.limit:
|
if query.limit:
|
||||||
limit = "LIMIT %s" % (str(query.limit))
|
if detect_leftover:
|
||||||
elif self._row_limit:
|
limit = "LIMIT %s" % (str(query.limit + 1))
|
||||||
limit = "LIMIT %s" % (str(self._row_limit))
|
else:
|
||||||
|
limit = "LIMIT %s" % (str(query.limit))
|
||||||
|
|
||||||
sql = "SELECT %s.* FROM %s %s %s %s" \
|
sql = "SELECT %s.* FROM %s %s %s %s" \
|
||||||
% (commits_table, tables, conditions, order_by, limit)
|
% (commits_table, tables, conditions, order_by, limit)
|
||||||
@@ -458,14 +468,20 @@ class CheckinDatabase:
|
|||||||
return sql
|
return sql
|
||||||
|
|
||||||
def RunQuery(self, query):
|
def RunQuery(self, query):
|
||||||
sql = self.CreateSQLQueryString(query)
|
sql = self.CreateSQLQueryString(query, 1)
|
||||||
cursor = self.db.cursor()
|
cursor = self.db.cursor()
|
||||||
cursor.execute(sql)
|
cursor.execute(sql)
|
||||||
|
query.SetExecuted()
|
||||||
|
row_count = 0
|
||||||
|
|
||||||
while 1:
|
while 1:
|
||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
if not row:
|
if not row:
|
||||||
break
|
break
|
||||||
|
row_count = row_count + 1
|
||||||
|
if query.limit and (row_count > query.limit):
|
||||||
|
query.SetLimitReached()
|
||||||
|
break
|
||||||
|
|
||||||
(dbType, dbCI_When, dbAuthorID, dbRepositoryID, dbDirID,
|
(dbType, dbCI_When, dbAuthorID, dbRepositoryID, dbDirID,
|
||||||
dbFileID, dbRevision, dbStickyTag, dbBranchID, dbAddedLines,
|
dbFileID, dbRevision, dbStickyTag, dbBranchID, dbAddedLines,
|
||||||
@@ -504,13 +520,12 @@ class CheckinDatabase:
|
|||||||
if file_id == None:
|
if file_id == None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
commits_table = self._version >= 1 and 'commits' or 'checkins'
|
|
||||||
sql = "SELECT * FROM %s WHERE "\
|
sql = "SELECT * FROM %s WHERE "\
|
||||||
" repositoryid=%%s "\
|
" repositoryid=%%s "\
|
||||||
" AND dirid=%%s"\
|
" AND dirid=%%s"\
|
||||||
" AND fileid=%%s"\
|
" AND fileid=%%s"\
|
||||||
" AND revision=%%s"\
|
" AND revision=%%s"\
|
||||||
% (commits_table)
|
% (self.GetCommitsTable())
|
||||||
sql_args = (repository_id, dir_id, file_id, commit.GetRevision())
|
sql_args = (repository_id, dir_id, file_id, commit.GetRevision())
|
||||||
|
|
||||||
cursor = self.db.cursor()
|
cursor = self.db.cursor()
|
||||||
@@ -527,10 +542,9 @@ class CheckinDatabase:
|
|||||||
def sql_delete(self, table, key, value, keep_fkey = None):
|
def sql_delete(self, table, key, value, keep_fkey = None):
|
||||||
sql = "DELETE FROM %s WHERE %s=%%s" % (table, key)
|
sql = "DELETE FROM %s WHERE %s=%%s" % (table, key)
|
||||||
sql_args = (value, )
|
sql_args = (value, )
|
||||||
commits_table = self._version >= 1 and 'commits' or 'checkins'
|
|
||||||
if keep_fkey:
|
if keep_fkey:
|
||||||
sql += " AND %s NOT IN (SELECT %s FROM %s WHERE %s = %%s)" \
|
sql += " AND %s NOT IN (SELECT %s FROM %s WHERE %s = %%s)" \
|
||||||
% (key, keep_fkey, commits_table, keep_fkey)
|
% (key, keep_fkey, self.GetCommitsTable(), keep_fkey)
|
||||||
sql_args = (value, value)
|
sql_args = (value, value)
|
||||||
cursor = self.db.cursor()
|
cursor = self.db.cursor()
|
||||||
cursor.execute(sql, sql_args)
|
cursor.execute(sql, sql_args)
|
||||||
@@ -769,8 +783,9 @@ class QueryEntry:
|
|||||||
self.data = data
|
self.data = data
|
||||||
self.match = match
|
self.match = match
|
||||||
|
|
||||||
## CheckinDatabaseQueryData is a object which contains the search parameters
|
## CheckinDatabaseQuery is an object which contains the search
|
||||||
## for a query to the CheckinDatabase
|
## parameters for a query to the Checkin Database and -- after the
|
||||||
|
## query is executed -- the data returned by the query.
|
||||||
class CheckinDatabaseQuery:
|
class CheckinDatabaseQuery:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
## sorting
|
## sorting
|
||||||
@@ -790,7 +805,8 @@ class CheckinDatabaseQuery:
|
|||||||
|
|
||||||
## limit on number of rows to return
|
## limit on number of rows to return
|
||||||
self.limit = None
|
self.limit = None
|
||||||
|
self.limit_reached = 0
|
||||||
|
|
||||||
## list of commits -- filled in by CVS query
|
## list of commits -- filled in by CVS query
|
||||||
self.commit_list = []
|
self.commit_list = []
|
||||||
|
|
||||||
@@ -798,6 +814,9 @@ class CheckinDatabaseQuery:
|
|||||||
## are added
|
## are added
|
||||||
self.commit_cb = None
|
self.commit_cb = None
|
||||||
|
|
||||||
|
## has this query been run?
|
||||||
|
self.executed = 0
|
||||||
|
|
||||||
def SetRepository(self, repository, match = "exact"):
|
def SetRepository(self, repository, match = "exact"):
|
||||||
self.repository_list.append(QueryEntry(repository, match))
|
self.repository_list.append(QueryEntry(repository, match))
|
||||||
|
|
||||||
@@ -843,6 +862,20 @@ class CheckinDatabaseQuery:
|
|||||||
def AddCommit(self, commit):
|
def AddCommit(self, commit):
|
||||||
self.commit_list.append(commit)
|
self.commit_list.append(commit)
|
||||||
|
|
||||||
|
def SetExecuted(self):
|
||||||
|
self.executed = 1
|
||||||
|
|
||||||
|
def SetLimitReached(self):
|
||||||
|
self.limit_reached = 1
|
||||||
|
|
||||||
|
def GetLimitReached(self):
|
||||||
|
assert self.executed
|
||||||
|
return self.limit_reached
|
||||||
|
|
||||||
|
def GetCommitList(self):
|
||||||
|
assert self.executed
|
||||||
|
return self.commit_list
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
## entrypoints
|
## entrypoints
|
||||||
@@ -861,7 +894,7 @@ def ConnectDatabase(cfg, readonly=0):
|
|||||||
user = cfg.cvsdb.user
|
user = cfg.cvsdb.user
|
||||||
passwd = cfg.cvsdb.passwd
|
passwd = cfg.cvsdb.passwd
|
||||||
db = CheckinDatabase(cfg.cvsdb.host, cfg.cvsdb.port, user, passwd,
|
db = CheckinDatabase(cfg.cvsdb.host, cfg.cvsdb.port, user, passwd,
|
||||||
cfg.cvsdb.database_name, cfg.cvsdb.row_limit)
|
cfg.cvsdb.database_name)
|
||||||
db.Connect()
|
db.Connect()
|
||||||
return db
|
return db
|
||||||
|
|
||||||
|
77
lib/ezt.py
77
lib/ezt.py
@@ -347,7 +347,7 @@ class Template:
|
|||||||
for_names = [ ]
|
for_names = [ ]
|
||||||
|
|
||||||
if base_format:
|
if base_format:
|
||||||
program.append((self._cmd_format, _printers[base_format]))
|
program.append((self._cmd_format, _formatters[base_format]))
|
||||||
|
|
||||||
for i in range(len(parts)):
|
for i in range(len(parts)):
|
||||||
piece = parts[i]
|
piece = parts[i]
|
||||||
@@ -405,13 +405,13 @@ class Template:
|
|||||||
elif cmd == 'format':
|
elif cmd == 'format':
|
||||||
if args[1][0]:
|
if args[1][0]:
|
||||||
# argument is a variable reference
|
# argument is a variable reference
|
||||||
printer = args[1]
|
formatter = args[1]
|
||||||
else:
|
else:
|
||||||
# argument is a string constant referring to built-in printer
|
# argument is a string constant referring to built-in formatter
|
||||||
printer = _printers.get(args[1][1])
|
formatter = _formatters.get(args[1][1])
|
||||||
if not printer:
|
if not formatter:
|
||||||
raise UnknownFormatConstantError(str(args[1:]))
|
raise UnknownFormatConstantError(str(args[1:]))
|
||||||
program.append((self._cmd_format, printer))
|
program.append((self._cmd_format, formatter))
|
||||||
|
|
||||||
# remember the cmd, current pos, args, and a section placeholder
|
# remember the cmd, current pos, args, and a section placeholder
|
||||||
stack.append([cmd, len(program), args[1:], None])
|
stack.append([cmd, len(program), args[1:], None])
|
||||||
@@ -465,13 +465,13 @@ class Template:
|
|||||||
except TypeError:
|
except TypeError:
|
||||||
raise Exception("Unprintable value type for '%s'" % (str(valrefs[0][0])))
|
raise Exception("Unprintable value type for '%s'" % (str(valrefs[0][0])))
|
||||||
|
|
||||||
def _cmd_format(self, printer, ctx):
|
def _cmd_format(self, formatter, ctx):
|
||||||
if type(printer) is TupleType:
|
if type(formatter) is TupleType:
|
||||||
printer = _get_value(printer, ctx)
|
formatter = _get_value(formatter, ctx)
|
||||||
ctx.printers.append(printer)
|
ctx.formatters.append(formatter)
|
||||||
|
|
||||||
def _cmd_end_format(self, valref, ctx):
|
def _cmd_end_format(self, valref, ctx):
|
||||||
ctx.printers.pop()
|
ctx.formatters.pop()
|
||||||
|
|
||||||
def _cmd_include(self, (valref, reader), ctx):
|
def _cmd_include(self, (valref, reader), ctx):
|
||||||
fname = _get_value(valref, ctx)
|
fname = _get_value(valref, ctx)
|
||||||
@@ -637,14 +637,23 @@ def _get_value((refname, start, rest), ctx):
|
|||||||
# string or a sequence
|
# string or a sequence
|
||||||
return ob
|
return ob
|
||||||
|
|
||||||
|
def _print_formatted(formatters, ctx, chunk):
|
||||||
|
# print chunk to ctx.fp after running it sequentially through formatters
|
||||||
|
for formatter in formatters:
|
||||||
|
chunk = formatter(chunk)
|
||||||
|
ctx.fp.write(chunk)
|
||||||
|
|
||||||
def _write_value(value, args, ctx):
|
def _write_value(value, args, ctx):
|
||||||
# value is a callback function, generates its own output
|
# value is a callback function, generates its own output
|
||||||
if callable(value):
|
if callable(value):
|
||||||
apply(value, [ctx] + list(args))
|
apply(value, [ctx] + list(args))
|
||||||
return
|
return
|
||||||
|
|
||||||
# pop printer in case it recursively calls _write_value
|
# squirrel away formatters in case one of them recursively calls
|
||||||
printer = ctx.printers.pop()
|
# _write_value() -- we'll use them (in reverse order) to format our
|
||||||
|
# output.
|
||||||
|
formatters = ctx.formatters[:]
|
||||||
|
formatters.reverse()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# if the value has a 'read' attribute, then it is a stream: copy it
|
# if the value has a 'read' attribute, then it is a stream: copy it
|
||||||
@@ -653,7 +662,7 @@ def _write_value(value, args, ctx):
|
|||||||
chunk = value.read(16384)
|
chunk = value.read(16384)
|
||||||
if not chunk:
|
if not chunk:
|
||||||
break
|
break
|
||||||
printer(ctx, chunk)
|
_print_formatted(formatters, ctx, chunk)
|
||||||
|
|
||||||
# value is a substitution pattern
|
# value is a substitution pattern
|
||||||
elif args:
|
elif args:
|
||||||
@@ -666,14 +675,16 @@ def _write_value(value, args, ctx):
|
|||||||
piece = args[idx]
|
piece = args[idx]
|
||||||
else:
|
else:
|
||||||
piece = '<undef>'
|
piece = '<undef>'
|
||||||
printer(ctx, piece)
|
_print_formatted(formatters, ctx, piece)
|
||||||
|
|
||||||
# plain old value, write to output
|
# plain old value, write to output
|
||||||
else:
|
else:
|
||||||
printer(ctx, value)
|
_print_formatted(formatters, ctx, value)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
ctx.printers.append(printer)
|
# restore our formatters
|
||||||
|
formatters.reverse()
|
||||||
|
ctx.formatters = formatters
|
||||||
|
|
||||||
|
|
||||||
class TemplateData:
|
class TemplateData:
|
||||||
@@ -715,7 +726,7 @@ class Context:
|
|||||||
"""A container for the execution context"""
|
"""A container for the execution context"""
|
||||||
def __init__(self, fp):
|
def __init__(self, fp):
|
||||||
self.fp = fp
|
self.fp = fp
|
||||||
self.printers = []
|
self.formatters = []
|
||||||
def write(self, value, args=()):
|
def write(self, value, args=()):
|
||||||
_write_value(value, args, self)
|
_write_value(value, args, self)
|
||||||
|
|
||||||
@@ -828,20 +839,26 @@ class BaseUnavailableError(EZTException):
|
|||||||
class UnknownFormatConstantError(EZTException):
|
class UnknownFormatConstantError(EZTException):
|
||||||
"""The format specifier is an unknown value."""
|
"""The format specifier is an unknown value."""
|
||||||
|
|
||||||
def _raw_printer(ctx, s):
|
def _raw_formatter(s):
|
||||||
ctx.fp.write(s)
|
return s
|
||||||
|
|
||||||
def _html_printer(ctx, s):
|
|
||||||
ctx.fp.write(cgi.escape(s))
|
|
||||||
|
|
||||||
def _uri_printer(ctx, s):
|
def _html_formatter(s):
|
||||||
ctx.fp.write(urllib.quote(s))
|
return cgi.escape(s)
|
||||||
|
|
||||||
_printers = {
|
def _xml_formatter(s):
|
||||||
FORMAT_RAW : _raw_printer,
|
s = s.replace('&', '&')
|
||||||
FORMAT_HTML : _html_printer,
|
s = s.replace('<', '<')
|
||||||
FORMAT_XML : _html_printer,
|
s = s.replace('>', '>')
|
||||||
FORMAT_URI : _uri_printer,
|
return s
|
||||||
|
|
||||||
|
def _uri_formatter(s):
|
||||||
|
return urllib.quote(s)
|
||||||
|
|
||||||
|
_formatters = {
|
||||||
|
FORMAT_RAW : _raw_formatter,
|
||||||
|
FORMAT_HTML : _html_formatter,
|
||||||
|
FORMAT_XML : _xml_formatter,
|
||||||
|
FORMAT_URI : _uri_formatter,
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- standard test environment ---
|
# --- standard test environment ---
|
||||||
|
20
lib/idiff.py
20
lib/idiff.py
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# 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
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -20,7 +20,7 @@ import difflib
|
|||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
import ezt
|
import ezt
|
||||||
import cgi
|
import sapi
|
||||||
|
|
||||||
def sidebyside(fromlines, tolines, context):
|
def sidebyside(fromlines, tolines, context):
|
||||||
"""Generate side by side diff"""
|
"""Generate side by side diff"""
|
||||||
@@ -49,18 +49,18 @@ def _mdiff_split(flag, (line_number, text)):
|
|||||||
while True:
|
while True:
|
||||||
m = _re_mdiff.search(text, pos)
|
m = _re_mdiff.search(text, pos)
|
||||||
if not m:
|
if not m:
|
||||||
segments.append(_item(text=cgi.escape(text[pos:]), type=None))
|
segments.append(_item(text=sapi.escape(text[pos:]), type=None))
|
||||||
break
|
break
|
||||||
|
|
||||||
if m.start() > pos:
|
if m.start() > pos:
|
||||||
segments.append(_item(text=cgi.escape(text[pos:m.start()]), type=None))
|
segments.append(_item(text=sapi.escape(text[pos:m.start()]), type=None))
|
||||||
|
|
||||||
if m.group(1) == "+":
|
if m.group(1) == "+":
|
||||||
segments.append(_item(text=cgi.escape(m.group(2)), type="add"))
|
segments.append(_item(text=sapi.escape(m.group(2)), type="add"))
|
||||||
elif m.group(1) == "-":
|
elif m.group(1) == "-":
|
||||||
segments.append(_item(text=cgi.escape(m.group(2)), type="remove"))
|
segments.append(_item(text=sapi.escape(m.group(2)), type="remove"))
|
||||||
elif m.group(1) == "^":
|
elif m.group(1) == "^":
|
||||||
segments.append(_item(text=cgi.escape(m.group(2)), type="change"))
|
segments.append(_item(text=sapi.escape(m.group(2)), type="change"))
|
||||||
|
|
||||||
pos = m.end()
|
pos = m.end()
|
||||||
|
|
||||||
@@ -166,12 +166,12 @@ def _differ_split(row, guide):
|
|||||||
|
|
||||||
for m in _re_differ.finditer(guide, pos):
|
for m in _re_differ.finditer(guide, pos):
|
||||||
if m.start() > pos:
|
if m.start() > pos:
|
||||||
segments.append(_item(text=cgi.escape(line[pos:m.start()]), type=None))
|
segments.append(_item(text=sapi.escape(line[pos:m.start()]), type=None))
|
||||||
segments.append(_item(text=cgi.escape(line[m.start():m.end()]),
|
segments.append(_item(text=sapi.escape(line[m.start():m.end()]),
|
||||||
type="change"))
|
type="change"))
|
||||||
pos = m.end()
|
pos = m.end()
|
||||||
|
|
||||||
segments.append(_item(text=cgi.escape(line[pos:]), type=None))
|
segments.append(_item(text=sapi.escape(line[pos:]), type=None))
|
||||||
|
|
||||||
return _item(gap=ezt.boolean(gap), type=type, segments=segments,
|
return _item(gap=ezt.boolean(gap), type=type, segments=segments,
|
||||||
left_number=left_number, right_number=right_number)
|
left_number=left_number, right_number=right_number)
|
||||||
|
85
lib/query.py
85
lib/query.py
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2009 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# 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
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -217,8 +217,9 @@ def decode_command(cmd):
|
|||||||
else:
|
else:
|
||||||
return "exact"
|
return "exact"
|
||||||
|
|
||||||
def form_to_cvsdb_query(form_data):
|
def form_to_cvsdb_query(cfg, form_data):
|
||||||
query = cvsdb.CreateCheckinQuery()
|
query = cvsdb.CreateCheckinQuery()
|
||||||
|
query.SetLimit(cfg.cvsdb.row_limit)
|
||||||
|
|
||||||
if form_data.repository:
|
if form_data.repository:
|
||||||
for cmd, str in listparse_string(form_data.repository):
|
for cmd, str in listparse_string(form_data.repository):
|
||||||
@@ -275,8 +276,30 @@ def prev_rev(rev):
|
|||||||
return string.join(r, '.')
|
return string.join(r, '.')
|
||||||
|
|
||||||
def is_forbidden(cfg, cvsroot_name, module):
|
def is_forbidden(cfg, cvsroot_name, module):
|
||||||
auth_params = cfg.get_authorizer_params('forbidden', cvsroot_name)
|
'''Return 1 if MODULE in CVSROOT_NAME is forbidden; return 0 otherwise.'''
|
||||||
forbidden = auth_params.get('forbidden', '')
|
|
||||||
|
# CVSROOT_NAME might be None here if the data comes from an
|
||||||
|
# unconfigured root. This interfaces doesn't care that the root
|
||||||
|
# isn't configured, but if that's the case, it will consult only
|
||||||
|
# the base and per-vhost configuration for authorizer and
|
||||||
|
# authorizer parameters.
|
||||||
|
if cvsroot_name:
|
||||||
|
authorizer, params = cfg.get_authorizer_and_params_hack(cvsroot_name)
|
||||||
|
else:
|
||||||
|
authorizer = cfg.options.authorizer
|
||||||
|
params = cfg.get_authorizer_params()
|
||||||
|
|
||||||
|
# If CVSROOT_NAME isn't configured to use an authorizer, nothing
|
||||||
|
# is forbidden. If it's configured to use something other than
|
||||||
|
# the 'forbidden' authorizer, complain. Otherwise, check for
|
||||||
|
# forbiddenness per the PARAMS as expected.
|
||||||
|
if not authorizer:
|
||||||
|
return 0
|
||||||
|
if authorizer != 'forbidden':
|
||||||
|
raise Exception("The 'forbidden' authorizer is the only one supported "
|
||||||
|
"by this interface. The '%s' root is configured to "
|
||||||
|
"use a different one." % (cvsroot_name))
|
||||||
|
forbidden = params.get('forbidden', '')
|
||||||
forbidden = map(string.strip, filter(None, string.split(forbidden, ',')))
|
forbidden = map(string.strip, filter(None, string.split(forbidden, ',')))
|
||||||
default = 0
|
default = 0
|
||||||
for pat in forbidden:
|
for pat in forbidden:
|
||||||
@@ -290,11 +313,7 @@ def is_forbidden(cfg, cvsroot_name, module):
|
|||||||
|
|
||||||
def build_commit(server, cfg, desc, files, cvsroots, viewvc_link):
|
def build_commit(server, cfg, desc, files, cvsroots, viewvc_link):
|
||||||
ob = _item(num_files=len(files), files=[])
|
ob = _item(num_files=len(files), files=[])
|
||||||
|
ob.log = desc and string.replace(server.escape(desc), '\n', '<br />') or ''
|
||||||
if desc:
|
|
||||||
ob.log = string.replace(server.escape(desc), '\n', '<br />')
|
|
||||||
else:
|
|
||||||
ob.log = ' '
|
|
||||||
|
|
||||||
for commit in files:
|
for commit in files:
|
||||||
repository = commit.GetRepository()
|
repository = commit.GetRepository()
|
||||||
@@ -328,9 +347,10 @@ def build_commit(server, cfg, desc, files, cvsroots, viewvc_link):
|
|||||||
except:
|
except:
|
||||||
raise Exception, str([directory, commit.GetFile()])
|
raise Exception, str([directory, commit.GetFile()])
|
||||||
|
|
||||||
## if we couldn't find the cvsroot path configured in the
|
## If we couldn't find the cvsroot path configured in the
|
||||||
## viewvc.conf file, then don't make the link
|
## viewvc.conf file, or we don't have a VIEWVC_LINK, then
|
||||||
if cvsroot_name:
|
## don't make the link.
|
||||||
|
if cvsroot_name and viewvc_link:
|
||||||
flink = '[%s] <a href="%s/%s?root=%s">%s</a>' % (
|
flink = '[%s] <a href="%s/%s?root=%s">%s</a>' % (
|
||||||
cvsroot_name, viewvc_link, urllib.quote(file),
|
cvsroot_name, viewvc_link, urllib.quote(file),
|
||||||
cvsroot_name, file)
|
cvsroot_name, file)
|
||||||
@@ -358,23 +378,27 @@ def build_commit(server, cfg, desc, files, cvsroots, viewvc_link):
|
|||||||
return ob
|
return ob
|
||||||
|
|
||||||
def run_query(server, cfg, form_data, viewvc_link):
|
def run_query(server, cfg, form_data, viewvc_link):
|
||||||
query = form_to_cvsdb_query(form_data)
|
query = form_to_cvsdb_query(cfg, form_data)
|
||||||
db = cvsdb.ConnectDatabaseReadOnly(cfg)
|
db = cvsdb.ConnectDatabaseReadOnly(cfg)
|
||||||
db.RunQuery(query)
|
db.RunQuery(query)
|
||||||
|
|
||||||
if not query.commit_list:
|
commit_list = query.GetCommitList()
|
||||||
return [ ]
|
if not commit_list:
|
||||||
|
return [ ], 0
|
||||||
|
|
||||||
|
row_limit_reached = query.GetLimitReached()
|
||||||
|
|
||||||
commits = [ ]
|
commits = [ ]
|
||||||
files = [ ]
|
files = [ ]
|
||||||
|
|
||||||
cvsroots = {}
|
cvsroots = {}
|
||||||
|
viewvc.expand_root_parents(cfg)
|
||||||
rootitems = cfg.general.svn_roots.items() + cfg.general.cvs_roots.items()
|
rootitems = cfg.general.svn_roots.items() + cfg.general.cvs_roots.items()
|
||||||
for key, value in rootitems:
|
for key, value in rootitems:
|
||||||
cvsroots[cvsdb.CleanRepository(value)] = key
|
cvsroots[cvsdb.CleanRepository(value)] = key
|
||||||
|
|
||||||
current_desc = query.commit_list[0].GetDescription()
|
current_desc = commit_list[0].GetDescription()
|
||||||
for commit in query.commit_list:
|
for commit in commit_list:
|
||||||
desc = commit.GetDescription()
|
desc = commit.GetDescription()
|
||||||
if current_desc == desc:
|
if current_desc == desc:
|
||||||
files.append(commit)
|
files.append(commit)
|
||||||
@@ -397,7 +421,7 @@ def run_query(server, cfg, form_data, viewvc_link):
|
|||||||
return len(commit.files) > 0
|
return len(commit.files) > 0
|
||||||
commits = filter(_only_with_files, commits)
|
commits = filter(_only_with_files, commits)
|
||||||
|
|
||||||
return commits
|
return commits, row_limit_reached
|
||||||
|
|
||||||
def main(server, cfg, viewvc_link):
|
def main(server, cfg, viewvc_link):
|
||||||
try:
|
try:
|
||||||
@@ -406,29 +430,32 @@ def main(server, cfg, viewvc_link):
|
|||||||
form_data = FormData(form)
|
form_data = FormData(form)
|
||||||
|
|
||||||
if form_data.valid:
|
if form_data.valid:
|
||||||
commits = run_query(server, cfg, form_data, viewvc_link)
|
commits, row_limit_reached = run_query(server, cfg,
|
||||||
|
form_data, viewvc_link)
|
||||||
query = None
|
query = None
|
||||||
else:
|
else:
|
||||||
commits = [ ]
|
commits = [ ]
|
||||||
|
row_limit_reached = 0
|
||||||
query = 'skipped'
|
query = 'skipped'
|
||||||
|
|
||||||
|
docroot = cfg.options.docroot
|
||||||
|
if docroot is None and viewvc_link:
|
||||||
|
docroot = viewvc_link + '/' + viewvc.docroot_magic_path
|
||||||
|
|
||||||
data = ezt.TemplateData({
|
data = ezt.TemplateData({
|
||||||
'cfg' : cfg,
|
'cfg' : cfg,
|
||||||
'address' : cfg.general.address,
|
'address' : cfg.general.address,
|
||||||
'vsn' : viewvc.__version__,
|
'vsn' : viewvc.__version__,
|
||||||
'repository' : server.escape(form_data.repository, 1),
|
'repository' : server.escape(form_data.repository),
|
||||||
'branch' : server.escape(form_data.branch, 1),
|
'branch' : server.escape(form_data.branch),
|
||||||
'directory' : server.escape(form_data.directory, 1),
|
'directory' : server.escape(form_data.directory),
|
||||||
'file' : server.escape(form_data.file, 1),
|
'file' : server.escape(form_data.file),
|
||||||
'who' : server.escape(form_data.who, 1),
|
'who' : server.escape(form_data.who),
|
||||||
'docroot' : cfg.options.docroot is None \
|
'docroot' : docroot,
|
||||||
and viewvc_link + '/' + viewvc.docroot_magic_path \
|
|
||||||
or cfg.options.docroot,
|
|
||||||
|
|
||||||
'sortby' : form_data.sortby,
|
'sortby' : form_data.sortby,
|
||||||
'date' : form_data.date,
|
'date' : form_data.date,
|
||||||
|
|
||||||
'query' : query,
|
'query' : query,
|
||||||
|
'row_limit_reached' : ezt.boolean(row_limit_reached),
|
||||||
'commits' : commits,
|
'commits' : commits,
|
||||||
'num_commits' : len(commits),
|
'num_commits' : len(commits),
|
||||||
'rss_href' : None,
|
'rss_href' : None,
|
||||||
|
97
lib/sapi.py
97
lib/sapi.py
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# 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
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -20,13 +20,27 @@ import string
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
|
import cgi
|
||||||
|
|
||||||
|
|
||||||
# global server object. It will be either a CgiServer or a proxy to
|
# global server object. It will be either a CgiServer, a WsgiServer,
|
||||||
# an AspServer or ModPythonServer object.
|
# or a proxy to an AspServer or ModPythonServer object.
|
||||||
server = None
|
server = None
|
||||||
|
|
||||||
|
|
||||||
|
# Simple HTML string escaping. Note that we always escape the
|
||||||
|
# double-quote character -- ViewVC shouldn't ever need to preserve
|
||||||
|
# that character as-is, and sometimes needs to embed escaped values
|
||||||
|
# into HTML attributes.
|
||||||
|
def escape(s):
|
||||||
|
s = str(s)
|
||||||
|
s = string.replace(s, '&', '&')
|
||||||
|
s = string.replace(s, '>', '>')
|
||||||
|
s = string.replace(s, '<', '<')
|
||||||
|
s = string.replace(s, '"', """)
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
class Server:
|
class Server:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.pageGlobals = {}
|
self.pageGlobals = {}
|
||||||
@@ -34,6 +48,9 @@ class Server:
|
|||||||
def self(self):
|
def self(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def escape(self, s):
|
||||||
|
return escape(s)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -129,9 +146,6 @@ class CgiServer(Server):
|
|||||||
global server
|
global server
|
||||||
server = self
|
server = self
|
||||||
|
|
||||||
global cgi
|
|
||||||
import cgi
|
|
||||||
|
|
||||||
def addheader(self, name, value):
|
def addheader(self, name, value):
|
||||||
self.headers.append((name, value))
|
self.headers.append((name, value))
|
||||||
|
|
||||||
@@ -160,9 +174,6 @@ class CgiServer(Server):
|
|||||||
self.header(status='301 Moved')
|
self.header(status='301 Moved')
|
||||||
sys.stdout.write('This document is located <a href="%s">here</a>.\n' % url)
|
sys.stdout.write('This document is located <a href="%s">here</a>.\n' % url)
|
||||||
|
|
||||||
def escape(self, s, quote = None):
|
|
||||||
return cgi.escape(s, quote)
|
|
||||||
|
|
||||||
def getenv(self, name, value=None):
|
def getenv(self, name, value=None):
|
||||||
ret = os.environ.get(name, value)
|
ret = os.environ.get(name, value)
|
||||||
if self.iis and name == 'PATH_INFO' and ret:
|
if self.iis and name == 'PATH_INFO' and ret:
|
||||||
@@ -175,7 +186,7 @@ class CgiServer(Server):
|
|||||||
def FieldStorage(fp=None, headers=None, outerboundary="",
|
def FieldStorage(fp=None, headers=None, outerboundary="",
|
||||||
environ=os.environ, keep_blank_values=0, strict_parsing=0):
|
environ=os.environ, keep_blank_values=0, strict_parsing=0):
|
||||||
return cgi.FieldStorage(fp, headers, outerboundary, environ,
|
return cgi.FieldStorage(fp, headers, outerboundary, environ,
|
||||||
keep_blank_values, strict_parsing)
|
keep_blank_values, strict_parsing)
|
||||||
|
|
||||||
def write(self, s):
|
def write(self, s):
|
||||||
sys.stdout.write(s)
|
sys.stdout.write(s)
|
||||||
@@ -187,6 +198,63 @@ class CgiServer(Server):
|
|||||||
return sys.stdout
|
return sys.stdout
|
||||||
|
|
||||||
|
|
||||||
|
class WsgiServer(Server):
|
||||||
|
def __init__(self, environ, start_response):
|
||||||
|
Server.__init__(self)
|
||||||
|
|
||||||
|
self._environ = environ
|
||||||
|
self._start_response = start_response;
|
||||||
|
self._headers = []
|
||||||
|
self._wsgi_write = None
|
||||||
|
self.headerSent = False
|
||||||
|
|
||||||
|
global server
|
||||||
|
server = self
|
||||||
|
|
||||||
|
global cgi
|
||||||
|
import cgi
|
||||||
|
|
||||||
|
def addheader(self, name, value):
|
||||||
|
self._headers.append((name, value))
|
||||||
|
|
||||||
|
def header(self, content_type='text/html; charset=UTF-8', status=None):
|
||||||
|
if not status:
|
||||||
|
status = "200 OK"
|
||||||
|
if not self.headerSent:
|
||||||
|
self.headerSent = True
|
||||||
|
self._headers.insert(0, ("Content-Type", content_type),)
|
||||||
|
self._wsgi_write = self._start_response("%s" % status, self._headers)
|
||||||
|
|
||||||
|
def redirect(self, url):
|
||||||
|
"""Redirect client to url. This discards any data that has been queued
|
||||||
|
to be sent to the user. But there should never by any anyway.
|
||||||
|
"""
|
||||||
|
self.addheader('Location', url)
|
||||||
|
self.header(status='301 Moved')
|
||||||
|
self._wsgi_write('This document is located <a href="%s">here</a>.' % url)
|
||||||
|
|
||||||
|
def getenv(self, name, value=None):
|
||||||
|
return self._environ.get(name, value)
|
||||||
|
|
||||||
|
def params(self):
|
||||||
|
return cgi.parse(environ=self._environ, fp=self._environ["wsgi.input"])
|
||||||
|
|
||||||
|
def FieldStorage(self, fp=None, headers=None, outerboundary="",
|
||||||
|
environ=os.environ, keep_blank_values=0, strict_parsing=0):
|
||||||
|
return cgi.FieldStorage(self._environ["wsgi.input"], headers,
|
||||||
|
outerboundary, self._environ, keep_blank_values,
|
||||||
|
strict_parsing)
|
||||||
|
|
||||||
|
def write(self, s):
|
||||||
|
self._wsgi_write(s)
|
||||||
|
|
||||||
|
def flush(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def file(self):
|
||||||
|
return File(self)
|
||||||
|
|
||||||
|
|
||||||
class AspServer(ThreadedServer):
|
class AspServer(ThreadedServer):
|
||||||
def __init__(self, Server, Request, Response, Application):
|
def __init__(self, Server, Request, Response, Application):
|
||||||
ThreadedServer.__init__(self)
|
ThreadedServer.__init__(self)
|
||||||
@@ -219,9 +287,6 @@ class AspServer(ThreadedServer):
|
|||||||
def redirect(self, url):
|
def redirect(self, url):
|
||||||
self.response.Redirect(url)
|
self.response.Redirect(url)
|
||||||
|
|
||||||
def escape(self, s, quote = None):
|
|
||||||
return self.server.HTMLEncode(str(s))
|
|
||||||
|
|
||||||
def getenv(self, name, value = None):
|
def getenv(self, name, value = None):
|
||||||
ret = self.request.ServerVariables(name)()
|
ret = self.request.ServerVariables(name)()
|
||||||
if not type(ret) is types.UnicodeType:
|
if not type(ret) is types.UnicodeType:
|
||||||
@@ -283,9 +348,6 @@ class ModPythonServer(ThreadedServer):
|
|||||||
self.request = request
|
self.request = request
|
||||||
self.headerSent = 0
|
self.headerSent = 0
|
||||||
|
|
||||||
global cgi
|
|
||||||
import cgi
|
|
||||||
|
|
||||||
def addheader(self, name, value):
|
def addheader(self, name, value):
|
||||||
self.request.headers_out.add(name, value)
|
self.request.headers_out.add(name, value)
|
||||||
|
|
||||||
@@ -308,9 +370,6 @@ class ModPythonServer(ThreadedServer):
|
|||||||
self.request.write("You are being redirected to <a href=\"%s\">%s</a>"
|
self.request.write("You are being redirected to <a href=\"%s\">%s</a>"
|
||||||
% (url, url))
|
% (url, url))
|
||||||
|
|
||||||
def escape(self, s, quote = None):
|
|
||||||
return cgi.escape(s, quote)
|
|
||||||
|
|
||||||
def getenv(self, name, value = None):
|
def getenv(self, name, value = None):
|
||||||
try:
|
try:
|
||||||
return self.request.subprocess_env[name]
|
return self.request.subprocess_env[name]
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 2006-2008 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 2006-2010 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# 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
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -29,7 +29,15 @@ class GenericViewVCAuthorizer:
|
|||||||
def check_root_access(self, rootname):
|
def check_root_access(self, rootname):
|
||||||
"""Return 1 iff the associated username is permitted to read ROOTNAME."""
|
"""Return 1 iff the associated username is permitted to read ROOTNAME."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def check_universal_access(self, rootname):
|
||||||
|
"""Return 1 if the associated username is permitted to read every
|
||||||
|
path in the repository at every revision, 0 if the associated
|
||||||
|
username is prohibited from reading any path in the repository, or
|
||||||
|
None if no such determination can be made (perhaps because the
|
||||||
|
cost of making it is too great)."""
|
||||||
|
pass
|
||||||
|
|
||||||
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
|
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
|
||||||
"""Return 1 iff the associated username is permitted to read
|
"""Return 1 iff the associated username is permitted to read
|
||||||
revision REV of the path PATH_PARTS (of type PATHTYPE) in
|
revision REV of the path PATH_PARTS (of type PATHTYPE) in
|
||||||
@@ -44,6 +52,9 @@ class ViewVCAuthorizer(GenericViewVCAuthorizer):
|
|||||||
"""The uber-permissive authorizer."""
|
"""The uber-permissive authorizer."""
|
||||||
def check_root_access(self, rootname):
|
def check_root_access(self, rootname):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
def check_universal_access(self, rootname):
|
||||||
|
return 1
|
||||||
|
|
||||||
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
|
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
|
||||||
return 1
|
return 1
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 2006-2008 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 2006-2010 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# 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
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -23,7 +23,14 @@ class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
|
|||||||
|
|
||||||
def check_root_access(self, rootname):
|
def check_root_access(self, rootname):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
def check_universal_access(self, rootname):
|
||||||
|
# If there aren't any forbidden paths, we can grant universal read
|
||||||
|
# access. Otherwise, we make no claim.
|
||||||
|
if not self.forbidden:
|
||||||
|
return 1
|
||||||
|
return None
|
||||||
|
|
||||||
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
|
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
|
||||||
# No path? No problem.
|
# No path? No problem.
|
||||||
if not path_parts:
|
if not path_parts:
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 2008 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 2008-2010 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# 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
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -46,6 +46,13 @@ class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
|
|||||||
def check_root_access(self, rootname):
|
def check_root_access(self, rootname):
|
||||||
return self._check_root_path_access(rootname)
|
return self._check_root_path_access(rootname)
|
||||||
|
|
||||||
|
def check_universal_access(self, rootname):
|
||||||
|
# If there aren't any forbidden regexps, we can grant universal
|
||||||
|
# read access. Otherwise, we make no claim.
|
||||||
|
if not self.forbidden:
|
||||||
|
return 1
|
||||||
|
return None
|
||||||
|
|
||||||
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
|
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
|
||||||
root_path = rootname
|
root_path = rootname
|
||||||
if path_parts:
|
if path_parts:
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 2006-2008 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 2006-2011 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# 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
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -54,7 +54,10 @@ class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
|
|||||||
# option names.
|
# option names.
|
||||||
cp = ConfigParser()
|
cp = ConfigParser()
|
||||||
cp.optionxform = lambda x: x
|
cp.optionxform = lambda x: x
|
||||||
cp.read(self.authz_file)
|
try:
|
||||||
|
cp.read(self.authz_file)
|
||||||
|
except:
|
||||||
|
raise debug.ViewVCException("Unable to parse configured authzfile file")
|
||||||
|
|
||||||
# Figure out if there are any aliases for the current username
|
# Figure out if there are any aliases for the current username
|
||||||
aliases = []
|
aliases = []
|
||||||
@@ -221,6 +224,36 @@ class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
|
|||||||
paths = self._get_paths_for_root(rootname)
|
paths = self._get_paths_for_root(rootname)
|
||||||
return (paths is not None) and 1 or 0
|
return (paths is not None) and 1 or 0
|
||||||
|
|
||||||
|
def check_universal_access(self, rootname):
|
||||||
|
paths = self._get_paths_for_root(rootname)
|
||||||
|
if not paths: # None or empty.
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# Search the access determinations. If there's a mix, we can't
|
||||||
|
# claim a universal access determination.
|
||||||
|
found_allow = 0
|
||||||
|
found_deny = 0
|
||||||
|
for access in paths.values():
|
||||||
|
if access:
|
||||||
|
found_allow = 1
|
||||||
|
else:
|
||||||
|
found_deny = 1
|
||||||
|
if found_allow and found_deny:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# We didn't find both allowances and denials, so we must have
|
||||||
|
# found one or the other. Denials only is a universal denial.
|
||||||
|
if found_deny:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# ... but allowances only is only a universal allowance if read
|
||||||
|
# access is granted to the root directory.
|
||||||
|
if found_allow and paths.has_key('/'):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# Anything else is indeterminable.
|
||||||
|
return None
|
||||||
|
|
||||||
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
|
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
|
||||||
# Crawl upward from the path represented by PATH_PARTS toward to
|
# Crawl upward from the path represented by PATH_PARTS toward to
|
||||||
# the root of the repository, looking for an explicitly grant or
|
# the root of the repository, looking for an explicitly grant or
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2011 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# 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
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -76,7 +76,7 @@ class Repository:
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def openfile(self, path_parts, rev):
|
def openfile(self, path_parts, rev, options):
|
||||||
"""Open a file object to read file contents at a given path and revision.
|
"""Open a file object to read file contents at a given path and revision.
|
||||||
|
|
||||||
The return value is a 2-tuple of containg the file object and revision
|
The return value is a 2-tuple of containg the file object and revision
|
||||||
@@ -86,6 +86,8 @@ class Repository:
|
|||||||
of the repository. e.g. ["subdir1", "subdir2", "filename"]
|
of the repository. e.g. ["subdir1", "subdir2", "filename"]
|
||||||
|
|
||||||
rev is the revision of the file to check out
|
rev is the revision of the file to check out
|
||||||
|
|
||||||
|
options is a dictionary of implementation specific options
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def listdir(self, path_parts, rev, options):
|
def listdir(self, path_parts, rev, options):
|
||||||
@@ -180,8 +182,10 @@ class Repository:
|
|||||||
|
|
||||||
rev is the revision of the item to return information about
|
rev is the revision of the item to return information about
|
||||||
|
|
||||||
Return value is a 4-tuple containing the date, author, log
|
Return value is a 5-tuple containing: the date, author, log
|
||||||
message, and a list of ChangedPath items representing paths changed
|
message, a list of ChangedPath items representing paths changed,
|
||||||
|
and a dictionary mapping property names to property values for
|
||||||
|
properties stored on an item.
|
||||||
|
|
||||||
Raise vclib.UnsupportedFeature if the version control system
|
Raise vclib.UnsupportedFeature if the version control system
|
||||||
doesn't support a global revision concept.
|
doesn't support a global revision concept.
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2011 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# 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
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -40,6 +40,11 @@ class BaseCVSRepository(vclib.Repository):
|
|||||||
if not vclib.check_root_access(self):
|
if not vclib.check_root_access(self):
|
||||||
raise vclib.ReposNotFound(name)
|
raise vclib.ReposNotFound(name)
|
||||||
|
|
||||||
|
def open(self):
|
||||||
|
# See if a universal read access determination can be made.
|
||||||
|
if self.auth and self.auth.check_universal_access(self.name) == 1:
|
||||||
|
self.auth = None
|
||||||
|
|
||||||
def rootname(self):
|
def rootname(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
@@ -162,7 +167,14 @@ class BinCVSRepository(BaseCVSRepository):
|
|||||||
return revs[-1]
|
return revs[-1]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def openfile(self, path_parts, rev):
|
def openfile(self, path_parts, rev, options):
|
||||||
|
"""see vclib.Repository.openfile docstring
|
||||||
|
|
||||||
|
Option values recognized by this implementation:
|
||||||
|
|
||||||
|
cvs_oldkeywords
|
||||||
|
boolean. true to use the original keyword substitution values.
|
||||||
|
"""
|
||||||
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
|
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
|
||||||
raise vclib.Error("Path '%s' is not a file."
|
raise vclib.Error("Path '%s' is not a file."
|
||||||
% (string.join(path_parts, "/")))
|
% (string.join(path_parts, "/")))
|
||||||
@@ -170,12 +182,14 @@ class BinCVSRepository(BaseCVSRepository):
|
|||||||
rev_flag = '-p'
|
rev_flag = '-p'
|
||||||
else:
|
else:
|
||||||
rev_flag = '-p' + rev
|
rev_flag = '-p' + rev
|
||||||
|
if options.get('cvs_oldkeywords', 0):
|
||||||
|
kv_flag = '-ko'
|
||||||
|
else:
|
||||||
|
kv_flag = '-kkv'
|
||||||
full_name = self.rcsfile(path_parts, root=1, v=0)
|
full_name = self.rcsfile(path_parts, root=1, v=0)
|
||||||
|
|
||||||
used_rlog = 0
|
used_rlog = 0
|
||||||
tip_rev = None # used only if we have to fallback to using rlog
|
tip_rev = None # used only if we have to fallback to using rlog
|
||||||
|
fp = self.rcs_popen('co', (kv_flag, rev_flag, full_name), 'rb')
|
||||||
fp = self.rcs_popen('co', (rev_flag, full_name), 'rb')
|
|
||||||
try:
|
try:
|
||||||
filename, revision = _parse_co_header(fp)
|
filename, revision = _parse_co_header(fp)
|
||||||
except COMissingRevision:
|
except COMissingRevision:
|
||||||
@@ -1022,16 +1036,16 @@ def _get_logs(repos, dir_path_parts, entries, view_tag, get_dirs):
|
|||||||
file.errors.append("rlog error: %s" % msg)
|
file.errors.append("rlog error: %s" % msg)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
tag = None
|
||||||
if view_tag == 'MAIN' or view_tag == 'HEAD':
|
if view_tag == 'MAIN' or view_tag == 'HEAD':
|
||||||
tag = Tag(None, default_branch)
|
tag = Tag(None, default_branch)
|
||||||
elif taginfo.has_key(view_tag):
|
elif taginfo.has_key(view_tag):
|
||||||
tag = Tag(None, taginfo[view_tag])
|
tag = Tag(None, taginfo[view_tag])
|
||||||
elif view_tag:
|
elif view_tag and (eof != _EOF_FILE):
|
||||||
# the tag wasn't found, so skip this file
|
# the tag wasn't found, so skip this file (unless we already
|
||||||
|
# know there's nothing left of it to read)
|
||||||
_skip_file(rlog)
|
_skip_file(rlog)
|
||||||
eof = 1
|
eof = _EOF_FILE
|
||||||
else:
|
|
||||||
tag = None
|
|
||||||
|
|
||||||
# we don't care about the specific values -- just the keys and whether
|
# we don't care about the specific values -- just the keys and whether
|
||||||
# the values point to branches or revisions. this the fastest way to
|
# the values point to branches or revisions. this the fastest way to
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2011 The ViewCVS Group. All Rights Reserved.
|
||||||
# Copyright (C) 2000 Curt Hagenlocher <curt@hagenlocher.org>
|
# Copyright (C) 2000 Curt Hagenlocher <curt@hagenlocher.org>
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# By using this file, you agree to the terms and conditions set forth in
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2011 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# 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
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -127,9 +127,9 @@ class CCVSRepository(BaseCVSRepository):
|
|||||||
% (string.join(path_parts2, "/")))
|
% (string.join(path_parts2, "/")))
|
||||||
|
|
||||||
temp1 = tempfile.mktemp()
|
temp1 = tempfile.mktemp()
|
||||||
open(temp1, 'wb').write(self.openfile(path_parts1, rev1)[0].getvalue())
|
open(temp1, 'wb').write(self.openfile(path_parts1, rev1, {})[0].getvalue())
|
||||||
temp2 = tempfile.mktemp()
|
temp2 = tempfile.mktemp()
|
||||||
open(temp2, 'wb').write(self.openfile(path_parts2, rev2)[0].getvalue())
|
open(temp2, 'wb').write(self.openfile(path_parts2, rev2, {})[0].getvalue())
|
||||||
|
|
||||||
r1 = self.itemlog(path_parts1, rev1, vclib.SORTBY_DEFAULT, 0, 0, {})[-1]
|
r1 = self.itemlog(path_parts1, rev1, vclib.SORTBY_DEFAULT, 0, 0, {})[-1]
|
||||||
r2 = self.itemlog(path_parts2, rev2, vclib.SORTBY_DEFAULT, 0, 0, {})[-1]
|
r2 = self.itemlog(path_parts2, rev2, vclib.SORTBY_DEFAULT, 0, 0, {})[-1]
|
||||||
@@ -152,7 +152,7 @@ class CCVSRepository(BaseCVSRepository):
|
|||||||
def revinfo(self, rev):
|
def revinfo(self, rev):
|
||||||
raise vclib.UnsupportedFeature
|
raise vclib.UnsupportedFeature
|
||||||
|
|
||||||
def openfile(self, path_parts, rev=None):
|
def openfile(self, path_parts, rev, options):
|
||||||
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
|
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
|
||||||
raise vclib.Error("Path '%s' is not a file."
|
raise vclib.Error("Path '%s' is not a file."
|
||||||
% (string.join(path_parts, "/")))
|
% (string.join(path_parts, "/")))
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2011 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# 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
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -194,7 +194,8 @@ class _Parser:
|
|||||||
else:
|
else:
|
||||||
# Chew up "newphrase"
|
# Chew up "newphrase"
|
||||||
# warn("Unexpected RCS token: $token\n")
|
# warn("Unexpected RCS token: $token\n")
|
||||||
pass
|
while self.ts.get() != ';':
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
if f is None:
|
if f is None:
|
||||||
self.ts.unget(token)
|
self.ts.unget(token)
|
||||||
|
@@ -19,7 +19,11 @@ import string
|
|||||||
import common
|
import common
|
||||||
|
|
||||||
class _TokenStream:
|
class _TokenStream:
|
||||||
token_term = string.whitespace + ';:'
|
token_term = string.whitespace + ";:"
|
||||||
|
try:
|
||||||
|
token_term = frozenset(token_term)
|
||||||
|
except NameError:
|
||||||
|
pass
|
||||||
|
|
||||||
# the algorithm is about the same speed for any CHUNK_SIZE chosen.
|
# the algorithm is about the same speed for any CHUNK_SIZE chosen.
|
||||||
# grab a good-sized chunk, but not too large to overwhelm memory.
|
# grab a good-sized chunk, but not too large to overwhelm memory.
|
||||||
@@ -44,15 +48,17 @@ class _TokenStream:
|
|||||||
# out more complex solutions.
|
# out more complex solutions.
|
||||||
|
|
||||||
buf = self.buf
|
buf = self.buf
|
||||||
|
lbuf = len(buf)
|
||||||
idx = self.idx
|
idx = self.idx
|
||||||
|
|
||||||
while 1:
|
while 1:
|
||||||
if idx == len(buf):
|
if idx == lbuf:
|
||||||
buf = self.rcsfile.read(self.CHUNK_SIZE)
|
buf = self.rcsfile.read(self.CHUNK_SIZE)
|
||||||
if buf == '':
|
if buf == '':
|
||||||
# signal EOF by returning None as the token
|
# 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
|
return None
|
||||||
|
lbuf = len(buf)
|
||||||
idx = 0
|
idx = 0
|
||||||
|
|
||||||
if buf[idx] not in string.whitespace:
|
if buf[idx] not in string.whitespace:
|
||||||
@@ -60,7 +66,7 @@ class _TokenStream:
|
|||||||
|
|
||||||
idx = idx + 1
|
idx = idx + 1
|
||||||
|
|
||||||
if buf[idx] == ';' or buf[idx] == ':':
|
if buf[idx] in ';:':
|
||||||
self.buf = buf
|
self.buf = buf
|
||||||
self.idx = idx + 1
|
self.idx = idx + 1
|
||||||
return buf[idx]
|
return buf[idx]
|
||||||
@@ -70,17 +76,18 @@ class _TokenStream:
|
|||||||
token = ''
|
token = ''
|
||||||
while 1:
|
while 1:
|
||||||
# find token characters in the current buffer
|
# find token characters in the current buffer
|
||||||
while end < len(buf) and buf[end] not in self.token_term:
|
while end < lbuf and buf[end] not in self.token_term:
|
||||||
end = end + 1
|
end = end + 1
|
||||||
token = token + buf[idx:end]
|
token = token + buf[idx:end]
|
||||||
|
|
||||||
if end < len(buf):
|
if end < lbuf:
|
||||||
# we stopped before the end, so we have a full token
|
# we stopped before the end, so we have a full token
|
||||||
idx = end
|
idx = end
|
||||||
break
|
break
|
||||||
|
|
||||||
# we stopped at the end of the buffer, so we may have a partial token
|
# we stopped at the end of the buffer, so we may have a partial token
|
||||||
buf = self.rcsfile.read(self.CHUNK_SIZE)
|
buf = self.rcsfile.read(self.CHUNK_SIZE)
|
||||||
|
lbuf = len(buf)
|
||||||
idx = end = 0
|
idx = end = 0
|
||||||
|
|
||||||
self.buf = buf
|
self.buf = buf
|
||||||
@@ -94,22 +101,24 @@ class _TokenStream:
|
|||||||
chunks = [ ]
|
chunks = [ ]
|
||||||
|
|
||||||
while 1:
|
while 1:
|
||||||
if idx == len(buf):
|
if idx == lbuf:
|
||||||
idx = 0
|
idx = 0
|
||||||
buf = self.rcsfile.read(self.CHUNK_SIZE)
|
buf = self.rcsfile.read(self.CHUNK_SIZE)
|
||||||
if buf == '':
|
if buf == '':
|
||||||
raise RuntimeError, 'EOF'
|
raise RuntimeError, 'EOF'
|
||||||
|
lbuf = len(buf)
|
||||||
i = string.find(buf, '@', idx)
|
i = string.find(buf, '@', idx)
|
||||||
if i == -1:
|
if i == -1:
|
||||||
chunks.append(buf[idx:])
|
chunks.append(buf[idx:])
|
||||||
idx = len(buf)
|
idx = lbuf
|
||||||
continue
|
continue
|
||||||
if i == len(buf) - 1:
|
if i == lbuf - 1:
|
||||||
chunks.append(buf[idx:i])
|
chunks.append(buf[idx:i])
|
||||||
idx = 0
|
idx = 0
|
||||||
buf = '@' + self.rcsfile.read(self.CHUNK_SIZE)
|
buf = '@' + self.rcsfile.read(self.CHUNK_SIZE)
|
||||||
if buf == '@':
|
if buf == '@':
|
||||||
raise RuntimeError, 'EOF'
|
raise RuntimeError, 'EOF'
|
||||||
|
lbuf = len(buf)
|
||||||
continue
|
continue
|
||||||
if buf[i + 1] == '@':
|
if buf[i + 1] == '@':
|
||||||
chunks.append(buf[idx:i+1])
|
chunks.append(buf[idx:i+1])
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2011 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# 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
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import re
|
import re
|
||||||
|
import urllib
|
||||||
|
|
||||||
_re_url = re.compile('^(http|https|file|svn|svn\+[^:]+)://')
|
_re_url = re.compile('^(http|https|file|svn|svn\+[^:]+)://')
|
||||||
|
|
||||||
@@ -23,8 +24,20 @@ def canonicalize_rootpath(rootpath):
|
|||||||
import svn.core
|
import svn.core
|
||||||
return svn.core.svn_path_canonicalize(rootpath)
|
return svn.core.svn_path_canonicalize(rootpath)
|
||||||
except:
|
except:
|
||||||
|
if os.name == 'posix':
|
||||||
|
rootpath_lower = rootpath.lower()
|
||||||
|
if rootpath_lower in ['file://localhost',
|
||||||
|
'file://localhost/',
|
||||||
|
'file://',
|
||||||
|
'file:///'
|
||||||
|
]:
|
||||||
|
return '/'
|
||||||
|
if rootpath_lower.startswith('file://localhost/'):
|
||||||
|
return os.path.normpath(urllib.unquote(rootpath[16:]))
|
||||||
|
elif rootpath_lower.startswith('file:///'):
|
||||||
|
return os.path.normpath(urllib.unquote(rootpath[7:]))
|
||||||
if re.search(_re_url, rootpath):
|
if re.search(_re_url, rootpath):
|
||||||
return rootpath[-1] == '/' and rootpath[:-1] or rootpath
|
return rootpath.rstrip('/')
|
||||||
return os.path.normpath(rootpath)
|
return os.path.normpath(rootpath)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2009 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2011 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# 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
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -18,10 +18,9 @@ import os
|
|||||||
import string
|
import string
|
||||||
import re
|
import re
|
||||||
import tempfile
|
import tempfile
|
||||||
import popen2
|
|
||||||
import time
|
import time
|
||||||
import urllib
|
import urllib
|
||||||
from svn_repos import Revision, SVNChangedPath, _datestr_to_date, _compare_paths, _path_parts, _cleanup_path, _rev2optrev, _fix_subversion_exception
|
from svn_repos import Revision, SVNChangedPath, _datestr_to_date, _compare_paths, _path_parts, _cleanup_path, _rev2optrev, _fix_subversion_exception, _split_revprops
|
||||||
from svn import core, delta, client, wc, ra
|
from svn import core, delta, client, wc, ra
|
||||||
|
|
||||||
|
|
||||||
@@ -52,6 +51,29 @@ def get_directory_props(ra_session, path, rev):
|
|||||||
props = ra.svn_ra_get_dir(ra_session, path, rev)
|
props = ra.svn_ra_get_dir(ra_session, path, rev)
|
||||||
return props
|
return props
|
||||||
|
|
||||||
|
def client_log(url, start_rev, end_rev, log_limit, cross_copies,
|
||||||
|
cb_func, ctx):
|
||||||
|
try:
|
||||||
|
client.svn_client_log4([url], start_rev, start_rev, end_rev,
|
||||||
|
log_limit, 1, not cross_copies, 0, None,
|
||||||
|
cb_func, ctx)
|
||||||
|
except AttributeError:
|
||||||
|
# Wrap old svn_log_message_receiver_t interface with a
|
||||||
|
# svn_log_entry_t one.
|
||||||
|
def cb_convert(paths, revision, author, date, message, pool):
|
||||||
|
class svn_log_entry_t:
|
||||||
|
pass
|
||||||
|
log_entry = svn_log_entry_t()
|
||||||
|
log_entry.changed_paths = paths
|
||||||
|
log_entry.revision = revision
|
||||||
|
log_entry.revprops = { core.SVN_PROP_REVISION_LOG : message,
|
||||||
|
core.SVN_PROP_REVISION_AUTHOR : author,
|
||||||
|
core.SVN_PROP_REVISION_DATE : date,
|
||||||
|
}
|
||||||
|
cb_func(log_entry, pool)
|
||||||
|
client.svn_client_log2([url], start_rev, end_rev, log_limit,
|
||||||
|
1, not cross_copies, cb_convert, ctx)
|
||||||
|
|
||||||
### END COMPATABILITY CODE ###
|
### END COMPATABILITY CODE ###
|
||||||
|
|
||||||
|
|
||||||
@@ -68,7 +90,11 @@ class LogCollector:
|
|||||||
self.show_all_logs = show_all_logs
|
self.show_all_logs = show_all_logs
|
||||||
self.lockinfo = lockinfo
|
self.lockinfo = lockinfo
|
||||||
|
|
||||||
def add_log(self, paths, revision, author, date, message, pool):
|
def add_log(self, log_entry, pool):
|
||||||
|
paths = log_entry.changed_paths
|
||||||
|
revision = log_entry.revision
|
||||||
|
msg, author, date, revprops = _split_revprops(log_entry.revprops)
|
||||||
|
|
||||||
# Changed paths have leading slashes
|
# Changed paths have leading slashes
|
||||||
changed_paths = paths.keys()
|
changed_paths = paths.keys()
|
||||||
changed_paths.sort(lambda a, b: _compare_paths(a, b))
|
changed_paths.sort(lambda a, b: _compare_paths(a, b))
|
||||||
@@ -88,8 +114,8 @@ class LogCollector:
|
|||||||
if change.copyfrom_path:
|
if change.copyfrom_path:
|
||||||
this_path = change.copyfrom_path + self.path[len(changed_path):]
|
this_path = change.copyfrom_path + self.path[len(changed_path):]
|
||||||
if self.show_all_logs or this_path:
|
if self.show_all_logs or this_path:
|
||||||
entry = Revision(revision, _datestr_to_date(date), author, message, None,
|
entry = Revision(revision, date, author, msg, None, self.lockinfo,
|
||||||
self.lockinfo, self.path[1:], None, None)
|
self.path[1:], None, None)
|
||||||
self.logs.append(entry)
|
self.logs.append(entry)
|
||||||
if this_path:
|
if this_path:
|
||||||
self.path = this_path
|
self.path = this_path
|
||||||
@@ -157,7 +183,7 @@ class RemoteSubversionRepository(vclib.Repository):
|
|||||||
# Setup the client context baton, complete with non-prompting authstuffs.
|
# Setup the client context baton, complete with non-prompting authstuffs.
|
||||||
# TODO: svn_cmdline_setup_auth_baton() is mo' better (when available)
|
# TODO: svn_cmdline_setup_auth_baton() is mo' better (when available)
|
||||||
core.svn_config_ensure(self.config_dir)
|
core.svn_config_ensure(self.config_dir)
|
||||||
self.ctx = client.svn_client_ctx_t()
|
self.ctx = client.svn_client_create_context()
|
||||||
self.ctx.auth_baton = core.svn_auth_open([
|
self.ctx.auth_baton = core.svn_auth_open([
|
||||||
client.svn_client_get_simple_provider(),
|
client.svn_client_get_simple_provider(),
|
||||||
client.svn_client_get_username_provider(),
|
client.svn_client_get_username_provider(),
|
||||||
@@ -177,6 +203,10 @@ class RemoteSubversionRepository(vclib.Repository):
|
|||||||
self.youngest = ra.svn_ra_get_latest_revnum(self.ra_session)
|
self.youngest = ra.svn_ra_get_latest_revnum(self.ra_session)
|
||||||
self._dirent_cache = { }
|
self._dirent_cache = { }
|
||||||
self._revinfo_cache = { }
|
self._revinfo_cache = { }
|
||||||
|
|
||||||
|
# See if a universal read access determination can be made.
|
||||||
|
if self.auth and self.auth.check_universal_access(self.name) == 1:
|
||||||
|
self.auth = None
|
||||||
|
|
||||||
def rootname(self):
|
def rootname(self):
|
||||||
return self.name
|
return self.name
|
||||||
@@ -211,7 +241,7 @@ class RemoteSubversionRepository(vclib.Repository):
|
|||||||
raise vclib.ItemNotFound(path_parts)
|
raise vclib.ItemNotFound(path_parts)
|
||||||
return pathtype
|
return pathtype
|
||||||
|
|
||||||
def openfile(self, path_parts, rev):
|
def openfile(self, path_parts, rev, options):
|
||||||
path = self._getpath(path_parts)
|
path = self._getpath(path_parts)
|
||||||
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
|
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
|
||||||
raise vclib.Error("Path '%s' is not a file." % path)
|
raise vclib.Error("Path '%s' is not a file." % path)
|
||||||
@@ -252,7 +282,7 @@ class RemoteSubversionRepository(vclib.Repository):
|
|||||||
if not vclib.check_path_access(self, entry_path_parts, entry.kind, rev):
|
if not vclib.check_path_access(self, entry_path_parts, entry.kind, rev):
|
||||||
continue
|
continue
|
||||||
dirent = dirents[entry.name]
|
dirent = dirents[entry.name]
|
||||||
entry.date, entry.author, entry.log, changes = \
|
entry.date, entry.author, entry.log, revprops, changes = \
|
||||||
self.revinfo(dirent.created_rev)
|
self.revinfo(dirent.created_rev)
|
||||||
entry.rev = str(dirent.created_rev)
|
entry.rev = str(dirent.created_rev)
|
||||||
entry.size = dirent.size
|
entry.size = dirent.size
|
||||||
@@ -283,9 +313,8 @@ class RemoteSubversionRepository(vclib.Repository):
|
|||||||
log_limit = 0
|
log_limit = 0
|
||||||
if limit:
|
if limit:
|
||||||
log_limit = first + limit
|
log_limit = first + limit
|
||||||
client.svn_client_log2([url], _rev2optrev(rev), _rev2optrev(1),
|
client_log(url, _rev2optrev(rev), _rev2optrev(1), log_limit,
|
||||||
log_limit, 1, not cross_copies,
|
cross_copies, lc.add_log, self.ctx)
|
||||||
lc.add_log, self.ctx)
|
|
||||||
revs = lc.logs
|
revs = lc.logs
|
||||||
revs.sort()
|
revs.sort()
|
||||||
prev = None
|
prev = None
|
||||||
@@ -337,7 +366,7 @@ class RemoteSubversionRepository(vclib.Repository):
|
|||||||
if not cached_info:
|
if not cached_info:
|
||||||
cached_info = self._revinfo_raw(rev)
|
cached_info = self._revinfo_raw(rev)
|
||||||
self._revinfo_cache[rev] = cached_info
|
self._revinfo_cache[rev] = cached_info
|
||||||
return cached_info[0], cached_info[1], cached_info[2], cached_info[3]
|
return tuple(cached_info)
|
||||||
|
|
||||||
def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
|
def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
|
||||||
p1 = self._getpath(path_parts1)
|
p1 = self._getpath(path_parts1)
|
||||||
@@ -352,7 +381,7 @@ class RemoteSubversionRepository(vclib.Repository):
|
|||||||
args = vclib._diff_args(type, options)
|
args = vclib._diff_args(type, options)
|
||||||
|
|
||||||
def _date_from_rev(rev):
|
def _date_from_rev(rev):
|
||||||
date, author, msg, changes = self.revinfo(rev)
|
date, author, msg, revprops, changes = self.revinfo(rev)
|
||||||
return date
|
return date
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -378,8 +407,11 @@ class RemoteSubversionRepository(vclib.Repository):
|
|||||||
if rev is None or rev == 'HEAD':
|
if rev is None or rev == 'HEAD':
|
||||||
return self.youngest
|
return self.youngest
|
||||||
try:
|
try:
|
||||||
|
if type(rev) == type(''):
|
||||||
|
while rev[0] == 'r':
|
||||||
|
rev = rev[1:]
|
||||||
rev = int(rev)
|
rev = int(rev)
|
||||||
except ValueError:
|
except:
|
||||||
raise vclib.InvalidRevision(rev)
|
raise vclib.InvalidRevision(rev)
|
||||||
if (rev < 0) or (rev > self.youngest):
|
if (rev < 0) or (rev > self.youngest):
|
||||||
raise vclib.InvalidRevision(rev)
|
raise vclib.InvalidRevision(rev)
|
||||||
@@ -417,29 +449,54 @@ class RemoteSubversionRepository(vclib.Repository):
|
|||||||
return revisions[0]
|
return revisions[0]
|
||||||
|
|
||||||
def _revinfo_raw(self, rev):
|
def _revinfo_raw(self, rev):
|
||||||
# return 5-tuple (date, author, message, changes)
|
# return 5-tuple (date, author, msg, revprops, changes)
|
||||||
optrev = _rev2optrev(rev)
|
optrev = _rev2optrev(rev)
|
||||||
revs = []
|
revs = []
|
||||||
|
|
||||||
def _log_cb(changed_paths, revision, author,
|
def _log_cb(log_entry, pool, retval=revs):
|
||||||
datestr, message, pool, retval=revs):
|
### Subversion 1.5 and earlier didn't offer the 'changed_paths2'
|
||||||
date = _datestr_to_date(datestr)
|
### hash, and in Subversion 1.6, it's offered but broken.
|
||||||
|
try:
|
||||||
|
changed_paths = log_entry.changed_paths2
|
||||||
|
paths = (changed_paths or {}).keys()
|
||||||
|
except:
|
||||||
|
changed_paths = log_entry.changed_paths
|
||||||
|
paths = (changed_paths or {}).keys()
|
||||||
|
paths.sort(lambda a, b: _compare_paths(a, b))
|
||||||
|
revision = log_entry.revision
|
||||||
|
msg, author, date, revprops = _split_revprops(log_entry.revprops)
|
||||||
action_map = { 'D' : vclib.DELETED,
|
action_map = { 'D' : vclib.DELETED,
|
||||||
'A' : vclib.ADDED,
|
'A' : vclib.ADDED,
|
||||||
'R' : vclib.REPLACED,
|
'R' : vclib.REPLACED,
|
||||||
'M' : vclib.MODIFIED,
|
'M' : vclib.MODIFIED,
|
||||||
}
|
}
|
||||||
paths = (changed_paths or {}).keys()
|
|
||||||
paths.sort(lambda a, b: _compare_paths(a, b))
|
|
||||||
changes = []
|
changes = []
|
||||||
found_readable = found_unreadable = 0
|
found_readable = found_unreadable = 0
|
||||||
for path in paths:
|
for path in paths:
|
||||||
pathtype = None
|
|
||||||
change = changed_paths[path]
|
change = changed_paths[path]
|
||||||
action = action_map.get(change.action, vclib.MODIFIED)
|
### svn_log_changed_path_t (which we might get instead of the
|
||||||
|
### svn_log_changed_path2_t we'd prefer) doesn't have the
|
||||||
|
### 'node_kind' member.
|
||||||
|
pathtype = None
|
||||||
|
if hasattr(change, 'node_kind'):
|
||||||
|
if change.node_kind == core.svn_node_dir:
|
||||||
|
pathtype = vclib.DIR
|
||||||
|
elif change.node_kind == core.svn_node_file:
|
||||||
|
pathtype = vclib.FILE
|
||||||
|
### svn_log_changed_path2_t only has the 'text_modified' and
|
||||||
|
### 'props_modified' bits in Subversion 1.7 and beyond. And
|
||||||
|
### svn_log_changed_path_t is without.
|
||||||
|
text_modified = props_modified = 0
|
||||||
|
if hasattr(change, 'text_modified'):
|
||||||
|
if change.text_modified == core.svn_tristate_true:
|
||||||
|
text_modified = 1
|
||||||
|
if hasattr(change, 'props_modified'):
|
||||||
|
if change.props_modified == core.svn_tristate_true:
|
||||||
|
props_modified = 1
|
||||||
### Wrong, diddily wrong wrong wrong. Can you say,
|
### Wrong, diddily wrong wrong wrong. Can you say,
|
||||||
### "Manufacturing data left and right because it hurts to
|
### "Manufacturing data left and right because it hurts to
|
||||||
### figure out the right stuff?"
|
### figure out the right stuff?"
|
||||||
|
action = action_map.get(change.action, vclib.MODIFIED)
|
||||||
if change.copyfrom_path and change.copyfrom_rev:
|
if change.copyfrom_path and change.copyfrom_rev:
|
||||||
is_copy = 1
|
is_copy = 1
|
||||||
base_path = change.copyfrom_path
|
base_path = change.copyfrom_path
|
||||||
@@ -462,21 +519,21 @@ class RemoteSubversionRepository(vclib.Repository):
|
|||||||
base_path = None
|
base_path = None
|
||||||
base_rev = None
|
base_rev = None
|
||||||
changes.append(SVNChangedPath(path, revision, pathtype, base_path,
|
changes.append(SVNChangedPath(path, revision, pathtype, base_path,
|
||||||
base_rev, action, is_copy, 0, 0))
|
base_rev, action, is_copy,
|
||||||
|
text_modified, props_modified))
|
||||||
found_readable = 1
|
found_readable = 1
|
||||||
else:
|
else:
|
||||||
found_unreadable = 1
|
found_unreadable = 1
|
||||||
|
|
||||||
if found_unreadable:
|
if found_unreadable:
|
||||||
message = None
|
msg = None
|
||||||
if not found_readable:
|
if not found_readable:
|
||||||
author = None
|
author = None
|
||||||
date = None
|
date = None
|
||||||
revs.append([date, author, message, changes])
|
revs.append([date, author, msg, revprops, changes])
|
||||||
|
|
||||||
client.svn_client_log([self.rootpath], optrev, optrev,
|
client_log(self.rootpath, optrev, optrev, 1, 0, _log_cb, self.ctx)
|
||||||
1, 0, _log_cb, self.ctx)
|
return tuple(revs[0])
|
||||||
return revs[0][0], revs[0][1], revs[0][2], revs[0][3]
|
|
||||||
|
|
||||||
##--- custom --##
|
##--- custom --##
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# -*-python-*-
|
# -*-python-*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 1999-2009 The ViewCVS Group. All Rights Reserved.
|
# Copyright (C) 1999-2011 The ViewCVS Group. All Rights Reserved.
|
||||||
#
|
#
|
||||||
# By using this file, you agree to the terms and conditions set forth in
|
# 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
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||||
@@ -115,6 +115,27 @@ def _rootpath2url(rootpath, path):
|
|||||||
return 'file://' + string.join([rootpath, path], "/")
|
return 'file://' + string.join([rootpath, path], "/")
|
||||||
|
|
||||||
|
|
||||||
|
# Given a dictionary REVPROPS of revision properties, pull special
|
||||||
|
# ones out of them and return a 4-tuple containing the log message,
|
||||||
|
# the author, the date (converted from the date string property), and
|
||||||
|
# a dictionary of any/all other revprops.
|
||||||
|
def _split_revprops(revprops):
|
||||||
|
if not revprops:
|
||||||
|
return None, None, None, {}
|
||||||
|
special_props = []
|
||||||
|
for prop in core.SVN_PROP_REVISION_LOG, \
|
||||||
|
core.SVN_PROP_REVISION_AUTHOR, \
|
||||||
|
core.SVN_PROP_REVISION_DATE:
|
||||||
|
if revprops.has_key(prop):
|
||||||
|
special_props.append(revprops[prop])
|
||||||
|
del(revprops[prop])
|
||||||
|
else:
|
||||||
|
special_props.append(None)
|
||||||
|
msg, author, datestr = tuple(special_props)
|
||||||
|
date = _datestr_to_date(datestr)
|
||||||
|
return msg, author, date, revprops
|
||||||
|
|
||||||
|
|
||||||
def _datestr_to_date(datestr):
|
def _datestr_to_date(datestr):
|
||||||
try:
|
try:
|
||||||
return core.svn_time_from_cstring(datestr) / 1000000
|
return core.svn_time_from_cstring(datestr) / 1000000
|
||||||
@@ -183,59 +204,6 @@ class NodeHistory:
|
|||||||
def __getitem__(self, idx):
|
def __getitem__(self, idx):
|
||||||
return self.histories[idx]
|
return self.histories[idx]
|
||||||
|
|
||||||
|
|
||||||
def _get_history(svnrepos, path, rev, path_type, limit=0, options={}):
|
|
||||||
if svnrepos.youngest == 0:
|
|
||||||
return []
|
|
||||||
|
|
||||||
rev_paths = []
|
|
||||||
fsroot = svnrepos._getroot(rev)
|
|
||||||
show_all_logs = options.get('svn_show_all_dir_logs', 0)
|
|
||||||
if not show_all_logs:
|
|
||||||
# See if the path is a file or directory.
|
|
||||||
kind = fs.check_path(fsroot, path)
|
|
||||||
if kind is core.svn_node_file:
|
|
||||||
show_all_logs = 1
|
|
||||||
|
|
||||||
# Instantiate a NodeHistory collector object, and use it to collect
|
|
||||||
# history items for PATH@REV.
|
|
||||||
history = NodeHistory(svnrepos.fs_ptr, show_all_logs, limit)
|
|
||||||
try:
|
|
||||||
repos.svn_repos_history(svnrepos.fs_ptr, path, history.add_history,
|
|
||||||
1, rev, options.get('svn_cross_copies', 0))
|
|
||||||
except core.SubversionException, e:
|
|
||||||
_fix_subversion_exception(e)
|
|
||||||
if e.apr_err != _SVN_ERR_CEASE_INVOCATION:
|
|
||||||
raise
|
|
||||||
|
|
||||||
# Now, iterate over those history items, checking for changes of
|
|
||||||
# location, pruning as necessitated by authz rules.
|
|
||||||
for hist_rev, hist_path in history:
|
|
||||||
path_parts = _path_parts(hist_path)
|
|
||||||
if not vclib.check_path_access(svnrepos, path_parts, path_type, hist_rev):
|
|
||||||
break
|
|
||||||
rev_paths.append([hist_rev, hist_path])
|
|
||||||
return rev_paths
|
|
||||||
|
|
||||||
|
|
||||||
def _log_helper(svnrepos, path, rev, lockinfo):
|
|
||||||
rev_root = fs.revision_root(svnrepos.fs_ptr, rev)
|
|
||||||
|
|
||||||
# Was this path@rev the target of a copy?
|
|
||||||
copyfrom_rev, copyfrom_path = fs.copied_from(rev_root, path)
|
|
||||||
|
|
||||||
# Assemble our LogEntry
|
|
||||||
date, author, msg, changes = svnrepos._revinfo(rev)
|
|
||||||
if fs.is_file(rev_root, path):
|
|
||||||
size = fs.file_length(rev_root, path)
|
|
||||||
else:
|
|
||||||
size = None
|
|
||||||
entry = Revision(rev, date, author, msg, size, lockinfo, path,
|
|
||||||
copyfrom_path and _cleanup_path(copyfrom_path),
|
|
||||||
copyfrom_rev)
|
|
||||||
return entry
|
|
||||||
|
|
||||||
|
|
||||||
def _get_last_history_rev(fsroot, path):
|
def _get_last_history_rev(fsroot, path):
|
||||||
history = fs.node_history(fsroot, path)
|
history = fs.node_history(fsroot, path)
|
||||||
history = fs.history_prev(history, 0)
|
history = fs.history_prev(history, 0)
|
||||||
@@ -314,14 +282,14 @@ class FileContentsPipe:
|
|||||||
|
|
||||||
|
|
||||||
class BlameSource:
|
class BlameSource:
|
||||||
def __init__(self, local_url, rev, first_rev):
|
def __init__(self, local_url, rev, first_rev, config_dir):
|
||||||
self.idx = -1
|
self.idx = -1
|
||||||
self.first_rev = first_rev
|
self.first_rev = first_rev
|
||||||
self.blame_data = []
|
self.blame_data = []
|
||||||
|
|
||||||
ctx = client.ctx_t()
|
ctx = client.svn_client_create_context()
|
||||||
core.svn_config_ensure(None)
|
core.svn_config_ensure(config_dir)
|
||||||
ctx.config = core.svn_config_get_config(None)
|
ctx.config = core.svn_config_get_config(config_dir)
|
||||||
ctx.auth_baton = core.svn_auth_open([])
|
ctx.auth_baton = core.svn_auth_open([])
|
||||||
try:
|
try:
|
||||||
### TODO: Is this use of FIRST_REV always what we want? Should we
|
### TODO: Is this use of FIRST_REV always what we want? Should we
|
||||||
@@ -376,7 +344,7 @@ class LocalSubversionRepository(vclib.Repository):
|
|||||||
self.auth = authorizer
|
self.auth = authorizer
|
||||||
self.svn_client_path = utilities.svn or 'svn'
|
self.svn_client_path = utilities.svn or 'svn'
|
||||||
self.diff_cmd = utilities.diff or 'diff'
|
self.diff_cmd = utilities.diff or 'diff'
|
||||||
self.config_dir = config_dir
|
self.config_dir = config_dir or None
|
||||||
|
|
||||||
# See if this repository is even viewable, authz-wise.
|
# See if this repository is even viewable, authz-wise.
|
||||||
if not vclib.check_root_access(self):
|
if not vclib.check_root_access(self):
|
||||||
@@ -406,6 +374,10 @@ class LocalSubversionRepository(vclib.Repository):
|
|||||||
self._fsroots = {}
|
self._fsroots = {}
|
||||||
self._revinfo_cache = {}
|
self._revinfo_cache = {}
|
||||||
|
|
||||||
|
# See if a universal read access determination can be made.
|
||||||
|
if self.auth and self.auth.check_universal_access(self.name) == 1:
|
||||||
|
self.auth = None
|
||||||
|
|
||||||
def rootname(self):
|
def rootname(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
@@ -421,19 +393,14 @@ class LocalSubversionRepository(vclib.Repository):
|
|||||||
def itemtype(self, path_parts, rev):
|
def itemtype(self, path_parts, rev):
|
||||||
rev = self._getrev(rev)
|
rev = self._getrev(rev)
|
||||||
basepath = self._getpath(path_parts)
|
basepath = self._getpath(path_parts)
|
||||||
kind = fs.check_path(self._getroot(rev), basepath)
|
pathtype = self._gettype(basepath, rev)
|
||||||
pathtype = None
|
if pathtype is None:
|
||||||
if kind == core.svn_node_dir:
|
|
||||||
pathtype = vclib.DIR
|
|
||||||
elif kind == core.svn_node_file:
|
|
||||||
pathtype = vclib.FILE
|
|
||||||
else:
|
|
||||||
raise vclib.ItemNotFound(path_parts)
|
raise vclib.ItemNotFound(path_parts)
|
||||||
if not vclib.check_path_access(self, path_parts, pathtype, rev):
|
if not vclib.check_path_access(self, path_parts, pathtype, rev):
|
||||||
raise vclib.ItemNotFound(path_parts)
|
raise vclib.ItemNotFound(path_parts)
|
||||||
return pathtype
|
return pathtype
|
||||||
|
|
||||||
def openfile(self, path_parts, rev):
|
def openfile(self, path_parts, rev, options):
|
||||||
path = self._getpath(path_parts)
|
path = self._getpath(path_parts)
|
||||||
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
|
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
|
||||||
raise vclib.Error("Path '%s' is not a file." % path)
|
raise vclib.Error("Path '%s' is not a file." % path)
|
||||||
@@ -472,7 +439,7 @@ class LocalSubversionRepository(vclib.Repository):
|
|||||||
continue
|
continue
|
||||||
path = self._getpath(entry_path_parts)
|
path = self._getpath(entry_path_parts)
|
||||||
entry_rev = _get_last_history_rev(fsroot, path)
|
entry_rev = _get_last_history_rev(fsroot, path)
|
||||||
date, author, msg, changes = self._revinfo(entry_rev)
|
date, author, msg, revprops, changes = self._revinfo(entry_rev)
|
||||||
entry.rev = str(entry_rev)
|
entry.rev = str(entry_rev)
|
||||||
entry.date = date
|
entry.date = date
|
||||||
entry.author = author
|
entry.author = author
|
||||||
@@ -521,20 +488,19 @@ class LocalSubversionRepository(vclib.Repository):
|
|||||||
# 'limit' parameter here as numeric cut-off for the depth of our
|
# 'limit' parameter here as numeric cut-off for the depth of our
|
||||||
# history search.
|
# history search.
|
||||||
if options.get('svn_latest_log', 0):
|
if options.get('svn_latest_log', 0):
|
||||||
revision = _log_helper(self, path, rev, lockinfo)
|
revision = self._log_helper(path, rev, lockinfo)
|
||||||
if revision:
|
if revision:
|
||||||
revision.prev = None
|
revision.prev = None
|
||||||
revs.append(revision)
|
revs.append(revision)
|
||||||
else:
|
else:
|
||||||
history = _get_history(self, path, rev, path_type,
|
history = self._get_history(path, rev, path_type, first + limit, options)
|
||||||
first + limit, options)
|
|
||||||
if len(history) < first:
|
if len(history) < first:
|
||||||
history = []
|
history = []
|
||||||
if limit:
|
if limit:
|
||||||
history = history[first:first+limit]
|
history = history[first:first+limit]
|
||||||
|
|
||||||
for hist_rev, hist_path in history:
|
for hist_rev, hist_path in history:
|
||||||
revision = _log_helper(self, hist_path, hist_rev, lockinfo)
|
revision = self._log_helper(hist_path, hist_rev, lockinfo)
|
||||||
if revision:
|
if revision:
|
||||||
# If we have unreadable copyfrom data, obscure it.
|
# If we have unreadable copyfrom data, obscure it.
|
||||||
if revision.copy_path is not None:
|
if revision.copy_path is not None:
|
||||||
@@ -562,36 +528,56 @@ class LocalSubversionRepository(vclib.Repository):
|
|||||||
raise vclib.Error("Path '%s' is not a file." % path)
|
raise vclib.Error("Path '%s' is not a file." % path)
|
||||||
rev = self._getrev(rev)
|
rev = self._getrev(rev)
|
||||||
fsroot = self._getroot(rev)
|
fsroot = self._getroot(rev)
|
||||||
history = _get_history(self, path, rev, path_type, 0,
|
history = self._get_history(path, rev, path_type, 0,
|
||||||
{'svn_cross_copies': 1})
|
{'svn_cross_copies': 1})
|
||||||
youngest_rev, youngest_path = history[0]
|
youngest_rev, youngest_path = history[0]
|
||||||
oldest_rev, oldest_path = history[-1]
|
oldest_rev, oldest_path = history[-1]
|
||||||
source = BlameSource(_rootpath2url(self.rootpath, path),
|
source = BlameSource(_rootpath2url(self.rootpath, path),
|
||||||
youngest_rev, oldest_rev)
|
youngest_rev, oldest_rev, self.config_dir)
|
||||||
return source, youngest_rev
|
return source, youngest_rev
|
||||||
|
|
||||||
|
def revinfo(self, rev):
|
||||||
|
return self._revinfo(rev, 1)
|
||||||
|
|
||||||
|
def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
|
||||||
|
p1 = self._getpath(path_parts1)
|
||||||
|
p2 = self._getpath(path_parts2)
|
||||||
|
r1 = self._getrev(rev1)
|
||||||
|
r2 = self._getrev(rev2)
|
||||||
|
if not vclib.check_path_access(self, path_parts1, vclib.FILE, rev1):
|
||||||
|
raise vclib.ItemNotFound(path_parts1)
|
||||||
|
if not vclib.check_path_access(self, path_parts2, vclib.FILE, rev2):
|
||||||
|
raise vclib.ItemNotFound(path_parts2)
|
||||||
|
|
||||||
|
args = vclib._diff_args(type, options)
|
||||||
|
|
||||||
|
def _date_from_rev(rev):
|
||||||
|
date, author, msg, revprops, changes = self._revinfo(rev)
|
||||||
|
return date
|
||||||
|
|
||||||
|
try:
|
||||||
|
temp1 = temp_checkout(self, p1, r1)
|
||||||
|
temp2 = temp_checkout(self, p2, r2)
|
||||||
|
info1 = p1, _date_from_rev(r1), r1
|
||||||
|
info2 = p2, _date_from_rev(r2), r2
|
||||||
|
return vclib._diff_fp(temp1, temp2, info1, info2, self.diff_cmd, args)
|
||||||
|
except core.SubversionException, e:
|
||||||
|
_fix_subversion_exception(e)
|
||||||
|
if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
|
||||||
|
raise vclib.InvalidRevision
|
||||||
|
raise
|
||||||
|
|
||||||
|
def isexecutable(self, path_parts, rev):
|
||||||
|
props = self.itemprops(path_parts, rev) # does authz-check
|
||||||
|
return props.has_key(core.SVN_PROP_EXECUTABLE)
|
||||||
|
|
||||||
|
##--- helpers ---##
|
||||||
|
|
||||||
def _revinfo(self, rev, include_changed_paths=0):
|
def _revinfo(self, rev, include_changed_paths=0):
|
||||||
"""Internal-use, cache-friendly revision information harvester."""
|
"""Internal-use, cache-friendly revision information harvester."""
|
||||||
|
|
||||||
def _revinfo_helper(rev, include_changed_paths):
|
def _get_changed_paths(fsroot):
|
||||||
# Get the revision property info. (Would use
|
"""Return a 3-tuple: found_readable, found_unreadable, changed_paths."""
|
||||||
# editor.get_root_props(), but something is broken there...)
|
|
||||||
revprops = fs.revision_proplist(self.fs_ptr, rev)
|
|
||||||
msg = revprops.get(core.SVN_PROP_REVISION_LOG)
|
|
||||||
author = revprops.get(core.SVN_PROP_REVISION_AUTHOR)
|
|
||||||
datestr = revprops.get(core.SVN_PROP_REVISION_DATE)
|
|
||||||
date = _datestr_to_date(datestr)
|
|
||||||
|
|
||||||
# Optimization: If our caller doesn't care about the changed
|
|
||||||
# paths, and we don't need them to do authz determinations, let's
|
|
||||||
# get outta here.
|
|
||||||
if self.auth is None and not include_changed_paths:
|
|
||||||
return date, author, msg, None
|
|
||||||
|
|
||||||
# If we get here, then we either need the changed paths because we
|
|
||||||
# were asked for them, or we need them to do authorization checks.
|
|
||||||
# Either way, we need 'em, so let's get 'em.
|
|
||||||
fsroot = self._getroot(rev)
|
|
||||||
editor = repos.ChangeCollector(self.fs_ptr, fsroot)
|
editor = repos.ChangeCollector(self.fs_ptr, fsroot)
|
||||||
e_ptr, e_baton = delta.make_editor(editor)
|
e_ptr, e_baton = delta.make_editor(editor)
|
||||||
repos.svn_repos_replay(fsroot, e_ptr, e_baton)
|
repos.svn_repos_replay(fsroot, e_ptr, e_baton)
|
||||||
@@ -644,7 +630,8 @@ class LocalSubversionRepository(vclib.Repository):
|
|||||||
if vclib.check_path_access(self, parts, pathtype, rev):
|
if vclib.check_path_access(self, parts, pathtype, rev):
|
||||||
if is_copy and change.base_path and (change.base_path != path):
|
if is_copy and change.base_path and (change.base_path != path):
|
||||||
parts = _path_parts(change.base_path)
|
parts = _path_parts(change.base_path)
|
||||||
if not vclib.check_path_access(self, parts, pathtype, change.base_rev):
|
if not vclib.check_path_access(self, parts, pathtype,
|
||||||
|
change.base_rev):
|
||||||
is_copy = 0
|
is_copy = 0
|
||||||
change.base_path = None
|
change.base_path = None
|
||||||
change.base_rev = None
|
change.base_rev = None
|
||||||
@@ -656,24 +643,108 @@ class LocalSubversionRepository(vclib.Repository):
|
|||||||
found_readable = 1
|
found_readable = 1
|
||||||
else:
|
else:
|
||||||
found_unreadable = 1
|
found_unreadable = 1
|
||||||
|
return found_readable, found_unreadable, changedpaths.values()
|
||||||
|
|
||||||
|
def _get_change_copyinfo(fsroot, path, change):
|
||||||
|
if hasattr(change, 'copyfrom_known') and change.copyfrom_known:
|
||||||
|
copyfrom_path = change.copyfrom_path
|
||||||
|
copyfrom_rev = change.copyfrom_rev
|
||||||
|
else:
|
||||||
|
copyfrom_rev, copyfrom_path = fs.copied_from(fsroot, path)
|
||||||
|
return copyfrom_path, copyfrom_rev
|
||||||
|
|
||||||
|
def _simple_auth_check(fsroot):
|
||||||
|
"""Return a 2-tuple: found_readable, found_unreadable."""
|
||||||
|
found_unreadable = found_readable = 0
|
||||||
|
if hasattr(fs, 'paths_changed2'):
|
||||||
|
changes = fs.paths_changed2(fsroot)
|
||||||
|
else:
|
||||||
|
changes = fs.paths_changed(fsroot)
|
||||||
|
paths = changes.keys()
|
||||||
|
for path in paths:
|
||||||
|
change = changes[path]
|
||||||
|
pathtype = None
|
||||||
|
if hasattr(change, 'node_kind'):
|
||||||
|
if change.node_kind == core.svn_node_file:
|
||||||
|
pathtype = vclib.FILE
|
||||||
|
elif change.node_kind == core.svn_node_dir:
|
||||||
|
pathtype = vclib.DIR
|
||||||
|
parts = _path_parts(path)
|
||||||
|
if pathtype is None:
|
||||||
|
# Figure out the pathtype so we can query the authz subsystem.
|
||||||
|
if change.change_kind == fs.path_change_delete:
|
||||||
|
# Deletions are annoying, because they might be underneath
|
||||||
|
# copies (make their previous location non-trivial).
|
||||||
|
prev_parts = parts
|
||||||
|
prev_rev = rev - 1
|
||||||
|
parent_parts = parts[:-1]
|
||||||
|
while parent_parts:
|
||||||
|
parent_path = '/' + self._getpath(parent_parts)
|
||||||
|
parent_change = changes.get(parent_path)
|
||||||
|
if not (parent_change and \
|
||||||
|
(parent_change.change_kind == fs.path_change_add or
|
||||||
|
parent_change.change_kind == fs.path_change_replace)):
|
||||||
|
del(parent_parts[-1])
|
||||||
|
continue
|
||||||
|
copyfrom_path, copyfrom_rev = \
|
||||||
|
_get_change_copyinfo(fsroot, parent_path, parent_change)
|
||||||
|
if copyfrom_path:
|
||||||
|
prev_rev = copyfrom_rev
|
||||||
|
prev_parts = _path_parts(copyfrom_path) + \
|
||||||
|
parts[len(parent_parts):]
|
||||||
|
break
|
||||||
|
del(parent_parts[-1])
|
||||||
|
pathtype = self._gettype(self._getpath(prev_parts), prev_rev)
|
||||||
|
else:
|
||||||
|
pathtype = self._gettype(self._getpath(parts), rev)
|
||||||
|
if vclib.check_path_access(self, parts, pathtype, rev):
|
||||||
|
found_readable = 1
|
||||||
|
copyfrom_path, copyfrom_rev = \
|
||||||
|
_get_change_copyinfo(fsroot, path, change)
|
||||||
|
if copyfrom_path and copyfrom_path != path:
|
||||||
|
parts = _path_parts(copyfrom_path)
|
||||||
|
if not vclib.check_path_access(self, parts, pathtype,
|
||||||
|
copyfrom_rev):
|
||||||
|
found_unreadable = 1
|
||||||
|
else:
|
||||||
|
found_unreadable = 1
|
||||||
|
if found_readable and found_unreadable:
|
||||||
|
break
|
||||||
|
return found_readable, found_unreadable
|
||||||
|
|
||||||
|
def _revinfo_helper(rev, include_changed_paths):
|
||||||
|
# Get the revision property info. (Would use
|
||||||
|
# editor.get_root_props(), but something is broken there...)
|
||||||
|
revprops = fs.revision_proplist(self.fs_ptr, rev)
|
||||||
|
msg, author, date, revprops = _split_revprops(revprops)
|
||||||
|
|
||||||
# If our caller doesn't care about changed paths, we must be
|
# Optimization: If our caller doesn't care about the changed
|
||||||
# here for authz reasons only. That means the minute we've
|
# paths, and we don't need them to do authz determinations, let's
|
||||||
# found both a readable and an unreadable path, we can bail out.
|
# get outta here.
|
||||||
if (not include_changed_paths) and found_readable and found_unreadable:
|
if self.auth is None and not include_changed_paths:
|
||||||
return date, author, None, None
|
return date, author, msg, revprops, None
|
||||||
|
|
||||||
|
# If we get here, then we either need the changed paths because we
|
||||||
|
# were asked for them, or we need them to do authorization checks.
|
||||||
|
#
|
||||||
|
# If we only need them for authorization checks, though, we
|
||||||
|
# won't bother generating fully populated ChangedPath items (the
|
||||||
|
# cost is too great).
|
||||||
|
fsroot = self._getroot(rev)
|
||||||
|
if include_changed_paths:
|
||||||
|
found_readable, found_unreadable, changedpaths = \
|
||||||
|
_get_changed_paths(fsroot)
|
||||||
|
else:
|
||||||
|
changedpaths = None
|
||||||
|
found_readable, found_unreadable = _simple_auth_check(fsroot)
|
||||||
|
|
||||||
# Okay, we've process all our paths. Let's filter our metadata,
|
# Filter our metadata where necessary, and return the requested data.
|
||||||
# and return the requested data.
|
|
||||||
if found_unreadable:
|
if found_unreadable:
|
||||||
msg = None
|
msg = None
|
||||||
if not found_readable:
|
if not found_readable:
|
||||||
author = None
|
author = None
|
||||||
date = None
|
date = None
|
||||||
if include_changed_paths:
|
return date, author, msg, revprops, changedpaths
|
||||||
return date, author, msg, changedpaths.values()
|
|
||||||
else:
|
|
||||||
return date, author, msg, None
|
|
||||||
|
|
||||||
# Consult the revinfo cache first. If we don't have cached info,
|
# Consult the revinfo cache first. If we don't have cached info,
|
||||||
# or our caller wants changed paths and we don't have those for
|
# or our caller wants changed paths and we don't have those for
|
||||||
@@ -681,45 +752,55 @@ class LocalSubversionRepository(vclib.Repository):
|
|||||||
rev = self._getrev(rev)
|
rev = self._getrev(rev)
|
||||||
cached_info = self._revinfo_cache.get(rev)
|
cached_info = self._revinfo_cache.get(rev)
|
||||||
if not cached_info \
|
if not cached_info \
|
||||||
or (include_changed_paths and cached_info[3] is None):
|
or (include_changed_paths and cached_info[4] is None):
|
||||||
cached_info = _revinfo_helper(rev, include_changed_paths)
|
cached_info = _revinfo_helper(rev, include_changed_paths)
|
||||||
self._revinfo_cache[rev] = cached_info
|
self._revinfo_cache[rev] = cached_info
|
||||||
return cached_info[0], cached_info[1], cached_info[2], cached_info[3]
|
return tuple(cached_info)
|
||||||
|
|
||||||
def revinfo(self, rev):
|
def _log_helper(self, path, rev, lockinfo):
|
||||||
return self._revinfo(rev, 1)
|
rev_root = fs.revision_root(self.fs_ptr, rev)
|
||||||
|
copyfrom_rev, copyfrom_path = fs.copied_from(rev_root, path)
|
||||||
def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
|
date, author, msg, revprops, changes = self._revinfo(rev)
|
||||||
p1 = self._getpath(path_parts1)
|
if fs.is_file(rev_root, path):
|
||||||
p2 = self._getpath(path_parts2)
|
size = fs.file_length(rev_root, path)
|
||||||
r1 = self._getrev(rev1)
|
else:
|
||||||
r2 = self._getrev(rev2)
|
size = None
|
||||||
if not vclib.check_path_access(self, path_parts1, vclib.FILE, rev1):
|
return Revision(rev, date, author, msg, size, lockinfo, path,
|
||||||
raise vclib.ItemNotFound(path_parts1)
|
copyfrom_path and _cleanup_path(copyfrom_path),
|
||||||
if not vclib.check_path_access(self, path_parts2, vclib.FILE, rev2):
|
copyfrom_rev)
|
||||||
raise vclib.ItemNotFound(path_parts2)
|
|
||||||
|
|
||||||
args = vclib._diff_args(type, options)
|
|
||||||
|
|
||||||
def _date_from_rev(rev):
|
def _get_history(self, path, rev, path_type, limit=0, options={}):
|
||||||
date, author, msg, changes = self._revinfo(rev)
|
if self.youngest == 0:
|
||||||
return date
|
return []
|
||||||
|
|
||||||
|
rev_paths = []
|
||||||
|
fsroot = self._getroot(rev)
|
||||||
|
show_all_logs = options.get('svn_show_all_dir_logs', 0)
|
||||||
|
if not show_all_logs:
|
||||||
|
# See if the path is a file or directory.
|
||||||
|
kind = fs.check_path(fsroot, path)
|
||||||
|
if kind is core.svn_node_file:
|
||||||
|
show_all_logs = 1
|
||||||
|
|
||||||
|
# Instantiate a NodeHistory collector object, and use it to collect
|
||||||
|
# history items for PATH@REV.
|
||||||
|
history = NodeHistory(self.fs_ptr, show_all_logs, limit)
|
||||||
try:
|
try:
|
||||||
temp1 = temp_checkout(self, p1, r1)
|
repos.svn_repos_history(self.fs_ptr, path, history.add_history,
|
||||||
temp2 = temp_checkout(self, p2, r2)
|
1, rev, options.get('svn_cross_copies', 0))
|
||||||
info1 = p1, _date_from_rev(r1), r1
|
|
||||||
info2 = p2, _date_from_rev(r2), r2
|
|
||||||
return vclib._diff_fp(temp1, temp2, info1, info2, self.diff_cmd, args)
|
|
||||||
except core.SubversionException, e:
|
except core.SubversionException, e:
|
||||||
_fix_subversion_exception(e)
|
_fix_subversion_exception(e)
|
||||||
if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
|
if e.apr_err != _SVN_ERR_CEASE_INVOCATION:
|
||||||
raise vclib.InvalidRevision
|
raise
|
||||||
raise
|
|
||||||
|
|
||||||
def isexecutable(self, path_parts, rev):
|
# Now, iterate over those history items, checking for changes of
|
||||||
props = self.itemprops(path_parts, rev) # does authz-check
|
# location, pruning as necessitated by authz rules.
|
||||||
return props.has_key(core.SVN_PROP_EXECUTABLE)
|
for hist_rev, hist_path in history:
|
||||||
|
path_parts = _path_parts(hist_path)
|
||||||
|
if not vclib.check_path_access(self, path_parts, path_type, hist_rev):
|
||||||
|
break
|
||||||
|
rev_paths.append([hist_rev, hist_path])
|
||||||
|
return rev_paths
|
||||||
|
|
||||||
def _getpath(self, path_parts):
|
def _getpath(self, path_parts):
|
||||||
return string.join(path_parts, '/')
|
return string.join(path_parts, '/')
|
||||||
@@ -728,8 +809,11 @@ class LocalSubversionRepository(vclib.Repository):
|
|||||||
if rev is None or rev == 'HEAD':
|
if rev is None or rev == 'HEAD':
|
||||||
return self.youngest
|
return self.youngest
|
||||||
try:
|
try:
|
||||||
|
if type(rev) == type(''):
|
||||||
|
while rev[0] == 'r':
|
||||||
|
rev = rev[1:]
|
||||||
rev = int(rev)
|
rev = int(rev)
|
||||||
except ValueError:
|
except:
|
||||||
raise vclib.InvalidRevision(rev)
|
raise vclib.InvalidRevision(rev)
|
||||||
if (rev < 0) or (rev > self.youngest):
|
if (rev < 0) or (rev > self.youngest):
|
||||||
raise vclib.InvalidRevision(rev)
|
raise vclib.InvalidRevision(rev)
|
||||||
@@ -742,7 +826,20 @@ class LocalSubversionRepository(vclib.Repository):
|
|||||||
r = self._fsroots[rev] = fs.revision_root(self.fs_ptr, rev)
|
r = self._fsroots[rev] = fs.revision_root(self.fs_ptr, rev)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
##--- custom --##
|
def _gettype(self, path, rev):
|
||||||
|
# Similar to itemtype(), but without the authz check. Returns
|
||||||
|
# None for missing paths.
|
||||||
|
try:
|
||||||
|
kind = fs.check_path(self._getroot(rev), path)
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
if kind == core.svn_node_dir:
|
||||||
|
return vclib.DIR
|
||||||
|
if kind == core.svn_node_file:
|
||||||
|
return vclib.FILE
|
||||||
|
return None
|
||||||
|
|
||||||
|
##--- custom ---##
|
||||||
|
|
||||||
def get_youngest_revision(self):
|
def get_youngest_revision(self):
|
||||||
return self.youngest
|
return self.youngest
|
||||||
|
916
lib/viewvc.py
916
lib/viewvc.py
File diff suppressed because it is too large
Load Diff
@@ -27,7 +27,9 @@ numbers, and not literal):
|
|||||||
3. Verify that copyright years are correct in both the license-1.html
|
3. Verify that copyright years are correct in both the license-1.html
|
||||||
file and the source code.
|
file and the source code.
|
||||||
|
|
||||||
4. Update and commit the 'CHANGES' file.
|
4. Update and commit the 'CHANGES' file, using any available crystal
|
||||||
|
balls or other forward-looking devices to take a stab at the
|
||||||
|
release date.
|
||||||
|
|
||||||
5. Test, test, test! There is no automatic testsuite available. So
|
5. Test, test, test! There is no automatic testsuite available. So
|
||||||
just run with permuting different `viewvc.conf' settings... and
|
just run with permuting different `viewvc.conf' settings... and
|
||||||
@@ -38,50 +40,76 @@ numbers, and not literal):
|
|||||||
should exactly reflect what you wish to distribute and dub "the
|
should exactly reflect what you wish to distribute and dub "the
|
||||||
release".
|
release".
|
||||||
|
|
||||||
7. Edit the file 'lib/viewvc.py' and remove the "-dev" suffix from
|
7. Update your release branch working copy to HEAD.
|
||||||
|
|
||||||
|
svn up
|
||||||
|
|
||||||
|
8. 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,
|
__version__. The remainder should be of the form "X.Y.Z", where X,
|
||||||
Y, and Z are positive integers. Do NOT commit this change.
|
Y, and Z are positive integers.
|
||||||
|
|
||||||
8. Update your working copy to HEAD, and tag the release:
|
*** Do NOT commit this change. ***
|
||||||
|
|
||||||
svn update
|
9. "Peg" the contributed templates externals definition to the
|
||||||
svn cp -m "Tag the X.Y.Z final release." . \
|
current HEAD revision:
|
||||||
http://viewvc.tigris.org/svn/viewvc/tags/X.Y.Z
|
|
||||||
|
|
||||||
9. Go into an empty directory and run the 'make-release' script:
|
svn pedit svn:externals .
|
||||||
|
|
||||||
|
(squeeze "-rBASE_REV", where BASE_REV is the current HEAD revision
|
||||||
|
number, between 'templates-contrib' and the target URL).
|
||||||
|
|
||||||
|
*** Do NOT commit this change. ***
|
||||||
|
|
||||||
|
10. Tag the release:
|
||||||
|
|
||||||
|
svn cp -m "Tag the X.Y.Z final release." . ^/tags/X.Y.Z
|
||||||
|
|
||||||
|
This will create a copy of the release branch, plus your local
|
||||||
|
modifications to the svn:externals property and lib/viewvc.py
|
||||||
|
file, to the tag location.
|
||||||
|
|
||||||
|
11. Revert the changes in your working copy.
|
||||||
|
|
||||||
|
svn revert -R .
|
||||||
|
|
||||||
|
12. Go into an empty directory and run the 'make-release' script:
|
||||||
|
|
||||||
tools/make-release viewvc-X.Y.Z tags/X.Y.Z
|
tools/make-release viewvc-X.Y.Z tags/X.Y.Z
|
||||||
|
|
||||||
10. Verify the archive files:
|
13. Verify the archive files:
|
||||||
|
|
||||||
- do they have a LICENSE.html file?
|
- do they have a LICENSE.html file?
|
||||||
- do they have necessary include documentation?
|
- do they have necessary include documentation?
|
||||||
- do they *not* have unnecessary stuff?
|
- do they *not* have unnecessary stuff?
|
||||||
- do they install and work correctly?
|
- do they install and work correctly?
|
||||||
|
|
||||||
11. Upload the created archive files (tar.gz and zip) into the Files
|
14. Upload the created archive files (tar.gz and zip) into the Files
|
||||||
and Documents section of the Tigris.org project, and modify the
|
and Documents section of the Tigris.org project, and modify the
|
||||||
CHECKSUMS document there accordingly. Also, drop a copy of the
|
CHECKSUMS document there accordingly:
|
||||||
archive files into the root directory of the viewvc.org website
|
|
||||||
(unversioned).
|
|
||||||
|
|
||||||
12. On trunk, update the websites (both the viewvc.org/ and www/ ones)
|
http://viewvc.tigris.org/servlets/ProjectDocumentList?folderID=6004
|
||||||
|
|
||||||
|
Also, drop a copy of the archive files into the root directory of
|
||||||
|
the viewvc.org website (unversioned).
|
||||||
|
|
||||||
|
15. On trunk, update the websites (both the viewvc.org/ and www/ ones)
|
||||||
to refer to the new release files, and copy the CHANGES for the
|
to refer to the new release files, and copy the CHANGES for the
|
||||||
new release into trunk's CHANGES file.
|
new release into trunk's CHANGES file.
|
||||||
|
|
||||||
13. Edit the file 'lib/viewvc.py' again, re-adding the "-dev" suffix
|
16. Edit the file 'lib/viewvc.py' again, incrementing the patch number
|
||||||
and incrementing the patch number assigned to the __version__
|
assigned to the __version__ variable. Add a new empty block in
|
||||||
variable, and add a new empty block in the branch's CHANGES file,
|
the branch's CHANGES file. Commit your changes:
|
||||||
and commit:
|
|
||||||
|
|
||||||
svn ci -m "Begin a new release cycle."
|
svn ci -m "Begin a new release cycle."
|
||||||
|
|
||||||
14. Edit the Issue Tracker configuration options, adding a new Version
|
17. Edit the Issue Tracker configuration options, adding a new Version
|
||||||
for the just-released one, and a new Milestone for the next patch
|
for the just-released one, and a new Milestone for the next patch
|
||||||
(and possibly, minor or major) release. (For the Milestone sort
|
(and possibly, minor or major) release. (For the Milestone sort
|
||||||
key, use a packed integer XXYYZZ: 1.0.3 == 10003, 2.11.4 == 21104.)
|
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
|
http://viewvc.tigris.org/issues/editversions.cgi?component=viewvc&action=add
|
||||||
post it to the announce@ list, to the project's News area, and to
|
http://viewvc.tigris.org/issues/editmilestones.cgi?component=viewvc&action=add
|
||||||
other places interested in this sort of stuff, such as Freshmeat
|
|
||||||
(http://www.freshmeat.net).
|
18. Send to the announce@ list a message explaining all the cool new
|
||||||
|
features, and post similar announcements to other places interested
|
||||||
|
in this sort of stuff, such as Freshmeat (http://www.freshmeat.net).
|
||||||
|
@@ -21,13 +21,13 @@
|
|||||||
<th style="width:6%;"></th>
|
<th style="width:6%;"></th>
|
||||||
<th style="width:47%; vertical-align:top;">
|
<th style="width:47%; vertical-align:top;">
|
||||||
[is left.path right.path][else][left.path][end]
|
[is left.path right.path][else][left.path][end]
|
||||||
revision [if-any left_view_href]<a href="[left_view_href]">[end][left.rev][if-any left_view_href]</a>[end],
|
revision [if-any left_view_href]<a href="[left_view_href]">[end][left.rev][if-any left_view_href]</a>[end][if-any left.author] by <em>[left.author]</em>[end],
|
||||||
[left.date]
|
[left.date]
|
||||||
[if-any left.tag]<br />Tag: [left.tag][end]
|
[if-any left.tag]<br />Tag: [left.tag][end]
|
||||||
</th>
|
</th>
|
||||||
<th style="width:47%; vertical-align:top;">
|
<th style="width:47%; vertical-align:top;">
|
||||||
[is left.path right.path][else][right.path][end]
|
[is left.path right.path][else][right.path][end]
|
||||||
revision [if-any right_view_href]<a href="[right_view_href]">[end][right.rev][if-any right_view_href]</a>[end],
|
revision [if-any right_view_href]<a href="[right_view_href]">[end][right.rev][if-any right_view_href]</a>[end][if-any right.author] by <em>[right.author]</em>[end],
|
||||||
[right.date]
|
[right.date]
|
||||||
[if-any right.tag]<br />Tag: [right.tag][end]
|
[if-any right.tag]<br />Tag: [right.tag][end]
|
||||||
</th>
|
</th>
|
||||||
|
@@ -94,9 +94,6 @@ form { margin: 0; }
|
|||||||
.vc_properties {
|
.vc_properties {
|
||||||
margin: 1em 0;
|
margin: 1em 0;
|
||||||
}
|
}
|
||||||
.vc_properties h2 {
|
|
||||||
font-size: 115%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*** File Content Markup Styles ***/
|
/*** File Content Markup Styles ***/
|
||||||
@@ -274,6 +271,12 @@ table.vc_idiff tbody th {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*** Graph Display Form ***/
|
/*** Warning! ***/
|
||||||
.vc_graph_form {
|
.vc_warning {
|
||||||
|
border-width: 1px 2px 2px 2px;
|
||||||
|
border-color: black;
|
||||||
|
border-style: solid;
|
||||||
|
background-color: red;
|
||||||
|
color: white;
|
||||||
|
padding: 0.5em;
|
||||||
}
|
}
|
||||||
|
@@ -71,9 +71,9 @@ Revision [if-any revision_href]<a href="[revision_href]"><strong>[rev]</strong><
|
|||||||
[if-any image_src_href][define hide_binary_garbage]0[end][end]
|
[if-any image_src_href][define hide_binary_garbage]0[end][end]
|
||||||
|
|
||||||
[is hide_binary_garbage "1"]
|
[is hide_binary_garbage "1"]
|
||||||
<p><strong>This file's contents are not viewable. Please
|
<p><strong>This file's contents are not viewable.
|
||||||
<a href="[download_href]">download</a> this version of the
|
[if-any download_href]Please <a href="[download_href]">download</a>
|
||||||
file in order to view it.</strong></p>
|
this version of the file in order to view it.[end]</strong></p>
|
||||||
[else]
|
[else]
|
||||||
|
|
||||||
[define last_rev]0[end]
|
[define last_rev]0[end]
|
||||||
|
@@ -15,78 +15,4 @@
|
|||||||
alt="Revisions of [where]" />
|
alt="Revisions of [where]" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
[define graph_disp_opts][end]
|
|
||||||
[if-any opt_gflip][define graph_disp_opts]1[end][end]
|
|
||||||
[if-any opt_gbbox][define graph_disp_opts]1[end][end]
|
|
||||||
[if-any opt_gleft][define graph_disp_opts]1[end][end]
|
|
||||||
|
|
||||||
[define graph_user_opts][end]
|
|
||||||
[if-any graph_disp_opts][define graph_user_opts]1[end][end]
|
|
||||||
[if-any opt_gshow][define graph_user_opts]1[end][end]
|
|
||||||
[if-any opt_gmaxtag][define graph_user_opts]1[end][end]
|
|
||||||
|
|
||||||
[if-any graph_user_opts]
|
|
||||||
|
|
||||||
<form method="get" action="[graph_action]">
|
|
||||||
<div class="vc_graph_form">
|
|
||||||
[for graph_hidden_values]<input type="hidden" name="[graph_hidden_values.name]" value="[graph_hidden_values.value]"/>[end]
|
|
||||||
|
|
||||||
[is graph_disp_opts "1"]
|
|
||||||
<p><strong>Graph display options:</strong></p>
|
|
||||||
<table class="auto">
|
|
||||||
[if-any opt_gflip]
|
|
||||||
<tr>
|
|
||||||
<td><input id="gflip" type="checkbox" name="gflip" value="1"[if-any gflip] checked="checked"[end] /></td>
|
|
||||||
<td style="text-align: left;"><label for="gflip">Flip the graph</label></td>
|
|
||||||
</tr>
|
|
||||||
[end]
|
|
||||||
[if-any opt_gbbox]
|
|
||||||
<tr>
|
|
||||||
<td><input id="gbbox" type="checkbox" name="gbbox" value="1"[if-any gbbox] checked="checked"[end] /></td>
|
|
||||||
<td style="text-align: left;"><label for="gbbox">Add a branch box at the tip of each branch</label></td>
|
|
||||||
</tr>
|
|
||||||
[end]
|
|
||||||
[if-any opt_gleft]
|
|
||||||
<tr>
|
|
||||||
<td><input id="gleft" type="checkbox" name="gleft" value="1"[if-any gleft] checked="checked"[end] /></td>
|
|
||||||
<td style="text-align: left;"><label for="gleft">Draw tree left-to-right (instead of top-to-bottom)</label></td>
|
|
||||||
</tr>
|
|
||||||
[end]
|
|
||||||
</table>
|
|
||||||
[end]
|
|
||||||
|
|
||||||
[if-any opt_gshow]
|
|
||||||
<p><strong>Revision display options:</strong></p>
|
|
||||||
<table class="auto">
|
|
||||||
<tr>
|
|
||||||
<td><input id="gshow_all" type="radio" name="gshow" value="all"[is gshow "all"] checked="checked"[end] /></td>
|
|
||||||
<td style="text-align: left;"><label for="gshow_all">Show all revisions</label></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><input id="gshow_inittagged" type="radio" name="gshow" value="inittagged"[is gshow "inittagged"] checked="checked"[end] /></td>
|
|
||||||
<td style="text-align: left;"><label for="gshow_inittagged">Show only tagged and initial untagged revisions</label></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><input id="gshow_tagged" type="radio" name="gshow" value="tagged"[is gshow "tagged"] checked="checked"[end] /></td>
|
|
||||||
<td style="text-align: left;"><label for="gshow_tagged">Show only tagged revisions</label></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
[end]
|
|
||||||
|
|
||||||
[if-any opt_gmaxtag]
|
|
||||||
<p><strong>Tag limitation:</strong></p>
|
|
||||||
<table class="auto">
|
|
||||||
<tr>
|
|
||||||
<td><input id="gmaxtag" type="text" size="3" name="gmaxtag" value="[gmaxtag]" /></td>
|
|
||||||
<td style="text-align: left;"><label for="gmaxtag">Maximum number of tags to display (0=all)</label></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
[end]
|
|
||||||
|
|
||||||
<input type="submit" value="Refresh" />
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
[end]
|
|
||||||
|
|
||||||
[include "include/footer.ezt"]
|
[include "include/footer.ezt"]
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td>[if-any cfg.general.address]<address><a href="mailto:[cfg.general.address]">[cfg.general.address]</a></address>[else] [end]</td>
|
<td>[if-any cfg.general.address]<address><a href="mailto:[cfg.general.address]">[cfg.general.address]</a></address>[else] [end]</td>
|
||||||
<td style="text-align: right;"><strong><a href="[help_href]">ViewVC Help</a></strong></td>
|
<td style="text-align: right;">[if-any help_href]<strong><a href="[help_href]">ViewVC Help</a></strong>[else] [end]</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Powered by <a href="http://viewvc.tigris.org/">ViewVC [vsn]</a></td>
|
<td>Powered by <a href="http://viewvc.tigris.org/">ViewVC [vsn]</a></td>
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<title>[if-any rootname][[][rootname]][else]ViewVC[end] [page_title]</title>
|
<title>[if-any rootname][[][rootname]][else]ViewVC[end] [page_title]</title>
|
||||||
<meta name="generator" content="ViewVC [vsn]" />
|
<meta name="generator" content="ViewVC [vsn]" />
|
||||||
<link rel="shortcut icon" href="[docroot]/images/favicon.ico" type="image/x-icon" />
|
<link rel="shortcut icon" href="[docroot]/images/favicon.ico" />
|
||||||
<link rel="stylesheet" href="[docroot]/styles.css" type="text/css" />
|
<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>
|
</head>
|
||||||
|
@@ -4,13 +4,13 @@
|
|||||||
<!-- ViewVC :: http://www.viewvc.org/ -->
|
<!-- ViewVC :: http://www.viewvc.org/ -->
|
||||||
<head>
|
<head>
|
||||||
<title>Checkin Database Query</title>
|
<title>Checkin Database Query</title>
|
||||||
<link rel="stylesheet" href="[docroot]/styles.css" type="text/css" />
|
[if-any docroot]<link rel="stylesheet" href="[docroot]/styles.css" type="text/css" />[end]
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
[# setup page definitions]
|
[# setup page definitions]
|
||||||
[define help_href][docroot]/help_query.html[end]
|
[define help_href][if-any docroot][docroot]/help_query.html[end][end]
|
||||||
[# end]
|
[# end]
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -158,7 +158,15 @@
|
|||||||
[is query "skipped"]
|
[is query "skipped"]
|
||||||
[else]
|
[else]
|
||||||
<p><strong>[num_commits]</strong> matches found.</p>
|
<p><strong>[num_commits]</strong> matches found.</p>
|
||||||
|
[if-any row_limit_reached]
|
||||||
|
<p class="vc_warning">WARNING: These query results have been
|
||||||
|
artificially limited by an administrative threshold value and do
|
||||||
|
<em>not</em> represent the entirety of the data set which matches
|
||||||
|
the query. Consider modifying your query to be more specific</a>,
|
||||||
|
using your version control tool's query capabilities, or asking
|
||||||
|
your administrator to raise the database response size
|
||||||
|
threshold.</p>
|
||||||
|
[end]
|
||||||
[if-any commits]
|
[if-any commits]
|
||||||
<table cellspacing="0" cellpadding="2">
|
<table cellspacing="0" cellpadding="2">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -202,21 +210,21 @@
|
|||||||
</td>
|
</td>
|
||||||
|
|
||||||
[# uncommment, if you want a separate Description column:
|
[# uncommment, if you want a separate Description column:
|
||||||
{if-index commits.files first{
|
{if-index commits.files first}
|
||||||
<td style="vertical-align:top;" rowspan="{commits.num_files}">
|
<td style="vertical-align:top;" rowspan="{commits.num_files}">
|
||||||
{commits.log}
|
{if-any commits.log}{commits.log}{else} {end}
|
||||||
</td>
|
</td>
|
||||||
{end}
|
{end}
|
||||||
|
|
||||||
(substitute brackets for the braces)
|
(substitute brackets for the braces)
|
||||||
]
|
]
|
||||||
</tr>
|
</tr>
|
||||||
[# and also take the following out in the "Description column"-case:]
|
[# and also take the following out in the "Description column" case:]
|
||||||
[if-index commits.files last]
|
[if-index commits.files last]
|
||||||
<tr class="vc_row_[if-index commits even]even[else]odd[end]">
|
<tr class="vc_row_[if-index commits even]even[else]odd[end]">
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td colspan="5"><strong>Log:</strong><br />
|
<td colspan="5"><strong>Log:</strong><br />
|
||||||
<pre class="vc_log">[commits.log]</pre></td>
|
<pre class="vc_log">[if-any commits.log][commits.log][else] [end]</pre></td>
|
||||||
</tr>
|
</tr>
|
||||||
[end]
|
[end]
|
||||||
[# ---]
|
[# ---]
|
||||||
|
@@ -7,6 +7,15 @@
|
|||||||
|
|
||||||
<p><strong>[english_query]</strong></p>
|
<p><strong>[english_query]</strong></p>
|
||||||
[# <!-- {sql} --> ]
|
[# <!-- {sql} --> ]
|
||||||
|
[if-any row_limit_reached]
|
||||||
|
<p class="vc_warning">WARNING: These query results have been
|
||||||
|
artificially limited by an administrative threshold value and do
|
||||||
|
<em>not</em> represent the entirety of the data set which matches
|
||||||
|
the query. Consider <a href="[queryform_href]">modifying your
|
||||||
|
query to be more specific</a>, using your version control tool's
|
||||||
|
query capabilities, or asking your administrator to raise the
|
||||||
|
database response size threshold.</p>
|
||||||
|
[end]
|
||||||
<p><a href="[queryform_href]">Modify query</a></p>
|
<p><a href="[queryform_href]">Modify query</a></p>
|
||||||
<p><a href="[backout_href]">Show commands which could be used to back out these changes</a></p>
|
<p><a href="[backout_href]">Show commands which could be used to back out these changes</a></p>
|
||||||
|
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
[include "include/header.ezt" "revision"]
|
[include "include/header.ezt" "revision"]
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<form method="get" action="[jump_rev_action]">
|
<form method="get" action="[jump_rev_action]">
|
||||||
<table cellspacing="1" cellpadding="2" style="width: auto;">
|
<table cellspacing="1" cellpadding="2" style="width: auto;">
|
||||||
<tr align="left">
|
<tr align="left">
|
||||||
@@ -42,7 +43,7 @@
|
|||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<p><strong>Changed paths:</strong></p>
|
<h2>Changed paths</h2>
|
||||||
|
|
||||||
<table cellspacing="1" cellpadding="2">
|
<table cellspacing="1" cellpadding="2">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -77,4 +78,5 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
[include "include/props.ezt"]
|
||||||
[include "include/footer.ezt"]
|
[include "include/footer.ezt"]
|
||||||
|
@@ -9,6 +9,12 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="vc_header_sort">Name</th>
|
<th class="vc_header_sort">Name</th>
|
||||||
|
[is cfg.options.show_roots_lastmod "1"]
|
||||||
|
<th class="vc_header">Revision</th>
|
||||||
|
<th class="vc_header">Age</th>
|
||||||
|
<th class="vc_header">Author</th>
|
||||||
|
<th class="vc_header">Log</th>
|
||||||
|
[end]
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
@@ -20,6 +26,12 @@
|
|||||||
<img src="[docroot]/images/dir.png" alt="" class="vc_icon" />
|
<img src="[docroot]/images/dir.png" alt="" class="vc_icon" />
|
||||||
[roots.name]</a>
|
[roots.name]</a>
|
||||||
</td>
|
</td>
|
||||||
|
[is cfg.options.show_roots_lastmod "1"]
|
||||||
|
<td style="width:20"> [if-any roots.log_href]<a href="[roots.log_href]">[roots.rev]</a>[else][roots.rev][end]</td>
|
||||||
|
<td style="width:20"> [roots.ago]</td>
|
||||||
|
<td style="width:20"> [roots.author]</td>
|
||||||
|
<td style="width:20"> [roots.short_log]</td>
|
||||||
|
[end]
|
||||||
</tr>
|
</tr>
|
||||||
[end]
|
[end]
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@@ -7,11 +7,11 @@
|
|||||||
<description>[is roottype "svn"]Subversion[else]CVS[end] commits to the[if-any where] [where] directory of the[end] [rootname] repository</description>
|
<description>[is roottype "svn"]Subversion[else]CVS[end] commits to the[if-any where] [where] directory of the[end] [rootname] repository</description>
|
||||||
|
|
||||||
[for commits]<item>
|
[for commits]<item>
|
||||||
<title>[if-any commits.rev][commits.rev]: [end][[commits.author]] [commits.short_log]</title>
|
<title>[if-any commits.rev][commits.rev]: [end][[commits.author]] [format "xml"][commits.short_log][end]</title>
|
||||||
[if-any commits.rss_url]<link>[commits.rss_url]</link>[end]
|
[if-any commits.rss_url]<link>[commits.rss_url]</link>[end]
|
||||||
<author>[commits.author]</author>
|
<author>[commits.author]</author>
|
||||||
<pubDate>[if-any commits.rss_date][commits.rss_date][else](unknown date)[end]</pubDate>
|
<pubDate>[if-any commits.rss_date][commits.rss_date][else](unknown date)[end]</pubDate>
|
||||||
<description><pre>[format "xml"][commits.log][end]</pre></description>
|
<description><pre>[format "xml"][format "html"][commits.log][end][end]</pre></description>
|
||||||
</item>[end]
|
</item>[end]
|
||||||
</channel>
|
</channel>
|
||||||
</rss>
|
</rss>
|
||||||
|
@@ -49,6 +49,10 @@ CLEAN_MODE = None
|
|||||||
FILE_INFO_LIST = [
|
FILE_INFO_LIST = [
|
||||||
("bin/cgi/viewvc.cgi", "bin/cgi/viewvc.cgi", 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/cgi/query.cgi", "bin/cgi/query.cgi", 0755, 1, 0, 0),
|
||||||
|
("bin/wsgi/viewvc.wsgi", "bin/wsgi/viewvc.wsgi", 0755, 1, 0, 0),
|
||||||
|
("bin/wsgi/viewvc.fcgi", "bin/wsgi/viewvc.fcgi", 0755, 1, 0, 0),
|
||||||
|
("bin/wsgi/query.wsgi", "bin/wsgi/query.wsgi", 0755, 1, 0, 0),
|
||||||
|
("bin/wsgi/query.fcgi", "bin/wsgi/query.fcgi", 0755, 1, 0, 0),
|
||||||
("bin/mod_python/viewvc.py", "bin/mod_python/viewvc.py", 0755, 1, 0, 0),
|
("bin/mod_python/viewvc.py", "bin/mod_python/viewvc.py", 0755, 1, 0, 0),
|
||||||
("bin/mod_python/query.py", "bin/mod_python/query.py", 0755, 1, 0, 0),
|
("bin/mod_python/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/handler.py", "bin/mod_python/handler.py", 0755, 1, 0, 0),
|
||||||
@@ -75,11 +79,12 @@ if sys.platform == "win32":
|
|||||||
## List of directories for installation.
|
## List of directories for installation.
|
||||||
## type (source path,
|
## type (source path,
|
||||||
## destination path,
|
## destination path,
|
||||||
|
## boolean -- optional item?,
|
||||||
## boolean -- prompt before replacing?)
|
## boolean -- prompt before replacing?)
|
||||||
TREE_LIST = [
|
TREE_LIST = [
|
||||||
("lib", "lib", 0),
|
("lib", "lib", 0, 0),
|
||||||
("templates", "templates", 1),
|
("templates", "templates", 0, 1),
|
||||||
("templates-contrib", "templates-contrib", 1),
|
("templates-contrib", "templates-contrib", 1, 1),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -204,6 +209,8 @@ def install_file(src_path, dst_path, mode, subst_path_vars,
|
|||||||
temp = raw_input("Do you want to [O]verwrite, [D]o "
|
temp = raw_input("Do you want to [O]verwrite, [D]o "
|
||||||
"not overwrite, or [V]iew "
|
"not overwrite, or [V]iew "
|
||||||
"differences? ")
|
"differences? ")
|
||||||
|
if len(temp) == 0:
|
||||||
|
continue
|
||||||
temp = string.lower(temp[0])
|
temp = string.lower(temp[0])
|
||||||
if temp == "v" and ext not in BINARY_FILE_EXTS:
|
if temp == "v" and ext not in BINARY_FILE_EXTS:
|
||||||
print """
|
print """
|
||||||
@@ -275,18 +282,22 @@ LEGEND
|
|||||||
py_compile.compile(destdir_path, destdir_path + "c" , dst_path)
|
py_compile.compile(destdir_path, destdir_path + "c" , dst_path)
|
||||||
|
|
||||||
|
|
||||||
def install_tree(src_path, dst_path, prompt_replace):
|
def install_tree(src_path, dst_path, is_optional, prompt_replace):
|
||||||
"""Install a tree whose source is at SRC_PATH (which is relative
|
"""Install a tree whose source is at SRC_PATH (which is relative
|
||||||
to the ViewVC source directory) into the location DST_PATH (which
|
to the ViewVC source directory) into the location DST_PATH (which
|
||||||
is relative both to the global ROOT_DIR and DESTDIR settings). If
|
is relative both to the global ROOT_DIR and DESTDIR settings). If
|
||||||
PROMPT_REPLACE is set (and is not overridden by global setting
|
PROMPT_REPLACE is set (and is not overridden by global setting
|
||||||
CLEAN_MODE), prompt the user for how to deal with already existing
|
CLEAN_MODE), prompt the user for how to deal with already existing
|
||||||
files that differ from the to-be-installed version."""
|
files that differ from the to-be-installed version. If
|
||||||
|
IS_OPTIONAL is set, don't fuss about a missing source item."""
|
||||||
|
|
||||||
orig_src_path = src_path
|
orig_src_path = src_path
|
||||||
orig_dst_path = dst_path
|
orig_dst_path = dst_path
|
||||||
src_path = _actual_src_path(src_path)
|
src_path = _actual_src_path(src_path)
|
||||||
dst_path = os.path.join(ROOT_DIR, string.replace(dst_path, '/', os.sep))
|
dst_path = os.path.join(ROOT_DIR, string.replace(dst_path, '/', os.sep))
|
||||||
|
if not os.path.isdir(src_path):
|
||||||
|
print " skipping %s" % (dst_path)
|
||||||
|
return
|
||||||
destdir_path = os.path.join(DESTDIR + dst_path)
|
destdir_path = os.path.join(DESTDIR + dst_path)
|
||||||
|
|
||||||
# Get a list of items in the directory.
|
# Get a list of items in the directory.
|
||||||
@@ -306,7 +317,7 @@ def install_tree(src_path, dst_path, prompt_replace):
|
|||||||
|
|
||||||
# If the item is a subdirectory, recurse. Otherwise, install the file.
|
# If the item is a subdirectory, recurse. Otherwise, install the file.
|
||||||
if os.path.isdir(os.path.join(src_path, fname)):
|
if os.path.isdir(os.path.join(src_path, fname)):
|
||||||
install_tree(orig_src_child, orig_dst_child, prompt_replace)
|
install_tree(orig_src_child, orig_dst_child, 0, prompt_replace)
|
||||||
else:
|
else:
|
||||||
set_paths = 0
|
set_paths = 0
|
||||||
compile_it = fname[-3:] == '.py'
|
compile_it = fname[-3:] == '.py'
|
||||||
|
@@ -1,9 +0,0 @@
|
|||||||
# Old documents.
|
|
||||||
RedirectPermanent /upgrading.html http://viewvc.tigris.org/nonav/source/browse/*checkout*/viewvc/trunk/docs/upgrading-howto.html
|
|
||||||
RedirectPermanent /template-authoring-guide.html http://viewvc.tigris.org/nonav/source/browse/*checkout*/viewvc/trunk/docs/template-authoring-guide.html
|
|
||||||
RedirectPermanent /url-reference.html http://viewvc.tigris.org/nonav/source/browse/*checkout*/viewvc/trunk/docs/url-reference.html
|
|
||||||
|
|
||||||
# The license-1.html file.
|
|
||||||
RedirectPermanent /license-1.html http://viewvc.tigris.org/nonav/source/browse/*checkout*/viewvc/trunk/LICENSE.html
|
|
||||||
|
|
||||||
|
|
@@ -1,93 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
||||||
<head>
|
|
||||||
<title>ViewVC: Contact</title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
|
||||||
<link rel="stylesheet" type="text/css" href="./styles.css"/>
|
|
||||||
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<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="./faq.html">FAQ</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-contacting-us">Contacting Us</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-contacting-us">Contacting Us</h2>
|
|
||||||
|
|
||||||
<div class="section-body">
|
|
||||||
|
|
||||||
<p>ViewVC is an <a href="http://www.opensource.org/">Open Source</a>
|
|
||||||
project, and all <a href="./contributing.html">contributions</a>
|
|
||||||
are welcome. Please send any comments, questions, or suggestions
|
|
||||||
to the <a
|
|
||||||
href="mailto:users@viewvc.tigris.org">ViewVC
|
|
||||||
users mailing list</a>. There is also a <a
|
|
||||||
href="mailto:dev@viewvc.tigris.org">mailing
|
|
||||||
list specifically for ViewVC developers</a>. You can subscribe to
|
|
||||||
these lists (and other project lists), as well view the list
|
|
||||||
archives, <a
|
|
||||||
href="http://viewvc.tigris.org/servlets/ProjectMailingListList"
|
|
||||||
>here</a>. If you are having problems with ViewVC, consider
|
|
||||||
checking our <a href="./faq.html">Frequently Asked Questions</a>
|
|
||||||
page and list of <a
|
|
||||||
href="http://viewvc.tigris.org/issues/buglist.cgi?component=viewvc&issue_status=UNCONFIRMED&issue_status=NEW&issue_status=STARTED&issue_status=REOPENED"
|
|
||||||
>open issues</a> before mail our users@ list — perhaps the
|
|
||||||
information you need is already available in one of those
|
|
||||||
places.</p>
|
|
||||||
|
|
||||||
<p>If you prefer interaction that's a little more real-time, use your
|
|
||||||
favorite IRC client to pop into <tt><a
|
|
||||||
href="irc://irc.freenode.net/viewvc">#viewvc</a></tt> on
|
|
||||||
irc.freenode.net.</p>
|
|
||||||
|
|
||||||
<p>So, to summarize:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>To discuss ViewVC installation, configuration, and behavior: users@viewvc.tigris.org</li>
|
|
||||||
<li>To discuss the development of ViewVC itself or submit patches: dev@viewvc.tigris.org</li>
|
|
||||||
<li>To discussion anything ViewVC-related in real time: irc.freenode.net, #viewvc</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</div> <!-- section-body -->
|
|
||||||
</div> <!-- section -->
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@@ -1,242 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
||||||
<head>
|
|
||||||
<title>ViewVC: Contributing</title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
|
||||||
<link rel="stylesheet" type="text/css" href="./styles.css"/>
|
|
||||||
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<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="./faq.html">FAQ</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-getting-started">Getting Started</a></li>
|
|
||||||
<li><a href="#sec-testing">Testing and Reporting</a></li>
|
|
||||||
<li><a href="#sec-coding-style">Coding Style</a></li>
|
|
||||||
<li><a href="#sec-patches">Submitting Patches</a></li>
|
|
||||||
<li><a href="#sec-security">Security</a></li>
|
|
||||||
<li><a href="#sec-adding-features">Adding Features</a></li>
|
|
||||||
<li><a href="#sec-templates">Hacking on Templates</a></li>
|
|
||||||
</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-getting-started">Getting Started</h2>
|
|
||||||
|
|
||||||
<div class="section-body">
|
|
||||||
|
|
||||||
<p>Some basic knowledge about <a
|
|
||||||
href="http://www.python.org">Python</a> and development tools like
|
|
||||||
<code>diff</code> is required. Your best bet is to start with a
|
|
||||||
fresh source code snapshot, which you may obtain from our
|
|
||||||
Subversion repository (see instructions <a
|
|
||||||
href="./download.html#sec-subversion">here</a>).</p>
|
|
||||||
|
|
||||||
<p>Version control history can be obtained using Subversion clients,
|
|
||||||
but is also browsable using <a
|
|
||||||
href="http://viewvc.tigris.org/source/browse/viewvc/trunk/"
|
|
||||||
>tigris.org's integrated ViewVC tool</a>.</p>
|
|
||||||
|
|
||||||
</div> <!-- section-body -->
|
|
||||||
</div> <!-- section -->
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
|
|
||||||
<h2 id="sec-testing">Testing and Reporting</h2>
|
|
||||||
|
|
||||||
<div class="section-body">
|
|
||||||
|
|
||||||
<p>Testing usability and the installation process on different
|
|
||||||
platforms is also a valuable contribution. Please report your
|
|
||||||
results back to us developers. Bandwidth is getting cheaper daily,
|
|
||||||
so don't be afraid — in fact, feel encouraged — to dump
|
|
||||||
as much detail about the problems you are seeing as possible into
|
|
||||||
your bug reports. Here are some things you definitely should
|
|
||||||
try to include:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
|
|
||||||
<li>What version of ViewVC you are using (if you are using a source
|
|
||||||
snapshot, tell us the date of that snapshot).</li>
|
|
||||||
|
|
||||||
<li>What operating system your ViewVC is running on.</li>
|
|
||||||
|
|
||||||
<li>What version of Python you are using.</li>
|
|
||||||
|
|
||||||
<li>Whether you are running ViewVC standalone, or as a CGI program
|
|
||||||
under a web server (and if so, what web server).</li>
|
|
||||||
|
|
||||||
<li>The URL of your ViewVC instantiation, if it is public.
|
|
||||||
Sometimes, letting developers see the problem for themselves can
|
|
||||||
save everyone alot of time.</li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</div> <!-- section-body -->
|
|
||||||
</div> <!-- section -->
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
|
|
||||||
<h2 id="sec-coding-style">Coding Style</h2>
|
|
||||||
|
|
||||||
<div class="section-body">
|
|
||||||
|
|
||||||
<p>Unlike its predecessor, CvsWeb, ViewVC is written in Python, so it
|
|
||||||
doesn't suffer from the "unmaintainable code effect" that hits most
|
|
||||||
Perl projects sooner or later:</p>
|
|
||||||
|
|
||||||
<blockquote>
|
|
||||||
|
|
||||||
<p>"[Perl] combines all the worst aspects of C and Lisp: a
|
|
||||||
billion different sublanguages in one monolithic executable. It
|
|
||||||
combines the power of C with the readability of
|
|
||||||
PostScript." — Jamie Zawinski
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</blockquote>
|
|
||||||
|
|
||||||
<p>Of course, a symphony of insanity can be composed in any language,
|
|
||||||
so we do try to stick to some basic guiding principles. Maintain
|
|
||||||
whatever style is present in the code being modified. New code can
|
|
||||||
use anything sane (which generally means <a
|
|
||||||
href="http://www.python.org/dev/peps/pep-0008/">PEP 8</a>).
|
|
||||||
Our only real peeve is if someone writes a function call as:
|
|
||||||
<code>some_func (args)</code> — that space between the
|
|
||||||
function name and opening parenthesis is Huge Badness. Oh, and we
|
|
||||||
do <strong>not</strong> use Subversion keywords (such as
|
|
||||||
<code>$</code><code>Id$</code>) within the source.</p>
|
|
||||||
|
|
||||||
<p>Otherwise… <em>shrug</em>.</p>
|
|
||||||
|
|
||||||
</div> <!-- section-body -->
|
|
||||||
</div> <!-- section -->
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
|
|
||||||
<h2 id="sec-patches">Submitting Patches</h2>
|
|
||||||
|
|
||||||
<div class="section-body">
|
|
||||||
|
|
||||||
<p>Nothing speaks more loudly when bugs or features are the topic than
|
|
||||||
a patch. And quite frankly, sometimes if you want something done,
|
|
||||||
you gotta do it yourself. So, patches are always welcome. If you
|
|
||||||
aren't sure what exactly a "patch" is, or don't know how
|
|
||||||
to generate one, but you've got code contributions to make, please
|
|
||||||
don't hesitate to ask questions on the mailing lists. Patch
|
|
||||||
generation and application are pretty easy thing to get the hang of,
|
|
||||||
and drastically simplify code submission and review.</p>
|
|
||||||
|
|
||||||
<p>Please use the <a
|
|
||||||
href="http://viewvc.tigris.org/servlets/ProjectIssues">Issue
|
|
||||||
Tracker</a> to submit your patches. Unified contextual diffs
|
|
||||||
against the latest development snapshot are preferred.</p>
|
|
||||||
|
|
||||||
<p>If you have commit access, then you should know what you're doing.
|
|
||||||
Just make changes directly. Subscribing to the <a
|
|
||||||
href="http://viewvc.tigris.org/servlets/ProjectMailingListList"
|
|
||||||
><tt>dev@</tt> developer mailing list</a> is recommended in any
|
|
||||||
case.</p>
|
|
||||||
|
|
||||||
</div> <!-- section-body -->
|
|
||||||
</div> <!-- section -->
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
|
|
||||||
<h2 id="sec-security">Security</h2>
|
|
||||||
|
|
||||||
<div class="section-body">
|
|
||||||
|
|
||||||
<p>Since ViewVC is used on the Internet, security is a major concern.
|
|
||||||
If you need to pass data from the request into an external program,
|
|
||||||
please don't use <code>os.system()</code> or
|
|
||||||
<code>os.popen()</code>. Please use the module
|
|
||||||
<code>lib/popen.py</code> that is included in the ViewVC
|
|
||||||
distribution instead.</p>
|
|
||||||
|
|
||||||
</div> <!-- section-body -->
|
|
||||||
</div> <!-- section -->
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
|
|
||||||
<h2 id="sec-adding-features">Adding Features</h2>
|
|
||||||
|
|
||||||
<div class="section-body">
|
|
||||||
|
|
||||||
<p>If you need a new configuration option think carefully, into which
|
|
||||||
section it belongs. Try to keep the content of
|
|
||||||
<code>cgi/viewvc.conf.dist</code> file and the library module
|
|
||||||
<code>lib/config.py</code> in sync.</p>
|
|
||||||
|
|
||||||
<p>Because ViewVC is a Web-based application, people will have ViewVC
|
|
||||||
URLs hyperlinked from other sites, embedded in emails, bookmarked
|
|
||||||
in their browsers, etc. It is very important to ensure that those
|
|
||||||
URLs continue to retrieve the information they were intended to
|
|
||||||
retrieve even if ViewVC is upgraded on the hosting server. In
|
|
||||||
other words, as new features require modifications to the <a
|
|
||||||
href="./url-reference.html">ViewVC URL schema</a>, make sure those
|
|
||||||
modifications preserve the existing functionality of all ViewVC
|
|
||||||
URLs.</p>
|
|
||||||
|
|
||||||
<p>The library subdirectory contains a module <code>debug.py</code>,
|
|
||||||
which you may find useful for performance testing.</p>
|
|
||||||
|
|
||||||
<p>If a new file or module is added, a new line in the installer
|
|
||||||
program <code>viewvc-install</code> is required.</p>
|
|
||||||
|
|
||||||
</div> <!-- section-body -->
|
|
||||||
</div> <!-- section -->
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
|
|
||||||
<h2 id="sec-templates">Hacking on Templates</h2>
|
|
||||||
|
|
||||||
<div class="section-body">
|
|
||||||
|
|
||||||
<p>The library module <code>ezt.py</code> contains a module docstring
|
|
||||||
which describes the directives used in the HTML templates used by
|
|
||||||
ViewVC. The templates themselves can be found in the
|
|
||||||
<code>templates</code> subdirectory. We're currently developing a
|
|
||||||
how-to guide for
|
|
||||||
<a href="http://viewvc.tigris.org/source/browse/viewvc/trunk/docs/template-authoring-guide.html?rev=HEAD"
|
|
||||||
>ViewVC template customization</a>.</p>
|
|
||||||
|
|
||||||
</div> <!-- section-body -->
|
|
||||||
</div> <!-- section -->
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@@ -1,121 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
||||||
<head>
|
|
||||||
<title>ViewVC: Download</title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
|
||||||
<link rel="stylesheet" type="text/css" href="./styles.css"/>
|
|
||||||
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<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="./faq.html">FAQ</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-download">Downloading</a></li>
|
|
||||||
<li><a href="#sec-subversion">Subversion Checkout</a></li>
|
|
||||||
<li><a href="#sec-upgrading">Upgrading</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-download">Downloading</h2>
|
|
||||||
|
|
||||||
<div class="section-body">
|
|
||||||
|
|
||||||
<p>You can download the latest release of ViewVC (and the older ViewVC
|
|
||||||
and ViewCVS releases, too) from our <a
|
|
||||||
href="http://viewvc.tigris.org/servlets/ProjectDocumentList?folderID=6004"
|
|
||||||
>Documents & Files</a> area. For information about what has
|
|
||||||
changed in each release, see the <a
|
|
||||||
href="http://viewvc.tigris.org/source/browse/viewvc/trunk/CHANGES?rev=HEAD"
|
|
||||||
>CHANGES</a> file.</p>
|
|
||||||
|
|
||||||
<p>We are also making <a href="./nightly/">nightly snapshots</a>
|
|
||||||
available in tar.gz and zip formats.</p>
|
|
||||||
|
|
||||||
</div> <!-- section-body -->
|
|
||||||
</div> <!-- section -->
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
|
|
||||||
<h2 id="sec-subversion">Subversion Checkout</h2>
|
|
||||||
|
|
||||||
<div class="section-body">
|
|
||||||
|
|
||||||
<p>The source code for ViewVC is maintained in a Subversion repository
|
|
||||||
at Tigris.org. You can checkout the trunk of our development tree
|
|
||||||
from <a href="http://viewvc.tigris.org/svn/viewvc/trunk/"
|
|
||||||
>http://viewvc.tigris.org/svn/viewvc/trunk/</a>. You'll
|
|
||||||
need to provide your Tigris.org username and password when so
|
|
||||||
prompted, or, if you don't have a Tigris.org account, use "guest"
|
|
||||||
as the username (with no, or an empty, password).</p>
|
|
||||||
|
|
||||||
</div> <!-- section-body -->
|
|
||||||
</div> <!-- section -->
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
|
|
||||||
<h2 id="sec-upgrading">Upgrading</h2>
|
|
||||||
|
|
||||||
<div class="section-body">
|
|
||||||
|
|
||||||
<p>We've tried to ensure that ViewVC URLs are stable, and that even
|
|
||||||
when we deprecate a particular URL syntax, we continue to support
|
|
||||||
the handling of it (using HTTP redirects to point browsers to the
|
|
||||||
new form of that URL). We know that ViewVC URLs get bookmarked,
|
|
||||||
and nobody likes when their bookmarked URLs suddenly stop working.</p>
|
|
||||||
|
|
||||||
<p>Across patch releases of ViewVC (when only the <em>Z</em> component
|
|
||||||
of <em>version X.Y.Z</em> changes), we do our best to keep the
|
|
||||||
configuration file syntax and template data dictionary unchanged,
|
|
||||||
too. This makes it much easier for folks who need to upgrade
|
|
||||||
quickly to get security or other bug fixes. But across major and
|
|
||||||
minor releases, all bets are off, and chances are good that we've
|
|
||||||
done some major plumbing. When upgrading your ViewVC instance
|
|
||||||
across major or minor version numbers, you'll almost certainly want
|
|
||||||
to consult our
|
|
||||||
<a href="http://viewvc.tigris.org/source/browse/viewvc/trunk/docs/upgrading-howto.html?rev=HEAD"
|
|
||||||
>upgrading HOWTO</a> for tips on how to migrate your configuration
|
|
||||||
files and any template customizations you've made into their new
|
|
||||||
formats.</p>
|
|
||||||
|
|
||||||
</div> <!-- section-body -->
|
|
||||||
</div> <!-- section -->
|
|
||||||
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@@ -1,394 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
||||||
<head>
|
|
||||||
<title>ViewVC: Frequently Asked Questions (FAQ)</title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
|
||||||
<link rel="stylesheet" type="text/css" href="./styles.css"/>
|
|
||||||
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<div id="title">
|
|
||||||
<a href="http://www.viewvc.org/"><img
|
|
||||||
src="./images/title.jpg" alt="ViewVC: Frequently Asked Questions (FAQ)"/></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="./faq.html">FAQ</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="#faq-q">Questions</a></li>
|
|
||||||
<li><a href="#faq-a">Answers</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="faq-q">Questions</h2>
|
|
||||||
<!-- ##################################################################### -->
|
|
||||||
|
|
||||||
<div class="section-body">
|
|
||||||
|
|
||||||
<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
|
|
||||||
<h3 class="faq-section" id="faq-q-general">General Usage</h3>
|
|
||||||
<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
|
|
||||||
<li><a href="#installation">Where does the installation documentation,
|
|
||||||
if any, live?</a></li>
|
|
||||||
|
|
||||||
<li><a href="#vhost-root">How can I expose ViewVC at the root of a
|
|
||||||
virtual host on my webserver?</a></li>
|
|
||||||
|
|
||||||
<li><a href="#authz-support">Does ViewVC support path-based
|
|
||||||
authorization, such as Subversion's authz-file mechanism?</a></li>
|
|
||||||
|
|
||||||
<li><a href="#missing-tmpdir">What causes "Error: OSError: [Errno 2] No such file
|
|
||||||
or directory: '/tmp/tmpGc-Ztj'"?</a></li>
|
|
||||||
|
|
||||||
<li><a href="#standalone-only">Why does <em>SOME-FEATURE</em>
|
|
||||||
work under standalone.py, but not under Apache (or IIS or
|
|
||||||
…)?</a></li>
|
|
||||||
|
|
||||||
<li><a href="#rss-support">How do I enable ViewVC's RSS feed
|
|
||||||
capabilities?</a></li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
|
|
||||||
<h3 class="faq-section" id="faq-q-cvs">CVS Browsing</h3>
|
|
||||||
<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
|
|
||||||
<li><a href="#error-displaying-cvs-files">Why can I navigate only those CVS
|
|
||||||
directories that have no files in them?</a></li>
|
|
||||||
|
|
||||||
<li><a href="#rlog-output-ended-early">What causes "Error: Rlog output ended
|
|
||||||
early. Expected RCS file "/opt/cvs/project/file,v""?</a></li>
|
|
||||||
|
|
||||||
<li><a href="#comalformedoutput">What causes "Error: COMalformedOutput: Unable to
|
|
||||||
find filename in co output stream"?</a></li>
|
|
||||||
|
|
||||||
<li><a href="#error-during-rlog">What causes "Error: error during
|
|
||||||
rlog: 0x100"?</a></li>
|
|
||||||
|
|
||||||
<li><a href="#missing-files">Why do my directories have no files in them?</a></li>
|
|
||||||
|
|
||||||
<li><a href="#none-match">ViewVC doesn't show files I'm looking for,
|
|
||||||
and instead displays the message "NOTE: There are N files, but
|
|
||||||
none match the current selection criteria". How can I fix this?</a></li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
|
|
||||||
<h3 class="faq-section" id="faq-q-svn">Subversion Browsing</h3>
|
|
||||||
<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
|
|
||||||
<li><a href="#no-module-named-svn">What causes "Error: ImportError: No module named
|
|
||||||
svn"?</a></li>
|
|
||||||
|
|
||||||
<li><a href="#remote-svn-access">Can I use ViewVC with remote
|
|
||||||
Subversion repositories?</a></li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
|
|
||||||
<!-- ##################################################################### -->
|
|
||||||
<h2 id="faq-a">Answers</h2>
|
|
||||||
<!-- ##################################################################### -->
|
|
||||||
|
|
||||||
<div class="section-body">
|
|
||||||
|
|
||||||
<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
|
|
||||||
<h3 class="faq-section" id="faq-a-general">General Usage</h3>
|
|
||||||
<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
|
|
||||||
|
|
||||||
<div id="installation">
|
|
||||||
<p class="faq-atitle">Where does the installation documentation, if
|
|
||||||
any, live?</p>
|
|
||||||
|
|
||||||
<p>ViewVC's installation how-to documentation lives in the INSTALL
|
|
||||||
file located in the root of the ViewVC source code distribution.
|
|
||||||
The most recent version of this document (which may cover
|
|
||||||
unreleased ViewVC versions) can be found
|
|
||||||
at <a href="http://viewvc.tigris.org/source/browse/*checkout*/viewvc/trunk/INSTALL"
|
|
||||||
>http://viewvc.tigris.org/source/browse/*checkout*/viewvc/trunk/INSTALL</a>.
|
|
||||||
If you are upgrading an existing ViewVC instance, you'll also want
|
|
||||||
to read the upgrade documentation, found
|
|
||||||
at <a href="http://viewvc.tigris.org/source/browse/*checkout*/viewvc/trunk/docs/upgrading-howto.html"
|
|
||||||
>http://viewvc.tigris.org/source/browse/*checkout*/viewvc/trunk/docs/upgrading-howto.html</a>.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="vhost-root">
|
|
||||||
<p class="faq-atitle">How can I expose ViewVC at the root of a virtual
|
|
||||||
host on my webserver?</p>
|
|
||||||
|
|
||||||
<p>If you want to dedicate a virtual host on your server just to
|
|
||||||
ViewVC, such the root directory of that host maps to ViewVC's root
|
|
||||||
display, you can do so by placing the following lines inside
|
|
||||||
the <code>VirtualHost</code>Apache configuration:</p>
|
|
||||||
|
|
||||||
<blockquote><pre>Alias /docroot /usr/local/viewvc/templates/docroot
|
|
||||||
ScriptAlias / /usr/local/viewvc/bin/cgi/viewvc.cgi/</pre></blockquote>
|
|
||||||
|
|
||||||
<p>The trick appears to be the presence of the trailing slash
|
|
||||||
character on the <code>ScriptAlias</code> directive.</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="authz-support">
|
|
||||||
<p class="faq-atitle">Does ViewVC support path-based authorization,
|
|
||||||
such as Subversion's authz-file mechanism?</p>
|
|
||||||
|
|
||||||
<p>This feature is available in ViewVC 1.1.0, which you can get from
|
|
||||||
our <a href="http://viewvc.org/download.html" >Download</a>
|
|
||||||
page.</p>
|
|
||||||
|
|
||||||
<p>If you prefer to use only final releases, there are some available
|
|
||||||
workarounds. For example, if you are running ViewVC under Apache,
|
|
||||||
you can use regular Apache configuration directives to
|
|
||||||
authz-protect areas of your repository — see
|
|
||||||
the <a href="http://httpd.apache.org/docs/2.2/mod/core.html#location"
|
|
||||||
>Location</a>
|
|
||||||
and <a href="http://httpd.apache.org/docs/2.2/mod/core.html#locationmatch"
|
|
||||||
>LocationMatch</a> directives, as well as
|
|
||||||
the <a href="http://httpd.apache.org/docs/2.2/howto/auth.html"
|
|
||||||
>Authentication, Authorization and Access Control</a> portions of
|
|
||||||
the Apache HTTP Server documentation. This works best when ViewVC
|
|
||||||
is only serving up a single repository, or when the
|
|
||||||
<code>root_as_url_component</code> option is enabled otherwise.
|
|
||||||
And you might have to disable the checkout view, or at least turn
|
|
||||||
off the use of <code>checkout_magic</code> (see
|
|
||||||
<code>viewvc.conf</code> for details).</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="missing-tmpdir">
|
|
||||||
<p class="faq-atitle">What causes "Error: OSError: [Errno 2] No such
|
|
||||||
file or directory: '/tmp/tmpGc-Ztj'"?</p>
|
|
||||||
|
|
||||||
<p>This is tracked in <a
|
|
||||||
href="http://viewvc.tigris.org/issues/show_bug.cgi?id=282">issue
|
|
||||||
#282</a>. While we haven't figured out how to make the error
|
|
||||||
message more graceful or helpful, the basic problem seems to
|
|
||||||
generally boil down to a misconfiguration of ViewVC. Make sure
|
|
||||||
your helper applications are in the program search path
|
|
||||||
(<code>$PATH</code>, e.g.) on your ViewVC server, or accurately
|
|
||||||
specified in <code>viewvc.conf</code>.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="standalone-only">
|
|
||||||
<p class="faq-atitle">Why does <em>SOME-FEATURE</em> work under
|
|
||||||
standalone.py, but not under Apache (or IIS or …)?</p>
|
|
||||||
|
|
||||||
<p>Most of the time folks run standalone.py, they do so as a regular
|
|
||||||
system user, from a shell running with any and all the
|
|
||||||
environmental customizations present in their shell startup
|
|
||||||
scripts. But most web server packages (like Apache) run as a
|
|
||||||
different, often underprivileged, user, whose environment is
|
|
||||||
stripped down to just the system-wide default state. This can
|
|
||||||
cause problems for ViewVC's various helper applications, which
|
|
||||||
might reside in a location that's included as part of your (and
|
|
||||||
thus standalone.py's) <code>$PATH</code>, but not that of the user
|
|
||||||
as whom the web server package runs. The solution might be as
|
|
||||||
simple explicitly configuring the paths of the helper applications
|
|
||||||
in <code>viewvc.conf</code>, or as complex as expanding the program
|
|
||||||
search path used by your web server software.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="rss-support">
|
|
||||||
<p class="faq-atitle">How do I enable ViewVC's RSS feed capabilities?</p>
|
|
||||||
|
|
||||||
<p>ViewVC generates its RSS feeds from repository data mirrored in a
|
|
||||||
database as part of its MySQL integration. Follow the steps in
|
|
||||||
ViewVC's <code>INSTALL</code> file to setup and configure the MySQL
|
|
||||||
integration and begin mirroring your commit metadata in the
|
|
||||||
database — the RSS feed feature will then be enabled with no
|
|
||||||
additional configuration.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
|
|
||||||
<h3 class="faq-section" id="faq-a-cvs">CVS Browsing</h3>
|
|
||||||
<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
|
|
||||||
|
|
||||||
<div id="error-displaying-cvs-files">
|
|
||||||
|
|
||||||
<p class="faq-atitle">Why can I navigate only those CVS directories
|
|
||||||
that have no files in them?</p>
|
|
||||||
|
|
||||||
<p>ViewVC can generally display CVS directories without the use of any
|
|
||||||
external tools. But unless configured to use the incomplete,
|
|
||||||
experimental rcsparse module (via the <code>use_rcsparse</code>
|
|
||||||
configuration option), it relies on either the RCS toolchain or the
|
|
||||||
CVSNT tool (on Windows) to get information about versioned files.
|
|
||||||
If the system is missing both of these, you'll need to remedy that.
|
|
||||||
If ViewVC simply cannot find the installed tools, ensure that they
|
|
||||||
are available in the system <code>$PATH</code>, or specify their
|
|
||||||
location in the <code>viewvc.conf</code> file using
|
|
||||||
the <code>utilities/rcs_dir</code> or <code>utilities/cvsnt</code>
|
|
||||||
options. (Note that prior to ViewVC 1.1.0, these options were found
|
|
||||||
at <code>general/rcs_path</code>
|
|
||||||
and <code>general/cvsnt_exe_path</code>.)</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="rlog-output-ended-early">
|
|
||||||
|
|
||||||
<p class="faq-atitle">What causes "Error: Rlog output ended
|
|
||||||
early. Expected RCS file "/opt/cvs/project/file,v""?</p>
|
|
||||||
|
|
||||||
<p>This is another symptom of the basic problem described <a
|
|
||||||
href="#error-displaying-cvs-files">here</a>.</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="comalformedoutput">
|
|
||||||
|
|
||||||
<p class="faq-atitle">What causes "Error: COMalformedOutput: Unable to
|
|
||||||
find filename in co output stream"?</p>
|
|
||||||
|
|
||||||
<p>This is another symptom of the basic problem described <a
|
|
||||||
href="#error-displaying-cvs-files">here</a>.</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="error-during-rlog">
|
|
||||||
<p class="faq-atitle">What causes "Error: error during rlog:
|
|
||||||
0x100"?</p>
|
|
||||||
|
|
||||||
<p>### TODO ###</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="missing-files">
|
|
||||||
<p class="faq-atitle">Why do my directories have no files in them?</p>
|
|
||||||
|
|
||||||
<p>There are a few reasons why this can happen. Here are some of the
|
|
||||||
most common ones:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Some folks mistakenly point ViewVC's configuration bits to their
|
|
||||||
CVS working copies. But ViewVC isn't a working copy browser
|
|
||||||
— it's a <em>repository</em> browser. If you don't know
|
|
||||||
the difference, here's a tip that might help: CVS repositories
|
|
||||||
are directories trees filled with files that end with
|
|
||||||
"<code>,v</code>". If your directory isn't filled with "comma
|
|
||||||
vee" files, it probably is <em>not</em> a CVS repository.</li>
|
|
||||||
<li>… <!-- TODO --></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="none-match">
|
|
||||||
<p class="faq-atitle">ViewVC doesn't show files I'm looking for, and
|
|
||||||
instead displays the message "NOTE: There are N files, but none
|
|
||||||
match the current selection criteria". How can I fix this?</p>
|
|
||||||
|
|
||||||
<p>From time to time, CVS and CVSNT add support for new keywords to
|
|
||||||
the RCS backend used to house repository data. If you're running a
|
|
||||||
version of ViewVC or ViewCVS that hasn't yet learned to handle
|
|
||||||
those new keywords, you might get the error you're seeing. The
|
|
||||||
solution is to try to get versions of CVS/CVSNT and ViewVC which
|
|
||||||
are better aligned, which generally means upgrading ViewVC (which
|
|
||||||
is probably less disruptive than downgrading your version control
|
|
||||||
system).</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
|
|
||||||
<h3 class="faq-section" id="faq-a-svn">Subversion Browsing</h3>
|
|
||||||
<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
|
|
||||||
|
|
||||||
<div id="no-module-named-svn">
|
|
||||||
<p class="faq-atitle">What causes "Error: ImportError: No module named
|
|
||||||
svn"?</p>
|
|
||||||
|
|
||||||
<p>ViewVC uses Subversion's Python bindings to interact with and pull
|
|
||||||
information out of your Subversion repositories. These bindings
|
|
||||||
are not, however, generally provided as part of the ViewVC
|
|
||||||
distribution — you have to install them yourself some other
|
|
||||||
way. (For more information, contact the <a
|
|
||||||
href="http://subversion.tigris.org">Subversion</a> community.) The
|
|
||||||
error you see is Python being asked to import the Subversion Python
|
|
||||||
bindings and being unable to do so, typically because the bindings
|
|
||||||
modules aren't found in the Python library search path.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="remote-svn-access">
|
|
||||||
|
|
||||||
<p class="faq-atitle">Can I use ViewVC with remote Subversion
|
|
||||||
repositories?</p>
|
|
||||||
|
|
||||||
<p>ViewVC prefers to have direct access to the repository (and in
|
|
||||||
fact, <em>must</em> have that for CVS repositories), but there does
|
|
||||||
exist experimental support for remote Subversion repositories.
|
|
||||||
Enabling this is a fairly simple — just use the URL of the
|
|
||||||
repository where you would use its path in the
|
|
||||||
<code>svn_roots</code> configuration options (sorry, you can't use
|
|
||||||
<code>root_parents</code> for remote repositories because
|
|
||||||
Subversion doesn't expose a repository-listing repository access
|
|
||||||
API).</p>
|
|
||||||
|
|
||||||
<p>What you should expect:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><p>Near parity with local-access Subversion in terms of
|
|
||||||
functionality.</p></li>
|
|
||||||
|
|
||||||
<li><p>Known shortcomings:</p>
|
|
||||||
<ul>
|
|
||||||
<li>file sizes aren't reported everywhere</li>
|
|
||||||
<li>the "revision" view lacks/botches some information</li>
|
|
||||||
<li>she ain't the fastest horse on the track…</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li><p>Lack of configury for dealing with the intricacies of remote
|
|
||||||
access. If the auth credentials and such you need to access
|
|
||||||
the remote repository aren't cached in
|
|
||||||
<code>~VIEWVC_USER/.subversion</code> (where
|
|
||||||
<code>VIEWVC_USER</code> is the system user as whom ViewVC
|
|
||||||
runs), stuff won't work.</p></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div> <!-- section -->
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
Binary file not shown.
@@ -1,186 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
||||||
<head>
|
|
||||||
<title>ViewVC: Repository Browsing</title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
|
||||||
<link rel="stylesheet" type="text/css" href="./styles.css"/>
|
|
||||||
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<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="./faq.html">FAQ</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-what-is-viewvc">What Is ViewVC?</a></li>
|
|
||||||
<li><a href="#sec-requirements">Requirements</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-what-is-viewvc">What Is ViewVC?</h2>
|
|
||||||
|
|
||||||
<div class="section-body">
|
|
||||||
|
|
||||||
<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>Support for path-based authorization, including parsing and
|
|
||||||
honoring Subversion authz configuration files.</li>
|
|
||||||
|
|
||||||
<li>RSS feed generation for tracking changes to repositories or
|
|
||||||
individual items within repositories.</li>
|
|
||||||
|
|
||||||
<li>Individually configurable virtual host support.</li>
|
|
||||||
|
|
||||||
<li>Line-based annotation/blame display.</li>
|
|
||||||
|
|
||||||
<li>Revision graph capabilities (via integration with <a
|
|
||||||
href="http://www.akhphd.au.dk/~bertho/cvsgraph/">CvsGraph</a>)
|
|
||||||
(<em>CVS only</em>).</li>
|
|
||||||
|
|
||||||
<li>Syntax highlighting support.</li>
|
|
||||||
|
|
||||||
<li><a href="http://www.mozilla.org/projects/bonsai/">Bonsai</a>-like
|
|
||||||
repository query facilities.</li>
|
|
||||||
|
|
||||||
<li>Template-driven output generation.</li>
|
|
||||||
|
|
||||||
<li>Colorized, side-by-side differences.</li>
|
|
||||||
|
|
||||||
<li>Tarball generation (by tag/branch for CVS, by revision for
|
|
||||||
Subversion).</li>
|
|
||||||
|
|
||||||
<li>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> <!-- section-body -->
|
|
||||||
</div> <!-- section -->
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
|
|
||||||
<h2 id="sec-requirements">Requirements</h2>
|
|
||||||
|
|
||||||
<div class="section-body">
|
|
||||||
|
|
||||||
<p>The only hard software requirement for running ViewVC is <a
|
|
||||||
href="http://www.python.org/">Python 1.5.2</a> or later. All other
|
|
||||||
requirements depend on what you want to do with the tool.</p>
|
|
||||||
|
|
||||||
<p>For use with Subversion repositories, you need these things:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
|
|
||||||
<li><a href="http://subversion.tigris.org/">Subversion</a> 1.2 or
|
|
||||||
later and its SWIG Python bindings.</li>
|
|
||||||
|
|
||||||
<li><a href="http://www.gnu.org/software/diffutils/diffutils.html">GNU
|
|
||||||
diff</a></li>
|
|
||||||
|
|
||||||
<li>Physical access to a Subversion repository (though there is
|
|
||||||
limited, use-at-your-risk support for remote access, too).</li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>If you plan to use ViewVC with CVS repositories, you need the
|
|
||||||
following things:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
|
|
||||||
<li><a href="http://www.cs.purdue.edu/homes/trinkle/RCS/">RCS</a>
|
|
||||||
(Revision Control System)</li>
|
|
||||||
|
|
||||||
<li><a href="http://www.gnu.org/software/diffutils/diffutils.html">GNU
|
|
||||||
diff</a></li>
|
|
||||||
|
|
||||||
<li>Read-only, physical access to a CVS repository.</li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>ViewVC integrates with additional pieces of software to provide
|
|
||||||
certain bits of optional functionality:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
|
|
||||||
<li><a href="http://httpd.apache.org/">Apache HTTP Server</a>, or
|
|
||||||
another server capable of running CGI programs — unless
|
|
||||||
you just want ViewVC to run in standalone server mode.</li>
|
|
||||||
|
|
||||||
<li><a href="http://www.mysql.com/">MySQL</a> — Needed to use
|
|
||||||
the commit database query functionality.</li>
|
|
||||||
|
|
||||||
<li><a href="http://pygments.org/">Pygments</a> — Needed for
|
|
||||||
syntax highlighting in versioned file contents
|
|
||||||
displays.</li>
|
|
||||||
|
|
||||||
<li><a href="http://www.akhphd.au.dk/~bertho/cvsgraph/">CvsGraph</a>
|
|
||||||
— Needed for version graph displays.</li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</div> <!-- section-body -->
|
|
||||||
</div> <!-- section -->
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@@ -1,219 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import urllib
|
|
||||||
import shutil
|
|
||||||
import getopt
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
|
|
||||||
class BuildError(Exception):
|
|
||||||
def __init__(self, message):
|
|
||||||
self.message = message
|
|
||||||
def __str__(self):
|
|
||||||
return self.message
|
|
||||||
|
|
||||||
|
|
||||||
def make_release(branch, export_dir, publish_dir, root_url, username, password):
|
|
||||||
|
|
||||||
# Export the requested ViewVC source tree.
|
|
||||||
cmd = "svn export --quiet '%s/%s' %s " \
|
|
||||||
"--username '%s' --password '%s' --non-interactive --force" \
|
|
||||||
% (root_url, urllib.quote(branch), export_dir, username, password)
|
|
||||||
sys.stdout.write("Running: %s\n" % (cmd))
|
|
||||||
os.system(cmd)
|
|
||||||
|
|
||||||
# Get the version number from ViewVC itself.
|
|
||||||
sys.path.insert(0, os.path.join(export_dir, 'lib'))
|
|
||||||
try:
|
|
||||||
import viewvc
|
|
||||||
except ImportError:
|
|
||||||
raise BuildError("Unable to import viewvc module; export failed?")
|
|
||||||
version = viewvc.__version__
|
|
||||||
del sys.modules['viewvc']
|
|
||||||
del viewvc
|
|
||||||
del sys.path[0]
|
|
||||||
|
|
||||||
# Now, use ViewVC tools to make the distribution archives.
|
|
||||||
localtime = time.localtime()
|
|
||||||
date = "%4d%02d%02d" % (localtime[0], localtime[1], localtime[2])
|
|
||||||
distversion = "viewvc-%s" % (version)
|
|
||||||
distname = "%s-%s" % (distversion, date)
|
|
||||||
gzip_name = distname + '.tar.gz'
|
|
||||||
zip_name = distname + '.zip'
|
|
||||||
curdir = os.getcwd()
|
|
||||||
try:
|
|
||||||
os.chdir(os.path.join(export_dir, 'tools'))
|
|
||||||
os.system('./make-release %s %s' % (distname, branch))
|
|
||||||
finally:
|
|
||||||
os.chdir(curdir)
|
|
||||||
|
|
||||||
# Finally, return the locations of the archive files we've built.
|
|
||||||
gzip_file = os.path.join(export_dir, 'tools', gzip_name)
|
|
||||||
if not os.path.exists(gzip_file):
|
|
||||||
gzip_file = None
|
|
||||||
zip_file = os.path.join(export_dir, 'tools', zip_name)
|
|
||||||
if not os.path.exists(zip_file):
|
|
||||||
zip_file = None
|
|
||||||
|
|
||||||
# Remove superceded archives.
|
|
||||||
if gzip_file or zip_file:
|
|
||||||
dirents = os.listdir(publish_dir)
|
|
||||||
for dirent in dirents:
|
|
||||||
if dirent.startswith(distversion) \
|
|
||||||
and ((dirent.endswith('.tar.gz') and gzip_file) \
|
|
||||||
or (dirent.endswith('.zip') and zip_file)):
|
|
||||||
os.unlink(dirent)
|
|
||||||
|
|
||||||
# Install the new archives.
|
|
||||||
if gzip_file:
|
|
||||||
os.rename(gzip_file, os.path.join(publish_dir, gzip_name))
|
|
||||||
if zip_file:
|
|
||||||
os.rename(zip_file, os.path.join(publish_dir, zip_name))
|
|
||||||
|
|
||||||
# Return our archive names.
|
|
||||||
return gzip_file and gzip_name or None, zip_file and zip_name or None
|
|
||||||
|
|
||||||
|
|
||||||
def publish_releases(branches, publish_dir, root_url, username, password):
|
|
||||||
new_index_contents = get_html_index_header()
|
|
||||||
for branch in branches:
|
|
||||||
sys.stdout.write("Beginning build for branch '%s'.\n" % (branch))
|
|
||||||
export_dir = None
|
|
||||||
try:
|
|
||||||
export_dir = tempfile.mkdtemp("", "viewvc-nightly-")
|
|
||||||
gzip_file, zip_file = make_release(branch, export_dir, publish_dir,
|
|
||||||
root_url, username, password)
|
|
||||||
new_index_contents = new_index_contents + """
|
|
||||||
<p>Build of %s:</p>
|
|
||||||
<ul>
|
|
||||||
<li><a href="%s">%s</a></li>
|
|
||||||
<li><a href="%s">%s</a></li>
|
|
||||||
</ul>
|
|
||||||
""" % (branch, urllib.quote(gzip_file), gzip_file,
|
|
||||||
urllib.quote(zip_file), zip_file)
|
|
||||||
finally:
|
|
||||||
if export_dir:
|
|
||||||
sys.stdout.write("Removing temporary directory '%s'.\n" % (export_dir))
|
|
||||||
shutil.rmtree(export_dir)
|
|
||||||
sys.stdout.write("Finished build for branch '%s'.\n" % (branch))
|
|
||||||
|
|
||||||
new_index_contents = new_index_contents + get_html_index_footer()
|
|
||||||
open(os.path.join(publish_dir, 'index.html'), 'w').write(new_index_contents)
|
|
||||||
|
|
||||||
|
|
||||||
def get_html_index_header():
|
|
||||||
return """
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
||||||
<head>
|
|
||||||
<title>ViewVC: Nightly Snapshots</title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
|
||||||
<link rel="stylesheet" type="text/css" href="../styles.css"/>
|
|
||||||
<link rel="shortcut icon" href="../favicon.ico" type="image/x-icon" />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<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="./faq.html">FAQ</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="%s">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>
|
|
||||||
<div class="section-body">
|
|
||||||
""" % ("#sec-snapshots")
|
|
||||||
|
|
||||||
|
|
||||||
def get_html_index_footer():
|
|
||||||
return """
|
|
||||||
</div> <!-- section-body -->
|
|
||||||
</div> <!-- section -->
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def usage_and_exit(errmsg=None):
|
|
||||||
stream = errmsg and sys.stderr or sys.stdout
|
|
||||||
progname = os.path.basename(sys.argv[0])
|
|
||||||
stream.write("""%s -- nightly ViewVC build generation
|
|
||||||
|
|
||||||
Usage: %s [OPTIONS] PUBLISH-DIR BRANCH ...
|
|
||||||
|
|
||||||
Build an archive from one or more BRANCH in the ViewVC source
|
|
||||||
repository, dropping them into PUBLISH-DIR alongside an index.html
|
|
||||||
file that name and links to them.
|
|
||||||
|
|
||||||
Options:
|
|
||||||
--help (-h, -?) : Show this usage message
|
|
||||||
--username : Username used for source export
|
|
||||||
--password : Password used for source export
|
|
||||||
--root-url : Alternative source repository root URL
|
|
||||||
|
|
||||||
""" % (progname, progname))
|
|
||||||
if errmsg:
|
|
||||||
stream.write("ERROR: %s\n" % (errmsg))
|
|
||||||
sys.exit(errmsg and 1 or 0)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
root_url = "http://viewvc.tigris.org/svn/viewvc"
|
|
||||||
username = password = ""
|
|
||||||
opts, args = getopt.getopt(sys.argv[1:], 'h?',
|
|
||||||
['help', 'username=', 'password=', 'root-url='])
|
|
||||||
for name, value in opts:
|
|
||||||
if name == '-h' or name == '-?' or name == '--help':
|
|
||||||
usage_and_exit()
|
|
||||||
elif name == '--username':
|
|
||||||
username = value
|
|
||||||
elif name == '--password':
|
|
||||||
password = value
|
|
||||||
elif name == '--root-url':
|
|
||||||
root_url = value
|
|
||||||
argc = len(args)
|
|
||||||
if argc < 2:
|
|
||||||
usage_and_exit("Not enough arguments")
|
|
||||||
try:
|
|
||||||
publish_releases(args[1:], args[0], root_url, username, password)
|
|
||||||
except BuildError, e:
|
|
||||||
sys.stderr.write(str(e) + "\n")
|
|
||||||
sys.exit(1)
|
|
@@ -1,169 +0,0 @@
|
|||||||
body {
|
|
||||||
background-color: #b2d388;
|
|
||||||
color: black;
|
|
||||||
font-family: trebuchet ms, arial, sans-serif;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#title {
|
|
||||||
background-color: #739c3e;
|
|
||||||
height: 70px;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
width: 95%;
|
|
||||||
height: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
address {
|
|
||||||
font-size: 60%;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
background-color: #94bd5e;
|
|
||||||
padding: 2px 0.5em 2px 0.5em;
|
|
||||||
margin: 0;
|
|
||||||
border-bottom: dotted 1px rgb(180,193,205);
|
|
||||||
font-size: 110%;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 100%;
|
|
||||||
font-weight: bold;
|
|
||||||
border-bottom: dotted 1px rgb(180,193,205);
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
padding: 2px 0.5em 2px 0.5em;
|
|
||||||
margin: 0;
|
|
||||||
font-size: 90%;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
p, dl {
|
|
||||||
padding: 0.5em;
|
|
||||||
margin: 0;
|
|
||||||
font-size: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul, ol {
|
|
||||||
font-size: 90%;
|
|
||||||
padding: 0.5em;
|
|
||||||
margin: 0 0 0 0.25in;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-size: 105%;
|
|
||||||
font-style: italic;
|
|
||||||
font-family: monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
text-align: justify;
|
|
||||||
font-style: italic;
|
|
||||||
margin: 0 0.5in 0 0.5in;
|
|
||||||
padding: 5px;
|
|
||||||
border: 1px dotted black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section {
|
|
||||||
background: white;
|
|
||||||
border-color: rgb(24,24,24);
|
|
||||||
border-width: 1px;
|
|
||||||
border-style: solid;
|
|
||||||
padding: 0;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-body {
|
|
||||||
padding: 0 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section p, .section dl, .section ul, .section ol {
|
|
||||||
padding: 0.5em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#menu {
|
|
||||||
background: black;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
#menu a, #menu a:visited {
|
|
||||||
background: black;
|
|
||||||
color: white;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#menu a:hover {
|
|
||||||
background: black;
|
|
||||||
color: white;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
#submenu {
|
|
||||||
background: rgb(90%,97%,99%);
|
|
||||||
font-size: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pagetable tr {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pagetable {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pagecolumn1 {
|
|
||||||
width: 175px;
|
|
||||||
padding: 1em 0 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pagecolumn1 a, #pagecolumn1 a:visited {
|
|
||||||
color: rgb(0,0,164);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pagecolumn1 a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pagecolumn2 {
|
|
||||||
padding: 1em 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pagecolumn2 a, #pagecolumn2 a:visited {
|
|
||||||
color: rgb(0,0,164);
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pagecolumn2 a:hover {
|
|
||||||
background-color: rgb(180,193,205);
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bookmarks {
|
|
||||||
padding-left: 0.5em;
|
|
||||||
font-size: 80%;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notice {
|
|
||||||
border: 1px solid black;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
background: yellow;
|
|
||||||
}
|
|
||||||
|
|
||||||
.faq-section {
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.faq-atitle {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
@@ -1,181 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
||||||
<head>
|
|
||||||
<title>ViewVC: About</title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
|
||||||
<link rel="stylesheet" type="text/css" href="./styles.css"/>
|
|
||||||
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<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="./faq.html">FAQ</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-history">The History of ViewVC</a></li>
|
|
||||||
<li><a href="#sec-viewcvs-group">The ViewCVS Group</a></li>
|
|
||||||
<li><a href="#sec-site-credits">About This Site</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<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-history">The History of ViewVC</h2>
|
|
||||||
|
|
||||||
<div class="section-body">
|
|
||||||
|
|
||||||
<p>The ViewVC software was inspired by early versions of cvsweb
|
|
||||||
(originally written by Bill Fenner, further developed by Henner
|
|
||||||
Zeller, and now maintained as <a
|
|
||||||
href="http://www.freebsd.org/projects/cvsweb.html">CVSweb</a> by
|
|
||||||
the FreeBSD community). Greg Stein wanted to make some changes and
|
|
||||||
updates, but cvsweb was implemented in Perl. He wrote:</p>
|
|
||||||
|
|
||||||
<blockquote>
|
|
||||||
|
|
||||||
<p>"While I can manage some Perl, cvsweb was rather
|
|
||||||
unmaintainable for me. So I undertook the task to convert the
|
|
||||||
software to Python. As a result, I've actually been able to go
|
|
||||||
<strong>way</strong> beyond the simple changes that I had
|
|
||||||
envisioned."
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</blockquote>
|
|
||||||
|
|
||||||
<p>So ViewVC started out as just a port of the cvsweb script,
|
|
||||||
originally called ViewCVS. Along the way, it has had numerous
|
|
||||||
cleanups and other modifications, a process simplified by the
|
|
||||||
elegance of the <a href="http://www.python.org/">Python</a>
|
|
||||||
language.</p>
|
|
||||||
|
|
||||||
<p>In 2001, the ViewCVS project was moved to <a
|
|
||||||
href="http://www.sourceforge.net">SourceForge</a>, a popular
|
|
||||||
software collaboration environment. There the project continued to
|
|
||||||
mature, releasing several stable-yet-pre-1.0 versions. In 2002,
|
|
||||||
C. Michael Pilato began implementing support for Subversion in
|
|
||||||
ViewCVS, taking advantage of a version control abstraction layer
|
|
||||||
begun by Lucas Bruand. Along the way, Russell Yanofsky delivered
|
|
||||||
large improvements to that abstraction, and to ViewCVS as whole.
|
|
||||||
ViewCVS was well on its way to releasing a 1.0 version.</p>
|
|
||||||
|
|
||||||
<p>Of course, now that ViewCVS could browse Subversion repositories as
|
|
||||||
easily as CVS ones, the ViewCVS name seemed inappropriate. Also,
|
|
||||||
the active ViewCVS developers at the time were growing frustrated
|
|
||||||
with SourceForge as a project hosting environment —
|
|
||||||
Subversion wasn't yet available as an option for version control,
|
|
||||||
the CVS service was always down at just the wrong moment, the bug
|
|
||||||
trackers were painful to use, and so on. So in late 2005, the
|
|
||||||
decision was made to rename the project to ViewVC, to convert the
|
|
||||||
project's CVS data to Subversion, and to move the project and its
|
|
||||||
version controlled and open issue data to <a
|
|
||||||
href="http://www.tigris.org">Tigris.org</a>.</p>
|
|
||||||
|
|
||||||
<p>Today, ViewVC is being developed at <a
|
|
||||||
href="http://viewvc.tigris.org">http://viewvc.tigris.org</a> by a
|
|
||||||
small community of folks.</p>
|
|
||||||
|
|
||||||
</div> <!-- section-body -->
|
|
||||||
</div> <!-- section -->
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
|
|
||||||
<h2 id="sec-viewcvs-group">The ViewCVS Group</h2>
|
|
||||||
|
|
||||||
<div class="section-body">
|
|
||||||
|
|
||||||
<p>The ViewCVS Group is an informal group of people working on and
|
|
||||||
developing the ViewVC package. The current set of members are
|
|
||||||
listed below with some of their notable contributions:</p>
|
|
||||||
|
|
||||||
<dl>
|
|
||||||
<dt><a href="http://www.lyra.org/greg/">Greg Stein</a></dt>
|
|
||||||
<dd>original python port of Henner Zeller's cvsweb, secure popen
|
|
||||||
implementation, configuration file implementation, rcsparse
|
|
||||||
module, and EZT template engine</dd>
|
|
||||||
|
|
||||||
<dt>Jay Painter</dt>
|
|
||||||
<dd>CVSdb query engine</dd>
|
|
||||||
|
|
||||||
<dt>Tanaka Akira</dt>
|
|
||||||
<dd>enscript colorization and tarball generation</dd>
|
|
||||||
|
|
||||||
<dt>Tim Cera</dt>
|
|
||||||
<dd>CvsGraph support, log_table template, regular expression search,
|
|
||||||
and paging capability</dd>
|
|
||||||
|
|
||||||
<dt>Peter Funk</dt>
|
|
||||||
<dd>standalone server, blimp logo, and numerous improvements to
|
|
||||||
ViewVC's interfaces and documentation</dd>
|
|
||||||
|
|
||||||
<dt>Lucas Bruand</dt>
|
|
||||||
<dd>C++ RCS parser (tparse) and vclib module for supporting new
|
|
||||||
version control systems</dd>
|
|
||||||
|
|
||||||
<dt><a href="http://www.cmichaelpilato.com/">C. Michael Pilato</a></dt>
|
|
||||||
<dd>Subversion support, root_as_url alternative URL scheme,
|
|
||||||
templatization work, website design, documentation</dd>
|
|
||||||
|
|
||||||
<dt>Russell Yanofsky</dt>
|
|
||||||
<dd>Windows support and the sapi module for supporting multiple web
|
|
||||||
server interfaces, sweeping abstraction and UI improvements</dd>
|
|
||||||
|
|
||||||
<dt>James Henstridge</dt>
|
|
||||||
<dd>integrated query interface, support for querying Subversion
|
|
||||||
repositories, caching support, CSS formatting, and the EZT
|
|
||||||
"define" directive</dd>
|
|
||||||
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
</div> <!-- section-body -->
|
|
||||||
</div> <!-- section -->
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
|
|
||||||
<h2 id="sec-site-credits">About This Site</h2>
|
|
||||||
|
|
||||||
<div class="section-body">
|
|
||||||
|
|
||||||
<p>The ViewVC website was designed by <a
|
|
||||||
href="http://www.cmichaelpilato.com/">C. Michael Pilato</a>. All
|
|
||||||
HTML was hand-edited in Emacs, and the little splashes of graphical
|
|
||||||
goodness owe their existence to Open Office and the Gimp. Textual
|
|
||||||
content for the site is mostly the work of Greg Stein, but has been
|
|
||||||
tweaked through the ages by various ViewVC contributors.</p>
|
|
||||||
|
|
||||||
</div> <!-- section-body -->
|
|
||||||
</div> <!-- section -->
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@@ -8,7 +8,6 @@
|
|||||||
#longdescription { border: none; }
|
#longdescription { border: none; }
|
||||||
#longdescription h2 { display: none; }
|
#longdescription h2 { display: none; }
|
||||||
#customcontent h2 { display: block; }
|
#customcontent h2 { display: block; }
|
||||||
.h2 { margin-bottom: 2em; }
|
|
||||||
</style>
|
</style>
|
||||||
<!-- End custom stylations -->
|
<!-- End custom stylations -->
|
||||||
</head>
|
</head>
|
||||||
@@ -19,27 +18,10 @@
|
|||||||
|
|
||||||
<h1>ViewVC — Web-based Version Control Repository Browsing</h1>
|
<h1>ViewVC — Web-based Version Control Repository Browsing</h1>
|
||||||
|
|
||||||
<div class="h2"
|
<div class="h2">
|
||||||
style="border-style: solid;
|
<h2>Latest Release</h2>
|
||||||
border-width: 1px 2px 2px 1px;
|
|
||||||
border-color: black;
|
|
||||||
background: #eed;
|
|
||||||
padding: 0.5em;">
|
|
||||||
|
|
||||||
<h2>Latest Release(s)</h2>
|
<p>The most recent release of ViewVC is: <strong>1.0.7</strong></p>
|
||||||
|
|
||||||
<p>The most recent stable release of ViewVC is: <strong>1.1.2</strong></p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="http://www.viewvc.org/download.html"
|
|
||||||
>Download or checkout</a> this release</li>
|
|
||||||
<li>See the
|
|
||||||
<a href="http://viewvc.tigris.org/source/browse/*checkout*/viewvc/tags/1.1.2/CHANGES"
|
|
||||||
>CHANGES</a> in this release.</li>
|
|
||||||
<li>Read the
|
|
||||||
<a href="http://viewvc.tigris.org/source/browse/*checkout*/viewvc/trunk/docs/release-notes/1.1.0.html"
|
|
||||||
>release notes</a> for this version line.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -63,16 +45,15 @@
|
|||||||
<li>Line-based annotation/blame display</li>
|
<li>Line-based annotation/blame display</li>
|
||||||
<li>Revision graph capabilities (<em>CVS only</em>)</li>
|
<li>Revision graph capabilities (<em>CVS only</em>)</li>
|
||||||
<li>Syntax highlighting support</li>
|
<li>Syntax highlighting support</li>
|
||||||
<li>Path-based authorization</li>
|
|
||||||
<li>Commit metadata query facilities</li>
|
<li>Commit metadata query facilities</li>
|
||||||
<li>Template-driven output generation</li>
|
<li>Template-driven output generation</li>
|
||||||
<li>Colorized, side-by-side differences</li>
|
<li>Colorized, side-by-side differences</li>
|
||||||
<li>Tarball generation (by tag for CVS, by revision for Subversion)</li>
|
<li>Tarball generation (by tag for CVS, by revision for Subversion)</li>
|
||||||
<li>Ability to run as CGI script, under mod_python, or as a
|
|
||||||
standalone server application</li>
|
|
||||||
<li>Regexp-based file searching</li>
|
|
||||||
<li>INI-like configuration file (no code tweaking required)</li>
|
|
||||||
<li>Localization support based on the Accept-Language request header</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>
|
</ul>
|
||||||
|
|
||||||
<p>For a complete list of changes present in each release, see
|
<p>For a complete list of changes present in each release, see
|
||||||
@@ -85,28 +66,20 @@
|
|||||||
<div class="h2">
|
<div class="h2">
|
||||||
<h2>Wanna Talk About ViewVC?</h2>
|
<h2>Wanna Talk About ViewVC?</h2>
|
||||||
|
|
||||||
<table border="0" cellpadding="10" cellspacing="10" style="margin: 0 5%;">
|
<p>If you have questions about ViewVC — how to configure it, if
|
||||||
<thead>
|
some behavior you are seeing is expected or not, and so on —
|
||||||
<tr style="vertical-align: top;">
|
send email to our users list: <a
|
||||||
<th style="width: 50%;">User/Admin Discussion</th>
|
href="mailto:users@viewvc.tigris.org"
|
||||||
<th style="width: 50%;">Developer Discussion</th>
|
>users@viewvc.tigris.org</a>.</p>
|
||||||
</tr>
|
|
||||||
</thead>
|
<p>If you'd like to discuss the actual development of ViewVC itself,
|
||||||
<tbody>
|
or submit a patch to ViewVC's sources, you can do so on our
|
||||||
<tr style="vertical-align: top;">
|
development list: <a href="mailto:dev@viewvc.tigris.org"
|
||||||
<td>If you have questions about ViewVC — how to configure it, if
|
>dev@viewvc.tigris.org</a>.</p>
|
||||||
some behavior you are seeing is expected or not, and so on —
|
|
||||||
send email to <a href="mailto:users@viewvc.tigris.org"
|
<p>Finally, if you prefer realtime chatter, use your favorite IRC
|
||||||
>users@viewvc.tigris.org</a> or use your favorite IRC client to
|
client to pop into <tt><a href="irc://irc.freenode.net/viewvc"
|
||||||
pop into <tt><a href="irc://irc.freenode.net/viewvc"
|
>#viewvc</a></tt> on irc.freenode.net.</p>
|
||||||
>#viewvc</a></tt> on irc.freenode.net.</td>
|
|
||||||
<td>If you'd like to discuss the actual development of ViewVC itself,
|
|
||||||
or submit a patch to ViewVC's sources, you can do so on our
|
|
||||||
development list, <a href="mailto:dev@viewvc.tigris.org"
|
|
||||||
>dev@viewvc.tigris.org</a>.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -13,14 +13,12 @@
|
|||||||
|
|
||||||
<li><a href="http://viewvc.tigris.org/servlets/ProjectNewsList"
|
<li><a href="http://viewvc.tigris.org/servlets/ProjectNewsList"
|
||||||
>Announcements</a></li>
|
>Announcements</a></li>
|
||||||
<li><a href="http://viewvc.tigris.org/ds/viewForums.do"
|
<li><a href="http://viewvc.tigris.org/servlets/ProjectMailingListList"
|
||||||
>Discussions</a></li>
|
>Mailing lists</a></li>
|
||||||
<li><a href="http://viewvc.tigris.org/source/browse/viewvc/"
|
<li><a href="http://viewvc.tigris.org/source/browse/viewvc/"
|
||||||
>Source Code</a></li>
|
>Subversion</a></li>
|
||||||
<li><a href="http://viewvc.tigris.org/issues/buglist.cgi?component=viewvc&issue_status=UNCONFIRMED&issue_status=NEW&issue_status=STARTED&issue_status=REOPENED"
|
<li><a href="http://viewvc.tigris.org/issues/buglist.cgi?component=viewvc&issue_status=UNCONFIRMED&issue_status=NEW&issue_status=STARTED&issue_status=REOPENED"
|
||||||
>Issue tracker</a></li>
|
>Issue tracker</a></li>
|
||||||
<li><a href="http://viewvc.tigris.org/servlets/ProjectDocumentList?folderID=6004"
|
|
||||||
>Downloads</a></li>
|
|
||||||
|
|
||||||
</ul></dd>
|
</ul></dd>
|
||||||
<!-- .................................................................. -->
|
<!-- .................................................................. -->
|
||||||
|
Reference in New Issue
Block a user