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

Compare commits

..

115 Commits

Author SHA1 Message Date
(no author)
f7920e796c This commit was manufactured by cvs2svn to create tag 'V0_7'.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/tags/V0_7@197 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-30 09:19:18 +00:00
gstein
02f2243cc7 *) updated for new CVS site
*) use cvs export and require a tag


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@196 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-30 09:19:18 +00:00
gstein
8766cf00ca rolling 0.7
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@195 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-30 09:15:03 +00:00
gstein
ba039d5a8f add a reference to Karl's book. delete a broken link.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@194 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-30 08:54:12 +00:00
gstein
007ad51b2c change web site references from www.lyra.org/viewcvs/ to the new
viewcvs.sourceforge.net/ site.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@193 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-30 08:49:19 +00:00
gstein
c3d12bb0c8 add a persistent URL format for reaching the HEAD revision
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@192 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-30 08:37:17 +00:00
gstein
d0de5e7ad0 add the two new lib/ modules.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@191 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-30 08:18:28 +00:00
gstein
4a00a0bb4f add an item for the next release
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@190 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-30 08:16:38 +00:00
gstein
abb4a468fc The single/double find stuff was stupid. single would always be <= double.
Looking for a double is simply looking at the character following the '@'.
Removing the second find also solved some cache-thrashing that occurred with
big CHUNK_SIZE values. Plus a general speedup. :-)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@189 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-14 10:49:39 +00:00
gstein
cc3807f964 More speedups.
* avoid lstrip() -- it can take a while on large strings
* use loops instead of more complex ops. loops have a higher per-iteration
  cost, but a lower constant time. since N is small, it is a win.
* avoid "re" altogether; use string.digits in class Parser

(rcsparse is now over 10x faster since I started optimizing)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@188 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-14 08:44:33 +00:00
gstein
3bff6b7378 More performance tweaks.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@187 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-14 05:53:35 +00:00
gstein
fc6d80e2fb Speed up the get() method by being smarter about regular expression use,
avoiding slicing of strings, and more fine-tuned parsing.

(some debug stuff, too; this will disappear soon; just checkpointing now)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@186 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-13 02:52:26 +00:00
gstein
425ae2e8ec Speed up the log extraction by avoiding regular expressions (there are
simple equivalents which are faster).

Add a test function for profiling.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@185 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-13 02:50:24 +00:00
gstein
c2a29c83cd save a little test program for comparing rcsparse vs rlog output parsing
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@184 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-13 00:16:42 +00:00
gstein
799816c21f minor nit: fetch_log's last return value is a list, not a dict.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@183 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-13 00:13:12 +00:00
gstein
e3dbdb4fcc Update copyright years to include 2001.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@182 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-12 22:51:02 +00:00
gstein
c28afba169 removed unneeded #! marker
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@181 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-12 12:33:17 +00:00
gstein
d790f07d2c Apply a patch from apache.org: watch out (and recover) for files which have
"illegal" timestamps in them.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@180 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-12 12:26:46 +00:00
gstein
edf252fb2f Now, make the appropriate changes to get the split CGI script/library to
actually work: move imports, wrap run_cgi() around the logic in viewcvs.py,
shift around the CONF_PATHNAME stuff, etc.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@179 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-12 12:22:51 +00:00
gstein
6942dd6b4b Slice a big chunk out of viewcvs.cgi and move it to viewcvs.py.
Absolutely no other changes. No additions, no reformat, no nothing...


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@178 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-12 12:05:08 +00:00
gstein
a75f32fc3c Older versions of Python do not like lists passed to mktime(). Ensure that
we pass a tuple.

Fixes bug #421282
Submitted by: mjpieters@users.sourceforge.net


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@177 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-12 11:42:08 +00:00
gstein
e243a0e1ad Record that we couldn't stat the file, or that it is unreadable. This allows
us to actually tell the user about it (and do so!).

Also removed a spurious try/except in generate_tarball; get_file_data()
shouldn't be raising one any more.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@176 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-12 11:34:17 +00:00
gstein
755e4e74c3 In directory views (and tarballs), don't include files or dirs that we
cannot read.

Reported by: Jaime E. Villate <villate@fe.up.pt>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@175 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-12 10:23:59 +00:00
gstein
a46b9dd3ba The (colored) links need to specify the diff_format=h option. Also correct a
spelling/typo and add missing right parents.

Submitted by: Chris Tillman <tillman@azstarnet.com>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@174 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-12 09:25:53 +00:00
gstein
ab987dc6fa *) some updates for the move to SourceForge.
*) add information about ViewCVS' increased security


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@173 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-11 21:21:50 +00:00
akr
a6ac1d1892 handle FreeBSD's rlog output which has extra "----------------------------\n".
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@172 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-11 07:24:15 +00:00
akr
945cb91e38 (link_includes): use sticky parameters for a link.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@171 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-10 09:12:45 +00:00
gstein
262f3569c7 way different nowadays, so make the header reflect current reality. update
commentary, and keep appropriate recognition of Curt's work.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@170 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-09 11:35:54 +00:00
gstein
1b358fc88d switch from a line-oriented processing to buffer-oriented. provides
approximately 3x performance increase.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@169 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-09 11:32:47 +00:00
gstein
455faa1fe6 switch to a TokenStream plus the parser. provides for better isolation of
the token parsing semantics.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@168 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-09 10:30:12 +00:00
gstein
01facd113b commit a checkpoint, with some tools, before doing some heavy lifting
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@167 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-09 09:23:00 +00:00
gstein
67daa9e5e2 Extract the RCS parsing code into a separate module. It now uses a "sink"
model, sending events/info to the blame script.

(this allows the RCS parser to be used in numerous contexts by simply
 switching the Sink that is used)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@166 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-08 19:34:58 +00:00
akr
03a5620947 (_re_rewrite_url): recognize fragment identifier.
http://sourceforge.net/tracker/?func=detail&atid=318760&aid=421284&group_id=18760


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@165 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-06 10:06:23 +00:00
akr
424521d40e (get_file_data): ignore files which causes failures on stat(2) such
as dangling symlinks.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@164 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-06 09:13:01 +00:00
akr
1eeb39f264 (html_time): Since very old timestamp (82 years, 6 months in this case)
causes overflow of plain integer, use long integer.

use `year' correctly for these old timestamps.

http://sourceforge.net/tracker/index.php?func=detail&aid=418428&group_id=1&atid=100001
http://sourceforge.net/tracker/index.php?func=detail&aid=421096&group_id=18760&atid=118760


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@163 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-05 19:52:42 +00:00
akr
7aa5c33589 (urlencode): Don't add redundant '?'.
http://sourceforge.net/tracker/?func=detail&atid=118760&aid=421281&group_id=18760


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@162 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-05 18:02:00 +00:00
gstein
60236803e4 This background will be needed when the website moves to SF.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@161 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-02 19:50:51 +00:00
gstein
a26cfff0ad fix viewcvs-browsing link on the page
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@160 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-02 19:27:36 +00:00
akr
f0c34a715d fixed at viewcvs.cgi:1.57.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@159 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-05-01 05:34:41 +00:00
akr
4cb1282b70 change option name for tarball generation from tarball' to allow_tar'.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@158 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-04-28 10:38:16 +00:00
akr
f34424ca20 make tarball generation configurable.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@157 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-04-28 08:50:28 +00:00
akr
bc6851ea6f separate branch and non-branch tags in tag menu.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@156 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-04-27 09:56:18 +00:00
akr
3b10a1763f tarball generation implemented.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@155 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-04-27 09:25:38 +00:00
akr
329d20633a use state instead of Attic/ to determine file existence if a tag is
specified.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@154 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-04-27 08:26:14 +00:00
akr
5251065e6d fix blame for empty deltatext especially 1.1 to 1.1.1.1.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@153 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-04-27 07:05:49 +00:00
akr
3d6f71ce00 couldn't handle multiple RCS-encoded string in single line.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@152 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-04-27 06:51:36 +00:00
akr
1a69430064 couldn't scan RCS-encoded string ends with @.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@151 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-04-27 06:44:20 +00:00
akr
050ad1f8fe add sticky info to blame link to fix problem with non-default repository.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@150 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-04-27 06:12:33 +00:00
akr
3965ce9221 ignore CVS directory in the repository which is used for fileattr.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@149 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-04-27 06:03:10 +00:00
akr
12003f27b5 branch selection fix. branchpoint entry may precede revisions on the
branch in rlog output.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@148 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-04-27 05:53:46 +00:00
gstein
b0b1b5603e Revamp the "co" output processing to give clearer errors. Be wary of
warnings that may be generated when doing the "co".


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@147 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-04-10 06:08:11 +00:00
gstein
2b8cc9d34c *) ignore a warning from rlog
*) fix the "hide_cvsroot" option flag processing


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@146 8cb11bc2-c004-0410-86c3-e597b4017df7
2001-04-10 05:36:06 +00:00
gstein
4ddb89e053 add the 0.6 references
add (missing) refs to who.html and license-1.html


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@144 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-07-25 12:16:33 +00:00
gstein
c9e782c881 rolling
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@143 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-07-25 12:02:21 +00:00
gstein
7d8f036490 not sure that I like the clickable_path parameters, but this is the quickest
way right now to ensure we get the "/" handled properly.
[ will need future review ]


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@142 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-07-25 12:00:26 +00:00
gstein
02bad3fbe3 duh :-)
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@141 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-07-25 11:59:22 +00:00
gstein
892364776e add trailing CR to the error message. use hasattr() rather than "in dir()"
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@139 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-07-02 00:44:05 +00:00
jpaint
8996332950 write error message to stderr instead of printing it so it will show
up in webserver logs


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@138 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-07-01 17:04:48 +00:00
jpaint
eb214de775 check MySQLdb for Timestamp() and friends; exit with a informitive error
of they don't exist.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@137 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-07-01 17:01:45 +00:00
jpaint
5ca77ced3c fix error -- use lowercase "dbi"
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@136 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-07-01 16:53:36 +00:00
jpaint
91d2ebfc64 move the dbi abstraction to dbi.py; I'll deal with various errors and
incompatibilities in different versions of MySQLdb here...


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@135 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-06-27 03:09:52 +00:00
gstein
ee7abc077a some minor tweaks from a while back
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@134 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-06-26 06:39:50 +00:00
gstein
087db42096 some stuff that had accumulated
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@133 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-06-26 06:39:06 +00:00
jpaint
028b54de90 modifications to accept the comma/command-seperated multiple query
strings


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@132 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-06-11 23:12:48 +00:00
jpaint
cb4f496b99 moved query object from lib/database.py to lib/query.py; expanded query
object to accept multiple directories,  repositories, authors, and files;
it also does regular expressions (optionally) now

Note: this commit doesn't leave the database in a very useable state,
      I'll fix that very soon.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@131 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-06-11 16:47:37 +00:00
jpaint
573293bbfc let people know Python 1.5.2 is a requirement for the SQL database part
of ViewCVS


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@130 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-06-01 23:04:48 +00:00
gstein
e6080c8366 execvp() can raise an exception, which means we never get to the sys.exit()
call. by wrapping it with try/except, we can ensure that get there.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@129 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-25 06:57:02 +00:00
gstein
346c91205b oops. parts[0] doesn't always exist.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@128 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-22 08:56:44 +00:00
gstein
3828e969de two changes:
1) try to fix a problem on FreeBSD where it seems the parent process is
     not waiting for the child (piped) processes to complete.
  2) handle the checkout_magic_path better -- it was showing up as the
     request.module and getting caught up in the 'forbidden' processing.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@127 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-22 08:48:07 +00:00
gstein
1a821bda9e add pipe_cmds() to set up a sequence of processes/pipes
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@126 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-22 08:46:04 +00:00
gstein
ddd782a950 The daylight flag should be zero since these values are in UTC. Problem
found by Chris Meyer <cmeyer@gatan.com>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@125 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-17 08:01:53 +00:00
gstein
f2dffceb6d fix bug found by Nick.T.Reinking@supervalu.com
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@124 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-17 06:56:11 +00:00
gstein
8810ab6c57 some fixes for Python 1.5(.1) compatibility. problems found by the help of
Bruce Langlois <bruce@acsp.com>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@123 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-17 06:42:49 +00:00
gstein
b21597d96d bunch of stuff about 0.5
additional updates, discussion, etc


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@122 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-12 11:07:37 +00:00
gstein
c553401843 roll 0.5
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@121 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-12 10:34:01 +00:00
gstein
ee8a705131 add compilation of lib/ files (running as the web server probably will not
allow a write to lib/, so we do it ahead of time)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@120 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-12 10:26:11 +00:00
gstein
665d46a59d minor tweaks. additional info/notes/etc
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@119 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-12 10:20:56 +00:00
gstein
15d7883bb0 add 'use_enscript' option
change the default allow_annotate to true.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@118 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-12 10:18:17 +00:00
gstein
6ed78e918e fix the links that are generated
the "primordial" revision no longer links to the directory. the user can do
    that from the navbar at the top of the page (a bit more intuitive).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@117 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-12 07:24:13 +00:00
jpaint
5463d8ff1b Updated the docs for the modified installation paths (ie, cgi/ directory
went away).  Maybe we should provide a sample .htaccess file which
instructs the webserver to refuse access to the non-cgi scripts.

Keep in mind I'm a Roxen fan, the the .htaccess files don't have all the
features they have in Apache ;)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@116 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-12 03:23:33 +00:00
jpaint
934209abb9 have rlog.py use the rcs path set in the config file
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@115 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-12 03:19:09 +00:00
jpaint
a19338dd0a first draft of updated INSTALL instructions -- comments/spelling fixed
probably needed


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@114 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-12 02:57:11 +00:00
gstein
ee6c5f5da3 don't create a cgi/ directory.
update the shell-bang line at the top of the executable files with the
    correct python executable path.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@113 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-12 01:56:50 +00:00
jpaint
43d6d82b34 added popen.py to the installer
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@112 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-12 00:25:00 +00:00
jpaint
7ad684b001 let's not broadcast my passwords to the world...
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@111 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-12 00:24:10 +00:00
jpaint
25e4e5d18a Fixed up viewcvs-install script. It includes a few
files, excludes a few we don't use, and added a new field to the install
file list which will prompt before overwriting a file (viewcvs.conf, for
example).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@110 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-11 23:55:07 +00:00
gstein
2719168ddc be more specific about what kind of markers we look for in a log output.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@109 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-11 22:34:46 +00:00
gstein
31272b7cea use dict.get() to simplify/speed some code.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@108 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-11 22:34:14 +00:00
jpaint
eb940183e3 script to create the MySQL database for the CVSdb part of ViewCVS
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@107 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-11 20:03:45 +00:00
gstein
33356d5a30 fix some previous-revision handling (generally failed on files with just a
single revision in them)
strip out the header/footer stuff from make_html()


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@106 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-11 11:15:54 +00:00
gstein
7ba05d4b43 revise some of the MIME type handling.
improve the header/footer for the annotated files


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@105 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-11 11:09:41 +00:00
gstein
083de4d0c7 initial testing/support for annotation using Curt's new module
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@104 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-11 01:13:23 +00:00
gstein
cbe1f36d8a remove unused code.
slight change to use math.log10()
fix problem with finding the end of a @-delimited token. It didn't work
    when the terminating @ was at the end of a line.
remove the CGI script stuff, but leave a direct-invocation for testing


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@103 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-11 01:12:33 +00:00
gstein
efa434d7fa use new popen.popen() for more security and to deal with filenames that
have quotes in them.
improve the check for "unified" format in diff output
detect and properly handle "\ No newline at end of file" during diff output


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@102 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-10 01:09:16 +00:00
gstein
7fc9018074 allow errors to be captured or tossed.
fix small bug with mode=='w' (use correct file for stdout/stderr)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@101 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-10 00:58:44 +00:00
gstein
a7fe838521 better version of popen(), which allows us to not worry about quoting the
arguments to the target program.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@100 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-09 22:38:21 +00:00
gstein
a1e7108d76 small tweak to get this working right. 'token' had an empty string, so the
reference to token[-1] raised an error.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@99 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-09 11:48:49 +00:00
gstein
867883e525 untabify. indent changed, too.
despite the size of this diff, there were NO code changes. "cvs diff -b"
    to see that the change was whitespace only.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@98 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-09 11:21:30 +00:00
gstein
2f376b11e3 quicky script to build releases
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@97 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-09 11:00:50 +00:00
gstein
07763938a3 fix typo
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@96 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-09 10:30:29 +00:00
gstein
182aeaa7fa various simplification of the code. use re.sub() rather than line-by-line
replacements for the config variable stuff.
output a bit more information when unknown errors occur.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@95 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-09 10:29:13 +00:00
gstein
75d59eb292 add os.makedirs() compatibility
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@94 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-09 10:28:07 +00:00
gstein
18048c0a80 update the copyright and license information.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@93 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-09 08:36:29 +00:00
gstein
fb262791a1 first draft of the license and the "who" pages.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@92 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-09 02:27:16 +00:00
gstein
b2d9bf88a1 add virtual host capability: each set of vhosts can override the common
settings.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@91 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-09 02:00:56 +00:00
gstein
8e94cc5775 add more complex "forbidden" patterns (requested by Jon Stevens @ ASF)
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@90 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-08 23:54:35 +00:00
gstein
e8c829df09 expand the use of enscript. provide for disabling specific languages in case
the local installation of enscript does not support them.
add a footer to the bottom of all "marked up" displays
pass the "guessed" MIME type to markup_stream() so that we can properly
    detect images and display them properly.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@89 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-08 04:57:31 +00:00
gstein
b892974ffe deal with a diff that reports no change
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@88 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-07 13:16:34 +00:00
gstein
78022b0e38 from Tanaka Akira <akr@m17n.org>: add elisp colorization via the "enscript"
program.
  Greg mods: configured with allow_elisp_coloring and enscript_path. read
  and write in chunks rather than slurping in the entire source file.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@87 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-05-07 12:54:02 +00:00
gstein
17c4db41dc initial checkin from Curt.
this currently operates as a CGI, but we will be integrating it as a part
    of viewcvs.cgi; therefore, it is going into lib/ to become a module.
this file is "pure" Curt except for the license in the header (changed per
    Curt's email to the viewcvs-dev list), and some comments about it
    being maintained as part of the ViewCVS project.
    [ change will progress from this snapshot ]


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@86 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-04-28 14:01:48 +00:00
jpaint
8070b6bba1 import string -- fix bug
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@85 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-04-27 17:48:05 +00:00
jpaint
c8ebba802e * CVSdb now uses viewcvs.conf
* added licence text for lib/compat.py lib/config.py
* viewcvs-install now installs + sets all the paths and modes for
	installed files


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@84 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-04-26 22:46:47 +00:00
jpaint
5b24650755 just a little bit more work
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@83 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-04-25 22:26:59 +00:00
jpaint
8b9a143376 fixed bug where we called the old exit function and it's no longer
there!


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@82 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-04-25 20:35:13 +00:00
jpaint
741a3daefe working on quick-n-dirty installer in Python which will allow us to get
a release out before too long; I need to make a list of to-do items
so this is easy to get working...


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@81 8cb11bc2-c004-0410-86c3-e597b4017df7
2000-04-25 18:44:33 +00:00
29 changed files with 5418 additions and 2655 deletions

125
INSTALL
View File

@@ -9,20 +9,32 @@ INSTALLING VIEWCVS
You need to have RCS installed. Specifically, "rlog", "rcsdiff",
and "co". This script was tested against RedHat's rcs-5.7-10.rpm
Note, that the viewcvs.cgi-script needs to have READ-ONLY, physical
access to the repository (or a copy of it). Therefore, rsh/ssh or
Note, that the viewcvs.cgi script needs to have READ-ONLY, physical
access to the CVS repository (or a copy of it). Therefore, rsh/ssh or
pserver access doesn't work yet.
2) Copy viewcvs.cgi to the cgi-script location of your web server.
For the checkin database to work, you will need MySQL >= 3.22,
and the Python DBAPI 2.0 module, MySQLdb. This was tested with
MySQLdb 1.12.
If Python is not located in /usr/local/bin, then you'll need to
edit the first line of viewcvs.cgi.
2) Installation is handled by the ./viewcvs-install script. Run this
script and you will be prompted for a installation root path.
The default is /usr/local/viewcvs. The installer sets the install
path in some of the files, and ViewCVS cannot be moved to a
different path after the install.
3) Copy viewcvs.conf.dist to the same directory and RENAME it to
viewcvs.conf
Note: while 'root' is usually required to create /usr/local/viewcvs,
ViewCVS does not have to be installed as root, nor does it run as root.
It is just as valid to place ViewCVS in a home directory, too.
4) Edit viewcvs.conf for your specific configuration. In particular,
examine the following configuration options:
Note: viewcvs-install will create directories if needed. It will
prompt before overwriting files that may have been modified (such
as viewcvs.conf), thus making it safe to install over the top of
a previous installation. It will always overwrite program files,
however.
3) Edit <install-root>viewcvs.conf for your specific configuration.
In particular, examine the following configuration options:
cvs_roots
default_root
@@ -32,11 +44,98 @@ INSTALLING VIEWCVS
There are some other options that are usually nice to change. See
viewcvs.conf for more information.
5) That's it. Try it out.
4) The CGI programs are in <install-root>/cgi/. You can symlink to this
directory from somewhere in your published HTTP server path if your
webserver is configured to follow symbolic links. You can also copy
the installed <install-root>/cgi/*.cgi scripts after the install
(unlike the other files in ViewCVS, the CGI scripts can be moved).
Warning: ViewCVS has not been tested on web servers operating on the
Win32 platform.
NOTE: for security reasons, it is not advisable to install ViewCVS
directly into your published HTTP directory tree (due to the MySQL
passwords in viewcvs.conf).
5) That's it for repository browsing. Instructions for getting the
SQL checkin database working are below.
WARNING: ViewCVS has not been tested on web servers operating on the
Win32 platform.
SQL Checkin Database
--------------------
This feature is a clone of the Mozilla Project's Bonsai database. It
catalogs every commit in the CVS repository into a SQL database. In fact,
the databases are 100% compatible.
Various queries can be preformed on the database. After installing ViewCVS,
there are some additional steps required to get the database working.
1) You need MySQL >= 3.22, and the Python module MySQLdb >= 1.12 installed.
Python 1.5.2 is REQUIRED by MySQLdb, therefore to use this part of
ViewCVS you must be useing Python 1.5.2.
2) You need to create a MySQL user who has permission to create databases.
Optionally, you can create a second user with read-only access to the
database.
3) Run the <install-root>/make-database script. It will prompt you for
your MySQL user, password, and the name of database you want to
create. The database name defaults to "ViewCVS". This script creates
the database and sets up the empty tables. If you run this on a
existing ViewCVS database, you will loose all your data!
4) Edit your <install-root>/viewcvs.conf file. There is a [cvsdb]
section. You will need to set:
host = # MySQL database server host
database_name = # the name of the database you created with
# make-database
user = # the read/write database user
passwd = # password for read/write database user
readonly_user = # the readonly database user -- it's pretty
# safe to use the read/write user here
readonly_passwd = # password for the readonly user
5) Two programs are provided for updating the checkin database,
cvsdbadmin and loginfo-handler. They serve two different purposes.
The cvsdbadmin program walks through your CVS repository and adds
every commit in every file. This is commonly used for initalizing
the database from a repository which has been in use. The
loginfo-handler script is executed by the CVS server's CVSROOT/loginfo
system upon each commit. It makes real-time updates to the checkin
database as commits are made to the repository.
To build a database of all the commits in the CVS repository /home/cvs,
invoke: "./cvsdbadmin rebuild /home/cvs". If you want to update
the checkin database, invoke: "./cvsdbadmin update /home/cvs". The
update mode checks to see if a commit is already in the database,
and only adds it if it is abscent.
To get real-time updates, you'll want to checkout the CVSROOT module
from your CVS repository and edit CVSROOT/loginfo. Add the line:
ALL (echo %{sVv}; cat) | <install-root>/loginfo-handler
If you have other scripts invoked by CVSROOT/loginfo, you will want
to make sure to change any running under the "DEFAULT" keyword to
"ALL" like the loginfo handler, and probably carefully read the
execution rules for CVSROOT/loginfo from the CVS manual.
6) You may want to modify the HTML template files:
<install-root>/html-templates/queryformtemplate.html
<install-root>/html-templates/querytemplate.html
They're used by the queryform.cgi and query.cgi scripts generate
HTML output. At some point, viewcvs.cgi, query.cgi, and queryform.cgi
will use the same mechanism for HTML generation, but not yet.
7) You should be ready to go. Load up the queryform.cgi script and give
it a try.
IF YOU HAVE PROBLEMS ...
@@ -75,7 +174,7 @@ If you've trouble to make viewcvs.cgi work:
o check the ViewCVS home page:
http://www.lyra.org/greg/python/viewcvs/
http://viewcvs.sourceforge.net/
o review the ViewCVS mailing list archive to see if somebody else had
the same problem, and it was solved:

25
TODO
View File

@@ -14,25 +14,26 @@ TODO ITEMS
*) committing with a specific revision number:
http://mailman.lyra.org/pipermail/viewcvs/2000q1/000008.html
*) add an "allowed" modules. process the forbidden modules first. any
match will throw it out immediately. if an allowed is present, then
disallow any module unless it is present in the allowed list.
*) provide a virtual host capability. consider multiple hosts which
map a particular Location to the same directory (i.e. the same
ViewCVS script and config file). provide for a way to have global
options plus vhost-specific options.
*) add capability similar to cvs2cl.pl:
http://mailman.lyra.org/pipermail/viewcvs/2000q2/000050.html
suggestion from Chris Meyer <cmeyer@gatan.com>.
*) add a tree view of the directory structure (and files?)
*) include a ConfigParser.py to help older Python installations
*) add a check for the rcs programs/paths to viewcvs-install. clarify the
dependency on RCS in the docs.
*) add a page that describes how to reach anonymous CVS for ViewCVS
*) have a "check" mode that verifies binaries are available on rcs_path
-> alternately (probably?): use rcsparse rather than external tools
KNOWN BUGS
----------
*) from Harri Pasanen, Feb 7: when hideattic is set, files added in a
branch are not visible.
*) from Dieter Deyke, Jan 12: if the CVS revisions differ by just a
keyword, then the diff output chokes.

View File

@@ -1,89 +1,206 @@
#!/usr/bin/python
# -*- Mode: python -*-
#
# Copyright (C) 2000-2001 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 ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
# CGI script to process and display queries to CVSdb
#
# -----------------------------------------------------------------------
# Copyright (C) 2000 Jay Painter. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth below:
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
# This script is part of the ViewCVS package. More information can be
# found at http://viewcvs.sourceforge.net/.
#
# -----------------------------------------------------------------------
#
# For tracking purposes, this software is identified by:
# $Id$
#
# -----------------------------------------------------------------------
## BOOTSTRAP
import sys, os, string
_viewcvs_root = string.strip(open("/etc/viewcvs/root", "r").read())
sys.path.append(os.path.join(_viewcvs_root, "lib"))
##
#########################################################################
#
# INSTALL-TIME CONFIGURATION
#
# These values will be set during the installation process. During
# development, they will remain None.
#
LIBRARY_DIR = None
CONF_PATHNAME = None
HTML_TEMPLATE_DIR = None
# Adjust sys.path to include our library directory
import sys
if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
else:
sys.path[:0] = ['../lib'] # any other places to look?
#########################################################################
import os
import string
import cgi
import time
import cvsdbapi
import cgi, time, cvsdbapi
## tuple of alternating row colors
Colors = ("#ccccee", "#ffffff")
def HTMLHeader():
print "Content-type: text/html"
print
## returns a tuple-list (mod-str, string)
def listparse_string(str):
return_list = []
cmd = ""
temp = ""
escaped = 0
state = "eat leading whitespace"
for c in str:
## handle escaped charactors
if not escaped and c == "\\":
escaped = 1
continue
## strip leading white space
if state == "eat leading whitespace":
if c in string.whitespace:
continue
else:
state = "get command or data"
## parse to '"' or ","
if state == "get command or data":
## just add escaped charactors
if escaped:
escaped = 0
temp = temp + c
continue
## the data is in quotes after the command
elif c == "\"":
cmd = temp
temp = ""
state = "get quoted data"
continue
## this tells us there was no quoted data, therefore no
## command; add the command and start over
elif c == ",":
## strip ending whitespace on un-quoted data
temp = string.rstrip(temp)
return_list.append( ("", temp) )
temp = ""
state = "eat leading whitespace"
continue
## record the data
else:
temp = temp + c
continue
## parse until ending '"'
if state == "get quoted data":
## just add escaped charactors
if escaped:
escaped = 0
temp = temp + c
continue
## look for ending '"'
elif c == "\"":
return_list.append( (cmd, temp) )
cmd = ""
temp = ""
state = "eat comma after quotes"
continue
## record the data
else:
temp = temp + c
continue
## parse until ","
if state == "eat comma after quotes":
if c in string.whitespace:
continue
elif c == ",":
state = "eat leading whitespace"
continue
else:
print "format error"
sys.exit(1)
if cmd or temp:
return_list.append( (cmd, temp) )
return return_list
def decode_command(cmd):
if cmd == "r":
return "regex"
elif cmd == "l":
return "like"
else:
return "exact"
def FormToCheckinQuery(form):
query = cvsdbapi.CreateCheckinQuery()
if form.has_key("repository"):
temp = form["repository"].value
query.SetRepository(temp)
for cmd, str in listparse_string(temp):
cmd = decode_command(cmd)
query.SetRepository(str, cmd)
if form.has_key("branch"):
temp = form["branch"].value
query.SetBranch(temp)
for cmd, str in listparse_string(temp):
cmd = decode_command(cmd)
query.SetBranch(str, cmd)
if form.has_key("directory"):
temp = form["directory"].value
query.SetDirectory(temp)
for cmd, str in listparse_string(temp):
cmd = decode_command(cmd)
query.SetDirectory(str, cmd)
if form.has_key("file"):
temp = form["file"].value
query.SetFile(temp)
for cmd, str in listparse_string(temp):
cmd = decode_command(cmd)
query.SetFile(str, cmd)
if form.has_key("who"):
temp = form["who"].value
query.SetAuthor(temp)
for cmd, str in listparse_string(temp):
cmd = decode_command(cmd)
query.SetAuthor(str, cmd)
if form.has_key("sortby"):
temp = form["sortby"].value
if temp == "date":
query.SetSortMethod(query.SORT_DATE)
query.SetSortMethod("date")
elif temp == "author":
query.SetSortMethod(query.SORT_AUTHOR)
query.SetSortMethod("author")
else:
query.SetSortMethod(query.SORT_FILE)
query.SetSortMethod("file")
if form.has_key("date"):
temp = form["date"].value
@@ -180,10 +297,9 @@ class HTMLTemplate:
def Main():
HTMLHeader()
print "Content-type: text/html\n\n"
template_path = os.path.join(
_viewcvs_root, "html-templates", "querytemplate.html")
template_path = os.path.join(HTML_TEMPLATE_DIR, "querytemplate.html")
template = HTMLTemplate(template_path)
template.Print1()

View File

@@ -1,46 +1,42 @@
#!/usr/bin/python
# -*- Mode: python -*-
#
# nothing here yet!
# Copyright (C) 2000-2001 The ViewCVS Group. All Rights Reserved.
#
# -----------------------------------------------------------------------
# Copyright (C) 2000 Jay Painter. 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 ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# By using this file, you agree to the terms and conditions set forth below:
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
# For tracking purposes, this software is identified by:
# $Id$
#
# -----------------------------------------------------------------------
## BOOTSTRAP
import sys, os, string
_viewcvs_root = string.strip(open("/etc/viewcvs/root", "r").read())
sys.path.append(os.path.join(_viewcvs_root, "lib"))
##
#########################################################################
#
# INSTALL-TIME CONFIGURATION
#
# These values will be set during the installation process. During
# development, they will remain None.
#
LIBRARY_DIR = None
CONF_PATHNAME = None
HTML_TEMPLATE_DIR = None
# Adjust sys.path to include our library directory
import sys
if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
else:
sys.path[:0] = ['../lib'] # any other places to look?
#########################################################################
import os, string
def HTMLHeader():
@@ -50,8 +46,7 @@ def HTMLHeader():
def Main():
HTMLHeader()
template_path = os.path.join(
_viewcvs_root, "html-templates", "queryformtemplate.html")
template_path = os.path.join(HTML_TEMPLATE_DIR, "queryformtemplate.html")
print open(template_path, "r").read()

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@
# Configuration file for ViewCVS
#
# Information on ViewCVS is located at the following web site:
# http://www.lyra.org/viewcvs/
# http://viewcvs.sourceforge.net/
#
#---------------------------------------------------------------------------
@@ -28,6 +28,8 @@
# long_intro
# repository_info
#
# use_enscript
#
# For Python source colorization:
#
# py2html_path
@@ -94,19 +96,55 @@ main_title = CVS Repository
# This should contain a list of modules in the repository that should not be
# displayed (by default or by explicit path specification).
#
# This configuration can be a simple list of modules, or it can get quite
# complex:
#
# *) The "!" can be used before a module to explicitly state that it
# is NOT forbidden. Whenever this form is seen, then all modules will
# be forbidden unless one of the "!" modules match.
#
# *) Shell-style "glob" expressions may be used. "*" will match any
# sequence of zero or more characters, "?" will match any single
# character, "[seq]" will match any character in seq, and "[!seq]"
# will match any character not in seq.
#
# *) Tests are performed in sequence. The first match will terminate the
# testing. This allows for more complex allow/deny patterns.
#
# Tests are case-sensitive.
#
forbidden =
# forbidden = example
# forbidden = example1, example2
# Some examples:
#
# Disallow "example" but allow all others:
# forbidden = example
#
# Disallow "example1" and "example2" but allow all others:
# forbidden = example1, example2
#
# Allow *only* "example1" and "example2":
# forbidden = !example1, !example2
#
# Forbid modules starting with "x":
# forbidden = x*
#
# Allow modules starting with "x" but no others:
# forbidden = !x*
#
# Allow "xml", forbid other modules starting with "x", and allow the rest:
# forbidden = !xml, x*, !*
#
#---------------------------------------------------------------------------
[cvsdb]
host = master
database_name = bonsai
user = root
passwd = ogieta50
readonly_user = root
readonly_passwd = ogieta50
#host = localhost
#database_name = ViewCVS
#user =
#passwd =
#readonly_user =
#readonly_passwd =
#---------------------------------------------------------------------------
[images]
@@ -202,7 +240,7 @@ long_intro =
</p>
<p>
This script
(<a href="http://www.lyra.org/viewcvs/">ViewCVS</a>)
(<a href="http://viewcvs.sourceforge.net/">ViewCVS</a>)
has been written by Greg Stein
&lt;<a href="mailto:gstein@lyra.org">gstein@lyra.org</a>&gt;
based on the
@@ -214,7 +252,7 @@ long_intro =
Licence</a>.
If you would like to use this CGI script on your own web server and
CVS tree, see Greg's
<a href="http://www.lyra.org/viewcvs/">ViewCVS distribution
<a href="http://viewcvs.sourceforge.net/">ViewCVS distribution
site</a>.
Please send any suggestions, comments, etc. to
<a href="mailto:gstein@lyra.org">Greg Stein</a>.
@@ -224,9 +262,9 @@ doc_info =
<h3>CVS Documentation</h3>
<blockquote>
<p>
<a href="http://cvsbook.red-bean.com/">Karl Fogel's CVS book</a><br>
<a href="http://www.loria.fr/~molli/cvs/doc/cvs_toc.html">CVS
User's Guide</a><br>
<a href="http://www.arc.unm.edu/~rsahu/cvs.html">CVS Tutorial</a><br>
<a href="http://cellworks.washington.edu/pub/docs/cvs/tutorial/cvs_tutorial_1.html">Another CVS tutorial</a><br>
<a href="http://www.csc.calpoly.edu/~dbutler/tutorials/winter96/cvs/">Yet
another CVS tutorial (a little old, but nice)</a><br>
@@ -307,7 +345,7 @@ hr_ignore_keyword_subst = 1
# NOTE: this requires rw-access to the CVSROOT/history file, and rw-access to
# the subdirectory to place the lock... so you maybe don't want it
# WARNING: this is not yet implemented!!
allow_annotate = 0
allow_annotate = 1
# allow pretty-printed version of files
allow_markup = 1
@@ -378,4 +416,59 @@ diff_font_size = -1
# the width of the textinput in the request-diff-form
input_text_size = 12
# should we use 'enscript' for syntax coloring?
use_enscript = 0
#
# if the enscript program is not on the path, set this value
# Note: there should be a trailing slash
#
enscript_path =
# enscript_path = /usr/bin/
#
# ViewCVS has its own set of mappings from filename extensions and filenames
# to languages. If the language is not supported by enscript, then it can
# be listed here to disable the use of enscript.
#
disable_enscript_lang =
# disable_enscript_lang = perl, cpp
#
# ViewCVS can generate tarball from a repository on the fly.
#
allow_tar = 0
# allow_tar = 1
#---------------------------------------------------------------------------
[vhosts]
### DOC
# vhost1 = glob1, glob2
# vhost2 = glob3, glob4
# [vhost1-section]
# option = value
# [vhost1-othersection]
# option = value
# [vhost2-section]
# option = value
#
# Here is an example:
#
# [vhosts]
# lyra = *lyra.org
#
# [lyra-general]
# forbidden = hideme
#
# [lyra-options]
# show_logs = 0
#
# Note that "lyra" is the "canonical" name for all hosts in the lyra.org
# domain. This canonical name is then used within the additional, vhost-
# specific sections to override specific values in the common sections.
#
#---------------------------------------------------------------------------

576
lib/blame.py Normal file
View File

@@ -0,0 +1,576 @@
#!/usr/local/bin/python
# -*-python-*-
#
# Copyright (C) 2000-2001 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 2000 Curt Hagenlocher <curt@hagenlocher.org>
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
# blame.py: Annotate each line of a CVS file with its author,
# revision #, date, etc.
#
# -----------------------------------------------------------------------
#
# This software is being maintained as part of the ViewCVS project.
# Information is available at:
# http://viewcvs.sourceforge.net/
#
# This file is based on the cvsblame.pl portion of the Bonsai CVS tool,
# developed by Steve Lamm for Netscape Communications Corporation. More
# information about Bonsai can be found at
# http://www.mozilla.org/bonsai.html
#
# cvsblame.pl, in turn, was based on Scott Furman's cvsblame script
#
# -----------------------------------------------------------------------
#
import string
import sys
import os
import re
import time
import math
import cgi
import rcsparse
class CVSParser(rcsparse.Sink):
# Precompiled regular expressions
trunk_rev = re.compile('^[0-9]+\\.[0-9]+$')
last_branch = re.compile('(.*)\\.[0-9]+')
is_branch = re.compile('(.*)\\.0\\.([0-9]+)')
d_command = re.compile('^d(\d+)\\s(\\d+)')
a_command = re.compile('^a(\d+)\\s(\\d+)')
SECONDS_PER_DAY = 86400
def __init__(self):
self.Reset()
def Reset(self):
self.last_revision = {}
self.prev_revision = {}
self.revision_date = {}
self.revision_author = {}
self.revision_branches = {}
self.next_delta = {}
self.prev_delta = {}
self.tag_revision = {}
self.revision_symbolic_name = {}
self.timestamp = {}
self.revision_ctime = {}
self.revision_age = {}
self.revision_log = {}
self.revision_deltatext = {}
self.revision_map = []
self.lines_added = {}
self.lines_removed = {}
# Map a tag to a numerical revision number. The tag can be a symbolic
# branch tag, a symbolic revision tag, or an ordinary numerical
# revision number.
def map_tag_to_revision(self, tag_or_revision):
try:
revision = self.tag_revision[tag_or_revision]
match = self.is_branch.match(revision)
if match:
branch = match.group(1) + '.' + match.group(2)
if self.last_revision.get(branch):
return self.last_revision[branch]
else:
return match.group(1)
else:
return revision
except:
return ''
# Construct an ordered list of ancestor revisions to the given
# revision, starting with the immediate ancestor and going back
# to the primordial revision (1.1).
#
# Note: The generated path does not traverse the tree the same way
# that the individual revision deltas do. In particular,
# the path traverses the tree "backwards" on branches.
def ancestor_revisions(self, revision):
ancestors = []
revision = self.prev_revision.get(revision)
while revision:
ancestors.append(revision)
revision = self.prev_revision.get(revision)
return ancestors
# Split deltatext specified by rev to each line.
def deltatext_split(self, rev):
lines = string.split(self.revision_deltatext[rev], '\n')
if lines[-1] == '':
del lines[-1]
return lines
# Extract the given revision from the digested RCS file.
# (Essentially the equivalent of cvs up -rXXX)
def extract_revision(self, revision):
path = []
add_lines_remaining = 0
start_line = 0
count = 0
while revision:
path.append(revision)
revision = self.prev_delta.get(revision)
path.reverse()
path = path[1:] # Get rid of head revision
text = self.deltatext_split(self.head_revision)
# Iterate, applying deltas to previous revision
for revision in path:
adjust = 0
diffs = self.deltatext_split(revision)
self.lines_added[revision] = 0
self.lines_removed[revision] = 0
lines_added_now = 0
lines_removed_now = 0
for command in diffs:
dmatch = self.d_command.match(command)
amatch = self.a_command.match(command)
if add_lines_remaining > 0:
# Insertion lines from a prior "a" command
text.insert(start_line + adjust, command)
add_lines_remaining = add_lines_remaining - 1
adjust = adjust + 1
elif dmatch:
# "d" - Delete command
start_line = string.atoi(dmatch.group(1))
count = string.atoi(dmatch.group(2))
begin = start_line + adjust - 1
del text[begin:begin + count]
adjust = adjust - count
lines_removed_now = lines_removed_now + count
elif amatch:
# "a" - Add command
start_line = string.atoi(amatch.group(1))
count = string.atoi(amatch.group(2))
add_lines_remaining = count
lines_added_now = lines_added_now + count
else:
raise RuntimeError, 'Error parsing diff commands'
self.lines_added[revision] = self.lines_added[revision] + lines_added_now
self.lines_removed[revision] = self.lines_removed[revision] + lines_removed_now
return text
def set_head_revision(self, revision):
self.head_revision = revision
def set_principal_branch(self, branch_name):
self.principal_branch = branch_name
def define_tag(self, name, revision):
# Create an associate array that maps from tag name to
# revision number and vice-versa.
self.tag_revision[name] = revision
### actually, this is a bit bogus... a rev can have multiple names
self.revision_symbolic_name[revision] = name
def set_comment(self, comment):
self.file_description = comment
def set_description(self, description):
self.rcs_file_description = description
# Construct dicts that represent the topology of the RCS tree
# and other arrays that contain info about individual revisions.
#
# The following dicts are created, keyed by revision number:
# self.revision_date -- e.g. "96.02.23.00.21.52"
# self.timestamp -- seconds since 12:00 AM, Jan 1, 1970 GMT
# self.revision_author -- e.g. "tom"
# self.revision_branches -- descendant branch revisions, separated by spaces,
# e.g. "1.21.4.1 1.21.2.6.1"
# self.prev_revision -- revision number of previous *ancestor* in RCS tree.
# Traversal of this array occurs in the direction
# of the primordial (1.1) revision.
# self.prev_delta -- revision number of previous revision which forms
# the basis for the edit commands in this revision.
# This causes the tree to be traversed towards the
# trunk when on a branch, and towards the latest trunk
# revision when on the trunk.
# self.next_delta -- revision number of next "delta". Inverts prev_delta.
#
# Also creates self.last_revision, keyed by a branch revision number, which
# indicates the latest revision on a given branch,
# e.g. self.last_revision{"1.2.8"} == 1.2.8.5
def define_revision(self, revision, timestamp, author, state,
branches, next):
self.tag_revision[revision] = revision
branch = self.last_branch.match(revision).group(1)
self.last_revision[branch] = revision
#self.revision_date[revision] = date
self.timestamp[revision] = timestamp
# Pretty print the date string
ltime = time.localtime(self.timestamp[revision])
formatted_date = time.strftime("%d %b %Y %H:%M", ltime)
self.revision_ctime[revision] = formatted_date
# Save age
self.revision_age[revision] = ((time.time() - self.timestamp[revision])
/ self.SECONDS_PER_DAY)
# save author
self.revision_author[revision] = author
# ignore the state
# process the branch information
branch_text = ''
for branch in branches:
self.prev_revision[branch] = revision
self.next_delta[revision] = branch
self.prev_delta[branch] = revision
branch_text = branch_text + branch + ''
self.revision_branches[revision] = branch_text
# process the "next revision" information
if next:
self.next_delta[revision] = next
self.prev_delta[next] = revision
is_trunk_revision = self.trunk_rev.match(revision) is not None
if is_trunk_revision:
self.prev_revision[revision] = next
else:
self.prev_revision[next] = revision
# Construct associative arrays containing info about individual revisions.
#
# The following associative arrays are created, keyed by revision number:
# revision_log -- log message
# revision_deltatext -- Either the complete text of the revision,
# in the case of the head revision, or the
# encoded delta between this revision and another.
# The delta is either with respect to the successor
# revision if this revision is on the trunk or
# relative to its immediate predecessor if this
# revision is on a branch.
def set_revision_info(self, revision, log, text):
self.revision_log[revision] = log
self.revision_deltatext[revision] = text
def parse_cvs_file(self, rcs_pathname, opt_rev = None, opt_m_timestamp = None):
# Args in: opt_rev - requested revision
# opt_m - time since modified
# Args out: revision_map
# timestamp
# revision_deltatext
# CheckHidden(rcs_pathname);
try:
rcsfile = open(rcs_pathname, 'r')
except:
raise RuntimeError, ('error: %s appeared to be under CVS control, ' +
'but the RCS file is inaccessible.') % rcs_pathname
rcsparse.Parser().parse(rcsfile, self)
rcsfile.close()
if opt_rev in [None, '', 'HEAD']:
# Explicitly specified topmost revision in tree
revision = self.head_revision
else:
# Symbolic tag or specific revision number specified.
revision = self.map_tag_to_revision(opt_rev)
if revision == '':
raise RuntimeError, 'error: -r: No such revision: ' + opt_rev
# The primordial revision is not always 1.1! Go find it.
primordial = revision
while self.prev_revision.get(primordial):
primordial = self.prev_revision[primordial]
# Don't display file at all, if -m option is specified and no
# changes have been made in the specified file.
if opt_m_timestamp and self.timestamp[revision] < opt_m_timestamp:
return ''
# Figure out how many lines were in the primordial, i.e. version 1.1,
# check-in by moving backward in time from the head revision to the
# first revision.
line_count = 0
if self.revision_deltatext.get(self.head_revision):
tmp_array = self.deltatext_split(self.head_revision)
line_count = len(tmp_array)
skip = 0
rev = self.prev_revision.get(self.head_revision)
while rev:
diffs = self.deltatext_split(rev)
for command in diffs:
dmatch = self.d_command.match(command)
amatch = self.a_command.match(command)
if skip > 0:
# Skip insertion lines from a prior "a" command
skip = skip - 1
elif dmatch:
# "d" - Delete command
start_line = string.atoi(dmatch.group(1))
count = string.atoi(dmatch.group(2))
line_count = line_count - count
elif amatch:
# "a" - Add command
start_line = string.atoi(amatch.group(1))
count = string.atoi(amatch.group(2))
skip = count;
line_count = line_count + count
else:
raise RuntimeError, 'error: illegal RCS file'
rev = self.prev_revision.get(rev)
# Now, play the delta edit commands *backwards* from the primordial
# revision forward, but rather than applying the deltas to the text of
# each revision, apply the changes to an array of revision numbers.
# This creates a "revision map" -- an array where each element
# represents a line of text in the given revision but contains only
# the revision number in which the line was introduced rather than
# the line text itself.
#
# Note: These are backward deltas for revisions on the trunk and
# forward deltas for branch revisions.
# Create initial revision map for primordial version.
self.revision_map = [primordial] * line_count
ancestors = [revision, ] + self.ancestor_revisions(revision)
ancestors = ancestors[:-1] # Remove "1.1"
last_revision = primordial
ancestors.reverse()
for revision in ancestors:
is_trunk_revision = self.trunk_rev.match(revision) is not None
if is_trunk_revision:
diffs = self.deltatext_split(last_revision)
# Revisions on the trunk specify deltas that transform a
# revision into an earlier revision, so invert the translation
# of the 'diff' commands.
for command in diffs:
if skip > 0:
skip = skip - 1
else:
dmatch = self.d_command.match(command)
amatch = self.a_command.match(command)
if dmatch:
start_line = string.atoi(dmatch.group(1))
count = string.atoi(dmatch.group(2))
temp = []
while count > 0:
temp.append(revision)
count = count - 1
self.revision_map = (self.revision_map[:start_line - 1] +
temp + self.revision_map[start_line - 1:])
elif amatch:
start_line = string.atoi(amatch.group(1))
count = string.atoi(amatch.group(2))
del self.revision_map[start_line:start_line + count]
skip = count
else:
raise RuntimeError, 'Error parsing diff commands'
else:
# Revisions on a branch are arranged backwards from those on
# the trunk. They specify deltas that transform a revision
# into a later revision.
adjust = 0
diffs = self.deltatext_split(revision)
for command in diffs:
if skip > 0:
skip = skip - 1
else:
dmatch = self.d_command.match(command)
amatch = self.a_command.match(command)
if dmatch:
start_line = string.atoi(dmatch.group(1))
count = string.atoi(dmatch.group(2))
del self.revision_map[start_line + adjust - 1:start_line + adjust - 1 + count]
adjust = adjust - count
elif amatch:
start_line = string.atoi(amatch.group(1))
count = string.atoi(amatch.group(2))
skip = count
temp = []
while count > 0:
temp.append(revision)
count = count - 1
self.revision_map = (self.revision_map[:start_line + adjust] +
temp + self.revision_map[start_line + adjust:])
adjust = adjust + skip
else:
raise RuntimeError, 'Error parsing diff commands'
last_revision = revision
return revision
re_includes = re.compile('\\#(\\s*)include(\\s*)"(.*?)"')
re_filename = re.compile('(.*[\\\\/])?(.+)')
def link_includes(text, root, rcs_path, sticky = None):
match = re_includes.match(text)
if match:
incfile = match.group(3)
for rel_path in ('', 'Attic', '..'):
trial_root = os.path.join(rcs_path, rel_path)
file = os.path.join(root, trial_root)
file = os.path.normpath(os.path.join(file, incfile + ',v'))
if os.access(file, os.F_OK):
url = os.path.join(rel_path, incfile)
if sticky:
url = url + '?' + sticky
return '#%sinclude%s"<a href="%s">%s</a>"' % \
(match.group(1), match.group(2), url, incfile)
return text
def make_html(root, rcs_path, opt_rev = None, sticky = None):
filename = os.path.join(root, rcs_path)
parser = CVSParser()
revision = parser.parse_cvs_file(filename, opt_rev)
count = len(parser.revision_map)
text = parser.extract_revision(revision)
if len(text) != count:
raise RuntimeError, 'Internal consistency error'
match = re_filename.match(rcs_path)
if not match:
raise RuntimeError, 'Unable to parse filename'
file_head = match.group(1)
file_tail = match.group(2)
open_table_tag = '<table border=0 cellpadding=0 cellspacing=0 width="100%">'
startOfRow = '<tr><td colspan=3%s><pre>'
endOfRow = '</td></tr>'
print open_table_tag + (startOfRow % '')
if count == 0:
count = 1
line_num_width = int(math.log10(count)) + 1
revision_width = 3
author_width = 5
line = 0
usedlog = {}
usedlog[revision] = 1
old_revision = 0
row_color = ''
lines_in_table = 0
inMark = 0
rev_count = 0
for revision in parser.revision_map:
thisline = text[line]
line = line + 1
usedlog[revision] = 1
line_in_table = lines_in_table + 1
# Escape HTML meta-characters
thisline = cgi.escape(thisline)
# Add a link to traverse to included files
if 1: # opt_includes
thisline = link_includes(thisline, root, file_head, sticky)
output = ''
# Highlight lines
#mark_cmd;
#if (defined($mark_cmd = $mark_line{$line}) and mark_cmd != 'end':
# output = output + endOfRow + '<tr><td bgcolor=LIGHTGREEN width="100%"><pre>'
# inMark = 1
if old_revision != revision and line != 1:
if row_color == '':
row_color = ' bgcolor="#e7e7e7"'
else:
row_color = ''
if not inMark:
if lines_in_table > 100:
output = output + endOfRow + '</table>' + open_table_tag + (startOfRow % row_color)
lines_in_table = 0
else:
output = output + endOfRow + (startOfRow % row_color)
elif lines_in_table > 200 and not inMark:
output = output + endOfRow + '</table>' + open_table_tag + (startOfRow % row_color)
lines_in_table = 0
output = output + "<a name=%d></a>" % (line, )
if 1: # opt_line_nums
output = output + ('%%%dd' % (line_num_width, )) % (line, )
if old_revision != revision or rev_count > 20:
revision_width = max(revision_width, len(revision))
if parser.prev_revision.get(revision):
fname = file_tail[:-2] # strip the ",v"
url = '%s.diff?r1=%s&amp;r2=%s' % \
(fname, parser.prev_revision[revision], revision)
if sticky:
url = url + '&' + sticky
output = output + ' <a href="%s"' % (url, )
if 0: # use_layers
output = output + " onmouseover='return log(event,\"%s\",\"%s\");'" % (
parser.prev_revision[revision], revision)
output = output + ">"
else:
output = output + " "
parser.prev_revision[revision] = ''
author = parser.revision_author[revision]
# $author =~ s/%.*$//;
author_width = max(author_width, len(author))
output = output + ('%%-%ds ' % (author_width, )) % (author, )
output = output + revision
if parser.prev_revision.get(revision):
output = output + '</a>'
output = output + (' ' * (revision_width - len(revision) + 1))
old_revision = revision
rev_count = 0
else:
output = output + ' ' + (' ' * (author_width + revision_width))
rev_count = rev_count + 1
output = output + thisline
# Close the highlighted section
#if (defined $mark_cmd and mark_cmd != 'begin'):
# chop($output)
# output = output + endOfRow + (startOfRow % row_color)
# inMark = 0
print output
print endOfRow + '</table>'
def main():
if len(sys.argv) != 3:
print 'USAGE: %s cvsroot rcs-file' % sys.argv[0]
sys.exit(1)
make_html(sys.argv[1], sys.argv[2])
if __name__ == '__main__':
main()

View File

@@ -1,48 +0,0 @@
# -*- Mode: python -*-
# -----------------------------------------------------------------------
# Copyright (C) 2000 Jay Painter. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth below:
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# -----------------------------------------------------------------------
#
# For tracking purposes, this software is identified by:
# $Id$
#
# -----------------------------------------------------------------------
class EmptyNameSpace:
"Placehoder empty class for nesting namespaces."
pass
## [cvsdb]
cvsdb = EmptyNameSpace()
cvsdb.host = 'master'
cvsdb.database_name = 'bonsai'
cvsdb.user = 'root'
cvsdb.passwd = 'ogieta50'
cvsdb.readonly_user = 'root'
cvsdb.readonly_passwd = 'ogieta50'

View File

@@ -1,36 +1,17 @@
# -*- Mode: python -*-
# -----------------------------------------------------------------------
# Copyright (C) 2000 Jay Painter. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth below:
# Copyright (C) 2000-2001 The ViewCVS Group. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 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 ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
# For tracking purposes, this software is identified by:
# $Id$
#
# -----------------------------------------------------------------------
import os

View File

@@ -1,13 +1,28 @@
# -*- Mode: python -*-
#
# ### add license stuff
# Copyright (C) 2000-2001 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 ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
# compat.py: compatibility functions for operation across Python 1.5.x
#
# -----------------------------------------------------------------------
#
import urllib
import string
import time
import re
import os
#
# urllib.urlencode() is new to Python 1.5.2
@@ -23,18 +38,31 @@ except AttributeError:
keyvalue = [ ]
for key, value in dict.items():
keyvalue.append(quote(key) + '=' + quote(str(value)))
return '?' + string.join(keyvalue, '&')
return string.join(keyvalue, '&')
#
# time.strptime() is new to Python 1.5.2
#
if hasattr(time, 'strptime'):
def cvs_strptime(timestr):
'Parse a CVS-style date/time value.'
return time.strptime(timestr, '%Y/%m/%d %H:%M:%S')
else:
_re_rev_date = re.compile('([0-9]{4})/([0-9][0-9])/([0-9][0-9]) '
'([0-9][0-9]):([0-9][0-9]):([0-9][0-9])')
def cvs_strptime(timestr):
'Parse a CVS-style date/time value.'
matches = _re_rev_date.match(timestr).groups()
return tuple(map(int, matches)) + (0, 1, -1)
cvs_strptime.__doc__ = 'Parse a CVS-style date/time value.'
return tuple(map(int, matches)) + (0, 1, 0)
#
# os.makedirs() is new to Python 1.5.2
#
try:
makedirs = os.makedirs
except AttributeError:
def makedirs(path, mode=0777):
head, tail = os.path.split(path)
if head and tail and not os.path.exists(head):
makedirs(head, mode)
os.mkdir(path, mode)

View File

@@ -1,13 +1,27 @@
# -*- Mode: python -*-
#
# ### add license stuff
# Copyright (C) 2000-2001 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 ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
# config.py: configuration utilities
#
# -----------------------------------------------------------------------
#
import sys
import os
import string
import ConfigParser
import fnmatch
#########################################################################
@@ -28,41 +42,71 @@ import ConfigParser
class Config:
_sections = ('general', 'images', 'options', 'colors', 'text', 'cvsdb')
_force_multi_value = ('cvs_roots', 'forbidden', 'even_odd')
_force_multi_value = ('cvs_roots', 'forbidden', 'even_odd',
'disable_enscript_lang')
def __init__(self):
for section in self._sections:
setattr(self, section, _sub_config())
def load_config(self, fname):
def load_config(self, fname, vhost=None):
this_dir = os.path.dirname(sys.argv[0])
pathname = os.path.join(this_dir, fname)
parser = ConfigParser.ConfigParser()
parser.read(pathname)
for section in self._sections:
if not parser.has_section(section):
continue
if parser.has_section(section):
self._process_section(parser, section, section)
sc = getattr(self, section)
if vhost:
self._process_vhost(parser, vhost)
for opt in parser.options(section):
value = parser.get(section, opt)
if opt in self._force_multi_value or section == 'images':
value = map(string.strip, string.split(value, ','))
else:
try:
value = int(value)
except ValueError:
pass
def _process_section(self, parser, section, subcfg_name):
sc = getattr(self, subcfg_name)
if opt == 'cvs_roots':
roots = { }
for root in value:
name, path = map(string.strip, string.split(root, ':'))
roots[name] = path
value = roots
setattr(sc, opt, value)
for opt in parser.options(section):
value = parser.get(section, opt)
if opt in self._force_multi_value or subcfg_name == 'images':
value = map(string.strip, filter(None, string.split(value, ',')))
else:
try:
value = int(value)
except ValueError:
pass
if opt == 'cvs_roots':
roots = { }
for root in value:
name, path = map(string.strip, string.split(root, ':'))
roots[name] = path
value = roots
setattr(sc, opt, value)
def _process_vhost(self, parser, vhost):
canon_vhost = self._find_canon_vhost(parser, vhost)
if not canon_vhost:
# none of the vhost sections matched
return
cv = canon_vhost + '-'
lcv = len(cv)
for section in parser.sections():
if section[:lcv] == cv:
self._process_section(parser, section, section[lcv:])
def _find_canon_vhost(self, parser, vhost):
vhost = string.lower(vhost)
for canon_vhost in parser.options('vhosts'):
value = parser.get('vhosts', canon_vhost)
patterns = map(string.lower, map(string.strip,
filter(None, string.split(value, ','))))
for pat in patterns:
if fnmatch.fnmatchcase(vhost, pat):
return canon_vhost
return None
def set_defaults(self):
"Set some default values in the configuration."
@@ -142,6 +186,10 @@ class Config:
self.options.diff_font_face = 'Helvetica,Arial'
self.options.diff_font_size = -1
self.options.input_text_size = 12
self.options.use_enscript = 0
self.options.enscript_path = ''
self.options.disable_enscript_lang = ()
self.options.allow_tar = 0
self.text.long_intro = """\
<p>
@@ -158,7 +206,7 @@ class Config:
</p>
<p>
This script
(<a href="http://www.lyra.org/viewcvs/">ViewCVS</a>)
(<a href="http://viewcvs.sourceforge.net/">ViewCVS</a>)
has been written by Greg Stein
&lt;<a href="mailto:gstein@lyra.org">gstein@lyra.org</a>&gt;
based on the
@@ -169,7 +217,7 @@ class Config:
<a href="http://www.opensource.org/licenses/bsd-license.html">BSD-License</a>.
If you would like to use this CGI script on your own web server and
CVS tree, see Greg's
<a href="http://www.lyra.org/viewcvs/">ViewCVS distribution
<a href="http://viewcvs.sourceforge.net/">ViewCVS distribution
site</a>.
Please send any suggestions, comments, etc. to
<a href="mailto:gstein@lyra.org">Greg Stein</a>.
@@ -181,9 +229,9 @@ class Config:
<h3>CVS Documentation</h3>
<blockquote>
<p>
<a href="http://cvsbook.red-bean.com/">Karl Fogel's CVS book</a><br>
<a href="http://www.loria.fr/~molli/cvs/doc/cvs_toc.html">CVS
User's Guide</a><br>
<a href="http://www.arc.unm.edu/~rsahu/cvs.html">CVS Tutorial</a><br>
<a href="http://cellworks.washington.edu/pub/docs/cvs/tutorial/cvs_tutorial_1.html">Another CVS tutorial</a><br>
<a href="http://www.csc.calpoly.edu/~dbutler/tutorials/winter96/cvs/">Yet another CVS tutorial (a little old, but nice)</a><br>
<a href="http://www.cs.utah.edu/dept/old/texinfo/cvs/FAQ.txt">An old but very useful FAQ about CVS</a>
@@ -204,6 +252,19 @@ class Config:
</p>
"""
def is_forbidden(self, module):
if not module:
return 0
default = 0
for pat in self.general.forbidden:
if pat[0] == '!':
default = 1
if fnmatch.fnmatchcase(module, pat[1:]):
return 0
elif fnmatch.fnmatchcase(module, pat):
return 1
return default
class _sub_config:
def get_image(self, which):
text = '[%s]' % string.upper(which)
@@ -212,3 +273,10 @@ class _sub_config:
return '<img src="%s" alt="%s" border=0 width=%s height=%s>' % \
(path, text, width, height)
return text
if not hasattr(sys, 'hexversion'):
# Python 1.5 or 1.5.1. fix the syntax for ConfigParser options.
import regex
ConfigParser.option_cre = regex.compile('^\([-A-Za-z0-9._]+\)\(:\|['
+ string.whitespace
+ ']*=\)\(.*\)$')

View File

@@ -1,45 +1,44 @@
# -*- Mode: python -*-
# -----------------------------------------------------------------------
# Copyright (C) 2000 Jay Painter. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth below:
# Copyright (C) 2000-2001 The ViewCVS Group. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 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 ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
# For tracking purposes, this software is identified by:
# $Id$
#
# -----------------------------------------------------------------------
import os, cfg, database, rlog, commit
#########################################################################
#
# INSTALL-TIME CONFIGURATION
#
# These values will be set during the installation process. During
# development, they will remain None.
#
CONF_PATHNAME = None
#########################################################################
import os
import database
import query
import rlog
import commit
import config
## error
error = 'cvsdbapi error'
## database
CreateCheckinDatabase = database.CreateCheckinDatabase
CreateCheckinQuery = database.CreateCheckinQuery
CreateCheckinQuery = query.CreateCheckinQuery
## rlog
GetRLogData = rlog.GetRLogData
@@ -52,6 +51,11 @@ PrintCommit = commit.PrintCommit
gCheckinDatabase = None
gCheckinDatabaseReadOnly = None
## load configuration file, the data is used globally here
cfg = config.Config()
cfg.set_defaults()
cfg.load_config(CONF_PATHNAME)
def ConnectDatabaseReadOnly():
global gCheckinDatabaseReadOnly

View File

@@ -1,44 +1,24 @@
# -*- Mode: python -*-
# -----------------------------------------------------------------------
# Copyright (C) 2000 Jay Painter. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth below:
# Copyright (C) 2000-2001 The ViewCVS Group. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 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 ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
# For tracking purposes, this software is identified by:
# $Id$
#
# -----------------------------------------------------------------------
import os, sys, string, time
## imports from the database API; we re-assign the namespace here so it
## is easier to switch databases
import MySQLdb
DBI = MySQLdb
import os
import sys
import string
import time
import dbi
from commit import CreateCommit, PrintCommit
@@ -46,17 +26,19 @@ from commit import CreateCommit, PrintCommit
## of the CheckinDatabase class
sqlBase = 'SELECT checkins.type, checkins.ci_when,checkins. whoid, checkins.repositoryid, checkins.dirid, checkins.fileid, checkins.revision, checkins.stickytag, checkins.branchid, checkins.addedlines, checkins.removedlines, checkins.descid FROM %s WHERE %s %s'
sqlRepository = '(checkins.repositoryid=repositories.id AND repositories.repository="%s")'
sqlBranch = '(checkins.branchid=branches.id AND branches.branch="%s")'
sqlDirectory = '(checkins.dirid=dirs.id AND dirs.dir LIKE "%s%%")'
sqlFile = '(checkins.fileid=files.id AND files.file="%s")'
sqlFromDate ='(checkins.ci_when>="%s")'
sqlToDate = '(checkins.ci_when<="%s")'
sqlAuthor = '(checkins.whoid=people.id AND people.who="%s")'
sqlRepository = '(checkins.repositoryid = repositories.id AND repositories.repository %s "%s")'
sqlBranch = '(checkins.branchid = branches.id AND branches.branch %s "%s")'
sqlDirectory = '(checkins.dirid = dirs.id AND dirs.dir %s "%s")'
sqlFile = '(checkins.fileid = files.id AND files.file %s "%s")'
sqlAuthor = '(checkins.whoid = people.id AND people.who %s "%s")'
sqlFromDate ='(checkins.ci_when >= "%s")'
sqlToDate = '(checkins.ci_when <= "%s")'
sqlSortByDate = 'ORDER BY checkins.ci_when DESC'
sqlSortByAuthor = 'ORDER BY checkins.whoid'
sqlSortByFile = 'ORDER BY checkins.fileid'
sqlExcludeVersionFiles = '(checkins.fileid=files.id AND files.file NOT LIKE "%%.ver")'
sqlExcludeVersionFiles = '(checkins.fileid = files.id AND files.file NOT LIKE "%%.ver")'
sqlCheckCommit = 'SELECT * FROM checkins WHERE checkins.repositoryid=%s AND checkins.dirid=%s AND checkins.fileid=%s AND checkins.revision=%s'
## CheckinDatabase provides all interfaces needed to the SQL database
@@ -77,7 +59,8 @@ class CheckinDatabase:
self.dbDescriptionIDCache = {}
def Connect(self):
self.dbConn = self.SQLConnect()
self.dbConn = dbi.connect(
self.dbHost, self.dbUser, self.dbPasswd, self.dbDatabase)
def SQLGetID(self, table, field, identifier, auto_set):
sql = 'SELECT id FROM %s x WHERE x.%s="%s"' % (
@@ -258,7 +241,7 @@ class CheckinDatabase:
## module to do the conversion
temp = time.localtime(commit.GetTime())
dbCI_When = DBI.Timestamp(
dbCI_When = dbi.Timestamp(
temp[0], temp[1], temp[2], temp[3], temp[4], temp[5])
dbWhoID = self.GetAuthorID(commit.GetAuthor())
@@ -281,46 +264,74 @@ class CheckinDatabase:
cursor = self.dbConn.cursor()
cursor.execute(sql, sqlArguments)
def SQLQueryListString(self, sqlString, query_entry_list):
sqlList = []
for query_entry in query_entry_list:
## figure out the correct match type
if query_entry.match == "exact":
match = "="
elif query_entry.match == "like":
match = "LIKE"
elif query_entry.match == "regex":
match = "REGEXP"
sqlList.append(sqlString % (match, query_entry.data))
return "(%s)" % (string.join(sqlList, " OR "))
def CreateSQLQueryString(self, query):
tableList = ['checkins']
condList = []
tableList.append('files')
## XXX: this is to exclude .ver files -- RN specific hack --JMP
tableList.append("files")
condList.append(sqlExcludeVersionFiles)
if query.repository:
tableList.append('repositories')
condList.append(sqlRepository % (query.repository))
if query.branch:
tableList.append('branches')
condList.append(sqlBranch % (query.branch))
if len(query.repository_list):
tableList.append("repositories")
condList.append(
self.SQLQueryListString(sqlRepository, query.repository_list))
if len(query.branch_list):
tableList.append("branches")
condList.append(
self.SQLQueryListString(sqlBranch, query.branch_list))
if len(query.directory_list):
tableList.append("dirs")
condList.append(
self.SQLQueryListString(sqlDirectory, query.directory_list))
if len(query.file_list):
tableList.append("files")
condList.append(
self.SQLQueryListString(sqlFile, query.file_list))
if len(query.author_list):
tableList.append("people")
condList.append(
self.SQLQueryListString(sqlAuthor, query.author_list))
if query.from_date:
condList.append(sqlFromDate % (str(query.from_date)))
if query.to_date:
condList.append(sqlToDate % (str(query.to_date)))
if query.author:
tableList.append('people')
condList.append(sqlAuthor % (query.author))
if query.directory:
tableList.append('dirs')
condList.append(sqlDirectory % (query.directory))
if query.file:
#tableList.append('files')
condList.append(sqlFile % (query.file))
if query.sort == query.SORT_DATE:
if query.sort == "date":
order_by = sqlSortByDate
elif query.sort == query.SORT_AUTHOR:
elif query.sort == "author":
order_by = sqlSortByAuthor
elif query.sort == query.SORT_FILE:
elif query.sort == "file":
order_by = sqlSortByFile
## exclude duplicates from the table list
for table in tableList[:]:
while tableList.count(table) > 1:
tableList.remove(table)
sql = sqlBase % (
string.join(tableList, ', '),
string.join(condList, ' AND '),
@@ -390,106 +401,8 @@ class CheckinDatabase:
return None
return commit
class MySQLCheckinDatabase(CheckinDatabase):
def SQLConnect(self):
return MySQLdb.connect(
host = self.dbHost,
user = self.dbUser,
passwd = self.dbPasswd,
db = self.dbDatabase)
## CheckinDatabaseQueryData is a object which contains the search parameters
## for a query to the CheckinDatabase
class CheckinDatabaseQuery:
SORT_DATE = 0
SORT_AUTHOR = 1
SORT_FILE = 2
SORT_CHANGESIZE = 3
def __init__(self):
## repository to query
self.repository = None
## branch
self.branch = None
## directory to seach
self.directory = None
## file to search for
self.file = None
## sorting method
self.sort = CheckinDatabaseQuery.SORT_DATE;
## author to search for
self.author = None
## date range in DBI 2.0 timedate objects
self.from_date = None
self.to_date = None
## list of commits -- filled in by CVS query
self.commit_list = []
## commit_cb provides a callback for commits as they
## are added
self.commit_cb = None
def SetRepository(self, repository):
self.repository = repository
def SetBranch(self, branch):
self.branch = branch
def SetDirectory(self, directory):
self.directory = directory
def SetFile(self, file):
self.file = file
def SetSortMethod(self, sort):
self.sort = sort
def SetAuthor(self, author):
self.author = author
def SetFromDateObject(self, date):
self.from_date = date
def SetToDateObject(self, date):
self.to_date = date
def SetFromDateHoursAgo(self, hours_ago):
ticks = time.time() - (3600 * hours_ago)
self.from_date = DBI.TimestampFromTicks(ticks)
def SetFromDateDaysAgo(self, days_ago):
ticks = time.time() - (86400 * days_ago)
self.from_date = DBI.TimestampFromTicks(ticks)
def SetToDateDaysAgo(self, days_ago):
ticks = time.time() - (86400 * days_ago)
self.to_date = DBI.TimestampFromTicks(ticks)
def AddCommit(self, commit):
self.commit_list.append(commit)
if self.commit_cb:
self.commit_cb(commit)
def SetCommitCB(self, callback):
self.commit_cb = callback
## entrypoints
def CreateCheckinDatabase(host, user, passwd, database):
return MySQLCheckinDatabase(host, user, passwd, database)
def CreateCheckinQuery():
return CheckinDatabaseQuery()
return CheckinDatabase(host, user, passwd, database)

71
lib/dbi.py Normal file
View File

@@ -0,0 +1,71 @@
# -*- Mode: python -*-
#
# Copyright (C) 2000-2001 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 ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
import sys
import MySQLdb
dbi_error = "dbi error"
## make some checks in MySQLdb
_no_datetime = """\
ERROR: Your version of MySQLdb requires the mxDateTime module
for the Timestamp() and TimestampFromTicks() methods.
You will need to install mxDateTime to use the ViewCVS
database.
"""
if not hasattr(MySQLdb, "Timestamp") or \
not hasattr(MySQLdb, "TimestampFromTicks"):
sys.stderr.write(_no_datetime)
sys.exit(1)
class Cursor:
def __init__(self, mysql_cursor):
self.__cursor = mysql_cursor
def execute(self, *args):
apply(self.__cursor.execute, args)
def fetchone(self):
try:
row = self.__cursor.fetchone()
except IndexError:
row = None
return row
class Connection:
def __init__(self, host, user, passwd, db):
self.__mysql = MySQLdb.connect(
host=host, user=user, passwd=passwd, db=db)
def cursor(self):
return Cursor(self.__mysql.cursor())
def Timestamp(year, month, date, hour, minute, second):
return MySQLdb.Timestamp(year, month, date, hour, minute, second)
def TimestampFromTicks(ticks):
return MySQLdb.TimestampFromTicks(ticks)
def connect(host, user, passwd, db):
return Connection(host, user, passwd, db)

187
lib/popen.py Normal file
View File

@@ -0,0 +1,187 @@
#
# Copyright (C) 2000-2001 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 ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
# popen.py: a replacement for os.popen()
#
# This implementation of popen() provides a cmd + args calling sequence,
# rather than a system() type of convention. The shell facilities are not
# available, but that implies we can avoid worrying about shell hacks in
# the arguments.
#
# -----------------------------------------------------------------------
#
import os
import sys
def popen(cmd, args, mode, capture_err=1):
# flush the stdio buffers since we are about to change the FD under them
sys.stdout.flush()
sys.stderr.flush()
r, w = os.pipe()
pid = os.fork()
if pid:
# in the parent
# close the descriptor that we don't need and return the other one.
if mode == 'r':
os.close(w)
return _pipe(os.fdopen(r, 'r'), pid)
os.close(r)
return _pipe(os.fdopen(w, 'w'), pid)
# in the child
# we'll need /dev/null for the discarded I/O
null = os.open('/dev/null', os.O_RDWR)
if mode == 'r':
# hook stdout/stderr to the "write" channel
os.dup2(w, 1)
# "close" stdin; the child shouldn't use it
### this isn't quite right... we may want the child to read from stdin
os.dup2(null, 0)
# what to do with errors?
if capture_err:
os.dup2(w, 2)
else:
os.dup2(null, 2)
else:
# hook stdin to the "read" channel
os.dup2(r, 0)
# "close" stdout/stderr; the child shouldn't use them
### this isn't quite right... we may want the child to write to these
os.dup2(null, 1)
os.dup2(null, 2)
# don't need these FDs any more
os.close(null)
os.close(r)
os.close(w)
# the stdin/stdout/stderr are all set up. exec the target
try:
os.execvp(cmd, (cmd,) + tuple(args))
except:
pass
# crap. shouldn't be here.
sys.exit(127)
def pipe_cmds(cmds):
# flush the stdio buffers since we are about to change the FD under them
sys.stdout.flush()
sys.stderr.flush()
prev_r, parent_w = os.pipe()
null = os.open('/dev/null', os.O_RDWR)
for cmd in cmds[:-1]:
r, w = os.pipe()
pid = os.fork()
if not pid:
# in the child
# hook up stdin to the "read" channel
os.dup2(prev_r, 0)
# hook up stdout to the output channel
os.dup2(w, 1)
# toss errors
os.dup2(null, 2)
# close these extra descriptors
os.close(prev_r)
os.close(parent_w)
os.close(null)
os.close(r)
os.close(w)
# time to run the command
try:
os.execvp(cmd[0], cmd)
except:
pass
sys.exit(127)
# in the parent
# we don't need these any more
os.close(prev_r)
os.close(w)
# the read channel of this pipe will feed into to the next command
prev_r = r
# no longer needed
os.close(null)
# done with most of the commands. set up the last command to write to stdout
pid = os.fork()
if not pid:
# in the child (the last command)
# hook up stdin to the "read" channel
os.dup2(prev_r, 0)
# close these extra descriptors
os.close(prev_r)
os.close(parent_w)
# run the last command
try:
os.execvp(cmds[-1][0], cmds[-1])
except:
pass
sys.exit(127)
# not needed any more
os.close(prev_r)
# write into the first pipe, wait on the final process
return _pipe(os.fdopen(parent_w, 'w'), pid)
class _pipe:
"Wrapper for a file which can wait() on a child process at close time."
def __init__(self, file, child_pid):
self.file = file
self.child_pid = child_pid
def eof(self):
pid, status = os.waitpid(self.child_pid, os.WNOHANG)
if pid:
self.file.close()
self.file = None
return status
return None
def close(self):
if self.file:
self.file.close()
self.file = None
return os.waitpid(self.child_pid, 0)[1]
return None
def __getattr__(self, name):
return getattr(self.file, name)
def __del__(self):
if self.file:
self.close()

102
lib/query.py Normal file
View File

@@ -0,0 +1,102 @@
# -*- Mode: python -*-
#
# Copyright (C) 2000-2001 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 ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
import time
import dbi
## QueryEntry holds data on one match-type in the SQL database
## match is: "exact", "like", or "regex"
class QueryEntry:
def __init__(self, data, match):
self.data = data
self.match = match
## CheckinDatabaseQueryData is a object which contains the search parameters
## for a query to the CheckinDatabase
class CheckinDatabaseQuery:
def __init__(self):
## sorting
self.sort = "date"
## repository to query
self.repository_list = []
self.branch_list = []
self.directory_list = []
self.file_list = []
self.author_list = []
## date range in DBI 2.0 timedate objects
self.from_date = None
self.to_date = None
## list of commits -- filled in by CVS query
self.commit_list = []
## commit_cb provides a callback for commits as they
## are added
self.commit_cb = None
def SetRepository(self, repository, match = "exact"):
self.repository_list.append(QueryEntry(repository, match))
def SetBranch(self, branch, match = "exact"):
self.branch_list.append(QueryEntry(branch, match))
def SetDirectory(self, directory, match = "exact"):
self.directory_list.append(QueryEntry(directory, match))
def SetFile(self, file, match = "exact"):
self.file_list.append(QueryEntry(file, match))
def SetAuthor(self, author, match = "exact"):
self.author_list.append(QueryEntry(author, match))
def SetSortMethod(self, sort):
self.sort = sort
def SetFromDateObject(self, ticks):
self.from_date = dbi.TimestampFromTicks(ticks)
def SetToDateObject(self, ticks):
self.to_date = dbi.TimestampFromTicks(ticks)
def SetFromDateHoursAgo(self, hours_ago):
ticks = time.time() - (3600 * hours_ago)
self.from_date = dbi.TimestampFromTicks(ticks)
def SetFromDateDaysAgo(self, days_ago):
ticks = time.time() - (86400 * days_ago)
self.from_date = dbi.TimestampFromTicks(ticks)
def SetToDateDaysAgo(self, days_ago):
ticks = time.time() - (86400 * days_ago)
self.to_date = dbi.TimestampFromTicks(ticks)
def AddCommit(self, commit):
self.commit_list.append(commit)
if self.commit_cb:
self.commit_cb(commit)
def SetCommitCB(self, callback):
self.commit_cb = callback
## entrypoints
def CreateCheckinQuery():
return CheckinDatabaseQuery()

441
lib/rcsparse.py Normal file
View File

@@ -0,0 +1,441 @@
#
# Copyright (C) 2000-2001 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 ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
# This software is being maintained as part of the ViewCVS project.
# Information is available at:
# http://viewcvs.sourceforge.net/
#
# This file was originally based on portions of the blame.py script by
# Curt Hagenlocher.
#
# -----------------------------------------------------------------------
import string
import time
class _TokenStream:
token_term = string.whitespace + ';'
# the algorithm is about the same speed for any CHUNK_SIZE chosen.
# grab a good-sized chunk, but not too large to overwhelm memory.
CHUNK_SIZE = 100000
# CHUNK_SIZE = 5 # for debugging, make the function grind...
def __init__(self, file):
self.rcsfile = file
self.idx = 0
self.buf = self.rcsfile.read(self.CHUNK_SIZE)
if self.buf == '':
raise RuntimeError, 'EOF'
def get(self):
"Get the next token from the RCS file."
# Note: we can afford to loop within Python, examining individual
# characters. For the whitespace and tokens, the number of iterations
# is typically quite small. Thus, a simple iterative loop will beat
# out more complex solutions.
buf = self.buf
idx = self.idx
while 1:
if idx == len(buf):
buf = self.rcsfile.read(self.CHUNK_SIZE)
if buf == '':
# signal EOF by returning None as the token
del self.buf # so we fail if get() is called again
return None
idx = 0
if buf[idx] not in string.whitespace:
break
idx = idx + 1
if buf[idx] == ';':
self.buf = buf
self.idx = idx + 1
return ';'
if buf[idx] != '@':
end = idx + 1
token = ''
while 1:
# find token characters in the current buffer
while end < len(buf) and buf[end] not in self.token_term:
end = end + 1
token = token + buf[idx:end]
if end < len(buf):
# we stopped before the end, so we have a full token
idx = end
break
# we stopped at the end of the buffer, so we may have a partial token
buf = self.rcsfile.read(self.CHUNK_SIZE)
idx = end = 0
self.buf = buf
self.idx = idx
return token
# a "string" which starts with the "@" character. we'll skip it when we
# search for content.
idx = idx + 1
chunks = [ ]
while 1:
if idx == len(buf):
idx = 0
buf = self.rcsfile.read(self.CHUNK_SIZE)
if buf == '':
raise RuntimeError, 'EOF'
i = string.find(buf, '@', idx)
if i == -1:
chunks.append(buf[idx:])
idx = len(buf)
continue
if i == len(buf) - 1:
chunks.append(buf[idx:i])
idx = 0
buf = '@' + self.rcsfile.read(self.CHUNK_SIZE)
if buf == '@':
raise RuntimeError, 'EOF'
continue
if buf[i + 1] == '@':
chunks.append(buf[idx:i+1])
idx = i + 2
continue
chunks.append(buf[idx:i])
self.buf = buf
self.idx = i + 1
return string.join(chunks, '')
# _get = get
# def get(self):
token = self._get()
print 'T:', `token`
return token
def match(self, match):
"Try to match the next token from the input buffer."
token = self.get()
if token != match:
raise RuntimeError, ('Unexpected parsing error in RCS file.\n' +
'Expected token: %s, but saw: %s' % (match, token))
def unget(self, token):
"Put this token back, for the next get() to return."
# Override the class' .get method with a function which clears the
# overridden method then returns the pushed token. Since this function
# will not be looked up via the class mechanism, it should be a "normal"
# function, meaning it won't have "self" automatically inserted.
# Therefore, we need to pass both self and the token thru via defaults.
# note: we don't put this into the input buffer because it may have been
# @-unescaped already.
def give_it_back(self=self, token=token):
del self.get
return token
self.get = give_it_back
class Parser:
def parse_rcs_admin(self):
while 1:
# Read initial token at beginning of line
token = self.ts.get()
# We're done once we reach the description of the RCS tree
if token[0] in string.digits:
self.ts.unget(token)
return
if token == "head":
self.sink.set_head_revision(self.ts.get())
self.ts.match(';')
elif token == "branch":
self.sink.set_principal_branch(self.ts.get())
self.ts.match(';')
elif token == "symbols":
while 1:
tag = self.ts.get()
if tag == ';':
break
(tag_name, tag_rev) = string.split(tag, ':')
self.sink.define_tag(tag_name, tag_rev)
elif token == "comment":
self.sink.set_comment(self.ts.get())
self.ts.match(';')
# Ignore all these other fields - We don't care about them. Also chews
# up "newphrase".
elif token in ("locks", "strict", "expand", "access"):
while 1:
tag = self.ts.get()
if tag == ';':
break
else:
pass
# warn("Unexpected RCS token: $token\n")
raise RuntimeError, "Unexpected EOF";
def parse_rcs_tree(self):
while 1:
revision = self.ts.get()
# End of RCS tree description ?
if revision == 'desc':
self.ts.unget(revision)
return
# Parse date
self.ts.match('date')
date = self.ts.get()
self.ts.match(';')
# Convert date into timestamp
date_fields = string.split(date, '.') + ['0', '0', '0']
date_fields = map(string.atoi, date_fields)
if date_fields[0] < 100:
date_fields[0] = date_fields[0] + 1900
timestamp = time.mktime(tuple(date_fields))
# Parse author
self.ts.match('author')
author = self.ts.get()
self.ts.match(';')
# Parse state
self.ts.match('state')
state = ''
while 1:
token = self.ts.get()
if token == ';':
break
state = state + token + ' '
state = state[:-1] # toss the trailing space
# Parse branches
self.ts.match('branches')
branches = [ ]
while 1:
token = self.ts.get()
if token == ';':
break
branches.append(token)
# Parse revision of next delta in chain
self.ts.match('next')
next = self.ts.get()
if next == ';':
next = None
else:
self.ts.match(';')
# there are some files with extra tags in them. for example:
# owner 640;
# group 15;
# permissions 644;
# hardlinks @configure.in@;
# this is "newphrase" in RCSFILE(5). we just want to skip over these.
while 1:
token = self.ts.get()
if token == 'desc' or token[0] in string.digits:
self.ts.unget(token)
break
# consume everything up to the semicolon
while self.ts.get() != ';':
pass
self.sink.define_revision(revision, timestamp, author, state, branches,
next)
def parse_rcs_description(self):
self.ts.match('desc')
self.sink.set_description(self.ts.get())
def parse_rcs_deltatext(self):
while 1:
revision = self.ts.get()
if revision is None:
# EOF
break
self.ts.match('log')
log = self.ts.get()
### need to add code to chew up "newphrase"
self.ts.match('text')
text = self.ts.get()
self.sink.set_revision_info(revision, log, text)
def parse(self, file, sink):
self.ts = _TokenStream(file)
self.sink = sink
self.parse_rcs_admin()
self.parse_rcs_tree()
# many sinks want to know when the tree has been completed so they can
# do some work to prep for the arrival of the deltatext
self.sink.tree_completed()
self.parse_rcs_description()
self.parse_rcs_deltatext()
# easiest for us to tell the sink it is done, rather than worry about
# higher level software doing it.
self.sink.parse_completed()
self.ts = self.sink = None
class Sink:
def set_head_revision(self, revision):
pass
def set_principal_branch(self, branch_name):
pass
def define_tag(self, name, revision):
pass
def set_comment(self, comment):
pass
def set_description(self, description):
pass
def define_revision(self, revision, timestamp, author, state,
branches, next):
pass
def set_revision_info(self, revision, log, text):
pass
def tree_completed(self):
pass
def parse_completed(self):
pass
# --------------------------------------------------------------------------
#
# TESTING AND DEBUGGING TOOLS
#
class DebugSink:
def set_head_revision(self, revision):
print 'head:', revision
def set_principal_branch(self, branch_name):
print 'branch:', branch_name
def define_tag(self, name, revision):
print 'tag:', name, '=', revision
def set_comment(self, comment):
print 'comment:', comment
def set_description(self, description):
print 'description:', description
def define_revision(self, revision, timestamp, author, state,
branches, next):
print 'revision:', revision
print ' timestamp:', timestamp
print ' author:', author
print ' state:', state
print ' branches:', branches
print ' next:', next
def set_revision_info(self, revision, log, text):
print 'revision:', revision
print ' log:', log
print ' text:', text[:100], '...'
class DumpSink:
"""Dump all the parse information directly to stdout.
The output is relatively unformatted and untagged. It is intended as a
raw dump of the data in the RCS file. A copy can be saved, then changes
made to the parsing engine, then a comparison of the new output against
the old output.
"""
def __init__(self):
global sha
import sha
def set_head_revision(self, revision):
print revision
def set_principal_branch(self, branch_name):
print branch_name
def define_tag(self, name, revision):
print name, revision
def set_comment(self, comment):
print comment
def set_description(self, description):
print description
def define_revision(self, revision, timestamp, author, state,
branches, next):
print revision, timestamp, author, state, branches, next
def set_revision_info(self, revision, log, text):
print revision, sha.new(log).hexdigest(), sha.new(text).hexdigest()
def tree_completed(self):
print 'tree_completed'
def parse_completed(self):
print 'parse_completed'
def dump_file(fname):
Parser().parse(open(fname), DumpSink())
def time_file(fname):
import time
p = Parser().parse
f = open(fname)
s = Sink()
t = time.time()
p(f, s)
t = time.time() - t
print t
def _usage():
print 'This is normally a module for importing, but it has a couple'
print 'features for testing as an executable script.'
print 'USAGE: %s COMMAND filename,v' % sys.argv[0]
print ' where COMMAND is one of:'
print ' dump: filename is "dumped" to stdout'
print ' time: filename is parsed with the time written to stdout'
sys.exit(1)
if __name__ == '__main__':
import sys
if len(sys.argv) != 3:
usage()
if sys.argv[1] == 'dump':
dump_file(sys.argv[2])
elif sys.argv[1] == 'time':
time_file(sys.argv[2])
else:
usage()

View File

@@ -1,38 +1,37 @@
# -*- Mode: python -*-
# -----------------------------------------------------------------------
# Copyright (C) 2000 Jay Painter. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth below:
# Copyright (C) 2000-2001 The ViewCVS Group. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 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 ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
# For tracking purposes, this software is identified by:
# $Id$
#
# -----------------------------------------------------------------------
import os, sys, string, time, re
#########################################################################
#
# INSTALL-TIME CONFIGURATION
#
# These values will be set during the installation process. During
# development, they will remain None.
#
CONF_PATHNAME = None
#########################################################################
import os, sys, string, re, time, config
## load configuration file, the data is used globally here
cfg = config.Config()
cfg.set_defaults()
cfg.load_config(CONF_PATHNAME)
## RLogOutputParser uses the output of rlog to build a list of Commit
## objects describing all the checkins from a given RCS file; this
@@ -107,7 +106,8 @@ class RLog:
if self.date:
arg_list.append('-d%s' % (self.date))
self.cmd = 'rlog %s "%s"' % (string.join(arg_list), self.filename)
temp = os.path.join(cfg.general.rcs_path, "rlog")
self.cmd = '%s %s "%s"' % (temp, string.join(arg_list), self.filename)
self.rlog = os.popen(self.cmd, 'r')
def fix_filename(self, filename):
@@ -245,7 +245,9 @@ class RLogOutputParser:
def parse_one_rlog_entry(self):
## revision line/first line
line = self.rlog.readline()
if not line:
# Since FreeBSD's rlog outputs extra "---...---\n" before
# "===...===\n", _rlog_end may be occured here.
if not line or line == _rlog_end:
return None
## revision

2526
lib/viewcvs.py Normal file

File diff suppressed because it is too large Load Diff

139
tests/timelog.py Normal file
View File

@@ -0,0 +1,139 @@
import time
import string
import profile
import rcsparse
import viewcvs
def lines_changed(delta):
idx = 0
added = deleted = 0
while idx < len(delta):
op = delta[idx]
i = string.find(delta, ' ', idx + 1)
j = string.find(delta, '\n', i + 1)
line = int(delta[idx+1:i])
count = int(delta[i+1:j])
idx = j + 1
if op == 'd':
deleted = deleted + count
else: # 'a' for adding text
added = added + count
# skip new text
while count > 0:
nl = string.find(delta, '\n', idx)
assert nl > 0, 'missing a newline in the delta in the RCS file'
idx = nl + 1
count = count - 1
return added, deleted
class FetchSink(rcsparse.Sink):
def __init__(self, which_rev=None):
self.head = self.branch = ''
self.tags = { }
self.meta = { }
self.revs = [ ]
self.base = { }
self.entries = { }
self.which = which_rev
def set_head_revision(self, revision):
self.head = revision
def set_principal_branch(self, branch_name):
self.branch = branch_name
def define_tag(self, name, revision):
self.tags[name] = revision
def define_revision(self, revision, timestamp, author, state,
branches, next):
self.meta[revision] = (timestamp, author, state)
self.base[next] = revision
for b in branches:
self.base[b] = revision
def set_revision_info(self, revision, log, text):
timestamp, author, state = self.meta[revision]
entry = viewcvs.LogEntry(revision, int(timestamp) - time.timezone, author,
state, None, log)
# .revs is "order seen" and .entries is for random access
self.revs.append(entry)
self.entries[revision] = entry
if revision != self.head:
added, deleted = lines_changed(text)
if string.count(revision, '.') == 1:
# on the trunk. reverse delta.
changed = '+%d -%d' % (deleted, added)
self.entries[self.base[revision]].changed = changed
else:
# on a branch. forward delta.
changed = '+%d -%d' % (added, deleted)
self.entries[revision].changed = changed
def parse_completed(self):
if self.which:
self.revs = [ self.entries[self.which] ]
def fetch_log2(full_name, which_rev=None):
sink = FetchSink(which_rev)
rcsparse.Parser().parse(open(full_name), sink)
return sink.head, sink.branch, sink.tags, sink.revs
def compare_fetch(full_name, which_rev=None):
d1 = viewcvs.fetch_log(full_name, which_rev)
d2 = fetch_log2(full_name, which_rev)
if d1[:3] != d2[:3]:
print 'd1:', d1[:3]
print 'd2:', d2[:3]
return
if len(d1[3]) != len(d2[3]):
print 'len(d1[3])=%d len(d2[3])=%d' % (len(d1[3]), len(d2[3]))
return
def sort_func(e, f):
return cmp(e.rev, f.rev)
d1[3].sort(sort_func)
d2[3].sort(sort_func)
import pprint
for i in range(len(d1[3])):
if vars(d1[3][i]) != vars(d2[3][i]):
pprint.pprint((i, vars(d1[3][i]), vars(d2[3][i])))
def time_fetch(full_name, which_rev=None):
t = time.time()
viewcvs.fetch_log(full_name, which_rev)
t1 = time.time() - t
t = time.time()
fetch_log2(full_name, which_rev)
t2 = time.time() - t
print t1, t2
def profile_fetch(full_name, which_rev=None):
p = profile.Profile()
def many_calls(*args):
for i in xrange(10):
apply(fetch_log2, args)
p.runcall(many_calls, full_name, which_rev)
p.print_stats()
def varysize(full_name, which_rev=None):
def one_run(n, *args):
rcsparse._TokenStream.CHUNK_SIZE = n
t = time.time()
for i in xrange(5):
apply(fetch_log2, args)
print n, time.time() - t
#one_run(2020, full_name, which_rev)
#one_run(4070, full_name, which_rev)
#one_run(8170, full_name, which_rev)
#one_run(8192, full_name, which_rev)
#one_run(16384, full_name, which_rev)
one_run(32740, full_name, which_rev)
one_run(65500, full_name, which_rev)
one_run(100000, full_name, which_rev)
one_run(200000, full_name, which_rev)
one_run(500000, full_name, which_rev)

View File

@@ -1,49 +1,46 @@
#!/usr/bin/env python
# -*- Mode: python -*-
#
# Copyright (C) 2000-2001 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 ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
# administrative program for CVSdb; this is primarily
# used to add/rebuild CVS repositories to the database
#
# -----------------------------------------------------------------------
# Copyright (C) 2000 Jay Painter. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth below:
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# -----------------------------------------------------------------------
#
# For tracking purposes, this software is identified by:
# $Id$
#
# -----------------------------------------------------------------------
## BOOTSTRAP
import sys, os, string
_viewcvs_root = string.strip(open("/etc/viewcvs/root", "r").read())
sys.path.append(os.path.join(_viewcvs_root, "lib"))
##
#########################################################################
#
# INSTALL-TIME CONFIGURATION
#
# These values will be set during the installation process. During
# development, they will remain None.
#
import cvsdbapi
LIBRARY_DIR = None
CONF_PATHNAME = None
# Adjust sys.path to include our library directory
import sys
if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
else:
sys.path[:0] = ['../lib'] # any other places to look?
#########################################################################
import os, string, cvsdbapi
def UpdateFile(db, repository, path):

View File

@@ -1,48 +1,45 @@
#!/usr/bin/python
# -*- Mode: python -*-
#
# Copyright (C) 2000-2001 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 ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
# updates SQL database with new commit records
#
# -----------------------------------------------------------------------
# Copyright (C) 2000 Jay Painter. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth below:
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# -----------------------------------------------------------------------
#
# For tracking purposes, this software is identified by:
# $Id$
#
# -----------------------------------------------------------------------
## BOOTSTRAP
import sys, os, string
_viewcvs_root = string.strip(open("/etc/viewcvs/root", "r").read())
sys.path.append(os.path.join(_viewcvs_root, "lib"))
##
#########################################################################
#
# INSTALL-TIME CONFIGURATION
#
# These values will be set during the installation process. During
# development, they will remain None.
#
import getopt, re, cvsdbapi
LIBRARY_DIR = None
CONF_PATHNAME = None
# Adjust sys.path to include our library directory
import sys
if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
else:
sys.path[:0] = ['../lib'] # any other places to look?
#########################################################################
import os, string, getopt, re, cvsdbapi
DEBUG_FLAG = 0
@@ -132,7 +129,7 @@ def ProcessLoginfo(repository, stdin_list):
if len(list) == 4:
if list[1] == '-' and list[2] == 'New' and list[3] == 'directory':
debug('new directory')
exit(0, file_hash, 1)
return
## each file in the file list _should_ be of the form:
## file-name,<old-ver>,<new-ver>

146
tools/make-database Executable file
View File

@@ -0,0 +1,146 @@
#!/usr/bin/env python
# -*- Mode: python -*-
#
# Copyright (C) 2000-2001 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 ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
# administrative program for CVSdb; creates a clean database in
# MySQL 3.22 or later
#
# -----------------------------------------------------------------------
#
import os, sys, string
INTRO_TEXT = """\
This script creates the database and tables in MySQL used by the ViewCVS
checkin database. You will be prompted for: database user, database user
password, and database name. This script will use mysql to create the
database for you. You will then need to set the appropriate parameters
in your viewcvs.conf file under the [cvsdb] section.
"""
DATABASE_SCRIPT="""\
DROP DATABASE IF EXISTS <dbname>;
CREATE DATABASE <dbname>;
USE <dbname>;
DROP TABLE IF EXISTS branches;
CREATE TABLE branches (
id mediumint(9) DEFAULT '0' NOT NULL auto_increment,
branch varchar(64) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE branch (branch)
);
DROP TABLE IF EXISTS checkins;
CREATE TABLE checkins (
type enum('Change','Add','Remove'),
ci_when datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
whoid mediumint(9) DEFAULT '0' NOT NULL,
repositoryid mediumint(9) DEFAULT '0' NOT NULL,
dirid mediumint(9) DEFAULT '0' NOT NULL,
fileid mediumint(9) DEFAULT '0' NOT NULL,
revision varchar(32) binary DEFAULT '' NOT NULL,
stickytag varchar(255) binary DEFAULT '' NOT NULL,
branchid mediumint(9) DEFAULT '0' NOT NULL,
addedlines int(11) DEFAULT '0' NOT NULL,
removedlines int(11) DEFAULT '0' NOT NULL,
descid mediumint(9),
UNIQUE repositoryid (repositoryid,dirid,fileid,revision),
KEY ci_when (ci_when),
KEY whoid (whoid),
KEY repositoryid_2 (repositoryid),
KEY dirid (dirid),
KEY fileid (fileid),
KEY branchid (branchid)
);
DROP TABLE IF EXISTS descs;
CREATE TABLE descs (
id mediumint(9) DEFAULT '0' NOT NULL auto_increment,
description text,
hash bigint(20) DEFAULT '0' NOT NULL,
PRIMARY KEY (id),
KEY hash (hash)
);
DROP TABLE IF EXISTS dirs;
CREATE TABLE dirs (
id mediumint(9) DEFAULT '0' NOT NULL auto_increment,
dir varchar(128) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE dir (dir)
);
DROP TABLE IF EXISTS files;
CREATE TABLE files (
id mediumint(9) DEFAULT '0' NOT NULL auto_increment,
file varchar(128) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE file (file)
);
DROP TABLE IF EXISTS people;
CREATE TABLE people (
id mediumint(9) DEFAULT '0' NOT NULL auto_increment,
who varchar(32) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE who (who)
);
DROP TABLE IF EXISTS repositories;
CREATE TABLE repositories (
id mediumint(9) DEFAULT '0' NOT NULL auto_increment,
repository varchar(64) binary DEFAULT '' NOT NULL,
PRIMARY KEY (id),
UNIQUE repository (repository)
);
DROP TABLE IF EXISTS tags;
CREATE TABLE tags (
repositoryid mediumint(9) DEFAULT '0' NOT NULL,
branchid mediumint(9) DEFAULT '0' NOT NULL,
dirid mediumint(9) DEFAULT '0' NOT NULL,
fileid mediumint(9) DEFAULT '0' NOT NULL,
revision varchar(32) binary DEFAULT '' NOT NULL,
UNIQUE repositoryid (repositoryid,dirid,fileid,branchid,revision),
KEY repositoryid_2 (repositoryid),
KEY dirid (dirid),
KEY fileid (fileid),
KEY branchid (branchid)
);
"""
if __name__ == "__main__":
print INTRO_TEXT
user = raw_input("MySQL User: ")
passwd = raw_input("MySQL Password: ")
dbase = raw_input("ViewCVS Database Name [default: ViewCVS]: ")
if not dbase:
dbase = "ViewCVS"
cmd = "{ mysql --user=%s --password=%s ; } 2>&1" % (user, passwd)
dscript = string.replace(DATABASE_SCRIPT, "<dbname>", dbase)
mysql = os.popen(cmd, "w")
mysql.write(dscript)
status = mysql.close()
if status:
print "[ERROR] the database did not create sucessfully."
sys.exit(1)
print "Database created successfully."
sys.exit(0)

39
tools/make-release Executable file
View File

@@ -0,0 +1,39 @@
#!/bin/sh
#
# Copyright (C) 2000-2001 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 ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
# make-release: internal tool for creating ViewCVS releases
#
# -----------------------------------------------------------------------
#
if [ "x$1" = "x" ]; then
echo "USAGE: $0 tagname target-directory"
exit 1
fi
if test -e $2; then
echo "ERROR: must remove $2 first."
exit 1
fi
# grab a copy of the CVS repository
echo 'Checking out into:' $2
cvs -d :pserver:anonymous@cvs.viewcvs.sourceforge.net:/cvsroot/viewcvs export -r $1 -d $2 viewcvs
# various shifting, cleanup
mv $2/website/license-1.html $2/LICENSE.html
rm -r $2/website
rm $2/tools/make-release
echo 'Done.'

180
viewcvs-install Executable file
View File

@@ -0,0 +1,180 @@
#!/usr/bin/env python
# -*- Mode: python -*-
#
# Copyright (C) 2000-2001 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 ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
# install script for viewcvs -- temporary?
#
# ### this will eventually be replaced by autoconf plus tools. an
# ### interactive front-end to ./configure may be provided.
#
# -----------------------------------------------------------------------
#
import os
import sys
import string
import re
import traceback
import py_compile
# get access to our library modules
sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), 'lib'))
import compat
## installer text
INFO_TEXT = """\
This is the ViewCVS installer. It will allow you to choose the install
path for ViewCVS. You will now be asked some installation questions.
Defaults are given in square brackets. Just hit [Enter] if a default
is okay.
"""
## installer defaults
ROOT_DIR = "/usr/local/viewcvs-dev"
## list of files for installation
## tuple (source path, destination path, install mode, true/false flag for
## search-and-replace, flag for prompt before replace, compile_it)
##
FILE_INFO_LIST = [
("cgi/viewcvs.cgi", "cgi/viewcvs.cgi", 0755, 1, 0, 0),
("cgi/queryform.cgi", "cgi/queryform.cgi", 0755, 1, 0, 0),
("cgi/query.cgi", "cgi/query.cgi", 0755, 1, 0, 0),
("cgi/viewcvs.conf.dist", "viewcvs.conf", 0644, 0, 1, 0),
("lib/PyFontify.py", "lib/PyFontify.py", 0644, 0, 0, 1),
("lib/blame.py", "lib/blame.py", 0644, 0, 0, 1),
("lib/commit.py", "lib/commit.py", 0644, 0, 0, 1),
("lib/compat.py", "lib/compat.py", 0644, 0, 0, 1),
("lib/config.py", "lib/config.py", 0644, 0, 0, 1),
("lib/cvsdbapi.py", "lib/cvsdbapi.py", 0644, 1, 0, 1),
("lib/database.py", "lib/database.py", 0644, 0, 0, 1),
("lib/dbi.py", "lib/dbi.py", 0644, 0, 0, 1),
("lib/popen.py", "lib/popen.py", 0644, 0, 0, 1),
("lib/py2html.py", "lib/py2html.py", 0644, 0, 0, 1),
("lib/query.py", "lib/query.py", 0644, 1, 0, 1),
("lib/rcsparse.py", "lib/rcsparse.py", 0644, 1, 0, 1),
("lib/rlog.py", "lib/rlog.py", 0644, 1, 0, 1),
("lib/viewcvs.py", "lib/viewcvs.py", 0644, 1, 0, 1),
("tools/loginfo-handler", "loginfo-handler", 0755, 1, 0, 0),
("tools/cvsdbadmin", "cvsdbadmin", 0755, 1, 0, 0),
("tools/make-database", "make-database", 0755, 1, 0, 0),
("html-templates/queryformtemplate.html",
"html-templates/queryformtemplate.html", 0644, 0, 1, 0),
("html-templates/querytemplate.html",
"html-templates/querytemplate.html", 0644, 0, 1, 0),
]
def Error(text, etype=None, evalue=None):
print
print "[ERROR] %s" % text
if etype:
print '[ERROR] ',
traceback.print_exception(etype, evalue, None, file=sys.stdout)
sys.exit(1)
def MkDir(path):
try:
compat.makedirs(path)
except os.error, e:
if e[0] == 17:
# EEXIST: file exists
return
if e[0] == 13:
# EACCES: permission denied
Error("You do not have permission to create directory %s" % path)
Error("Unknown error creating directory %s" % path, OSError, e)
def SetOnePath(contents, var, value):
pattern = re.compile('^' + var + r'\s*=\s*.*$', re.MULTILINE)
repl = '%s = "%s"' % (var, os.path.join(ROOT_DIR, value))
return re.sub(pattern, repl, contents)
def SetPythonPaths(contents):
if contents[:2] == '#!':
shbang = '#!' + sys.executable
contents = re.sub('^#![^\n]*', shbang, contents)
contents = SetOnePath(contents, 'LIBRARY_DIR', 'lib')
contents = SetOnePath(contents, 'CONF_PATHNAME', 'viewcvs.conf')
contents = SetOnePath(contents, 'HTML_TEMPLATE_DIR', 'html-templates')
return contents
def InstallFile(src_path, dest_path, mode, set_python_paths, prompt_replace,
compile_it):
dest_path = os.path.join(ROOT_DIR, dest_path)
if prompt_replace and os.path.exists(dest_path):
temp = raw_input("File %s exists, overwright? [y/N]: " % (dest_path))
if not temp or string.lower(temp[0]) != "y":
return
try:
contents = open(src_path, "r").read()
except IOError, e:
Error(str(e))
if set_python_paths:
contents = SetPythonPaths(contents)
## write the file to the destination location
path, basename = os.path.split(dest_path)
MkDir(path)
try:
open(dest_path, "w").write(contents)
except IOError, e:
if e[0] == 13:
# EACCES: permission denied
Error("You do not have permission to write file %s" % dest_path)
Error("Unknown error writing file %s" % dest_path, IOError, e)
os.chmod(dest_path, mode)
if compile_it:
py_compile.compile(dest_path)
## MAIN
if __name__ == "__main__":
print INFO_TEXT
## get the install path
temp = raw_input("Installation Path [%s]: " % ROOT_DIR)
temp = string.strip(temp)
if len(temp):
ROOT_DIR = temp
## install the files
print
print "Installing ViewCVS to:", ROOT_DIR
for args in FILE_INFO_LIST:
print " ", args[0]
apply(InstallFile, args)
print
print "Installation Complete"

BIN
website/images/chalk.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 755 B

View File

@@ -5,56 +5,75 @@
</head>
<body background="/images/chalk.jpg">
<h1>ViewCVS: Viewing CVS Repositories</h1>
<table width="100&#37;" cellspacing=5>
<tr>
<td>
<h1>ViewCVS: Viewing CVS Repositories</h1>
</td>
<td align=center valign=top bgcolor="white" width="1%">
<b>Quickstart:</b>
<a href="viewcvs-0.6.tar.gz">download</a>
</td>
<td width="1%"><a href="http://sourceforge.net/"><img border=0
src="http://sourceforge.net/sflogo.php?group_id=18760&type=1"></a><br><a href="http://sourceforge.net/projects/viewcvs/">ViewCVS&nbsp;project&nbsp;page</a>
</td>
</tr>
</table>
<p>
The ViewCVS software was inspired by
<a href="http://linux.fh-heilbronn.de/~zeller/cgi/cvsweb.cgi"><i>cvsweb</i></a>
<a href="http://stud.fh-heilbronn.de/~zeller/cgi/cvsweb.cgi/"><i>cvsweb</i></a>
(by <a href="mailto:zeller@think.de">Henner Zeller</a>).
I wanted to make some changes and updates, but cvsweb was
implemented in Perl (and rather poorly, IMO). So I undertook the
implemented in Perl. While I can manage some Perl, cvsweb was
rather unmaintainable for me. So I undertook the
task to convert the software to
<a href="http://www.python.org/"><i>Python</i></a>.
<a href="http://www.python.org/"><i>Python</i></a>. As a result,
I've actually been able to go <em>way</em> beyond the simple
changes that I had envisioned.
</p>
<p>
ViewCVS can browse directories, change logs, and specific
revisions of files. It can display diffs between versions and
show selections of files based on tags or branches.
show selections of files based on tags or branches. In addition,
ViewCVS has "annotation" or "blame" support, and the beginnings
of Bonsai-like query facilities.
</p>
<p>
ViewCVS is currently at version 0.4. It was a
port of the cvsweb script, but has had numerous cleanups and other
modifications, based on some of Python's strengths. There is
still some "badness" in there, but I've been working on flushing
that out, along with a few new features. The
functionality of ViewCVS is equal to that of cvsweb, minus the
"annotation" support. Annotation requires read/write access to
the CVS repository (at this time), and I believe that is a
Bad Thing to do. One of my tasks will be eliminating the
read/write requirement.
ViewCVS is currently at version 0.6. It was a port of the cvsweb
script, but has had numerous cleanups and other modifications,
based on some of Python's strengths. There is still some minor
"badness" remaining from the Perl code, but I've been working on
flushing that out, while adding new features. Currently, the
functionality of ViewCVS surpasses that of cvsweb.
</p>
<p>
The software is available for download:
</p>
<blockquote>
<a href="viewcvs-0.4.tar.gz">Version 0.4 of ViewCVS</a>
<a href="viewcvs-0.6.tar.gz">Version 0.6 of ViewCVS</a>
</blockquote>
<p>
Of course, it is also available through ViewCVS itself:
</p>
<blockquote>
<a href="/cgi-bin/viewcvs.cgi/gjspy/viewcvs/">http://www.lyra.org/cgi-bin/viewcvs.cgi/gjspy/viewcvs/</a>
<a href="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/viewcvs/">http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/viewcvs/</a>
</blockquote>
<p>
ViewCVS requires <strong>Python 1.5</strong> (which has been out
for a couple years and is readily available for your favorite
operating system).
operating system). If you choose to use the SQL Checkin Database
feature, then you must use <strong>Python 1.5.2</strong> and the
<a href="http://dustman.net/andy/python/MySQLdb"><i>MySQLdb
module</i></a> installed.
</p>
<p>
[ <a href="../">up to Python software</a> ]
[ <a href="../../">up to Greg's page</a> ]
ViewCVS has been developed by the <a href="who.html">ViewCVS
Group</a> and is made available under a
<a href="license-1.html">BSD-type license</a>.
</p>
<hr width="75&#37;">
@@ -66,16 +85,46 @@
<a href="http://mailman.lyra.org/mailman/listinfo/viewcvs">ViewCVS
mailing list</a>.
</p>
<p>
A <a href="http://mailman.lyra.org/mailman/listinfo/viewcvs-dev">mailing
list for ViewCVS developers</a> is also available.
</p>
<hr width="75&#37;">
<h2>Additional features over cvsweb</h2>
<p>
<strong>New to version 0.5:</strong>
</p>
<ul>
<li>Colorization for Python files</li>
<li>Better reporting for unreadable files</li>
<li>More robust when given varying <code>rcsdiff</code> or
<code>rlog</code> outputs</li>
<li>Hard breaks in human-readable diffs</li>
<li>
Colorization for many file types via <code>enscript</code>.
</li>
<li>
Bonsai-like query features.
</li>
<li>
Annotation/blame support against a <strong>read-only</strong>
repository.
</li>
<li>
Configuration on a per-virtual-host basis. This allows you
to share the configuration file and ViewCVS installation
across virtual hosts, yet still be able to fine-tune the
options when necessary.
</li>
</ul>
<p>
Other improvements over cvsweb:
</p>
<ul>
<li>Better reporting for unreadable files.</li>
<li>
More robust when given varying <code>rcsdiff</code> or
<code>rlog</code> outputs.
</li>
<li>Hard breaks in human-readable diffs.</li>
<li>
The configuration file is optional (you can change the values
right in the CGI script and avoid the config file, if you so
@@ -85,6 +134,16 @@
<li>
Directories with a large number of files can be viewed.
</li>
<li>
<strong>Security</strong>: ViewCVS only requires read access
to the CVS repository (not read/write). With the correct
security partitioning, this means that even if ViewCVS were to
be subverted, your source code is safe. Further, ViewCVS does
not use any <code>system()</code> or <code>popen()</code>
calls, which are very susceptible to abuse.
<br>
<small>(cvsweb had a hole due to a popen() call)</small>
</li>
</ul>
<p>
@@ -93,6 +152,7 @@
<ul>
<li>UI streamlining/simplification</li>
<li>Integration with CVS checkin auto-mail scripts</li>
<li>Tighter integration the query features</li>
<li>
<i>Suggestions? Send mail to the
<a href="mailto:viewcvs@lyra.org">viewcvs@lyra.org</a>
@@ -105,14 +165,29 @@
Longer term:
</p>
<ul>
<li>Annotation ("blame") support (similar to cvsweb)</li>
<li>Integration with an indexer such as LXR</li>
<li>Additional colorizers</li>
</ul>
<hr width="75&#37;">
<h2>Colorization of Python files</h2>
<h2>Colorization of files</h2>
<p>
ViewCVS can make use of the <code>enscript</code> program to
colorize files in the CVS repository. If <code>enscript</code>
is present on your system, then set the
<code>use_enscript</code> option in the
<code>viewcvs.conf</code> configuration file. If necessary,
update the <code>enscript_path</code> option to point to your
installation directory. ... That's it! Now, as you view files
through ViewCVS, they will be colored.
</p>
<h3>Colorization of Python files</h3>
<p>
ViewCVS currently comes with a builtin colorizer for Python
source files. This may go away, given the new
<code>enscript</code> support...
</p>
<p>
Christophe Pelte suggested this feature: colorize Python source
files using
@@ -130,7 +205,7 @@
<address><a href="mailto:gstein@lyra.org">Greg Stein</a></address>
<!-- Created: Fri Dec 3 02:51:37 PST 1999 -->
<!-- hhmts start -->
Last modified: Fri Mar 24 03:12:34 PST 2000
Last modified: Fri May 11 14:22:36 PDT 2001
<!-- hhmts end -->
</body>
</html>

83
website/license-1.html Normal file
View File

@@ -0,0 +1,83 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>ViewCVS License Agreement (v1)</title>
</head>
<body>
<h1>ViewCVS License Agreement (v1)</h1>
<p>
The following text constitutes the license agreement for the
<a href="./">ViewCVS</a> software. It
is an agreement between
<a href="who.html">The ViewCVS
Group</a> and the users of ViewCVS.
</p>
<p>
<small>
<em>
Note: the copyright years were updated on May 12, 2001. No
other changes were made to the license.
</em>
</small>
</p>
<hr>
<p>
<b>
Copyright &copy; 1999-2001 The ViewCVS Group. All rights reserved.
</b>
</p>
<p>
By using ViewCVS, you agree to the terms and conditions set
forth below:
</p>
<p>
Redistribution and use in source and binary forms, with or
without modification, are permitted provided that the following
conditions are met:
</p>
<ol>
<li>
<p>
Redistributions of source code must retain the above
copyright notice, this list of conditions and the following
disclaimer.
</p>
</li>
<li>
<p>
Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials
provided with the distribution.
</p>
</li>
</ol>
<p>
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
</p>
<hr>
<address><a href="mailto:gstein@lyra.org">Greg Stein</a></address>
<!-- Created: Mon May 8 19:01:27 PDT 2000 -->
<!-- hhmts start -->
Last modified: Sat May 12 15:53:33 PDT 2001
<!-- hhmts end -->
</body>
</html>

32
website/who.html Normal file
View File

@@ -0,0 +1,32 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>The ViewCVS Group</title>
</head>
<body background="/images/chalk.jpg">
<h1>The ViewCVS Group</h1>
<p>
The ViewCVS Group is an informal group of people working on and
developing the ViewCVS package. The current set of members are:
</p>
<ul>
<li><a href="http://www.lyra.org/greg/"><b>Greg Stein</b></a></li>
<li>Jay Painter</li>
</ul>
<p>
Please note that the <a href="./">ViewCVS</a> package is offered
under a BSD-type license, which is detailed on the
<a href="license-1.html">ViewCVS License</a> page.
</p>
<hr>
<address><a href="mailto:gstein@lyra.org">Greg Stein</a></address>
<!-- Created: Mon May 8 19:08:58 PDT 2000 -->
<!-- hhmts start -->
Last modified: Fri May 11 14:10:54 PDT 2001
<!-- hhmts end -->
</body>
</html>