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

Compare commits

...

1111 Commits

Author SHA1 Message Date
3c1cfef827 fix glob pattern interpretation 2015-06-16 16:17:01 +03:00
6c18327bbf fix fulltext comment search type radiobutton 2014-12-03 16:38:21 +03:00
cd14ba3825 Fix patch view 2014-04-02 15:29:04 +04:00
8ca4b5b85a Enable branch field if roottype != svn, not if is == cvs 2013-11-20 17:07:20 +04:00
8b3d3363f2 Use non-destructive subconfigs instead of in-place per-root patching of config object 2013-11-20 17:03:33 +04:00
44c5f2bb1a Remove binary_mime_re option 2013-11-20 17:03:33 +04:00
d3d81490e3 Use REQUEST_URI instead of SCRIPT_NAME 2013-09-11 17:05:26 +04:00
5814634779 Fix auth for repository root 2013-08-16 20:18:21 +04:00
b3000cf63b More fixes for globalauth 2013-08-12 16:48:21 +04:00
0a6f6a7a66 OK, now globalauth works without apache2 fixup handler 2013-08-12 16:27:54 +04:00
3ddd0caa42 Start new globalauth implementation 2013-08-09 20:13:57 +04:00
983f9c7379 Post-merge debug.
Also return some lost files back, document 4intra.net modifications
in CHANGES and README files, remove 'union' authorizer and rewritehtml
as the similar functionality is already provided by the core.

Also fix diffs for non-bash (sh/ash/dash) shells.
2013-07-24 17:37:59 +04:00
56c2b61458 Merge with original r2905 2013-07-18 19:13:28 +04:00
vfilippov
479a5b4506 Bug 124910 - Fix indexing file deletions (f**king undocumented swig bindings!!!)
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1653 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:12:24 +04:00
vfilippov
5d442fac7d Bug 113586 - Suppress UNSAFE STATEMENT warning
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1628 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:12:24 +04:00
vfilippov
57e1ca8909 Bug 113586 - Suppress UNSAFE STATEMENT warning
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1626 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:12:24 +04:00
vfilippov
8492aa772e Bug 82651 - Limit content length for CALL SNIPPETS
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1609 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:12:24 +04:00
vfilippov
e854e254f9 Bug 106871
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1603 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:12:23 +04:00
vfilippov
4b06eeeb94 Bug 105184 - Force annotation using client.blame3()
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1593 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:12:23 +04:00
vfilippov
ac063ff93a Bug 82651 - 500 instead of 404 on module import errors
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1591 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:12:23 +04:00
vfilippov
b5ac9522cc Bug 82651 - Allow index entries overwrite mode for Sphinx content indexing
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1588 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:12:23 +04:00
vfilippov
a071627c59 Bug 82651 - Pass force to handle_revision
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1587 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:12:23 +04:00
vfilippov
24e0a24ca9 Bug 99105 - Exact match on repo using last part of name
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1585 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:12:23 +04:00
vfilippov
dfff9c0cc2 Bug 82651
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1573 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:05 +04:00
vfilippov
0bd2b940f9 Bug 82651
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1452 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:05 +04:00
vfilippov
24b979d9e2 Bug 88900 - Force cvs_ondisk_charset
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1451 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:05 +04:00
vfilippov
7d06bd21bc Bug 82651
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1447 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:05 +04:00
vfilippov
fa08478619 Bug 82651 - () -> None
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1446 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:04 +04:00
vfilippov
7d15648286 Bug 82651 - Fix for inaccessible repos
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1445 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:04 +04:00
vfilippov
76987f0851 Bug 82651 - Retrieve text file contents from SVN when searching (debug)
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1444 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:04 +04:00
vfilippov
928bf6f1a6 Bug 82651 - Retrieve text file contents from SVN when searching
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1443 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:04 +04:00
vfilippov
4cd52560ac Bug 88267 - Partial rebuild ability for CVS
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1442 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:04 +04:00
vfilippov
a0a40b6047 Bug 87710
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1424 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:04 +04:00
vfilippov
e8c05fc096 Bug 87133
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1423 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:03 +04:00
vfilippov
999c9de4d3 Bug 87501 - Add must-revalidate headers
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1422 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:03 +04:00
vfilippov
131171943d Bug 87501 - Guess for full diff
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1421 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:03 +04:00
vfilippov
e415cd7bb0 Bug 87501 - init charset guesser
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1417 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:03 +04:00
vfilippov
575b4d8a49 Bug 63447 - 1/20 probability for cache clean
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1411 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:03 +04:00
vfilippov
3ec2c244a8 Bug 82651 - simple buffered reader for diff pipes
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1402 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:02 +04:00
vfilippov
160233f758 Bug 82651 - Content size limit (4MB Sphinx)
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1401 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:02 +04:00
vfilippov
72934bf6cd Bug 82651 - Content size limit (4MB Sphinx), enable snippets setting
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1400 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:02 +04:00
vfilippov
a564b02d18 Bug 82651 - Store contents for snippet retrieval in MySQL
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1399 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:02 +04:00
vfilippov
80ccb26b20 Bug 82651 - Store contents for snippet retrieval in MySQL
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1398 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:01 +04:00
vfilippov
1b75ada880 Bug 82651 - Remove rest of UTF-8 ugly hacks
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1396 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:01 +04:00
vfilippov
ecadbf9fd3 Bug 82651 - Remove rest of UTF-8 ugly hacks
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1394 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:01 +04:00
vfilippov
8dc02448bc Bug 82651
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1393 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:01 +04:00
vfilippov
8aca8406a3 Bug 82651 - Non-verbose mode
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1392 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:01 +04:00
vfilippov
639d1c25db Bug 82651 - Tika&Sphinx&chardet content indexing (done!)
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1389 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:01 +04:00
vfilippov
e363cf19b1 Bug 82651 - Tika&Sphinx&chardet content indexing (done!)
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1388 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:00 +04:00
vfilippov
83c7e6fe49 Bug 82651
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1371 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:00 +04:00
vfilippov
361a00ff13 Bug 82651 - Fix cvsdb glob search, TODO index file contents
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1365 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:00 +04:00
vfilippov
e8f25d9c7b Bug 63447 - Cache expiration using mtime; Clean cache sometimes! (with 1/1000 probability)
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1345 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:00 +04:00
vfilippov
c6582d1480 Bug 79260 - Fix cvsntacl auth for Python 2.6
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1265 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:00 +04:00
vfilippov
ceb4990dec Bug 79260 - Fix cvsntacl auth for Python 2.6
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1264 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:07:00 +04:00
vfilippov
12434cb5b7 Bug 57786 - Fix ViewVC pipe errors through use of inetd "cvsnt rcsfile" service
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1242 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:59 +04:00
vfilippov
f4f2e432a7 Bug 76690 - Index
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1231 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:59 +04:00
vfilippov
7eb621bcd1 Bug 76690 - Optimize "only svn" / "only cvs"
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1230 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:59 +04:00
vfilippov
5de0639a9c Bug 76690 - Check glob match for being really an exact one
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1229 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:59 +04:00
vfilippov
e25a91837e Bug 74522 - Ignore spaces in ViewVC diffstat
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1225 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:59 +04:00
vfilippov
6df7a894d1 Bug 70605
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1219 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:58 +04:00
vfilippov
04d3d504e0 Bug 73748 - Use real paths for repositories
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1195 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:58 +04:00
vfilippov
33fffa82e8 Bug 71273 - Fix exception in ViewVC diffs
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@1041 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:58 +04:00
vfilippov
fdd255f0ff Bug 63447 - /i
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@894 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:58 +04:00
vfilippov
0b5123e1b8 Bug 63447
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@884 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:58 +04:00
vfilippov
56614d0f13 Bug 63447 - Support for FOF_Sudo authorization
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@883 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:58 +04:00
vfilippov
94c0c90329 Bug 63447 - include fof_sudo in rss links
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@879 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:58 +04:00
vfilippov
a4c3bd1a46 Bug 63447
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@877 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:57 +04:00
vfilippov
a9701721e2 Bug 63447 - Cache security
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@875 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:57 +04:00
vfilippov
5c1ac512d1 Bug 57786
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@871 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:57 +04:00
vfilippov
cd9c47fe46 Bug 57786Show diff href
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@870 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:57 +04:00
vfilippov
bb906c1f70 Bug 63447
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@869 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:57 +04:00
vfilippov
b9a894f708 Bug 63447 - Global auth with external config file
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@868 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:57 +04:00
vfilippov
1fae3f7e3e Bug 63447
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@865 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:57 +04:00
vfilippov
c73ba23f6e Bug 63447 - AnyJSON instead of simply json, debug
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@864 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:56 +04:00
vfilippov
0f323a50a4 Bug 63447 - Single sign-on for ViewVC
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@862 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:56 +04:00
vfilippov
f3ba9d5e0a Bug 63447 - Single sign-on for ViewVC
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@861 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:56 +04:00
vfilippov
1cda6497e1 Debug "unsecure patch" detection for queries across multiple repos,
debug vcauth grp


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@771 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:56 +04:00
vfilippov
b9f2b63c09 Bug 45675: Bug 60603 displayed an empty patch
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@661 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:56 +04:00
vfilippov
b1cffd5f2d Bug 60409 - Output correct link rel=self in RSS feeds
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@644 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:56 +04:00
vfilippov
323a4d5629 Bug 59499
Show diffs for moved files in query results


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@633 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:55 +04:00
vfilippov
d65737cc43 Bug 57786
Ignore SIGPIPE


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@587 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:55 +04:00
vfilippov
67b205634e Bug 37020
Удалил изврат, добавив чуть меньший изврат:
Теперь в процессе установки bin-файлы не модифицируются,
а только добавляется рядом с ними файл viewvcinstallpath,
в котором прописываются пути.


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@539 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:55 +04:00
vfilippov
4e9089255c Bug 57246
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@538 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:55 +04:00
vfilippov
bf062cc41b Bug 57245
Hyperlink bug URLs

[rewritehtml]
name.find = REGEXP
name.replace = REPLACEMENT


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@537 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:55 +04:00
vfilippov
ab7e1bdc64 Bug 37020
SP4 lexer


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@529 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:55 +04:00
vfilippov
e17b0dce21 Bug 56474
Honor repository for build_commit


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@518 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:55 +04:00
vfilippov
552d04e882 Bug 45200
remove temp files


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@517 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:55 +04:00
vfilippov
f0a1418fbf Bug 45200
USE SHELL!!!
The bug was probably somewhere in file descriptor cloning + Apache webserver


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@516 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:54 +04:00
vfilippov
75be406156 Bug 45200
Use temp file


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@512 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:54 +04:00
vfilippov
964531a7a9 Bug 37020
mystical empty diffs


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@421 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:54 +04:00
vfilippov
4304976db7 Bug 37020
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@280 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:54 +04:00
vfilippov
8a649198d4 Bug 37020
Bug 32155
remove date & author from table


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@272 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:54 +04:00
vfilippov
e78c234550 Bug 37020
Bug 32155
Fix an EVERLASTING error for all RSS generator:
Generating dates via strftime() with non-english LC_TIME


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@271 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:54 +04:00
vfilippov
8367e08370 Bug 37020
Don't verify comments


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@270 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:54 +04:00
vfilippov
b7c8b5eb6f Bug 37020
Bug 32155
RSS with committed file lists


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@269 6955db30-a419-402b-8a0d-67ecbb4d7f56
2013-07-18 17:06:54 +04:00
06bfb6a5fe Record merge with r2243 in git 2013-07-18 17:05:41 +04:00
cmpilato
4251b52987 Fix buglet in (unused) ViewVCHtmlFormatter.get_result() function.
* lib/viewvc.py
  (ViewVCHtmlFormatter.get_result): Remove some unnecessary
    statements, and fix the fact that this was disregarding the 'maxlen'
    parameter.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2905 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-07-10 16:29:13 +00:00
cmpilato
0ac2f63f71 * conf/viewvc.conf.dist: Minor comment formatting tweak.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2904 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-05-01 15:49:29 +00:00
cmpilato
aa724feae4 Fix issue #527 ("ViewVC markup/annotate views raise exceptions
depending on Python version").

* lib/viewvc.py
  (transcode_text): Avoid using keyword arguments with unicode() and
    .encode(), support for which wasn't added until Python 2.7.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2902 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-25 14:52:58 +00:00
cmpilato
9e97bd332d * CHANGES
Merge 1.1.20 changes.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2901 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-24 14:12:41 +00:00
cmpilato
89d478a933 Bump latest advertised release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2899 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-24 13:31:36 +00:00
cmpilato
a1fd08948a * lib/viewvc.py
(markup_stream, DiffSource._format_text): Fix still more buglets
    around tab-to-space conversion.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2895 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-23 20:17:01 +00:00
cmpilato
d2e7f4aff2 * lib/vclib/ccvs/__init__.py
(find_root_in_parent): Minor comment tweak only.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2893 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-23 18:53:15 +00:00
cmpilato
ece31e7369 * lib/vclib/ccvs/__init__.py
(_is_cvsroot): New helper function.
  (expand_root_parent, find_root_in_parent): Rework these to now
    use _is_cvsroot().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2892 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-23 18:49:10 +00:00
cmpilato
16d7e0af8a Fix issue #526 ("Subversion roots not longer accessible").
This is a big-time regression in root handling which unfortunately
found its way into the 1.1.19 release.

Reported by: Michael Theys <michael.th90{_AT_}gmail.com>,
             olli hauer <ohauer{_AT_}gmx.de>

* lib/vclib/ccvs/__init__.py
  (expand_root_parent): Avoid unnecessary convenience variable.
  (find_root_in_parent): Don't return a rootpath that we've not
    checked for existence!!


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2891 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-23 18:43:15 +00:00
cmpilato
75e503a16b * CHANGES
Merge in 1.1.19 changes.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2888 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-22 19:28:18 +00:00
cmpilato
3fbaffa2fd Bump latest advertised release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2885 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-22 19:20:06 +00:00
cmpilato
a4ad1b13c2 * lib/viewvc.py
(make_time_string): A little syntax change to be more Pythonic.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2881 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-19 20:34:46 +00:00
cmpilato
1f58e41376 Finish issue #46 ("ISO 8601 date/time format").
* lib/viewvc.py
  (make_time_string): If cfg.options.iso8601_timestamps is set,
    generate ISO-8601-compliant timestamp strings.

* lib/config.py
  (Config.set_defaults): Initialize 'iso8601_timestamps' option value.

* conf/viewvc.conf.dist
  (iso8601_timestamps): New option.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2880 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-19 20:31:15 +00:00
cmpilato
4fd9cc0811 Fix some latent bugs whitespace handling.
* lib/viewvc.py
  (markup_stream): Only expand tabs if the tabsize > 0.
  (DiffSource._format_text): Only strip EOL stuffs from the ends of
    lines -- preserve other whitespace forms.  Also, only expand tabs if
    the tabsize > 0.

* conf/viewvc.conf.dist
  (tabsize): Use the term "horizontal tab character" rather than
    "tabstop".  The latter is the destination; the former is the
    character that tells the text flow to resume there.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2876 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-18 13:49:15 +00:00
cmpilato
7026dcb498 Fix an exception recently introduced.
* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.filesize): Recombine path_parts before
    calling _get_dirents().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2874 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-17 18:16:48 +00:00
cmpilato
6406b106a1 More work on issue #11 ("Universal UTF-8 output from ViewVC").
* lib/viewvc.py
  (markup_stream): When transcoding, handle the whole body of file
    contents at once rather than trying to go line-by-line.  Why?
    Because until transcoded, the concept of a "line" is rather
    meaningless.  (NOTE: There is almost certainly some fallout to
    occur in the annotate view as a result of this work, since each VC
    system's annotation support also uses the naive concept of a
    line.)

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2873 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-17 17:59:41 +00:00
cmpilato
a2090ce90b Make some additional dents on issue #11 ("Universal UTF-8 output from
ViewVC").

Use the 'chardet' module where available and enabled by configuration
to detect source file content encoding, and transcode the output to
UTF-8.  We supported this already via Pygments when
'enable_syntax_coloration' was set; now we can also support this when
it isn't.

* lib/viewvc.py
  (detect_encoding, transcode_text): New helper functions.
  (markup_stream): Use the new helper functions to attempt to
    transcode text into UTF-8 even when syntax coloration is *not* in
    use.

* conf/viewvc.conf.dist
  (detect_encoding): Remove notation about this only being used when
    'enable_syntax_coloration' is also enabled.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2872 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-17 15:23:42 +00:00
cmpilato
0ca6106034 Fix issue #525 ("Tarball output is double-compressed when
allow_compress=1").

* lib/viewvc.py
  (get_writeready_server_file): Add 'allow_compress' parameter, and
    handling to give callers the power to disable response-level
    compression.
  (download_tarball): When calling get_writeready_server_file(),
    disable compression (if any) since we're doing our own gzipping
    herein.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2870 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-16 18:15:50 +00:00
cmpilato
801eaff764 Fix an ancient code concern by no longer reading file content fully
into memory when generating tarballs.

* lib/viewvc.py
  (generate_tarball): Avoid reading file contents fully into memory.
    Rather, query the filesize from the vclib provider and chunk the
    output.  If the filesize must be calculated, use two chunked
    passes over those contents (one to measure, one to write to the
    tarball).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2867 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-15 19:06:30 +00:00
cmpilato
1ca3dc4195 Fix issue #524 ("Give administrators a way to limit the size of files
processed by markup and annotate views").  This introduces a new
'max_filesize_kbytes' configuration option for limiting markup and
annotate operations on really big files (whose contents unfortunately
must be read fully into memory sometimes).  By default, a 512-kilobyte
limit will be in place.

* lib/vclib/__init__.py
  (Repository.filesize): New.

* lib/vclib/svn/svn_repos.py
  (LocalSubversionRepository.filesize): New function.

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.filesize): New function.

* lib/vclib/ccvs/bincvs.py
  (BaseCVSRepository.filesize): New function (returns -1 aka "not
    implemented")

* conf/viewvc.conf.dist
  (max_filesize_kbytes): New configuration option.

* lib/config.py
  (Config.set_defaults): Set default value for new
    'max_filesize_kbytes' configuration option.

* lib/viewvc.py
  (assert_viewable_filesize): New helper function.
  (markup_or_annotate): Use assert_viewable_filesize() and the new
    repos.filesize() API to honor the new 'max_filesize_kbytes'
    configuration option.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2866 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-15 19:04:40 +00:00
cmpilato
814bee3e4a Over in Subversion-land, I finally got around to exposing the
svn_cmdline_create_auth_baton() function via the SWIG Python
bindings.  So now use it if it's available!

* lib/vclib/svn/svn_ra.py
  (setup_client_ctx): New compatability-sensitive function.
  (RemoteSubversionRepository.open): Use setup_client_ctx() now.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2864 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-04-12 15:05:28 +00:00
cmpilato
b67254fcf2 Optimize the mapping of a single root name to a root path by avoiding
a potentially costly directory listing within the root parent paths.
This has been shown to reduce the initial ViewVC startup overhead by
400% in some situations where disk I/O is especially sluggish.

* lib/vclib/ccvs/__init__.py
  (find_root_in_parent): New function.

* lib/vclib/svn/__init__.py
  (find_root_in_parent): New function.

* lib/viewvc.py
  (find_root_in_parents): Use the new find_root_in_parent() functions
    offered by the vclib implementations rather than the more expensive
    full root expansion stuffs.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2862 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-03-20 13:15:34 +00:00
cmpilato
decb5e375b * lib/viewvc.py
Drop in some more timestamp debugging sections.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2860 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-03-18 18:38:51 +00:00
cmpilato
af996b9b49 Finish issue #487 ("Preserve Subversion symlinks in generated
tarballs") for remote Subversion repositories, too.

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.get_symlink_target): New function.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2858 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-03-04 20:23:09 +00:00
cmpilato
388c55e564 * lib/vclib/svn/svn_ra.py
(cat_to_tempfile): Renamed from temp_checkout().  Callers updated.
  (RemoteSubversionRepository.openfile): Use cat_to_tempfile() now,
    and try to head off a race condition that could leave tempfiles
    lying about.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2857 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-03-04 19:57:35 +00:00
cmpilato
ab923539dd Finish issue #487 ("Preserve Subversion symlinks in generated tarballs")
for local Subversion repositories.

* lib/vclib/svn/svn_repos.py
  (LocalSubversionRepository.get_symlink_target): New function.

* lib/viewvc.py
  (generate_tarball_header): Add the ability to generate private
    headers for long symlink names, too.
  (generate_tarball): Use the Repository object's get_symlink_target()
    function (if available) to determine whether a versioned object is a
    symlink, and use that information to preserve symlinks in
    generated tarballs.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2855 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-03-04 19:37:31 +00:00
cmpilato
701ba24454 * lib/viewvc.py
(generate_tarball_header): Indentation fixes only.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2854 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-03-04 16:52:19 +00:00
cmpilato
eaeb527802 * lib/viewvc.py
Fix spelling error ('typefrag' should be 'typeflag') throughout.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2853 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-03-04 16:51:38 +00:00
cmpilato
819915112e * templates/default/docroot/styles.css
Revert r2835.  Not liking the yellow.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2852 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-03-01 15:52:29 +00:00
cmpilato
33eeb41763 * CHANGES: Merge in 1.1.18's changes.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2851 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-02-28 19:34:22 +00:00
cmpilato
345e7ceb8d Bump the advertised latest release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2849 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-02-28 19:26:50 +00:00
cmpilato
63563517d7 * bin/make-database
Be less sloppy about what this script reports as default behavior
  around hostnames and ports.  If a hostname isn't supplied,
  "localhost" isn't strictly passed to 'mysql'; same for the port.
  And on UNIX, the lack of an explicit hostname (or an explicit
  "localhost" one) will cause 'mysql' to use a UNIX socket rather than
  a TCP/IP one, regardless of what the provided port is.  So it's not
  strictly accurate to imply that by not providing a hostname and
  port, 'make-database' will use "localhost/3306" for that
  information.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2844 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-02-26 16:51:03 +00:00
cmpilato
b8a7f32fb4 When querying the commits database, explicitly name columns in case
someone has a modified/customized database with additional or
reordered columns.

* lib/cvsdb.py
  (CheckinDatabase.CheckCommit, CheckinDatabase.PurgeRepository):
    Name columns in SELECT statement rather than using '*'.

Patch by: Grant Bremer <gbremer{__AT__}tigris.org>
          (Tweaked by me.)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2843 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-02-26 16:43:12 +00:00
cmpilato
8854a73040 * bin/make-database
Use "ENGINE=MyISAM" rather than "TYPE=MyISAM" throughout.  The
  latter syntax was deprecated in MySQL 5.0 and dropped in 5.5.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2842 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-02-26 16:15:35 +00:00
cmpilato
9b57e7d6a6 Fix issue #521 ("make-database does not allow the database port to be
specified").

* bin/make-database
  (__main__): Add a --port option and handling thereof, passing the
    value off to 'mysql'.

Patch by: Grant Bremer <gbremer{__AT__}tigris.org>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2841 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-02-25 20:51:01 +00:00
cmpilato
3edd7de4d1 Fix issue #347 ("ccvs module handling of "dead" files doesn't jive
with that of bincvs logic").

* lib/vclib/ccvs/ccvs.py
  (InfoSink.define_revision): Tweak the revision matching logic a bit
    to include branch points as valid revisions when examining branch
    tags.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2839 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-02-25 20:35:56 +00:00
cmpilato
07ac7f5e54 Mark busted ,v files with no revisions as "absent" in the rcsparse-
driven CVS backend, fixing an inconsistency between rcsparse-based and
binary-based parsing.

* lib/vclib/ccvs/ccvs.py
  (InfoSink.__init__): Init new 'saw_revision' flag.
  (InfoSink.define_revision): Set 'saw_revision'.
  (InfoSink.parse_completed): If 'saw_revision' is not set, set the
    'absent' flag.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2837 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-02-25 20:01:45 +00:00
cmpilato
41858c6f89 * templates/default/docroot/styles.css
Follow up to r2835, removing an unnecessary "!important" CSS
  declaration.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2836 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-02-22 16:56:26 +00:00
cmpilato
bbe8b42877 * templates/default/docroot/styles.css
Highlight file content lines in yellow when hovered over.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2835 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-02-22 16:48:33 +00:00
cmpilato
3d3f677b3c * templates/default/file.ezt
Reduce a bit of redundancy.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2834 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-02-22 16:44:51 +00:00
cmpilato
572554fa89 * lib/viewvc.py
(markup_stream): Strip EOL characters from the ends of marked-up
    lines.  Templates can re-add line breaks, but they can't easily
    strip them.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2832 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-02-22 16:34:10 +00:00
cmpilato
281ed5ca84 Correct a royally botched CHANGES entry.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2830 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-01-31 19:49:49 +00:00
cmpilato
bb4a748eda Fix issue #519 ("Stack trace while accessing a BDB repository if last
commit deleted a file or directory").

* lib/vclib/svn/svn_repos.py
  (_get_change_copyinfo): Only call svn_fs_copied_from() on "add" and
    "replace" change items (which might actually be copies).  This
    avoids raising an exception caused by running svn_fs_copied_from()
    on a missing (via deletion) root/path pair.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2827 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-01-29 15:57:57 +00:00
cmpilato
f48add83f7 Bump copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2820 8cb11bc2-c004-0410-86c3-e597b4017df7
2013-01-04 19:01:54 +00:00
cmpilato
b57831ade8 Fix the handling of diff options throughout.
* lib/viewvc.py
  (DiffDescription.__init__): Don't set self.diff_options.
  (DiffDescription.get_content_diff, DiffDescription.get_prop_diff):
    Rename local variable 'options' to 'diff_options', and actually
    populate *it* rather than the otherwise unused (and now removed)
    'diff_options' class variable.
  (DiffDescription._get_diff, DiffDescription._line_idiff_sidebyside,
   DiffDescription._line_idiff_unified, DiffDescription._content_fp,
   DiffDescription._prop_fp): Rename 'options' to 'diff_options'.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2818 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-25 20:21:13 +00:00
cmpilato
19818e269c * lib/viewvc.py
(view_patch): Honor the "show functions" option when generating
    patches, too.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2817 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-25 20:14:16 +00:00
cmpilato
0d1da3c79b * templates/default/include/diff_display.ezt
Show the "extra" diff info stuff, too.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2816 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-25 19:56:52 +00:00
cmpilato
d018467937 Revert r2649, as the default templates *should* support the property
diff stuff now if I recall correctly.

* conf/viewvc.conf.dist,
* lib/config.py
  Use "templates/default" now for the default templates.  Duh.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2815 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-25 19:16:18 +00:00
cmpilato
cea54da382 * CHANGES
Merge 1.1.17 changes.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2812 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-25 14:06:06 +00:00
cmpilato
6fcc2b5992 Bump most recent reported release. Again.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2811 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-25 14:05:24 +00:00
cmpilato
dcb7e17dc6 Fix issue #516 ("Regression: UnboundLocalError: local variable
'log_pagestart' referenced before assignment").

* lib/viewvc.py
  (view_log): Initialize the 'log_pagestart' variable.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2808 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-25 13:46:15 +00:00
cmpilato
e8f975475e Update link to the CHANGES file.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2807 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-24 18:50:57 +00:00
cmpilato
06910f29e3 * CHANGES
Include 1.1.16 and 1.0.13 changes, too.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2806 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-24 18:46:52 +00:00
cmpilato
64b0994f2f Bump most stable release version.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2804 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-24 18:21:47 +00:00
cmpilato
a8d3373025 Fix issue #514 (Simple file view has page title with "Annotation of:").
* templates/classic/file.ezt,
* templates/default/file.ezt
  Set the page's <title> attribute to "Annotation of ..." or "Contents
  of ...", depending on whether the output is annotated.

Patch by: John McNally <jmcnally{__AT__}collab.net>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2796 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-24 16:57:59 +00:00
cmpilato
de517ae29c Fix issue #515 ("XSS bug in diff view (CVE-2012-4533)").
* lib/viewvc.py
  (DiffSource._get_row): Pass the "extra" line information through the
    formatter code so that, at a minimum, it's HTML-escaped.

Patch by: Nicolás Alvarez <nicolas.alvarez{__AT__}gmail.com>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2792 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-24 13:26:36 +00:00
cmpilato
4a98f512f7 * conf/viewvc.conf.dist
Show the default value of 'hr_funout' as 1 (which matches the
  programmatic default).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2791 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-24 13:22:14 +00:00
cmpilato
f4945fd7d9 Oops! Fix the diff view I broke in r2784.
* lib/viewvc.py
  (view_diff): Add 'cfg' convenience variable (to avoid a stack trace
    caused by using such a thing a few lines later).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2790 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-03 14:33:38 +00:00
cmpilato
4590ebbd6b Fix issue #512 ("'Select for diffs' does not work across pages").
* lib/viewvc.py
  (view_log): Preserve the 'log_pagestart' query value when generating
    the 'select for diff' links so that clicking the link returns you to
    the same page (modulo repagination due to new commits in the race
    window ... but let's not think about that).  Also, preserve the
    'r1' query parameter when generating the paging form.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2788 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-10-03 14:22:48 +00:00
cmpilato
ace5d55f0e * bin/cgi/query.cgi,
* bin/cgi/viewvc.cgi
  Add some commented-out logic for renice-ing the ViewVC CGI process.

Inspired by:  Karl Berry <karl{__AT__}freefriends.org>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2786 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-09-05 15:52:27 +00:00
cmpilato
00feefc3dc Finish issue #510 ("Block the expensive display of binary files").
Add a new configuration option 'binary_mime_types' which accepts a
comma-delimited list of MIME content type patterns ('text/plain', or
'image/*', etc.) against which versioned file MIME types are
compared for the purposes of deciding whether to allow their display
in the 'markup', 'annotate', 'diff' and 'patch' views.

* conf/viewvc.conf.dist
  (binary_mime_types): Describe new option.

* lib/config.py
  (_force_multi_value): Add 'binary_file_types' to the list of
    multi-value options.
  (Config.set_defaults): Initialize cfg.options.binary_mime_types.

* lib/viewvc.py
  (is_binary_file_mime_type): New function.
  (get_file_view_info): Use is_binary_file_mime_type() to determine
    whether to return links to content-ful views of the input file.
  (markup_or_annotate, view_diff): Use is_binary_file_mime_type() to
    deny display of so-deemed binary files.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2784 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-09-05 12:55:19 +00:00
cmpilato
adfa50c9b4 * lib/vclib/svn/svn_ra.py
(RemoteSubversionRepository.itemlog): Only fetch lock and size
    information for files, not directories.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2781 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-22 20:22:49 +00:00
cmpilato
5e815bc101 * docs/release-notes/1.1.0.html
Update some of the warnings with notes about their subsequent
  resolutions.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2780 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-22 19:30:10 +00:00
cmpilato
ca040b2361 Merge changes from 1.1.15 release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2779 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-22 19:29:31 +00:00
cmpilato
b5d66b7afe Bump latest advertised release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2777 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-22 18:52:43 +00:00
cmpilato
1a6390d78a * templates/default/docroot/images/lock-icon.gif
New icon file.

* templates/default/directory.ezt,
* templates/default/docroot/styles.css
  Add template bits for displaying a lock-icon "overlay" for locked
  items in the directory view.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2774 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-19 20:01:39 +00:00
cmpilato
698e9db4f2 * lib/viewvc.py
(LogFormatter.get): Fix a regression introduced in 1.1.14's handling
    of log messages when not HTML-ifying them (for example, when serving
    them up via RSS).

Patch by: Christoph Sommer <christoph.sommer{__AT__}uibk.ac.at>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2771 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-19 18:45:36 +00:00
cmpilato
163f63ed15 Fix some breakage in the annotate view for remote SVN repositories.
* lib/viewvc.py
  (markup_or_annotate): Don't forget to cross copies when requesting
    the item's log.

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.itemlog): Treat 'svn_latest_log' option
    specially, as in the svn_repos case.  (Ugh.)
  (RemoteSubversionRepository.annotate): Pass 'svn_show_all_dir_logs'
    option to itemlog().  Also, upgrade to svn_client_blame2() API.
  (RemoteSubversionRepository._get_last_history_rev): Now return both
    the info-provided create_rev, and the more accurate
    last_history_rev.  Callers updated.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2770 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-19 15:26:41 +00:00
cmpilato
44ec30da8e Abstract some code into a helper function, and fix some brokenness therein.
* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository._revinfo_fetch): New.  Holds the guts of
    the revision info harvesting (plus some bugfixes thereto) from...
  (RemoteSubversionRepository._revinfo): ...this, which now calls the
    helper function.  Also, don't tuple-ize the already-tupled cache
    info.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2768 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-16 01:38:39 +00:00
cmpilato
1380dba9ba Normalize some variables before hitting the Subversion API.
* lib/vclib/svn/svn_ra.py
  (client_log): Convert incoming 'cross_copies' and 'include_changes'
    values to integers.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2767 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-16 01:36:11 +00:00
cmpilato
6533b4fc7c Optimize revision info fetches for remote SVN repositories to avoid
unnecessary (and somewhat expensive) work.

* lib/vclib/svn/svn_ra.py
  (client_log): Add 'include_changes' parameter, pass to the
    Subversion log APIs.  Callers updated.
  (_revinfo): Was _revinfo_raw().  Add 'include_changed_paths'
    parameter.  Now handles the revinfo cache, only fetches changed
    paths when required, and bails out early of authz checks when
    possible.  All internal callers of revinfo() have been updated to
    use this interface instead.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2765 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-16 01:13:25 +00:00
cmpilato
6964b067e6 Fix a couple of correctness/performance regressions in the remote SVN
annotate view recently introduced.

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.annotate): Pass 'svn_cross_copies'
    option to itemlog() so that annotation history isn't unnaturally
    truncated.
  (RemoteSubversionRepository._blame_cb): Only consult the revinfo
    cache when authz checks are required.  This improves the speed of
    the operation when universal read access is granted to the user.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2763 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-16 00:51:25 +00:00
cmpilato
fee21df5d7 Finish, I believe, issue #353 ("Remote Subversion repositories not
fully honoring authz rules").  In doing so, this makes the svn_ra
module the most accurate it has ever been, hopefully without too
terribly much extra cost.

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.listdir): No longer check access here.
    That's handled down in _get_dirents() now.
  (RemoteSubversionRepository.dirlogs): Don't check dirent access here.
    Just ensure that the returned entries are those which are
    represented in the (filtered) set return from _get_dirents().
    Also, replace the revision metadata stored on each dirent with
    values from the revinfo cache (which does authz sanitizing).
  (RemoteSubversionRepository._get_dirents): Do authz-checking of
    dirents here, and use _get_last_history_rev() to populate a useful
    created_rev.
  (RemoteSubversionRepository._get_last_history_rev): Because
    Subversion's RA layer doesn't consider copy events when
    determining an item's last-committed-rev, compensate for this with
    a bounded log operation which does.  This brings created-rev
    parity with the svn_repos module (at the cost of the extra RA
    work, but with the benefit of, you know, accuracy.
  (RemoteSubversionRepository._revinfo_raw): Leave a TODO about a
    future optimization.
  (RemoteSubversionRepository._log_cb): Set found_unreadable when
    sanitizing an unreadable copyfrom path, too.
  (RemoteSubversionRepository.created_rev): Now just a thin wrapper
    around the beefed-up _get_last_history_rev() function.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2760 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-15 23:34:01 +00:00
cmpilato
ada79bc6e7 * lib/vclib/svn/svn_ra.py
(LogCollector.add_log): Allow the access_check_func to be None (and
    avoid trying to call it in that case).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2759 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-15 23:07:22 +00:00
cmpilato
01ebe77beb Fix a security issue: When a readable path is copied from an
unreadable one, Subversion will obscure the fact that the operation
was a copy (by removing copyfrom info) and will deem the log message
for the revision in which the copy occurred to be unreadable.  ViewVC
was only doing the former bit; now it does the latter, too.

* lib/vclib/svn/svn_repos.py
  (LocalSubversionRepository._get_changed_paths): Set found_unreadable
    when we have to hide a copyfrom path, too.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2758 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-15 23:05:47 +00:00
cmpilato
87b574b3ee For issue #353, check path access in the annotation view code for
remote SVN repositories.

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.annotate): Examine revision logs to
    determine the legal annotation range we are allowed to request,
    and use the revinfo cache to strip sensitive author/data info from
    the annotation data.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2757 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-15 02:17:55 +00:00
cmpilato
fc7d9b1da4 For issue #353 ("Remote Subversion repositories not fully honoring
authz rules"):

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.get_locations): Check authz on the
    result of a get_locations lookup (being sure to use the original
    path in the error message, if any).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2756 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-15 02:11:12 +00:00
cmpilato
4cc840b54a For issue #353, check path access in the code that backs the revision
log view for remote SVN repositories.

* lib/vclib/svn/svn_ra.py
  (LogCollector.__init__): Add 'access_check_func' parameter, stashed
    away as a member variable.  Initialize 'done' variable to False.
  (LogCollector.add_log): Use access_check_func() to test for access.
    If access is denied, set 'done' to True and ignore future
    invocations.
  (RemoteSubversionRepository.itemlog): Add _access_checker inner
    function, passed as a callback to LogCollector.__init__().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2755 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-13 21:57:38 +00:00
cmpilato
3df47b625e * notes/releases.txt
Add some URLs for the announce@ and freecode postings.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2753 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-12 13:02:34 +00:00
cmpilato
836e643dc5 * CHANGES: Merge in the 1.1.14 changes.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2752 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-12 12:57:12 +00:00
cmpilato
ca52fe277d Bump latest release version number.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2750 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-12 12:54:04 +00:00
cmpilato
bfe2cbe5ca Fix issue #246 ("Add support for issue tracker links in commit-log
viewer").

NOTE: There are some limitations here, most prominantly that commas
can't be used in the regular expressions which define replacements,
and that only match groupings 0-9 can be used in the replacement
format string.

* conf/viewvc.conf.dist
  (custom_log_formatting): New configuration option.

* lib/config.py
  (Config._force_multi_value, Config.set_defaults): Add handling of
    new 'custom_log_formatting' option.

* lib/viewvc.py
  (ViewVCHtmlFormatter.format_custom_url): New formatter callback.
  (LogFormatter.get): Register the new formatter callback for rules
    found in the 'custom_log_formatting' option value.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2746 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-06-12 11:11:18 +00:00
cmpilato
91654688a1 * templates/default/file.ezt
Fix some markup validation issues.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2743 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-04-20 21:04:14 +00:00
cmpilato
9d75ed19f8 Finish issue #506 ("Log message tokenization results could be reused
for better performance").

* lib/viewvc.py
  Replace uses of format_log() throughout with calls to LogFormatter()
  (to get a formatter "lf") then lf.get() (to get the formatted log
  string).  Also...
  (format_log): Remove as unused.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2741 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-04-17 15:29:27 +00:00
cmpilato
f65b03fcdc For issue #506 ("Log message tokenization results could be reused for
better performance"), make the first step of two in trying to avoid
parsing log messages twice when once will suffice.

* lib/viewvc.py
  (ViewVCHtmlFormatterTokens): New class for generating HTML-formatted
    text from a set of provided ViewVCHtmlFormatter tokens.
  (ViewVCHtmlFormatter.get_result): Track renamed function, and defer
    the work of the text generation to the token object's get_result()
    method.
  (ViewVCHtmlFormatter.tokenize_text): Renamed from _tokenize_text(),
    and now return a ViewVCHtmlFormatterTokens object.
  (LogFormatter): New class for encapsulating the log formatting logic.
  (format_log): Make a wrapper around LogFormatter for now.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2740 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-04-17 15:25:56 +00:00
cmpilato
60b80bd3b2 Fix issue #505 ("Username case normalization breaks when browsing
anonymously").

* lib/vcauth/svnauthz/__init__.py
  (ViewVCAuthorizer.__init__): Don't try to convert a None username to
    lower- or upper-case.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2738 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-03-28 14:15:51 +00:00
cmpilato
272ae0fa37 Remove erroneous CHANGES entry.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2736 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-02-07 21:10:18 +00:00
cmpilato
23714979e4 Follow-up to r2512, trying to, you know, get that change right this
time.

* lib/vclib/svn/__init__.py
  (_canonicalize_path): New helper function.
  (canonicalize_rootpath): Rework this to perform the URL -> absolute
    path conversion any time it can, not only when using really old
    Subversion versions.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2735 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-02-07 21:10:04 +00:00
cmpilato
1b63870590 Follow-up to r2731, trying to ensure that users with pre-1.4 Subversion
won't hit AttributeError's on account of svn_path_canonicalize() not 
being exposed through Subversion's Python bindings.

* lib/vclib/svn/svn_repos.py
  (_canonicalize_path): New helper function.
  (_rootpath2url): Use _canonicalize_path() instead of
    core.svn_path_canonicalize().

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository._geturl): Use (imported)
    _canonicalize_path() instead of core.svn_path_canonicalize().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2733 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-02-01 19:45:35 +00:00
cmpilato
1296106171 Fix issue #504 ("annotate view fails on filenames with colon (:)
characters in their names"), another in a long string of annotate view
brokennesses.  (Is that word?)  This time, the problem was a disparity
between Python's urllib encoding and what Subversion deems canonical.

* lib/vclib/svn/svn_repos.py
  (_rootpath2url): Canonicalize URLs for use with Subversion.

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository._geturl): Canonicalize URLs for use with
    Subversion.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2731 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-02-01 16:24:29 +00:00
cmpilato
3297f45285 * lib/vclib/svn/__init__.py
(canonicalize_rootpath): Add a TODO comment.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2730 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-01-31 22:37:32 +00:00
cmpilato
91d1b75856 * notes/releases.txt
Minor tweaks/corrections to the release procedure.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2729 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-01-23 18:58:02 +00:00
cmpilato
8f39d274f5 Merge 1.1.13's CHANGES.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2727 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-01-23 18:52:01 +00:00
cmpilato
86449bdec7 Bump pointer to latest version.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2726 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-01-23 18:51:45 +00:00
cmpilato
7043120d2c * tools/bump-copyright-years
(update_license): Remove.
  (bump_years): Print reminder about amending the change history
    section of the LICENSE.html file.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2722 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-01-23 18:31:20 +00:00
cmpilato
ad0c0dd5fa * tools/bump-copyright-years
(replace_end_year): Remove debugging print statements, and simplify code.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2721 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-01-23 17:57:10 +00:00
cmpilato
9e9b82218c Bump copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2720 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-01-23 17:52:47 +00:00
cmpilato
85df9e6ba4 * tools/bump-copyright-years
New tool for bumping copyright years.  I'm tired of trying to
  micromanage these things.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2719 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-01-23 17:51:58 +00:00
cmpilato
8fc1166f2d Bump copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2716 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-01-23 16:42:03 +00:00
cmpilato
25ab342bbf * lib/vclib/svn/svn_repos.py
(_rootpath2url): Get the absolute path before splitting off the
    drive, not afterward.  Otherwise, (some) drive letter will just get
    tacked back onto the path!  As we now verify elsewhere that
    rootpaths aren't relative, we needn't worry that .splitdrive() will
    return a relative rootpath.

Suggested by: Jens Peters <jp7677{__AT__}gmail.com>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2714 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-01-06 21:34:58 +00:00
cmpilato
ccb7f2e3f1 Ensure that we are dealing with absolute repository paths. Who knows
what kind of chaos may ensue otherwise.

* conf/viewvc.conf.dist
  Note that paths should be absolute filesystem paths.

* lib/vclib/svn/__init__.py
  (canonicalize_rootpath, expand_root_parent): Assert that local
    repository paths are absolute.

* lib/vclib/ccvs/__init__.py
  (canonicalize_rootpath, expand_root_parent): Assert that local
    repository paths are absolute.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2713 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-01-05 15:35:39 +00:00
cmpilato
0cd9f664d6 * INSTALL
Per issue #474, describe how to setup static icon/stylesheet
  delivery, warning about alias ordering.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2712 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-01-04 17:19:27 +00:00
cmpilato
6fe390a642 Move a customization out of ezt.py to eliminate unnecessary deltas
against the upstream version of this module.

* lib/common.py
  (TemplateData): Moved here...

* lib/ezt.py
  ...from here.

* lib/query.py,
* lib/viewvc.py
  Import 'TemplateData' from 'common' now, and update references to this
  relocated class.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2711 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-01-04 15:35:12 +00:00
cmpilato
5d68a5f883 * lib/vclib/svn/svn_repos.py
(_rootpath2url): "drive" already carries the colon, so don't append one.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2709 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-01-03 20:07:30 +00:00
cmpilato
6418278d55 * lib/vclib/svn/svn_repos.py
(_rootpath2url): Try a different approach that should actually
    handle spaces in the "in-repos" path, too, and maybe (if I'm super
    lucky) also work on Windows.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2707 8cb11bc2-c004-0410-86c3-e597b4017df7
2012-01-03 15:18:21 +00:00
cmpilato
1dd1a21537 * lib/viewvc.py
(): Stop importing the pygments stuff at the module-global scope,
    and go back to doing so...
  (markup_stream): ...here.
  (markup_or_annotate): No longer consider access to Pygments when
    making the first pass at colorizing -- if we don't have it,
    markup_stream() will fail quickly and we can take the second
    (non-colorizing) pass.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2702 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-12-12 20:01:30 +00:00
cmpilato
06a3feec90 Reintegrate the 'issue-495-dev' branch into the trunk. This
reintroduces the issue #495 feature ("Syntax highlight/colorize
scripts without extensions") while building much more fault tolerance
into the system.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2699 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-12-06 14:22:48 +00:00
cmpilato
a03cd82de5 On the 'issue-495-dev' branch, make what I think are some pretty
useful improvements to the syntax coloration and annotation codepaths.
First, settle on the file contents as fetched via repos.openfile() as
the canonical source of such.  But also, allow any exceptions thrown
while colorizing those file contents to trigger a second attempt
without colorization enabled.  This should allow for non-error-ful
display of binary files which lack both an extension and VC content
type hint (those are treated by default as text files).

* lib/viewvc.py
  (markup_stream): Add docstring.  Replace 'fp' parameter with
    'file_lines' parameter.  Add 'colorize' parameter.  No longer try
    to munge 'blame_data' -- expect that callers have done that.  Lose
    first_line tracking stuff, as fetching the first line of the file
    is no longer destructive.  Always use 'file_lines' as the source
    of file contents; never the text attached to the 'blame-data'.
  (markup_or_annotate): Rework this to do more of the cheap work of
    annotating and markup up so that markup_stream() can be called
    more than once if necessary -- once to attempt colorization, and
    again without that feature if the first pass fails.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/issue-495-dev@2698 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-12-05 21:11:29 +00:00
cmpilato
094024a0ec On the 'issue-495-dev' branch:
* lib/vclib/__init__.py
  (Repository.annotate): Rewrite docstring for clarity.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/issue-495-dev@2697 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-12-05 20:06:11 +00:00
cmpilato
56e645ecb8 ### NOTE FROM THE FUTURE: This commit probably broke the ###
###  "annotate view without syntax coloration" codepath.   ###

On the 'issue-495-dev' branch:  Let vclib API consumers request that
annotation data come with or without the associated text.

* lib/vclib/__init__.py
  (Repository.annotate): Add optional 'include_text' parameter.

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.annotate): Add 'include_text' parameter
    and, if False, have the annotation callback drop the text on the floor.

* lib/vclib/svn/svn_repos.py
  (BlameSource.__init__): Add 'include_text' param; squirrel away the value.
  (BlameSource._blame_cb): Don't keep text we're asked not to keep.
  (LocalSubversionRepository.annotate): Add 'include_text' parameter,
    passed to BlameSource.__init__.

* lib/vclib/ccvs/bincvs.py
  (BinCVSRepository.annotate): Add 'include_text' parameter, passed to
    blame.BlameSource().

* lib/vclib/ccvs/ccvs.py
  (CCVSRepository.annotate): Add 'include_text' parameter, passed to
    blame.BlameSource().

* lib/vclib/ccvs/blame.py
  (BlameSource.__init__): Add 'include_text' param; squirrel away the value.
  (BlameSource.__getitem__): Don't keep text we're asked not to keep.

* lib/blame.py
  (HTMLBlameSource.__init__): Update call to repos.annotate().



git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/issue-495-dev@2696 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-12-05 19:58:38 +00:00
cmpilato
2f722f39b9 On the 'issue-495-dev' branch:
* lib/viewvc.py
  (markup_stream): Was markup_stream_pygments().  Caller changed.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/issue-495-dev@2695 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-12-05 18:31:55 +00:00
cmpilato
402dfd831f On the 'issue-495-dev' branch:
* lib/viewvc.py
  (markup_stream_pygments): Remove level of indentation made
    unnecessary by r2693.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/issue-495-dev@2694 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-12-05 18:30:50 +00:00
cmpilato
738d17f71f On the 'issue-495-dev' branch:
* lib/viewvc.py
  (): Try to import the pygments code at the global scope instead of...
  (markup_stream_pygments): ...here.  Add/move some comments, too.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/issue-495-dev@2693 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-12-05 18:28:05 +00:00
cmpilato
fdc0bcd420 On the issue-495-dev branch: Add BRANCH-README.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/issue-495-dev@2692 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-12-02 19:49:45 +00:00
cmpilato
db032720a8 On the 'issue-495-dev' branch: Re-apply the most recently committed
(then reverted) bits of the issue #495 work.

* lib/viewvc.py (markup_stream_pygments)

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/issue-495-dev@2691 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-12-02 19:48:24 +00:00
cmpilato
c9256effc4 Create a branch for issue #495 development.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/issue-495-dev@2690 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-12-02 19:38:59 +00:00
cmpilato
b42a4a0915 * lib/viewvc.py
(markup_or_annotate): Don't show annotation warnings for markup
    views of images.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2688 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-12-02 18:35:01 +00:00
cmpilato
d2275afb6d * lib/viewvc.py
(markup_stream_pygments): Re-make the semantic changes from r2680,
    which were (I believe) good ones, even if the lexer guessing stuff
    hasn't yet work out entirely.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2686 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-12-02 18:18:23 +00:00
cmpilato
5db50e6bcc Revert r2657, r2680, and r2681, effectively removing support for
Pygments' lexer guessing functionality (closing the REOPENED bug issue
#501, and necessitating that feature issue #495 be itself REOPENED).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2684 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-12-02 17:51:41 +00:00
cmpilato
7b6ecd807c * templates/classic/file.ezt
Say "Content type" rather than "File MIME type".


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2683 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-12-02 16:10:57 +00:00
cmpilato
e8a0caeef5 *** THIS REVISION WAS REVERTED IN r2684 ***
For issue #501 ("Stack trace when trying to 'view' binary files"):

* lib/viewvc.py
  (markup_stream_pygments): On second thought, allow guessing to
    happen on non-None MIME types iff they appear to be text-y.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2681 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-11-29 15:33:20 +00:00
cmpilato
dfeb3b5d90 *** THIS REVISION WAS REVERTED IN r2684 ***
For issue #501 ("Stack trace when trying to 'view' binary files"):

* lib/viewvc.py
  (markup_stream_pygments): Rework the Pygments lexer-choosing logic a
    bit.  First, don't try any of it when syntax highlighting is
    disabled.  Secondly, don't guess at a lexer if we know the file's
    MIME type and have already failed to get a matching lexer.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2680 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-11-29 15:25:00 +00:00
cmpilato
5943e01304 * lib/viewvc.py
(markup_or_annotate): Pass 'mime_type' to common_template_data() so
    it can properly set the 'prefer_markup' bit.  Otherwise, it will
    guess without out svn:mime-type at its disposal.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2679 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-11-29 15:17:59 +00:00
cmpilato
6a8d5debd6 Template-y changes for file views.
* templates/default/markup.ezt
  Delete as unused.

* templates/default/include/fileview.ezt
  Delete, after merging contents into...

* templates/default/file.ezt
  ...here.  Also, port the [hide_binary_garbage] stuff from the classic
  templates.

* templates/default/docroot/styles.css
  (.vc_notice): New class.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2678 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-11-29 14:59:49 +00:00
cmpilato
537c59c516 Port a change from the 'classic' templates to the new 'default' ones.
* templates/default/query_results.ezt
  Display warning text when query results are superficially truncated.

* templates/default/docroot/styles.css
  (.vc_warning): New style.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2676 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-11-18 20:31:59 +00:00
cmpilato
92b7b65707 Fix annotate views of files in Subversion repository whose paths
contain non-URI-safe characters (spaces, non-ASCII stuff, etc.)

* lib/vclib/svn/svn_repos.py
  (_rootpath2url): Use urllib.pathname2url to URL-encode the path
    portion of the URL we are building.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2674 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-11-14 21:28:46 +00:00
cmpilato
46e17662d5 Fix issue #499 ("svndbadmin fails on deleted files").
* bin/svndbadmin
  (SvnRev.__init__): Update the logic used to calculate change types
    and diff objects to no longer assume that deleted paths have None
    for their change.path.  (Subversion's 1.7 bindings always populate
    change.path.)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2671 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-11-14 20:14:14 +00:00
cmpilato
7ab960262a Merge in 1.1.12's CHANGES.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2670 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-11-03 14:45:17 +00:00
cmpilato
6f47cef67d Add a step to the release procedure.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2668 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-11-03 14:43:57 +00:00
cmpilato
a592e3b0bc Bump latest version number.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2666 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-11-03 14:39:40 +00:00
cmpilato
94d9f0ef49 * templates/default/log.ezt,
* templates/default/include/pathrev_form.ezt,
* templates/default/directory.ezt,
* templates/default/diff.ezt,
* templates/default/docroot/styles.css
  Still more template stylistic tweaks.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2662 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-11-01 18:45:27 +00:00
cmpilato
b566f297b3 * templates/default/include/diff_display.ezt
Track recent rename of diffs.display_as to diffs.diff_block_format.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2661 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-11-01 14:14:40 +00:00
cmpilato
a6be4da978 * templates/default/log.ezt,
* templates/default/docroot/styles.css
  Layout/style tweaks to the new default template set.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2660 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-11-01 14:12:58 +00:00
cmpilato
8cdccc1ea5 Fix a bug which prevented certain directory diff displays.
* lib/viewvc.py
  (diff_side_item): Pass the option to repos.itemlog() which says to
    include directory logs even for revisions in which the directory
    itself was not explicitly modified (props changed).

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2659 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-11-01 13:40:01 +00:00
cmpilato
ccb53d164e *** THIS REVISION WAS REVERTED IN r2684 ***
Finish issue #495 ("Syntax highlight/colorize scripts without
extensions").

* lib/viewvc.py
  (markup_stream_pygments): Failing all else, use the Pygments
    guess_lexer() function to guess a file's content type from the
    first line of its text.  (Most of this patch is compensation for
    the first that if this heuristic codepath is traversed, we've eaten
    a line of text from the file object that we don't expect to have
    been eaten.

Patch by: Chris Mayo <cjmayo{__AT__}tigris.org>
          (Tweaked by me.)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2657 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-31 21:39:33 +00:00
stilor
441da057cc * lib/viewvc.py
(DiffSource): Do not switch to flush state. Such switch causes changes
  to be displayed as removal and readdition.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2656 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-28 20:37:01 +00:00
cmpilato
a69597e29c Finish issue #470 ("No links to repository root logs").
* lib/viewvc.py
  (view_roots): Generate a log_href -- the revision log for the root
    directory of the repository -- where it makes sense to do so.

* templates/classic/roots.ezt,
* templates/default/roots.ezt
  Markup the last-modified-revision as a link to the log view where we can.

* docs/template-authoring-guide.html
  Note the additional data dictionary item.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2653 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-28 19:24:37 +00:00
cmpilato
43f001ef25 * templates/default/file.ezt,
* templates/default/log.ezt,
* templates/default/docroot/styles.css,
  More markup changes to the default templates.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2652 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-27 21:14:02 +00:00
cmpilato
4341dab5b7 * templates/default/revision.ezt,
* templates/default/log.ezt,
* templates/default/graph.ezt,
* templates/default/diff.ezt,
* templates/default/include/diff_display.ezt
  Take a stab at updating the new default templates to handle the
  property diff stuff.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2651 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-27 20:59:38 +00:00
stilor
6e81b5eb1e * docs/template-authoring-guide.html
* templates/classic/include/diff_display.ezt
* lib/viewvc.py
  Rename 'display_as' to 'diff_block_format', as discussed on ML.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2650 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-27 18:20:06 +00:00
cmpilato
dc1763b37b * lib/config.py,
* conf/viewvc.conf.dist
  Use the "classic" templates until the "default" ones can be updated
  to reflect recent improvements (such as the property-diff stuff).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2649 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-27 18:10:37 +00:00
cmpilato
65137920a8 Begin the work of making the 'newvc' contributed template set into the
new default for ViewVC 1.2.  We'll keep the old templates around as a
"classic" option.

* lib/config.py,
* conf/viewvc.conf.dist
  (Config.set_defaults): Set cfg.options.template_dir to
    "templates/default", and make the matching edit in the pristine
    configuration file.

* templates/:
  Now just a container for...

* templates/classic/,
* templates/classic/*:
  ...the old default templates (which were 'templates' and 'templates/*'.

* templates/default/,
  templates/default/*:
  ...and the new default, copied from the 'templates-contrib/1.1' area.




git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2647 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-27 18:05:14 +00:00
cmpilato
00d96de446 * CHANGES: Note the addition of prop-diff support.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2646 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-27 14:53:49 +00:00
cmpilato
6008bc6a7b Reintegrate the ^/branches/property-diff branch.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2645 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-27 14:51:43 +00:00
cmpilato
753d2d5320 On the 'property-diff' branch:
* docs/template-authoring-guide.html
  Update the template authoring guide in light of the changes I made
  in r2643.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2644 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-26 19:18:20 +00:00
cmpilato
2b5e7b51a0 On the 'property-diff' branch: rename the 'diff' template data
dictionary item to 'diffs' for consistency with other multi-value
items.  Yes, I know it makes the template usage itself weird
... "diffs.changes" instead of "diff.changes", but...

* lib/viewvc.py
  (view_diff): Store the desc.changes in the 'diffs' data dictionary
    item, not the 'diff' item.

* templates/diff.ezt
* templates/include/diff_display.ezt
  Replace uses of 'diff' with 'diffs'.  Selectively, of course.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2643 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-26 19:11:41 +00:00
stilor
6453447c63 * docs/template-authoring-guide.html
(top level) Introduce formatting rules for  4th and 5th levels of variables.
  (diff.ezt) Update for the changes on the property-diff branch. Describe
  missing parts (intraline diffs, patch_href). Fix some typos and copy-paste
  errors.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2642 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-24 20:05:37 +00:00
cmpilato
5e3c53e592 Sync the 'property-diff' branch with outstanding trunk changes.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2641 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-21 14:47:51 +00:00
cmpilato
24cbe623e7 * docs/template-authoring-guide.html
Update to refer to ViewVC 1.2, not 1.0.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2640 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-21 14:47:02 +00:00
cmpilato
48a59d30ad * docs/release-notes/1.2.0.html
New stub file.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2639 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-21 14:46:35 +00:00
cmpilato
605e66e56f * docs/release-notes/1.1.0.html
Add some helpful markup comments.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2638 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-21 14:46:15 +00:00
cmpilato
661e7fc569 * notes/releases.txt
Try to document the creation of new release branches (though it's been a
  while since I've done that, so this is all subject to my imperfect memory.)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2637 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-21 14:42:33 +00:00
cmpilato
055e1dad53 * docs/upgrading-howto.html
Add stub section for "from 1.1" section.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2635 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-20 19:48:55 +00:00
cmpilato
51f194d4ad * docs/upgrading-howto.html
Dial back the color intensity a bit.  Sheesh.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2634 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-20 19:48:00 +00:00
cmpilato
3f19b50a08 * docs/upgrading-howto.html
Tweak the "from 0.8" section for a bit of consistency with other sections.
  (As if anyone is still running 0.8.)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2633 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-20 19:47:14 +00:00
cmpilato
5e22b37a56 Sync the property-diff branch with the latest trunk changes. (Yawn.)
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2632 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-19 13:20:57 +00:00
stilor
1e14eccbe0 * diff_display.ezt
(anchor): Replace <a name="xxx"/> with <p id="xxx"/> for XHTML compliance.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2629 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-17 19:13:12 +00:00
stilor
4bf50b31f7 * viewvc.py
Follow existing conventions on indenting function arguments/hash initializers
  carried over to the next line.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2628 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-17 19:06:27 +00:00
stilor
68496ebc9f * diff_display.ezt
* viewvc.py
  Expand tabs to spaces, as per review.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2627 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-17 18:51:52 +00:00
stilor
a789c13698 * viewvc.py
(Request.run_viewvc): Select diff view for directories if r1/r2 arguments
  are provided.
  (view_revision): Generate a link to diff view on directories if there was
  a change in properties.

* log.ezt
  (revision links): Generate 'diff to previous' and 'diff to selected' for
  directories as well as files. Check for URL, not revision when determining
  if 'diff to previous' link should be created (for consistency with 'diff
  to selected')


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2626 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-16 19:02:32 +00:00
stilor
44a6fe7465 * viewvc.py
(view_diff): Pass anchor locations to the diff template.

* diff_display.ezt
  (top-level): Generate anchors.

* revision.ezt
  (path links): Use anchors to point to content and property parts of the diff.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2625 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-16 18:50:08 +00:00
stilor
90a1d6cae2 * viewvc.py
(DiffDescription): Add support for property diffs.
  (diff_side_item): Store properties hash in the side items.
  (view_diff): Generate property diffs.

* diff_display.ezt
  (headers): Indicate the property being diffed, if applicable.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2624 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-16 08:12:51 +00:00
stilor
4fe882972a * viewvc.py:
(view_diff): Remove unused local variables.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2623 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-16 07:58:18 +00:00
stilor
f57be6e516 * viewvc.py
(DiffDescription): New class. Move the diff format selection and processing
  to this new class. Split the processing into "preparation" and actual diff.

The ideas behind this new class are:
1. It will accumulate the diff "blocks". Currently, it will handle content and
properties. In the future, it can be easily reused to accumulate diffs for
recursive ("revision") diff.
2. It separates the diff method from the selection of content to be diffed.
We have two content inputs (content, properties), four formats (raw, traditional
side-by-side, intraline side-by-side, intraline unified). The former two expect
a stream (fp), the latter two expect array of lines. This class makes each of
these chunks separate from each other.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2622 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-16 07:29:23 +00:00
stilor
c819b3a3fc * diff_display.ezt
(raw): Gracefully handle the case where there are no changes (output
  "No changes" instead of not displaying anything).

* viewvc.py
  (diff_parse_headers): Detect if there were no input from diff stream,
  report RCSDIFF_NO_CHANGES in this case.
  (view_diff): If binary/empty changes are detected, relay that information
  to the template.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2621 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-16 07:06:51 +00:00
stilor
682ff6c9b9 * viewvc.py
(diff_side_item): Do not return log_entry, it is not used. Rename
  "bare" and "links" items to more descriptive "prop" and "content".


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2620 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-16 06:48:47 +00:00
stilor
988f5b535e * viewvc.py
(view_diff): In preparation for factoring out the "differ" code, make view_diff
  always pass the differences as 'changes' array/stream. The format is now selected
  via new 'display_as' argumnet.

* diff_display.ezt
  (all formats): Accommodate changes in viewvc.py



git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2619 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-16 06:25:38 +00:00
stilor
4780023396 * diff_display.ezt
(all formats): Remove the use of empty <h3> as spacer, instead add margin-top on tables.
  (sidebyside, unified): Specify column widths. Otherwise, files with narrow content
  are displayed with line number columns occupying 50% of the screen.
  (unified): Remove cut-n-paste "width" attribute specification.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2618 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-16 06:09:42 +00:00
stilor
63227ef2a1 * diff_display.ezt
Remove definitions which have been moved to start of the file.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2617 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-16 05:57:39 +00:00
stilor
6253fec4fb * diff_display.ezt
(left_header/right_header): Define common left/right side descriptions,
  use them in all diff output formats (adding them to raw and unified, which
  didn't have headers before)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2616 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-16 05:55:29 +00:00
stilor
7cdab259b8 * viewvc.py
(is_undisplayable): New function to check if property name/value
  can be displayed. Use this function in current file/dir/revision views.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2615 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-16 05:33:25 +00:00
stilor
d1427e6639 * diff.ezt
(legend): Remove references to revisions (revisions may be the same, e.g.
  if diffing same revision on different branches). There are detailed references
  in the headers.
  (legend): Mention that colors designate not only affected lines, but also
  characters (if intraline diffs are enabled).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2614 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-16 04:48:01 +00:00
stilor
04329a707b * viewvc.py
(view_diff): Make diff an iterable (sequence); later property changes will be
  added to the sequence. Pass hide_legend, left_rev, right_rev outside of the
  diff[] array to untie diff.ezt from include/diff_display.ezt. Rename format
  to diff_format for consistency with template name.

* diff.ezt
  Same, plus small fixes in legend: capitalize first letter in 'changed',
  refer to revision as such, not as 'v.XXX' - such references are not used
  anywhere else.
  


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2613 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-06 05:37:56 +00:00
stilor
888f7ee302 * viewvc.py
(view_diff): Restore try-except block. It is unused for SVN,
  but still used for CVS.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2612 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-06 05:07:49 +00:00
cmpilato
205484b0f2 * INSTALL
Fix pointer to Subversion project website.

Found by:  Daniel Shahaf <d.s@daniel.shahaf.name>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2609 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-04 14:59:08 +00:00
stilor
7466b03e7c * viewvc.py
(view_diff): Factor out common code preparing left/right item information into a new
  function, diff_side_item.
  (diff_side_item): New function.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2607 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-01 19:25:00 +00:00
stilor
737b5d2b23 * viewvc.py
(view_diff): Remove try-except block, exceptions are now handled in
    setup_diff with more specific error messages. Merge the 'if fp'
    block with the preceding conditional - which is the only way fp
    is set to non-None.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2606 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-01 07:10:10 +00:00
stilor
c6775f5b89 * common.py
New file to house common definitions; _item and _RCSDIFF_*
  for now. Remove local definitions in the rest of modules.

* idiff.py
  (sidebyside, unified): Return _RCSDIFF_NO_CHANGES type if
  the generator failed to yield anything else.
  (sidebyside): Add type attribute to the returned tuple so
  that template can check the type.

* diff_display.ezt
  (top-level): Define messages to be used if diffs cannot be
  displayed. Use the definitions in all non-raw displays.
  (sidebyside,unified): Handle _RCSDIFF_IS_BINARY and
  _RCSDIFF_NO_CHANGES; the former is not returned yet - will
  be passed to the template once properties are diffed.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2605 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-01 06:33:22 +00:00
stilor
eba17bcbd7 * viewvc.py
(view_diff): Encapsulate into a single _item parts that would
  be repeated when multiple "diffable" items will be passed to diff.ezt.
  At that time, diff will be changed to a sequence.

* diff_display.ezt, diff.ezt
  Prefix those repeatable parts with 'diff'.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2604 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-01 05:35:15 +00:00
stilor
3e5836cdb4 * diff.ezt
Split the actual diff-formatting part into a separate includable template.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2603 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-01 04:50:35 +00:00
stilor
35544ecbef Create a branch for property diffs integration (issue 383).
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/property-diff@2602 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-10-01 04:26:15 +00:00
cmpilato
a6c9d3ac49 Loop until receiving a definitive answer to the interactive overwrite
query, rather than croaking on an empty response.

* viewvc-install
  (install_file): If raw_input() return an empty string, re-ask the
    question.

Patch by: Alexey Neyman <stilor@att.net>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2599 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-09-30 19:09:38 +00:00
cmpilato
f44c50a5ed Fix issue #494 ("allow override config from in mod_python"). This
commit allows environmental overrides to trump programmatically
passed-in configuration paths.

* INSTALL
  Mention the VIEWVC_CONF_PATHNAME override environment variable.

* lib/viewvc.py
  (load_config): Document this function and the order in which it
    searches for a configuration path.  Use server.getenv() instead of
    os.environ.get() where we can so that environmental overrides work
    in mod_python.

Patch by: Alon Bar-Lev <alon.barlev@gmail.com>
          (Tweaked by me.)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2597 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-09-30 15:45:39 +00:00
cmpilato
b96b8d4003 Revert r2595.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2596 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-09-30 15:15:11 +00:00
cmpilato
814e0d4d6c *** This commit was reverted in r2596 ***
For issue #494 ("allow override config from in mod_python"), use
server.getenv() instead of os.environ.get() to look for the special
VIEWVC_CONF_PATHNAME environment variable.

* INSTALL
  Mention the VIEWVC_CONF_PATHNAME override environment variable.

* lib/viewvc.py
  (load_config): Use server.getenv() instead of os.environ.get().

Patch by: Alon Bar-Lev <alon.barlev@gmail.com>
          (Tweaked by me.)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2595 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-09-30 14:59:28 +00:00
cmpilato
1ae87bb8b6 * conf/viewvc.conf.dist
Note the importance of the MIME type maps for syntax coloration, and
  point folks to the 'mime_types_files' option.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2593 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-09-14 17:53:23 +00:00
cmpilato
ec2a0a3f3b Finish issue #491 ("Explain in viewvc.conf.dist the views (used for
allowed_views, etc.)").

* conf/viewvc.conf.dist
  (allowed_views): Add descriptions of the various views.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2591 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-09-07 17:42:59 +00:00
cmpilato
ac75dc9651 * bin/svndbadmin
Fix a minor buglet in the usage message.

Reported by: Jean-Yves Avenard <jyavenard@gmail.com>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2588 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-07-01 17:57:10 +00:00
cmpilato
59f55fecb6 (More) gracefully handle some errorful input conditions.
* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository._getrev): Re-raise all exceptions as
    InvalidRevision exceptions.

* lib/vclib/svn/svn_repos.py
  (LocalSubversionRepository._getrev): Re-raise all exceptions as
    InvalidRevision exceptions.

Found by:  Daniel Shahaf <d.s@daniel.shahaf.name>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2586 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-06-23 15:25:07 +00:00
cmpilato
7da44377c5 Fix issue #488 ("Allow 'rrNNN' formatting for Subversion revision
specifiers (with multiple 'r')").

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository._getrev): Accept multiple leading 'r's
    in revision specifiers.

* lib/vclib/svn/svn_repos.py
  (LocalSubversionRepository._getrev): Accept multiple leading 'r's
    in revision specifiers.

Patch by:  Daniel Shahaf <d.s@daniel.shahaf.name>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2584 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-06-23 15:09:11 +00:00
cmpilato
9228cc9a89 * CHANGES
Fix a mistaken issue reference.

* INSTALL
  Add a step allowing access to your ViewVC install directory, and delay the
  Apache restart by a step.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2582 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-06-14 13:29:09 +00:00
cmpilato
c355d1ce3e Fix issue #486 ("OperationError raised when trying to do a glob search").
Add code to workaround the fact that in Python 2.6,
fnmatch.translate() stopped returning strings that ended with '$'
(which work fine as MySQL regular expressions) and started instead
returning strings that ended with '\Z(?ms)' (which... don't).

* lib/cvsdb.py
  (CheckinDatabase.SQLQueryListString): If the returned regexp ends
    with '\Z(?ms)', replace those characters with a single '$'

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2580 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-06-06 19:57:51 +00:00
cmpilato
47c12cb194 Fix issue #485 ("Patch view hiding path details").
* lib/viewvc.py
  (diff_parse_headers): Add 'path1' and 'path2' parameters, and use
    those paths in the returned header lines.
  (view_patch, view_diff): Pass paths into diff_parse_headers() now.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2577 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-27 18:58:59 +00:00
cmpilato
c9f9c96db2 * www/index.html
Update latest revision to 1.1.11.

* CHANGES
  Copy 1.1.11's changes into this file.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2574 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-17 12:38:13 +00:00
cmpilato
18a52bd5ce More copyright updates.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2570 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-17 12:17:35 +00:00
cmpilato
02bd4d70db Update some copyright notices.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2569 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-17 12:02:28 +00:00
cmpilato
aac6bbafb9 Add '--help' option to standalone.py.
* bin/standalone.py
  (usage, badusage): New functions.
  (main): Separate the option parsing from the option validation.  Add
    support for a '--help' option.  On bad input, now print a suggestion
    to run the script with '--help' for usage hints.

Patch concept by: Prabhu Gnana Sundar <prabhugs@collab.net>
                  (Heavily, heavily tweaked by me.)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2565 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-12 18:34:12 +00:00
cmpilato
90d35a6fc1 * bin/standalone.py
(main): Revert (mostly) a wording change made in r2562.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2563 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-12 13:47:04 +00:00
cmpilato
91995a4241 * bin/standalone.py
(main): Rework the usage message for conciseness, and fix an old typo, too.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2562 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-12 13:39:12 +00:00
cmpilato
eef47fbb1f * bin/standalone.py
(main): Use a pristine Options() object when printing the usage
    message (so the stated default values of options aren't affected
    by what the user provided).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2561 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-12 13:15:32 +00:00
cmpilato
63ddc213ae * bin/standalone.py
(main): Restore alphabetical order of options listed in the usage message.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2560 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-12 13:10:36 +00:00
cmpilato
8eeac0cd59 * bin/standalone.py
(main): Switch to sequence syntax to prevent future headache:
    '-h' in ('--help') returns True, which is not what we expect.
    '-h' in ['--help'] returns False, which is what we want.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2559 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-12 13:09:27 +00:00
cmpilato
5132017538 Fix issue #444 ("ViewVC stumbles over revisionless ,v files when
sticky tag is specified").

* lib/vclib/ccvs/bincvs.py
  (_get_logs): Only try to skip the "rest of the file" if there's
    reason to believe there's a "rest of the file".  While here,
    ensure that the 'tag' variable is defined in all cases (though it
    shouldn't matter).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2557 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-05-05 14:36:27 +00:00
cmpilato
a00c6ee5cb Fix issue #483 ("Error skipping newphrases when parsing RCS data").
* lib/vclib/ccvs/rcsparse/common.py
  (_Parser.parse_rcs_admin): Chew up newphrases found while parsing
    the admin block.

Patch by: Giovanni Pellicciotta <giovanni.pellicciotta@anubex.com>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2555 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-04-21 16:03:31 +00:00
cmpilato
868300daf4 Fix spelling errors introduced in r2551.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2553 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-04-20 15:01:17 +00:00
cmpilato
61bcf03fcd Fix (to the degree that I believe is reasonable at this time) issue
#433 ("queries return only partial results").  When a database query
is artificially limited by the 'row_limit' setting, inform the user
that the returned data is incomplete.

* lib/cvsdb.py
  (CheckinDatabase.CreateSQLQueryString): Add 'detect_leftover'
    parameter, used internally to check for a reached query limit.
  (CheckinDatabase.RunQuery): Update call to CreateSQLQueryString(),
    and check for leftover query response rows.  If any are found, set
    the appropriate flag on the query object.
  (CheckinDatabaseQuery.__init__): Set initial values for new
    'executed' and 'limit_reached' members.
  (CheckinDatabaseQuery.SetExecuted,
   CheckinDatabaseQuery.SetLimitReached,
   CheckinDatabaseQuery.GetLimitReached,
   CheckinDatabaseQuery.GetCommitList): New functions.

* lib/viewvc.py
  (view_query): Use query.GetCommitList() now instead of poking into
    the query object directly.  Also, check query.GetLimitReached(),
    reporting the findings through the data dictionary (via a new
    'row_limit_reached' item) to the templates.

* lib/query.py
  (run_query): Use query.GetCommitList() now instead of poking into
    the query object directly.  Now return a 2-tuple of commits and a
    limit-reached flag.
  (main): Update expectations of run_query() call.  Populate
    'row_limit_reached' data dictionary item.

* templates/query_results.ezt,
* templates/query.ezt
  Display a warning if the query results are incomplete.

* templates/docroot/styles.css
  (.vc_warning): New style definition.

* docs/template-authoring-guide.html
  Document the new 'row_limit_reached' template item.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2551 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-04-20 14:50:40 +00:00
cmpilato
1e4c3f92f6 Move a bunch of duplicated statements into a helper function.
While here, add notes to the 'row_limit' and 'rss_row_limit'
configuration option descriptions.

* lib/cvsdb.py
  (CheckinDatabase.GetCommitsTable): New helper.
  (CheckinDatabase.AddCommit, CheckinDatabase.CreateSQLQueryString,
   CheckinDatabase.CheckCommit, CheckinDatabase.sql_delete): Use new
    GetCommitsTable() helper instead of hard-coding the version-specific
    selection of the commits table.

* conf/viewvc.conf.dist
  (row_limit, rss_row_limit): Make it clear what exactly is getting
    limited here.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2550 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-04-20 14:05:16 +00:00
cmpilato
df71275a13 Try to make some sense of the various CVSdb-related limitation
mechanisms, namely by removing the largely redundant "global" limit
and allowing the per-query row limit (which already exist, too) to do
its work.

While here, remove a poorly conceived (but thankfully unhighlighted)
mechanism for overriding the administrative limit on database rows
which was accessible via URL CGI params.

* lib/viewvc.py
  (_legal_params): Remove 'limit' as a legal parameter.
  (view_query): No longer allow an undocumented URL parameter to
    override the admin-declared SQL row limit.  That should have never
    been allowed!

* lib/cvsdb.py
  (CheckinDatabase.__init__): Remove 'row_limit' parameter and
    associated self._row_limit member.
  (CheckinDatabase.CreateSQLQueryString): No longer fuss with
    self._row_limit.  Let the individual query carry the row limit.
  (ConnectDatabase): Update call to CheckinDatabase().

* lib/query.py
  (form_to_cvsdb_query): Now accept 'cfg' parameter, and set the
    query's row limit from the configured defaults.
  (run_query): Update call to form_to_cvsdb_query().

* docs/url-reference.html
  Remove reference to the 'limit' parameter.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2547 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-04-19 20:40:04 +00:00
cmpilato
4818a56012 Fix (I think...) issue #479 ("annotate a file, which uses
CVS-keywords").  This changes causes the checkout of CVS file
contents -- when used as part of the markup/annotate logic -- to not
expand keywords.  This helps it to be consistent with the results of
the annotate information query.

* lib/vclib/__init__.py,
* lib/vclib/svn/svn_ra.py,
* lib/vclib/svn/svn_repos.py
* lib/vclib/ccvs/ccvs.py
  (openfile): Add 'options' parameter (unused).  Callers updated.

* lib/vclib/ccvs/bincvs.py
  (openfile): Add 'options' parameter, and look for a 'cvs_oldkeywords'
    option to govern the use of -kkv or -ko in the 'co' command.
    Callers updated.

* lib/viewvc.py
  (markup_or_annotate): Pass 'cvs_oldkeywords' option to repos.openfile().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2545 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-04-01 16:59:11 +00:00
cmpilato
f12cef277c Fix issue #477 ("Large log messages trigger excessive memory
consumption").

* lib/viewvc.py
  (ViewVCHtmlFormatter._tokenize_text): Switch to a line-based
    approach.  This provides a *vast* improvement in performance and
    memory usage, especially for large log messages with many
    mark-up-able regions.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2543 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-04-01 14:37:24 +00:00
cmpilato
0ca7fac7fb Finish issue #478 ("Client-facing unhandled exceptions, traceback
dumped") by raising a cleaner error message when asked to display a
"checkout" of a non-file.

* lib/viewvc.py
  (view_checkout): If the target isn't a file, raise a
    ViewVCException().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2541 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-03-29 16:35:54 +00:00
cmpilato
35a55c317e * lib/vclib/ccvs/blame.py
(CVSParser.extract_revision): Fix a typo (aka "syntax error").

Found by: Cristian Tibirna <tibirna{__AT__}kde.org>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2540 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-03-28 17:46:28 +00:00
cmpilato
963a3a2094 * bin/standalone.py
(main): Fix broken option handling: -d expected an argument, -c
    didn't and was doubly associated with both --config-file and
    --htpasswd-file.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2538 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-03-15 20:40:23 +00:00
cmpilato
5ce98d04d6 Bump latest version statement and links, and copy CHANGES from 1.1.10 release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2536 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-03-15 16:36:35 +00:00
cmpilato
49957ea54b Hopefully, fix issue #475 ("regression: required authorization to
root") and issue #476 ("Stack trace for some users if last commit
deleted a file or folder") by preventing ViewVC from trying to look up
the path type of a deleted path at an invalid location.

* lib/vclib/svn/svn_repos.py
  (LocalSubversionRepository._gettype): New helper function.
  (LocalSubversionRepository.itemtype): Now use _gettype() helper.
  (_get_change_copyinfo): New helper.
  (_simple_auth_check): Rework this function to definitively resolve
    the path type of paths it passes through the authz system,
    handling the complication of determining the path of a now-deleted
    path by consulting its last location prior to deletion.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2531 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-03-11 20:17:21 +00:00
cmpilato
bd3323410a Add some helpful URLs to the release instructions.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2529 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-18 20:01:13 +00:00
cmpilato
fce93313e5 Post-release twiddling.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2527 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-18 19:55:28 +00:00
cmpilato
76dae127d6 Update copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2524 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-18 19:24:59 +00:00
cmpilato
2f8af5fdb7 * conf/viewvc.conf.dist (log_pagesextra): Set value to match defaults.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2522 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-18 18:27:58 +00:00
cmpilato
c3dc73d840 Followup to r2517, for issue #457.
* templates/roots.ezt
  Also show the last author, and mark only the "Name" header as the
  sort choice.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2519 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-18 16:56:16 +00:00
cmpilato
0fe6e33643 Finish issue #457 ("Display repository metadata (last-commit stuff) in
roots view").

* lib/viewvc.py
  (view_roots): Include revision metadata in the data dictionary.
  (list_roots): If configured to do so, calculate some last-modified
    metadata for Subversion roots.

* lib/config.py
  (Config.set_defaults): Set default value for new show_roots_lastmod
    option.

* conf/viewvc.conf.dist
  (show_roots_lastmod): New option.

* templates/roots.ezt
  Show some roots metadata if configured to do so.

* docs/template-authoring-guide.html
  Document new 'roots' view data dictionary items.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2517 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-18 15:11:01 +00:00
cmpilato
f7df7da7f0 Finish issue #455 ("ViewVC 1.1.x missing URL parsing in file contents
view").

* lib/viewvc.py
  (_re_rewrite_escaped_url): New compiled regexp.
  (markup_escaped_urls): New helper function.
  (markup_stream_pygments): Use markup_escaped_urls() to wrap URLs in
    <a> tags, something Pygments won't do for us.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2514 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-17 16:05:46 +00:00
cmpilato
bc2ab5c093 * lib/vclib/svn/__init__.py
(canonicalize_rootpath): Per the thought found in issue #446
    ("Specifying repo location using file:// prefix in svn_roots leads
    to lack of hyperlinks on revision view"), convert file:/// and
    file://localhost/ URLs into local paths.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2512 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-16 20:27:33 +00:00
cmpilato
2e69660725 Make what should be some decent performance improvements in the
Subversion revision metadata harvesting logic.

* lib/vclib/svn/svn_repos.py
  (LocalSubversionRepository._revinfo): Split this into two logical
    codepaths, one that needs changed-path information along with the
    revision metadata, one which does not.  (Because if we don't need
    it, there are faster ways to get what we *do* need.)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2509 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-11 21:33:28 +00:00
cmpilato
51fe3f9d1c * lib/vclib/svn/svn_repos.py
(_get_history, _log_helper): Move these into...
  (LocalSubversionRepository._get_history,
   LocalSubversionRepository._log_helper): ...here.  Update callers.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2507 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-11 21:16:13 +00:00
cmpilato
77bf7001a6 * lib/vcauth/svnauthz/__init__.py
(ViewVCAuthorizer._get_paths_for_root): Trap and return a cleaned-up
    error when the authzfile isn't parse-able.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2505 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-11 16:55:11 +00:00
cmpilato
2dfe9c55f0 Clarify that Python 3.x is not yet supported.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2502 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-02-07 14:47:22 +00:00
cmpilato
c39a091b83 * lib/vclib/svn/svn_ra.py
(client_log): Check for the correct exception.

Reported by: Phil Jeary <Phil.Jeary@dovetailservices.com>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2500 8cb11bc2-c004-0410-86c3-e597b4017df7
2011-01-04 19:22:32 +00:00
cmpilato
5678e463ad Make the number of "extra pages" of log output configuration. (An old
TODO item I'd forgotten about.)

* lib/config.py
  (Config.set_defaults): Set cfg.options.log_pagesextra default value.

* lib/viewvc.py
  (EXTRA_PAGES): Removed.
  (paging_sws): Add 'extra_pages' parameter, used instead of static
    EXTRA_PAGES variable.
  (view_log): Update call to paging_sws().  Replace uses of static
    EXTRA_PAGES with cfg.options.log_pagesextra.

* conf/viewvc.conf.dist
  (log_pagesextra): New configuration item.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2498 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-12-09 17:10:58 +00:00
cmpilato
e8ba12d66d Fix issue 425 ("Authorization subsystem needs some optimization").
Give the 'vcauth' subsystem a way to make universal access
determinations, which can seriously improve performance in situations
where a user has universal read access to a repository.

* lib/vcauth/__init__.py
  (GenericViewVCAuthorizer.check_universal_access): New skeletal function.
  (ViewVCAuthorizer.check_universal_access): New function.

* lib/vcauth/svnauthz/__init__.py (ViewVCAuthorizer.check_universal_access),
* lib/vcauth/forbidden/__init__.py (ViewVCAuthorizer.check_universal_access),
* lib/vcauth/forbiddenre/__init__.py (ViewVCAuthorizer.check_universal_access)
  New functions.

* lib/vclib/ccvs/bincvs.py
  (BaseCVSRepository.open): New function.

* lib/vclib/svn/svn_repos.py
  (LocalSubversionRepository.open): Now check for universal read access.

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.open): Now check for universal read access.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2496 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-12-09 16:10:04 +00:00
mhagger
31d16b42fe Provide better error info for invalid CVS timestamps.
Patch by: Craig Leres <leres@tigris.org>
Expanded by: me

The original version of this patch was submitted to cvs2svn issue #141:
http://cvs2svn.tigris.org/issues/show_bug.cgi?id=141

* lib/vclib/ccvs/rcsparse/common.py
  (_Parser._parse_rcs_tree_entry): If there is an error when parsing a
  CVS timestamp, include the revision number in the exception message.
  The calendar.timegm() function is not very picky, but it does emit an
  error if the month number is invalid.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2495 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-12-09 08:37:18 +00:00
cmpilato
31bf260508 Cruft removal. Don't tempt folks to configure the path to their
Subversion client, as ViewVC no longer uses that information.

* lib/vclib/svn/svn_repos.py
  (LocalSubversionRepository.__init__): Don't look for svn client path
    in the 'utilities' dictionary.  We don't use it anyway.

* lib/config.py
  (Config.set_defaults): Don't populate utilities.svn any more.

* conf/viewvc.conf.dist
  (utilities/svn): Remove as unused.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2493 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-12-06 19:08:20 +00:00
cmpilato
4c965a521d Add some notes about issue #439.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2491 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-12-03 20:50:43 +00:00
cmpilato
ce4f396604 * lib/vclib/ccvs/bincvs.py
(_path_join): Fix one of my more pathetic coding errors.  (How do
    you lose track of the proper valid variable name in a two-line
    function.  Honestly...)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2490 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-12-03 17:25:34 +00:00
cmpilato
0c38626f18 * CHANGES
Add 1.1.8 changes.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2489 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-12-02 21:37:04 +00:00
cmpilato
6ac853c1f4 Update website to reflect latest release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2487 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-12-02 20:58:13 +00:00
cmpilato
beb2205b64 Minor tweak to the release process notes.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2483 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-12-02 20:37:36 +00:00
cmpilato
060ef83f0e Issue #472 ("Using view=markup on folder causes errors").
* lib/viewvc.py
  (view_markup, view_annotate): Raise a more graceful error message
    when asked for markup or annotate view on a non-file.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2480 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-11-30 21:11:19 +00:00
cmpilato
de95d36720 * bin/standalone.py
(has_crypt, _check_passwd): If 'crypt' isn't available, look for
    'fcrypt' and use it instead.
  (main): Always show --htpasswd-file option, but raise an informative
    error if someone tries to use it when there's no cryptographic support.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2478 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-11-30 18:19:28 +00:00
cmpilato
f0e2fa721a * lib/config.py
(Config._is_allowed_section, Config._is_allowed_override): Lose
    unused 'parser' parameter.  Callers updated.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2476 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-11-30 08:49:20 +00:00
cmpilato
f3629550dd * lib/viewvc.py
(view_directory): Add some more debug timers.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2475 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-11-24 21:34:16 +00:00
cmpilato
5f50e82bda Fix issue #471 ("standalone.py won't start on Windows: no module named
'crypt'") by making htpasswd file support optional (based on the
availability of the 'crypt' module).

* bin/standalone.py
  (): Conditionally import 'crypt' and define _check_passwd() helper function.
  (ViewVCHTTPRequestHandler.validate_password): Use _check_passwd() now.
  (main): Conditionally built accepted options list and usage string based
    on whether 'crypt' is available.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2473 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-11-16 16:02:46 +00:00
cmpilato
400eb13d76 Fix issue #467 (I think...) by not claiming a particular content
length when compression would skew that.

* lib/viewvc.py
  (get_writeready_server_file): Add optional 'content_length'
    parameter, and the code to handle it.
  (view_doc): Update call to get_writeready_server_file().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2471 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-10-05 15:01:41 +00:00
cmpilato
c123490436 * CHANGES
Copy in the 1.1.7 changes.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2469 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-09 18:50:06 +00:00
cmpilato
ce5a303c02 Bump latest release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2467 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-09 18:47:55 +00:00
cmpilato
40df73e111 Bump some copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2463 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-09 18:19:03 +00:00
cmpilato
239844c040 * conf/viewvc.conf.dist
(viewvc_base_url): Add another example showing a relative ViewVC
    base URL.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2460 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-09 15:23:35 +00:00
cmpilato
d6a4d294fb Fix the query script's WSGI and FastCGI deployments.
* lib/sapi.py
  (WsgiServer.FieldStorage): Don't pass self._headers to
    cgi.FieldStorage() -- that parameter is for *input* headers, and
    self._headers is a collection of output headers.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2459 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-09 14:10:35 +00:00
cmpilato
1d33308f90 Allow users to tell the query script where ViewVC is located while
still generating the same defaults as before.

* conf/viewvc.conf.dist
  (query, query.viewvc_base_url): New section and value.

* lib/config.py
  (_base_sections): Add 'query'.
  (Config.set_defaults): Set default value for cfg.query.viewvc_base_url.

* bin/asp/query.asp,
* bin/cgi/query.cgi,
* bin/mod_python/query.py,
* bin/wsgi/query.fcgi,
* bin/wsgi/query.wsgi,
  Ask the configuration for the location of ViewVC before falling back
  to old defaults.

* templates/query.ezt
  Don't reference unset variables.  Do test the log message for
  empty-ness, dropping a non-breaking space in place where it is.

* templates/include/footer.ezt
  Don't reference unset variables.  

* lib/query.py
  (build_commit): Allow ob.log to be empty.  Don't generate ViewVC
    links if we don't have a base URL for ViewVC.
  (main): Calculate docroot in light of possible absent viewvc_link.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2458 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-09 13:40:42 +00:00
cmpilato
2012320bfc * lib/vclib/ccvs/ccvs.py
Lose more explicit invocations of 'string' module functions (which
  no worky because we aren't importing that module any more).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2457 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-09 11:44:09 +00:00
cmpilato
e2433ea8e9 * lib/viewvc.py
(_re_rewrite_svnrevref): Wrap the regexp with word boundaries.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2455 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-08 18:26:15 +00:00
cmpilato
1d8e32110c * lib/vclib/svn/svn_repos.py
(_split_revprops): Special-case the handling of empty input.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2454 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-08 18:11:28 +00:00
cmpilato
b6f0d36c72 * notes/releases.txt
Tweak the release procedure to include pegging the externals
  definition which pulls in the 'templates-contrib' subdirectory.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2452 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-08 17:03:30 +00:00
cmpilato
42f1c80e74 * CHANGES
The FastCGI support is now coming in 1.1.x.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2448 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-07 19:20:50 +00:00
cmpilato
8360e07a97 Stop importing the 'popen2' module -- we aren't using it.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2446 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-07 19:09:07 +00:00
cmpilato
a0b87889dc * CHANGES: Note recent FastCGI support addition.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2445 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-07 15:50:24 +00:00
cmpilato
8b78e4d0b3 Finish issue #464: Add support for FastCGI (using a WSGI end-around).
* bin/wsgi/viewvc.fcgi,
* bin/wsgi/query.fcgi
  New scripts.

* INSTALL
  Note the additional configuration/deployment option.

* viewvc-install
  Install the .fcgi files, too.

Patch by: Mark A. Ziesemer <ziesemer{_AT_}tigris.org>
          (Tweaked minorly by me.)

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2444 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-07 15:47:53 +00:00
cmpilato
42208db4aa Typo fix. Patch by Mark A. Ziesemer <ziesemer{_AT_}tigris.org>
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2442 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-07 15:41:00 +00:00
cmpilato
ed975ad336 Typo fix. Patch by Mark A. Ziesemer <ziesemer{_AT_}tigris.org>
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2441 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-07 15:40:36 +00:00
cmpilato
6b7c9d066f Finish issue #113: Support auto-markup of revision references.
* lib/viewvc.py
  (_re_rewrite_svnrevref): New regular expression.
  (ViewVCHtmlFormatter.format_svnrevref): New.
  (format_log): Accept 'request' parameter instead of 'cfg' (which can
    be obtained via the request).  For Subversion repositories,
    register a formatter which marks up revision references as links
    to the revision view.
  (): Update callers of format_log().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2439 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-07 15:17:32 +00:00
cmpilato
fb5ca5c1d9 * CHANGES
Note new minimum Python version.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2438 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-03 16:50:33 +00:00
cmpilato
a5df176395 Wow. Drop a "general code cleanup" kind of bomb on the codebase. All
of this is aimed at not paying the maintenance price of supporting
Python versions prior to 2.4 any longer, plus a little bit of just
getting dead code out of the way.

* lib/compat.py
  Remove as unused.

* bin/cvsdbadmin,
* bin/loginfo-handler,
* bin/make-database,
* bin/svndbadmin,
* lib/accept.py,
* lib/blame.py,
* lib/cvsdb.py,
* lib/popen.py,
* lib/query.py,
* lib/sapi.py,
* lib/vcauth/forbidden/__init__.py
* lib/vcauth/forbiddenre/__init__.py,
* lib/vcauth/svnauthz/__init__.py,
* lib/vclib/__init__.py,
* lib/vclib/ccvs/blame.py,
* lib/win32popen.py,
* tests/timelog.py
  Replace explicit import and use of the 'string' module with newer constructs.

* bin/standalone.py,
* lib/viewvc.py 
  No longer use 'compat' module.  Replace explicit import and use of
  the 'string' module with newer constructs.

* lib/dbi.py
  Use calender.timegm() instead of compat.timegm().

* lib/vcauth/__init__.py
  Lose unused module imports.

* lib/config.py,
  Replace explicit import and use of the 'string' module with newer
  constructs where possible.  Lose old ConfigParser patch-up code for
  Python 1.5.1.

* lib/vclib/ccvs/ccvs.py
  Replace explicit import and use of the 'string' module with newer
  constructs where possible.  Import _path_join() from bincvs, and use
  it instead of a bunch of copy-and-pasted string join() statements
  throughout.

* lib/vclib/ccvs/__init__.py
  (cvs_strptime): Moved here from the 'compat' module.

* lib/vclib/ccvs/bincvs.py
  (): No longer use 'compat' module.  Replace explicit import and use
    of the 'string' module with newer constructs.
  (_path_join): New, used now instead of a bunch of copy-and-pasted
    string join() statements throughout.

* viewvc-install
  Don't use the 'compat' module any more.

Also, so some rearranging of non-critical bits.

* misc/:              New directory.
* misc/py2html.py:    Moved from 'lib/py2html.py'.
* misc/PyFontify.py:  Moved from 'lib/PyFontify.py'.
* misc/elemx/:        Moved from 'elemx/'.
* misc/tparse/:       Moved from 'tparse/'.
* tools/make-release
  Omit 'misc' directory from releases, too.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2437 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-03 16:49:52 +00:00
cmpilato
a86bac818e * lib/vclib/svn/svn_repos.py
(BlameSource.__init__): Use client.create_context() instead of
    client.ctx_t() to avoid "NULL proxy object pool" error.

(I should have done this with the changes in r2421, but overlooked it,
I guess.)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2435 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-03 16:18:55 +00:00
cmpilato
07ba91e7d9 * lib/vclib/svn/svn_repos.py,
* lib/vclib/svn/svn_ra.py
  Remove explicit import and use of 'string' module.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2434 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-02 19:46:14 +00:00
cmpilato
41bc85c437 * viewvc-install
Purge explicit import and use of the 'string' module.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2433 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-02 19:43:35 +00:00
cmpilato
0e0c657341 * INSTALL
Python 2.4 is now the required Python for trunk.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2432 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-02 19:39:52 +00:00
cmpilato
6b35895704 Parse the "; charset=..." bit out of Subversion's svn:mime-type
property, and use it to inform Pygments as to the file's encoding in
the markup and annotate views (while still providing that information
to the user agent in the checkout view).

* lib/viewvc.py
  (parse_mime_type): New helper function.
  (calculate_mime_type): Now also return the encoding as possibly
    parsed from the svn:mime-type property.  Callers updated.
  (get_writeready_server_file): Add 'encoding' parameter.
  (markup_stream_pygments): Add 'encoding' parameter which, if
    provided, becomes the encoding passed to Pygments.
  (view_checkout): Pass the encoding as/if provided by calculate_mime_type()
    to get_writeready_server_file().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2430 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-08-25 20:09:39 +00:00
cmpilato
3f5c86fe85 ViewVC's options are defined and described to be lower-case, with the
only exception being the freeform [vhost] section values and key-value
file stuffs.  In those places, user-defined case could be helpful, and
is certainly not documented as broken.  So allow it, per issue #466.

* lib/config.py
  (Config.load_config, Config.load_kv_files): Override
    ConfigParser.optionxform() to avoid case normalization of option names.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2428 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-08-23 20:25:58 +00:00
cmpilato
8c2b5cd63a * lib/viewvc.py
(ViewVCHtmlFormatter): Was HtmlFormatter.  Which, uh, has the same
    name as an object imported from Pygments.
  (format_log): Track renamed class.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2426 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-08-19 04:18:56 +00:00
cmpilato
ab1f329994 Empower the revision view for remote Subversion repositories to
display node kind information and, by extension, links to the markup
and diff views for files.

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository._revinfo_raw): Tweak _log_cb() inner
    function to make use of the svn_log_changed_path2_t information
    where available.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2424 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-08-13 17:48:31 +00:00
cmpilato
6444e57831 Build the Subversion client context object correctly (thus avoiding a
weird NULL proxy object pool error).

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.open): Use svn_client_create_context()
    instead of svn_client_ctx_t().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2421 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-08-13 16:17:39 +00:00
cmpilato
6e5703686a Note the removal of standalone.py's GUI mode.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2416 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-07-15 21:02:01 +00:00
cmpilato
f548912f9a Finish issue #49 - authentication support for standalone.py.
* bin/standalone.py
  (Options.htpasswd_file): New variable.
  (AuthenticationException): New.
  (ViewVCHTTPRequestHandler.handle_request): Handle AuthenticationException.
  (ViewVCHTTPRequestHandler.validate_password): New.
  (ViewVCHTTPRequestHandler.run_viewvc): If htpasswd authentication is
    enabled, then complain about missing authn creds, and validated
    any presented creds.
  (main): Present and handle the new --htpasswd-file option.  Also, do
    some rudimentary validation of --htpasswd-file and --config-file values.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2414 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-07-15 20:50:54 +00:00
cmpilato
8f9eaf9e26 * bin/standalone.py
(main): Don't accept the -g option.  (This is leftover from a
    previous change.)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2413 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-07-15 20:31:17 +00:00
cmpilato
9ce6a651c7 More improvements to standalone.py.
* bin/standalone.py
  (NotViewVCLocationException): New exception.
  (ViewVCHTTPRequestHandler.do_GET, ViewVCHTTPRequestHandler.do_POST):
    Now just thin wrappers around...
  (ViewVCHTTPRequestHandler.handle_request): ...this new function.
  (ViewVCHTTPRequestHandler.is_viewvc): Allow for the case where the
    script alias is empty (a server root deployment).
  (ViewVCHTTPRequestHandler.redirect): Remove as unused (the code's
    been merged into handle_request()).
  (ViewVCHTTPRequestHandler.run_viewvc): Do the is_viewvc() check here
    now.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2411 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-07-15 20:22:36 +00:00
cmpilato
28b4383a7b Remove the GUI mode from standalone.py. Great idea when the tool was
simpler, but I've not done it justice in terms of upkeep.

* bin/standalone.py
  (__author__, __date__, __version__, __credits__): Removed in favor of a
    a simple header comment.
  (Options.start_gui): Removed this member variable.
  (nogui, gui): Removed.
  (main): Was 'cli'.  Remove all option handling for, and usage
    references to, GUI mode.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2409 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-07-15 19:06:09 +00:00
cmpilato
e3042df5a3 * bin/standalone.py
(Options): Minor formatting and noop logic changes.
  (ViewVCHTTPServer): Was ViewVC_Server; move to module scope.
  (ViewVCHTTPRequestHandler): Was ViewVC_Handler; move to module scope.
  (serve): Track class renames.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2408 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-07-15 18:55:23 +00:00
cmpilato
26522f7f71 * bin/standalone.py
Reformat this file for consistency with other bits of ViewVC.  There
  *should* be no meaningful logic changes in this commit.  (If there
  are, it's probably a mistake.)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2407 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-07-15 18:43:10 +00:00
cmpilato
ff990c90b5 Record change for previous commit.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2406 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-17 20:51:56 +00:00
cmpilato
5a87b383e9 Finish issue #441: Allow "rNNN" formatting for Subversion revision specifiers.
* lib/vclib/svn/svn_repos.py (LocalSubversionRepository._getrev),
* lib/vclib/svn/svn_ra.py (RemoteSubversionRepository._getrev):
  Now accept revision strings that begin with 'r'.

Patch by: Daniel Shahaf <d.s{__AT__}daniel.shahaf.name>
          (Tweaked by me.)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2405 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-17 20:43:28 +00:00
cmpilato
f17e5a76a2 Fix a bug which prevented 'standalone.py -r REPOS' from being used
without a configuration file.

* lib/config.py
  (Config.get_authorizer_and_params_hack): Make sure to always return
    a 2-tuple.  Callers will be expecting that, ya know?

Reported by: Daniel Shahaf <d.s{__AT__}daniel.shahaf.name>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2403 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-17 20:06:59 +00:00
cmpilato
10d460902d Finish issue #453 by teaching ViewVC to display all displayable
Subversion revision properties.

NOTE: The svn_ra logic attempts to do the right thing when
      pre-Subversion 1.5 libraries are install, but I haven't had the
      chance to actually test this out myself.

* templates/revision.ezt
  Include the props.ezt property handler template fragment for use
  with revision props.  Also, minor markup change to a header.

* templates/docroot/styles.css
  Lose some unnecessary stylation.
 
* lib/viewvc.py
  (get_itemprops): Lose unused variable has_binary_props.
  (view_revision): Handle new return value from repos.revinfo(),
    processing extra revision props similarly to the way that file/dir
    props are processed and passing them to the template data
    dictionary.

* lib/vclib/svn/svn_ra.py
  Import _split_revprops() from svn_repos.
  (client_log): New compatibility wrapper.
  (add_log): Reformat as an svn_log_entry_receiver_t callback.
  (RemoteSubversionRepository.dirlogs, _date_from_rev): Track changes
    to self.revinfo().
  (RemoteSubversionRepository.itemlog): Now use client_log().
  (RemoteSubversionRepository._revinfo_raw): Now use client_log() and
    return revprops dict, too.
  (_log_cb): Reformat as an svn_log_entry_receiver_t callback.

* lib/vclib/svn/svn_repos.py
  (_split_revprops): New helper.
  (_log_helper, LocalSubversionRepository.dirlogs, _date_from_rev):
    Track changes to repos._revinfo().
  (_revinfo): Use _split_revprops(), and now return revprops, too.
  (_revinfo_helper): Now return revprops dict, too.
  (_date_from_rev): 

* lib/vclib/__init__.py
  (Repository.revinfo): Update docstring to indicate that this
    interface now returns a revprops dictionary, too.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2401 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-15 15:18:48 +00:00
cmpilato
c6f65cb422 Offer a little more help to folks trying to configure the root_parents
option.

* conf/viewvc.conf.dist
  (root_parents): Rewrite the documentation for this to be more clear
    and to note the valid root type strings.
  
* lib/viewvc.py
  (Request.run_viewvc, expand_root_parents): Make some error strings
    provide more helpful information.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2399 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-03 19:42:33 +00:00
cmpilato
f90d575dd2 Oops. Forgot that direct SVN access requires authn.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2398 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-02 14:49:01 +00:00
cmpilato
bcb28885a9 i can haz logo?
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2397 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-02 14:47:43 +00:00
cmpilato
60c2e59707 Trade broken link for working one.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2396 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-02 14:44:31 +00:00
cmpilato
90e5df36c9 Minor process and verbiage tweak.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2393 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-02 14:37:39 +00:00
cmpilato
29cba5c197 Remove now-unused Announcements link.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2392 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-02 14:25:18 +00:00
cmpilato
b60b4148ba Merge in CHANGES from 1.0.12 and 1.1.6.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2391 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-02 14:20:46 +00:00
cmpilato
0df74987cc Bump latest version.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2390 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-02 14:19:03 +00:00
cmpilato
bf31982901 Shorten the update/copy instructions.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2381 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-06-02 12:50:08 +00:00
cmpilato
bee9ac95be Fix issue #452 - Unable to purge data from query database for
non-existent repository.

* bin/svndbadmin
  (main): Do repository existence checking here, like the corresponding
    code in cvsdbadmin does.  (In fact, structure this function like that
    corresponding cvsdbadmin code.)
  (__main__): No longer do existence checks here.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2379 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-05-20 19:41:33 +00:00
cmpilato
9e2ee8277b Fix issue #451 - ViewVC RSS feed does not correctly escape contents of
<title>.

* templates/rss.ezt
  Apply the necessary formatting for RSS feed title and description
  elements.  Too bad so many readers have developed their own
  individual ideas about presentation of this under-documented format.

(See also r2376.)

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2377 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-05-20 19:10:06 +00:00
cmpilato
b07b83d252 Teach the EZT library to handle nested [format] blocks rather than its
current only-use-the-most-recently-noticed formatter approach.

* lib/ezt.py
  (Template._cmd_format): Rename 'printer' parameter to 'formatter'.
  (_print_formatted): New helper function.
  (_write_value): Now pop/restore the whole stack of formatters, and
    use _print_formatted() to do the real output writing.
  (Context.__init__): Rename 'printers' member to 'formatters'.
    Consumers updated.
  (_raw_formatter, _html_formatter, _uri_formatter): Renamed from
    _raw_printer(), _html_printer(), and _uri_printer() respectively.
    Consumers updated.
  (_xml_formatter): New.
  (_formatters): Renamed from _printers.  Consumers updated.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2376 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-05-20 19:06:11 +00:00
cmpilato
aa3f355ec2 Fix issue #449 - RSS feed returned with no mime type set
* lib/viewvc.py
  (generate_page): Actually pass the content_type to
    get_writeready_server_file().

Patch by: Tom Throckmorton <throck{_AT_}tigris.org>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2374 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-05-20 15:06:44 +00:00
cmpilato
a04e0a3297 Optimizations for rcsparse.
* lib/vclib/ccvs/rcsparse/default.py
  (_TokenStream): Convert token_term into a frozenset if the Python
    version supports such.
  (_TokenStream.get): Remove unnecessary buffer length calculations.

Patch by: Brian Harring <ferringb{_AT_}tigris.org>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2372 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-05-20 14:56:08 +00:00
cmpilato
b922b3604d Fix issue #454 - AttributeError exception trying to escape non-string input.
* lib/sapi.py
  (escape): Ensure that the input is string-ified before doing string
    transformations on it.

Patch by: Michael Henry <drmikehenry{__AT__}tigris.org>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2369 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-05-06 13:51:30 +00:00
cmpilato
cadb94c8b4 * INSTALL
Fix some formatting, and -- Ooh!  Did you see that?  Why, yes, I
  *did* just pull on some armor-plated underwear in the WSGI
  deployment section.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2367 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-05-05 15:26:07 +00:00
cmpilato
0d2cad4c2d Lose bogus MIME type in favicon link tag.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2364 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-04-21 19:07:30 +00:00
cmpilato
4a96cb39f5 * lib/viewvc.py
(view_revision): Include a self-referential 'revision_href' item in
    the template data dictionary.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2362 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-04-14 17:16:57 +00:00
cmpilato
ec36a17b1c Bump published latest version number.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2361 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-30 15:15:04 +00:00
cmpilato
d899df1771 * lib/vclib/ccvs/rcsparse/__init__.py,
* lib/vclib/ccvs/rcsparse/common.py
  Add some much-needed interface docs and comments.

Patch by: Jon Foster <jon.foster {_AT_} cabot.co.uk>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2360 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-29 18:22:04 +00:00
cmpilato
8af6e2d824 Copy CHANGES items from 1.1.5 and 1.0.11 releases.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2359 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-29 16:51:11 +00:00
cmpilato
16f6728f48 Duh. Bump copyright year in LICENSE.html file, too.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2352 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-29 15:37:05 +00:00
cmpilato
1da4f1a0e3 Copyright bumps only.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2349 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-29 15:30:00 +00:00
cmpilato
8af29de901 There were too many ways to do something as simple as HTML escaping in
the ViewVC codebase.  Simplify, conjoin, remove, etc.

* lib/sapi.py
  (escape): New function.  *The* preferred HTML-escaping mechanism.
  (Server.escape): New common Server object escape mechanism (which
    uses the aforementioned escape(), of course).
  (CgiServer.escape, WsgiServer.escape, AspServer.escape,
   ModPythonServer.escape): Lose as unnecessary.

* lib/viewvc.py
  (Request.get_form): Escape hidden form variable names and values.
  (htmlify): Remove.
  (): Replace all uses of cgi.escape() and htmlify() with (directly or
    indirectly) sapi.escape().
  
* lib/query.py
  (main): Use server.escape() instead of cgi.escape().

* lib/blame.py
  (HTMLBlameSource.__getitem__): Use sapi.escape() instead of
    cgi.escape().

* lib/idiff.py
  (_mdiff_split, _differ_split): Use sapi.escape() instead of
    cgi.escape().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2344 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-11 19:56:22 +00:00
cmpilato
8018ab4a95 Oops! Fix version typo.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2342 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-10 22:01:27 +00:00
cmpilato
eb245f2cde Copy in CHANGES entries for 1.0.10 and 1.1.4 release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2341 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-10 21:57:44 +00:00
cmpilato
19cc8e7e7b Bump latest release note.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2335 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-10 21:40:11 +00:00
cmpilato
26fa0600c6 Bump copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2330 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-03-10 21:17:28 +00:00
cmpilato
82c5390d06 * lib/viewvc.py
(view_queryform): Escape user-provided input before passing it
    directly off to the templates.  Can you say "XSS attack vector"?


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2326 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-02-10 19:19:53 +00:00
cmpilato
3bfefeaaff * lib/viewvc.py
(query_backup): Switch to using the sapi interface for output file
    I/O instead of using 'print'.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2325 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-02-10 19:18:18 +00:00
cmpilato
3563f77bc0 Fix use of 'allow_tar' in an example immediately after saying that it's been
removed.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2322 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-01-29 14:30:22 +00:00
cmpilato
9dc26d4a01 Fix issue #447: Annotate view broken for local SVN repo.
* lib/vclib/svn/svn_repos.py
  (BlameSource.__init__): Add 'config_dig' parameter, and use it to
    register the Subversion configuration directory.
  (LocalSubversionRepository.__init__): Recognize an empty-string
    config_dir as None.  (Yay for configuration file nuances!)
  (LocalSubversionRepository.annotate): Pass self.config_dir to
    BlameSource().

Patch (mostly) by: Jan Parthey <jpar{_AT_}tigris.org>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2320 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-01-19 15:10:58 +00:00
cmpilato
9fbedaeded * conf/viewvc.conf.dist
Comment tweaks, primarily to note in the authorizer parameter
  sections that those options only apply when 'authorizer' has been
  set to the correct respective authorizer name.

Suggested by: Dan Poirier <poirier{_AT_}pobox.com>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2318 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-01-08 17:24:47 +00:00
cmpilato
2d0fced231 Add a bit of a workaround -- which fortunately applies to probably 99%
of ViewVC users -- for issue #445 (standalone.py throws exception on
root listing after visiting a root).

* conf/viewvc.conf.dist
  Add warning about using per-root options with standalone.py.

* lib/config.py
  (Config.overlay_root_options): Move the assertion/recording related
    to the one-time-only overlay stuffs down to the point where
    problems might occur.  This gives standalone.py users who don't
    use per-root configuration options the requisite mercy to let
    their servers continue to function.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2316 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-01-07 15:56:29 +00:00
cmpilato
167a98ca4e * INSTALL
Fix a typo.  Found by Arfrever F. T. A. <arfrever.fta{_AT_}gmail.com>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2315 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-22 21:43:15 +00:00
cmpilato
fa33ac3990 Bump latest version on website.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2314 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-22 20:50:32 +00:00
cmpilato
e5f533a115 Copy in 1.1.3 CHANGES.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2313 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-22 20:50:19 +00:00
cmpilato
bedf47ea58 * conf/viewvc.conf.dist
(docroot): Add admonishment about how this interplays with per-root
    configuration of the 'template_dir' option.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2308 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-08 17:12:44 +00:00
cmpilato
4979fd6091 * conf/viewvc.conf.dist
Try to consistify the way our admonishments appear herein.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2306 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-08 17:05:36 +00:00
cmpilato
94708561eb Move the viewvc.org website directory to the root of the repository.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2303 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-04 21:49:18 +00:00
cmpilato
050eb3c433 Add some screenshots, and make some minor style tweaks.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2302 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-04 21:48:26 +00:00
cmpilato
2d091dc582 Some security-related improvements/fixes.
Make per-root authorizer-related configuration work so that admins can
feel comfortable exposing their root listing views again.

Also, make the query interface require that queried roots be
configured (explicitly or implicitly) to use either the 'forbidden'
authorizer or none at all.  This is a security fix, since
administrators might reasonably have thought that if they configured a
root to use another authorizer, the query interface would have honored
that configuration.

* lib/config.py
  (Config.__init__): Now track whether root options have been overlayed.
  (Config.overlay_root_options): Assert that no root options have been
    overlayed (and then noted that they now have).
  (Config.get_authorizer_and_params_hack): New function to workaround
    our inability to un-overlay root-specific options.  It's only the
    query interface and root listing views that really need to act on
    multiple roots at once, and really only the authorization options
    that matter there anyway.
  (Config.get_authorizer_params): Remove per-root overlay hacks from
    this function.

* lib/viewvc.py
  (Request.run_viewvc): Update call to setup_authorizer() (to not
    specify the rootname).
  (setup_authorizer): Make the rootname parameter option, as a flag
    for whether to consult the current configuration or instead use
    the hack which manually digs around for per-root overrides of
    authorizer stuffs.

* lib/query.py
  (is_forbidden): Don't try to apply the 'forbidden' authorizer where
    some other (or no) authorizer has been configured for a given
    root.  But do complain if another authorizer has been configured,
    rather than simply letting stuff leak through that an
    administrator might reasonably expect to have been hidden.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2300 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-03 06:04:32 +00:00
cmpilato
fe6b7afb66 * lib/query.py
(run_query): Expand roots so we're playing with a full deck.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2297 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-03 05:57:22 +00:00
cmpilato
a6565f89f9 Appease the monster in me who growls every time he finds a website
whose primary navigation links aren't preserved on every page.

* viewvc.org/who.html,
* viewvc.org/faq.html,
* viewvc.org/download.html,
* viewvc.org/contact.html
  Lose the 'Project Page' and 'Contributing' nav links.

* viewvc.org/index.html
  Lose the 'Project Page' and 'Contributing' nav links.  Put the
  (short) license on this page.

* viewvc.org/contributing.html
  Lose the 'Project Page' and 'Contributing' nav links.  Put info
  about the viewvc.tigris.org site on this page.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2295 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-02 19:49:25 +00:00
cmpilato
59e6fa414e Fix issue #442: Standalone server 1.1.2 fails to start under Python 1.5.2
* lib/viewvc.py
  (load_config): Tweak lambda usage for 1.5.2-compliance.

Patch by:  Dmitry Bulgakov <dvb{_AT_}tigris.org>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2293 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-02 16:01:49 +00:00
cmpilato
eda31f6050 Take a crack at revamping the configuration subsystem to allow for a
clear understanding of per-vhost and per-root configuration overrides.
This should resolve issue #411 (Can't override authz-* sections in
virtual host).

* conf/viewvc.conf.dist
  Add comments about the scope and permissability of per-vhost and
  per-root overrides.

* lib/config.py
  (): Add some comments about option layering -- including a fancy
    schmancy ASCII art diagram! -- and make some minor comment
    formatting tweaks.
  (Config._base_sections): Was Config._sections.  Add 'authz-*'.
  (Config._force_multi_value): Reformat and comment.
  (Config._allowed_overrides): New mapping of valid overrides.
  (Config.__init__): Track renamed _base_sections member, and avoid
    instantiating _sub_config items for non-explicitly-name base
    sections found therein.
  (Config.load_config): Add docstring.  Use _is_allowed_section() to
    determine which sections to process.
  (Config.load_kv_files): Add docstring.
  (Config.path): Minor docstring tweak. 
  (Config._process_section): Instantiate missing _sub_config() items.
    Add a FIXME comment.
  (Config._is_allowed_section, Config._is_allowed_override): New
    functions.
  (Config._process_vhost): Now use _is_allowed_override() for section
    filtering.
  (Config._process_root_options): Removed, merged with tweaks into...
  (Config.overlay_root_options): ...here, which now uses
    _is_allowed_override for section filtering.
  (Config.get_authorizer_params): Look in the calculated configuration
    rather than specific configuration file regions.  Add a FIXME
    comment.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2292 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-01 20:16:17 +00:00
cmpilato
438eb061bb * lib/config.py
(Config.load_config): Remove 'rootname' parameter that's unused by
    callers, and the code that employs it within this function.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2291 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-01 17:36:41 +00:00
cmpilato
3a4ca4d18a * lib/viewvc.py
(common_template_data): Default 'roots_href' to None, and only
    populate it if the roots listing is one of the configured allowed
    views.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2288 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-01 14:58:32 +00:00
cmpilato
d1cbb81fb5 Finish issue #440 (Database query by glob/exact match fails).
Defer validation of certain query-view-related input whose format is
unknown at the time of validation.  That includes all the form fields
whose interpretation (as an exact match, a blog, a regular expression,
etc.) changes based on the another field's value.  Instead, do that
validation in the view funcs themselves.

* lib/viewvc.py
  (_legal_params): Set the validator for the 'branch', 'file', 'who',
    and 'comment' parameters to None.
  (validate_query_args): New function for more careful query arg validation.
  (view_queryform, view_query): Call validate_query_args().

Tested by: Jon Foster <jonfoster{_AT_}tigris.org>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2286 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-12-01 14:53:10 +00:00
cmpilato
cd62600043 Fix issue #438, a regression caused by a botched function signature
change in r2244.

* lib/viewvc.py
  (view_checkout, view_cvsgraph_image, view_doc, view_patch): Fix
    calls to copy_stream().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2281 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-11-10 22:16:17 +00:00
cmpilato
7e3a9d7f4d Make ViewVC cross copies in Subversion history by default.
* lib/config.py
  (Config.set_defaults): Make 'options.cross_copies' default to 1.  At
    a minimum that makes it jive with the commented out default value
    shown in viewvc.conf.dist, but I believe that it's also the better
    of the two ways to resolve that disparity in terms of user experience.

Noticed by: Tom Throckmorton <throck{_AT_}gmail.com>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2279 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-11-05 16:35:05 +00:00
cmpilato
11efd97b23 For issue #434, mark up URLs and email addresses in item property
values as we do for revision property values.

* lib/viewvc.py
  (get_itemprops): Pass property values through format_log().

Patch by: Senthil Kumaran S <senthil@collab.net>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2277 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-10-25 22:06:54 +00:00
cmpilato
54086fd651 Finish issue #431 - make revision metadata available in diff view.
* lib/viewvc.py
  (view_diff): Use repos.itemlog() to fetch revision metadata about
  the left- and right-hand diff objects and expose 'author', 'log',
  'ago', and 'size' to the templates.

* docs/template-authoring-guide.html
  Document the newly added template data dictionary items.

* templates/diff.ezt
  Display the revision authors in the diff view.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2275 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-10-25 20:46:09 +00:00
cmpilato
1f8c5aca37 Fix a bug that caused log message in the query view to be truncated to
a single character.

* lib/viewvc.py
  (build_commit): Fix calls to format_log().  It turns out that
    parameter ordering is, you know, somewhat important.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2273 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-10-08 17:53:14 +00:00
cmpilato
f182d12e97 As part of issue #397, add initial support for mod_wsgi deployments.
* lib/sapi.py
  (WsgiServer): New class.

* bin/wsgi,
* bin/wsgi/viewvc.wsgi,
* bin/wsgi/query.wsgi
  New stubs.

* viewvc-install
  (FILE_INFO_LIST): Also install WSGI scripts.

* INSTALL
  Add instructions for WSGI deployment.

Patch (mostly) by: Rune Halvorsen <runefh{_AT_}gmail.com>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2271 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-10-08 14:56:25 +00:00
cmpilato
4c9aa8e1a6 Minor tweaks.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2270 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-10-08 14:50:04 +00:00
cmpilato
6e4710d1c6 Clarify the Apache configuration instructions.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2269 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-10-08 14:48:02 +00:00
cmpilato
98f1b93068 * lib/vclib/svn/svn_repos.py
(LocalSubversionRepository.open): Remove custom SIGTERM handler.
    It's causing problems for mod_python deployments, and I can't seem
    to make it do anything meaningful for CGI deployments either.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2268 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-10-06 19:11:28 +00:00
cmpilato
9015d12885 Fix issue #427 - regex filtering broken by bogus validator function.
* lib/viewvc.py
  (_validate_regex): Try compiling the incoming regex, returning True
    on success and None otherwise.  (Simply 'pass'ing caused all
    regexs to fail validation.)

Patch by: Robert Fleming <flemingr{_AT_}tigris.org>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2265 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-09-09 18:54:15 +00:00
cmpilato
0f376ac9a4 [singing] A spoonful of proofreading helps the temperature go down...
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2263 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-09-09 16:03:02 +00:00
cmpilato
761a97cb47 * conf/viewvc.conf.dist
(utilities): Clarify what we mean by "the directories in which
    certain programs live".

Suggested by: Eric McCarty <emccarty{_AT_}ostendo.com>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2261 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-09-09 15:57:43 +00:00
cmpilato
f72e67fa3e * templates/file.ezt
Don't point folks to the checkout view if it's disabled.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2259 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-09-09 14:18:15 +00:00
cmpilato
0b42d41e43 * lib/viewvc.py
(HtmlFormatter._tokenize_text): Give preference to the longer of
    overlapping matches that begin at the same point.  Add some
    comments that better explain what we're doing.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2257 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-31 14:54:26 +00:00
cmpilato
e7a9e33a36 Make some tweaks to the HtmlFormatter to allow more complex usages.
* lib/viewvc.py
  (HtmlFormatter): Add docstring.
  (HtmlFormatter.get_result): Now return the total number of readable
    characters, too.
  (format_log): Update expected return values from lf.get_result().  


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2255 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-27 15:17:37 +00:00
cmpilato
8a8e8cd1f5 Make the installing of the 'templates-contrib' tree optional.
* viewvc-install
  (TREE_LIST): Add a new field -- a boolean "is-optional" flag.
  (install_tree): New parameter 'is_optional', used to avoid whining when
    something in the source tree is missing.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2252 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-25 15:25:16 +00:00
cmpilato
40581a211c * lib/viewvc.py
(view_diff): Tweak some logic ordering, and ensure that 'changes' is
    initialized as a sequence (instead of None) as some template logic
    paths seem to care.

Reported by: Lawrence Cutlip-Mason <rena.larry.cm{_AT_}gmail.com>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2251 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-25 15:22:04 +00:00
cmpilato
6b4297e7f5 Add configurable support for tabstop-to-space translation.
* conf/viewvc.conf.dist
  (options.tabsize): New.

* lib/config.py
  (Config.set_defaults): Set default value for the 'tabsize' option.

* lib/viewvc.py
  (markup_stream_pygments): Pass the 'tabsize' parameter to Pygments' lexers.
    When not using pygments, use 'string.expandtabs' to do tab-to-space
    conversion (possibly with a new object that wraps BlameSource objects
    solely for that purpose).
  (DiffSource._format_text): Honor the tabsize configuration options when
    expanding tabs to spaces.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2249 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-24 15:08:58 +00:00
cmpilato
884a5de16d Follow-up to r2244 and r2245, supplying a way for the HtmlFormatter to
indicate that truncation happened (so callers can tack on an ellipsis
or somesuch).

* lib/viewvc.py
  (HtmlFormatter.format_email_truncated): Fix logic to use ellipsis
    for mangling but not for truncation.  (Also fix an off-by-one
    error in the logic.)
  (HtmlFormatter.get_result): Now return the result string and a
    "was-truncated" flag.
  (format_log): Update call to HtmlFormatter.get_result, and tack on
   an ellipsis if the log was truncated.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2247 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-21 15:58:19 +00:00
cmpilato
589f111f20 Follow-up to r2244 with some changes that allow you to register
userdata along with the log message formatters for use by the
conversion functions.  While ViewVC doesn't use this right now, the
feature has proven useful in writing an add-on that allows somewhat
generic highlighting of issue/bug IDs to URLs.

* lib/viewvc.py
  (HtmlFormatToken): Remove.
  (HtmlFormatter.format_url, HtmlFormatter.format_email_obfuscated,
   HtmlFormatter.format_email_truncated, HtmlFormatter.format_email,
   HtmlFormatter.format_text): Now accept (unused) 'userdata' parameter.
  (HtmlFormatter.add_formatter): Now accept 'userdata' parameter, associated
    with the formatter for future use.
  (HtmlFormatter.get_result): Pass the 'userdata' from the token to its
    converter.
  (HtmlFormatter._tokenize_text): Switch to using _item()s instead of
    HtmlFormatTokens.  Associate with each item the userdata for its converter.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2245 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-21 15:05:21 +00:00
cmpilato
a2cd81f304 Begin taking steps toward customizable log message markup/formatting,
and I think, actually fix ancient issue #3 ("URL cut off in elipsis")!

Incidentally, this change also makes the email address obfuscation
stuff work as documented.  Not sure how I started munging data when
mangle_email_addresses=1 (by substituting " at " for the at-sign), but
no more.

* lib/viewvc.py
  (htmlify): Drop 'mangle_email_addresses' parameter, which was mostly
    unused, and no longer do anything except very basic HTML encoding.
    Callers updated.
  (_re_rewrite_url): Tweak to match *non*-HTML-encoded URLs now.
  (HtmlFormatToken, HtmlFormatter): New classes for log formatting.
  (mangle_email_addresses): Remove as unused.
  (format_log): Add 'maxlen' parameter, allowing this function to be used
    for both long- and short-form log message formatting.
  (copy_stream): Drop unnecessary 'cfg' parameter.  Update call to htmlify().
  (MarkupPipeWrapper.__init__): Drop 'cfg' parameter as unused.
  (MarkupPipeWrapper.__call__): Update call to htmlify().
  (markup_or_annotate, view_revision, view_directory, view_log,
    build_commit): Use format_log() to format both long- and
    short-form log messages.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2244 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-20 20:38:32 +00:00
vfilippov
04d3b88f6a Bug 37020
Merge with r2243 from official SVN


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@268 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-08-20 12:43:52 +00:00
vfilippov
d85d6578da Bug 53107
For Wiki Template:cvs


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@256 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-08-17 14:30:37 +00:00
cmpilato
eb69c40687 Merge in 1.0.9 and 1.1.2's changes.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2242 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-11 16:00:21 +00:00
cmpilato
6cbb3fadac Note new latest release on project homepage.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2241 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-11 15:58:09 +00:00
cmpilato
cc4589ab10 Rename 'Source tarballs' left-nav as 'Downloads'.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2240 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-11 15:26:33 +00:00
cmpilato
fcff592db3 Rename 'Subversion' left-nav as 'Source Code'.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2239 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-11 15:25:55 +00:00
cmpilato
694a14e0d2 Update 'Mailing Lists' left-nav link.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2238 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-08-11 15:25:14 +00:00
vfilippov
7a40e1c902 Bug 52230
A fix for potential bug when no Subversion repositories are visible



git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@206 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-07-24 17:35:25 +00:00
cmpilato
205b3b67e1 Make it easier for folks to show/hide binary file contents in the
markup/annotate views.

* templates/file.ezt
  Add some customizable template logic to hide the contents of file's with
  non-human-readable file formats.  Were Greg Stein dead, he'd be rolling
  over in his grave right now.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2228 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-16 19:28:29 +00:00
cmpilato
8df8e878f4 * lib/viewvc.py
(view_error): Settle for simple HTML-escaping of error messages
    rather than full htmlification.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2225 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-14 20:43:46 +00:00
cmpilato
f038efef96 Fix issue #422: syntax coloration dropping initial blank lines from
files.

* lib/viewvc.py
  (markup_stream_pygments): Pass stripnl=False to Pygments lexers so
    they won't strip out leading blank lines from the files they are
    colorizing.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2223 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-13 17:13:16 +00:00
cmpilato
52584dec66 Document some shortcomings of the path-based authz subsystem.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2222 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-13 14:09:17 +00:00
cmpilato
5c9f504727 * conf/viewvc.conf.dist
(allow_compress): Add a note about the speed penalty this option causes.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2220 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-07 14:05:12 +00:00
cmpilato
7817608915 Try to avoid content spoofing errors. Prior to this change, a URL
like this:

   http://localhost/viewvc/subversion/?view=foo%22)%20was%20passed\
   %20as%20a%20parameter.20%20Visit%20http://www.baddy.com%20to%20\
   figure%20out%20why%20(%22foo

Would result in an error page that read as follows:

   An illegal value ("foo") was passed as a parameter. Visit
   http://www.baddy.com to figure out why ("foo") was passed as a
   parameter.

(where "http://www.baddy.com" was linkified, and could potentially
point to a malicious website.)

With this change, we will avoid printing unknown parameter names, and
will show the parameter name rather its value when a bogus value is
detected.  Yes, there's admittedly some information loss here that
might be useful to the well-meaning but fat-fingered user, but the
security aspect is more important.

* lib/viewvc.py
  (_validate_param): Don't print illegal parameter names, and show the
    (legal) parameter name rather than its value when that value is
    illegal.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2217 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-06 19:03:06 +00:00
cmpilato
0292a54ec0 Some more around input validation, cleaning up some code and
tightening up some other bits.

* lib/viewvc.py
  (_validate_view, _validate_mimetype): New validation functions.
  (_re_validate_mimetype): Removed as unused.
  (_legal_params): Tweak the validation routines for 'view' and
    'content-type' to point to _validate_view() and _validate_mimetype(),
    respectively.
  (_validate_param): Now check for non-zero result from validation
    functions as the "valid" indicator, rather than requiring each of
    them to raise an exception in troubled times.
  (Request.run_viewvc): Lose now-unnecessary validation of
    'content-type' parameter -- the normal parameter validation stuff
    should catch problems there.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2213 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-06 15:05:23 +00:00
cmpilato
6c93d8c8d1 * lib/viewvc.py
(Request.run_viewvc): Move the logic that maps view=rev to
    view=revision into the parameter validation loop.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2212 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-06 14:48:53 +00:00
cmpilato
4f622d375b * lib/viewvc.py
(Request.run_viewvc): Use an intermediate variable to simplify some
    logic around input parameter validation.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2211 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-07-06 14:46:21 +00:00
stas
c8dbd38e0c Bug 51239
try: except: pass
FUCKING PYDON


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@198 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-07-02 13:46:38 +00:00
stas
82ea92e4a4 Bug 44995
Unicode() string in format_log


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@196 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-07-02 11:22:55 +00:00
vfilippov
be67aab7dc Bug 32155
Fix RSS urls in multi-repository feeds


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@194 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-07-01 10:29:45 +00:00
cmpilato
867514f9ef Minor comment tweak.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2209 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-17 21:22:14 +00:00
cmpilato
b36d8584e8 * conf/viewvc.conf.dist
Comment out all the options here, forcing folks to uncomment the
  stuff they want to modify.  This allows the parsing of this file to
  be optimized toward doing less work, while maintaining a consistent
  initial presentation.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2207 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-17 14:32:16 +00:00
stas
8ecc076ebc Bug 37020
Fix build_commit access check


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@186 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-06-17 12:13:05 +00:00
stas
6a0562d708 Bug 37020
debug


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@185 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-06-16 16:54:14 +00:00
cmpilato
8e848a4025 Finish issue #415 - ModPythonServer shouldn't call sys.exit().
(This doesn't really fix anything, and hopefully doesn't break anything
either, but is merely a "good programming practice" cleanup item.)

* lib/viewvc.py
  (Request.run_viewvc): Ensure that server.redirect() is the last
    thing this function does (when it does it).

* lib/sapi.py
  (CgiServer.redirect): Avoid calling sys.exit().  Also, fix a use of
    print() that should be sys.stdout.write() (for consistency).
  (AspServer.redirect, ModPythonServer.redirect): Avoid calling sys.exit().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2205 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-16 15:04:24 +00:00
vfilippov
6835e74f20 Merge with ViewVC 1.2-dev http://viewvc.tigris.org/svn/viewvc@2204
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@184 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-06-16 14:11:20 +00:00
cmpilato
e7e8beca0a Finish issue #336 - Custom cvsgraph rendering via CGI parameters.
* conf/viewvc.conf.dist
  (allowed_cvsgraph_useropts): New option.

* lib/config.py
  (Config.set_defaults): Set default value for new
    'allowed_cvsgraph_useropts' option.

* lib/viewvc.py
  (_legal_params): Add new legal parameters: 'gflip', 'gbbox',
    'gshow', 'gleft', and 'gmaxtag'.
  (cvsgraph_make_reqopt, cvsgraph_normalize_gshow, cvsgraph_extraopts):
    New helper functions.
  (view_cvsgraph_image): Now pass the -O option set to the cvsgraph
    binary.
  (view_cvsgraph): Now pass the -O option set to the cvsgraph binary.
    Also, add new template data stuff for generating a user-configurable
    graph display options form.

* templates/graph.ezt,
* templates/docroot/styles.css
  Add template stuff for generating a user-configurable graph display
  options form.

* docs/url-reference.html,
* docs/template-authoring-guide.html
  Update documentation.

* CHANGES
  Note this change.

Patch by:  Bertho Stultiens <bertho{_AT_}j.auh.dk> (originally),
           Jene Jasper <tigris{_AT_}shadowland.demon.nl> (port to 1.1.x),
           me (tweaks for official ViewVC inclusion)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2204 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-15 20:18:35 +00:00
cmpilato
c3bdeea60b Correct some inconsistent markup in documentation.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2201 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-15 20:11:33 +00:00
cmpilato
3d8aecfd95 Tighten up some input validation.
* lib/viewvc.py
  (_re_validate_boolint): New.
  (_legal_params): Switch the validation function to _re_validate_boolint
   for the following: 'hideattic', 'makeimage', 'parent', 'tarball',
   and 'hidecvsroot'.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2199 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-15 19:41:30 +00:00
cmpilato
c713952d5e Minor documentation wording tweak.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2197 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-15 19:06:26 +00:00
svnuser
4b05147064 Bug 50473
A workaround for line counts when moving


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@178 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-06-15 15:53:35 +00:00
cmpilato
8910c295cc Finish issue #420 - "cvsdbadmin rebuild" and "svndbadmin rebuild"
complain about unknown repositories.

* bin/svndbadmin
  (main): When rebuilding, ignore the UnknownRepositoryError; when
    purging, turn that sucker into something readable.

* bin/cvsdbadmin
  (__main__): When rebuilding, ignore the UnknownRepositoryError; when
    purging, turn that sucker into something readable.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2195 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-08 15:50:51 +00:00
cmpilato
1d496a8f51 Make error handling in cvsdb a little more flexible.
* lib/cvsdb.py
  (UnknownRepositoryError, DatabaseVersionError): New Exception classes.
  (CheckinDatabase.Connect): Raise DatabaseVersionError instead of a
    generic Exception.
  (CheckinDatabase.PurgeRepository): Raise UnknownRepositoryError
    instead of a generic Exception.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2194 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-08 15:23:16 +00:00
cmpilato
892a951493 Finish issue #419: svnauthz module doesn't match Subversion's
case-handling semantics.

* conf/viewvc.conf.dist
  (force_username_case): New option.

* lib/vcauth/svnauthz/__init__.py
  (ViewVCAuthorizer.__init__): Find and handle new force_username_case
    authorizer option.
  (ViewVCAuthorizer._get_paths_for_root): Replace ConfigParser.optionxform()
    (which does normalization of option names) with an identity function
    of sorts.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2192 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-05 19:03:07 +00:00
cmpilato
1371a71f20 Consistify the layout -- at least on a section-by-section basis -- of
the viewvc.conf.dist file.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2190 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-05 17:52:47 +00:00
cmpilato
aba3033c27 Remove CHANGES item for change that should appear in 1.1.2 instead of 1.2.0.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2189 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-04 15:43:55 +00:00
cmpilato
74bfd3e9d8 Post-release fun.
* CHANGES
  Copy 1.1.1's changes here.

* www/index.html
  Update 'latest release' notes.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2186 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-06-03 15:05:32 +00:00
cmpilato
7cb54076fe Finish (for now) the 1.1.0 release ntoes.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2183 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-29 18:16:41 +00:00
cmpilato
197f352804 * templates/file.ezt
Use "Contents of /path/to/file" instead of "Annotate of /path/to/file" as
  the page title.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2181 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-29 17:57:03 +00:00
cmpilato
f48559766a * lib/cvsdb.py
(CheckinDatabase.PurgeRepository): Don't allow the purge operation
    to actually *create* a "repositories" table entry.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2179 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-29 15:09:51 +00:00
cmpilato
546501816b Fix issue #417 - "cvsdbadmin rebuild" fails to record some of the
commit/repository info.

* lib/cvsdb.py
  (CheckinDatabase.PurgeRepository): Clear all the ID caches after
    running a purge operation so that, if the purge is actually part
    of a rebuild, the subsequent update doesn't merely pull IDs from
    the cache (with the side-effect of not readding them to the database).

Reported by: Naran Babhu <naranbabhu{_AT_}tigris.org
             Martin Dessureault <martin{_AT_}austin.rr.com>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2178 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-29 15:08:32 +00:00
cmpilato
8089335fc6 Fix issue #416 - Can't see query form due to missing template variables.
* lib/viewvc.py
  (view_queryform): Add 'query_action' and 'query_hidden_values' back
    to the data dictionary, as they were accidentally dropped in r2123.

Reported by: Naran Babhu <naranbabhu{_AT_}tigris.org>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2175 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-28 13:59:47 +00:00
svnuser
a208ec46ab Bug 37020
Search by revision number


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@165 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-05-21 14:42:39 +00:00
cmpilato
d739127ea4 Update external to point to 1.2 versions of contributed templates.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2172 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-18 13:28:53 +00:00
cmpilato
4b4f450ecb Update CHANGES list for 1.1.0 release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2169 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-13 17:11:27 +00:00
cmpilato
588f9000e9 Update the viewvc.org site.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2168 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-13 14:44:58 +00:00
cmpilato
7ecae1790a One last tweak.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2167 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-13 14:43:13 +00:00
cmpilato
a154179492 Need ... homepage ... beauty...
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2166 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-13 14:41:52 +00:00
cmpilato
cc4f8254d6 More Tigris homepage tweaks.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2165 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-13 14:40:24 +00:00
cmpilato
c695ede476 Update Tigris homepage.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2164 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-13 14:31:11 +00:00
cmpilato
c910df0835 Add left-nav link to source tarballs.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2163 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-13 14:20:53 +00:00
cmpilato
914e0e7521 Copy 1.0.8's CHANGES.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2152 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 17:26:04 +00:00
cmpilato
4c81b1fd91 Note new version of ViewVC.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2151 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 17:25:04 +00:00
cmpilato
92a95601d1 Bump copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2146 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 17:08:54 +00:00
cmpilato
211bc90343 Finish issue #402: Split the 'use_pagesize' configuration directive
into two: 'log_pagesize' and 'dir_pagesize', individually controlling
the size of pages used (if at all) for the revision log and directory
views, respectively.

* conf/viewvc.conf.dist
  (use_pagesize): Removed, in favor of...
  (dir_pagesize, log_pagesize): ...these.

* lib/viewvc.py,
* lib/config.py,
* bin/standalone.py
  Replace the use and tooling around 'use_pagesize' with
  'dir_pagesize' and 'log_pagesize' as appropriate.

* templates/include/paging.ezt,
* templates/include/dir_header.ezt
  Stop using the option value to determine whether or not to show
  pagination UI.  Use the presence of some pages instead.
  
* docs/upgrading-howto.html
  Note the changes in options.

Patch by: Lei Zhang <thestig{_AT_}google.com>
          (Tweaked by me.)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2142 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 15:45:25 +00:00
cmpilato
fdff86c5f4 Fix the GUI mode of standalone.py -- it wasn't even starting
correctly, and we don't need a toggle for 'enscript' any more.

* bin/standalone.py
  (GUI.__init__): Pass the configuration file to handle_config().
    Lose 'enscript'-related stuff.
  (GUI.toggle_use_enscript): Remove.
  (cli): Fix call to gui(), dropping bogus parameter.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2140 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 15:34:11 +00:00
cmpilato
7ca7528869 Fix issue #409, an exception thrown when sorting by revision in a
remote Subversion directory view.

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.dirlogs): Store the entry's revision as
    a string, for consistency with other vclib modules.

Reported by: Wojciech Wróblewski <wojtek{_AT_}elmi.pl>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2137 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-05 14:52:35 +00:00
cmpilato
dfa98b490f Fix an exception in log views of Subversion repositories with 0
revisions.

* lib/vclib/svn/svn_repos.py
  (_get_history): Add easy-out for repositories with 0 revisions.

Reported by: Wojciech Wróblewski <wojtek{_AT_}elmi.pl>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2134 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-05-04 14:53:24 +00:00
cmpilato
bacb71b1d2 Call make-release correctly.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2132 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-04-20 17:47:50 +00:00
cmpilato
3da11f485a Slight terminology tweak.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2129 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-04-20 17:40:51 +00:00
cmpilato
a8e6f976ef * tools/make-release
Make this able to build any branch, not just trunk and tag names.

* notes/releases.txt
  Update example of using make-release.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2128 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-04-20 17:38:57 +00:00
stas
86c313bcf8 Bug 37020
rss_href


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@163 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-04-10 10:26:29 +00:00
vfilippov
a2e45b4468 Bug 37020
404 not found on log_href's of removed files
More request.roottype ---> my_repos['roottype']


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@157 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-03-31 13:07:48 +00:00
stas
5ed8c4967a Bug 47903
Incorrect exam_rev for SVN deleted files


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@150 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-03-25 18:14:54 +00:00
cmpilato
6d6a0287ac * lib/viewvc.py
(view_directory, view_log): Add some comments explaining the
    presence of certain data dictionary dummy values.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2124 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-24 17:01:53 +00:00
cmpilato
63af297920 Try to make ViewVC provide a consistent, predictable data dictionary
in all of its templated views.  Do this with a custom, dictionary-like
class that prevents the creation of new keys after an initial
instantiation of keys and (possibly dummy) values.

* lib/ezt.py
  (TemplateData): New.

* lib/viewvc.py
  (common_template_data): Now return an ezt.TemplateData() object.
  (make_comma_sep_list_string): New.
  (markup_or_annotate): Use new ezt.TemplateData() interface now.  Use
    make_comma_sep_list_string() where applicable.
  (view_roots, view_log, view_cvsgraph, view_diff, view_revision,
   view_queryform, view_query): Use new ezt.TemplateData() interface now.
  (view_directory): Use new ezt.TemplateData() interface now.  Drop
    'search_re_form' dictionary item.

* lib/query.py
  (main): Use new ezt.TemplateData() interface now.  While here, drop
    'script_name' calculation (it isn't used).

* templates/include/dir_header.ezt
  Display the search form if 'search_re_action' is set, not 'search_re_form'.

* docs/template-authoring-guide.html
  Remove 'search_re_form'.  Update 'search_re_action' description.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2123 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-24 16:55:25 +00:00
cmpilato
d7ac8ee2d4 * templates/include/file_header.ezt
Lose template reference of 'log_href_rev', which was removed in
  r2116 as unused.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2121 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-24 16:32:29 +00:00
cmpilato
11b4c4f4f8 Clutterkiller! Put the default configuration files into a conf/
subdirectory.

* conf/
  New subdirectory.

* cvsgraph.conf.dist,
* mimetypes.conf.dist,
* viewvc.conf.dist
  Move these from here ...

* conf/cvsgraph.conf.dist,
* conf/mimetypes.conf.dist,
* conf/viewvc.conf.dist
  ... to here.

* viewvc-install
  (FILE_INFO_LIST): Track new locations of configuration files.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2119 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-19 20:41:41 +00:00
cmpilato
c6671ecc50 Attempt to compensate for the fact that some versions of Subversion's
Python bindings do not correctly set the .apr_err and .message members
of SubversionException objects by patching up those exceptions using
the exception arguments.

(Unfortunately, I don't have a version of these bindings installed for
testing.)

* lib/vclib/svn/svn_repos.py
  (_fix_subversion_exception): New helper function.
  (_get_history, BlameSource.__init__, LocalSubversionRepository.rawdiff,
   LocalSubversionRepository.get_location, LocalSubversionRepository.last_rev):
    Use _fix_subversion_exception().

* lib/vclib/svn/svn_ra.py
  (): Import _fix_subversion_exception from svn_repos.
  (RemoteSubversionRepository._date_from_rev, 
   RemoteSubversionRepository.get_location): Use _fix_subversion_exception().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2117 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-19 18:02:35 +00:00
cmpilato
0bcb42c158 * lib/viewvc.py
(common_template_data): Stop initializing an unused value.

* docs/template-authoring-guide.html
  Lose docs for unused (and spelled wrong, to boot) template variable.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2116 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-19 17:46:54 +00:00
cmpilato
586c6bfb9e * lib/ezt.py
(Template._cmd_for): Raise a more useful exception message when the
    to-be-looped-over variable ain't a sequence.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2115 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-19 17:44:07 +00:00
cmpilato
ca12b5257c * lib/ezt.py
(Template._cmd_print): Raise a more helpful exception to give some
    clues to template authors who tried to, say, print a sequence
    reference.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2111 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-19 15:21:30 +00:00
cmpilato
7fd9e405a1 Update copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2107 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-18 16:43:33 +00:00
cmpilato
6361a849a6 Update release notes.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2106 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-18 16:15:49 +00:00
cmpilato
e72184e288 Fix namespace problem with raised Exception.
* lib/viewvc.py
  (view_revision): raise *debug.*ViewVCException.

Patch by: Kamesh Jayachandran <kamesh@collab.net>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2103 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-18 12:45:47 +00:00
cmpilato
2dc51276ce Finish issue #401: Support MIME type overrides in ViewVC configuration.
Trade the 'mime_types_file' option for 'mime_types_files' -- an
ordered list of MIME mapping files to consult.  And provide our own
(empty) mapping file that folks can use to override the mappings
provided by other such files.

* mimetypes.conf.dist
  New file.

* viewvc.conf.dist
  (mime_types_files): Was mime_types_file, and now accepts multiple values.

* lib/config.py
  (Config._force_multi_value): Add "mime_types_files" to the list of
    multi-value configuration options.
  (Config.set_defaults): Track rename of mime_types_file parameter,
    now setting the default to a list containing only "mimetypes.conf".

* lib/viewvc.py
  (load_config): Track new name and format of mime_types_files option.

* viewvc-install
  (FILE_INFO_LIST): Also install mimetypes.conf.dist as itself and as
    mimetypes.conf.

* INSTALL
  (INSTALLING VIEWVC): Update reference to renamed configuration option.

* docs/upgrading-howto.html
  Update this document.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2101 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-03-06 16:43:04 +00:00
cmpilato
e1575692be Finish issue #396 - Malformed accept-language header crashes viewvc
* lib/accept.py
  (AcceptLanguageParseError): Was AcceptParseError.
  (_parse): Track renamed Exception.

* lib/viewvc.py
  (Request.__init__): Catch and handle raised AcceptLanguageParseError.

Patch by: Rune Halvorsen <runefh{_AT_}gmail.com>,
          me


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2097 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-26 16:12:15 +00:00
cmpilato
748efe3815 Add FAQ entry about exposing ViewVC at a vhost root.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2096 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-24 13:36:41 +00:00
cmpilato
d681df85d3 Allow ViewVC to (optionally) use the 'chardet' module during syntax
coloration to perform character encoding detection (and subsequent
translation to UTF-8).

(Thanks to Jeremy Whitlock <jcscoobyrs@gmail.com> for pointing me in
this direction, if inadvertantly.)

* viewvc.conf.dist
  (options.detect_encoding): New.

* lib/config.py
  (Config.set_defaults): Initialize the 'detect_encoding' parameter.

* lib/viewvc.py
  (markup_stream_pygments): If the configuration asks for character
    encoding detection, try to import the 'chardet' module and -- if all
    goes well -- tell Pygments to use it.

* CHANGES
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2095 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-20 17:23:27 +00:00
cmpilato
e53b3af42f ViewVC doesn't "do" directory entry sorting by revision for CVS, so
don't imply that it does in the UI.

* lib/viewvc.py
  (view_directory): Don't provide sortby_rev_href to the template.

* templates/directory.ezt
  Only offer sort links when those links are provided by ViewVC.

* templates/dir_new.ezt
  Only offer sort links when those links are provided by ViewVC.  Use
  date-based sorting if rev-based sorting isn't available.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2090 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-20 15:20:15 +00:00
stas
dbd3e4af59 Bug 46528
Bug 46710
default format


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@134 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-02-16 12:57:47 +00:00
vfilippov
5349a36a18 Bug 46528
Bug 46710
OR in group formats


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@133 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-02-16 12:55:32 +00:00
stas
81df47c357 Bug 46528
strip's


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@132 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-02-16 12:44:38 +00:00
stas
c916450eac Bug 46710
Bug 46528
Debugw


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@131 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-02-16 11:43:17 +00:00
stas
e4ea3a9f85 Bug 46710
Bug 46528
debug cvsntacl authorizer


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@130 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-02-16 11:41:16 +00:00
vfilippov
e6be979387 Bug 46528
By root group check specification


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@128 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-02-13 10:43:39 +00:00
vfilippov
2896c70f26 Bug 46528
New authorizers: grp, union, cvsntacl


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@127 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-02-12 16:37:15 +00:00
vfilippov
50b67b3ddb Bug 45076
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@126 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-02-11 12:57:01 +00:00
vfilippov
3c7ad9405c Bug 46239
Look in CVS/SVN/All repos link on query results page


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@121 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-02-03 12:19:33 +00:00
cmpilato
d1a7412c6d Remove dead code.
* lib/popen.py
  (pipe_cmds, _copy): Remove as unused.

* bin/standalone.py
  (StandaloneServer.run_viewvc): Tweak comment that referred to pipe_cmds().

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


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2088 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-03 03:53:25 +00:00
cmpilato
ee692db2b0 Fix issue #398 (File Log Viewer Shows Wrong Log Message) by asking the
vclib layer for revision-sorted output rather than "whatever you want
to give me".

* lib/viewvc.py
  (markup_or_annotate): Pass vclib.SORTBY_REV instead of vclib.SORTBY_DEFAULT
    to the itemlog() interface.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2086 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-02-02 18:10:59 +00:00
vfilippov
ab286694fe Bug 46239
Search only CVS/SVN repositories option


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@119 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-02-02 17:20:11 +00:00
vfilippov
1cf0815b3d Bug 45675
Unsecure patch detection fix for SVN roots


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@108 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-01-27 11:27:05 +00:00
cmpilato
544ca74ed9 Add a skeletal version of some semblance of 1.1.0 release notes, taken
from an email response I gave on the dev@ list.  Will massage this
into something a little more ready for publicity later.

* docs/release-notes,
* docs/release-notes/1.1.0.html
  New.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2085 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-01-15 16:56:44 +00:00
vfilippov
355033b015 Bug 45675 -- debug
!!previous commit also was related to bug 45675


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@100 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-01-15 10:18:33 +00:00
vfilippov
2f99f7b72c Bug 45675 -- better way of diffing added/removed files
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@99 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-01-15 10:00:38 +00:00
vfilippov
e8d7fb16ff Bug 45675
debug


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@98 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-01-15 09:11:40 +00:00
vfilippov
e1cc47c375 Bug 45675: Patches from query results
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@97 6955db30-a419-402b-8a0d-67ecbb4d7f56
2009-01-14 14:07:41 +00:00
cmpilato
f6844dda91 Finish issue #334 by adding an empty CSS class def and some references
to it for line number columns in the diff view.

* templates/docroot/styles.css
  (.vc_diff_line_number): New.

* templates/diff.ezt
  Use new vc_diff_line_number class.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2083 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-01-13 19:10:09 +00:00
cmpilato
5fdfefa137 Document the new database schema stuff.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2081 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-01-13 18:44:43 +00:00
cmpilato
cd64b5da8b Add some real command-line parameter handling to 'make-database',
effectively allowing for non-interactive operation.

* bin/make-database
  (INTRO_TEXT): Removed, merged into the usage message printed by...
  (usage_and_exit): ...this new function.
  (__main__): Add new command-line parsing logic, including support of
    new options (--username, --hostname, --password, --dbname) and the
    replacement of the --bonsai-compatible option with a more generic
    --version.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2079 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-01-13 18:18:46 +00:00
cmpilato
623ab85805 Merge to trunk all changes made on the issue-366-dev branch,
completing issue #366 (cvsdb purge operation is painfully slow).

* lib/cvsdb.py,
* bin/make-database


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2078 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-01-13 18:16:11 +00:00
cmpilato
ceb7057b9f Remove unnecessary empty svn:mergeinfo.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2077 8cb11bc2-c004-0410-86c3-e597b4017df7
2009-01-13 18:14:52 +00:00
cmpilato
b6486f5324 On the 'issue-366-dev' branch: add 'make-database --help' parameter.
* bin/make-database
  (BONSAI_COMPAT): Tweak a little bit.
  (__main__): Add support for a --help parameter that prints a usage message.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/issue-366-dev@2076 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-22 21:22:46 +00:00
cmpilato
af83138e5c On the 'issue-366-dev' branch: Rename the 'checkins' table to
'commits' in schema version 1 (so that old version-ignorant code will
croak on a version-1 database).

* lib/cvsdb.py
  (CheckinDatabase.AddCommit, CheckinDatabase.CreateSQLQueryString,
   CheckinDatabase.CheckCommit, CheckinDatabase.sql_delete,
   CheckinDatabase.PurgeRepository): Account for the fact that in
    version 1 of the commits database schema, the 'checkins' table has
    been renamed to 'commits'.

* bin/make-database
  (DATABASE_SCRIPT_VERSION_1): Rename the 'checkins' table to 'commits'.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/issue-366-dev@2075 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-22 21:04:12 +00:00
stas
5a55d3c0cd O_o max context value = 2^25-1 ... workaround for Bug 45200
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@76 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-22 18:13:08 +00:00
vfilippov
00d1ffe3e0 fix
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@75 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-22 18:00:37 +00:00
cmpilato
8f8dea6051 On the 'issue-366-dev' branch: Add a new index to version 1 of the
commits database schema, and use it (when present) in the 'purge'
operation.

* lib/cvsdb.py
  (CheckinDatabase.sql_purge): New function.
  (CheckinDatabase.PurgeRepository): If we have a schema version that
    supports it, use a much faster approach of purging.  Otherwise, we
    have to suffer through a slow purge process.

* bin/make-database
  (DATABASE_SCRIPT_VERSION_1): Add a new index of 'descid's to the
    'checkins' table.

Patch (mostly) by: Larry Shatzer, Jr. <larrys@gmail.com>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/issue-366-dev@2074 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-22 15:38:09 +00:00
cmpilato
ba9cf67fae On the issue-366-dev branch: Add a new version of the commits database
schema that includes a `metadata' table (in which may be found the
schema version).

* lib/cvsdb.py
  (CVSDB_VERSION): New global variable.
  (CheckinDatabase.__init__): Init a new _version variable.
  (CheckinDatabase.Connect): Fetch a list of tables and see if the new
    `metadata' table is present.  If so, use it to query the database
    schema version.  (Else, assume version 0.)
  (CheckinDatabase.GetTableList, CheckinDatabase.GetMetadataValue,
   CheckinDatabase.SetMetadataValue): New functions.

* bin/make-database
  Rework this to be able to write two different schemas -- the
  original, Bonsai-compatible one, and a new one -- triggered by the
  presence/absence of a command-line --bonsai-compatible parameter.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/issue-366-dev@2073 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-22 15:30:16 +00:00
cmpilato
09a5adb85d Create branch for issue #366 (cvsdb purge operation is painfully slow) work.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/issue-366-dev@2072 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-22 15:23:18 +00:00
cmpilato
0b1ac97f75 Try to deal with Subversion versions that lack the
SVN_ERR_CEASE_INVOCATION error code.

* lib/vclib/svn/svn_repos.py
  (_SVN_ERR_CEASE_INVOCATION): New compatibility variable.
  (NodeHistory.add_history, _get_history): Use compatibility variable
    instead of testing for SVN_ERR_CEASE_INVOCATION directly.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2070 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-19 19:48:43 +00:00
cmpilato
3e77755819 Document new num_changes item in upgrade notes.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2068 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-19 19:45:44 +00:00
cmpilato
1433941124 Expose to revision.ezt a count of the total number of changed paths.
* lib/viewvc.py
  (view_revision): Add new 'num_changes' data dictionary item.

* templates/revision.ezt
  Expose new 'num_changes' item as a header on this page, and tweak
  the way the more/first changes links appear.

* docs/template-authoring-guide.html
  Document num_changes dictionary item.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2067 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-19 19:43:18 +00:00
vfilippov
0d3176a320 bug 45200
'rcsdiff' workaround for fucking cvsnt


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@73 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-19 14:47:24 +00:00
vfilippov
053cc33ffd bug 44943
blame_source ---->> utf8string


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@68 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-16 14:29:30 +00:00
vfilippov
93144b2168 bug 37020
bug 44996
more CVS charset fixes


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@62 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-12 16:19:41 +00:00
vfilippov
c102b6b2a0 utf8string cvs logs
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@61 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-12 12:36:39 +00:00
vfilippov
7cd0e372bb russian filenames in cvs fix
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@60 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-11 16:02:02 +00:00
vfilippov
4e047ae281 bug 44931
s.encode('utf-8') in ezt


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@59 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-11 10:46:42 +00:00
cmpilato
c733fceb9f Rework the 'rlog-ended-early' FAQ bit with a more generic entry.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2066 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-10 18:12:29 +00:00
cmpilato
ca5a2bfbc9 Fix issue #385 (Hide/show annotations links mismanaged for binary
files).

* lib/viewvc.py
  (markup_or_annotate): Make the default value for the 'annotation'
    data dictionary member 'none' (instead of None) to simplify
    template logic.

* docs/template-authoring-guide.html
  Update docs for 'annotated'.

* templates/file.ezt
  Use simplified logic to avoid missing links.  (No, not *that* kind ...)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2064 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-10 17:26:37 +00:00
cmpilato
77fd2759c7 Remove unnecessary module imports.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2063 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-10 17:25:11 +00:00
vfilippov
1128625ac3 bug 44887
debug Magic MIME type guessing


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@58 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-10 13:21:37 +00:00
stas
15e2d27b7d xml
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@57 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-10 13:06:59 +00:00
vfilippov
86dcf849e3 debug magic code
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@56 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-10 13:03:55 +00:00
vfilippov
5f66346633 bug 44887
do not annotate binary files


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@55 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-10 12:26:16 +00:00
vfilippov
6586c8e4d7 bug 37020
enc fix


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@54 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-09 18:44:05 +00:00
vfilippov
d34f8f5946 bug 37020
debug


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@53 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-09 16:52:16 +00:00
vfilippov
842f0e712a bug 37020
templates for multi-repos query form


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@52 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-09 16:46:42 +00:00
vfilippov
0ad8ee1554 debug
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@51 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-09 16:46:28 +00:00
vfilippov
0f545ca76b del
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@50 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-09 16:36:37 +00:00
vfilippov
c3f2777a4e bug 37020
multi-root query form


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@49 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-09 16:34:49 +00:00
vfilippov
45c636fd11 bug 37020
no pagesize by default


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@48 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-09 15:18:31 +00:00
vfilippov
2d9276a06d KEY descid
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@47 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-09 14:54:40 +00:00
vfilippov
eb6edef712 cvs logs -----> utf8
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@46 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-09 11:23:21 +00:00
vfilippov
b574b8594d utf8
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@45 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-08 13:00:51 +00:00
vfilippov
3bfb004158 asynchronous SVN update script
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@44 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-08 12:32:42 +00:00
cmpilato
08a8b110ac Allow admins to enable/disable diff/patch views via the allowed_views
configuration bit.

* lib/viewvc.py
  (view_diff, view_patch): Only show diffs if 'diff' is one of the
    allowed views.

* lib/config.py
  (Config.set_defaults): Add 'diff' to the set of allowed_views (and
    sort the values alphabetically where here).

* viewvc.conf.dist
  (allowed_views): Add 'diff' to the set of views you can specify, and
    include it in the default values.  While here, sort the values
    alphabetically.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2058 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-12-05 17:01:39 +00:00
vfilippov
23eea873fa fix a bug in setup cvs hooks script
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@43 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-04 21:51:19 +00:00
vfilippov
9f0557ff85 testing ViewVC hooks
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@42 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-04 21:32:44 +00:00
vfilippov
00f38a1b55 utf8string diffs
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@41 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-04 15:47:45 +00:00
vfilippov
3b4f7698af rights
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@40 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-02 14:55:27 +00:00
vfilippov
0114b46db0 fix directory rights
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@39 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-02 14:53:23 +00:00
vfilippov
a0c895b5a6 debug
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@38 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-02 14:46:25 +00:00
vfilippov
e74a8ac42d Apache config via virthost
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@37 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-02 14:15:01 +00:00
vfilippov
d94e658457 cvs_ondisk_charset
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@36 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-02 10:39:18 +00:00
vfilippov
cbcffad79a physical charset
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@35 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-12-01 18:16:46 +00:00
vfilippov
025eb36df4 multiple repos co CVSROOT
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@34 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-27 15:20:35 +00:00
vfilippov
33a8f2849c CustIS install script, it's done and tested now
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@33 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-26 14:18:40 +00:00
vfilippov
1bbf731b83 setup-svn-hooks
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@32 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-26 14:15:32 +00:00
vfilippov
cd68fb0f79 improved ACL import script
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@31 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-21 17:06:03 +00:00
vfilippov
97e5d91c18 import
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@30 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-18 17:25:26 +00:00
vfilippov
28ba6929af cvsacl
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@29 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-18 17:24:50 +00:00
vfilippov
3187e57026 None
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@28 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-18 13:49:12 +00:00
vfilippov
a30b597260 check access rights when querying commit database
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@27 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-18 13:36:33 +00:00
vfilippov
1480000938 debug
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@26 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-17 17:04:16 +00:00
vfilippov
bfe175e5cd setup cvs hook script
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@25 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-17 16:19:31 +00:00
vfilippov
2cadb542a2 pygments
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@24 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-14 19:42:47 +00:00
vfilippov
13b23a5696 total plus/minus lines
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@23 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-14 17:57:57 +00:00
vfilippov
822ec29624 bug 37020
fucking encodings


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@22 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-14 14:53:48 +00:00
cmpilato
38a7338c9d Add a configuration option for telling ViewVC to *not* honor the
svn:mime-type property.

* lib/config.py
  (Config.set_defaults): Set options.svn_ignore_mimetype default value.

* viewvc.conf.dist
  (svn_ignore_mimetype): New.

* lib/viewvc.py
  (calculate_mime_type): Consult cfg.options.svn_ignore_mimetype
    before looking up the 'svn:mime-type' property.

* docs/upgrading-howto.html
  Add a note about the new configuration option.

Patch (mostly) by: JJ <eggsgloriouseggs {_AT_} gmail.com>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2055 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-13 21:44:15 +00:00
cmpilato
bf40ef2683 It's very confusing to comment out the authorizer configuration line
and have that mean "use an authorizer".  So let's just prevent that
confusion right now, okay?

* lib/config.py
  (Config.set_defaults): Set 'authorizer' by default to None.

* viewvc.conf.dist
  (authorizer): Update comments for correctness, and don't imply that
    "forbidden" is the default authorizer.

* docs/upgrading-howto.html
  Stop saying that "forbidden" is the default authorizer.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2053 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-13 21:20:29 +00:00
cmpilato
11f5685955 Finish issue #384 - repos._revinfo_raw() is doing far too much work
when no authz is in use.  Vastly improves performance of
repos.itemlog() for local Subversion repositories *not* protected by
an authorizer.

* lib/vclib/svn/svn_repos.py
  (LocalSubversionRepository._revinfo): Was ._revinfo_raw().  Now
    encapsulates the caching logic that used to live in .revinfo(), plus
    the old logic of _revinfo_raw() modified to avoid changed-path
    processing when that processing isn't strictly required by callers.
  (LocalSubversionRepository.revinfo): Make this just a thin wrapper
    around ._revinfo() now.  Internal callers of this function updated
    to use ._revinfo() instead.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2051 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-13 21:14:14 +00:00
cmpilato
4904e03324 Minor improvements to the debug timer code.
* lib/debug.py
  (t_dump): Was dump().  Now accepts an output file handle, and sorts
    the output in a predictable fashion.

* lib/viewvc.py
  (main): Track changes to debug.dump().

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2048 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-13 19:45:13 +00:00
vfilippov
f9b1b8a50c encodings
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@21 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-13 16:51:57 +00:00
vfilippov
6978ac9e5d merged
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@20 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-13 14:56:58 +00:00
vfilippov
230e2f1700 bug
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@19 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-12 20:17:34 +00:00
vfilippov
899204468b cron reload
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@18 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-12 19:04:57 +00:00
vfilippov
712761df3f fast cvsdbadmin
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@17 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-12 18:52:54 +00:00
vfilippov
73eaad686b bug 37020
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@16 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-12 18:48:25 +00:00
vfilippov
6556287ff3 bug 37020
debug


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@15 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-12 18:46:44 +00:00
vfilippov
4b51a62390 bug 37020
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@14 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-12 18:45:01 +00:00
vfilippov
5ea538f50e Pygments from tarball
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@13 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-12 18:26:03 +00:00
vfilippov
521261bb34 bug 37020
automatic hook setup


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@12 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-12 18:14:50 +00:00
vfilippov
9e55dba9f9 bug 37020
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@11 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-12 17:40:19 +00:00
vfilippov
9ac8f10967 bug 37020
http_proxy


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@10 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-12 17:08:12 +00:00
vfilippov
6ef2a85ae9 debug
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@9 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-12 16:42:44 +00:00
vfilippov
1200a15887 bug 37020
config


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@8 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-12 16:39:48 +00:00
vfilippov
0fddc0bb87 Bug 37020
Install script


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@7 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-12 16:12:45 +00:00
vfilippov
28a41fb268 fix pygments
git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@6 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-12 16:12:19 +00:00
cmpilato
bd1254aa5f Avoid returning huge lists of variables from get_file_view_info(), and
use an ad-hoc class to hold all that stuff instead.

* lib/viewvc.py
  (get_file_view_info): Now return an object with interesting member variables
    instead of a nasty long list of values in an easy-to-goof-up order.
  (common_template_data, view_directory, view_log, view_diff): Update
    uses of get_file_view_info to track new calling semantics.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2047 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-11 16:21:58 +00:00
vfilippov
585580ec57 bug 37020
Ability to connect to MySQL through UNIX socket
diff links in query.py are shown now (moved expand_root_parents to config.py)
full-text comment searches in query and query_form are supported using MySQL FULLTEXT indexes
<select> for repository selection in query


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@5 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-11 14:25:07 +00:00
vfilippov
f3aa325419 bug 37020
viewvc 1.1.0-beta1 initial commit


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@4 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-11 14:17:41 +00:00
vfilippov
9b00bc278f bug 43834
dirs


git-svn-id: svn://svn.office.custis.ru/3rdparty/viewvc.org/trunk@3 6955db30-a419-402b-8a0d-67ecbb4d7f56
2008-11-11 14:12:33 +00:00
cmpilato
8b6e568ae1 * viewvc.org/faq.html: Minor wording tweak.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2046 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-10 22:05:27 +00:00
cmpilato
bc13ce9938 * viewvc.org/faq.html: Update the answer to the authz question.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2045 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-10 14:29:47 +00:00
cmpilato
0ddf057bbc Minor website tweakage.
* viewvc.org/index.html
  Lose 'Future Plans' section, and overhaul the feature and requirements lists.

* viewvc.org/contributing.html
  Fix the link to the Template Authoring Guide.

* viewvc.org/download.html
  Add a section for upgrading existing ViewVC installations.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2044 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-06 20:36:37 +00:00
cmpilato
5dbdea76ce docs/upgrading-howto.html: Don't claim as removed options not in 1.0.x.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2043 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-05 21:13:54 +00:00
cmpilato
8a9b9562f3 Merge r2040 from the 1.1.x branch:
* CHANGES: Combine some changes, and remove a now-bogus one.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2041 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-05 16:31:47 +00:00
cmpilato
51994aabc9 Doh! Remove empty <div> section.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2039 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-04 21:45:28 +00:00
cmpilato
f3edee505d Website and CHANGES file updates.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2038 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-11-04 21:44:44 +00:00
cmpilato
bcfb8f2c97 * lib/viewvc.py (__version__): Bump to '1.2-dev'.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2034 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-30 17:37:04 +00:00
cmpilato
c481fe3ace Support rule inversion in the 'svnauthz' module, just as Subversion supports.
* lib/vcauth/svnauthz/__init__.py
  (_userspec_matches_user): New, abstracted from _process_access_section(),
    but now with support for the inversion indicator (~).
  (_process_access_section): Use new _userspec_matches_user().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2032 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-30 17:10:13 +00:00
cmpilato
563b5a9f6d * docs/upgrading-howto.html
Reorder some sections, and documenting the known issues with the
  authz stuff.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2031 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-29 18:33:08 +00:00
cmpilato
360bdfd5a9 Remove redundant CHANGES line.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2030 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-24 15:15:24 +00:00
cmpilato
d4749c20f2 Add FAQ entry about installation docs.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2029 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-22 13:32:37 +00:00
cmpilato
bf7676d7f1 * lib/vcauth/svnauthz/__init__.py
(ViewVCAuthorizer._process_access_section): Add support for the
    "$anonymous" and "$authenticated" magic user specifications
    introduced in Subversion 1.5.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2028 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-20 16:12:30 +00:00
cmpilato
8d5d67888d Note per-root configuration override change.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2027 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-15 00:28:05 +00:00
cmpilato
08454df121 Add support for allowing/disallow the root listing view.
* lib/viewvc.py
  (view_roots): Check to see if the root listing view is an allowed
    one before serving it up.

* viewvc.conf.dist
  Add 'roots' to the description of, and default value of, allowed_views.

* lib/config.py
  (Config.set_defaults): Add 'roots' to the default value of
    cfg.options.allowed_views.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2026 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-15 00:22:05 +00:00
cmpilato
a5b8f9176f Get per-root overrides of authorizer stuffs working, and advertise
this feature in viewvc.conf.

NOTE: Root listing views still currently suffer a bit here.  We can't
just overlay per-root options as we loop over roots because each root
will wind up with the union of the overrides for roots previously
handled in the loop.  We either need to find a way to clone the Config
object before overriding its values with per-root options (so the
original Config object is untouched) or find an elegant way to
*unoverlay* per-root options.  I suspect we'll have better luck with
the former approach.

* lib/viewvc.py
  (Request.run_viewvc): Overlap per-root options *before* setting up
    the authorizer for the root because, you know, the authorizer or
    its configuration might be what's being overridden.

* viewvc.conf.dist
  Note the existence of (and way to use) the per-root configuration overrides.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2025 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-15 00:11:54 +00:00
cmpilato
badc9e3ff0 Expose the authenticated username in the templates.
* templates/docroot/styles.css
  (#vc_nav_header): Drop 'font-weight: bold'.

* templates/include/header.ezt
  Convert vc_nav_header contents into a 1-row, 2-column table
  featuring the nav path and (if present) the authenticated username.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2024 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-14 23:53:55 +00:00
cmpilato
9d6c204efb Merge 1.0.7 changes into CHANGES file (and fix a long line while here).
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2023 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-14 22:21:44 +00:00
cmpilato
429a9e5aed Bump the version named as the latest release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2022 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-14 22:09:35 +00:00
cmpilato
574de8ddac Minor tweaks to the release process docs.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2021 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-14 22:08:26 +00:00
cmpilato
cf5491852c Fix issue #373: Regression: "as text" view no longer transmits
Content-type: text/plain header.

* lib/viewvc.py
  (Request.run_viewvc): Add 'text/plain' to the list of content types
    allowed to be specified via the CGI query params.
  (view_checkout): Revert the change from r1978 which caused this to
    ignore the content-type query param; we'll go back to paying
    attention to that, and simply trust that Request.run_viewvc() has
    sanitized it.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2016 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-10-02 15:46:19 +00:00
cmpilato
d525dd0737 * lib/viewvc.py
(setup_authorizer): Use the prescribed mechanism for dynamically loading a
    submodule.

Patch by: Bernd Kuemmerlen <bkuemmer {at} gmx.net>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2011 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-09-22 18:57:48 +00:00
cmpilato
502b9891d4 Tigris.org homepage updates.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2010 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-09-16 19:36:39 +00:00
cmpilato
e72570dc20 Copy 1.0.6 changes into trunk CHANGES file.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2009 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-09-16 19:15:46 +00:00
cmpilato
1fa6bf4978 Lose fixed-width formatting of a URL.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2008 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-09-16 19:08:11 +00:00
cmpilato
f00bf732df Bump most recent release version in website note.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2007 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-09-16 19:07:50 +00:00
cmpilato
d13fd6f02a * lib/viewvc.py
(setup_authorizer): Avoid try/except/finally syntax, which isn't
    supported by some older Python versions.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2002 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-09-11 14:11:39 +00:00
cmpilato
ba0e4598d3 * viewvc.conf.dist
No longer recommend that folks set use_enscript (since it has been
  removed) and use_cvsgraph (since it seems most folks these days are
  using Subversion anyway).



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2001 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-09-10 14:40:33 +00:00
cmpilato
899de5536f * lib/viewvc.py
(setup_authorizer): Use the 'imp' module instead of exec() commands
    to load a dynamically-determined (and arbitrarily named module).

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2000 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-09-08 13:30:31 +00:00
cmpilato
5b8d3cf325 Finish issue #105 (add option hide_errorful_entries).
* viewvc.conf.dist
  (hide_errorful_entries): New.

* lib/config.py
  (Config.set_defaults): Init cfg.options.hide_errorful_entries to 0.

* lib/viewvc.py
  (view_directory): If cfg.options.hide_errorful_entries is enabled,
    skip any directory entries that carry errors.

* docs/upgrading-howto.html
  Note the new option.

* CHANGES
  Note this (and the previous) change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1998 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-08-21 13:56:30 +00:00
cmpilato
0855e910ac Add some svn:ignore properties.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1997 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-08-21 13:50:22 +00:00
cmpilato
fbb4e04dbc In the CVS vclib providers, mark entries which have no revisions on
the requested tag as 'absent', rather than calling such a situation an
error.  This is for issue #105 (add option hide_not_readable).

* lib/vclib/ccvs/bincvs.py
  (CVSDirEntry.__init__): Add 'absent' parameter and handling.
  (_get_logs): Rather than raise such as an error, not files which
    have no revs on the selected branch/tag as "absent" (a
    non-error-ful state).

* lib/vclib/ccvs/ccvs.py
  (CCVSRepository.dirlogs): Init the .entry member of the dirent.
  (InfoSink.admin_completed): If we found nothing for a particular
    tag, and we're looking at a file, mark the entry as absent.

* lib/viewvc.py
  (view_directory): If a CVS file is marked as absent (meaning, "No
    revisions found on the requested branch"), don't show it at all.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1996 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-08-21 13:37:46 +00:00
cmpilato
329ec7e9bf Reverse-merge changes made in r1536 and r1537 (in which our mod_python
modules were renamed), and merge r1933 (in which the 'imp' module is
used to more directly deal with the import cycle problem).

* docs/upgrading-howto.html
  Remove upgrading notes about renamed modules since, now, they aren't
  renamed any more.

* viewvc-install
  Note re-renamed paths.

* bin/mod_python/viewvc_mp.py,
* bin/mod_python/query_mp.py
  Rename these back ...

* bin/mod_python/viewvc.py,
* bin/mod_python/query.py
  ... to these, and use the 'imp' module to load libraries from
  specific locations.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1994 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-08-20 18:01:37 +00:00
cmpilato
e9d1da3b8f * lib/viewvc.py
(build_commit): Ahem.  And then commit the fixes necessary to make
    r1991 actually work.

NOTE TO SELF: Be sure to test the right version of the software before
              committing.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1992 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-08-20 17:12:39 +00:00
cmpilato
3f8ecf1b67 * lib/viewvc.py
(build_commit): Remove duplicated authz checks, and try to tighten
    up the path/rev used in those checks.  While here, fix issue #368's
    complaint about the RSS feeds throwing an exception due to use of a
    non-existent variable.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1991 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-08-20 17:09:27 +00:00
cmpilato
b35d6b27d0 * lib/viewvc.py
(calculate_mime_type): Gracefully handle exceptions returned from
    .itemprops(), and fall back to guessing based on path name.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1990 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-08-20 14:45:34 +00:00
cmpilato
3738505ad7 * lib/vclib/svn/svn_repos.py
(LocalSubversionRepository._revinfo_raw): Fix a logic-o.  It's if
    a copy source path is *not* authorized for read that we want to say
    the original path was not copied.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1989 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-08-20 14:40:13 +00:00
cmpilato
a74cefa63c Finish issue #361 - Support reasonable copy-pasting of the path.
* templates/include/header.ezt
  Collapse the EZT logic for the navpath into a single line[1], and
  wrap the path separators (/) with custom styles.

* templates/docroot/styles.css
  (.vc_navheader .pathdiv): Define custom style with some left-right padding.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1987 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-08-18 18:13:12 +00:00
cmpilato
b90ed5fffa * lib/blame.py
Only import vclib.ccvs.blame for the one function that cares.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1986 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-08-13 20:13:15 +00:00
cmpilato
c264c62e3d Finish issue #364 - Recognize Subversion's svn:mime-type property.
* lib/viewvc.py
  (Request.run_viewvc): No longer set the request's mime_type member.
  (calculate_mime_type): New helper function.
  (common_template_data): Add optional 'mime_type' parameter, passed
    to get_file_view_info().
  (get_file_view_info): Use guess_mime() as the MIME type fallback,
    instead of consulting the now-absent request.mime_type.
  (markup_or_annotate, view_log, view_checkout, build_commit): Use 
    calculate_mime_type().

* templates/file.ezt
  Display a file's MIME type.

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1982 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-08-05 16:25:38 +00:00
cmpilato
286b8a2925 Update the URL reference in light of r1978 and r1979.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1980 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-07-28 19:26:35 +00:00
cmpilato
3a499652df Finish issue #354: Lose ability to set Content-type via CGI params.
For security purposes (because spoofing Content-type headers can have
undesirable side effects), no longer recognize 'content-type' CGI
parameters whose values aren't one of the magic MIME types ViewVC uses
for its own (non-MIME-type-setting) purposes.

* lib/viewvc.py
  (Request.run_viewvc): Ignore content-type CGI parameters whose
    values aren't one of the magic ViewVC MIME types used to indicate
    that folks want the markup view.
  (view_checkout): No longer consult the query parameters for a MIME type.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1978 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-07-28 18:51:51 +00:00
cmpilato
d272630eac Fix issue #360 - Purge functionality can orphan rows in checkins table.
* lib/cvsdb.py
  (CheckinDatabase.sql_delete): Add keep_fkey parameter, used to
    prevent deletion of keys that are still in use in the 'checkins'
    table.
  (CheckinDatabase.PurgeRepository): Pass keep_fkey parameter when
    deleting rows from tables other than 'checkins'.

* bin/cvsdbadmin,
* bin/svndbadmin
  Update script usage messages to indicate that rebuilding includes
  purging.

Patch by: Larry Shatzer (larrys {at} gmail.com)
          (Tweaked by me.)

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1974 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-07-07 13:21:48 +00:00
cmpilato
cb79c1f793 Add support for Subversion authz-file aliases, a feature new to
Subversion 1.5.  (This was filed as issue #359.)

* lib/vcauth/svnauthz/__init__.py
  (ViewVCAuthorizer._get_paths_for_root): Parse the 'aliases' section,
    and fix username checks to include aliases, too.

Patch by: Thom May <thom {at} clearairturbulence.org>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1973 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-30 18:46:07 +00:00
cmpilato
43337f8b0f * lib/vclib/svn/svn_ra.py (SelfCleanFP.readlines): New.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1972 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-26 08:00:21 +00:00
cmpilato
7f149c01d0 More authz stuff for remote SVN repositories.
* lib/vclib/svn/svn_ra.py
  (date_from_rev): Removed as unused.
  (LogCollector): Leave an authz-related TODO comment.
  (RemoteSubversionRepository.rawdiff): Hook into the authz-aware code.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1971 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-26 07:57:21 +00:00
cmpilato
2df94a5d37 Add some more authz checks for remote SVN repositories, and fix some
inconsistencies (versus local SVN repository views) in the revision
returned from openfile().

* lib/vclib/svn/svn_ra.py
  (LastHistoryCollector): Removed.  The main logic of this class now
    lives (with major tweaks) in RemoteSubversionRepository._revinfo_raw().
  (_get_rev_details): Removed.
  (RemoteSubversionRepository.open): Init _revinfo_cache member.
  (RemoteSubversionRepository.openfile): Use _get_last_history_rev()
    for the returned revision.
  (RemoteSubversionRepository.dirlogs): Use self.revinfo() now.
  (RemoteSubversionRepository.revinfo): Rework as a wrapper around
    _revinfo_raw().
  (RemoteSubversionRepository.rawdiff): Add some comments.
  (RemoteSubversionRepository._get_last_history_rev): New.
  (RemoteSubversionRepository._revinfo_raw): New, taking from old
    LastHistoryCollector interface, but reworked toward the goal of
    some authz interaction.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1970 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-26 07:52:18 +00:00
cmpilato
91c5418de7 Add a helper function, use it, and fix a little authz oopsy along the way.
* lib/vclib/svn/svn_repos.py
  (_path_parts): New, and now used throughout for path-to-parts
    conversions.
  (_cleanup_path): Rewrite as a wrapper around _path_parts().
  (_fs_path_join): Rewrite as a wrapper around _cleanup_path().
  (LocalSubversionRepository._revinfo_raw): Fix an authz check made
    against the wrong path.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1969 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-26 07:43:52 +00:00
cmpilato
1adb46f2b3 Fix a regression against 1.0.x which caused the wrong revision metadata
to be displayed for certain rev != rev-in-which-item-was-changed
Subversion markup and annotate displays.

* lib/viewvc.py
  (common_template_data): Add optional 'revision' argument, used to
    override other automated revision-figuring-outin' mechanisms.
  (markup_or_annotate): Use the revision returned by the openfile() or
    annotate() interfaces in the call to common_template_data().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1968 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-26 06:47:46 +00:00
cmpilato
410a80df6b Address issue #358 as best as possible (I believe).
* lib/viewvc.py
  (build_commit): Perform authz checks, dropping unreadable paths and
    stripping log messages for commit groupings with contain
    unreadable paths.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1967 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-25 06:43:23 +00:00
cmpilato
eb6c6964c4 Make the check-the-database-for-roots-before-creating-RSS-and-query-links
behavior optional (since the penalty otherwise could be deemed too
high to be worth paying).

* viewvc.conf.dist
  (check_database_for_root): New.

* lib/config.py
  (Config.set_defaults): Populate default cvsdb.check_database_for_root value.

* lib/viewvc.py
  (is_querydb_nonempty_for_root): Only do database root checks if
    cfg.cvsdb.check_database_for_root is set.

Patch by: Larry Shatzer <larrys {at} gmail.com>
          (Tweaked by me.)

* lib/cvsdb.py
  (GetCommitListFromRCSFile): Update call to Repository.itemlog().

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1966 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-23 23:50:52 +00:00
cmpilato
e157f923ed * lib/cvsdb.py
(GetCommitListFromRCSFile): Update call to Repository.itemlog().

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1965 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-23 23:50:45 +00:00
cmpilato
a8a6d5c10b I *thought* something seemed wrong. We don't *want* ViewVC to claim
some path is forbidden.  We want it to claim the path doesn't exist at
all!  So remove some unused cruft from a previous manifestation of the
authz support.

* lib/debug.py
  (ViewVCNotAuthorizedException): Remove as unused.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1964 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-21 00:35:26 +00:00
cmpilato
473951fa96 * lib/debug.py
(ViewVCNotAuthorizedException.__init__): Use "403 Forbidden" instead
    of the bogus "501 Not Authorized" status.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1963 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-21 00:28:11 +00:00
cmpilato
0aaeeb4398 * bin/standalone.py
(cli): Add 'host' to the list of accepted long options.

Patch by: Larry Shatzer, Jr. <larrys {at} gmail.com>



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1962 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-19 20:06:26 +00:00
cmpilato
9761bb7818 Add CHANGES line for issue #357 change.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1961 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-19 20:04:30 +00:00
cmpilato
46f42bf09a Finish issue #357.
Only populate rss_href and queryform_href if query support is enabled
*and* the current root has a presence in the commits database.

* lib/viewvc.py
  (common_template_data): Use is_querydb_nonempty_for_root() to
    conditionally set rss_href and queryform_href.
  (is_querydb_nonempty_for_root): New.

Patch partially by: Larry Shatzer, Jr. <larrys {at} gmail.com>
                    (I butchered it.)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1960 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-19 19:51:13 +00:00
cmpilato
24984a78d1 * bin/svndbadmin
Import 'vclib' so bad stuff doesn't happen.  (Such as referencing a
  non-imported module.)



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1959 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-19 19:48:17 +00:00
cmpilato
ec3deccc34 * viewvc.conf.dist
Fix example use of 'svn_dir' to 'svn'.

Patch by: Larry Shatzer, Jr. <larrys {at} gmail.com>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1958 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-19 14:50:39 +00:00
cmpilato
7e85c56317 Formatting changes only.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1957 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-13 17:29:15 +00:00
cmpilato
371a97fbb2 * viewvc.conf.dist
(hide_cvsroot): Move closer to 'authorizer', and note that someday
    it may go away.
  (diff_format): Document the 'f' option.
  (hr_breakable): Tweak description.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1956 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-13 15:09:45 +00:00
cmpilato
3effe02607 * viewvc.conf.dist
(log_sort): Rename 'cvs' value to 'none'.

* docs/upgrading-howto.html
  Note this change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1955 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-13 14:54:33 +00:00
cmpilato
7e5d3b27b1 Some intra-page link tweaks.
* lib/viewvc.py
  (Request.run_viewvc): Special-case the handling of self.where,
    self.pathtype, and self.path_parts when we're looking at the
    revision or root-listing views.
  (common_template_data): Take the current directory revision into
    account when generating a revision view link from the directory view.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1954 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-12 19:36:20 +00:00
cmpilato
079b596424 Interpret the per-template override options as relative to the
configured template directory now.

* lib/viewvc.py
  (get_view_template): Rework this to interpret per-template overrides
    as relative to the template-dir, which itself is relative to the
    configuration location.

* viewvc.conf.dist
  (templates): Strip 'templates/' from the sample template locations,
    and note that these paths are relative to the configured template
    directory.

* docs/upgrading-howto.html
  Note this change of interpretation.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1953 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-12 18:24:28 +00:00
cmpilato
fb0264a563 Make annotations work again for Subversion repositories.
* lib/vclib/svn/svn_repos.py
  (LocalSubversionRepository.annotate): Keep the return value from
    self.itemtype() so we can pass it to _get_history().

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1952 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-12 18:20:09 +00:00
cmpilato
c58fc4008b Update the upgrade documentation.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1951 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-12 17:40:17 +00:00
cmpilato
16ccaa931c Add vclib-specific path canonicalization and root-parent expansion
routines (and use them).

Background: I had delusions of adding root-parent expansion for remote
Subversion repositories, but I lacked the requisite motivation.
Still, these are good changes which further move VC-specific knowledge
out of ViewVC's core moddules and back into the vclib abstraction
layer, which such knowledge belongs.

* lib/viewvc.py
  (Request.run_viewvc): Use vclib.*.canonicalize_rootpath() to get
    version-control-specific rootpath canonicalization.
  (expand_root_parents, find_root_in_parents): Rework to use the
    expand_root_parent() vclib implementations.
  (locate_root): Docstring typo fix.

* lib/vclib/ccvs/__init__.py
  (canonicalize_rootpath, expand_root_parent): New.
  (CVSRepository): Use canonicalize_rootpath().

* lib/vclib/svn/__init__.py
  (_re_url): Make module-global.
  (canonicalize_rootpath, expand_root_parent): New.
  (SubversionRepository): Use canonicalize_rootpath().

* bin/cvsdbadmin
  (__main__): Use canonicalize_rootpath() before passing the root path
    to vclib.ccvs.CVSRepository().

* bin/svndbadmin
  (__main__): Use canonicalize_rootpath().

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1950 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-12 16:26:33 +00:00
cmpilato
656a46ad8c Don't specify how syntax highlighting is provided.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1949 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-12 14:44:17 +00:00
cmpilato
8404a211c0 Tweak website credits text just a bit.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1948 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-11 18:27:06 +00:00
cmpilato
71d3617c0d Shrink the title image a bit.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1947 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-11 18:23:49 +00:00
cmpilato
67d4261729 Add favicon.ico, and try to settle on a background color.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1946 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-11 18:17:54 +00:00
cmpilato
066b22585a More color tweaks.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1945 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-11 18:13:12 +00:00
cmpilato
0ad2b1f095 Re-brand the viewvc.org pages.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1944 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-11 18:07:57 +00:00
cmpilato
f89786a6fa * lib/vclib/svn/svn_ra.py
Fix a syntax error.  (This is what I get for testing a fix on one
  machine, but trying to commit an untested duplicate change from
  another.)



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1943 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-06 18:08:50 +00:00
cmpilato
417e2bbedf * lib/vclib/svn/svn_ra.py
(RemoteSubversionRepository.itemlog): Don't index into an empty
    path_parts list.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1942 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-05 20:12:27 +00:00
cmpilato
d6bae15b7d * CHANGES: Note the change committed in r1940.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1941 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-05 18:57:43 +00:00
cmpilato
cad4e52746 Finish issue #351, which solves a regression against 1.0.x *and*
improves upon things to boot (finishing issue #339)!

This implements support for a configuration Subversion runtime config
directory location, which is useful for employing cached authn
credentials against remote repositories that require them, as well as
avoiding complaints the Subversion library might make when trying to
ensure the existence of a runtime configuration directory.

* viewvc.conf.dist
  (options.svn_config_dir): New.

* lib/config.py
  (Config.set_defaults): Initialize options.svn_config_dir variable.

* lib/viewvc.py
  (Request.run_viewvc): Update call to vclib.svn.SubversionRepository().
  (list_roots): Update call to vclib.svn.SubversionRepository().

* lib/vclib/svn/__init__.py
  (SubversionRepository): Add 'config_dir' parameter, passed to
    updated calls to RemoteSubversionRepository() and
    LocalSubversionRepository()

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.__init__): Add 'config_dir' parameter,
    and squirrel it away in a member variable.
  (RemoteSubversionRepository.open): Add the key thing I've been
    missing for years to make custom runtime config directories work:
    setting the configuration directory location in the auth baton!
    God bless Eric Gillespie <epg@pretzelnet.org>.

* lib/vclib/svn/svn_repos.py
  (LocalSubversionRepository.__init__): Add 'config_dir' parameter,
    and squirrel it away in a member variable (currenty unused).

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1940 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-05 18:52:45 +00:00
cmpilato
9acf966bd7 Make dates appear again in remote Subversion directory views.
* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.dirlogs): Don't try to do
    string-to-number conversion of the entry date -- we already have
    the numeric value.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1938 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-03 18:00:37 +00:00
cmpilato
6c635e75a4 * lib/viewvc.py
(check_freshness): Move a comment closer to the code it addresses.
  (markup_or_annotate): Restore cache control header checks
    inadvertantly lost in a recent commit.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1937 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-03 17:11:34 +00:00
cmpilato
5b51bf9008 Finish issue #233: tarball entries from Subversion repositories don't
preserve executability.

* lib/vclib/__init__.py
  (Repository.isexecutable): New.

* lib/vclib/ccvs/bincvs.py
  (BaseCVSRepository.isexecutable): New.

* lib/vclib/svn/svn_repos.py
  (LocalSubversionRepository.isexecutable): New.

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.isexecutable): New.

* lib/viewvc.py
  (generate_tarball): Use repos.isexecutable() to get the executable
    bit for file tarball members.  (This loses old code which directly
    consulted the ,v file in the CVS case.)

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1936 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-03 17:02:55 +00:00
cmpilato
b5a2dd486d * lib/viewvc.py
(_get_diff_path_parts): Store the result of _path_parts() in
    'parts', not 'path', to avoid raising an exception when
    deferencing the former.

Found by: Jay Chang <Jay.Chang {at} intrado.com>
          (Folks who test nightly builds rawwwwwk.)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1935 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-03 00:35:37 +00:00
cmpilato
041c83fabe * lib/vclib/svn/svn_ra.py
Begin adding authz checks where necessary.  Still need to take care
  of rev metadata filtering and history truncation.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1934 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-02 19:34:43 +00:00
cmpilato
850422c786 * lib/vclib/svn/svn_repos.py
(LocalSubversionRepository): Throughout, don't clobber 'rev'
    variables before passing them off to .itemtype(), and ensure there
    *is* a local 'path' variable in case the .itemtype() failure case
    (which expects one) is raised



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1933 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-02 19:32:01 +00:00
cmpilato
1273f1da81 Add missing authz checks for rcsparse-backed CVS module.
* lib/vclib/ccvs/ccvs.py
  (CCVSRepository.dirlogs, CCVSRepository.itemlog,
   CCVSRepository.rawdiff, CCVSRepository.annotate,
   CCVSRepository.openfile): Add missing authz checks.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1932 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-02 18:52:46 +00:00
cmpilato
c1b351f78b * lib/vclib/ccvs/bincvs.py
(BaseCVSRepository, BinCVSRepository): Use Repository.itemtype()
    throughout as a combination authz check and file type sanity check.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1931 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-02 18:48:16 +00:00
cmpilato
c4ad7fc501 * viewvc.conf.dist
(show_subdir_lastmod): Tweak description to imply that this feature
    is for CVS only.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1930 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-02 17:59:03 +00:00
cmpilato
31a1a6f49c Ensure zero-padded dates in the nightly tarball names.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1929 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-06-02 17:15:03 +00:00
cmpilato
b0fb8b3ad7 * templates/include/dir_header.ezt,
* templates/include/dir_footer.ezt,
* templates/directory.ezt
  Move search box to metadata header section, and eliminate redundant "Current
  Search" header.  Make properties show up for dir_new.ezt, too.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1928 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-30 21:12:57 +00:00
cmpilato
0d0aafe7b2 * lib/vclib/svn/svn_ra.py
(svn_client_ls3): New helper (to deal with brokenness in Subversion
    1.4.x Python bindings).
  (RemoteSubversionRepository.itemlog, 
   RemoteSubversionRepository._get_dirents): Use svn_client_ls3 helper.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1927 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-30 21:02:31 +00:00
cmpilato
0fb5f8eb85 Workaround some Subversion 1.4.x Python bindings shortcomings.
* lib/vclib/svn/svn_ra.py
  (SVN_INVALID_REVNUM): Try to set from core.SVN_INVALID_REVNUM, but
    fallback to an explicit -1.
  (RemoteSubversionRepository.created_rev): Use SVN_INVALID_REVNUM
    compatability value.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1926 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-30 20:45:05 +00:00
cmpilato
19643d366c * lib/viewvc.py
(markup_stream_pygments): CGI-escape the original blame text lines
    so that if they wind up getting used, the output is valid.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1925 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-30 18:05:32 +00:00
cmpilato
4492bbaa1b * lib/viewvc.py
(markup_stream_pygments): Use 'utf-8' output in the Pygments HtmlFormatter().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1924 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-30 17:57:50 +00:00
cmpilato
e41d5a9064 Update online help documents.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1923 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-30 17:32:29 +00:00
cmpilato
2a4b0eeb99 Promote a ViewVC logo idea to The Real Thang(tm).
* notes/logo
  New directory.

* notes/logo/viewvc-logo.svg,
* notes/logo/viewvc-logo.odg,
* notes/logo/viewvc-logo.pdf
  Moved (with some margin tweaks) from ...

* notes/logo-ideas
  ... this directory, which is now deleted.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1922 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-30 17:07:33 +00:00
cmpilato
d768f2c850 Update ViewVC logo, and add favicon.
* templates/docroot/images/logo.png
  Removed.

* templates/docroot/images/viewvc-logo.png,
* templates/docroot/images/favicon.ico
  New.

* templates/docroot/help_dirview.html,
* templates/docroot/help_log.html,
* templates/docroot/help_query.html,
* templates/docroot/help_rootview.html
  Update icon references to point to viewvc-logo.png.

* templates/include/header.ezt
  Update icon reference to point to viewvc-logo.png, and add reference
  to new favicon.ico.

* templates/docroot/styles.css
  Use sans-serif fonts.  Serifs are so 1993.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1921 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-30 17:01:58 +00:00
cmpilato
88d4d62c39 Merge the work done on the 'merged-file-views' branch in full. For
the details of those changes, run:

   svn log --stop-on-copy --verbose \
   http://viewvc.tigris.org/svn/viewvc/branches/merged-file-views@1917

Basically, this change unifies the annotate and markup views at the
cost of dropping support for all but one of our syntax highlighting
engines -- Pygments.  (So, goodbye to 'enscript', 'highlight',
'source-highlight', 'py2html', and 'php'.)  By settling on a single
markup engine (and a Python-module-based one with a BSD license, at
that), we:

   * added syntax highlighting to the annotate view

   * added line numbers to the markup view (prior to this, you
     sometimes had 'em and sometimes didn't, depending on which
     highlighting engine you used).

   * essentially unified the markup and annotate views -- they even
     share the same template now.

   * can ship ViewVC with Pygments and syntax highighting enabled so
     folks don't have to do additional config work to get that feature.

This change may be controversial.  Depending on the overlap of
supported syntaxes across the various engines we supported prior to
this change, we may be losing support for some languages.  And we're
also losing URL markup-ing (which was, again, partially supported
depending on the markup engine you were using).  Somebody is going to
get upset that their pet benefit is now missing.  I understand that.
I'm optimistic, though, that we can identify the lossages that really,
really matter, and address them in low-maintenance-hassle ways using
this slimmer, trimmer codebase as the baseline.

Also in this commit (in addition to the merged changes):

* templates/docroot/styles.css
  Minor stylation tweaks.

* viewvc.conf.dist
  (enable_syntax_coloration): Tweak the comment to indicate that
    Pygments is required for syntax coloration to work.

* CHANGES
  Note these changes.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1918 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-30 14:38:09 +00:00
cmpilato
64c38e8248 * nightly/build-viewvc-snapshot
Duh.  Actually removing the temporary directory.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1915 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-30 13:15:31 +00:00
cmpilato
3f8390b18a * lib/viewvc.py
(MarkupPygments.__call__): The parameter is "nowrap", not "linenowrap".


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1910 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-23 20:04:50 +00:00
cmpilato
62883ba20b Avoid having the Pygments integration keeping two copies of the file
contents in memory at once.  One is bad enough, but will have to do
for now.

* lib/viewvc.py
  (MarkupPygments): New, constructed from the primary logic that used
    to live in ...
  (markup_stream_pygments): ... this function, which is now just a thin
    wrapper around MarkupPygments().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1909 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-23 19:40:52 +00:00
cmpilato
e400232039 Unify the option for enabling line numbers, and add support for line
number generation to the Pygments integration logic.

* viewvc.conf.dist,
* lib/config.py
  (Config.set_defaults): Collapse 'source_highlight_line_numbers' and
    'highlight_line_numbers' into just markup_line_numbers.

* lib/viewvc.py
  (MarkupHighlight.__init__, MarkupSourceHighlight.__init__): Trace
    option renames.
  (markup_stream_pygments): Recognize the markup_line_numbers option,
    and when set, use a custom LineNoHtmlFormatter class to generate
    line numbers similar to the way 'highlight' does.

* templates/docroot/styles.css
  (.line, .linenum): Tweak comment.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1908 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-23 19:22:33 +00:00
cmpilato
12c81ffae6 As part of issue #394, add support for integration with Pygments, the
Python-based syntax highlighting library.

* lib/config.py
  (Config.set_defaults): Add cfg.options.use_pygments option with a
    default value of 0.

* viewvc.conf.dist
  (use_pygments): Add use_pygments option under [options].

* lib/viewvc.py
  (markup_stream_pygments): New.
  (markup_or_annotate): Call markup_stream_pygments() before falling
    back to the command-line program options.

* templates/docroot/styles.css
  Add stylations for Pygments.

* CHANGES
  Note this change.

* INSTALL
  (TO THE IMPATIENT): Add Pygments to the list of supported
    highlighting engines.
  (ENABLING SYNTAX COLORATION): Rewrite this.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1906 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-23 18:42:43 +00:00
cmpilato
c252e41fc4 * bin/make-database
(__main__): Add some comments, and don't use the --host option with
    'mysql' if you don't have to.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1904 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-23 16:27:51 +00:00
cmpilato
940bac640b Add support for remote creation of ViewVC checkins database, and
handle Control-C more cleanly.

* bin/make-database
  (INTRO_TEXT): Update this text for accuracy and clarity.
  (__main__): Prompt the user for the database server hostname
    (defaulting to 'localhost'), and use the result with the --host
    argument to 'mysql'.  While here, catch the KeyboardInterrupt
    exception and silently terminate rather than raising a stacktrace.

Patch partially by Philip M. Gollucci <pgollucci {at} p6m7g8.com>.

Also:

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1902 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-23 12:41:46 +00:00
cmpilato
20c13ec06a * lib/viewvc.py
(view_directory): Always show the search form if enabled.  (If
    templates want to hide it when there are no files to search, they
    can.)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1899 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-22 18:18:48 +00:00
cmpilato
8274303424 * lib/viewvc.py
(common_template_data): Generate RSS hrefs for files, too, by using
    a directory search of its parent limited to the specified file.

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1898 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-22 17:58:21 +00:00
cmpilato
e689f77881 * templates/include/dir_footer.ezt
Fix an old reference to a long-since-renamed data dictionary object,
  and while here, make the regex search form look mo' betta.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1896 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-22 17:33:58 +00:00
cmpilato
43f5b14afa Continuing the endless quest to purge all HTML generation from
ViewVC's core libraries, turn the form hidden-values objects from HTML
strings to iterable objects that templates can use to *make* HTML strings.

* lib/viewvc.py
  (Request.get_form): Now prepare hidden values as an iterable list of
    objects with .name and .value attributes.
  (common_template_data): Don't add 'change_root_action' and
    'change_root_hidden_values' data dictionary items.
  (prepare_hidden_values): Remove as unused.

* templates/include/diff_form.ezt,
* templates/include/dir_footer.ezt,
* templates/include/dir_header.ezt,
* templates/include/paging.ezt,
* templates/include/pathrev_form.ezt,
* templates/include/sort.ezt,
* templates/diff.ezt,
* templates/log_table.ezt,
* templates/query_form.ezt,
* templates/revision.ezt
  Iterate over hidden-values items to generate <input type="hidden"
  .../> output.

* docs/upgrading-howto.html,
* docs/template-authoring-guide.html
  Note these changes.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1894 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-21 19:51:26 +00:00
cmpilato
263920a326 Give template authors the ability to reveal the active username.
* lib/viewvc.py
  (common_template_data): Add request.username to the common template
    data as 'username'.

* docs/template-authoring-guide.html
  Document the addition.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1893 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-21 13:21:14 +00:00
cmpilato
97ed841022 Add some variations on the eye theme.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1892 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-16 17:18:01 +00:00
cmpilato
802cf3cc5a Group some similarly-colored regions.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1891 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-15 14:30:05 +00:00
cmpilato
2253c4361c Fix issue #348 by making the 'co' parser more resilient to multiple
"special" lines of output.

Previously, output like the following would choke because the code was
able to deal with the first "special" line (the warning about unknown
phrases), but then wasn't able to handle the second "special" line
(about no side branches).

   $ co -pTAG_NAME /cvs/repos/some-file,v
   /cvs/repos/some-file,v  -->  standard output
   co: /cvs/repos/some-file,v: warning: Unknown phrases like `commitid ...;' are present.
   co: /cvs/repos/some-file,v: no side branches present for 1.1

If either of these lines had been the only special ones, stuff worked
fine.  But in concert, it all fell apart.

* lib/vclib/ccvs/bincvs.py
  (_parse_co_header): Use a line-reading loop instead of trying to
    expect certain output on specific lines.

Verified by: Ross Becker <ross {at} trapezenetworks.com>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1888 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-14 16:53:00 +00:00
cmpilato
debb3c26a3 Make the .itemprops() interface work for remote Subversion files, too.
* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.itemprops): Use svn_client_proplist2()
    instead of the RA interfaces.
  (RemoteSubversionRepository.created_rev): Rework this a little to
    handle the missing path case, and add some comments about the
    implementation.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1887 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-13 13:53:45 +00:00
cmpilato
2e6f3713c9 At least in one area of the codebase, avoid requiring a Python-2.3-ism.
* lib/config.py
  (Config._get_parser_items): New.
  (Config.get_authorizer_params): Use _get_parser_items() instead of
    the parser's items() function directly.

Reported by: Michael Leib <michael.leib {at} hypermediasystems.com>
(and even better...)
Verified by: Michael Leib <michael.leib {at} hypermediasystems.com>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1886 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-12 21:13:14 +00:00
cmpilato
e7a8f0336f Don't show dead files at all when using search-based filtering.
* lib/viewvc.py
  (view_directory): Do search-based filtering before filtering on dead
    files (while still avoiding searches on dead files)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1883 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-12 18:48:53 +00:00
cmpilato
f81abbfd39 Avoid problems caused by trying to search files in a given CVS tag
that don't exist in that tag by doing tag-based filtering first, then
fulltext searching.  I think this fixes issue #346.

* lib/viewvc.py
  (search_file): New function, cored from the guts of ...
  (search_files): ... this now-removed function.
  (view_directory): Narrow the file field down by tag selection first
    before doing fulltext searches.

Reported by: Ross Becker <ross {at} trapezenetworks.com>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1882 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-12 18:23:49 +00:00
cmpilato
555614bf5d Reduce the size of the 'highlight dots', and add an SVG version.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1881 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-05-06 23:03:06 +00:00
cmpilato
14e815a39b Don't ignore whitespace by default. That can be confusing to folks
expecting a diff.

* lib/config.py
  (Config.set_defaults): Default hr_ignore_white to 0 now.

* viewvc.conf.dist
  (hr_ignore_white): Default to 0 now.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1880 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-29 02:05:01 +00:00
cmpilato
e33aea9c56 Note the bugfix made in r1878.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1879 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-29 01:00:49 +00:00
cmpilato
3a3f309545 Fix issue #259 - the latest revision details page gets cached incorrectly.
* lib/viewvc.py
  (view_revision): Tell browsers not to cache the view of the youngest
    revision in a Subversion repository.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1878 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-29 00:59:09 +00:00
cmpilato
48eb269c38 Support a couple of different flavors of email address mangling.
* viewvc.conf.dist
  Update description of mangle_email_addresses option.

* lib/viewvc.py
  (mangle_email_addresses): New helper function.  Now supports a level of
    obfuscation without data loss.
  (htmlify): Use mangle_email_addresses() for address mangling.
  (format_log): Test for an explicit mangling level.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1877 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-28 19:20:17 +00:00
cmpilato
f30ceb4336 * viewvc.conf.dist
Clarify that only one authorizer can be in use at a time.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1876 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-28 18:25:06 +00:00
cmpilato
efd0ac1c26 Fix some URI encoding level issues with remote Subversion repository.
Noticed (and partial patch) by Jeffrey Klein <Jeffrey.Klein {at}
priorityhealth.com>.

* lib/vclib/svn/svn_ra.py
  Import urllib.
  (RemoteSubversionRepository._geturl): New helper function.
  (temp_checkout, RemoteSubversionRepository.openfile,
   RemoteSubversionRepository.itemlog, RemoteSubversionRepository.annotate, 
   RemoteSubversionRepository._get_dirents): Use the new .geturl() helper
    function.
  (RemoteSubversionRepository.itemprops): Wrap svn_ra_get_dir() in a
    try/except block to deal with older, busted versions of that AI.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1875 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-28 18:11:34 +00:00
cmpilato
f5cb5c1517 * lib/vclib/svn/svn_ra.py
(RemoteSubversionRepository.created_rev): Rename 'full_name'
    parameter to 'path' for consistency with other interfaces.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1874 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-28 18:05:45 +00:00
cmpilato
3d2cf8380d Lose gzip-binary-using fallback code, and actually make the
allow_compress option do something useful.

. o O ( What other dead code exists in this software? )

* lib/viewvc.py
  Import the 'gzip' module unconditionally.
  (Request.__init__): Determine if gzip output encoding is allowed.
  (get_writeready_server_file): New.
  (download_tarball): Lose the code that falls back to using a gzip
    binary.  Use get_writeready_server_file()
  (generate_page, view_checkout, view_cvsgraph_image, view_doc,
    view_patch): Use get_writeready_server_file(), allowing it to do
    server header output finalization.

* lib/config.py
  (Config.set_defaults): No longer initialize self.utilities.gzip.
    Now initialize cfg.option.allow_compress to 0.

* viewvc.conf.dist
  (utilities.gzip): Lose.
  (options.allow_compress): Lose note that indicates that 'gzip' must
    be installed and accessible in the program path.

* docs/upgrading-howto.html
  Don't note the addition of cfg.utilities.gzip ... because I just
  un-added it.

* CHANGES
  Note support for gzip-encoded output.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1873 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-23 16:18:05 +00:00
cmpilato
e11d706f30 * lib/viewvc.py
(view_revision): Use repos.get_youngest_revision() instead of
    peeking at repos.youngest directly.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1872 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-22 18:58:35 +00:00
cmpilato
d2d405513e Add 'viewvc' text to the logo.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1871 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-22 16:53:57 +00:00
cmpilato
45cf2fa972 Cleanup the design a bit: contrast the greens some more, thicken the 'V'
border, and in general pay closer attention to line landings and such.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1870 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-22 16:04:59 +00:00
cmpilato
89b012eb9f Restore website files to XHTML validation standards.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1869 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-21 20:04:50 +00:00
cmpilato
2c6ccc0191 Add some ViewVC logo ideas I've been sitting on for a while.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1868 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-18 15:48:24 +00:00
cmpilato
acff76174e Add upgrading notes about the removal of 'roots' from most views.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1867 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-17 20:25:29 +00:00
cmpilato
5fb74427f2 Remove the roots collection from the common-to-every-page data
dictionary stuffs.  It can be expensive to generate (especially when
authorization is in place) and brings little value considering we have
a roots listing view.  The sole known casualty in this change is the
little drop-down roots listing box, which is often one of the first
customizations (removing this) that folks make to their ViewVC
instances anyway.

* lib/viewvc.py
  (find_root_in_parents, locate_root): New functions.
  (common_template_data): Move the root listing data dictionary stuff ...
  (view_roots): ... to here.  Now uses expand_root_parents().
  (load_config): This, however, no longer uses expand_root_parents.
  (Request.run_viewvc): Use locate_root() to find a requested root
    name rather than expecting cvs_roots and svn_roots to be fully
    populated.

* templates/include/header.ezt
  Lose the root listing drop-down box, and de-table-ize the breadcrumbs.

* templates/docroot/styles.css
  (.vc_navheader): Add some padding.

* docs/template-authoring-guide.html
  Move the 'roots' stuff from the COMMON template data collection to
  the section specific to the root listing view.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1865 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-17 19:52:30 +00:00
cmpilato
4f45a6b364 Minor code refactoring.
* lib/viewvc.py
  (expand_root_parents): New, factored out of ...
  (load_config) ... this.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1864 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-17 18:23:51 +00:00
cmpilato
f38dfba74d Fix some inconsistencies in the way the roots listing is handled and
referred to when root_as_url_component is disabled.

* lib/viewvc.py
  (Request.run_viewvc): Only assume the default rootname if we're not
    in root_as_url_component mode *and* we're aren't being asked to view
    the root listing.
  (common_template_data): Always calculate a roots_href.  Also,
    gracefully deal with request.rootname being None.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1863 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-17 17:07:28 +00:00
cmpilato
f97eeac785 * lib/vclib/ccvs/ccvs.py
(CCVSRepository.rawdiff): Update calls to itemlog() overlooked in r1857.

Found by: Daniel Berlin <danielberlin {at} tigris.org>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1862 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-17 12:42:19 +00:00
cmpilato
f8ae6503fd * lib/viewvc.py
(common_template_data): Remove an obsolete TODO comment.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1861 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-16 20:51:20 +00:00
cmpilato
7cdabe099a * CHANGES
Add a note about recent pagination improvements.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1860 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-15 18:41:33 +00:00
cmpilato
e8123f68c2 Merge changes from the 'log-paging' branch:
$ svn merge -c1849,1850,1853,1854,1855,1856 \
    http://viewvc.tigris.org/svn/viewvc/branches/log-paging

This brings sliding-window-style pagination to the log revision view.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1857 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-15 18:17:02 +00:00
cmpilato
c1d3602bf3 * lib/vclib/svn/svn_ra.py
(RemoteSubversionRepository.itemprops): Pass the relative path to
    svn_ra_get_dir(), not the full URL.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1851 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-11 20:30:31 +00:00
cmpilato
18954aa9a9 Fix another bug in directory views that appeared when pagination was
enabled (in CVS).

* lib/viewvc.py
  (view_directory): Init the DirEntry.dead field.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1847 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-11 18:30:32 +00:00
cmpilato
c227c0a6e3 Fix a bug in directory views that appeared when pagination was enabled.
* lib/viewvc.py
  (view_directory): Init the DirEntry.lockinfo field.  (moral: The
    problem with cheating is that you eventually get caught.)



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1846 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-11 14:53:55 +00:00
cmpilato
4783fa5642 * lib/viewvc.py
(_legal_params): Move some params to a new grouping labeled as
    deprecated.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1845 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-11 14:52:27 +00:00
cmpilato
e2b02ff5f2 Add CHANGES item for property display.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1842 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-09 20:16:27 +00:00
cmpilato
3ab9ffbbc0 For issue #39, bang in some rudimentary support for displaying version
controlled item properties.  (Of course, this doesn't apply to CVS.)

* lib/vclib/__init__.py
  (Repository.itemprops): New.

* lib/vclib/ccvs/bincvs.py
  (BaseCVSRepository.itemprops): New.

* lib/vclib/svn/svn_repos.py
  (LocalSubversionRepository.itemprops): New.
  (LocalSubversionRepository._revinfo_raw): Fetch the whole revision
    proplist instead of repeatedly querying the filesystem.

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.itemprops): New.

* lib/viewvc.py
  (get_itemprops): New.
  (markup_or_annotate, view_directory): Use get_itemprops().

* templates/docroot/styles.css
  (.vc_properties, .vc_properties h2): New style defs.

* templates/include/props.ezt
  New.

* templates/markup.ezt,
* templates/directory.ezt,
* templates/annotate.ezt
  Include the new props.ezt template chunk.

* docs/template-authoring-guide.html,
* docs/upgrading-howto.html
  Document the new data dictionary bits.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1841 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-09 20:14:33 +00:00
cmpilato
81b39b70a1 Add support to standalone.py for specifying a configuration file
location on the command-line.

* bin/standalone.py
  (handle_config): Add 'config_file' parameter.
  (serve): Update call to handle_config().
  (cli): Parse the -c / --config-file argument, and describe it in the
    usage message.  Also, disallow it when asked to be in GUI mode.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1840 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-08 16:38:25 +00:00
cmpilato
35a1dd9938 Mostly just formatting changes.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1839 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-04 17:30:28 +00:00
cmpilato
b4bf269cf2 Clarify the working copy / repository distinction for CVS newbies.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1838 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-04-01 00:55:05 +00:00
cmpilato
62f82645fd * templates/docroot/styles.css
Add "white-space: nowrap" to table headers.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1837 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-03-18 21:39:55 +00:00
cmpilato
8acb06b609 Rename the forbiddenre authorizer's configuration token to avoid
confusing folks upgrading from ViewVC 1.0.x.

* lib/vcauth/forbiddenre/__init__.py
  (ViewVCAuthorizer.__init__): Look for a configuration option called
    "forbiddenre" instead of "forbidden".

* lib/config.py
  (_force_multi_value): Remove "forbidden" from this list, as we don't parse
    its value directly any more.

* docs/upgrading-howto.html
  Update the section about migrating forbiddenness settings.

* viewvc.conf.dist
  Rename the authz-forbidden.forbidden option to authz-forbidden.forbiddenre.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1836 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-03-18 21:08:19 +00:00
cmpilato
96be9c14cd Stop generating tarball URLs that are outside the URL namespace of the
repository with which they are associated, and use the Content-Disposition 
HTTP header to suggest names for tarball downloads.

* lib/viewvc.py
  (Request.get_link): No longer generate tarball URLs with the .tar.gz
    magic suffix.  We'll stick with explicit view=tar from now on.
  (download_tarball): Use the Content-Disposition HTTP header to
    dictate the recommended tarball name to browser agents.

Patch by: Martijn Ras <Martijn.Ras {at} gmail.com>
          me


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1835 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-03-17 23:34:55 +00:00
cmpilato
eda0309c55 * lib/vclib/ccvs/bincvs.py
(BaseCVSRepository.itemtype): Initialize the 'kind' variable to
    prevent referencing a non-existent variable.

Patch by: Stephane Chazelas <stephane_chazelas {at} yahoo.fr>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1834 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-03-04 17:28:30 +00:00
cmpilato
b03113f864 When I added the various view hrefs to the common template data (long
ago), I inadvertantly cross namespaces with the log view's use of
those variables as links to the HEAD versions of files.  Disambiguate
the head versions by renaming the data dictionary variables with head_
prefixes.

* lib/viewvc.py
  (view_log): Store HEAD href stuff in variables with "head_" prefixes
    so we don't clobber the global href variables.

* docs/upgrading-howto.html
  Note renames of annotate_href, download_href, download_text_href,
  prefer_markup, and view_href to head_annotate_href, head_download_href, 
  head_download_text_href, head_prefer_markup, and head_view_href
  (respectively).

* docs/template-authoring-guide.html,
* templates/include/log_header.ezt
  Track template variable renames.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1833 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-03-04 14:25:14 +00:00
cmpilato
5f8d6a1ff4 Truncate Subversion item log history if it dips into unreadable
(authz-wise) territory.  This should also filter unreadable revisions
from the annotate view, but I'm not as confident about that change.

* lib/vclib/svn/svn_repos.py
  (_get_history): Add 'path_type' parameter, rename 'full_name'
    parameter to 'path',  and truncate history at the first unreadable
    location (if any).
  (BlameSource.__init__): Pass 'first_rev' as the starting revision to
    the Subversion annotate logic, but leave a comment here questioning
    whether it was the right thing to do.
  (LocalSubversionRepository.itemlog): Update call to _get_history(),
    and filter unreadable copyfrom paths.
  (LocalSubversionRepository.annotate): Update call to _get_history().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1832 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-03-03 21:36:27 +00:00
cmpilato
8bc4d0109c Make some minor (though nice in terms of code readability)
optimizations to the way history is crawled in Subversion backends.

* lib/vclib/svn/svn_repos.py
  (NodeHistory): Make this into an iterable object instead of relying
    on a peek into a member variable.
  (NodeHistory.__init__): Make histories a list instead of
    dictionary.  We need the ordering.
  (NodeHistory.add_history): Validate the order in which revision info
    is received -- order matters now.
  (NodeHistory.__getitem__): New.
  (_get_history): Return the NodeHistory object, which is now iterable.
  (_log_helper): Swap the order of the 'path' and 'rev' parameters
    (for consistency).
  (_fetch_log): Merged into its only caller, which was ...
  (LocalSubversionRepository.itemlog): ...this.  Update the use of
    NodeHistory here to avoid unnecessary sorts and reverses and such.
  (LocalSubversionRepository.annotate): Update the use of NodeHistory here.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1831 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-03-03 21:00:45 +00:00
cmpilato
261db1bb7f * lib/vclib/svn/svn_repos.py
(LocalSubversionRepository.openfile, LocalSubversionRepository.listdir, 
   LocalSubversionRepository.dirlogs, LocalSubversionRepository.annotate): 
    Use self.itemtype() to pull off both an authz check as well as 
    kind-in-light-of-operation validation.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1830 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-03-03 20:35:19 +00:00
cmpilato
e1f287360a Add some missing module imports.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1829 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-28 16:14:15 +00:00
cmpilato
4395bc3b1c Update copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1828 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-28 16:11:24 +00:00
cmpilato
c58e82a6e2 Update the www/ area and CHANGES file in light of 1.0.5 release.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1827 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-28 15:49:20 +00:00
cmpilato
8916fe3969 Forward-port tweak to forbiddenre support made in r1817 on the 1.0.x branch.
* lib/vcauth/forbiddenre/__init__.py
  (ViewVCAuthorizer._check_root_path_access): Lose 'rootname' and
    'path_parts' parameters and logic to combine them; just accept the
    combined form as a new 'root_path' parameter.
  (ViewVCAuthorizer.check_root_access): Update call to 
    _check_root_path_access().
  (ViewVCAuthorizer.check_path_access): Do root and path combination
    here, and Update call to _check_root_path_access().

* viewvc.conf.dist
  (forbiddenre.forbidden): Update documentation and examples.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1818 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-25 21:07:06 +00:00
cmpilato
301281228b merge from 1.0.x -r1815, whose log message read thusly:
Fix the plus/minus line change counting in query results to ignore
   values from unreadable files.
   
   * lib/viewvc.py
     (build_commit): Calculate total plus/minus line change count for a
       given commit item (based on the sums of those values in
       non-forbidden file commits associated with it).
     (view_query): Update plus/minus line change count totals only
       *after* trimming unauthorized files
   
   * docs/template-authoring-guide.html
     (query_results): Note new commits.plus and commits.minus items; fix
       description of the plus_count and minus_count items.

While here, also:

* lib/viewvc.py
  (build_commit): Fix the authz check to use vclib.check_path_access,
    and feel vindicated by the fact that I actually found a use for
    that function.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1816 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-25 19:32:21 +00:00
cmpilato
7ed848b084 Update copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1813 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-22 15:11:27 +00:00
cmpilato
cf1f2ff5dd * viewvc.org/nightly/build-viewvc-snapshot
Completely rework this thing, in Python, to support more flexible branch
builds.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1812 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-22 14:49:12 +00:00
cmpilato
af559e2665 Fix a buglet that, for some reason, only shows up when viewing CVSROOT
directories.

* lib/vclib/ccvs/bincvs.py
  (_get_logs): Initialize CVSDirEntry item's lockinfo member to None.

* lib/vclib/ccvs/ccvs.py
  (CCVSRepository.dirlogs): Initialize CVSDirEntry item's lockinfo
    member to None.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1808 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-21 21:59:45 +00:00
cmpilato
8dadbb3674 Honor hide_cvsroot more like the CVSROOT is forbidden than simply obscured.
* lib/viewvc.py
  (is_cvsroot_path): New helper function.
  (view_directory, generate_tarball, build_commit): Use is_cvsroot_path().

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1806 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-21 21:41:17 +00:00
cmpilato
343ca81dbd * viewvc.conf.dist: Note that you can use this to hide roots, too.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1805 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-21 20:33:55 +00:00
cmpilato
0e129c4c77 Forward-port the r1800 bugfixes made in the 1.0.x branch, whose log
message read thusly:

   On the 1.0.x branch:
   
   Fix buglets (and minor security leak) related to the files attached
   to commit items in the query view and query.cgi script results.  These
   views still returned commit objects with all attached metadata even
   when all the files associated with that commit were blocked due to
   configured forbiddenness.  The generic query.ezt template masked this
   bug (because it was keyed on the files more so than on the commit
   items), but query_results.ezt revealed it.  Also, we were doing change
   limiting at the wrong time, so you'd get results that showed 2 files
   but read "Only first 5 files shown...".
   
   * lib/viewvc.py
     (build_commit): Trade the 'limited_files' parameter for a
       'max_files' parameter, and change the way file counting and
       filtering happens so we get accurate file counts and the maximum
       number of allowed files when limiting changes.  Now returns None
       if the would-be-returned commit item has no associated allowed
       files, and defers building of the commit item until necessary.
     (view_query): Don't do file limiting here, defer it to
       build_commit().  Also, watch for (and ignore) None returns from
       build_commit(), too.
   
   * lib/query.py
     (run_query): Strip out commits which have no associated files.
       Since commits in the query view are file-driven, the only way we
       could have a commit that has no files is if the files were
       stripped by forbiddenness checks.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1804 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-21 20:26:58 +00:00
cmpilato
f535d8e599 Tweak authz changes a bit.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1803 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-21 20:14:17 +00:00
cmpilato
08e86c9a45 Minor fixes required by new authz logic.
* lib/viewvc.py
  (_strip_suffix): If no path_parts are provided, return None.
  (Request.run_viewvc): Tweak the 404 error to, among other things,
    always have a leading slash on the path (so the empty path doesn't
    look so odd).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1799 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-15 20:50:22 +00:00
cmpilato
5a238e6a56 Tweak the contact summary a bit.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1796 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-14 15:53:23 +00:00
cmpilato
6ac32c2f1b Put a link to the FAQ and open issues on the Contact page.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1795 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-14 15:48:35 +00:00
cmpilato
7cf7328238 * lib/vclib/svn/svn_repos.py
Tweak all uses of vclib.svn.core.* to be just core.*


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1794 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-13 21:34:31 +00:00
cmpilato
10fa46063c * lib/vclib/svn/svn_repos.py
(LocalSubversionRepository.dirlogs): Oops!  Fix a buglet caused by
    looking at the wrong revision-holding variable.
 

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1791 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-13 17:39:12 +00:00
root
02f7f5b203 Committed through web interface.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1790 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-13 03:47:13 +00:00
root
431e05efd2 auto commit for alm editor.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1789 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-13 03:47:13 +00:00
root
13a6a53f9d auto commit for alm editor.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1788 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-13 03:47:12 +00:00
cmpilato
3cbf07551b Finish issue #57 with more support for showing locked status.
* lib/vclib/__init__.py
  (Repository.dirlogs): Update comment.
  (Revision.__init__): Add 'lockinfo' parameter, used to populate
    similarly named class member.

* lib/vclib/svn/svn_repos.py
  (Revision.__init__): Add 'lockinfo' parameter, and update call to
    vclib.Revision().
  (_log_helper): Update call to Revision(), and lose custom lockinfo handling.
  (LocalSubversionRepository.dirlogs): Populate entry lockinfo with a
    call to svn_fs_get_lock() for each entry.

* lib/vclib/svn/svn_ra.py
  (LogCollector.__init__): Add 'lockinfo' parameter, used to populate
    similarly named class member.
  (LogCollector.add_log): Pass self.lockinfo to updated call to Revision().
  (RemoteSubversionRepository.itemlog): Pass lock info to
    LogCollector(), and lose custom lockinfo handling.
  (RemoteSubversionRepository.itemtype, RemoteSubversionRepository.listdir): 
    Update expected return value from _get_dirents().
  (RemoteSubversionRepository.dirlogs): Populate entry lockinfo from
    updated return value from _get_dirents().
  (RemoteSubversionRepository._get_dirents): Rework to trade in
    dirents and locks instead of only dirents.

* lib/vclib/ccvs/bincvs.py
  (Revision.__init__): Update call to vclib.Revision().
  (_get_logs): Add 'lockinfo' member to DirEntry() items.

* lib/vclib/ccvs/ccvs.py
  (InfoSink.__init__): Init lockinfo dictionary.
  (InfoSink.set_locker): New.
  (InfoSink.define_revision): Set lockinfo on Revision item.
  (InfoSink.set_revision_info): Populate DirEntry lockinfo from
    Revision lockinfo data.

* lib/viewvc.py
  (view_directory): Populate entry lockinfo.
  (common_template_data): Populate the 'lockinfo' data dictionary item.

* templates/directory.ezt,
* templates/dir_new.ezt
* templates/annotate.ezt,
* templates/markup.ezt
  Tweak to show lock status.

* docs/template-authoring-guide.html
  Note new data dictionary items.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1787 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-12 21:06:40 +00:00
cmpilato
d620498e9e Add support for display of locked status.
* docs/template-authoring-guide.html
  Document the new appearances of the lockinfo data.

* templates/log.ezt,
* templates/log_table.ezt
  Show lock status information.

* templates/docroot/images/lock.png
  New icon.

* lib/viewvc.py
  (view_log): Populate the log revision entry's new "lockinfo" member.

* lib/vclib/svn/svn_repos.py
  (_log_helper): Accept 'lockinfo' parameter, used to populate the
    similarly named member of the Revision() object.
  (_fetch_log): Query the lock status of the input path, and update
    calls to _log_helper().

* lib/vclib/ccvs/ccvs.py
  (CCVSRepository.itemlog): Update call to _file_log(), passing lockinfo.
  (TreeSink.__init__): Init new lockinfo dictionary.
  (TreeSink.set_locker): New.

* lib/vclib/ccvs/bincvs.py
  (_parse_log_header): Now parse and return lock information, too.
  (_file_log): Add 'lockinfo' parameter, used to populate the
    similarly named Revision() object members.
  (BinCVSRepository._get_tip_revision, BinCVSRepository.itemlog):
    Expect lockinfo back from _parse_log_header(), and pass to updated
    calls to _file_log().
  (_get_logs): Expect lockinfo back from _parse_log_header().

* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.itemlog): Use svn_client_ls3() to fetch
    lock information.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1783 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-12 19:41:19 +00:00
cmpilato
2a9584a0fb Finish issue #238 by not making HTML out of short log messages in RSS
format mode.

* lib/viewvc.py
  (format_log): Now accept optional 'htmlize' parameter.
  (build_commit): Accept 'format' parameter, and use it to determine
    what value to pass for the 'htmlize' parameter of an updated call
    to format_log().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1779 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-12 15:29:28 +00:00
cmpilato
e6d8e1306d * bin/loginfo-handler,
* bin/cvsdbadmin
  Update calls to vclib.ccvs.CVSRepository() to account for new
  'authorizer' parameter.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1778 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-12 15:27:12 +00:00
cmpilato
34f764bc8f * lib/config.py
(Config.get_authorizer_params): Rework this to avoid Python 2.4-ism
    (dict.update() able to accept an iterable key/value sequence) and
    to favor root-specific parameters over general ones.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1777 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-12 15:02:41 +00:00
cmpilato
34e7003241 Minor typo fix.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1776 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-12 14:48:41 +00:00
cmpilato
cedb97c3d4 Finish issue #305 by allowing "markup" to be the configured default
file view.  This causes less-than-perfectly-compact URL generation in
some cases, but frankly, we'd have fewer URL-compatibility issues if
we hadn't been trying to discard information in the first place.

* lib/viewvc.py
  (Request.run_viewvc, Request.get_link): Honor "markup" as a valid value for
    default_file_view.

* viewvc.conf.dist
  (default_file_view): Note that "markup" is now a valid option here.

* CHANGES
  Record this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1775 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-11 22:16:00 +00:00
cmpilato
47ad6e149c Fix some minor oversights.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1774 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-11 22:11:16 +00:00
cmpilato
c7a392b75c Be so bold as to claim that the authz subsystem is in 1.1.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1773 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-11 21:14:02 +00:00
cmpilato
e0dff2601a Mostly unify the markup and annotate view logic. This does *not*
unify the views themselves; just the code that generates them.

* lib/viewvc.py
  (markup_or_annotate): New, carved from the guts of ...
  (view_markup, view_annotate): ... these, which are now just thin
    wrappers around markup_or_annotate().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1772 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-11 20:51:56 +00:00
cmpilato
fcf52b5c5f * lib/vclib/svn/svn_repos.py
(BlameSource._blame_cb): Increment the line number by 1;
    Subversion's annotate APIs are 0-based.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1771 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-11 20:47:11 +00:00
cmpilato
8f0623abc0 This is a cleanup commit, mostly around making sure that Repository.revinfo()
consistently returns a date, *not* a date string.

* lib/viewvc.py
  (_get_diff_path_parts): Fix the call to _path_parts to, you know,
    not reference bogus variables and actually use the value returned.

* lib/vclib/svn/svn_ra.py
  (LastHistoryCollector.add_history): Convert the date string to a real date.  
  (temp_checkout): Keep a handle on the name of the temporary file
    created, since that's what is returned by this function.
  (rawdiff): Look for Subversion exceptions in the proper namespace.

* lib/vclib/svn/svn_repos.py
  (_date_from_rev): Make this an inner function of rawdiff(), its only
    consumer.
  (_log_helper, LocalSubversionRepository.dirlogs): Don't convert the
    returned date.
  (LocalSubversionRepository._revinfo_raw): Return a date, not a date string.
  (BlameSource.__init__): Expect exceptions in the right namespace.
  (LocalSubversionRepository.rawdiff): Update call to _date_from_rev;
    expect exceptions in the right namespace.
  


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1770 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-11 16:53:20 +00:00
cmpilato
c3572f452c Fix a little buglet -- referencing a non-existant object.
* lib/vclib/svn/svn_ra.py
  (RemoteSubversionRepository.open): Use self.ctx.*, not just ctx.*

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1769 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-07 22:53:16 +00:00
cmpilato
a9243564bb * INSTALL: Recommend adding ViewVC to the site-wide robots.txt file.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1765 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-07 02:20:24 +00:00
cmpilato
b049f1dca8 * viewvc.conf.dist
(authorizer): Update comment to describe provided authorizers and
    mention forbiddenre.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1764 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-06 21:21:00 +00:00
cmpilato
057ab0fe25 Introduce a new authz module, like 'forbidden' but with support for
checking all roots and paths against regular expressions.

* viewvc.conf.dist
  (forbidden): New authz-forbiddenre section.

* lib/vcauth/forbiddenre,
* lib/vcauth/forbiddenre/__init__.py
  New authorizer based on simple regular expressions.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1763 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-06 21:16:51 +00:00
cmpilato
220792f72c Merge to trunk all the changes from the 'vcauth-reorg' branch as of
r1761, which see for logs.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1762 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-06 19:22:53 +00:00
cmpilato
c696f32d70 * lib/config.py
(Config.set_defaults): Clear the default admin address.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1758 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-02-06 17:48:45 +00:00
cmpilato
3a8717b11d Formatting and comment changes only.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1750 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-01-28 17:55:44 +00:00
cmpilato
edaae720da * lib/viewvc.py
(Request.__init__): Stop calculating and storing the 'may_compress'
    and 'no_file_links' values -- we don't use them anywhere!

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1749 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-01-28 17:46:23 +00:00
cmpilato
eb363507cb * INSTALL
Note that we now expect source-highlight 2.6.

* templates/docroot/styles
  Add style definitions to match the style names used by
  source-highlight.

* lib/viewvc.py
  (MarkupSourceHighlight.__init__): Use the 'xhtml-css' output format,
    and pass the --quiet option to suppress any noise that would
    wind up on stderr.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1748 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-01-24 22:02:19 +00:00
cmpilato
44f0356312 Try to use Python's gzip module for the tarball generation view, thus
reducing the list of binary dependencies by one for users of ... well,
any Python version that I could find as of at least 1.5.2.

TODO:  Are there any versions of Python supported by ViewVC in general
that don't provide the 'gzip' module?  Should we just rip out the use
of the external binary altogether?

(This was tracked in issue #319.)

* lib/viewvc.py
  (download_tarball): Use Python's gzip module if available, only
    falling back to a pipe through the gzip binary if it isn't.

* viewvc.conf.dist
  (cfg.utilities.gzip): Note that this setting is optional if Python
    provides the 'gzip' module.

Patch by: Gabriel Genellina <ggenellina@tigris.org>
(Tweaked by me.)

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1747 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-01-24 19:40:37 +00:00
cmpilato
d966338c1d Add an href to the root listing view to the common template data dictionary.
* lib/viewvc.py
  (common_template_data): Calculate and add 'roots_href' to the dictionary.

* templates/include/header.ezt
  Use new 'roots_href' data dictionary item.

* docs/template-authoring-guide.html
  Note this new dictionary member.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1746 8cb11bc2-c004-0410-86c3-e597b4017df7
2008-01-10 19:21:26 +00:00
cmpilato
8f49d24d7f Add some hints to INSTALL about getting Subversion and its bindings.
Suggested by user 'johnkw' in IRC.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1745 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-12-04 17:43:18 +00:00
cmpilato
aa6b9dcf8e Merge changes (r1735:1738) from the (misnamed) options-overhaul
branch.  This reduces the number of vclib plugins to two -- one for
each of CVS and Subversion.

* lib/viewvc.py
  (): Update callers of vclib.svn.created_rev(), vclib.svn.get_location(),
    vclib.svn.get_youngest_revision(), and vclib.svn.last_rev() to use
    request.repos.* instead.
  (Request.run_viewvc): For CVS, invoke only
    vclib.ccvs.CVSRepository(), but pass the use_rcsparse setting to
    it.  For Subversion, invoke only vclib.svn.SubversionRepository().

* lib/vclib/ccvs/ccvs.py
  Renamed from lib/vclib/ccvs/__init__.py, and tweaked to look for
  stuff common to the bincvs implementation in the sibling 'bincvs'
  module.

* lib/vclib/ccvs/__init__.py
  New, a replacement by a new stub file with a factory function
  that selects which CVS implementation to use.

* lib/vclib/ccvs/bincvs.py
  Moved from lib/vclib/bincvs/__init__.py.

* lib/vclib/bincvs
  Removed (it's now empty).

* lib/vclib/svn/svn_repos.py
  Renamed from lib/vclib/svn/__init__.py.
  (LocalSubversionRepository.created_rev,
   LocalSubversionRepository.get_location,
   LocalSubversionRepository.get_youngest_revision, 
   LocalSubversionRepository.last_rev): Moved into the class from outside.

* lib/vclib/svn/svn_ra.py
  Moved from lib/vclib/svn_ra/__init__.py.
  (RemoteSubversionRepository.created_rev,
   RemoteSubversionRepository.get_location,
   RemoteSubversionRepository.get_youngest_revision, 
   RemoteSubversionRepository.last_rev): Moved into the class from outside.

* lib/vclib/svn/__init__.py
  New, replacing previous incarnation with a file that contains only a
  single factory function.

* lib/vclib/svn_ra/
  Removed (it's now empty).

* bin/loginfo-handler
  (ProcessLoginfo): Now use vclib.ccvs.CVSRepository(), disabling use_rcsparse.

* bin/cvsdbadmin
  (__main__): Now use vclib.ccvs.CVSRepository(), disabling use_rcsparse.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1739 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-12-03 15:25:51 +00:00
mhagger
37373d8ab2 Change the way that rcsparse components are imported in run-tests.py.
The new method will work even if the contents of the "rcsparse"
directory are stored to a directory with a different name (as is the
case, for example, in cvs2svn).

* lib/vclib/ccvs/rcsparse/run-tests.py: Change how rcsparse.parse()
  and parse_rcs_file.LoggingSink are imported.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1734 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 22:59:09 +00:00
mhagger
5ab76ea1cf Change the way that rcsparse.parse() is imported in parse_rcs_file.py.
The new method will work even if the contents of the "rcsparse"
directory are stored to a directory with a different name (as is the
case, for example, in cvs2svn).

* lib/vclib/ccvs/rcsparse/parse_rcs_file.py: Change how
  rcsparse.parse() is imported.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1733 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 22:53:35 +00:00
mhagger
0e6c162246 Add method _Parser._read_until_semicolon(), and use it in other methods.
* lib/vclib/ccvs/rcsparse/common.py (_Parser._read_until_semicolon):
  New method.

  (_Parser._parse_admin_access, _Parser._parse_rcs_tree_entry): Use
  the new method.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1732 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 21:15:27 +00:00
mhagger
1f2a3399ea Fix and simplify the handling of dates in _Parser._parse_rcs_tree_entry().
* lib/vclib/ccvs/rcsparse/common.py (_Parser._parse_rcs_tree_entry):
  Adjust the handling of dates to conform more strictly to
  rcsparse(5), and simplify logic a bit.

* lib/vclib/ccvs/rcsparse/test-data/default,v,
  lib/vclib/ccvs/rcsparse/test-data/default.out: Change test case to
  include dates before the year 2000.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1731 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 21:13:53 +00:00
mhagger
53b48c9b4f Don't carry zeros along in date tuple.
* lib/vclib/ccvs/rcsparse/common.py (_Parser._parse_rcs_tree_entry):
  Append zeros to the end of the date tuple only when they are needed.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1730 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 21:05:16 +00:00
mhagger
e906090e8c Simplify _Parser._parse_rcs_tree_entry().
* lib/vclib/ccvs/rcsparse/common.py (_Parser._parse_rcs_tree_entry):
  Simplify logic.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1729 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 21:01:16 +00:00
mhagger
af7956447b Extract method _Parser._parse_rcs_tree_entry().
* lib/vclib/ccvs/rcsparse/common.py (_Parser._parse_rcs_tree_entry):
  New method, extracted from parse_rcs_tree().

  (_Parser.parse_rcs_tree): Use new method.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1728 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 21:00:21 +00:00
mhagger
939c980e5b Simplify _Parser._parse_admin_access().
* lib/vclib/ccvs/rcsparse/common.py (_Parser._parse_admin_access):
  Simplify logic and use list.append(x) instead of "list = list +
  [x]".


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1727 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 20:59:01 +00:00
mhagger
7a8d3c0453 Rename some local variables to better describe their uses.
* lib/vclib/ccvs/rcsparse/common.py (_Parser._parse_admin_access,
  _Parser._parse_admin_symbols, _Parser._parse_admin_locks): Rename
  local variables.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1726 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 20:58:00 +00:00
mhagger
7e0b5d2a9c Use match() to handle semicolons when possible.
This simplifies the code without a measureable performance cost.

* lib/vclib/ccvs/rcsparse/common.py (_Parser._parse_admin_head,
  _Parser._parse_admin_branch, _Parser._parse_admin_comment,
  _Parser._parse_admin_expand): Use the token scanner's match() method
  to handle semicolons.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1725 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 20:57:02 +00:00
mhagger
d7c87b8b2f Change the token stream match() methods to raise RCSExpected exceptions.
Previously, they raised a naked RuntimeError.  This change should be
harmless because nobody seems to catch these exceptions specifically.

* lib/vclib/ccvs/rcsparse/default.py (_TokenStream.match): Raise
  RCSExpected exception in the case of a mismatch.

* lib/vclib/ccvs/rcsparse/texttools.py (_mxTokenStream.match): Raise
  RCSExpected exception in the case of a mismatch.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1724 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 20:56:26 +00:00
mhagger
8087c0e643 Improve the error message for RCSExpected exceptions.
* lib/vclib/ccvs/rcsparse/common.py (RCSExpected.__init__): Improve
  the error message passed to the base class constructor.  Also
  improve spacing around the exception class definitions.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1723 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 20:53:40 +00:00
mhagger
4c04da27da Simplify the logic in texttools._mxTokenStream.match() (remove duplicate code).
* lib/vclib/ccvs/rcsparse/texttools.py (_mxTokenStream.match):
  Remove duplicate code.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1722 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 20:52:39 +00:00
mhagger
34f76bdc87 Handle files with empty "delta" (a.k.a., "tree") part.
According to rcsfile(5), there don't have to be any deltas in an RCS
file.  File without deltas can be created using "rcs -i -t- foofile".
This change allows rcsparse to handle such files.

This change might help fix cvs2svn Issue #80:
http://cvs2svn.tigris.org/issues/show_bug.cgi?id=80

* lib/vclib/ccvs/rcsparse/common.py (_Parser.admin_token_map): Add an
  entry for "desc" (because if the tree is empty, the next thing
  encountered after the administrative information is "desc").

  (_Parser.parse_rcs_admin): Terminate loop if "desc" is seen.

* lib/vclib/ccvs/rcsparse/test-data/empty-file,v,
  lib/vclib/ccvs/rcsparse/test-data/empty-file.out: Add a test RCS
  file with no contents to test data, and the results expected when
  parsing the file.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1721 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 20:51:40 +00:00
mhagger
57bf0cb554 Handle a "head" keyword with no revision number.
According to rcsfile(5), this is allowed.  In this situation, don't
invoke the set_head_revision() callback at all.

* lib/vclib/ccvs/rcsparse/common.py (_Parser._parse_admin_head): Handle
  the case that the "head" keyword doesn't list a revision.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1720 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 20:49:38 +00:00
mhagger
9adcdfae2f Remove dead code.
* lib/vclib/ccvs/rcsparse/common.py (_Parser.parse_rcs_admin): Remove
  dead code (the only way to escape from the loop is via "return").


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1719 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 20:47:29 +00:00
mhagger
075b580fdb Rewrite _Parser.parse_rcs_admin() to use a token lookup table.
* lib/vclib/ccvs/rcsparse/common.py (_Parser._parse_admin_head,
  _Parser._parse_admin_branch, _Parser._parse_admin_access,
  _Parser._parse_admin_symbols, _Parser._parse_admin_locks,
  _Parser._parse_admin_strict, _Parser._parse_admin_comment,
  _Parser._parse_admin_expand): New methods (one for each keyword that
  can appear in the admin section).

  (_Parser.admin_token_map): A map from keyword name to the method
  used to handle that keyword.

  (_Parser.parse_rcs_admin): Look up the keyword tokens in the map
  instead of using a big "if" statement.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1718 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 20:46:46 +00:00
mhagger
ae57f73e2f Separate handling of the "strict" keyword into a separate "if" branch.
This makes the keyword handling more uniform.

* lib/vclib/ccvs/rcsparse/common.py (_Parser.parse_rcs_admin):
  Separate handling of the "strict" keyword into a separate "if"
  branch.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1717 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 20:46:03 +00:00
mhagger
a70372d2ed Reorder definitions in the approximate order that they will be called.
Order the callbacks in Sink and the "if" branched in parse_rcs_admin()
in the approximate order that they will be encountered.

* lib/vclib/ccvs/rcsparse/common.py (Sink): Reorder method definitions.

  (_Parser.parse_rcs_admin): Reorder "if" statement branches.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1716 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-18 20:45:09 +00:00
cmpilato
9ce172e673 Welcome aboard, Michael.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1715 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-16 09:53:25 +00:00
cmpilato
bac09990f6 Fix a syntax error that was preventing compilation.
Submitted by: Michael Haggerty <mhagger@alum.mit.edu>

* tparse/tparse.h 
  (rcstoken::init): Fix declaration.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1714 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-16 09:49:22 +00:00
cmpilato
e2b783a403 * lib/vclib/ccvs/rcsparse/parse_rcs_file.py
Set svn:executable property for this file.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1713 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-16 09:44:12 +00:00
cmpilato
db6fbcdf1f Add a very primitive testing infrastructure for rcsparse, and the first test.
Submitted by: Michael Haggerty <mhagger@alum.mit.edu>

* lib/vclib/ccvs/rcsparse/run-tests.py: New file.

* lib/vclib/ccvs/rcsparse/test-data/default,v,
* lib/vclib/ccvs/rcsparse/test-data/default.out
  Test data for a simple test.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1712 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-16 09:42:56 +00:00
cmpilato
fcf688c20c Add a new test/demonstration script.
Submitted by: Michael Haggerty <mhagger@alum.mit.edu>

This script was taken from the cvs2svn project, http://cvs2svn.tigris.org.

* lib/vclib/ccvs/rcsparse/parse_rcs_file.py: New demonstration script;
  illustrates the use of the rcsparse API.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1711 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-11-16 09:39:14 +00:00
cmpilato
6c7de54d87 * viewvc.org/faq.html
Add a FAQ entry for the "...but none match the current selection
  criteria" error.  Suggested by user "brasko" in IRC today.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1710 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-10-30 21:43:56 +00:00
cmpilato
94017f01e8 * docs/upgrading-howto.html
Add a note about the change to 'svndbadmin rebuild'.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1709 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-10-09 13:21:13 +00:00
cmpilato
2856ac9ebc * viewvc.org/faq.html
(missing-files): Start answering this question.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1708 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-10-01 18:20:52 +00:00
cmpilato
525523e465 Prevent Exception when generating tarballs for remote Subversion
repositories.

* lib/vclib/svn_ra/__init__.py
  (SelfCleanFP.read): Add default parameter value for 'len' argument.

Patch by: Ceri Storey <cez@necrofish.org.uk>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1706 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-09-14 13:02:21 +00:00
cmpilato
7d4ce47182 * bin/cvsdbadmin,
* bin/svndbadmin
  (usage): Make it clear that the REPOSITORY command-line argument
    is a path to a repository (as opposed to a ViewVC rootname or
    relative URL or something else).

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1703 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-08-16 17:26:49 +00:00
cmpilato
efad0b6cd6 Add FAQ-n-A about RSS feeds.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1702 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-07-30 15:48:22 +00:00
cmpilato
3d6f1cc7d1 Finish issue #309: add links from diff view to revision views.
* lib/viewvc.py
  (view_diff): Rework the data dictionary: provide 'left' and 'right'
    container objects with members for stuff related to the files on
    the left and right side of the diff.  Also, add the usual
    per-file-revision view links to those containers, too.

* templates/diff.ezt
  Track the data dictionary changes, and add links to the preferred
  file views for each revision.

* docs/template-authoring-guide.html,
* docs/upgrading-howto.html
  Note template changes.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1701 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-07-26 20:56:10 +00:00
cmpilato
3d7b8a7a1a * docs/upgrading-howto.html
Followup to r1699, noting new 'rss_link_href' data dictionary item.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1700 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-07-26 20:44:41 +00:00
cmpilato
ed5898c37d Finish issue #307: RSS feeds should include a <channel><link> element.
* lib/viewvc.py
  (Request.get_url): Add new 'prefix' parameter, used to toggle
    whether or not the generated URL has the protocol and server name
    portions of the URL.  Move code from build_commit() to handle the
    prefix-inclusive case.
  (build_commit): Move URL prefix-generating code to
    Request.get_url(), and simply call that function with the new
    'prefix' option set.
  (view_query): Add new 'rss_link_href' data dictionary item.

* templates/rss.ezt
  Add <channel><link> bit to the output stream, populated with the new
  'rss_link_href' data dictionary item.

* docs/template-authoring-guide.html
  Add documentation for the new 'rss_link_href' data dictionary item,
  and note that query results also use rss.ezt.
  



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1699 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-07-26 18:55:15 +00:00
cmpilato
c487361c95 Note some completed enhancements.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1698 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-07-20 14:31:31 +00:00
cmpilato
b037efb91e Add a FAQ item about path-based authz.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1697 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-07-13 19:18:22 +00:00
cmpilato
29057c811f Finish issue #306 - RSS content type should be more specific.
* lib/viewvc.py
  (view_query): Use "application/rss+xml" instead "text/xml" for 
    the RSS feed output stream's content type.  Suggested by 
    Phil Ringnalda <philringnalda@tigris.org>.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1695 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-07-09 18:18:01 +00:00
cmpilato
8ca49db267 * viewvc.org/faq.html
(standalone-only): New question and answer about why stuff sometimes
    works under standalone.py but not under Apache with the same
    configuration.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1694 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-07-05 16:59:51 +00:00
cmpilato
d4e115bd3a * viewvc.org/faq.html
Answer the "no module named svn" question.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1693 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-07-05 16:22:16 +00:00
cmpilato
d09280ce6b * viewvc.org/faq.html
Reformat "questions" as (of all things) questions.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1692 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-07-05 16:19:55 +00:00
cmpilato
98aeeab676 * viewvc.org/faq.html
Populate the answer to the "missing temporary directory" question.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1691 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-07-05 16:09:23 +00:00
cmpilato
061b30a108 * viewvc.org/styles.css
(faq-section): New style name.

* viewvc.org/faq.html
  Make h3's bear the new faq-section style.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1690 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-07-05 16:04:13 +00:00
cmpilato
01baf48a1b Update the vhosts config example to not use 'cvs' and 'svn' in vhost names.
This was too easily confused with root type declarations.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1688 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-28 15:54:49 +00:00
cmpilato
46e7cdf817 * templates/rss.ezt
For issue #238, properly XML-entity-encode the log message embedded
  in RSS feed items.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1686 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-27 17:41:57 +00:00
cmpilato
703327df1c Implement a more-or-less generic global revision info function in the
vclib.Repository interface, and adapt the Subversion vclib modules to
implement it.

* lib/vclib/__init__.py
  (ADDED, DELETED, REPLACED, MODIFIED): New static variables.
  (Repository.revinfo): New function.
  (ChangedPath): New class.
  (UnsupportedFeature): New exception type.

* lib/vclib/bincvs/__init__.py
  (BinCVSRepository.revinfo): New (just raises vclib.UnsupportedFeature).

* lib/vclib/ccvs/__init__.py
  (CCVSRepository.revinfo): New (just raises vclib.UnsupportedFeature).

* lib/vclib/svn/__init__.py
  (SVNChangedPath): Was ChangedPath, now is a subclass of vclib.ChangedPath.
  (SubversionRepository.revinfo): Was get_revision_info().  Rework to
    use SVNChangedPath items.

* lib/vclib/svn_ra/__init__.py
  (): Import SVNChangedPath instead of ChangedPath.
  (LastHistoryCollector.add_history): Rework to use SVNChangedPath items.
  (SubversionRepository.revinfo): Was get_revision_info().

* lib/viewvc.py
  (view_revision): Rework this to use Repository.revinfo()


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1685 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-27 16:41:03 +00:00
cmpilato
da80a5898a Minor code cleanups (doing in vclib.svn_ra what I recently did in vclib.svn).
* lib/vclib/svn_ra/__init__.py
  (get_logs): Merge this (and delete it) ...
  (SubversionRepository.dirlogs): ... into here.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1684 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-27 15:04:39 +00:00
cmpilato
2601c02f5d Minor code cleanups.
* lib/vclib/svn/__init__.py
  (get_logs): Merge this (and delete it) ...
  (SubversionRepository.dirlogs): ... into here.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1683 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-27 14:58:30 +00:00
cmpilato
ad877bd5a5 Minor code simplification.
* lib/vclib/svn_ra/__init__.py
  (SubversionRepository.__init__): Trade a bunch of list.append() calls for
    a static initializition of the list.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1682 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-27 14:24:56 +00:00
cmpilato
2fe022c3a4 * viewvc.conf.dist,
* lib/config.py
  Re-sync (and re-order) the options listed in the sample configuration file
  and the Config object.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1681 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-20 13:25:18 +00:00
cmpilato
f40a836c23 * lib/vcauth/forbidden/__init__.py
(ViewVCAuthorizer.__init__): Don't assume that the 'forbidden' parameter
    is present.  Noticed by Vairoj Arunyaangkul <va@waveman.com>.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1680 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-20 13:23:52 +00:00
cmpilato
c791123a08 Add FAQ item for 'COMalformedOutput: ...' as suggested by Heather
Gordon <hgordon@shutterfly.com>.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1679 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-15 18:27:17 +00:00
cmpilato
be4ee9d817 For issue #303, duplicate the commented-out LD_LIBRARY_PATH setting
code from view_cvsgraph() into view_cvsgraph_image(), too, and
cross-reference them in the surrounding comments.

* lib/viewvc.py
  (view_cvsgraph_image): Add commented-out LD_LIBRARY_PATH set, just
    like what's in view_cvsgraph().
  (view_cvsgraph): Update comment and example.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1678 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-15 14:08:18 +00:00
cmpilato
889b3cdb0e Fix some webstuffs spelling oopses.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1677 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-15 13:19:20 +00:00
cmpilato
e1f3b9f4f7 Tweak the tigris.org left-nav a bit.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1676 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-15 13:17:13 +00:00
cmpilato
5c26dab649 Flesh out the 'rlog output ended early' answer.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1675 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-15 12:57:05 +00:00
cmpilato
c089f3bd73 Website tweaks to support the FAQ page.
* viewvc.org/styles.css
  Tweak (and add) styles.

* viewvc.org/who.html
* viewvc.org/index.html
* viewvc.org/contributing.html
* viewvc.org/download.html
* viewvc.org/contact.html
* viewvc.org/nightly/build-viewvc-snapshot
  Add some more CSS-able <div>'s, and add links to the FAQ page.

* viewvc.org/faq.html
  Flesh out a little more the layout of this document, and add our first
  answer!

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1674 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-14 12:29:31 +00:00
cmpilato
01b87f562e The disconnected query interface throws all the root-centric handling
convention of ViewVC into a tizzy, so rework the way the auth handling
stuff works there.  We'll get root-specific handling of 'forbidden'
out of this as a result.

* lib/query.py
  (is_forbidden): New.
  (build_commit): Lose the 'auth' parameter, and call is_forbidden to
    determine if a given result may be displayed.
  (run_query): No longer grab an Authorizer object.  Update calls to
    build_commit().




git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1673 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-06 20:32:17 +00:00
cmpilato
d421c3bc22 For issue #290 - Re-work the way email address mangling is managed to
prevent mangling inside file contents.  Why?  Because file contents
should be sancred, and besides, we can't control what our various
syntax highlighting programs will do with such addresses anyway.

* lib/viewvc.py
  (htmlify): Lose 'cfg' parameter; add 'mangle_email_addrs'.
  (format_log, view_markup, view_log, view_annotate, view_revision,
   build_commit): Update call to htmlify, using the configured value
    for mangle_email_addresses.
  (copy_stream, view_diff, english_query, view_error): Update call to
    htmlify, with email address mangling disabled.
  (DiffSource._format_text): Was spaced_html_text().  Update call to
    htmlify(), with email address mangling disabled.

* viewvc.conf.dist
  (mangle_email_addresses): Note that this doesn't affect the display
    of file contents.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1672 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-04 16:50:06 +00:00
cmpilato
53e1cd8f30 Add email address mangling feature to CHANGES.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1671 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-01 20:05:39 +00:00
cmpilato
6c80a17d45 Finish issue #290 - Introduce an option for mangling email addresses.
* viewvc.conf.dist
  (mangle_email_addresses): New option.

* lib/config.py
  (Config.set_defaults): Set defaults for new 'mangle_email_addresses'
    option.

* lib/viewvc.py
  In various functions, use 'cfg = request.cfg' to enhance readability.
  (htmlify): Add 'cfg' parameter.  Callers updated.  Honor the new cfg
    option 'mangle_email_addresses', showing only "username@..." when
    mangling.
  (copy_stream, MarkupPipeWrapper.__init__, MarkupShell.__init__): Add
    'cfg' parameter.  All callers updated.
  (MarkupEnscript.__init__, MarkupHighlight.__init__): Squirrel away
    the 'cfg' parameter.

* docs/upgrading-howto.html
  Note the new mangle_email_addresses option.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1670 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-01 20:03:56 +00:00
cmpilato
b5b1272ebb Add some notes on improving the vclib API.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1669 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-06-01 18:12:12 +00:00
cmpilato
8b0b3632ac Improve the vcauth stuffs error handling logic a bit.
* lib/viewvc.py
  (setup_authorizer): Rework this for tighter exception handling.

* lib/vcauth/svnauthz/__init__.py
  (ViewVCAuthorizer.__init__): Don't reveal server paths in the
    file-not-found exception.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1668 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-05-25 13:32:55 +00:00
cmpilato
3abdb58fc1 Fix the vcauth interactions of the tarball generation code.
* lib/viewvc.py
  (generate_tarball): Check every path -- not just top-level
    subdirectories -- for authorization.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1667 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-05-24 20:09:21 +00:00
cmpilato
65de16dd8f * lib/vcauth/forbidden/__init__.py
(): import vclib (so trying to use it later doesn't make bad stuff happen)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1666 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-05-21 14:45:00 +00:00
cmpilato
feca32c985 For issue #268: Merge the Authorizers' check_directory_access() and
check_file_access() functions into a single check_path_access().  Most
authorizers won't need to care about the distinction.

* lib/vcauth/__init__.py
  (GenericViewVCAuthorizer.check_path_access): New, replaces ...
  (GenericViewVCAuthorizer.check_file_access,
   GenericViewVCAuthorizer.check_directory_access): ...these
    now-removed functions.
  (ViewVCAuthorizer.check_path_access): New.
  (ViewVCAuthorizer.check_file_access,
   ViewVCAuthorizer.check_directory_access): Removed.

* lib/vcauth/forbidden/__init__.py
  (ViewVCAuthorizer.__init__): Squirrel away 'root' so we can use it ...
  (ViewVCAuthorizer.check_path_access): ...here.  Was
    check_directory_access(), and now optionally checks the path's type
    before making the access determination.
  (ViewVCAuthorizer.check_file_access): Removed.

* lib/vcauth/svnauthz/__init__.py
  (ViewVCAuthorizer.check_path_access): Was _check_path_access().  Add
    'rev' parameter.
  (ViewVCAuthorizer.check_file_access,
   ViewVCAuthorizer.check_directory_access): Removed.

* lib/viewvc.py
  (Request.run_viewvc, view_directory, _get_diff_path_parts,
   generate_tarball, view_revision, build_commit): Use the
    authorizor's check_path_access() instead of the now-removed
    check_directory_access() and check_file_access() functions.

* lib/query.py
  (build_commit): Use check_path_access() instead of
    check_directory_access().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1661 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-05-15 20:18:56 +00:00
cmpilato
c3bd8d5aea Consistify blockquote stylation, and update cvsweb link.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1660 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-05-15 18:38:24 +00:00
cmpilato
fc2e5b9bd1 Update URL for PEP 8.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1659 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-05-15 18:01:39 +00:00
cmpilato
9e64e86927 Remove vcauth/test module.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1657 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-05-14 19:44:30 +00:00
cmpilato
a98023499d Pass the Repository object to the vcauth modules so they can more
easily query the repository for information.

* lib/vcauth/__init__.py
  (GenericViewVCAuthorizer.__init__): Lose 'rootpath', 'roottype', and
    'rootname' for just 'root', so the authz modules can make queries
    of the backing VC system as necessary.

* lib/vcauth/forbidden/__init__.py
  (ViewVCAuthorizer.__init__): Lose 'rootpath', 'roottype', and
    'rootname' for just 'root'.

* lib/vcauth/svnauthz/__init__.py
  (ViewVCAuthorizer.__init__): Lose 'rootpath', 'roottype', and
    'rootname' for just 'root'.

* lib/viewvc.py
  (Request.run_viewvc): Update call to setup_authorizer().
  (setup_authorizer): Lose 'rootpath', 'roottype', and 'rootname' for
    just 'root'.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1655 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-05-10 21:44:28 +00:00
cmpilato
2ce86a5227 Ensure that vclib.Repository objects are aware of their name, path,
and type by forcing them to implement functions which query those
pieces of information.

* lib/vclib/__init__.py
  (Repository.rootname, Repository.rootpath, Repository.roottype): New.

* lib/vclib/bincvs/__init__.py
  (CVSRepository.rootname, CVSRepository.rootpath,
    CVSRepository.roottype): New.

* lib/vclib/svn/__init__.py
  (SubversionRepository.rootname, SubversionRepository.rootpath,
    SubversionRepository.roottype): New.
  
* lib/vclib/svn_ra/__init__.py
  (SubversionRepository.rootname, SubversionRepository.rootpath,
    SubversionRepository.roottype): New.

* lib/viewvc.py
  (Request.run_viewvc): Ask the Repository object for its roottype(),
    and translate the vclib value into a string.  (It would be nice to
    use the vclib value throughout the codebase, but not today.)

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1654 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-05-10 20:47:27 +00:00
cmpilato
5a5e3755f6 * lib/vcauth/svnauthz/__init__.py
(ViewVCAuthorizer.__init__): Look for the read ('r') code instead
    of trying to match specific permission strings ('r', 'rw', ...).
    Hopefully this gives us a little better resilience if Subversion grows
    more authz codes.  Suggested by Jan Grant <jan.grant@bristol.ac.uk>.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1653 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-05-10 17:00:57 +00:00
cmpilato
10a2463c9f * lib/vcauth/svnauthz/__init__.py
(ViewVCAuthorizer.__init__): Perform some minor logic optimizations
    and cleanups.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1652 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-05-09 22:16:41 +00:00
cmpilato
abb8486da4 * lib/vcauth/svnauthz/__init__.py
(ViewVCAuthorizer.__init__): Fix a logic bug in access rights
    determination.  Patch by Jan Grant <jan.grant@bristol.ac.uk>.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1651 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-05-09 22:06:00 +00:00
cmpilato
f5defb51ae Fix parse of multi-user svnauthz groups.
* lib/vcauth/svnauthz/__init__.py
  (ViewVCAuthorizer._process_group): Fix a usage of string.strip()
    where string.split() was intended.  Noticed by 
    Jan Grant <jan.grant@bristol.ac.uk>.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1650 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-05-09 15:42:37 +00:00
cmpilato
0f57c5b5e3 Remove reference to merged-and-removed authz-dev branch.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1646 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-05-03 18:22:19 +00:00
cmpilato
0d6e57a823 * viewvc-install
(TREE_LIST): Install the contributed templates, too.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1644 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-05-03 18:02:36 +00:00
cmpilato
ed4c21c012 * lib/viewvc.py
Fix some long lines.  No functional changes.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1643 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-05-03 18:01:56 +00:00
cmpilato
e5d47a1314 * lib/viewvc.py
(view_directory): Move the tarball_href calculation from here...
  (common_template_data): ...to here (which I thought I'd already done...)


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1633 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-28 23:06:49 +00:00
cmpilato
5321434ca4 * bin/loginfo-handler
(Cvs1Dot12ArgParse): Handle the imported sources case, too.  Thanks to
    Mark Keisler <mark@mitsein.net> for pointing this out in IRC today.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1627 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-26 19:36:46 +00:00
cmpilato
dc19cf90ba Merge the authz-dev branch work into trunk. Let's let the pluggable authz
subsystem go mainstream!

* notes/authz-dev-TODO
* lib/vcauth/*
  New, copied from the authz-dev branch.

* viewvc.conf.dist
* lib/viewvc.py
* lib/query.py
* lib/debug.py
  Merge changes from the authz-dev branch.

* lib/config.py
  Merge changes from the authz-dev branch.  Also, make 'forbidden' the
  default value for 'authorizer'.

* docs/upgrading-howto.html
  Add sections about handling forbidden modules.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1623 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-25 20:07:13 +00:00
cmpilato
fac695eec4 Add an externals definition which pulls in contributed template sets
for ViewVC 1.1.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1621 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-25 19:41:15 +00:00
cmpilato
93696bc9c2 * docs/upgrading-howto.html
Don't refer to "ViewCVS 1.0".  It was "ViewVC 1.0".


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1618 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-18 16:00:37 +00:00
cmpilato
141419f852 * lib/blame.py
(make_html): Not that I think anybody actually cares, but fix this
    function to generate HTML properly.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1617 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-17 21:38:33 +00:00
cmpilato
e1f28b1bc0 * lib/viewvc.py
* lib/vclib/ccvs/rcsparse/common.py
* lib/vclib/ccvs/rcsparse/default.py
* lib/vclib/ccvs/rcsparse/texttools.py
* lib/vclib/ccvs/blame.py
* lib/blame.py
* lib/popen.py
  Replace stray tabs with spaces.  (Hopefully) no logic changes.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1616 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-17 21:07:33 +00:00
cmpilato
ee45fd32af * lib/config.py
(Config.load_config): Stash a reference to the primary
    ConfigParser() object.
  (Config.overlay_root_options): Use the stashed ConfigParser()
    reference instead of re-parsing the configuration file.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1612 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-17 03:47:34 +00:00
cmpilato
6982bbc7b0 Use forward-slash (/) as the separator in config section names between
override groupings and the base configuration section that is being
overridden.  Why?  Besides revealing a clear heirachy of information
(which seems more intuitive to me, at least), I anticipate it being
helpful for disambiguation later, especially since neither vhosts nor
root names should have forward slashes in them.

* viewvc.conf.dist
  (vhosts): Tweak the inline comments in accordance with this new plan.

* lib/config.py
  (Config._process_vhost, Config._process_root_options): Expect a
    forward slash (/) character where a hyphen (-) was previously
    expected.

* docs/upgrading-howto.html
  Update upgrade documentation with these changes.

* CHANGES
  Note that per-root configuration overrides are now supported.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1609 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-16 23:59:09 +00:00
cmpilato
204c6eb21c Add support for per-root option overrides using sections named
root-ROOTNAME-CONFIGSECTION.

In order to keep the configuration section naming conventions
consistent, change the way virtual host override sections are named
from VHOSTNAME-CONFIGSECTION to vhost-VHOSTNAME-CONFIGSECTION.

* lib/config.py
  (Config.load_config): Add optional 'rootname' parameter.  Actually
    make use of self.conf_path.  If there is a rootname provided,
    overlay per-root options.
  (Config._process_vhost): Now expect vhost section names to begin
    with the prefix "vhost-".
  (Config._find_canon_vhost): Minimize some logic.
  (Config.overlay_root_options, Config._process_root_options): New.
  (ViewVCConfigurationError, IllegalOverrideSection): New.
  (MalformedRoot): Now inherit from ViewVCConfigurationError.
  
* lib/viewvc.py
  (Request.run_viewvc): Once the rootname is determined, overlay
    per-root configuration options.

* viewvc.conf.dist
  (vhosts): Update vhosts docs and examples to note the new "vhost-"
    section name prefix.

* docs/upgrading-howto.html
  Note the change in vhost override section naming expectations.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1607 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-16 14:54:01 +00:00
cmpilato
0c773e789b Finish issue #287 by ensuring that in a clash of root names, the
first-listed, cvs_roots-found, CVS repository wins.

* lib/query.py
  (run_query): Ensure that in a rootname clash situation, the CVS
    repository wins.

* lib/viewvc.py
  (list_roots): Ensure that in a rootname clash situation, the CVS
    repository wins.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1605 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-13 09:14:12 +00:00
cmpilato
63aba8c173 Move the 'use_rcsparse' option from 'general' to 'options'.
* viewvc.conf.dist
  (use_rcsparse): Move this from the 'general' section to the
    'options' section.

* lib/config.py
  (Config.set_defaults): Track the move of the 'use_rcsparse' section.

* lib/viewvc.py
  (Request.run_viewvc): Track the move of the 'use_rcsparse' section.

* docs/upgrading-howto.html
  Note the option changes, and re-work the upgrading-from-1.0.0 option
  changes section a little bit while I'm here.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1604 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-13 08:15:05 +00:00
cmpilato
a0a1ea7a42 * viewvc.conf.dist
Clean up some more option documentation.

* templates/include/footer.ezt
  Stop treating the cfg.general.address like a free-form field.  If admins
  don't like the way we display the address by default, they need only 
  tweak the footer.ezt template.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1603 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-13 07:40:39 +00:00
cmpilato
62dff59068 * viewvc.conf.dist
Take a stab at documenting ViewVC's vhost support.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1602 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-13 07:11:35 +00:00
cmpilato
a2d187d4be Add the nightly build scripts to version control.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1599 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 16:39:46 +00:00
cmpilato
0961f1bb6c "Gaaaaah."
That's what I say to the Universe.

"Gaaaaah."

* viewvc.org/license-1.html
  Remove symlink.

* viewvc.org/who.html
* viewvc.org/index.html
* viewvc.org/contributing.html
* viewvc.org/download.html
* viewvc.org/faq.html
* viewvc.org/contact.html
  Point the "License" nav item to the HEAD version of LICENSE.html.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1598 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 16:23:44 +00:00
cmpilato
5a4e2c343b The whole license file dance is annoying. Just put the thing where it
wants to be -- where folks expect to find it -- and be done with it.

* viewvc.org/license-1.html
  Moved this...

* LICENSE.html
  ...to here, and stripped out site branding stuffs...

* viewvc.org/license-1.html
  ...but re-added a symlink.

* viewvc.org/.htaccess
  Add a redirect rule to point license-1.html URLs to the latest
  LICENSE.html file.

* tools/make-release
  Don't bother copying the LICENSE.html file any more -- it's already
  in place.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1597 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 16:10:38 +00:00
cmpilato
25b411f04f Add some steps to releases.txt.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1592 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 15:37:13 +00:00
cmpilato
f5bfd66019 * tools/make-release
Uh... actually copy the LICENSE.html file into place like the
  comment claims we do.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1591 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 15:28:41 +00:00
cmpilato
0dfb93969d Update copyright years.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1590 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 15:26:36 +00:00
cmpilato
8336ed6dce * viewvc.org/license-1.html
Bump copyright years.

* viewvc.org/styles.css
  (blockquote): Tweak margins and add a dotted border.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1589 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 15:24:53 +00:00
cmpilato
bfa13e4161 Lose some .cvsignore files.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1588 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 15:02:50 +00:00
cmpilato
00b8f8a74e * tools/make-release
Fix some bugs in this script which prevented the to-be-deleted
  directories from actually being deleted.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1586 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 07:04:51 +00:00
cmpilato
ffe04321f3 Copy 1.0.4 CHANGES block to trunk.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1585 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 06:55:04 +00:00
cmpilato
90109ce020 Note new latest release of ViewVC.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1584 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 06:50:33 +00:00
cmpilato
e2c6ed5202 (Hopefully) really finish issue #262 by enabling auto-commit in CVSdb SQL.
* lib/cvsdb.py
  (CheckinDatabase.Connect): Issue "SET AUTOCOMMIT=1" so that InnoDB
    databases automatically commit changes made to the database.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1579 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 05:56:17 +00:00
cmpilato
1324797377 * templates/include/diff_form.ezt,
* templates/include/pathrev_form.ezt
  Fix various XHTML validation errors.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1577 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-10 05:09:14 +00:00
cmpilato
0d0f8c789d Finish issue #180 - Query results cache staleness under mod_python
Remove the code which attempts to cache database connection wrapper
objects.  That was useful long ago when the ViewVC code was sloppier,
but now the database handles get passed around in the call stack, so
there's a 1-to-1 mapping of ViewVC process to database connection.
The cache is, therefore, entirely unnecessary (and is causing
problems, in fact, for mod_python users).

* lib/cvsdb.py
  (gCheckinDatabase, gCheckinDatabaseReadOnly): Remove.
  (ConnectDatabase): Add 'readonly' optional parameter.  Don't try to
    play the connection caching game any more -- nobody cares.
  (ConnectDatabaseReadOnly): Reimplement as a wrapper around ConnectDatabase().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1573 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-09 13:45:18 +00:00
cmpilato
e144eb6942 * lib/viewvc.py
(common_template_data): Don't forget to take 'pathrev' into account
    when calculating the revision for Subversion views.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1572 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-06 17:37:24 +00:00
cmpilato
1d5c053757 Finish issue #296 - Query links for SVN deletions produce bad links.
* lib/viewvc.py
  (build_commit): Rework the view URLs so that, for Subversion, URLs
    related to deleted paths point to the previous revision.  And don't
    bother generating diff URLs for adds and removes -- only changes.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1569 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-06 16:36:27 +00:00
cmpilato
e2f383baf8 * templates/include/footer.ezt,
* templates/include/header.ezt
  Fix some XHTML validation problems.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1568 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-06 16:35:17 +00:00
cmpilato
f7095d713d * lib/viewvc.py
(redirect_pathrev): Automagically transform bogus input into,
    essentially, "HEAD".


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1566 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-04 03:06:48 +00:00
cmpilato
3b5ae57380 * viewvc-install
(install_file): Use os.sep instead of '/' as the trailing slash in the
    "created" stdout line.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1564 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-02 19:35:56 +00:00
cmpilato
3b15cf11cc Turn on root_as_url_component by default for ViewVC 1.1.
* lib/config.py
  (Config.set_defaults): Enable options.root_as_url_component by default.

* viewvc.conf.dist
  (default_root): Describe this a little better.
  (root_as_url_component): Indicate that enabled is the default state.

* docs/upgrading-howto.html
  Add a note about the root_as_url_component option default change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1563 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-02 19:20:07 +00:00
cmpilato
a5f6b657cf * viewvc-install
(install_file): Test e.errno instead of e[0], because on Windows, a
    Windows-specific subclass of OSError (WindowsError) is raised, and the
    first item of its tuple representation is the Windows-specific
    error code.  But e.errno seems always to hold the OS-independent
    error value.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1561 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-02 16:32:13 +00:00
cmpilato
3edd4b3b01 Fix a bug reported by Jens Peters <jpeters7677@gmx.de> which causes
ViewVC to only generate links from a directory's "log view" to its
"directory view" when there's no sticky revision set.

* lib/viewvc.py
  (view_log): Always generate a directory's "directory view" link.  


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1559 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-02 13:26:32 +00:00
cmpilato
d25e5e3098 * windows/README
Update Python for Windows Extensions URL (they now live at SourceForge).

* lib/win32popen.py
  Suggest that the Python for Windows Extensions might not be installed
  when importing a module from that collection fails.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1557 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-04-02 12:38:33 +00:00
cmpilato
9672b6d711 * bin/svndbadmin
(SvnRev.__init__): Don't use secs_from_timestr() -- it never
    learned to accept optional pools.  Do the math ourselves.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1556 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-29 06:00:04 +00:00
cmpilato
4ee8ea34e1 * INSTALL
(SECURITY INFORMATION): Update this with the latest information
    about the checkout view and how to toggle its enablement.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1554 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-29 02:07:27 +00:00
cmpilato
a0e92a8679 * templates/docroot/styles.css,
* templates/annotate.ezt
  Try to make the annotate view stylations look a little more like
  those of the markup view.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1553 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-28 18:48:08 +00:00
cmpilato
bb246bf7c7 Begin the work of merging the markup and annotate views by at least
having them populate almost identical data dictionaries, and having
similar template headers.

* docs/upgrading-howto.html
  (Upgrading from 1.0.0): Note that 'mime_type', 'log', 'date', 'ago',
    'author', 'branches', 'tags', 'branch_points', 'changed', 'size',
    'state', 'vendor_branch', and 'prev' were added to annotate.ezt.

* docs/template-authoring-guide.html
  (Annotation View): Add 'mime_type', 'log', 'date', 'ago', 'author',
    'branches', 'tags', 'branch_points', 'changed', 'size', 'state',
    'vendor_branch', and 'prev'.

* templates/annotate.ezt
  Basically, replace the top of this thing with a copy of the top of
  markup.ezt.

* lib/viewvc.py
  (view_annotate): Populate almost an identical data dictionary to
    what the markup view uses.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1552 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-28 18:34:51 +00:00
cmpilato
2f9a4df28d Add recent changes.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1551 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-28 18:26:50 +00:00
cmpilato
f7bf5a511e Finish issue #244 by normalizing the input search directory values.
* lib/viewvc.py
  (view_query): Use _path_parts to cleanup the list of query directories.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1550 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-28 03:04:18 +00:00
cmpilato
d234219a4f Remove a change that was backported to 1.0.x.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1549 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-27 20:30:13 +00:00
cmpilato
580463a8ed Note some recently made CHANGES.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1547 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-27 20:27:02 +00:00
cmpilato
5ce1ab531d Finish issue #224 by allowing svndbadmin to optionally accept a range
of revisions for the 'update' operation.

* bin/svndbadmin
  (): Update the script's header comment.
  (main): Now accept a 'revs' list instead of a single integer revision.
  (_rev2int): New helper function.
  (usage): Update usage message.
  (__main__): Now allow a revision range to be specified, with support
    for the 'HEAD' keyword, too.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1546 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-27 20:22:22 +00:00
cmpilato
2860672524 * bin/svndbadmin
De-pool-ize the use of the Subversion bindings.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1545 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-27 20:17:49 +00:00
cmpilato
2efd7cc4af Unify the allowable views configury, and all support for disabling the
checkout view.  The former is for sanity, the latter for security.

* viewvc.conf.dist
  (allow_tar, allow_annotate, allow_markup): Removed.
  (allowed_views): New.

* lib/config.py
  (Config._force_multi_value): Add 'allowed_views'.
  (Config.set_defaults): Set default for 'allowed_views'; no longer set
    defaults for 'allow_tar', 'allow_annotate', 'allow_markup'.

* lib/viewvc.py
  (default_view, view_directory, download_tarball, get_file_view_info,
   view_annotate, view_diff, build_commit, view_revision, view_markup,
   view_checkout): Track changes, adding code to prevent checkout view
    URL generation when the view is disabled, and doing the same for
    markup views (which should have already been done, since we already
    had an allow_markup option!)

* templates/query_results.ezt
* templates/markup.ezt
* templates/directory.ezt
* templates/log.ezt
* templates/log_table.ezt
* templates/annotate.ezt
  Don't assume checkout and markup views are present.

* docs/upgrading-howto.html
  Update to show the configuration changes.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1544 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-27 19:03:37 +00:00
cmpilato
676ee09745 Rename the 'rev' view to the 'revision' view (at the CGI param level).
* lib/viewvc.py
  (_views): Rename the 'rev' view to the 'revision' view.  (This has
    always bugged me.)
  (Request.run_viewvc): Redirect old 'view=rev' URLs to 'view=revision'.

* docs/url-reference.html
  Update to reflect new URL syntax (and compatability support).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1543 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-27 17:39:43 +00:00
cmpilato
ac39b5ec6c * docs/url-reference.html
Reformat to (mostly) fit in 80 columns.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1542 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-27 17:31:33 +00:00
cmpilato
68a7d107e2 * lib/viewvc.py
(_orig_path, common_template_data, view_directory, view_revision,
   setup_diff): Catch vclib.InvalidRevision exceptions from
    repos._getrev(), and re-throw them as ViewVCExceptions.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1539 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-12 15:06:50 +00:00
cmpilato
ea04c73b36 * templates/error.ezt
Only show the stacktrace when we've not provided a user-friend error
  message.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1538 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-12 14:54:10 +00:00
cmpilato
5443c117e6 * bin/mod_python/viewvc_mp.py,
* bin/mod_python/query_mp.py
  Remove unnecessary reload() statements.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1537 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-09 16:37:51 +00:00
cmpilato
ef89f0db73 Rename the Mod_Python stub scripts to avoid triggering an import loop
detection error.

* bin/mod_python/viewvc.py,
* bin/mod_python/query.py
  Renamed these ...

* bin/mod_python/viewvc_mp.py,
* bin/mod_python/query_mp.py
  ... to these.

* viewvc-install
  Track the renamed stub scripts.

* docs/upgrading-howto.html
  Note the change to the Mod_Python stub script names.
  



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1536 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-03-09 16:04:31 +00:00
cmpilato
3c0ab3e163 * INSTALL
Add a note about the security implications of the checkout view,
  suggested by Moritz Naumann <security@moritz-naumann.com>.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1535 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-02-27 15:38:49 +00:00
cmpilato
300a8236cb Robustness fixes in the query stuffs where empty or missing revision
metadata occurs.

* lib/cvsdb.py
  (Commit.SetTime, Commit.GetTime, CheckinDatabase.AddCommit): Handle
    missing dates.

* bin/svndbadmin
  (SvnRev.__init__): Handle missing or invalid datestamps.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1534 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-02-26 20:20:04 +00:00
cmpilato
891dfa4b85 Robustness fixes where empty or missing revision metadata occurs.
* lib/vclib/svn/__init__.py
  (_datestr_to_date): Make this function more robust in the face of
    bogus datestamps.

* lib/viewvc.py
  (htmlify, format_log, make_time_string, make_rss_time_string,
    build_commit, view_directory): Make this functions more gracefully
    handle "None" revision metadata, and not generate data like
    "Unknown date" or "&nbsp;".
  
* templates/log.ezt,
* templates/markup.ezt,
* templates/rss.ezt,
* templates/revision.ezt,
* templates/log_table.ezt
  Handle empty revision metadata more gracefully.  


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1533 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-02-26 19:28:48 +00:00
cmpilato
e4527a3732 Un-bind ViewVC's core libraries from the assumption that sys.stdout is
the output stream.

* lib/viewvc.py
  (copy_stream): Don't supply a default value for 'dst', and don't
    special-case a value of None for it, either.
  (view_checkout, view_cvsgraph_image, view_doc): Pass
    request.server.file() as the 'dst' parameter to copy_stream().
  (view_patch): Pass request.server.file() as the 'dst' parameter to
    copy_stream().  Also, use request.server.file() instead of
    sys.stdout.
  (download_tarball): Use request.server.flush() instead of
    sys.stdout.flush().
  (view_error): Use server.file() instead of sys.stdout.

* lib/query.py
  (main): Use server.file() instead of sys.stdout.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1532 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-02-26 18:07:19 +00:00
cmpilato
169aba8c30 * viewvc.conf.dist (use_source_highlight): Default to 0.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1531 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-02-13 15:21:39 +00:00
cmpilato
3c426916d4 Add new CHANGES item for source-highlight integration.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1530 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-02-01 22:30:46 +00:00
cmpilato
8254d2d876 I think I'm finished messing around with source-highlight integration
now.  No, really!

* INSTALL
  Okay, no more messing around with lesser version.  source-highlight
  2.5 it is.

* lib/viewvc.py
  (MarkupSourceHighlight.__init__): Use 'sed' to strip unnecessary
    leading and close tags generated by source-highlight.  Also, pass
    a value of "l_" for the line number reference prefix, which makes
    this consistent with highlight's line IDs.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1529 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-02-01 22:16:44 +00:00
cmpilato
85f7720267 Miscellaneous cleanups around the source-highlight integration.
* templates/docroot/styles.css
  Remove source-highlight styles.  We can't reliably get that program
  to generate real style names.

* viewvc.conf.dist
  (source_highlight): Fix the sample path.

* lib/viewvc.py
  (MarkupSourceHighlight): Rework this to pipe the file contents into
    source-highlight on stdin, and don't try to enable CSS output or
    anything fancy, because source-highlight has too many bugs in this
    area.  Use --failsafe mode.

* INSTALL
  Change the recommendation for the version of source-highlight.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1528 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-02-01 21:52:30 +00:00
cmpilato
436e10e74c Add notes to INSTALL about using source-highlight.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1527 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-02-01 20:19:54 +00:00
cmpilato
473b853a5b Add optional integration with GNU source-highlight. Patch against
ViewVC 1.0.3 by Dirk Jagdmann <doj@tigris.org>, tweaked to adhere to
ViewVC 1.1-dev code and conventions by myself.

* viewvc.conf.dist
  (utilities.source_highlight, options.use_source_highlight,
   options.source_highlight_line_numbers): New.

* templates/docroot/styles.css
  Add new default styles for source-highlight output mode.

* lib/viewvc.py
  (MarkupSourceHighlight): New.

* lib/config.py
  (set_defaults): Set default values for utilities.source_highlight,
    options.use_source_highlight, and options.source_highlight_line_numbers.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1526 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-02-01 16:42:48 +00:00
cmpilato
77446e313a * lib/vclib/svn_ra/__init__.py
(created_rev): Because the way ra.svn_ra_get_dir() seems to work
    differently across versions of the Subversion Python bindings,
    build in some fault tolerance.  
    Tested by Eric Hanchrow <offby1@blarg.net>.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1525 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-31 21:08:45 +00:00
cmpilato
310db99e62 * lib/vclib/svn_ra/__init__.py
(created_rev): Update use of ra.svn_ra_get_dir().

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1524 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-31 19:39:13 +00:00
cmpilato
b597b6a485 Minor comment tweaks.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1523 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-26 20:03:03 +00:00
cmpilato
e7014db4cf Update the INSTALL file.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1521 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-26 16:49:13 +00:00
cmpilato
8f5e381f21 Fix issue #284 - Regression: "Modify query" link no longer functions.
* lib/viewvc.py
  (view_query): Restore a queryform_href calculation incorrect
    abstracted out (probably by me).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1520 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-23 20:56:28 +00:00
cmpilato
b7af5fc568 * bin/loginfo-handler
Add some more debugging, and consume stdin so CVS's pipe doesn't
  back up (which causes an abort()).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1518 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-23 19:51:05 +00:00
cmpilato
7e0d117de8 * bin/loginfo-handler
Fix the loginfo-handler's argument handling so that it works with 
  single-file commits in CVS 1.12.x.  

  Patch by: Cristian Tibirna <ctibirna@giref.ulaval.ca>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1517 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-23 19:50:05 +00:00
cmpilato
95f5f3bc9c * CHANGES
Note the fix for issue #234, committed in r1515.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1516 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-23 19:46:13 +00:00
cmpilato
b9044a9a9d Finish issue #234 - standalone.py uses not registered port per default.
According to http://www.iana.org/assignments/port-numbers, "The
Dynamic and/or Private Ports are those from 49152 through 65535".

* bin/standalone.py
  (Options): Change default port to 49152.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1515 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-23 17:56:49 +00:00
cmpilato
9e07c413fa Improve the error display when trying to view annotations on a binary file.
* lib/vclib/__init__.py
  (NonTextualFileContents): New Exception.

* lib/vclib/svn/__init__.py
  (BlameSource.__init__): Translate the Subversion error
    SVN_ERR_CLIENT_IS_BINARY_FILE in the new vclib.NonTextualFileContents 
    exception.

* lib/viewvc.py
  (view_annotate): Catch the new vclib.NonTextualFileContents exception.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1514 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-23 17:47:37 +00:00
cmpilato
c8645305c5 * CHANGES
Add the bugfix for issue #221 completed in r1512.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1513 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-23 17:33:20 +00:00
cmpilato
4750fd345c Finish issue #221 - Annotate confused by long author names
* lib/vclib/svn/__init__.py
  (_rootpath2url): New helper, cored from BlameSource.__init__().
  (BlameSource): Rework this class to use the Subversion client Python
    bindings, specifically a call to svn_client_blame2().
  (SubversionRepository.annotate): Use new _rootpath2url(), and
    update the called to BlameSource().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1512 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-23 17:31:02 +00:00
cmpilato
4f1259d64d * lib/vclib/svn/__init__.py
(_rev2optrev): Moved here from the svn_ra module.

* lib/vclib/svn_ra/__init__.py
  (_rev2optrev): Moved to the svn module (now pulled in indirectly).
  (SubversionRepository.__init__): Fix a leftover instance of a pool.
    Also, add a comment about svn_cmdline_setup_auth_baton().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1511 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-23 17:22:17 +00:00
cmpilato
ead2d603a2 * CHANGES
Note new search-by-log-message feature, committed in r1509.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1510 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-23 16:24:49 +00:00
cmpilato
79fe3a2919 Finish issue #22 - Query on Log Messages.
Add the ability to query the commit database by log message comment in
addition to the existing query parameters.

Patch by: David Skyba <davidskyba@users.sourceforge.net>

* lib/cvsdb.py
  (CheckinDatabase.CreateSQLQueryString): Add support for filtering
    query results by log message.
  (CheckinDatabaseQuery.__init__): Add new comment_list member.
  (CheckinDatabaseQuery.SetComment): New.

* lib/viewvc.py
  (_legal_params): Add 'comment' and 'comment_match' as valid query
    parameters.
  (view_queryform): Populate new 'comment' and 'comment_match' data
    dictionary items.
  (english_query, view_query): Handle the new 'comment' and
    'comment_match' query items.

* templates/query_form.ezt
  Add UI for filtering queries by log message.

* docs/url-reference.html
  (Query View): Note new comment= and comment_match= URL parameters.

* docs/template-authoring-guide.html
  (variables-query_form): Note new comment and comment_match data
    dictionary items.





git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1509 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-23 16:22:40 +00:00
cmpilato
c3aabd8b7c Finish issue #12 -- Long paths in tarballs get truncated.
Use a GNU tar extension when path names longer than 100 characters are
being packaged in our tarball output.  

Patch by: Klaus Rennecke <marion@users.sourceforge.net>

I tested this on a Solaris box that had both the native tar program
and GNU tar.  Without the patch, but the native and GNU tar programs
created files with truncated filenames.  With the patch, GNU tar worked as
expected; the native tar program created a '././@LongLink' file
whose contents were the long path, and additionally created the
file with the truncated path.

* lib/viewvc.py
  (generate_tarball_header): For paths longer than 100 characters, use
    a GNU tar extension which allows arbitrary path links.  Also, fix
    the "version" header item to be '00', not \0.
    
* templates/include/dir_footer.ezt
  Change the "download tarball" link text to indicate that we are
  now generating GNU tarballs.

  


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1507 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-23 15:35:44 +00:00
cmpilato
5977b3c4fe * lib/compat.py
(mkdtemp): Fix the compatibility implementation's use of mktemp(),
    which prior to Python 2.3 (the same release that mkdtemp() shows
    up) only supported a single "suffix" argument.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1506 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-22 17:25:07 +00:00
cmpilato
59ecb71c51 * lib/viewvc.py
(view_directory): Initialize file.size, too.  A follow-up to r1504.
  


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1505 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-22 17:15:24 +00:00
cmpilato
ed664972cb Optimize directory displays where paging is enabled and sorting by
filename by first sorting, then only fetching the extended revision
metadata information for the items that would survive the page
filtering.

Patch by: Gustavo De Nardin <gustavodn@mandriva.com>
          (Tweaked by me.)

* lib/viewvc.py
  (view_directory): Only fetch dirlogs for directory entries that will be 
    on "this page".


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1504 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-18 20:38:03 +00:00
cmpilato
9b625017bb * viewvc.org/faq.html
Drop a skeletal FAQ page into place, but don't hook it into the rest
  of the site, seein' as how there's no real content here yet.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1503 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-11 13:29:41 +00:00
cmpilato
e0221b21bf Provide another hint to folks for whom ViewVC can't find Subversion bindings.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1502 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-08 21:28:19 +00:00
cmpilato
04cb1cd74d Finish issue #262 - svndbadmin doesn't commit data to MySQL InnoDB tables
* lib/cvsdb.py
  (CheckinDatabase.AddCommit): Set plus_count and minus_count
    explicitly to '0', which seems to be required for some folks'
    MySQL installations.

* bin/make-database
  Explicitly declare that we want tables of type "MyISAM".

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1500 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-05 23:05:14 +00:00
cmpilato
cf862e4e68 * lib/cvsdb.py
(CheckinDatabase.AddCommit): Add some newlines, to purty up the
    Exception string.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1499 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-05 16:07:05 +00:00
cmpilato
497cc24bbe * lib/cvsdb.py
(CheckinDatabase.AddCommit): Add some more information to any Exceptions
    received while adding commits to the database.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1498 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-04 23:05:39 +00:00
cmpilato
39eab459b4 * lib/viewvc.py
(MarkupHighlight.__call__): Minor indentation fix.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1497 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-04 19:22:35 +00:00
cmpilato
942d84818e Fix issue #280. Follow-up to r1493 with tweaks to INSTALL for the new
svndbadmin usage.

* INSTALL
  (SQL CHECKIN DATABASE): Recommend the use of 'svndbadmin update REV'
    in post-commit hooks, and 'svndbadmin update --force REV' in
    post-revprop-change.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1496 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-03 14:37:25 +00:00
cmpilato
6a03c7a4dd Add a new "uri" format to EZT.
NOTE: This is not currently used in ViewVC.  I needed it in another
piece of software, but wanted the tweaks to be publicly available
somewhere.

* lib/ezt.py
  (FORMAT_URI, _uri_printer): New.
  (_printers): Add mapping for new URI-formatting code.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1495 8cb11bc2-c004-0410-86c3-e597b4017df7
2007-01-02 15:39:51 +00:00
cmpilato
dbf67f4c0b Add some missing issue IDs to CHANGES entries.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1494 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-12-21 21:44:42 +00:00
cmpilato
a1c093ca2c For Issue #271, implement 'purge' commands for both cvsdbadmin and
svndbadmin.  Teach the 'rebuild' commands to first purge existing data
and then crawl the repository.  Also, drop support for the 'rev'
parameter to 'svndbadmin rebuild', adding instead a '--force' option
to 'svndbadmin update'.

Suggested, and SQL commands offered, by Mark <mark@mitsein.net>.

* lib/cvsdb.py
  (CheckinDatabase.sql_delete, CheckinDatabase.PurgeRepository): New.

* bin/svndbadmin
  (handle_revision): Add 'force' parameter, used to force update of
    commits already recorded in the database.
  (main): Add 'force' parameter, passed on to handle_revision().
    Handle the new 'purge' command, and teach 'rebuild' to also purge.
  (usage): Update usage info.
  (__main__): Add support for 'update --force' and 'purge', and drop
    support for 'rebuild rev'.  Add a KeyboardInterrupt handler.

* bin/cvsdbadmin
  (usage): Add 'purge' usage info.
  (__main__): Rework command-line parameter handling.  Add support for
    'purge' command, and make 'rebuild' first do a purge.

* CHANGES
  Note this change.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1493 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-12-21 20:51:24 +00:00
cmpilato
c6db566501 Finish issue #276.
* bin/make-database
  Up the length of the people table's 'who' column to 128 characters.
  Suggested by: Ted Mielczarek <luserspaz@tigris.org>

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1492 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-12-21 16:54:41 +00:00
cmpilato
1d2b2d9c35 Allow highlight to choose the syntax language based on the file's
extension and contents.

Patch by: Christophe Delmon <cdelmon@tigris.org>

(Now, if only we could make highlight stop telling us via Apache's
error_log every time it doesn't recognize a filetype...)

* lib/viewvc.py
  (MarkupHighlight.__init__): No longer calculate the file extension,
    and drop the --syntax argument to highlight.
  (MarkupHighlight.__call__): New.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1491 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-12-21 16:26:03 +00:00
cmpilato
862d5b7132 Make viewvc-install able to be run from an arbitrary location (instead
of requiring that you run it while sitting in its containing directory).

* viewvc-install
  (_actual_src_path): New helper function.
  (replace_file): Move this functionality into...
  (install_file): ...here.  Also, normalize some variable names for
    consistency with...
  (install_tree): ...this.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1488 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-12-20 18:08:44 +00:00
rey4
bc295fb361 Interpret relative paths in viewvc.conf as being relative to the
directory where that file resides, instead of being relative to the
grandparent directory of viewvc.py. 

This change lets you set up multiple installations of ViewVC that 
share a common library directory, but are otherwise independent. It
also allows ViewVC to work more nicely with Gentoo's webapp-config.

Warning: This change may break ViewVC installations that use
VIEWVC_CONF_PATHNAME settings pointing at configuration files outside
the ViewVC install directory.

* lib/config.py
  (Config.path): new method returning paths relative to config file

* lib/viewvc.py
  (_install_path): removed function
  (get_view_template, view_cvsgraph_image, view_cvsgraph, view_doc):
    call cfg.path instead of _install_path
  (load_config): replace call to _install_path with equivalent inline
    code

* viewvc.conf.dist
    update comments referring to ViewVC install directory

* CHANGES
    document this change


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1487 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-12-20 16:37:34 +00:00
cmpilato
87fb74e580 Prep PyFontify.py for Python 2.6 readiness, and make it stop giving
the following warning in Python 2.5:

   Warning: 'with' will become a reserved keyword in Python 2.6

Reported by: Philip M. Gollucci <pgollucci@p6m7g8.com>

* lib/PyFontify.py
  (replace): Removed.  Callers now use string.replace().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1486 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-12-19 18:41:56 +00:00
cmpilato
01e10dd1bb Minor improvements to some exception strings and their handling.
* lib/viewvc.py
  (view_doc): Lose newline characters in exception messages.
  (Request.run_viewvc): Rewrite the unfound root exception messages to
    be a little less cryptic.

* templates/error.ezt
  No longer wrap exception messages in <pre> tags.  Also, pad error
  output with a bunch of space characters to IE's "Friend Error
  Messages" don't show up.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1485 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-12-18 20:40:00 +00:00
cmpilato
44d86248d1 Minor stylistic tweaks.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1484 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-12-14 20:01:19 +00:00
cmpilato
cb78995c4a * viewvc-install
(install_file, install_tree): Replace '/' with the OS-specific
    directory separator character in the destination path before processing.
    This is follow-up to r1458.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1483 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-12-14 19:42:09 +00:00
cmpilato
1592197d08 Add some links to ViewVC instances.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1482 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-12-06 20:19:44 +00:00
cmpilato
bb39ba6b22 Finish issue #273.
* templates/docroot/styles.css
  (vc_row_special): New style.

* templates/annotate.ezt
  Markup annotation hunks whose revision matches the request one
  differently.  While here, remove some unnecessary [define] blocks.

Suggested by:  Marco Colombo <marcol@tigris.org>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1481 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-12-04 19:07:04 +00:00
cmpilato
40c37a55f8 Fix a bug that prevented the population of 'rev' for annotate views.
* lib/viewvc.py
  (common_template_data): Accept the 'annotate' parameter as a valid source
    for the 'rev' data item.

Noticed by:  Marco Colombo <marcol@tigris.org>


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1480 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-12-04 19:04:16 +00:00
cmpilato
9d16bcb2a7 * INSTALL
(SUBVERSION INTEGRATION): Tweak the example for testing Subversion
    Python bindings installation to be useful, showing how to find the
    installed version of those bindings.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1479 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-11-30 21:36:56 +00:00
cmpilato
5fcdcd8b8a * lib/vclib/svn_ra/__init__.py
Purge the svn_ra module of unnecessary pools.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1476 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-11-09 21:09:05 +00:00
cmpilato
fa035c8ae7 * lib/vclib/svn/__init__.py
Bump version requirement to Subversion 1.3.1.  Also, remove
  unnecessary pools from the entirety of the module.

* lib/vclib/svn_ra/__init__.py
  Bump version requirement to Subversion 1.3.1.

* INSTALL
  Bump Subversion version requirement to Subversion 1.3.1.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1475 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-11-09 20:47:45 +00:00
cmpilato
d83ff39472 Followup to r1439, with the correct logic in generate_page().
* lib/viewvc.py
  (generate_page): Reverse the logic in the if/else to be correct.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1473 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-11-09 17:55:25 +00:00
cmpilato
118c6cc35e Allow ViewVC to work when rcsparse is backed by the tparse module.
* lib/vclib/ccvs/__init__.py
* lib/vclib/ccvs/blame.py
  Use rcsparse.parse() instead of rcsparse.Parser.parse() throughout.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1472 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-11-08 20:01:40 +00:00
cmpilato
5f22029349 * lib/vclib/ccvs/rcsparse/common.py
Remove dependency on compat.  It's time for rcsparse to be free, and by
  golly, it's okay if it requires Python 2.0 now to do it.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1471 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-11-08 19:59:11 +00:00
cmpilato
1920391b2a Add missing CHANGES item for full diff support.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1467 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-11-02 14:55:44 +00:00
cmpilato
a962fae87a * bin/loginfo-handler
(__main__): Fix a syntax error I overlooked.  Follow-up to r1463.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1465 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-11-02 03:56:53 +00:00
cmpilato
ff2ac1d824 (Effectively) whitespace changes only.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1464 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-11-02 03:19:40 +00:00
cmpilato
e4967b894a Update loginfo-handler to be able to deal with the new loginfo format
introduced in CVS's 1.12 line.

Issue number(s): 257
Patch mostly by: Mark <mark@mitsein.net>, tweaked by me.

* bin/loginfo-handler
  (Cvs1Dot12ArgParse): New.
  (HeuristicArgParse): Update comment -- the problems is no longer
    with "current" CVS, but with "older" ones.
  (__main__): Detect the use of newer CVS loginfo formatting, and
    parse the arguments accordingly.  Also, clean up some indentation
    inconsistency.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1463 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-11-02 03:13:53 +00:00
cmpilato
3d65a28a3c Add support for two levels of quietness to the obnoxiously noisy
cvsdbadmin script.

* bin/cvsdbadmin
  (UpdateFile, RecurseUpdate, RootPath): Add new 'quiet_level'
    argument.  Callers updated.
  (usage): Rewrite to indicate the existence of the new -q flag, and
    to look more like the svndbadmin usage message.
  (__main__): Parse the new -q argument.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1462 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-11-02 02:00:35 +00:00
cmpilato
ac60888eaf Add some debug code to facilitate tarball generation debugging.
* lib/debug.py
  (SHOW_TIMES, SHOW_CHILD_PROCESSES): Add some explanatary comments.
  (TARFILE_PATH): New.

* lib/viewvc.py
  (download_tarball): When tarball debugging is enabled, generate the tarfile
    at the configured location, and deliver either a cheap success message
    or an error view to the browser.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1461 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-11-01 14:24:41 +00:00
cmpilato
9caee0c04d * viewvc-install
(install_file, install_tree): Replace '/' with the OS-specific
    directory separator character in src_path before processing.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1458 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-27 14:58:04 +00:00
cmpilato
818c168978 Finish issue #266 -- Query result shows file names with @ as email
addresses.

The ultimate problem here was that email address recognition banks on
the final component of addresses "server" only have 2-4 characters in
it.  But the query code was doing a little more here than necessary
anyway, mistakenly using htmlify() instead of its subset, server.escape().

* lib/viewvc.py
  (view_query, english_query, build_commit): Use
    request.server.escape() instead of its superset, htmlify(), to
    format stuff that needs to be HTML-escaped, but doesn't
    necessarily need to try to recognize URLs and email addresses.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1456 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-18 01:11:33 +00:00
cmpilato
aaca4217a7 Try to note the changes so far which are aimed for release in 1.1.0.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1455 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-18 01:09:23 +00:00
cmpilato
63d07e6065 Begin a section for 1.1.0 in CHANGES.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1454 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-18 00:36:48 +00:00
cmpilato
21f68a5118 Finish issue #261 -- detect SVN repository from standalone.
* viewvc/bin/standalone.py
  (serve): Recognize Subversion repository paths provided via -r, too.
  (cli): Update the usage message.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1453 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-17 03:50:23 +00:00
cmpilato
7e55acdc5d * viewvc/bin/standalone.py
(serve): Fix some leftover references to the old cvsnt_exe_path
    config option.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1452 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-17 03:38:21 +00:00
cmpilato
9115900b3a * www/index.html
Bump the stated latest version number to 1.0.3.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1451 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-13 20:49:15 +00:00
cmpilato
8845bc551f Merge security fix made in r1446 from 1.0.x to trunk. That log message read:
Dictate UTF-8 as the output character set for all ViewVC
   template-driven views.
   
   * lib/sapi.py
     (CgiServer.header, ModPythonServer.header): Add "; charset=UTF-8" to
       the Content-type header in ViewVC output.
     (AspServer.header): If no content type is specified, set the content
       type to 'text/html; charset=UTF-8'.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1450 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-13 20:48:05 +00:00
cmpilato
4cebbf43df * CHANGES
Merge 1.0.3 change list from the 1.0.x branch.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1449 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-13 20:46:56 +00:00
cmpilato
1171d112b7 * lib/vclib/svn/__init__.py
(get_revision_info): Removing some debugging code accidentally
    committed in r1443.  Because life would be too easy if cmpilato
    weren't a sloppy coder, and we certainly can't have *that*.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1444 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-13 19:44:29 +00:00
cmpilato
c41ffe04e2 Followup to r1440, in which I butchered some code under the guise of
fixing issue #265.  Sheesh.

* viewvc/lib/vclib/svn/__init__.py
  (get_revision_info): Store ChangedPath items in a different hash
    than the one we get from the Subversion bindings so replacement
    detection works.  While here, add support for Subversion 1.4.0's
    new 'action' changed item member.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1443 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-13 19:26:03 +00:00
cmpilato
36e0d19fe3 Tweak releases.txt to point out our Tigris.org milestone sort key pattern.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1442 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-13 16:32:28 +00:00
cmpilato
5bf80b54f4 *** WARNING: THIS CHANGE BREAKS STUFF; ALSO NEED r1443 and r1444 ***
Finish issue #265 - ViewVC shows wrong path for items deleted from a
                    parent dir copied in the same revision

* lib/vclib/svn/__init__.py
  (ChangedPathSet): Remove.
  (get_revision_info): Stop using the streamy callback reporting form
    of repos.ChangeCollector(), because its got some ... deficiencies.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1440 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-13 15:59:00 +00:00
cmpilato
a6cad82e55 Remove some redundancy by teaching generate_page(), which is *always*
immediately preceded by a call to request.server.header(), to just
make that call itself.

* lib/viewvc.py
  (generate_page): Add 'content_type' parameter, and handle the call
    to request.server.header() here instead of it always preceding
    calls to this function.
  (view_markup, view_roots, view_directory, view_log, view_annotate,
   view_cvsgraph, view_diff, view_revision, view_queryform): Lose
    calls to request.server.header() -- generate_page() does this for
    us now.
  (view_query): Update calls to generate_page(), and lose calls to
    request.server.header().



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1439 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-10-12 17:04:15 +00:00
cmpilato
7784009c8e Bump the stated latest version of the software.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1438 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-09-29 17:15:31 +00:00
cmpilato
692f539c36 * notes/releases.txt
Fix sample `make-release' command-line, and recommended tag commit
  message.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1437 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-09-29 17:15:13 +00:00
cmpilato
bfdd4c0988 Merge 1.0.2 CHANGES into trunk's copy of the file.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1436 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-09-29 16:57:48 +00:00
cmpilato
6b84e92bdf Follow-up to r1407, fixing some calls to modified APIs that I
overlooked in that revision.  This fixes issue #264, reported against
the nightly build.

* bin/loginfo-handler
  (ProcessLoginfo): Pass cfg.utilities instead of cfg.general to
    BinCVSRepository().

* bin/cvsdbadmin
  (usage): Pass cfg.utilities instead of cfg.general to
    BinCVSRepository()


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1431 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-09-29 15:16:15 +00:00
cmpilato
3e882435f2 * viewvc.conf.dist
Make some tweaks recommended in IRC by user "[1]tony" to help folks
  better understand the configuration file format and usage.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1430 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-09-28 17:51:17 +00:00
rey4
aaf85a14a6 Update the PHP CGI hack and add a comment to the config file pointing
out the CLI/CGI distinction. Thanks to Mark <mark@mitsein.net> and
Brian G. Peterson <brian@braverock.com> for bringing this issue up
on the users' list.

* lib/viewvc.py
  (markup_stream_php): update the cgi hack

* viewvc.conf.dist
  (utilities.php): add comment


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1428 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-09-27 20:06:22 +00:00
cmpilato
acd8ab25e9 Minor vclib interface cleanup, adding a new Annotation object, and
having the Repository.annotate() implementations return lists of them
(instead of lists of those cool-but-overused-_item-thingies).

* lib/vclib/__init__.py
  (Repository.annotate): Note that this interface now returns
    Annotation objects.
  (Annotation): New.
  Also, do some docstring addition/modification elsewhere in this file.

* lib/vclib/ccvs/blame.py
  (BlameSource.__getitem__): Return vclib.Annotation objects now.
  (_item): Remove as unneeded.

* lib/vclib/svn/__init__.py
  (BlameSource.__getitem__): Return vclib.Annotation objects now.
  (_item): Remove as unneeded.

* lib/vclib/svn_ra/__init__.py
  (SubversionRepository._blame_cb): Store vclib.Annotation objects now.
  (_item): Remove as unneeded.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1427 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-08-18 22:35:14 +00:00
cmpilato
41e1ae4171 Expose the path for each root in the [roots] common template data
object, again with the same warnings applied to [rootpath] in r1425.

* lib/viewvc.py
  (common_template_data):  Expose the path for each root in the "roots"
    data item.

* docs/upgrading-howto.html,
* docs/template-authoring-guide.html
  Update the docs.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1426 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-08-18 16:05:29 +00:00
cmpilato
eb70cfaaec * lib/viewvc.py
(common_template_data): Expose request.rootpath as "rootpath".

* docs/upgrading-howto.html,
* docs/template-authoring-guide.html
  Note this new exposition, though with a warning about its use in an
  insecure environment.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1425 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-08-17 15:20:44 +00:00
cmpilato
7a51a39ba0 * lib/compat.py
(mkdtemp): Flesh out the parameter list for mkdtemp(), passing those
    params to mktemp().

* viewvc/lib/viewvc.py
  (MarkupEnscript.__call__): Give the temporary directory a "viewvc"
    prefix so it is more easily identifiable in the case of a
    problem.  Also, fix a minor indentation inconsistency.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1424 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-08-16 23:59:12 +00:00
cmpilato
3dcc42d802 Fix a bug noticed by Michael Guntsche <mike@it-loops.com> which caused
file formats covered by custom "streamer" syntax highlighters to not
be passed through escript or highlight when their respective custom
stream was disabled.

* lib/viewvc.py
  (view_markup): Correct the syntax highlighter choosing logic.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1422 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-08-16 16:25:46 +00:00
cmpilato
696feb50e0 Fix some bugs introduced in r1407. Noticed by maxb.
* lib/viewvc.py
  (download_tarball): Don't reference non-existant variable cfg until
    creating it as a reference to request.cfg.
  (MarkupPHP.__init__): Drop the 'php_exe_path' variable, and add
    'cfg'.  Use 'cfg' to get at the 'php_path' configury.
  (markup_stream_php): Update call to MarkupPHP().


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1421 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-08-03 21:39:46 +00:00
cmpilato
edc66442b4 Update contact information with the IRC channel.
* www/index.html
  Note the new IRC channel.

* viewvc.org/contact.html
  Note the new IRC channel, reorganize the text a bit, and provide a
  handy-dandy contact summary.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1420 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-08-02 16:06:02 +00:00
cmpilato
f64490de1c Finish issue #245 by making the generated RSS feed URL match
scheme-wise with the URL used to access ViewVC.  Patch by Troels Arvin
<tarvin@tigris.org>, tweaked by cmpilato.

* lib/viewvc.py
  (build_commit): If the environment variable HTTPS is set to "on", then
    construct the rss_url data dictionary item with an "https" method instead
    of an "http" one.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1417 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-08-01 18:12:30 +00:00
cmpilato
491e02f504 * lib/vclib/svn/__init__.py
(BlameSource.__init__):  Pass the --non-interactive flag to 'svn blame'
    so it doesn't wedge when cache authstuffs aren't available or
    sufficient.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1416 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-08-01 17:07:07 +00:00
cmpilato
60991a4743 Finish issue #208 (Annotate aborts on #include "./filename"). Patch
more or less by Russell Yanofsky.

* lib/blame.py
  (link_includes): Calculate include paths in such a way that '.' is
    dropped and '..' is normalized.  This should prevent us from
    sending paths through Subversion's APIs that aren't legal (and
    cause assertions to fire).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1414 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-08-01 16:45:35 +00:00
cmpilato
2bcda59f31 Fix some grammar issues and, while here, rant about SF.net a little bit.
Sorry -- unable to resist.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1413 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-31 21:23:09 +00:00
cmpilato
9a73f275ec Website tweaks, mostly visual and validational in nature.
* viewvc.org/who.html,
* viewvc.org/license-1.html,
* viewvc.org/download.html,
* viewvc.org/contributing.html,
* viewvc.org/index.html,
* viewvc.org/contact.html
  Add the cutesy, "Hey, we're valid XHTML" logo; remove the group email
  address (that's what the Contact page is for); fix XHTML validation issues; 
  add a working DOCTYPE marker; add <meta> definitions of a UTF-8 character
  set.

* viewvc.org/styles.css
  Minor tweaks to font sizes and margins, mostly.  Nothing altogether
  interesting.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1412 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-31 20:56:48 +00:00
cmpilato
aff7923450 Remove useless .cvsignore file.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1411 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-31 20:54:00 +00:00
cmpilato
06c202f98a * docs/template-authoring-guide.html
Fill in the remaining blanks in the template authoring guide, and fix
  one erroneous "depth" indicator in the markup.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1410 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-31 18:53:17 +00:00
cmpilato
7a038950d7 * docs/upgrading-howto.html
Bring this, I think, up-to-date with the 1.1.0 work-in-progress.
  Also, fix some colors to avoid using green save for "added" variables.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1409 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-28 11:59:31 +00:00
cmpilato
e34725c830 Remove spurious blank line.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1408 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-28 11:10:17 +00:00
cmpilato
528d4aec3d Cleanup ViewVC's configuration and use of external utilities by
creating a new section of the configuration file strictly for defining
the locations of these helper applications.

This closes issue #229 (configurable path to sed) and issue #62
(configurable path to diff), and perhaps others I failed to find.

* viewvc.conf.dist
  Add a new "utilities" section for corraling all the various
  tool-location configurations, and relocate (with some tweaks) a
  bunch of options:
     general.rcs_path => utilities.rcs_dir
     general.cvsnt_ext_path = utilities.cvsnt
     general.svn_path => utilities.svn
     options.enscript_path => utilities.enscript
     options.highlight_path => utilities.highlight
     options.py2html_path => utilities.py2html_dir
     options.php_exe => utilities.php
     options.cvsgraph_path => utilities.cvsgraph
     utilities.diff (new)
     utilities.gzip (new)
     utilities.sed (new)
     options.use_py2html (new)

* lib/config.py
  (_sections): Add 'utilities' section.
  (Config.set_defaults): Reflect options tweaks made to
    viewvc.conf.dist in the code here.

* lib/viewvc.py
  (Request.run_viewvc): Track renamed utilities.svn option.  Now pass
    cfg.utilities into BinCVSRepository(), CCVSRepository(), and
    SubversionRepository().  Collapse now-identical
    SubversionRepository() calls.
  (markup_stream_python): Return immediately if options.use_py2html
    isn't set.  Track renamed utilities.py2html_dir option.
  (view_cvsgraph_image, view_cvsgraph): Track renamed
    utilities.cvsgraph option.
  (MarkupPHP.__init__): Track renamed utilities.php option, and allow
    for 'php' as a fallback value.
  (MarkupHighlight.__init__): Track renamed utilities.highlight option.
  (MarkupEnscript.__init__): Track renamed utilities.enscript option,
    and honor new utilities.sed option.
  (download_tarball): Use new utilities.gzip option.

* lib/vclib/__init__.py
  (_diff_fp.__init__): Add 'diff_cmd' parameter.

* lib/vclib/svn/__init__.py
  (SubversionRepository.__init__): Drop 'svn_path' parameter, and now
    accept 'utilities'.
  (SubversionRepository.rawdiff): Pass self.diff_cmd to _diff_fp().

* lib/vclib/svn_ra/__init__.py
  (SubversionRepository.rawdiff): Pass self.diff_cmd to _diff_fp().

* lib/vclib/ccvs/__init__.py
  (CCVSRepository.rawdiff): Pass self.utilities.diff or 'diff' to _diff_fp().

* lib/vclib/bincvs/__init__.py
  (CVSRepository.__init__): Add 'utilities' parameter.
  (BinCVSRepository.__init__): Lose as no-longer-necessary.
  (BinCVSRepository.rcs_popen): Track renamed options, and renamed
    member variable that hold those options.

* docs/upgrading-howto.html
  Note these options changes.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1407 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-28 11:04:12 +00:00
cmpilato
789f13c9f7 Stub out a section in the upgrading-howto.html document for 1.1.0.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1406 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-28 10:22:17 +00:00
cmpilato
090dbd7d3b Add a step in releases.txt for updating the Issue Tracker configuration.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1405 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-28 08:18:20 +00:00
cmpilato
a92daef556 Add 'nightly' to the svn:ignores.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1404 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-26 20:43:48 +00:00
cmpilato
83b1c6937a * viewvc.org/download.html,
* viewvc.org/contributing.html,
* viewvc.org/index.html,
* viewvc.org/contact.html
  Oops.  Forgot to commit these removed nav references to upgrading.html.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1403 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-26 20:30:59 +00:00
cmpilato
f817d8149c Add .htaccess file. No sense in not versioning it.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1402 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-26 20:29:42 +00:00
cmpilato
8bbe853ffe Do a documentation reorganization I've been dying to do for some time
now.  Get stuff that's aimed at regular developers off our website,
get the website out of our release tarballs, while letting the docs/
that ViewVC admins need remain in the tarballs.

* docs/
  New directory.

* docs/url-reference.html,
* docs/template-authoring-guide.html
  Moved these documents, which hardly need to live on our public website, here ...

* viewvc.org/url-reference.html,
* viewvc.org/template-authoring-guide.html
  ... from here.

* docs/upgrading-howto.html
  Move (and renamed, and de-website-ized) this...

* viewvc.org/upgrading.html
  ... from here.

* notes/
  New directory for developer notes.

* notes/releases.txt
  New, cored out of the contributing.html file, and greatly updated to
  track the reality of our new Subversion-land release process.

* notes/TODO
  Move here ...

* TODO
  ... from here.

* viewvc.org/who.html,
* viewvc.org/license-1.html
  Lose references to upgrading.html.

* viewvc.org/contributing.html
  Lose references to upgrading.html, and move the release rolling
  instructions out to notes/releases.txt.
 
* tools/make-release
  Also delete viewvc.org/ and notes/ from the distribution.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1401 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-26 20:19:22 +00:00
cmpilato
0bb2dc9f16 * viewvc.org/template-authoring-guide.html
Track new location of tarball_href.  Followup to r1399.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1400 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-24 14:53:41 +00:00
cmpilato
8612acd3c2 * lib/viewvc.py
(common_template_data): Populate tarball_href data dictionary member here,
    instead of ...
  (view_directory): ... here.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1399 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-24 14:52:39 +00:00
cmpilato
3d98a33ce7 Fix issue #18 (Annotate not working in windows for subversion).
Thanks to Hernán Martínez Foffani <hernan.martinez@ecc.es> for testing
this patch on Windows.

* lib/vclib/svn/__init__.py
  (BlameSource.__init__): Patch up the URLs passed to 'svn blame' on
    systems that don't use forward-slashes for path separators.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1396 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-21 09:47:19 +00:00
cmpilato
362ff5cde6 * viewvc-install
Complete rework this script for uniform code formatting, more readable
  output, support for a fully non-interactive install mode, installation
  of the unmodified configuration files (so folks can see their customizations
  well after they make them), and any other cleanups I could get my hands on.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1394 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-21 09:36:10 +00:00
cmpilato
d6489c2026 * CHANGES
Merge in 1.0.1 changes.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1392 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-21 01:02:38 +00:00
cmpilato
b8cbcda7ae * www/index.html
Bump note about the latest release to 1.0.1.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1391 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-21 00:42:24 +00:00
cmpilato
2fa593f359 Repair a paragraph suffering from missing words.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1390 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-20 22:31:54 +00:00
cmpilato
dcc79ade05 Correct a bunch of paths in the INSTALL document. Reported by
Arnaud Quiblier <aquiblier@gmail.com>.

* INSTALL
  Tweaky tweaky...


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1386 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-20 16:46:52 +00:00
cmpilato
323f09f7af Finish issue #250 -- Tarballs from Subversion repositories don't
preserve empty directories.

* lib/viewvc.py
  (generate_tarball): Add new (optional) dir_mtime parameter, used to specify
    the modification time of the current directory while generating tarball
    data.  Now, allow empty directories in Subversion tarballs (while
    preserving the "pruning" behavior for CVS tarballs).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1384 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-14 20:03:15 +00:00
cmpilato
b12a220928 Finish issue #249.
* lib/query.py
  (main): Add 'rss_href' to the data dictionary so the template
    doesn't freak out.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1382 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-14 18:32:42 +00:00
cmpilato
f448035ca4 * bin/standalone.py
(GUI.__init__): Fix minor spelling errors.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1381 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-14 18:23:29 +00:00
cmpilato
d8d2075d65 Finish issue #235.
* bin/standalone.py
  (Options):  Add daemon member.
  (cli): Add support for --daemon/-d option.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1380 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-14 18:08:28 +00:00
cmpilato
08c145ddc0 * bin/standalone.py
(cli): Tweak the layout of the usage message, print it to stderr,
    and report error details.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1379 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-14 17:37:48 +00:00
cmpilato
bb4204af9a Finish issue #241.
* lib/viewvc.py
  (get_file_view_info): Fix an oops which caused some whack URL
    generation for download-as-text links on files whose path has changed
    over time.
   


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1377 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-14 15:47:18 +00:00
cmpilato
2fcd41ded0 Finish issue #237.
Patch by: Russell Yanofsky <russ@yanofsky.org>
Verified by: Oliver Koltermann <ok1@tigris.org>

* lib/vclib/bincvs/__init__.py
  (_tag_tuple): Return () instead of raising a ValueError for
    single-component revisions.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1375 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-14 15:29:25 +00:00
cmpilato
df68135a6f Add some helpful text and warnings to the sample conf file, closing issue 248.
* viewvc.conf.dist
  Add a skeletal glossary of sorts, and warn that "forbidden" is only for
  modules, not roots.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1374 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-07-12 04:18:39 +00:00
maxb
87bbbba821 * lib/vclib/ccvs/rcsparse/texttools.py: Document what the texttools tag table
actually means, in terms of logical control flow.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1373 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-06-02 18:10:52 +00:00
maxb
3b40b8e245 * tparse/tparse.h: For istream, include <istream>, not <iostream>.
Incidentally, this avoids initializing the cin/cout/cerr/clog
    infrastructure - which is good, because that's somehow triggering a
    platform-specific bug on Cygwin, at the moment!


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1372 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-26 23:31:41 +00:00
maxb
b9102d4649 Resolve some inconsistency in the rcsparse library, concerning the parsing of
colons, which has an impact on symbols and locks.

Fixes a bug where the texttools backend would fail to parse RCS files
containing locks.

Fixes inelegance in the default backend, which no longer needs to override a
rather large chunk of the common code.

* lib/vclib/ccvs/rcsparse/default.py
  (_TokenStream.token_term): Add colon to set.
  (_TokenStream.get): Handle colon as a discrete token, just like semicolon.
  (Parser.parse_rcs_admin): Remove override definition entirely.

* lib/vclib/ccvs/rcsparse/common.py
  (_Parser.parse_rcs_admin): Fix "locks" clause to be consistent with colon
    being a token.

Lastly, the tparse backend: the changes made here are roughly congruent to
those made to the default backend, however they are completely untested, since
the current tparse in the repository seems broken - it dies due to memory
corruption.

* tparse/tparse.cpp (Token_term): Add colon to set.
  (TokenParser::get): Handle colon as a discrete token, just like semicolon.
  (tparseParser::parse_rcs_admin): Remove bizarre code which attempted to
    handle both the case of being, and not being, a discrete token via runtime
    detection.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1371 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-26 23:18:46 +00:00
maxb
dba9027f85 * tparse/Setup.py: Set svn:executable.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1370 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-26 19:14:45 +00:00
cmpilato
70530d1018 Apply the patch in issue #239, provided by "mbroadbent (Mark B)".
* templates/include/footer.ezt
  Fix an XHTML validation error caused by not closing an <A> tag.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1367 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-26 15:43:41 +00:00
cmpilato
464cf13729 * lib/viewvc.py
(DiffSource.__init__, DiffSource._get_row, DiffSource._flush_row):
    Add support for tracking the left-hand line numbers, too.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1366 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-20 07:19:32 +00:00
cmpilato
f70e9fdc4e * lib/viewvc.py
(view_diff): Fix call to common_template_data(), and avoid a path-from-parts
    reconstruction that's already been performed.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1365 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-20 07:08:53 +00:00
cmpilato
0e750439f8 Merge the commonize-navdata branch into the trunk. For change log
information, see these revisions:

r1348 | cmpilato | 2006-04-25 10:01:17 -0400 (Tue, 25 Apr 2006) | 17 lines
r1343 | cmpilato | 2006-04-20 04:00:21 -0400 (Thu, 20 Apr 2006) | 23 lines


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1364 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-19 15:40:24 +00:00
cmpilato
eedbe8b649 * tools/make-release
Only try to delete directories that exist (to reduce noise).

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1363 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-19 15:37:56 +00:00
cmpilato
a9de320c0e Consistify version heading formats, and lose intra-release dates.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1360 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-18 17:30:06 +00:00
rey4
dabc194191 Update old paths in installation docs. Patch and bug report from
Jens Seidel (jensseidel) in issue 236

* INSTALL
* viewvc-install


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1358 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-15 22:37:24 +00:00
rey4
3fdfabc8ee Fix exception on log page when use_pagesize is enabled. Patch from
Jay Rossiter / Signe <signe@cothlamadh.net> on users' list.

* lib/viewvc.py
  (view_log): call paging() with right arguments


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1357 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-15 22:21:15 +00:00
rey4
87c95ac6f8 Merge -r1354 from the `commonize-navdata' branch. It was an accidental
commit, the change was supposed to be for the trunk

* www/index.html
    update latest release section


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1355 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-02 13:38:42 +00:00
cmpilato
4b30fca3bf * CHANGES
Add date for the 1.0.0 release.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1353 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-01 21:21:30 +00:00
cmpilato
bebbc247c9 Merge -r1349 from the `commonize-navdata' branch (it was actually
intended for trunk anyway).

* viewcvs.sourceforge.net/
  Remove this tree.  It really doesn't need to persist in HEAD, and
  the SourceForge publishing directory isn't even a working copy of
  this location (because at the time, SF didn't support Subversion).


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1350 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-05-01 19:30:54 +00:00
rey4
c72910f422 Add title attributes to links that don't have other descriptive text.
Change related to issue 227 filed by Steve Rowe (steve_rowe).

* templates/include/dir_header.ezt
* templates/include/header.ezt
* templates/dir_new.ezt
* templates/revision.ezt


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1347 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-04-24 02:18:02 +00:00
rey4
669ea3162b Implement support for full diffs. Change based on a patch from
Jacob Nevins (sourceforge user "jtn") in issue 153.

* lib/vclib/__init__.py
  (_diff_args): perform full diff when "context" option is None
  
* lib/viewvc.py
  (view_diff): add logic for full diffs
  
* templates/diff.ezt
* templates/include/diff_form.ezt
    add option for full diffs

* viewvc.org/template-authoring-guide.html
* viewvc.org/url-reference.html
    update documentation for "diff_format" template variable and url param
  
    


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1346 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-04-23 21:53:00 +00:00
rey4
d9777eef27 Fix possible incompatibility between loginfo-handler script and
cvs 1.12.9. Based on bug report and patch from sourceforge user
"grubert" in issue 151

* bin/loginfo-handler
  (HeuristicArgParse): accept alternate command lines for
    commits of new and imported directories


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1345 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-04-23 20:38:54 +00:00
rey4
eb5ccaf906 Fix bug intepreting EZT substitution patterns
* lib/ezt.py
  (_write_value): fix logic error from wrong indentation


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1344 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-04-21 13:27:20 +00:00
cmpilato
d61e0b8e2c * viewvc.org/download.html
Thomas Güttler points out that apparently tigris.org's new "guest"
  user password is the empty string.
  


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1341 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-04-20 06:59:01 +00:00
cmpilato
e0d1a728a5 Fix a bug in the revision view URL generation and auto-upgrade.
* lib/viewvc.py
  (Request.run_viewvc): Translate 'rev' parameter to 'revision'
    (instead of to 'pathrev') in the revision view.

* templates/revision.ezt
  Use "revision" instead of "rev" for the jump_rev form input box.
  Patch by fengxj <fengxiangjun@neusoft.com>.



git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1339 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-04-20 06:53:42 +00:00
cmpilato
b749971cdf * templates/dir_new.ezt
Use pixels instead of percentages for the first column.  Also, make sure all
  the *_icon_link items are defined for all path types.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1338 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-04-19 05:54:36 +00:00
cmpilato
171670a621 * templates/dir_new.ezt
Followup to r1335.  Drop whitespace from the icon column, and stop setting
  the font-size to 0 there.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1337 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-04-19 05:40:40 +00:00
cmpilato
4c96e86027 Make the dir_new template able to show as much of the log message as
can fix on the screen, and have a fixed layout (which promotes rapid
navigation).

* lib/viewvc.py
  (view_directory): Don't truncate rows.log any more, but provide a
    new member rows.short_log that is truncate.

* viewvc.org/upgrading.html
  Note rename of directory entries' "log" variable to "short_log".

* viewvc.org/template-authoring-guide.html
  Describe entries.log and (new) entries.short_log.

* templates/docroot/styles.css
  (table.fixed, table.fixed td): New fixed table styles, for use with
    the dir_new template.

* templates/dir_new.ezt
  Use new fixed table styles, and display as much of the log messages
  as screen-real-estate-ily possible (with ellipsis for truncation on
  IE, even).

* templates/directory.ezt
  Use entries.short_log now instead of entries.log.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1335 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-04-14 04:58:33 +00:00
cmpilato
24558586a8 * templates/docroot/styles.css
New "vc_icon" style.

* templates/include/footer.ezt,
* templates/include/file_header.ezt,
* templates/dir_new.ezt,
* templates/query_form.ezt,
* templates/revision.ezt,
* templates/directory.ezt,
* templates/roots.ezt
  Use 'class="vc_icon"' instead of 'width="16" height="16"'.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1334 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-04-14 04:35:13 +00:00
rey4
9bc2a1e1f2 Make rlog parsing compatible with output from Debian's 5.7-18
RCS package, which outputs CVS commit ids when present. Change
based on patch Olivier 'zer0' MATZ <zer0@droids-corp.org>
sent to the issues list.

* lib/vclib/bincvs/__init__.py
  (_re_log_info): update to match lines with commit ids


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1333 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-04-14 03:45:31 +00:00
rey4
9ec5d1f09e Doc updates
* CHANGES
* INSTALL
* viewvc.org/index.html
* viewvc.org/upgrading.html
* windows/README


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1331 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-04-09 16:02:01 +00:00
cmpilato
956482e96b * www/index.html
(Latest Release): New section.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1330 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-04-06 20:48:18 +00:00
cmpilato
3c55e5eaf8 * lib/viewvc.py
(__version__): Bump to 1.1-dev.

git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1328 8cb11bc2-c004-0410-86c3-e597b4017df7
2006-04-06 19:54:29 +00:00
383 changed files with 28205 additions and 9001 deletions

449
CHANGES
View File

@@ -1,53 +1,402 @@
Version 1.0 (not yet released)
4Intra.net/CUSTIS improvements
* Support for full-text search over file contents, including binary
documents like *.doc and so on using Sphinx Search and Apache Tika
server. Patched Tika with fixes for #TIKA709 and #TIKA964 is highly
recommended:
http://wiki.4intra.net/public/tika-app-1.2-fix-TIKA709-TIKA964.jar
(SHA1 efef722a5e2322f7c2616d096552a48134dc5faa)
* Access right checks in query results.
* Access right checks for repository root directories.
* New query parameters: repository, repo type, revision number.
* Authorizer for CVSnt ACLs.
* InnoDB, additional database indexes and some search query
optimisations.
* Support for specifying path to MySQL UNIX socket.
* Asynchronous hook examples for updating SVN and CVS repos.
* Slightly more correct charset guessing, especially for Russian.
* Support for diffing added/removed files.
* File lists in RSS feeds for 'classic' template.
* Path configuration via a single 'viewvcinstallpath.py' file,
not via editing multiple bin/* files.
* Link to repository list instead of viewvc.org from the logo
* "rcsfile service" support used to workaround command execution
problems (forks) from Apache mod_python.
Version 1.2.0 (released ??-???-????)
* bumped minimum support Python version to 2.4
* implemented support for property diffs (issue #383)
* allow user-configurable cvsgraph display (issue #336)
* allow rNNNN syntax for Subversion revision numbers (issue #441)
Version 1.1.20 (released 24-Apr-2013)
* fix tab-to-space handling regression in markup view
* fix regression in root lookup handling (issue #526)
Version 1.1.19 (released 22-Apr-2013)
* improve root lookup performance (issue #523)
* new 'max_filesize_kbytes' config option and handling (issue #524)
* tarball generation improvements:
- preserve Subversion symlinks in generated tarballs (issue #487)
- reduce memory usage of tarball generation logic
- fix double compression of generated tarballs (issue #525)
* file content handling improvements:
- expanded support for encoding detection and transcoding (issue #11)
- fix tab-to-space conversion bugs in markup, annotate, and diff views
- fix handling of trailing whitespace in diff view
* add support for timestamp display in ISO8601 format (issue #46)
Version 1.1.18 (released 28-Feb-2013)
* fix exception raised by BDB-backed SVN repositories (issue #519)
* hide revision-less files when rcsparse is in use
* include branchpoints in branch views using rcsparse (issue #347)
* miscellaneous cvsdb improvements:
- add --port option to make-database (issue #521)
- explicitly name columns in queries (issue #522)
- update MySQL syntax to avoid discontinued "TYPE=" terms
Version 1.1.17 (released 25-Oct-2012)
* fix exception caused by uninitialized variable usage (issue #516)
Version 1.1.16 (released 24-Oct-2012)
* security fix: escape "extra" diff info to avoid XSS attack (issue #515)
* add 'binary_mime_types' configuration option and handling (issue #510)
* fix 'select for diffs' persistence across log pages (issue #512)
* remove lock status and filesize check on directories in remote SVN views
* fix bogus 'Annotation of' page title for non-annotated view (issue #514)
Version 1.1.15 (released 22-Jun-2012)
* security fix: complete authz support for remote SVN views (issue #353)
* security fix: log msg leak in SVN revision view with unreadable copy source
* fix several instances of incorrect information in remote SVN views
* increase performance of some revision metadata lookups in remote SVN views
* fix RSS feed regression introduced in 1.1.14
Version 1.1.14 (released 12-Jun-2012)
* fix annotation of svn files with non-URI-safe paths (issue #504)
* handle file:/// Subversion rootpaths as local roots (issue #446)
* fix bug caused by trying to case-normalize anon usernames (issue #505)
* speed up log handling by reusing tokenization results (issue #506)
* add support for custom revision log markup rules (issue #246)
Version 1.1.13 (released 23-Jan-2012)
* fix svndbadmin failure on deleted paths under Subversion 1.7 (issue #499)
* fix annotation of files in svn roots with non-URI-safe paths
* fix stray annotation warning in markup display of images
* more gracefully handle attempts to display binary content (issue #501)
Version 1.1.12 (released 03-Nov-2011)
* fix path display in patch and certain diff views (issue #485)
* fix broken cvsdb glob searching (issue 486)
* allow svn revision specifiers to have leading r's (issue #441, #448)
* allow environmental override of configuration location (issue #494)
* fix exception HTML-escaping non-string data under WSGI (issue #454)
* add links to root logs from roots view (issue #470)
* use Pygments lexer-guessing functionality (issue #495)
Version 1.1.11 (released 17-May-2011)
* security fix: remove user-reachable override of cvsdb row limit
* fix broken standalone.py -c and -d options handling
* add --help option to standalone.py
* fix stack trace when asked to checkout a directory (issue #478)
* improve memory usage and speed of revision log markup (issue #477)
* fix broken annotation view in CVS keyword-bearing files (issue #479)
* warn users when query results are incomplete (issue #433)
* avoid parsing errors on RCS newphrases in the admin section (issue #483)
* make rlog parsing code more robust in certain error cases (issue #444)
Version 1.1.10 (released 15-Mar-2011)
* fix stack trace in Subversion revision info logic (issue #475, issue #476)
Version 1.1.9 (released 18-Feb-2011)
* vcauth universal access determinations (issue #425)
* rework svn revision info cache for performance
* make revision log "extra pages" count configurable
* fix Subversion 1.4.x revision log compatibility code regression
* display sanitized error when authzfile is malformed
* restore markup of URLs in file contents (issue #455)
* optionally display last-committed metadata in roots view (issue #457)
Version 1.1.8 (released 02-Dec-2010)
* fix slowness triggered by allow_compress=1 configuration (issue #467)
* allow use of 'fcrypt' for Windows standalone.py authn support (issue #471)
* yield more useful error on directory markup/annotate request (issue #472)
Version 1.1.7 (released 09-Sep-2010)
* display Subversion revision properties in the revision view (issue #453)
* fix exception in 'standalone.py -r REPOS' when run without a config file
* fix standalone.py server root deployments (--script-alias='')
* add rudimentary Basic authentication support to standalone.py (issue #49)
* fix obscure "unexpected NULL parent pool" Subversion bindings error
* enable path info / link display in remote Subversion root revision view
* fix vhost name case handling inconsistency (issue #466)
* use svn:mime-type property charset param as encoding hint
* markup Subversion revision references in log messages (issue #313)
* add rudimentary support for FastCGI-based deployments (issue #464)
* fix query script WSGI deployment
* add configuration to fix query script cross-linking to ViewVC
Version 1.1.6 (released 02-Jun-2010)
* add rudimentary support for WSGI-based deployments (issue #397)
* fix exception caused by trying to HTML-escape non-string data (issue #454)
* fix incorrect RSS feed Content-Type header (issue #449)
* fix RSS <title> encoding problem (issue #451)
* allow 'svndbadmin purge' to work on missing repositories (issue #452)
Version 1.1.5 (released 29-Mar-2010)
* security fix: escape user-provided search_re input to avoid XSS attack
Version 1.1.4 (released 10-Mar-2010)
* security fix: escape user-provided query form input to avoid XSS attack
* fix standalone.py failure (when per-root options aren't used) (issue #445)
* fix annotate failure caused by ignored svn_config_dir (issue #447)
Version 1.1.3 (released 22-Dec-2009)
* security fix: add root listing support of per-root authz config
* security fix: query.py requires 'forbidden' authorizer (or none) in config
* fix URL-ification of truncated log messages (issue #3)
* fix regexp input validation (issue #426, #427, #440)
* add support for configurable tab-to-spaces conversion
* fix not-a-sequence error in diff view
* allow viewvc-install to work when templates-contrib is absent
* minor template improvements/corrections
* expose revision metadata in diff view (issue #431)
* markup file/directory item property URLs and email addresses (issue #434)
* make ViewVC cross copies in Subversion history by default
* fix bug that caused standalone.py failure under Python 1.5.2 (issue #442)
* fix support for per-vhost overrides of authorizer parameters (issue #411)
* fix root name identification in query.py interface
Version 1.1.2 (released 11-Aug-2009)
* security fix: validate the 'view' parameter to avoid XSS attack
* security fix: avoid printing illegal parameter names and values
* add optional support for character encoding detection (issue #400)
* fix username case handling in svnauthz module (issue #419)
* fix cvsdbadmin/svnadmin rebuild error on missing repos (issue #420)
* don't drop leading blank lines from colorized file contents (issue #422)
* add file.ezt template logic for optionally hiding binary file contents
Version 1.1.1 (released 03-Jun-2009)
* fix broken query form (missing required template variables) (issue #416)
* fix bug in cvsdb which caused rebuild operations to lose data (issue #417)
* fix cvsdb purge/rebuild repos lookup to error on missing repos
* fix misleading file contents view page title
Version 1.1.0 (released 13-May-2009)
* add support for full content diffs (issue #153)
* make many more data dictionary items available to all views
* various rcsparse and tparse module fixes
* add daemon mode to standalone.py (issue #235)
* rework helper application configuration options (issues #229, #62)
* teach standalone.py to recognize Subversion repositories via -r option
* now interpret relative paths in "viewvc.conf" as relative to that file
* add 'purge' subcommand to cvsdbadmin and svndbadmin (issue #271)
* fix orphaned data bug in cvsdbadmin/svndbadmin rebuild (issue #271)
* add support for query by log message (issues #22, #121)
* fix bug parsing 'svn blame' output with too-long author names (issue #221)
* fix default standalone.py port to be within private IANA range (issue #234)
* add unified configury of allowed views; checkout view disabled by default
* add support for ranges of revisions to svndbadmin (issue #224)
* make the query handling more forgiving of malformatted subdirs (issue #244)
* add support for per-root configuration overrides (issue #371)
* add support for optional email address mangling (issue #290)
* extensible path-based authorization subsystem (issue #268), supporting:
- Subversion authz files (new)
- regexp-based path hiding (for compat with 1.0.x)
- file glob top-level directory hiding (for compat with 1.0.x)
* allow default file view to be "markup" (issue #305)
* add support for displaying file/directory properties (issue #39)
* pagination improvements
* add gzip output encoding support for template-driven pages
* fix cache control bugs (issue #259)
* add RSS feed URL generation for file history
* add support for remote creation of ViewVC checkins database
* add integration with Pygments for syntax highlighting
* preserve executability of Subversion files in tarballs (issue #233)
* add ability to set Subversion runtime config dir (issue #351, issue #339)
* show RSS/query links only for roots found in commits database (issue #357)
* recognize Subversion svn:mime-type property values (issue #364)
* hide CVS files when viewing tags/branches on which they don't exist
* allow hiding of errorful entries from the directory view (issue #105)
* fix directory view sorting UI
* tolerate malformed Accept-Language headers (issue #396)
* allow MIME type mapping overrides in ViewVC configuration (issue #401)
* fix exception in rev-sorted remote Subversion directory views (issue #409)
* allow setting of page sizes for log and dir views individually (issue #402)
Version 1.0.13 (released 24-Oct-2012)
* security fix: escape "extra" diff info to avoid XSS attack (issue #515)
* security fix: remove user-reachable override of cvsdb row limit
* fix obscure "unexpected NULL parent pool" Subversion bindings error
* fix svndbadmin failure on deleted paths under Subversion 1.7 (issue #499)
Version 1.0.12 (released 02-Jun-2010)
* fix exception caused by trying to HTML-escape non-string data (issue #454)
Version 1.0.11 (released 29-Mar-2010)
* security fix: escape user-provided search_re input to avoid XSS attack
Version 1.0.10 (released 10-Mar-2010)
* security fix: escape user-provided query form input to avoid XSS attack
* fix errors viewing remote Subversion paths with URI-unsafe characters
* fix regexp input validation (issue #426, #427, #440)
Version 1.0.9 (released 11-Aug-2009)
* security fix: validate the 'view' parameter to avoid XSS attack
* security fix: avoid printing illegal parameter names and values
Version 1.0.8 (released 05-May-2009)
* fix directory view sorting UI
* tolerate malformed Accept-Language headers (issue #396)
* fix directory log views in revision-less Subversion repositories
* fix exception in rev-sorted remote Subversion directory views (issue #409)
Version 1.0.7 (released 14-Oct-2008)
* fix regression in the 'as text' download view (issue #373)
Version 1.0.6 (released 16-Sep-2008)
* security fix: ignore arbitrary user-provided MIME types (issue #354)
* fix bug in regexp search filter when used with sticky tag (issue #346)
* fix bug in handling of certain 'co' output (issue #348)
* fix regexp search filter template bug
* fix annotate code syntax error
* fix mod_python import cycle (issue #369)
Version 1.0.5 (released 28-Feb-2008)
* security fix: omit commits of all-forbidden files from query results
* security fix: disallow direct URL navigation to hidden CVSROOT folder
* security fix: strip forbidden paths from revision view
* security fix: don't traverse log history thru forbidden locations
* security fix: honor forbiddenness via diff view path parameters
* new 'forbiddenre' regexp-based path authorization feature
* fix root name conflict resolution inconsistencies (issue #287)
* fix an oversight in the CVS 1.12.9 loginfo-handler support
* fix RSS feed content type to be more specific (issue #306)
* fix entity escaping problems in RSS feed data (issue #238)
* fix bug in tarball generation for remote Subversion repositories
* fix query interface file-count-limiting logic
* fix query results plus/minus count to ignore forbidden files
* fix blame error caused by 'svn' unable to create runtime config dir
Version 1.0.4 (released 10-Apr-2007)
* fix some markup bugs in query views (issue #266)
* fix loginfo-handler's support for CVS 1.12.9 (issues #151, #257)
* make viewvc-install able to run from an arbitrary location
* update viewvc-install's output for readability
* fix bug writing commits to non-MyISAM databases (issue #262)
* allow long paths in generated tarballs (issue #12)
* fix bug interpreting EZT substitute patterns
* fix broken markup view disablement
* fix broken directory view link generation in directory log view
* fix Windows-specific viewvc-install bugs
* fix broke query result links for Subversion deleted items (issue #296)
* fix some output XHTML validation buglets
* fix database query cache staleness problems (issue #180)
Version 1.0.3 (released 13-Oct-2006)
* fix bug in path shown for Subversion deleted-under-copy items (issue #265)
* security fix: declare charset for views to avoid IE UTF7 XSS attack
Version 1.0.2 (released 29-Sep-2006)
* minor documentation fixes
* fix Subversion annotate functionality on Windows (issue #18)
* fix annotate assertions on uncanonicalized #include paths (issue #208)
* make RSS URL method match the method used to generate it (issue #245)
* fix Subversion annotation to run non-interactively, preventing hangs
* fix bug in custom syntax highlighter fallback logic
* fix bug in PHP CGI hack to avoid force-cgi-redirect errors
Version 1.0.1 (released 20-Jul-2006)
* fix exception on log page when use_pagesize is enabled
* fix an XHTML validation bug in the footer template (issue #239)
* fix handling of single-component CVS revision numbers (issue #237)
* fix bug in download-as-text URL link generation (issue #241)
* fix query.cgi bug, missing 'rss_href' template data item (issue #249)
* no longer omit empty Subversion directories from tarballs (issue #250)
* use actual modification time for Subversion directories in tarballs
Version 1.0 (released 01-May-2006)
* add support for viewing Subversion repositories
* add support for running on MS Windows (2003-Feb-09)
* generate strict XHTML output (2005-Sep-08)
* add support for running on MS Windows
* generate strict XHTML output
* add support for caching by sending "Last-Modified", "Expires",
"ETag", and "Cache-Control" headers (2004-Jun-03)
"ETag", and "Cache-Control" headers
* add support for Mod_Python on Apache 2.x and ASP on IIS
* Several changes to standalone.py:
- -h commandline option to specify hostname for non local use.
- -r commandline option may be repeated to use more than repository
before actually installing ViewCVS.
- New GUI field to test paging.
* add new, better-integrated query interface (2004-Jul-17)
* add integrated RSS feeds (2005-Dec-22)
* add new, better-integrated query interface
* add integrated RSS feeds
* add new "root_as_url_component" option to embed root names as
path components in ViewCVS URLs for a more natural URL scheme
in ViewCVS configurations with multiple repositories.
(2002-Dec-12)
* add new "use_localtime" option to display local times instead of
UTC times (2002-May-06)
* add new "use_localtime" option to display local times instead of UTC times
* add new "root_parents" option to make it possible to add and
remove repositories without modifying the ViewCVS configuration
(2004-Jul-16)
* add new "template_dir" option to facilitate switching between
sets of templates (2005-Feb-08)
* add new "template_dir" option to facilitate switching between sets of
templates
* add new "sort_group_dirs" option to disable grouping of
directories in directory listings (2005-Mar-07)
* add new "port" option to connect to a MySQL database on a nonstandard
port (2005-Dec-22)
directories in directory listings
* add new "port" option to connect to a MySQL database on a nonstandard port
* make "default_root" option optional. When no root is specified,
show a page listing all available repositories (2005-Feb-04)
show a page listing all available repositories
* add "default_file_view" option to make it possible for relative
links and image paths in checked out HTML files to work without
the need for special /*checkout*/ prefixes in URLs. Deprecate
"checkout_magic" option and disable by default (2006-Apr-03)
"checkout_magic" option and disable by default
* add "limit_changes" option to limit number of changed files shown per
commit by default in query results and in the Subversion revision view
* hide CVS "Attic" directories and add simple toggle for showing
dead files in directory listings (2004-Jul-31)
dead files in directory listings
* show Unified, Context and Side-by-side diffs in HTML instead of
in bare text pages (2004-Jun-22)
in bare text pages
* make View/Download links work the same for all file types
(2004-Jan-21)
* add links to tip of selected branch on log page (2005-Oct-03)
* allow use of "Highlight" program for colorizing (2005-Dec-20)
* add links to tip of selected branch on log page
* allow use of "Highlight" program for colorizing
* enable enscript colorizing for more file types
* add sorting arrows for directory views (2004-Jul-21)
* get rid of popup windows for checkout links (2004-Jan-21)
* add sorting arrows for directory views
* get rid of popup windows for checkout links
* obfuscate email addresses in html output by encoding @ symbol
with an HTML character reference (2004-Jul-29)
* add paging capability (2001-Dec-31)
with an HTML character reference
* add paging capability
* Improvements to templates
- add new template authoring guide
- increase coverage, use templates to produce HTML for diff pages,
@@ -56,41 +405,36 @@ Version 1.0 (not yet released)
- add new template variables providing ViewCVS URLs for more
links between related pages and less URL generation inside
templates
* add new [define] EZT directive for assigning variables within
templates (2004-Apr-21)
* add new [define] EZT directive for assigning variables within templates
* add command line argument parsing to install script to allow
non-interactive installs (2005-Jan-06)
* add stricter parameter validation to lower likelihood of CSS
vulnerabilities (2002-May-24)
non-interactive installs
* add stricter parameter validation to lower likelihood of cross-site
scripting vulnerabilities
* add support for cvsweb's "mime_type=text/x-cvsweb-markup" URLs
(2002-Oct-10)
* fix incompatibility with enscript 1.6.3 (2002-Feb-05)
* fix bug in parsing FreeBSD rlog output (2003-Jul-24)
* fix incompatibility with enscript 1.6.3
* fix bug in parsing FreeBSD rlog output
* work around rlog assumption all two digit years in RCS files are
relative to the year 1900. (2005-Sep-30)
relative to the year 1900.
* change loginfo-handler to cope with spaces in filenames and
support a simpler command line invocation from CVS (2003-Feb-11)
* show diff error when comparing two binary files (2002-Jan-23)
* make regular expression search skip binary files (2002-Jan-17)
support a simpler command line invocation from CVS
* make cvsdbadmin work properly when invoked on CVS subdirectory
paths instead of top-level CVS root paths
* show diff error when comparing two binary files
* make regular expression search skip binary files
* make regular expression search skip nonversioned files in CVS
directories instead of choking on them (2002-Sep-27)
directories instead of choking on them
* fix tarball generator so it doesn't include forbidden modules
(2002-Feb-22)
* output "404 Not Found" errors instead of "403 Forbidden" errors
to not reveal whether forbidden paths exist (2005-May-17)
* fix sorting bug in directory view (2002-Apr-18)
to not reveal whether forbidden paths exist
* fix sorting bug in directory view
* reset log and directory page numbers when leaving those pages
(2005-Jan-29)
* reset sort direction in directory listing when clicking new
columns (2004-Jul-21)
* fix "Accept-Language" handling for Netscape 4.x browsers
(2002-May-23)
* fix file descriptor leak in standalone server (2004-Jul-17)
* clean up zombie processes from running enscript (2002-Jun-15)
* fix mysql "Too many connections" error in cvsdbadmin (2003-Jul-24)
* get rid of mxDateTime dependency for query database (2003-Feb-09)
* reset sort direction in directory listing when clicking new columns
* fix "Accept-Language" handling for Netscape 4.x browsers
* fix file descriptor leak in standalone server
* clean up zombie processes from running enscript
* fix mysql "Too many connections" error in cvsdbadmin
* get rid of mxDateTime dependency for query database
* store query database times in UTC instead of local time
(2003-Feb-09)
* fix daylight saving time bugs in various parts of the code
Version 0.9.4 (released 17-Aug-2005)
@@ -138,7 +482,6 @@ Version 0.9 (released 23-Dec-2001)
* create dir_alternate.ezt for the flipped rev/name links
* various UI tweaks for the directory pages
Version 0.8 (released 10-Dec-2001)
* add EZT templating mechanism for generating output pages

View File

@@ -20,6 +20,7 @@ directly.
jamesh James Henstridge <???>
maxb Max Bowsher <maxb1@ukf.net>
eh Erik Hülsmann <e.huelsmann@gmx.net>
mhagger Michael Haggerty <mhagger@alum.mit.edu>
## Local Variables:
## coding:utf-8

674
INSTALL
View File

@@ -1,11 +1,12 @@
CONTENTS
--------
TO THE IMPATIENT
SECURITY INFORMATION
INSTALLING VIEWVC
APACHE CONFIGURATION
UPGRADING VIEWVC
SQL CHECKIN DATABASE
ENSCRIPT CONFIGURATION
ENABLING SYNTAX COLORATION
CVSGRAPH CONFIGURATION
IF YOU HAVE PROBLEMS...
@@ -16,10 +17,13 @@ Congratulations on getting this far. :-)
Required Software And Configuration Needed To Run ViewVC:
In General:
* Python 2, version 2.4 or later (sorry, no 3.x support yet)
(http://www.python.org/)
For CVS Support:
* Python 1.5.2 or later
(http://www.python.org/)
* RCS, Revision Control System
(http://www.cs.purdue.edu/homes/trinkle/RCS/)
* GNU-diff to replace diff implementations without the -u option
@@ -29,76 +33,86 @@ Congratulations on getting this far. :-)
For Subversion Support:
* Python 2.0 or later
(http://www.python.org/)
* Subversion, Version Control System, 1.2.0 or later
* Subversion, Version Control System, 1.3.1 or later
(binary installation and Python bindings)
(http://subversion.tigris.org/)
(http://subversion.apache.org/)
Optional:
* a web server capable of running CGI programs
(for example, Apache at http://httpd.apache.org/)
* MySQL to create and query a commit database
* MySQL 3.22 and MySQLdb 0.9.0 or later to create a commit database
(http://www.mysql.com/)
(http://sourceforge.net/projects/mysql-python)
* Enscript, code colorizer
(http://www.codento.com/people/mtr/genscript/)
* Highlight, code colorizer, 2.2.10 or later required, 2.4.5 or
later recommended for reliable line numbering
(http://www.andre-simon.de/)
* Pygments 0.9 or later, syntax highlighting engine
(http://pygments.org)
* CvsGraph 1.5.0 or later, graphical CVS revision tree generator
(http://www.akhphd.au.dk/~bertho/cvsgraph/)
GUI Operation:
Quick sanity check:
If you just want to see what your CVS repository looks like with
ViewVC, type "./standalone.py -g -r /PATH/TO/CVS/ROOT". This
will start a tiny webserver serving at http://localhost:7467/.
PLEASE NOTE: This requires Python with thread support enabled and
the Tkinter GUI. If you don't have one of these, omit the '-g' option.
If you just want to see what your repository looks like when seen
through ViewVC, type:
$ bin/standalone.py -r /PATH/TO/REPOSITORY
This will start a tiny ViewVC server at http://localhost:49152/viewvc/,
to which you can connect with your browser.
Standard operation:
To start installing right away (on UNIX): type "./viewvc-install"
in the current directory and answer the prompts. When it
finishes, edit the file viewvc.conf in the installation directory
to tell viewvc the paths to your CVS and Subversion repositories. Next,
configure your web server to run <INSTALL>/cgi/viewvc.cgi, as
appropriate for your web server. The section `INSTALLING VIEWVC'
below is still recommended reading.
to tell ViewVC the paths to your CVS and Subversion repositories.
Next, configure your web server (in the way appropriate to that browser)
to run <VIEWVC_INSTALLATION_DIRECTORY>/bin/cgi/viewvc.cgi. The section
`INSTALLING VIEWVC' below is still recommended reading.
SECURITY INFORMATION
--------------------
ViewVC provides a feature which allows version controlled content to
be served to web browsers just like static web server content. So, if
you have a directory full of interrelated HTML files that is housed in
your version control repository, ViewVC can serve those files as HTML.
You'll see in your web browser what you'd see if the files were part
of your website, with working references to stylesheets and images and
links to other pages.
It is important to realize, however, that as useful as that feature
is, there is some risk security-wise in its use. Essentially, anyone
with commit access to the CVS or Subversion repositories served by
ViewVC has the ability to affect site content. If a discontented or
ignorant user commits malicious HTML to a version controlled file
(perhaps just by way of documenting examples of such), that malicious
HTML is effectively published and live on your ViewVC instance.
Visitors viewing those versioned controlled documents get the
malicious code, too, which might not be what the original author
intended.
For this reason, ViewVC's "checkout" view is disabled by default. If
you wish to enable it, simply add "co" to the list of views enabled in
the allowed_views configuration option.
INSTALLING VIEWVC
------------------
1) To get viewvc.cgi to work, make sure that you have Python 1.5 or
greater installed and a webserver which is capable of executing
CGI scripts (either based on the .cgi extension, or by placing the
script within a specific directory).
NOTE: Windows users can refer to windows/README for Windows-specific
installation instructions.
You need to have RCS installed. Specifically, "rlog", "rcsdiff",
and "co". This script was tested against RedHat's rcs-5.7-10.rpm
Someone running HP-UX reported problems, that rcs doesn'nt honour
the setting of $PATH to find the diff utility. Please test, if
"rcsdiff -u" works. If not you might have to recompile RCS.
1) To get viewvc.cgi to work, make sure that you have Python installed
and a webserver which is capable of executing CGI scripts (either
based on the .cgi extension, or by placing the script within a specific
directory).
Note, that the viewvc.cgi script needs to have READ-ONLY, physical
access to the CVS repository (or a copy of it). Therefore, rsh/ssh or
pserver access to the repository will not work.
For the more human readable diff formats you need a modern diff utility.
If you are using Linux, this is no problem. But on commercial unices
you might want to install GNU-diff to be able to use unified or
side-by-side diffs.
If you want to use cvsgraph, you have to obtain and install this
separately. See below. This was tested with cvsgraph-1.5.1.
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 0.9.1.
Note that to browse CVS repositories, the viewvc.cgi script needs to
have READ-ONLY, physical access to the repository (or a copy of it).
Therefore, rsh/ssh or pserver access to the repository will not work.
And you need to have the RCS utilities installed, specifically "rlog",
"rcsdiff", and "co".
2) Installation is handled by the ./viewvc-install script. Run this
script and you will be prompted for a installation root path.
@@ -120,10 +134,13 @@ INSTALLING VIEWVC
3) Edit <VIEWVC_INSTALLATION_DIRECTORY>/viewvc.conf for your specific
configuration. In particular, examine the following configuration options:
cvs_roots
cvs_roots (for CVS)
svn_roots (for Subversion)
root_parents (for CVS or Subversion)
default_root
rcs_path
mime_types_file
root_as_url_component
rcs_dir
mime_types_files
There are some other options that are usually nice to change. See
viewvc.conf for more information. ViewVC provides a working,
@@ -131,115 +148,245 @@ INSTALLING VIEWVC
then edit the files in <VIEWVC_INSTALLATION_DIRECTORY>/templates.
You need knowledge about HTML to edit the templates.
4) The CGI programs are in <VIEWVC_INSTALLATION_DIRECTORY>/www/cgi/. You can
4) The CGI programs are in <VIEWVC_INSTALLATION_DIRECTORY>/bin/cgi/. You can
symlink to this directory from somewhere in your published HTTP server
path if your webserver is configured to follow symbolic links. You can
also copy the installed <VIEWVC_INSTALLATION_DIRECTORY>/www/cgi/*.cgi
also copy the installed <VIEWVC_INSTALLATION_DIRECTORY>/bin/cgi/*.cgi
scripts after the install (unlike the other files in ViewVC, the scripts
under www/ can be moved).
under bin/ can be moved).
If you are using Apache, then see below at the section
titled APACHE CONFIGURATION.
If you are using Apache, then see below at the section titled
APACHE CONFIGURATION.
NOTE: for security reasons, it is not advisable to install ViewVC
directly into your published HTTP directory tree (due to the MySQL
passwords in viewvc.conf).
5) That's it for repository browsing. Instructions for getting the
SQL checkin database working are below.
That's it for repository browsing. Instructions for getting the SQL
checkin database working are below.
APACHE CONFIGURATION
--------------------
1) Find out where the web server configuration file is kept. On
SuSE Linux it is /etc/httpd/httpd.conf, On RedHat Linux 7.3 it
is /etc/httpd/conf/httpd.conf. On other unices you may look
at /usr/local/etc or /etc/local. Use the vendor documentation
or the find utility, if in doubt.
1) Locate your Apache configuration file(s).
Either METHOD A:
2) The ScriptAlias directive is very useful for pointing
Typical locations are /etc/httpd/httpd.conf,
/etc/httpd/conf/httpd.conf, and /etc/apache/httpd.conf. Depending
on how Apache was installed, you may also look under /usr/local/etc
or /etc/local. Use the vendor documentation or the find utility if
in doubt.
2) Depending on how your Apache configuration is setup by default, you
might need to explicitly allow high-level access to the ViewVC
install location.
<Directory <VIEWVC_INSTALLATION_DIRECTORY>>
Order allow,deny
Allow from all
</Directory>
For example, if ViewVC is installed in /usr/local/viewvc-1.0 on
your system:
<Directory /usr/local/viewvc-1.0>
Order allow,deny
Allow from all
</Directory>
3) Configure Apache to expose ViewVC to users at the URL of your choice.
ViewVC provides several different ways to do this. Choose one of
the following methods:
-----------------------------------
METHOD A: CGI mode via ScriptAlias
-----------------------------------
The ScriptAlias directive is very useful for pointing
directly to the viewvc.cgi script. Simply insert a line containing
ScriptAlias /viewvc <VIEWVC_INSTALLATION_DIRECTORY>/www/cgi/viewvc.cgi
ScriptAlias /viewvc <VIEWVC_INSTALLATION_DIRECTORY>/bin/cgi/viewvc.cgi
into your httpd.conf file. Choose the location in httpd.conf where
also the other ScriptAlias lines reside. Some examples:
ScriptAlias /viewvc /usr/local/viewvc-1.0/www/cgi/viewvc.cgi
ScriptAlias /query /usr/local/viewvc-1.0/www/cgi/query.cgi
ScriptAlias /viewvc /usr/local/viewvc-1.0/bin/cgi/viewvc.cgi
ScriptAlias /query /usr/local/viewvc-1.0/bin/cgi/query.cgi
continue with step 3).
or alternatively METHOD B:
2) Copy the CGI scripts from
<VIEWVC_INSTALLATION_DIRECTORY>/www/cgi/*.cgi
----------------------------------------
METHOD B: CGI mode in cgi-bin directory
----------------------------------------
Copy the CGI scripts from
<VIEWVC_INSTALLATION_DIRECTORY>/bin/cgi/*.cgi
to the /cgi-bin/ directory configured in your httpd.conf file.
continue with step 3).
You can override configuration file location using:
SetEnv VIEWVC_CONF_PATHNAME /etc/viewvc.conf
and then there's METHOD C:
2) Copy the CGI scripts from
<VIEWVC_INSTALLATION_DIRECTORY>/www/cgi/*.cgi
------------------------------------------
METHOD C: CGI mode in ExecCGI'd directory
------------------------------------------
Copy the CGI scripts from
<VIEWVC_INSTALLATION_DIRECTORY>/bin/cgi/*.cgi
to the directory of your choosing in the Document Root adding the following
apache directives for the directory in httpd.conf or an .htaccess file:
Apache directives for the directory in httpd.conf or an .htaccess file:
Options +ExecCGI
AddHandler cgi-script .cgi
Options +ExecCGI
AddHandler cgi-script .cgi
(Note: For this to work mod_cgi has to be loaded. And for the .htaccess file
Note: For this to work mod_cgi has to be loaded. And for the .htaccess file
to be effective, "AllowOverride All" or "AllowOverride Options FileInfo"
need to have been specified for the directory.)
needs to have been specified for the directory.
continue with step 3).
or if you've got Mod_Python installed you can use METHOD D:
2) Copy the Python scripts and .htaccess file from
<VIEWVC_INSTALLATION_DIRECTORY>/www/mod_python/
to a directory being served by apache.
------------------------------------------
METHOD D: Using mod_python (if installed)
------------------------------------------
Copy the Python scripts and .htaccess file from
<VIEWVC_INSTALLATION_DIRECTORY>/bin/mod_python/
to a directory being served by Apache.
In httpd.conf, make sure that "AllowOverride All" or at least
"AllowOverride FileInfo Options" are enabled for the directory
you copied the files to.
You can override configuration file location using:
SetEnv VIEWVC_CONF_PATHNAME /etc/viewvc.conf
Note: If you are using Mod_Python under Apache 1.3 the tarball generation
and enscript colorizing features may not work because they use
multithreading. They do work fine with Apache 2.
feature may not work because it uses multithreading. This works fine
under Apache 2.
continue with step 3).
----------------------------------------
METHOD E: Using mod_wsgi (if installed)
----------------------------------------
Copy the Python scripts file from
<VIEWVC_INSTALLATION_DIRECTORY>/bin/wsgi/
to the directory of your choosing. Modify httpd.conf with the
following directives:
3) Restart apache. On SuSE Linux this is done using the command
rcapache restart and on RedHat Linux this is done using the command
/sbin/service httpd restart
WSGIScriptAlias /viewvc <VIEWVC_INSTALLATION_DIRECTORY>/bin/wsgi/viewvc.wsgi
WSGIScriptAlias /query <VIEWVC_INSTALLATION_DIRECTORY>/bin/wsgi/query.wsgi
4) Optional: adding access control:
You'll probably also need the following directive because of the
not-quite-sanctioned way that ViewVC manipulates Python objects.
In your httpd.conf you can control access to certain modules by adding
directives like this:
WSGIApplicationGroup %{GLOBAL}
<Location "<url to viewvc.cgi>/<modname_you_wish_to_access_ctl>">
AllowOverride None
AuthUserFile /path/to/passwd/file
AuthName "Client Access"
AuthType Basic
require valid-user
</Location>
Note: WSGI support in ViewVC is at this time quite rudimentary,
bordering on downright experimental. Your mileage may vary.
This idea is courtesy to Nick Bauman from http://www.cortexity.com/
-----------------------------------------
METHOD F: Using mod_fcgid (if installed)
-----------------------------------------
If you use access control, it is recommended that you disable the
checkout_magic option so people can't "sneak in" with URLs like
This uses ViewVC's WSGI support (from above), but supports using FastCGI,
and is a somewhat hybrid approach of several of the above methods.
http://<server_name>/viewvc/*checkout*/<module_name>
http://<server_name>/viewvc/~checkout~/<module_name>
Especially if fcgi is already being used for other purposes, e.g. PHP,
also using fcgi can prevent the need for including additional modules
(e.g. mod_python or mod_wsgi) within Apache, which may help lessen Apache's
memory usage and/or help improve performance.
and get access to seeing the file contents.
This depends on mod_fcgid:
http://httpd.apache.org/mod_fcgid/
as well as the fcgi server from Python's flup package:
http://pypi.python.org/pypi/flup
http://trac.saddi.com/flup
The following are some example httpd.conf fragments you can use to
support this configuration:
ScriptAlias /viewvc /usr/local/viewvc/bin/wsgi/viewvc.fcgi
ScriptAlias /query /usr/local/viewvc/bin/wsgi/query.fcgi
4) [Optional] Provide direct access to icons, stylesheets, etc.
ViewVC's HTML templates reference various stylesheets and icons
provided by ViewVC itself. By default, ViewVC generates URLs to
those artifacts which point back into ViewVC (using a magic
syntax); ViewVC in turn handles such magic URL requests by
streaming back the contents of the requested icon or stylesheet
file. While this simplifies the configuration and initial
deployment of ViewVC, it's not the most efficient approach to
deliver what is essentially static content.
To improve performance, consider carving out a URL space in your
webserver's configuration solely for this static content and
instruct ViewVC to use that space when generating URLs for that
content. For example, you might add an Alias such as the following
to your httpd.conf:
Alias /viewvc-docroot /usr/local/viewvc/templates/default/docroot
And then, in viewvc.conf, set the 'docroot' option to the same
location:
docroot = /viewvc-docroot
WARNING: As always when using Alias directives, be careful that you
have them in the correct order. For example, if you use an
ordering such as the following, Apache will hand requests for your
static documents off to ViewVC as if they were versioned resources:
ScriptAlias /viewvc /usr/local/viewvc/bin/wsgi/viewvc.fcgi
Alias /viewvc/static /usr/local/viewvc/templates/default/docroot
The correct order would be:
Alias /viewvc/static /usr/local/viewvc/templates/default/docroot
ScriptAlias /viewvc /usr/local/viewvc/bin/wsgi/viewvc.fcgi
(That said, it's best to avoid such namespace nesting altogether if
you can.)
5) [Optional] Add access control.
In your httpd.conf you can control access to certain modules by
adding directives like this:
<Location "<url to viewvc.cgi>/<modname_you_wish_to_access_ctl>">
AllowOverride None
AuthUserFile /path/to/passwd/file
AuthName "Client Access"
AuthType Basic
require valid-user
</Location>
WARNING: If you enable the "checkout_magic" or "allow_tar" options, you
will need to add additional location directives to prevent people
from sneaking in with URLs like:
http://<server_name>/viewvc/*checkout*/<module_name>
http://<server_name>/viewvc/~checkout~/<module_name>
http://<server_name>/viewvc/<module_name>.tar.gz?view=tar
6) Restart Apache.
The commands to do this vary. "httpd -k restart" and "apache -k
restart" are two common variants. On RedHat Linux it is done using
the command "/sbin/service httpd restart" and on SuSE Linux it is
done with "rcapache restart". Other systems use "apachectl restart".
7) [Optional] Protect your ViewVC instance from server-whacking webcrawlers.
As ViewVC is a web-based application which each page containing various
links to other pages and views, you can expect your server's performance
to suffer if a webcrawler finds your ViewVC instance and begins
traversing those links. We highly recommend that you add your ViewVC
location to a site-wide robots.txt file. Visit the Wikipedia page
for Robots.txt (http://en.wikipedia.org/wiki/Robots.txt) for more
information.
UPGRADING VIEWVC
-----------------
Please read the file upgrading.html in the website subdirectory or
at <http://viewvc.org/upgrading.html>.
Please read the file upgrading-howto.html in the docs/ subdirectory.
SQL CHECKIN DATABASE
@@ -252,15 +399,13 @@ database. In fact, the databases are 100% compatible.
Various queries can be performed on the database. After installing ViewVC,
there are some additional steps required to get the database working.
1) You need MySQL >= 3.22, and the Python module MySQLdb 0.9.0 installed.
Python 1.5.2 is REQUIRED by MySQLdb, therefore to use this part of
ViewVC you must be using Python 1.5.2.
1) You need MySQL and MySQLdb (a Python DBAPI 2.0 module) installed.
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 <VIEWVC_INSTALLATION_DIRECTORY>/make-database script. It will
3) Run the <VIEWVC_INSTALLATION_DIRECTORY>/bin/make-database script. It will
prompt you for your MySQL user, password, and the name of database you
want to create. The database name defaults to "ViewVC". This script
creates the database and sets up the empty tables. If you run this on a
@@ -272,105 +417,106 @@ there are some additional steps required to get the database working.
enabled = 1 # Whether to enable query support in viewvc.cgi
host = # MySQL database server host
port = # MySQL database server port (default is 3306)
database_name = # the name of the database you created with
# make-database
user = # the read/write database user
database_name = # name of database you created with make-database
user = # 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
readonly_user = # read-only database user
readonly_passwd = # password for the read-only user
5) Two programs are provided for updating the checkin database from a
CVS repository, cvsdbadmin and loginfo-handler. They serve two
different purposes. The cvsdbadmin program walks through your CVS
repository and adds every commit in every file. This is commonly
used for initializing the database from a repository which has been
in use. The loginfo-handler script is executed by the CVS server's
CVSROOT/loginfo system upon each commit. It makes real-time
updates to the checkin database as commits are made to the
repository.
Note that it's pretty safe in this instance for your read-only user
and your read-write user to be the same.
To build a database of all the commits in the CVS repository /home/cvs,
invoke: "./cvsdbadmin rebuild /home/cvs". If you want to update
the checkin database, invoke: "./cvsdbadmin update /home/cvs". The
update mode checks to see if a commit is already in the database,
and only adds it if it is absent.
5) At this point, you need to tell your version control system(s) to
publish their commit information to the database. This is done
using utilities that ViewVC provides.
To get real-time updates, you'll want to checkout the CVSROOT module
from your CVS repository and edit CVSROOT/loginfo. Add the line:
To publish CVS commits into the database:
ALL <VIEWVC_INSTALLATION_DIRECTORY>/loginfo-handler %{sVv}
Two programs are provided for updating the checkin database from
a CVS repository, cvsdbadmin and loginfo-handler. They serve
two different purposes. The cvsdbadmin program walks through
your CVS repository and adds every commit in every file. This
is commonly used for initializing the database from a repository
which has been in use. The loginfo-handler script is executed
by the CVS server's CVSROOT/loginfo system upon each commit. It
makes real-time updates to the checkin database as commits are
made to the repository.
If you have other scripts invoked by CVSROOT/loginfo, you will want
to make sure to change any running under the "DEFAULT" keyword to
"ALL" like the loginfo handler, and probably carefully read the
execution rules for CVSROOT/loginfo from the CVS manual.
To build a database of all the commits in the CVS repository
/home/cvs, invoke: "./cvsdbadmin rebuild /home/cvs". If you
want to update the checkin database, invoke: "./cvsdbadmin
update /home/cvs". The update mode checks to see if a commit is
already in the database, and only adds it if it is absent.
If you are running the Unix port of CVS-NT, you'll need to use a
slightly different command line:
To get real-time updates, you'll want to checkout the CVSROOT
module from your CVS repository and edit CVSROOT/loginfo. For
folks running CVS 1.12 or better, add this line:
ALL <VIEWVC_INSTALLATION_DIRECTORY>/bin/loginfo-handler %p %{sVv}
If you are running CVS 1.11 or earlier, you'll want a slightly
different command line in CVSROOT/loginfo:
ALL <VIEWVC_INSTALLATION_DIRECTORY>/bin/loginfo-handler %{sVv}
ALL <VIEWVC_INSTALLATION_DIRECTORY>/loginfo-handler %{sVv} cvsnt
The extra 'cvsnt' parameter tells the handler script to parse the
commit information in a different way.
If you have other scripts invoked by CVSROOT/loginfo, you will
want to make sure to change any running under the "DEFAULT"
keyword to "ALL" like the loginfo handler, and probably
carefully read the execution rules for CVSROOT/loginfo from the
CVS manual.
If you are running the Unix port of CVS-NT, the handler script
need to know about it. CVS-NT delivers commit information to
loginfo scripts differently than the way mainstream CVS does.
Your command line should look like this:
ALL <VIEWVC_INSTALLATION_DIRECTORY>/bin/loginfo-handler %{sVv} cvsnt
For Subversion repositories, there is a single script called
svndbadmin that performs both of the above tasks.
To publish Subversion commits into the database:
To build a database of all the commits in the Subversion
repository /home/svn, invoke: "./svndbadmin rebuild /home/svn".
If you want to update the checkin database, invoke:
"./svndbadmin update /home/svn".
To get real time updates, you will need to add a post-commit
hook (for the repository example above, the script should go in
/home/svn/hooks/post-commit). The script should look something
like this:
#!/bin/sh
REPOS="$1"
REV="$2"
<VIEWVC_INSTALLATION_DIRECTORY>/bin/svndbadmin update \
"$REPOS" "$REV"
If you allow revision property changes in your repository,
create a post-revprop-change hook script which uses the same
'svndbadmin update' command as the post-commit script, except
with the addition of the --force option:
#!/bin/sh
REPOS="$1"
REV="$2"
<VIEWVC_INSTALLATION_DIRECTORY>/bin/svndbadmin update --force \
"$REPOS" "$REV"
This will make sure that the checkin database stays consistent
when you change the svn:log, svn:author or svn:date revision
properties.
To build a database of all the commits in the Subversion repository
/home/svn, invoke: "./svndbadmin rebuild /home/svn". If you want
to update the checkin database, invoke: "./svndbadmin update
/home/svn".
To get real time updates, you will need to add a post-commit hook
(for the repository example above, the script should go in
/home/svn/hooks/post-commit). The script should look something
like this:
#!/bin/sh
REPOS="$1"
REV="$2"
<VIEWVC_INSTALLATION_DIRECTORY>/svndbadmin rebuild "$REPOS" "$REV"
If you allow revision property changes in your repository, create a
post-revprop-change hook script containing the same commands as the
post-commit one. This will make sure that the checkin database
stays consistent when you change the svn:log, svn:author or
svn:date revision properties.
6) You may want to modify the HTML template file:
<VIEWVC_INSTALLATION_DIRECTORY>/templates/query.ezt
This is used by the query.cgi script to generate part of its HTML output.
At some point the currently hardcoded table output will also vanish.
7) You should be ready to go. Load up the query.cgi script and give
it a try.
You should be ready to go. Click one of the "Query revision history"
links in ViewVC directory listings and give it a try.
ENSCRIPT CONFIGURATION
----------------------
ENABLING SYNTAX COLORATION
--------------------------
Enscript is program that can colorize sourcecode of a lot of languages.
Linux distributions like for example SuSE Linux from at least 7.0
up to the recently released 7.3 already contain a precompiled and
configured enscript 1.6.2 package.
1) Download genscript from http://www.codento.com/people/mtr/genscript/
2) Configure and compile per instructions with enscript.
(I 've not done this, since I'm using the precompiled package
delivered with SuSE Linux)
3) Set the 'use_enscript' option in viewvc.conf to 1.
4) That's it!
5) If you want to colorize exotic languages, you might have to
patch 'lib/viewvc.py' and add a new highlighting file to enscript.
For example, if you are interested in a patch for Modula-2 support,
send mail to pefu@sourceforge.net.
ViewVC uses Pygments (http://pygments.org) for syntax coloration. You
need only install a suitable version of that module, and if ViewVC
finds it in your Python module path, it will use it (unless you
specifically disable the feature by setting use_pygments = 0 in your
viewvc.conf file).
CVSGRAPH CONFIGURATION
@@ -380,70 +526,71 @@ CvsGraph is a program that can display a clickable, graphical tree
of files in a CVS repository.
WARNING: Under certain circumstances (many revisions of a file
or many branches or both) cvsgraph can generate very huge images.
or many branches or both) CvsGraph can generate very huge images.
Especially on thin clients these images may crash the Web-Browser.
Currently there is no known way to avoid this behavior of cvsgraph.
Currently there is no known way to avoid this behavior of CvsGraph.
So you have been warned!
Nevertheless cvsgraph can be quite helpful on repositories with
Nevertheless, CvsGraph can be quite helpful on repositories with
a reasonable number of revisions and branches.
1) Install viewvc according to instructions in 'INSTALLING
VIEWVC' section above. The installation directory is where
the 'viewvc-install' script copied and configured the viewvc
programs.
1) Install CvsGraph using your system's package manager or downloading
from the project home page.
2) Download CvsGraph from http://www.akhphd.au.dk/~bertho/cvsgraph/
2) Set the 'use_cvsgraph' options in viewvc.conf to 1.
3) Configure and compile per instructions with CvsGraph. I had
problems with 'configure' finding the gd library. Had to create
a link from libgd.so to libgd.do.4.0.0. On Solaris you might
want to edit the link command line and add the option -R if
you have you libraries at non-standard location.
3) You may also need to set the 'cvsgraph_path' option if the
CvsGraph executable is not located on the system PATH.
4) Place the 'cvsgraph' executable into a directory readable by the
userid running the web server. (default is '/usr/local/bin' if
you simply type 'make install' in the cvsgraph directory).
5) Check the setting of the 'cvsgraph_path' option in viewvc.conf:
/usr/local/bin/ is most often NOT contained in $PATH of the
webserver process (e.g. Apache), so you will have to edit this.
Set the 'use_cvsgraph' option in viewvc.conf to 1.
6) That's it!
7) There is a file <VIEWVC_INSTALLATION_DIRECTORY>/cvsgraph.conf that
4) There is a file <VIEWVC_INSTALLATION_DIRECTORY>/cvsgraph.conf that
you may want to edit if desired to set color and font characteristics.
See the cvsgraph.conf documentation. No edits are required in
cvsgraph.conf for operation with viewvc.
cvsgraph.conf for operation with ViewVC.
SUBVERSION INTEGRATION
----------------------
ViewVC now supports browsing of Subversion repositories. To use
ViewVC with Subversion, make sure you have both Subversion itself and
the Subversion Python bindings installed. See Subversion's
installation notes for more details on how to build and install these
items.
Unlike the CVS integration, which simply wraps the RCS and CVS utility
programs, the Subversion integration requires additional Python
libraries. To use ViewVC with Subversion, make sure you have both
Subversion itself and the Subversion Python bindings installed. These
can be obtained through typical package distribution mechanisms, or
may be build from source. (See the files 'INSTALL' and
'subversion/bindings/swig/INSTALL' in the Subversion source tree for
more details on how to build and install Subversion and its Python
bindings.)
Generally speaking, you'll know when your installation of Subversion's
bindings has been successful if you can import the 'svn.repos' module
from within your Python interpreter:
bindings has been successful if you can import the 'svn.core' module
from within your Python interpreter. Here's an example of doing so
which doubles as a quick way to check what version of the Subversion
Python binding you have:
% python
Python 2.2.2 (#1, Oct 29 2002, 02:47:30)
[GCC 2.96 20000731 (Red Hat Linux 7.2 2.96-108.7.2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import svn.repos
>>>
>>> from svn.core import *
>>> "%s.%s.%s" % (SVN_VER_MAJOR, SVN_VER_MINOR, SVN_VER_PATCH)
'1.3.1'
>>>
Note that by default, Subversion installs its bindings in a location
that is not in Python's default module search path (for example, on
Linux systems the default is usually /usr/local/lib/svn-python). You
need to remedy this, either by adding this path to Python's module
search path, or by relocation the bindings to some place in that
search path.
search path, or by relocating the bindings to some place in that
search path.
For example, you might want to create .pth file in your Python
installation directory's site-packages area which tells Python where
to find additional modules (in this case, you Subversion Python
bindings). You would do this as follows (and as root):
$ echo "/path/to/svn/bindings" > /path/to/python/site-packages/svn.pth
(Though, obviously, with the correct paths specified.)
Configuration of the Subversion repositories happens in much the same
way as with CVS repositories, only with the 'svn_roots' configuration
@@ -453,39 +600,42 @@ variable instead of the 'cvs_roots' one.
IF YOU HAVE PROBLEMS ...
------------------------
If you've trouble to make viewvc.cgi work:
If nothing seems to work:
=== If nothing seems to work:
* Check if you can execute CGI-scripts (Apache needs to have an
ScriptAlias /cgi-bin or cgi-script Handler defined). Try to
execute a simple CGI-script that often comes with the distribution
of the webserver; locate the logfiles and try to find hints which
explain the malfunction
o check if you can execute CGI-scripts (Apache needs to have an
ScriptAlias /cgi-bin or cgi-script Handler defined). Try to
execute a simple CGI-script that often comes with the distribution
of the webserver; locate the logfiles and try to find hints
which explain the malfunction
o view the entries in the webserver's error.log
* View the entries in the webserver's error.log
=== If viewvc seems to work but doesn't show the expected result
(Typical error: you can't see any files)
If ViewVC seems to work but doesn't show the expected result (Typical
error: you can't see any files)
o check whether the CGI-script has read-permissions to your
CVS-Repository. The CGI-script often runs as the user 'nobody'
or 'httpd' ..
* Check whether the CGI-script has read-permissions to your
CVS-Repository. The CGI-script generally runs as the same user
that the web server does, often user 'nobody' or 'httpd'.
o does viewvc find your RCS utilities? (edit rcs_path)
* Does ViewVC find your RCS utilities? (edit rcs_dir)
=== If something else happens or you can't get it to work:
If something else happens or you can't get it to work:
o check the ViewVC home page:
* Check the ViewVC home page:
http://viewvc.org/
http://viewvc.org/
o review the ViewVC mailing list archive to see if somebody else had
the same problem, and it was solved:
* Review the ViewVC mailing list archive to see if somebody else had
the same problem, and it was solved:
http://viewvc.tigris.org/servlets/SummarizeList?listName=users
http://viewvc.tigris.org/servlets/SummarizeList?listName=users
o send mail to the ViewVC mailing list: users@viewvc.tigris.org
* Check the ViewVC issue database to see if the problem you are
seeing is the result of a known bug:
NOTE: make sure you provide an accurate description of the problem
and any relevant tracebacks or error logs.
http://viewvc.tigris.org/issues/query.cgi
* Send mail to the ViewVC mailing list, users@viewvc.tigris.org.
NOTE: make sure you provide an accurate description of the problem
-- including the version of ViewVC you are using -- and any
relevant tracebacks or error logs.

View File

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

3
README
View File

@@ -1,6 +1,9 @@
ViewVC -- Viewing the content of CVS/SVN repositories with a Webbrowser.
This is the 4Intra.net patched version with some extra features.
Please read the file INSTALL for more information.
And see windows/README for more information on running ViewVC on
Microsoft Windows.

View File

@@ -3,7 +3,7 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -24,15 +24,15 @@
#
#########################################################################
#
# INSTALL-TIME CONFIGURATION
#
# These values will be set during the installation process. During
# development, they will remain None.
# development, there will be no 'viewvcinstallpath.py'
#
LIBRARY_DIR = None
CONF_PATHNAME = None
import viewvcinstallpath
LIBRARY_DIR = viewvcinstallpath.LIBRARY_DIR
CONF_PATHNAME = viewvcinstallpath.CONF_PATHNAME
#########################################################################
#
@@ -54,7 +54,10 @@ import query
server = sapi.AspServer(Server, Request, Response, Application)
try:
cfg = viewvc.load_config(CONF_PATHNAME, server)
query.main(server, cfg, "viewvc.asp")
viewvc_base_url = cfg.query.viewvc_base_url
if viewvc_base_url is None:
viewvc_base_url = "viewvc.asp"
query.main(server, cfg, viewvc_base_url)
finally:
s.close()

View File

@@ -3,7 +3,7 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -24,15 +24,15 @@
#
#########################################################################
#
# INSTALL-TIME CONFIGURATION
#
# These values will be set during the installation process. During
# development, they will remain None.
# development, there will be no 'viewvcinstallpath.py'
#
LIBRARY_DIR = None
CONF_PATHNAME = None
import viewvcinstallpath
LIBRARY_DIR = viewvcinstallpath.LIBRARY_DIR
CONF_PATHNAME = viewvcinstallpath.CONF_PATHNAME
#########################################################################
#

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -22,19 +22,19 @@
#
#########################################################################
#
# INSTALL-TIME CONFIGURATION
#
# These values will be set during the installation process. During
# development, they will remain None.
# development, there will be no 'viewvcinstallpath.py'
#
LIBRARY_DIR = None
CONF_PATHNAME = None
import viewvcinstallpath
LIBRARY_DIR = viewvcinstallpath.LIBRARY_DIR
CONF_PATHNAME = viewvcinstallpath.CONF_PATHNAME
#########################################################################
#
# Adjust sys.path to include our library directory
# Adjust sys.path to include our library directory.
#
import sys
@@ -47,6 +47,20 @@ else:
"../../../lib")))
#########################################################################
#
# If admins want nicer processes, here's the place to get them.
#
#try:
# os.nice(20) # bump the nice level of this process
#except:
# pass
#########################################################################
#
# Go do the work.
#
import sapi
import viewvc
@@ -54,4 +68,7 @@ import query
server = sapi.CgiServer()
cfg = viewvc.load_config(CONF_PATHNAME, server)
query.main(server, cfg, "viewvc.cgi")
viewvc_base_url = cfg.query.viewvc_base_url
if viewvc_base_url is None:
viewvc_base_url = "viewvc.cgi"
query.main(server, cfg, viewvc_base_url)

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -22,19 +22,19 @@
#
#########################################################################
#
# INSTALL-TIME CONFIGURATION
#
# These values will be set during the installation process. During
# development, they will remain None.
# development, there will be no 'viewvcinstallpath.py'
#
LIBRARY_DIR = None
CONF_PATHNAME = None
import viewvcinstallpath
LIBRARY_DIR = viewvcinstallpath.LIBRARY_DIR
CONF_PATHNAME = viewvcinstallpath.CONF_PATHNAME
#########################################################################
#
# Adjust sys.path to include our library directory
# Adjust sys.path to include our library directory.
#
import sys
@@ -47,12 +47,21 @@ else:
"../../../lib")))
#########################################################################
#
# If admins want nicer processes, here's the place to get them.
#
#try:
# os.nice(20) # bump the nice level of this process
#except:
# pass
### add code for checking the load average
#########################################################################
#
# Go do the work.
#
# go do the work
import sapi
import viewvc

216
bin/custis-install Executable file
View File

@@ -0,0 +1,216 @@
#!/bin/sh
# ViewVC installation script for CustIS
if [ -f custis-install-config ]; then
. custis-install-config
else
cat >custis-install-config <<EOF
CVS_ASYNC=
SVN_ASYNC=
CVS_USER=www-data
CVS_GROUP=cvs.users
CVSROOTS=
SVNROOT=
SVN_FORBIDDENRE=
DB_HOST=
DB_PORT=
DB_SOCKET=/var/run/mysqld/mysqld.sock
DB=
DB_USER=
DB_PASSWD=
VIEWVC_DIR=
VIEWVC_URI=/
VIEWVC_URI_SLASH=/
VIEWVC_STATIC_URI=/static
http_proxy=
no_proxy=
EOF
echo Empty 'custis-install-config' initialized, please edit it before installation.
exit
fi
if [ ! "$DB" -o ! "$VIEWVC_DIR" ]; then
echo Please set up 'custis-install-config' before installation.
exit
fi
################################################################################
export http_proxy
export no_proxy
DEPS="python libapache2-mod-python rcs diff cvsnt subversion subversion-tools python-setuptools python-subversion python-mysqldb cvsgraph"
echo "*** Installing dependency packages: $DEPS"
apt-get install $DEPS
echo "*** Installing Pygments for Python"
wget http://pypi.python.org/packages/source/P/Pygments/Pygments-0.11.1.tar.gz
tar -zxf Pygments-0.11.1.tar.gz
cd Pygments-0.11.1
python setup.py install
cd ..
echo "*** Installing ViewVC into $VIEWVC_DIR"
if [ ! -e $VIEWVC_DIR/viewvc.conf ]; then
../viewvc-install <<EOF
$VIEWVC_DIR
EOF
fi
echo "*** Writing ViewVC configuration into $VIEWVC_DIR/viewvc.conf"
for CVSROOT in $CVSROOTS; do
if [ "$vccvsroots" ]; then
vccvsroots="$vccvsroots, "
fi
vcrootname=`basename $CVSROOT`
vccvsroots="$vccvsroots$vcrootname: $CVSROOT"
done;
cat >"$VIEWVC_DIR/viewvc.conf" <<EOF
[general]
cvs_roots = $vccvsroots
root_parents = $SVNROOT : svn
cvsnt_exe_path = /usr/bin/cvsnt
mime_types_file = /etc/mime.types
address = Admin address: stas [gav-gav] custis [ru]
kv_files =
languages = en-us, ru-ru
[utilities]
rcs_dir = /usr/bin
cvsnt = /usr/bin/cvsnt
svn = /usr/bin/svn
diff = /usr/bin/diff
cvsgraph = /usr/bin/cvsgraph
[options]
allowed_views = markup, annotate, roots
authorizer = forbiddenre
checkout_magic = 0
cross_copies = 1
cvsgraph_conf = $VIEWVC_DIR/cvsgraph.conf
default_file_view = log
diff_format = h
docroot = $VIEWVC_STATIC_URI
enable_syntax_coloration = 1
generate_etags = 1
hide_attic = 1
hide_cvsroot = 1
hide_errorful_entries = 0
hr_breakable = 1
hr_funout = 0
hr_ignore_keyword_subst = 1
hr_ignore_white = 1
hr_intraline = 0
http_expiration_time = 600
limit_changes = 100
log_sort = date
mangle_email_addresses = 1
root_as_url_component = 1
short_log_len = 80
show_log_in_markup = 1
show_logs = 1
show_subdir_lastmod = 0
sort_by = file
sort_group_dirs = 1
svn_config_dir =
template_dir = templates
use_cvsgraph = 1
use_localtime = 1
use_pagesize = 0
use_rcsparse = 0
use_re_search = 0
[templates]
[cvsdb]
enabled = 1
host = $DB_HOST
socket = $DB_SOCKET
database_name = $DB
user = $DB_USER
passwd = $DB_PASSWD
readonly_user = $DB_USER
readonly_passwd = $DB_PASSWD
[vhosts]
[authz-forbidden]
forbidden =
[authz-forbiddenre]
forbiddenre = $SVN_FORBIDDENRE
[authz-svnauthz]
authzfile =
EOF
echo "*** Initializing database: $DB using $DB_USER@$DB_HOST"
$VIEWVC_DIR/bin/make-database <<EOF
$DB_HOST
$DB_USER
$DB_PASSWD
$DB
EOF
echo "*** Configuring Apache"
cat >/etc/apache2/sites-available/viewvc <<EOF
<VirtualHost *:80>
ServerName viewvc.office.custis.ru
ServerAlias viewvc
ServerAdmin sysadmins@custis.ru
ServerSignature Off
ErrorLog /var/log/apache2/viewvc-error.log
TransferLog /var/log/apache2/viewvc-access.log
LogLevel warn
# ViewVC at $VIEWVC_URI installed at $VIEWVC_DIR
DocumentRoot $VIEWVC_DIR/bin/mod_python
Alias $VIEWVC_STATIC_URI $VIEWVC_DIR/templates/docroot
Alias $VIEWVC_URI $VIEWVC_DIR/bin/mod_python/
<Location ~ ^${VIEWVC_URI_SLASH}*(\?.*)?$>
Options -Indexes
RewriteEngine On
RewriteRule .* ${VIEWVC_URI_SLASH}viewvc.py%{REQUEST_URI} [R,L]
</Location>
<Directory $VIEWVC_DIR/bin/mod_python>
Options +ExecCGI
AddHandler python-program .py
PythonHandler handler
PythonDebug Off
</Directory>
</VirtualHost>
EOF
a2enmod python
a2enmod mod_python
a2enmod rewrite
a2ensite viewvc
echo "*** Restarting Apache"
apache2ctl stop
sleep 1
apache2ctl start
echo "*** Building commit database for CVS"
for CVSROOT in $CVSROOTS; do
$VIEWVC_DIR/bin/cvsdbadmin rebuild $CVSROOT
done;
echo "*** Building commit database for Subversion repositories"
for i in `ls $SVNROOT`; do
if [ -d "$SVNROOT/$i" ]; then
$VIEWVC_DIR/bin/svndbadmin -v rebuild "$SVNROOT/$i"
fi
done;
# setup hooks for CVS
./setup-cvs-hooks "$CVSROOTS" "$VIEWVC_DIR" "$CVS_USER" "$CVS_GROUP" "$CVS_ASYNC"
# setup hooks for Subversion
./setup-svn-hooks "$SVNROOT" "$VIEWVC_DIR" "$SVN_ASYNC"

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
#!/usr/bin/python
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -18,15 +18,15 @@
#
#########################################################################
#
# INSTALL-TIME CONFIGURATION
#
# These values will be set during the installation process. During
# development, they will remain None.
# development, there will be no 'viewvcinstallpath.py'
#
LIBRARY_DIR = None
CONF_PATHNAME = None
import viewvcinstallpath
LIBRARY_DIR = viewvcinstallpath.LIBRARY_DIR
CONF_PATHNAME = viewvcinstallpath.CONF_PATHNAME
# Adjust sys.path to include our library directory
import sys
@@ -40,37 +40,52 @@ else:
#########################################################################
import os
import string
import cvsdb
import viewvc
import vclib.bincvs
import vclib.ccvs
from stat import *
def UpdateFile(db, repository, path, update):
def UpdateFile(db, repository, path, update, latest_checkin, quiet_level, encoding = None):
try:
if update:
mtime = os.stat(repository.rcsfile(path, 1))[ST_MTIME]
if mtime < latest_checkin:
return
commit_list = cvsdb.GetUnrecordedCommitList(repository, path, db)
else:
commit_list = cvsdb.GetCommitListFromRCSFile(repository, path)
except cvsdb.error, e:
print '[ERROR] %s' % (e)
return
except vclib.ItemNotFound, e:
return
file = string.join(path, "/")
file = '/'.join(path)
printing = 0
if update:
print '[%s [%d new commits]]' % (file, len(commit_list)),
if quiet_level < 1 or (quiet_level < 2 and len(commit_list)):
printing = 1
print '[%s [%d new commits]]' % (file, len(commit_list)),
else:
print '[%s [%d commits]]' % (file, len(commit_list)),
if quiet_level < 2:
printing = 1
print '[%s [%d commits]]' % (file, len(commit_list)),
## add the commits into the database
for commit in commit_list:
if encoding:
commit.SetFile(commit.GetFile().decode(encoding).encode('utf-8'))
db.AddCommit(commit)
sys.stdout.write('.')
if printing:
sys.stdout.write('.')
sys.stdout.flush()
print
if printing:
print
def RecurseUpdate(db, repository, directory, update):
def RecurseUpdate(db, repository, directory, update, latest_checkin,
quiet_level, encoding = None):
for entry in repository.listdir(directory, None, {}):
path = directory + [entry.name]
@@ -78,13 +93,16 @@ def RecurseUpdate(db, repository, directory, update):
continue
if entry.kind is vclib.DIR:
RecurseUpdate(db, repository, path, update)
RecurseUpdate(db, repository, path, update, latest_checkin,
quiet_level, encoding)
continue
if entry.kind is vclib.FILE:
UpdateFile(db, repository, path, update)
UpdateFile(db, repository, path, update, latest_checkin,
quiet_level, encoding)
def RootPath(path):
def RootPath(path, quiet_level):
"""Break os path into cvs root path and other parts"""
root = os.path.abspath(path)
path_parts = []
@@ -93,14 +111,16 @@ def RootPath(path):
while 1:
if os.path.exists(os.path.join(p, 'CVSROOT')):
root = p
print "Using repository root `%s'" % root
if quiet_level < 2:
print "Using repository root `%s'" % root
break
p, pdir = os.path.split(p)
if not pdir:
del path_parts[:]
print "Using repository root `%s'" % root
print "Warning: CVSROOT directory not found."
if quiet_level < 1:
print "Using repository root `%s'" % root
print "Warning: CVSROOT directory not found."
break
path_parts.append(pdir)
@@ -110,48 +130,82 @@ def RootPath(path):
return root, path_parts
def usage():
print 'Usage: %s <command> [arguments]' % (sys.argv[0])
print 'Performs administrative functions for the CVSdb database'
print 'Commands:'
print ' rebuild <repository> rebuilds the CVSdb database'
print ' for all files in the repository'
print ' update <repository> updates the CVSdb database for'
print ' all unrecorded commits'
print
cmd = os.path.basename(sys.argv[0])
sys.stderr.write(
"""Administer the ViewVC checkins database data for the CVS repository
located at REPOS-PATH.
Usage: 1. %s [[-q] -q] rebuild REPOS-PATH
2. %s [[-q] -q] update REPOS-PATH
3. %s [[-q] -q] purge REPOS-PATH
1. Rebuild the commit database information for the repository located
at REPOS-PATH, after first purging information specific to that
repository (if any).
2. Update the commit database information for all unrecorded commits
in the repository located at REPOS-PATH.
3. Purge information specific to the repository located at REPOS-PATH
from the database.
Use the -q flag to cause this script to be less verbose; use it twice to
invoke a peaceful state of noiselessness.
""" % (cmd, cmd, cmd))
sys.exit(1)
## main
if __name__ == '__main__':
## check that a command was given
if len(sys.argv) <= 2:
args = sys.argv
# check the quietness level (0 = verbose, 1 = new commits, 2 = silent)
quiet_level = 0
while 1:
try:
index = args.index('-q')
quiet_level = quiet_level + 1
del args[index]
except ValueError:
break
# validate the command
if len(args) <= 2:
usage()
command = args[1].lower()
if command not in ('rebuild', 'update', 'purge'):
sys.stderr.write('ERROR: unknown command %s\n' % command)
usage()
## set the handler function for the command
command = sys.argv[1]
if string.lower(command) == 'rebuild':
update = 0
elif string.lower(command) == 'update':
update = 1
else:
print 'ERROR: unknown command %s' % (command)
usage()
# get repository path
root, path_parts = RootPath(sys.argv[2])
## run command
# get repository and path, and do the work
root, path_parts = RootPath(args[2], quiet_level)
rootpath = vclib.ccvs.canonicalize_rootpath(root)
try:
## connect to the database we are updating
cfg = viewvc.load_config(CONF_PATHNAME)
db = cvsdb.ConnectDatabase(cfg)
cfg = viewvc.load_config(CONF_PATHNAME)
db = cvsdb.ConnectDatabase(cfg)
repository = vclib.bincvs.BinCVSRepository(None, root, cfg.general)
RecurseUpdate(db, repository, path_parts, update)
if command in ('rebuild', 'purge'):
if quiet_level < 2:
print "Purging existing data for repository root `%s'" % root
try:
db.PurgeRepository(root, len(path_parts) and '/'.join(path_parts) or '')
except cvsdb.UnknownRepositoryError, e:
if command == 'purge':
sys.stderr.write("ERROR: " + str(e) + "\n")
sys.exit(1)
if command in ('rebuild', 'update'):
repository = vclib.ccvs.CVSRepository(None, rootpath, None,
cfg.utilities, 0, cfg.guesser())
latest_checkin = db.GetLatestCheckinTime(repository)
if latest_checkin is None:
command = 'rebuild'
RecurseUpdate(db, repository, path_parts,
command == 'update', latest_checkin, quiet_level,
cfg.options.cvs_ondisk_charset)
except KeyboardInterrupt:
print
print '** break **'
sys.exit(0)

57
bin/cvsnt-import-cvsacl Executable file
View File

@@ -0,0 +1,57 @@
#!/usr/bin/perl
use strict;
my ($type, $path, $branch, $user, $perm);
my $R = ''; # -R for recursive
my $lvl = {
r => 1,
t => 2,
w => 3,
c => 4,
a => 4,
p => 5,
};
while(<>)
{
chomp;
next if /^\s*#/so;
($type, $path, $branch, $user, $perm) = split /:/, $_;
($user, $perm) = split /!/, $user;
next unless $perm;
$perm = [ sort { $lvl->{$b} cmp $lvl->{$a} } split //, $perm ];
$perm = $perm->[0];
if ($perm eq 't')
{
$perm = 'read,tag,nowrite,nocreate,nocontrol';
}
elsif ($perm eq 'r')
{
$perm = 'read,notag,nowrite,nocreate,nocontrol';
}
elsif ($perm eq 'w')
{
$perm = 'read,tag,write,nocreate,nocontrol';
}
elsif ($perm eq 'c' || $perm eq 'a')
{
$perm = 'read,tag,write,create,nocontrol';
}
elsif ($perm eq 'p')
{
$perm = 'read,tag,write,create,control';
}
print "cvs rchacl$R -a $perm";
print " -u '$user'" if $user ne 'ALL';
print " -r '$branch'" if $branch ne 'ALL';
if ($path ne 'ALL')
{
print " '$path'";
}
else
{
print ' `ls $CVSROOT | grep -v '."'#cvs'`";
}
print "\n";
}

21
bin/cvsnt-rcsfile-inetd.pl Executable file
View File

@@ -0,0 +1,21 @@
#!/usr/bin/perl
# Very simple inetd/xinetd "cvsnt rcsfile" service
# Useful for ViewVC as there is an unpleasant non-stable bug, probably somewhere
# inside mod_python or Apache, which SOMETIMES causes cvsnt subprocesses forked
# from mod_python to die. This gives empty diff outputs or different errors like
# "Error: Rlog output ended early. Expected RCS file ..."
# This script removes forking from mod_python code and solves the issue.
# Additional profit of this script is that you can probably browse REMOTE cvs
# repositories, if you expose this service to ViewVC, although it is not tested.
# USAGE: (local) create an inetd service with this script as server listening
# on some port of 127.0.0.1 and put "rcsfile_socket = 127.0.0.1:port"
# into "utilities" section of viewvc.conf
$args = <STDIN>;
$args =~ s/\s+$//so;
@args = $args =~ /\'([^\']+)\'/giso;
# We don't execute shell, so this is mostly safe, not a backdoor :)
exec('/usr/bin/cvsnt', 'rcsfile', @args);

View File

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

View File

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

View File

@@ -1,3 +1,3 @@
AddHandler python-program .py
PythonHandler handler
PythonDebug On
PythonDebug Off

8
bin/mod_python/handler.py Normal file → Executable file
View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -20,10 +20,8 @@ import os.path
def handler(req):
path, module_name = os.path.split(req.filename)
module_name, module_ext = os.path.splitext(module_name)
try:
module = apache.import_module(module_name, path=[path])
except ImportError:
raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND
# Let it be 500 Internal Server Error in case of import error
module = apache.import_module(module_name, path=[path])
req.add_common_vars()
module.index(req)

36
bin/mod_python/query.py Normal file → Executable file
View File

@@ -1,6 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -21,15 +22,15 @@
#
#########################################################################
#
# INSTALL-TIME CONFIGURATION
#
# These values will be set during the installation process. During
# development, they will remain None.
# development, there will be no 'viewvcinstallpath.py'
#
LIBRARY_DIR = None
CONF_PATHNAME = None
import viewvcinstallpath
LIBRARY_DIR = viewvcinstallpath.LIBRARY_DIR
CONF_PATHNAME = viewvcinstallpath.CONF_PATHNAME
#########################################################################
#
@@ -42,16 +43,33 @@ if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
import sapi
import viewvc
import query
reload(query) # need reload because initial import loads this stub file
import imp
# Import real ViewVC module
fp, pathname, description = imp.find_module('viewvc', [LIBRARY_DIR])
try:
viewvc = imp.load_module('viewvc', fp, pathname, description)
finally:
if fp:
fp.close()
# Import real ViewVC Query modules
fp, pathname, description = imp.find_module('query', [LIBRARY_DIR])
try:
query = imp.load_module('query', fp, pathname, description)
finally:
if fp:
fp.close()
cfg = viewvc.load_config(CONF_PATHNAME)
def index(req):
server = sapi.ModPythonServer(req)
try:
query.main(server, cfg, "viewvc.py")
viewvc_base_url = cfg.query.viewvc_base_url
if viewvc_base_url is None:
viewvc_base_url = "viewvc.py"
query.main(server, cfg, viewvc_base_url)
finally:
server.close()

28
bin/mod_python/viewvc.py Normal file → Executable file
View File

@@ -1,6 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -21,15 +22,15 @@
#
#########################################################################
#
# INSTALL-TIME CONFIGURATION
#
# These values will be set during the installation process. During
# development, they will remain None.
# development, there will be no 'viewvcinstallpath.py'
#
LIBRARY_DIR = None
CONF_PATHNAME = None
import viewvcinstallpath
LIBRARY_DIR = viewvcinstallpath.LIBRARY_DIR
CONF_PATHNAME = viewvcinstallpath.CONF_PATHNAME
#########################################################################
#
@@ -42,9 +43,22 @@ if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
import sapi
import viewvc
reload(viewvc) # need reload because initial import loads this stub file
import imp
import signal
# Totally ignore SIGPIPE - needed for overcoming popen() errors
def sigpipe(signum, frame):
pass
signal.signal(signal.SIGPIPE, sigpipe)
# Import real ViewVC module
fp, pathname, description = imp.find_module('viewvc', [LIBRARY_DIR])
try:
viewvc = imp.load_module('viewvc', fp, pathname, description)
finally:
if fp:
fp.close()
def index(req):
server = sapi.ModPythonServer(req)

57
bin/setup-cvs-hooks Executable file
View File

@@ -0,0 +1,57 @@
#!/bin/sh
CVSROOTS=$1
VIEWVC_DIR=$2
CVS_USER=$3
CVS_GROUP=$4
CVS_ASYNC=$5
if [ ! "$CVSROOTS" -o ! "$VIEWVC_DIR" -o ! "$CVS_USER" -o ! "$CVS_GROUP" ]; then
echo "USAGE: $0 <CVS_ROOTS> <VIEWVC_DIR> <CVS_USER> <CVS_GROUP> [CVS_ASYNC]"
exit
fi
echo "*** Setting up commit hooks for CVS repositories (job=$CVS_ASYNC)"
chgrp $CVS_GROUP $VIEWVC_DIR
chmod 775 $VIEWVC_DIR
chmod 1777 .
for CVSROOT in $CVSROOTS; do
vcrootname=`basename $CVSROOT`
if [ "$CVS_ASYNC" ]; then
VHOOK="touch $VIEWVC_DIR/.cvs-updated-$vcrootname"
else
VHOOK="$VIEWVC_DIR/bin/cvsdbadmin update $CVSROOT >/dev/null"
fi;
su $CVS_USER -s /bin/sh <<EOSH
CVSROOT=$CVSROOT cvs co CVSROOT
if [ $? -eq 0 ]; then
cd CVSROOT
mv loginfo loginfo.bak
grep -v '/.cvs-updated' <loginfo.bak | grep -v '/bin/cvsdbadmin update' >loginfo
cat >>loginfo <<EOF
ALL $VHOOK
EOF
cvs ci -m 'CVS commit hook for ViewVC' loginfo
cd ..
rm -Rf CVSROOT
fi
EOSH
if [ "$CVS_ASYNC" ]; then
cat >$VIEWVC_DIR/cvshook-$vcrootname <<EOF
#!/bin/sh
if [ -e "$VIEWVC_DIR/.cvs-updated-$vcrootname" ]; then
rm "$VIEWVC_DIR/.cvs-updated-$vcrootname"
$VIEWVC_DIR/bin/cvsdbadmin update $CVSROOT >/dev/null
fi
EOF
chmod 755 $VIEWVC_DIR/cvshook-$vcrootname
cat >/etc/cron.d/viewvc-cvs-$vcrootname <<EOF
*/5 * * * * root $VIEWVC_DIR/cvshook-$vcrootname
EOF
fi
done;
if [ "$CVS_ASYNC" ]; then
echo "*** Reloading cron daemon"
/etc/init.d/cron reload
fi

36
bin/setup-svn-hooks Executable file
View File

@@ -0,0 +1,36 @@
#!/bin/sh
SVNROOT=$1
VIEWVC_DIR=$2
SVN_ASYNC=$3
if [ ! "$SVNROOT" -o ! "$VIEWVC_DIR" ]; then
echo "USAGE: $0 <SVNROOT> <VIEWVC_DIR>"
exit
fi
echo "*** Setting up commit hooks for Subversion"
for i in `ls $SVNROOT`; do
if [ -d "$SVNROOT/$i" ]; then
if [ "$SVN_ASYNC" ]; then
cat >"$SVNROOT/$i/hooks/post-commit.tmp" <<EOF
#!/bin/sh
echo "\$1 \$2" >> $VIEWVC_DIR/.svn-updated
EOF
else
cat >"$SVNROOT/$i/hooks/post-commit.tmp" <<EOF
#!/bin/sh
$VIEWVC_DIR/bin/svndbadmin update \$1 \$2
EOF
fi
chmod 755 "$SVNROOT/$i/hooks/post-commit.tmp"
mv "$SVNROOT/$i/hooks/post-commit.tmp" "$SVNROOT/$i/hooks/post-commit"
fi
done;
if [ "$SVN_ASYNC" ]; then
cat >/etc/cron.d/viewvc-svn <<EOF
*/10 * * * * root $VIEWVC_DIR/bin/svnupdate-async.sh "$VIEWVC_DIR"
EOF
/etc/init.d/cron reload
fi

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 2004 James Henstridge
# Copyright (C) 2004-2013 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 2004-2007 James Henstridge
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -27,37 +28,41 @@
#
# If you allow changes to revision properties in your repository, you
# might also want to set up something similar in the
# post-revprop-change hook using "rebuild" instead of "update" to keep
# the checkin database consistent with the repository.
# post-revprop-change hook using "update" with the --force option to
# keep the checkin database consistent with the repository.
#
# -----------------------------------------------------------------------
#
#########################################################################
#
# INSTALL-TIME CONFIGURATION
#
# These values will be set during the installation process. During
# development, they will remain None.
# development, there will be no 'viewvcinstallpath.py'
#
LIBRARY_DIR = None
CONF_PATHNAME = None
import viewvcinstallpath
LIBRARY_DIR = viewvcinstallpath.LIBRARY_DIR
CONF_PATHNAME = viewvcinstallpath.CONF_PATHNAME
# Adjust sys.path to include our library directory
import sys
import os
if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
sys.path.insert(0, LIBRARY_DIR)
else:
sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0], "../../lib")))
sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0], "../../lib")))
#########################################################################
import os
import string
import socket
import select
import re
import mimetypes
import time
import svn.core
import svn.repos
@@ -66,27 +71,61 @@ import svn.delta
import cvsdb
import viewvc
import vclib
from viewvcmagic import ContentMagic
class SvnRepo:
"""Class used to manage a connection to a SVN repository."""
def __init__(self, path, pool):
self.scratch_pool = svn.core.svn_pool_create(pool)
def __init__(self, path, index_content = None, tika_client = None, guesser = None,
svn_ignore_mimetype = False, verbose = False):
self.path = path
self.repo = svn.repos.svn_repos_open(path, pool)
self.repo = svn.repos.svn_repos_open(path)
self.fs = svn.repos.svn_repos_fs(self.repo)
# youngest revision of base of file system is highest revision number
self.rev_max = svn.fs.youngest_rev(self.fs, pool)
self.rev_max = svn.fs.youngest_rev(self.fs)
self.index_content = index_content
self.tika_client = tika_client
self.guesser = guesser
self.verbose = verbose
self.svn_ignore_mimetype = svn_ignore_mimetype
def __getitem__(self, rev):
if rev is None:
rev = self.rev_max
elif rev < 0:
rev = rev + self.rev_max + 1
assert 0 <= rev <= self.rev_max
rev = SvnRev(self, rev, self.scratch_pool)
svn.core.svn_pool_clear(self.scratch_pool)
rev = SvnRev(self, rev)
return rev
_re_diff_change_command = re.compile('(\d+)(?:,(\d+))?([acd])(\d+)(?:,(\d+))?')
_re_diff_change_command = re.compile('^(\d+)(?:,(\d+))?([acd])(\d+)(?:,(\d+))?')
class StupidBufferedReader:
def __init__(self, fp, buffer = 262144):
self.fp = fp
self.bufsize = buffer
self.buffer = ''
self.eof = False
def __iter__(self):
return self
def next(self):
if self.eof:
raise StopIteration
return self.readline()
def readline(self):
if self.eof:
return ''
p = self.buffer.find('\n')
while p < 0:
b = self.fp.read(self.bufsize)
if not len(b):
r = self.buffer
self.buffer = ''
self.eof = True
return r
self.buffer = self.buffer + b
p = self.buffer.find('\n')
r = self.buffer[0:p+1]
self.buffer = self.buffer[p+1:]
return r
def _get_diff_counts(diff_fp):
"""Calculate the plus/minus counts by parsing the output of a
@@ -99,8 +138,7 @@ def _get_diff_counts(diff_fp):
GNU diff manual."""
plus, minus = 0, 0
line = diff_fp.readline()
while line:
for line in diff_fp:
match = re.match(_re_diff_change_command, line)
if match:
# size of first range
@@ -126,78 +164,203 @@ def _get_diff_counts(diff_fp):
# RdL - remove range R of file1, which would have been
# at line L of file2
minus = minus + count1
line = diff_fp.readline()
return plus, minus
class TikaClient:
# Create tika client
def __init__(self, tika_server, mime_types, verbose):
self.tika_server = tika_server
self.mime_types = mime_types
self.verbose = verbose
self.addr = tika_server.split(':')
# Split address
if len(self.addr) != 2:
raise Exception('tika_server value is incorrect: \''+tika_server+'\', please use \'host:port\' format')
self.addr = (self.addr[0], int(self.addr[1]))
# Build regexp for MIME types
m = re.split('\s+', mime_types.strip())
self.mime_regexp = re.compile('|'.join('^'+re.escape(i).replace('\\*', '.*')+'$' for i in m))
# Extract text content from file using Tika which runs in server mode
def get_text(self, filename, mime_type, log_filename):
if not self.mime_regexp.match(mime_type):
# Tika can't handle this mime type, return nothing
return ''
fd = None
s = None
text = ''
fsize = 0
try:
# Read original file
fd = open(filename, 'rb')
data = fd.read()
fsize = len(data)
if not fsize:
return ''
# Connect to Tika
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(self.addr)
s.setblocking(0)
sockfd = s.fileno()
# Tika is somewhat delicate about network IO, so:
# Read and write using poll(2) system call
p = select.poll()
p.register(sockfd)
while 1:
fds = p.poll()
if not fds:
break
(pollfd, event) = fds[0]
if event & select.POLLIN:
# Exception or empty data means EOF...
try: part = os.read(sockfd, 65536)
except: break
if not part: break
text += part
if event & select.POLLOUT:
if not len(data):
# Shutdown output and forget about POLLOUT
s.shutdown(socket.SHUT_WR)
p.modify(sockfd, select.POLLIN)
else:
# Write and consume some data
l = os.write(sockfd, data)
data = data[l:]
if len(text) == 0:
raise Exception('Empty response from Tika server')
if self.verbose:
print "Extracted %d bytes from %s (%s) of size %d" % (len(text), log_filename, mime_type, fsize)
except Exception, e:
if self.verbose:
print "Error extracting text from %s (%s) of size %d: %s" % (log_filename, mime_type, fsize, str(e))
finally:
if fd: fd.close()
if s: s.close()
return text
class SvnRev:
"""Class used to hold information about a particular revision of
the repository."""
def __init__(self, repo, rev, pool):
def __init__(self, repo, rev):
self.repo = repo
self.rev = rev
self.pool = pool
self.rev_roots = {} # cache of revision roots
subpool = svn.core.svn_pool_create(pool)
# revision properties ...
properties = svn.fs.revision_proplist(repo.fs, rev, pool)
self.author = str(properties.get(svn.core.SVN_PROP_REVISION_AUTHOR,''))
self.date = str(properties.get(svn.core.SVN_PROP_REVISION_DATE, ''))
self.log = str(properties.get(svn.core.SVN_PROP_REVISION_LOG, ''))
revprops = svn.fs.revision_proplist(repo.fs, rev)
self.author = str(revprops.get(svn.core.SVN_PROP_REVISION_AUTHOR,''))
self.date = str(revprops.get(svn.core.SVN_PROP_REVISION_DATE, ''))
self.log = str(revprops.get(svn.core.SVN_PROP_REVISION_LOG, ''))
# convert the date string to seconds since epoch ...
self.date = svn.core.secs_from_timestr(self.date, pool)
try:
self.date = svn.core.svn_time_from_cstring(self.date) / 1000000
except:
self.date = None
# get a root for the current revisions
fsroot = self._get_root_for_rev(rev)
# find changes in the revision
editor = svn.repos.RevisionChangeCollector(repo.fs, rev, pool)
e_ptr, e_baton = svn.delta.make_editor(editor, pool)
svn.repos.svn_repos_replay(fsroot, e_ptr, e_baton, pool)
editor = svn.repos.ChangeCollector(repo.fs, fsroot)
e_ptr, e_baton = svn.delta.make_editor(editor)
svn.repos.svn_repos_replay(fsroot, e_ptr, e_baton)
self.changes = []
changes_hash = {}
for path, change in editor.changes.items():
# clear the iteration subpool
svn.core.svn_pool_clear(subpool)
# skip non-file changes
if change.item_kind != svn.core.svn_node_file: continue
if change.item_kind != svn.core.svn_node_file:
continue
# deal with the change types we handle
action = None
base_root = None
base_path = change.base_path
if change.base_path:
base_root = self._get_root_for_rev(change.base_rev)
if not change.path:
# figure out what kind of change this is, and get a diff
# object for it. note that prior to 1.4 Subversion's
# bindings didn't give us change.action, but that's okay
# because back then deleted paths always had a change.path
# of None.
if hasattr(change, 'action') \
and change.action == svn.repos.CHANGE_ACTION_DELETE:
action = 'remove'
elif not change.path:
action = 'remove'
elif change.added:
action = 'add'
else:
action = 'change'
diffobj = svn.fs.FileDiff(base_root and base_root or None,
base_root and change.base_path or None,
change.path and fsroot or None,
change.path and change.path or None,
subpool, [])
if action == 'remove':
diffobj = svn.fs.FileDiff(base_root, change.base_path, None, None, None, ['-b', '-B'])
else:
diffobj = svn.fs.FileDiff(base_root, change.base_path, fsroot, change.path, None, ['-b', '-B'])
diff_fp = diffobj.get_pipe()
diff_fp = StupidBufferedReader(diff_fp)
plus, minus = _get_diff_counts(diff_fp)
self.changes.append((path, action, plus, minus))
# CustIS Bug 50473: a workaround for svnlib behaviour in file movements (FILE1 -> FILE2 + FILE1 -> null)
if change.base_path:
if not change.path and change.base_path in changes_hash:
minus = 0
elif change.path:
changes_hash[change.base_path] = change.path
content = ''
mime = ''
# need to check if binary file's content changed when copying,
# if not, don't extract it, just get it from previous revision later
if repo.index_content and action != 'remove' and change.path and (not change.base_path
or svn.fs.contents_changed(
base_root and base_root or None,
base_root and change.base_path or None,
fsroot, change.path
)):
props = svn.fs.node_proplist(fsroot, change.path)
if not repo.svn_ignore_mimetype:
mime = props.get('svn:mime-type', None)
else:
mime = None
mime = repo.guesser.guess_mime(
mime,
os.path.basename(change.path),
diffobj.tempfile2
)
# Read and guess charset by ourselves for text files
if mime and mime.startswith('text/') or (mime.startswith('application/') and mime.endswith('xml')):
try:
fd = open(diffobj.tempfile2, 'rb')
content = fd.read()
fd.close()
except: pass
# Guess charset
if content:
content, charset = repo.guesser.guess_charset(content)
if charset:
content = content.encode('utf-8')
if repo.verbose:
print 'Guessed %s for %s' % (charset, change.path)
elif repo.verbose:
print 'Failed to guess charset for %s, not indexing' % (change.path, )
# Try to extract content using Tika from binary documents
elif repo.tika_client:
content = repo.tika_client.get_text(diffobj.tempfile2, mime, change.path)
self.changes.append((path, action, plus, minus, content, mime))
def _get_root_for_rev(self, rev):
"""Fetch a revision root from a cache of such, or a fresh root
(which is then cached for later use."""
if not self.rev_roots.has_key(rev):
self.rev_roots[rev] = svn.fs.revision_root(self.repo.fs, rev,
self.pool)
self.rev_roots[rev] = svn.fs.revision_root(self.repo.fs, rev)
return self.rev_roots[rev]
def handle_revision(db, command, repo, rev, verbose):
def handle_revision(db, command, repo, rev, verbose, force=0):
"""Adds a particular revision of the repository to the checkin database."""
revision = repo[rev]
committed = 0
@@ -208,7 +371,7 @@ def handle_revision(db, command, repo, rev, verbose):
if verbose: print "skipped (no changes)."
return
for (path, action, plus, minus) in revision.changes:
for (path, action, plus, minus, content, mime) in revision.changes:
directory, file = os.path.split(path)
commit = cvsdb.CreateCommit()
commit.SetRepository(repo.path)
@@ -221,6 +384,8 @@ def handle_revision(db, command, repo, rev, verbose):
commit.SetPlusCount(plus)
commit.SetMinusCount(minus)
commit.SetBranch(None)
commit.SetContent(content)
commit.SetMimeType(mime)
if action == 'add':
commit.SetTypeAdd()
@@ -231,7 +396,7 @@ def handle_revision(db, command, repo, rev, verbose):
if command == 'update':
result = db.CheckCommit(commit)
if result:
if result and not force:
continue # already recorded
# commit to database
@@ -244,38 +409,89 @@ def handle_revision(db, command, repo, rev, verbose):
else:
print "skipped (already recorded)."
def main(pool, command, repository, rev=None, verbose=0):
def main(command, repository, revs=[], verbose=0, force=0):
cfg = viewvc.load_config(CONF_PATHNAME)
db = cvsdb.ConnectDatabase(cfg)
repo = SvnRepo(repository, pool)
if rev:
handle_revision(db, command, repo, rev, verbose)
else:
repository = os.path.realpath(repository)
# Purge what must be purged.
if command in ('rebuild', 'purge'):
if verbose:
print "Purging commit info for repository root `%s'" % repository
try:
db.PurgeRepository(repository)
except cvsdb.UnknownRepositoryError, e:
if command == 'purge':
sys.stderr.write("ERROR: " + str(e) + "\n")
sys.exit(1)
tika_client = None
if cfg.utilities.tika_server:
tika_client = TikaClient(cfg.utilities.tika_server, cfg.utilities.tika_mime_types, verbose)
repo = SvnRepo(
path = repository,
index_content = cfg.cvsdb.index_content,
tika_client = tika_client,
guesser = cfg.guesser(),
svn_ignore_mimetype = cfg.options.svn_ignore_mimetype,
verbose = verbose,
)
# Record what must be recorded.
if command == 'rebuild' or (command == 'update' and not revs):
for rev in range(repo.rev_max+1):
handle_revision(db, command, repo, rev, verbose)
handle_revision(db, command, repo, rev, verbose, force)
elif command == 'update':
if revs[0] is None:
revs[0] = repo.rev_max
if revs[1] is None:
revs[1] = repo.rev_max
revs.sort()
for rev in range(revs[0], revs[1]+1):
handle_revision(db, command, repo, rev, verbose, force)
def _rev2int(r):
if r == 'HEAD':
r = None
else:
r = int(r)
if r < 0:
raise ValueError, "invalid revision '%d'" % (r)
return r
def usage():
cmd = os.path.basename(sys.argv[0])
sys.stderr.write("""
Usage: 1. %s [-v] rebuild REPOSITORY [REVISION]
2. %s [-v] update REPOSITORY [REVISION]
sys.stderr.write(
"""Administer the ViewVC checkins database data for the Subversion repository
located at REPOS-PATH.
1. Rebuild the commit database information for REPOSITORY across all revisions
or, optionally, only for the specified REVISION.
Usage: 1. %s [-v] rebuild REPOS-PATH
2. %s [-v] update REPOS-PATH [REV[:REV2]] [--force]
3. %s [-v] purge REPOS-PATH
2. Update the commit database information for REPOSITORY across all revisions
or, optionally, only for the specified REVISION. This is just like
rebuilding, except that no commit information will be stored for
commits already present in the database.
1. Rebuild the commit database information for the repository located
at REPOS-PATH across all revisions, after first purging
information specific to that repository (if any).
2. Update the commit database information for the repository located
at REPOS-PATH across all revisions or, optionally, only for the
specified revision REV (or revision range REV:REV2). This is just
like rebuilding, except that, unless --force is specified, no
commit information will be stored for commits already present in
the database. If a range is specified, the revisions will be
processed in ascending order, and you may specify "HEAD" to
indicate "the youngest revision currently in the repository".
3. Purge information specific to the repository located at REPOS-PATH
from the database.
Use the -v flag to cause this script to give progress information as it works.
""" % (cmd, cmd))
""" % (cmd, cmd, cmd))
sys.exit(1)
if __name__ == '__main__':
verbose = 0
force = 0
args = sys.argv
try:
index = args.index('-v')
@@ -283,29 +499,47 @@ if __name__ == '__main__':
del args[index]
except ValueError:
pass
try:
index = args.index('--force')
force = 1
del args[index]
except ValueError:
pass
if len(args) < 3:
usage()
command = string.lower(args[1])
if command not in ('rebuild', 'update'):
command = args[1].lower()
if command not in ('rebuild', 'update', 'purge'):
sys.stderr.write('ERROR: unknown command %s\n' % command)
usage()
repository = args[2]
if not os.path.exists(repository):
sys.stderr.write('ERROR: could not find repository %s\n' % repository)
usage()
revs = []
if len(sys.argv) > 3:
rev = sys.argv[3]
if command == 'rebuild':
sys.stderr.write('ERROR: rebuild no longer accepts a revision '
'number argument. Usage update --force.')
usage()
elif command != 'update':
usage()
try:
rev = int(rev)
revs = map(lambda x: _rev2int(x), sys.argv[3].split(':'))
if len(revs) > 2:
raise ValueError, "too many revisions in range"
if len(revs) == 1:
revs.append(revs[0])
except ValueError:
sys.stderr.write('ERROR: revision "%s" is not numeric\n' % rev)
sys.stderr.write('ERROR: invalid revision specification "%s"\n' \
% sys.argv[3])
usage()
else:
rev = None
repository = cvsdb.CleanRepository(os.path.abspath(repository))
svn.core.run_app(main, command, repository, rev, verbose)
try:
repository = vclib.svn.canonicalize_rootpath(args[2])
repository = cvsdb.CleanRepository(os.path.abspath(repository))
main(command, repository, revs, verbose, force)
except KeyboardInterrupt:
print
print '** break **'
sys.exit(0)

50
bin/svnupdate-async Executable file
View File

@@ -0,0 +1,50 @@
#!/usr/bin/perl
# Скрипт для обновления SVN репозиториев svndbadmin-ом
# Берёт номера ревизий и имена репозиториев из перечисленных файлов или STDIN,
# группирует их по номерам и выводит список команд, необходимых для обновления
use strict;
# первый аргумент - путь к svndbadmin
my $svndbadmin = shift @ARGV
|| die "USAGE: $0 <path_to_svndbadmin> FILES...";
# считываем названия репозиториев и номера ревизий из файла
my $tou = {};
my ($repos, $rev);
while (<>)
{
s/^\s+//so;
s/\s+$//so;
($repos, $rev) = split /\s+/, $_;
$tou->{$repos}->{$rev} = 1;
}
# превращаем номера ревизий в диапазоны ревизий
my ($i, $j, $r, $nr);
foreach $repos (keys %$tou)
{
$rev = [ sort keys %{$tou->{$repos}} ];
$nr = [];
$j = 0;
for $i (1..@$rev)
{
if ($i > $#$rev || $rev->[$i]-$rev->[$j] > $i-$j)
{
$r = $rev->[$j];
$r .= ":".$rev->[$i-1] if $i-$j > 1;
push @$nr, $r;
$j = $i;
}
}
$tou->{$repos} = $nr;
}
# выводим список команд для выполнения
foreach $repos (keys %$tou)
{
foreach (@{$tou->{$repos}})
{
print "$svndbadmin update $repos $_\n";
}
}

8
bin/svnupdate-async.sh Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/sh
VIEWVC_DIR=$1
test -f "$VIEWVC_DIR/.svn-updating" -o ! -f "$VIEWVC_DIR/.svn-updated" && exit 0
mv "$VIEWVC_DIR/.svn-updated" "$VIEWVC_DIR/.svn-updating"
"$VIEWVC_DIR/bin/svnupdate-async" "$VIEWVC_DIR/bin/svndbadmin" "$VIEWVC_DIR/.svn-updating" | sh &> /tmp/svnupdate-async.log
rm "$VIEWVC_DIR/.svn-updating"

54
bin/wsgi/query.fcgi Normal file
View File

@@ -0,0 +1,54 @@
#!/usr/bin/python
# -*-python-*-
#
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
#
# viewvc: View CVS/SVN repositories via a web browser
#
# -----------------------------------------------------------------------
#
# This is a fcgi entry point for the query ViewVC app. It's appropriate
# for use with mod_fcgid and flup. It defines a single application function
# that is a valid fcgi entry point.
#
# mod_fcgid: http://httpd.apache.org/mod_fcgid/
# flup:
# http://pypi.python.org/pypi/flup
# http://trac.saddi.com/flup
#
# -----------------------------------------------------------------------
import sys, os
LIBRARY_DIR = None
CONF_PATHNAME = None
if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
else:
sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0],
"../../../lib")))
import sapi
import viewvc
import query
from flup.server import fcgi
def application(environ, start_response):
server = sapi.WsgiServer(environ, start_response)
cfg = viewvc.load_config(CONF_PATHNAME, server)
viewvc_base_url = cfg.query.viewvc_base_url
if viewvc_base_url is None:
viewvc_base_url = "viewvc.fcgi"
query.main(server, cfg, viewvc_base_url)
return []
fcgi.WSGIServer(application).run()

45
bin/wsgi/query.wsgi Normal file
View File

@@ -0,0 +1,45 @@
# -*-python-*-
#
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
#
# viewvc: View CVS/SVN repositories via a web browser
#
# -----------------------------------------------------------------------
#
# This is a wsgi entry point for the query ViewVC app. It's appropriate
# for use with mod_wsgi. It defines a single application function that
# is a valid wsgi entry point.
#
# -----------------------------------------------------------------------
import sys, os
LIBRARY_DIR = None
CONF_PATHNAME = None
if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
else:
sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0],
"../../../lib")))
import sapi
import viewvc
import query
def application(environ, start_response):
server = sapi.WsgiServer(environ, start_response)
cfg = viewvc.load_config(CONF_PATHNAME, server)
viewvc_base_url = cfg.query.viewvc_base_url
if viewvc_base_url is None:
viewvc_base_url = "viewvc.wsgi"
query.main(server, cfg, viewvc_base_url)
return []

50
bin/wsgi/viewvc.fcgi Normal file
View File

@@ -0,0 +1,50 @@
#!/usr/bin/python
# -*-python-*-
#
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
#
# viewvc: View CVS/SVN repositories via a web browser
#
# -----------------------------------------------------------------------
#
# This is a fcgi entry point for the main ViewVC app. It's appropriate
# for use with mod_fcgid and flup. It defines a single application function
# that is a valid fcgi entry point.
#
# mod_fcgid: http://httpd.apache.org/mod_fcgid/
# flup:
# http://pypi.python.org/pypi/flup
# http://trac.saddi.com/flup
#
# -----------------------------------------------------------------------
import sys, os
LIBRARY_DIR = None
CONF_PATHNAME = None
if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
else:
sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0],
"../../../lib")))
import sapi
import viewvc
from flup.server import fcgi
def application(environ, start_response):
server = sapi.WsgiServer(environ, start_response)
cfg = viewvc.load_config(CONF_PATHNAME, server)
viewvc.main(server, cfg)
return []
fcgi.WSGIServer(application).run()

41
bin/wsgi/viewvc.wsgi Normal file
View File

@@ -0,0 +1,41 @@
# -*-python-*-
#
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
#
# viewvc: View CVS/SVN repositories via a web browser
#
# -----------------------------------------------------------------------
#
# This is a wsgi entry point for the main ViewVC app. It's appropriate
# for use with mod_wsgi. It defines a single application function that
# is a valid wsgi entry point.
#
# -----------------------------------------------------------------------
import sys, os
LIBRARY_DIR = None
CONF_PATHNAME = None
if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
else:
sys.path.insert(0, os.path.abspath(os.path.join(sys.argv[0],
"../../../lib")))
import sapi
import viewvc
def application(environ, start_response):
server = sapi.WsgiServer(environ, start_response)
cfg = viewvc.load_config(CONF_PATHNAME, server)
viewvc.main(server, cfg)
return []

41
bin/wsgi/viewvcwsgi.py Normal file
View File

@@ -0,0 +1,41 @@
# -*-python-*-
#
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
#
# viewvc: View CVS/SVN repositories via a web browser
#
# -----------------------------------------------------------------------
#
# This is a wsgi entry point for the main ViewVC app. It's appropriate
# for use with mod_wsgi. It defines a single application function that
# is a valid wsgi entry point.
#
# -----------------------------------------------------------------------
import sys, os
import viewvcinstallpath
LIBRARY_DIR = viewvcinstallpath.LIBRARY_DIR
CONF_PATHNAME = viewvcinstallpath.CONF_PATHNAME
if LIBRARY_DIR:
sys.path.insert(0, LIBRARY_DIR)
else:
sys.path.insert(0, os.path.abspath(os.path.join(
os.path.dirname(__file__), "../../lib")))
import sapi
import viewvc
def application(environ, start_response):
server = sapi.WsgiServer(environ, start_response)
cfg = viewvc.load_config(CONF_PATHNAME, server)
viewvc.main(server, cfg)
return []

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

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

1304
conf/viewvc.conf.dist Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,213 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>ViewVC: 1.1.0 Release Notes</title>
<style>
.h2, .h3 {
padding: 0.25em 0em;
background: white;
}
.warning {
font-style: italic;
}
</style>
</head>
<body>
<h1>ViewVC 1.1.0 Release Notes</h1>
<div class="h2">
<h2 id="introduction">Introduction</h2>
<p>ViewVC 1.1.0 is the superset of all previous ViewVC releases.</p>
</div> <!-- h2 -->
<div class="h2">
<h2 id="compatibility">Compatibility</h2>
<p>Each ViewVC release strives to maintain URL stability with previous
releases, and 1.1.0 is no exception. All URLs considered valid for
previous ViewVC releases should continue to work correctly in this
release, though possibly only via the use of HTTP redirects
(generated by ViewVC itself).</p>
<p>The commits database functionality has changed in ViewVC 1.1.0 in
way that breaks compatibility with prior ViewVC releases, but only
for new database instantiations. ViewVC 1.1.0 will continue to
understand (for both read and write operations) the previous
schema, so you are not required to rebuild your commits database
for ViewVC 1.1.0 compatibility. By default, new commits databases
created using the 1.1.0 version of the <code>make-database</code>
script will use a new database schema that is unreadable by
previous ViewVC versions. However, if you need a database which
can co-exist with a previous ViewVC version, you can use
the <code>--version=1.0</code> option
to <code>make-database</code>.</p>
<p>The ViewVC configuration files and template language have changed
dramatically. See the file <code>docs/upgrading-howto.html</code>
in the release for information on porting existing versions of
those items for use with ViewVC 1.1.0.</p>
</div> <!-- h2 -->
<div class="h2">
<h2 id="compatibility">Features and Fixes</h2>
<div class="h3">
<h3 id="">Extensible path-based authorization w/ Subversion authz support</h3>
<p>In a nutshell, ViewVC is now able to do path-based authorization.
ViewVC 1.0 has a configuration option for naming 'forbidden'
modules, but it is really limited &mdash; it basically just makes a
universal decision about which top-level directories in every
hosted repository should be hidden by ViewVC. People want
more, and specifically requested that ViewVC learn how to honor
Subversion's authz files and semantics. So, along with some other
types of authorization approaches, that's what ViewVC 1.1 can now
do. If you are using mod_authz_svn with Apache today, or
svnserve's built-in authorization support, then you can now point
ViewVC to the same authz configuration file and have it honor the
access rules you've defined for your repositories.</p>
<p>Note that ViewVC does <strong>not</strong> handle authentication,
though. You'll need to configure your web server to demand login
credentials from users, which the web server itself can then hand
off to ViewVC for application against the authorization rules
you've defined.</p>
<p class="warning">WARNING: The root listing view does not consult the
authorization subsystem when deciding what roots to display to a
given user. If you need to protect your root names, consider
disabling it by removing <code>roots</code> from the set of views
listed in the <code>allowed_views</code> configuration option.
<strong>UPDATE: This was fixed in ViewVC 1.1.3.</strong></p>
<p class="warning">WARNING: Support for path-based authorization is
incomplete in the experimental version control backend modules,
including the one that permits display of remote Subversion
repositories. <strong>UPDATE: This was fixed in ViewVC
1.1.15.</strong></p>
</div> <!-- h3 -->
<div class="h3">
<h3 id="">Subversion versioned properties display</h3>
<p>ViewVC 1.1 displays the properties that Subversion lets you store
on files and directories
(<code>svn:mime-type</code>, <code>svn:mergeinfo</code>,
<code>svn:ignore</code>, etc.). Directory properties are shown by
default at the bottom of that directory's entry listing. File
properties are displayed at the bottom of that file's
markup/annotate view.</p>
</div> <!-- h3 -->
<div class="h3">
<h3 id="">Unified markup and annotation views</h3>
<p>The "markup" and "annotate" views in ViewVC now have a unified look
and feel (driven by a single EZT template). Both views support
syntax highlighting and Subversion file property display.</p>
</div> <!-- h3 -->
<div class="h3">
<h3 id="">Unified, hassle-free Pygments-based syntax highlighting</h3>
<p>ViewVC 1.0 does syntax highlighting by working with GNU enscript, or
highlight, or php, or py2html &mdash; all these external tools just
to accomplish a single task. But they all do things in slightly
different ways. And if you configure them wrongly, you get strange
errors. <a href="http://www.pygments.org/">Pygments</a> (which is
also used by <a href="http://trac.edgewall.org/">Trac</a> for
syntax highlighting) is a Python package that requires no
configuration, is easier to use inside ViewVC, and so on. So
ViewVC 1.1 drops support for all those various old integrations,
and just uses Pygments for everything now. This change was about
developer and administrator sanity. There will be complaints, to
be sure, about how various color schemes differ and what file types
now are and aren't understood by the syntax highlighting engine,
but this change should vastly simplify the discussions of such
things.</p>
</div> <!-- h3 -->
<div class="h3">
<h3 id="">Better MIME detection and handling</h3>
<p>ViewVC typically consults a MIME types file to determine what kind
of file a given document is, based on its filename extension
(<code>.jpg</code> = <code>image/jpeg</code>, &hellip;). But
Subversion lets you dictate a file's MIME type using
the <code>svn:mime-type</code> property. ViewVC now recognizes and
honors that property as the preferred source of a file's MIME type.
This can be disabled in the configuration, though, which might be
desirable if many of your Subversion-versioned files carry the
generic <code>application/octet-stream</code> MIME type that
Subversion uses by default for non-human-readable files.</p>
<p>Also, ViewVC now allows you to specify multiple MIME type mapping
files that you'd like it to consult when determine the MIME type of
files based on their extensions. This allows administrators to
easily define their own custom mappings for ViewVC's benefit
without potentially affecting the mappings used by other site
services.</p>
</div> <!-- h3 -->
<div class="h3">
<h3 id="">Support for full content diffs</h3>
<p>ViewVC 1.1 expands the previously existing options of "colored
diff" and "long colored diff" with a new "full colored diff", which
shows the full contents of the changed file (instead of only the 3
or 15 lines of context shown via the older diff display types).</p>
</div> <!-- h3 -->
<div class="h3">
<h3 id="">Support for per-root configuration overrides</h3>
<p>In ViewVC 1.1, you can setup configuration option overrides on a
per-root (per-repository) basis (if you need/care to do so). See
the comments in the <code>viewvc.conf.dist</code> file for more on
how to do this.</p>
</div> <!-- h3 -->
<div class="h3">
<h3 id="">Optional email address obfuscation/mangling</h3>
<p>ViewVC can, when displaying revision metadata, munge strings that
look like email addresses to protect them from screen-scraping
spammers. For example, a log message that says, "Patch by:
cmpilato@red-bean.com" can optionally be displayed by ViewVC using
HTML entity encoding for the characters (a trick that causes no
visible change to the output, but that might confuse
unsophisticated spam bot crawlers) or as "Patch by: cmpilato@..."
(which isn't a complete email address at all, but might be enough
information for the human reading the log message to know who to
blame for the patch).</p>
</div> <!-- h3 -->
<div class="h3">
<h3 id="">Pagination improvements</h3>
<p>The way that ViewVC splits directory and log views across pages has
been reworked. The old way was "Fetch all the information you can
find, then display only one page's worth." The new way is "Fetch
only what you need to display the page requested, plus a little bit
of border information." This provides a large performance
enhancement for the default sort orderings.</p>
</div> <!-- h3 -->
</div> <!-- h2 -->
</body>
</html>

View File

@@ -0,0 +1,49 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>ViewVC: 1.2.0 Release Notes</title>
<style>
.h2, .h3 {
padding: 0.25em 0em;
background: white;
}
.warning {
font-style: italic;
}
</style>
</head>
<body>
<h1>ViewVC 1.2.0 Release Notes</h1>
<div class="h2">
<h2 id="introduction">Introduction</h2>
<p>ViewVC 1.2.0 is the superset of all previous ViewVC releases.</p>
</div> <!-- h2 -->
<div class="h2">
<h2 id="compatibility">Compatibility</h2>
<p>Each ViewVC release strives to maintain URL stability with previous
releases, and 1.2.0 is no exception. All URLs considered valid for
previous ViewVC releases should continue to work correctly in this
release, though possibly only via the use of HTTP redirects
(generated by ViewVC itself).</p>
</div> <!-- h2 -->
<div class="h2">
<h2 id="compatibility">Features and Fixes</h2>
<div class="h3">
<h3 id=""></h3>
</div> <!-- h3 -->
</div> <!-- h2 -->
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
<html>
<head>
<title>ViewVC 1.0 URL Reference</title>
<title>ViewVC 1.1 URL Reference</title>
<style>
body {
background-color: rgb(180,193,205);
@@ -37,14 +37,22 @@ th.caption {
</head>
<body>
<h1>ViewVC 1.0 URL Reference</h1>
<h1>ViewVC 1.1 URL Reference</h1>
<div class="h2">
<h2 id="introduction">Introduction</h2>
<p>This document describes the format of URLs accepted by ViewVC 1.0 and is intended to be useful to users and outside software developers who want to create links to ViewVC pages. It should also be useful to ViewVC developers as a way of tracking and documenting the many quirks of ViewVC's URL handling logic.</p>
<p>This document describes the format of URLs accepted by ViewVC 1.1
and is intended to be useful to users and outside software
developers who want to create links to ViewVC pages. It should also
be useful to ViewVC developers as a way of tracking and documenting
the many quirks of ViewVC's URL handling logic.</p>
<p>Future releases of ViewVC will support the URL formats described in this document. Certain URLs currently accepted by ViewVC, such as redirecting URLs that result from the submission of form elements on ViewVC pages, are not documented here and therefore may not be supported by future releases of ViewVC.</p>
<p>Future releases of ViewVC will support the URL formats described in
this document. Certain URLs currently accepted by ViewVC, such as
redirecting URLs that result from the submission of form elements
on ViewVC pages, are not documented here and therefore may not be
supported by future releases of ViewVC.</p>
</div>
@@ -78,8 +86,9 @@ th.caption {
</ul>
<li><a href="#compat">Backwards Compatibility</a></li>
<ul>
<li><a href="#compat-viewrev">'<code>view=rev</code>' Parameter &rArr; '<code>view=revision</code>'</a></li>
<li><a href="#compat-cvsroot">'<code>cvsroot</code>' Parameter &rArr; '<code>root</code>'</a></li>
<li><a href="#compat-only_with_tag>'<code>only_with_tag</code>' Parameter &rArr; '<code>pathrev</code>'</a></li>
<li><a href="#compat-only_with_tag">'<code>only_with_tag</code>' Parameter &rArr; '<code>pathrev</code>'</a></li>
<li><a href="#compat-oldcheckout">'<code>~checkout~</code>' Magic Path Prefix &rArr; '<code>*checkout*</code>'</a></li>
<li><a href="#compat-checkout">'<code>*checkout*</code>' Magic Path Prefix &rArr; '<code>view=co</code>'</a></li>
<li><a href="#compat-root">'<code>root</code>' Parameter &rArr; Root Path Component</a></li>
@@ -89,7 +98,7 @@ th.caption {
<li><a href="#compat-tarball">'<code>tarball=1</code>' Parameter &rArr; '<code>view=tar</code>'</a></li>
<li><a href="#compat-graph">'<code>graph=1</code>' Parameter &rArr; '<code>view=graph</code>'</a></li>
<li><a href="#compat-makeimage">'<code>graph=1&makeimage=1</code>' Parameters &rArr; '<code>view=graphimg</code>'</a></li>
<li><a href="#compat-content_type">'<code>content_type=text/vnd.viewcvs-markup</code>' and '<code>content_type=text/x-cvsweb-markup</code>' Parameters&rArr; '<code>view=markup</code>'
<li><a href="#compat-content_type">'<code>content-type=text/vnd.viewcvs-markup</code>' and '<code>content-type=text/x-cvsweb-markup</code>' Parameters&rArr; '<code>view=markup</code>'
<li><a href="#compat-attic">'<code>Attic/FILE</code>' Paths &rArr; '<code>FILE</code>'</a></li>
</ul>
</div>
@@ -98,7 +107,11 @@ th.caption {
<div class="h2">
<h2 id="components">URL Components</h2>
<p>A ViewVC URL consists of 3 components: a <a href="#script-component">Script Location</a>, a <a href="#path-component">Repository Path</a>, and some optional <a href="#query-component">Query Parameters</a>. Some examples:</p>
<p>A ViewVC URL consists of 3 components: a <a
href="#script-component">Script Location</a>, a <a
href="#path-component">Repository Path</a>, and some optional <a
href="#query-component">Query Parameters</a>. Some examples:</p>
<table>
<tr>
@@ -134,22 +147,60 @@ th.caption {
</table>
<h3 id="script-component">ViewVC Script Location</h3>
<p>The script location is a common base for all ViewVC URL's pertaining to a particular installation. It's whatever location the web server is configured to serve ViewVC pages from.</p>
<p>The script location is a common base for all ViewVC URL's
pertaining to a particular installation. It's whatever location the
web server is configured to serve ViewVC pages from.</p>
<h3 id="path-component">Repository Path</h3>
<p>Since ViewVC is essentially a file system browser for repositories, repository paths referring to the files and directories being browsed get their own section in ViewVC URLs immediately following the script location. Repository paths are always case sensitive and separated by forward slashes, regardless of the underlying filesystem.</p>
<p>Repository paths can be given certain "magic" prefixes and suffixes. For example, a "/*checkout*" prefix can be added to file views to force a checkout even without an explicit "view=co" query parameter. And a ".tar.gz" suffix is added to download tarball URLs so downloaded tarballs will be saved with sensible default names.</p>
<p>Since ViewVC is essentially a file system browser for repositories,
repository paths referring to the files and directories being
browsed get their own section in ViewVC URLs immediately following
the script location. Repository paths are always case sensitive and
separated by forward slashes, regardless of the underlying
filesystem.</p>
<p>Repository paths can be given certain "magic" prefixes and
suffixes. For example, a "/*checkout*" prefix can be added to file
views to force a checkout even without an explicit "view=co" query
parameter. And a ".tar.gz" suffix is added to download tarball URLs
so downloaded tarballs will be saved with sensible default
names.</p>
<p>If the <code>root_as_url_component</code> configuration option is enabled, the first directory name in a repository path (after any magic prefix) is taken to be the name (from the ViewVC configuration) of the repository to browse rather than the name of an actual directory. The repository name can also be specified in a "root=" query parameter instead (see <a href="#root-param"><code>root</code> parameter</a> below).</p>
<p>If the <code>root_as_url_component</code> configuration option is
enabled, the first directory name in a repository path (after any
magic prefix) is taken to be the name (from the ViewVC
configuration) of the repository to browse rather than the name of
an actual directory. The repository name can also be specified in a
"root=" query parameter instead (see <a
href="#root-param"><code>root</code> parameter</a> below).</p>
<p>Paths beginning with "/*docroot*/" are an exception the rules above. These paths are used to provide access to files in the ViewVC template directory: image files, static HTML pages, and the ViewVC stylesheet. For more information, see the <a href="#docroot-view">Docroot View</a> syntax below.</p>
<p>Paths beginning with "/*docroot*/" are an exception the rules
above. These paths are used to provide access to files in the
ViewVC template directory: image files, static HTML pages, and the
ViewVC stylesheet. For more information, see the <a
href="#docroot-view">Docroot View</a> syntax below.</p>
<h3 id="query-component">Query Parameters</h3>
<p>Following the ViewVC and repository locations in URLs is an optional query string, a list of parameter/value pairs written like "?param1=value1&amp;param2=value2..." Some parameters, like "revision", "pathrev", and "root", augment repository path information, specifying revisions and repositories. Other parameters like "logsort" and "diff_format" control ViewVC display options. Some parameters are also "sticky" and get embedded into links inside the generated pages, sticking around for future page views.</p>
<p>Following the ViewVC and repository locations in URLs is an
optional query string, a list of parameter/value pairs written like
"?param1=value1&amp;param2=value2..." Some parameters, like
"revision", "pathrev", and "root", augment repository path
information, specifying revisions and repositories. Other
parameters like "logsort" and "diff_format" control ViewVC display
options. Some parameters are also "sticky" and get embedded into
links inside the generated pages, sticking around for future page
views.</p>
<p>ViewVC provides a number of different views of repository data including a directory listing view, a log view, a file diff view, and others. (The views are listed and described in the <code>help_rootview.html</code> ViewVC help page). URLs for each of these views accept specific parameters described in the <a href="#syntax">URL Syntax</a> section, but some parameters are used by multiple views and they are described below:</p>
<p>ViewVC provides a number of different views of repository data
including a directory listing view, a log view, a file diff view,
and others. (The views are listed and described in the
<code>help_rootview.html</code> ViewVC help page). URLs for each of
these views accept specific parameters described in the <a
href="#syntax">URL Syntax</a> section, but some parameters are used
by multiple views and they are described below:</p>
<table>
<thead>
@@ -161,19 +212,34 @@ th.caption {
<tbody>
<tr>
<td id="view-param"><code>view</code></td>
<td>The name of the view to display, does not need to be explicitly specified in many URLs. Possible values are shown in the <a href="#url-syntax">URL Syntax</a> section below.</td>
<td>The name of the view to display, does not need to be
explicitly specified in many URLs. Possible values are shown
in the <a href="#url-syntax">URL Syntax</a> section
below.</td>
</tr>
<tr>
<td id="revision-param"><code>revision</code></td>
<td>The revision or tag to display information about, used by several different views.</td>
<td>The revision or tag to display information about, used by
several different views.</td>
</tr>
<tr>
<td id="pathrev-param"><code>pathrev</code></td>
<td>The current sticky revision (Subversion) or sticky tag (CVS), as described in the <code>help_rootview.html</code> ViewVC help page. In Subversion, because path information is revision controlled, this value is also used to look up paths in the repository, providing a means of accessing paths that no longer exist in HEAD.</td>
<td>The current sticky revision (Subversion) or sticky tag (CVS),
as described in the <code>help_rootview.html</code> ViewVC
help page. In Subversion, because path information is revision
controlled, this value is also used to look up paths in the
repository, providing a means of accessing paths that no
longer exist in HEAD.</td>
</tr>
<tr>
<td id="root-param"><code>root</code></td>
<td>The name of the repository to browse. When the <code>default_root</code> configuration option is set or the <code>root_as_url_component</code> option is enabled, it is not neccessary to to specify this parameter. When the <code>root_as_url_component</code> option is enabled, ViewVC URLs with <code>root</code> parameters redirect to locations with the root values embedded in the repository paths.</td>
<td>The name of the repository to browse. When the
<code>default_root</code> configuration option is set or the
<code>root_as_url_component</code> option is enabled, it is
not neccessary to to specify this parameter. When the
<code>root_as_url_component</code> option is enabled, ViewVC
URLs with <code>root</code> parameters redirect to locations
with the root values embedded in the repository paths.</td>
</tr>
</tbody>
</table>
@@ -181,7 +247,9 @@ th.caption {
<div class="h2">
<h2 id="syntax">URL Syntax</h2>
<p>This section lists URL syntax for each ViewVC view. Parts of URLs which may vary shown as variables in <var>UPPERCASE</var>.</p>
<p>This section lists URL syntax for each ViewVC view. Parts of URLs
which may vary shown as variables in <var>UPPERCASE</var>.</p>
<h3 id="annotate-view">Annotate View</h3>
<table>
@@ -220,7 +288,9 @@ th.caption {
<tr>
<td><code>view=annotate</code></td>
<td>depends</td>
<td><a href="#view-param"><code>view</code> parameter</a>. Not required when an <code>annotate</code> parameter is present</td>
<td><a href="#view-param"><code>view</code> parameter</a>. Not
required when an <code>annotate</code> parameter is
present</td>
</tr>
<tr>
<td><code>annotate=<var>REVISION</var></code></td>
@@ -258,7 +328,9 @@ th.caption {
<tr>
<td><code>/*checkout*</code></td>
<td>optional</td>
<td>magic prefix. If specified when the <code>checkout_magic</code> configuration option is disabled, ViewVC will redirect to a URL without the prefix.</td>
<td>magic prefix. If specified when the
<code>checkout_magic</code> configuration option is disabled,
ViewVC will redirect to a URL without the prefix.</td>
</tr>
<tr>
<td><code><var>/PATH</var></code></td>
@@ -282,12 +354,18 @@ th.caption {
<tr>
<td><code>view=co</code></td>
<td>depends</td>
<td><a href="#view-param"><code>view</code> parameter</a>, not needed if the <code>default_file_view</code> configuration variable is set to <code>co</code>, since that makes the checkout view the default view for file paths. Also not needed if the <code>/*checkout*</code> magic prefix or the <code>revision</code> parameter is present.
<td><a href="#view-param"><code>view</code> parameter</a>, not
needed if the <code>default_file_view</code> configuration
variable is set to <code>co</code>, since that makes the
checkout view the default view for file paths. Also not needed
if the <code>/*checkout*</code> magic prefix or the
<code>revision</code> parameter is present.
</tr>
<tr>
<td><code>content-type=<var>TYPE</var></code></td>
<td>optional</td>
<td>MIME type to send with checked out file, default is a guess based on file extension</td>
<td>MIME type to send with checked out file, default is a guess
based on file extension</td>
</tr>
<tr>
<td><code>revision=<var>REVISION</var></code></td>
@@ -347,38 +425,52 @@ th.caption {
<tr>
<td><code>r1=<var>R1</var></code></td>
<td>required</td>
<td>starting revision or tag or the string "text" to indicate that <code><var>TR1</var></code> value (below) should override this one</td>
<td>starting revision or tag or the string "text" to indicate that
<code><var>TR1</var></code> value (below) should override this
one</td>
</tr>
<tr>
<td><code>r2=<var>R2</var></code></td>
<td>required</td>
<td>ending revision or tag or the string "text" to indicate that <code><var>TR2</var></code> value (below) should override this one</td>
<td>ending revision or tag or the string "text" to indicate that
<code><var>TR2</var></code> value (below) should override this
one</td>
</tr>
<tr>
<td><code>tr1=<var>TR1</var></code></td>
<td>depends</td>
<td>starting revision or tag, used if <var>r1</var> parameter is present and set to "text"</td>
<td>starting revision or tag, used if <var>r1</var> parameter is
present and set to "text"</td>
</tr>
<tr>
<td><code>tr2=<var>TR2</var></code></td>
<td>depends</td>
<td>ending revision or tag, used if <var>r2</var> parameter is present and set to "text"</td>
<td>ending revision or tag, used if <var>r2</var> parameter is
present and set to "text"</td>
</tr>
<tr>
<td><code>p1=<var>P1</var></code></td>
<td>optional</td>
<td>starting file path that can override the <code><var>PATH</var></code> value to allow files at two different paths to be compared</td>
<td>starting file path that can override the
<code><var>PATH</var></code> value to allow files at two different
paths to be compared</td>
</tr>
<tr>
<td><code>p2=<var>P2</var></code></td>
<td>optional</td>
<td>ending file path that can override the <code><var>PATH</var></code> value to allow files at two different paths to be compared</td>
<td>ending file path that can override the
<code><var>PATH</var></code> value to allow files at two different
paths to be compared</td>
</tr>
<tr>
<td><code>diff_format=<var>DIFF_FORMAT</var></code></td>
<td>optional</td>
<td>value specifying the type of diff to display. Can be "u" for unified diff, "c" for context diff, "s" for side by side diff, "h" for human readable diff, "l" for long human readable diff. If no value is specified the default depends on the <code>diff_format</code> configuration option.
</td>
<td>value specifying the type of diff to display. Can be "u" for
unified diff, "c" for context diff, "s" for side by side diff, "h"
for human readable diff, "l" for long human readable diff, and "f"
for a full human readable diff. If no value is specified the
default depends on the <code>diff_format</code> configuration
option.</td>
</tr>
<tr>
<td><code>pathrev=<var>PATHREV</var></code></td>
@@ -410,7 +502,8 @@ th.caption {
<tr>
<td><code><var>/PATH/</var></code></td>
<td>required</td>
<td>directory path to view. If the trailing slash is omitted, ViewVC will redirect to a URL that has a trailing slash.</td>
<td>directory path to view. If the trailing slash is omitted,
ViewVC will redirect to a URL that has a trailing slash.</td>
</tr>
</table>
<br />
@@ -434,22 +527,28 @@ th.caption {
<tr>
<td><code>hideattic=<var>HIDEATTIC</var></code></td>
<td>optional</td>
<td>"0" to show dead files in CVS directory listings or "1" to hide dead files. Default depends on the <code>hide_attic</code> configuration value.</td>
<td>"0" to show dead files in CVS directory listings or "1" to
hide dead files. Default depends on the <code>hide_attic</code>
configuration value.</td>
</tr>
<tr>
<td><code>search=<var>SEARCH</var></code></td>
<td>optional</td>
<td>regular expression to search files in the directory with if <code>use_re_search</code> configuration option is enabled</td>
<td>regular expression to search files in the directory with if
<code>use_re_search</code> configuration option is enabled</td>
</tr>
<tr>
<td><code>sortby=<var>SORTBY</var></code></td>
<td>optional</td>
<td>"file" "rev" "date" "author" or "log" to indicate how the directory listing should be sorted. Default depends on <code>sortby</code> configuration option.</td>
<td>"file" "rev" "date" "author" or "log" to indicate how the
directory listing should be sorted. Default depends on
<code>sortby</code> configuration option.</td>
</tr>
<tr>
<td><code>sortdir=<var>SORTBY</var></code></td>
<td>optional</td>
<td>"up" to sort directory in ascending order or "down" for descending order. Default is "up".</td>
<td>"up" to sort directory in ascending order or "down" for
descending order. Default is "up".</td>
</tr>
<tr>
<td><code>dir_pagestart=<var>PAGE</var></code></td>
@@ -491,7 +590,10 @@ th.caption {
<tr>
<td><code><var>/PATH</var></code></td>
<td>required</td>
<td>file path to retrieve. ViewVC will return the contents of the file located at <code>PATH</code>, relative to the <code>docroot</code> subdirectory of the directory specified in the <code>template_dir</code> configuration option.</td>
<td>file path to retrieve. ViewVC will return the contents of the
file located at <code>PATH</code>, relative to the
<code>docroot</code> subdirectory of the directory specified in
the <code>template_dir</code> configuration option.</td>
</tr>
</table>
<br />
@@ -552,6 +654,35 @@ th.caption {
<td>depends</td>
<td><a href="#root-param"><code>root</code> parameter</a></td>
</tr>
<tr>
<td><code>gflip=<var>GFLIP</var></code></td>
<td>optional</td>
<td>"1" if the revisions in the graph should run
youngest-to-oldest; "0" for the reverse</td>
</tr>
<tr>
<td><code>gbbox=<var>GBBOX</var></code></td>
<td>optional</td>
<td>"1" if the revision graph should contain branch boxes at the
tip of each branch; "0" otherwise</td>
</tr>
<tr>
<td><code>gleft=<var>GLEFT</var></code></td>
<td>optional</td>
<td>"1" if the revision graph should be orientated left-to-right;
"0" otherwise</td>
</tr>
<tr>
<td><code>gmaxtag=<var>GMAXTAG</var></code></td>
<td>optional</td>
<td>maximum number of per-revision tags to show in the revision graph</td>
</tr>
<tr>
<td><code>gshow=<var>GSHOW</var></code></td>
<td>optional</td>
<td>"all", "inittagged", or "tagged" &mdash; user-selected classes
of revision to show in the graph</td>
</tr>
</table>
<h3 id="graphimg-view">Graph Image View</h3>
@@ -598,6 +729,35 @@ th.caption {
<td>depends</td>
<td><a href="#root-param"><code>root</code> parameter</a></td>
</tr>
<tr>
<td><code>gflip=<var>GFLIP</var></code></td>
<td>optional</td>
<td>"1" if the revisions in the graph should run
youngest-to-oldest; "0" for the reverse</td>
</tr>
<tr>
<td><code>gbbox=<var>GBBOX</var></code></td>
<td>optional</td>
<td>"1" if the revision graph should contain branch boxes at the
tip of each branch; "0" otherwise</td>
</tr>
<tr>
<td><code>gleft=<var>GLEFT</var></code></td>
<td>optional</td>
<td>"1" if the revision graph should be orientated left-to-right;
"0" otherwise</td>
</tr>
<tr>
<td><code>gmaxtag=<var>GMAXTAG</var></code></td>
<td>optional</td>
<td>maximum number of per-revision tags to show in the revision graph</td>
</tr>
<tr>
<td><code>gshow=<var>GSHOW</var></code></td>
<td>optional</td>
<td>"all", "inittagged", or "tagged" &mdash; user-selected classes
of revision to show in the graph</td>
</tr>
</table>
<h3 id="log-view">Log View</h3>
@@ -637,12 +797,20 @@ th.caption {
<tr>
<td><code>view=log</code></td>
<td>depends</td>
<td><a href="#view-param"><code>view</code> parameter</a>, does not need to be specified for file paths when the <code>default_file_view</code> configuration option is set to <code>log</code>. However it is recommended that the parameter be passed anyway for consistency with directory log URLs and compatibility with ViewVC installations that set <code>default_file_view</code> to <code>co</code>.</td>
<td><a href="#view-param"><code>view</code> parameter</a>, does
not need to be specified for file paths when the
<code>default_file_view</code> configuration option is set to
<code>log</code>. However it is recommended that the parameter be
passed anyway for consistency with directory log URLs and
compatibility with ViewVC installations that set
<code>default_file_view</code> to <code>co</code>.</td>
</tr>
<tr>
<td><code>logsort=<var>SORT</var></code></td>
<td>optional</td>
<td>"rev" to sort log entries by revision number or "date" to sort by date. Default depends on the <code>log_sort</code> configuration value.</td>
<td>"rev" to sort log entries by revision number or "date" to sort
by date. Default depends on the <code>log_sort</code>
configuration value.</td>
</tr>
<tr>
<td><code>log_pagestart=<var>PAGE</var></code></td>
@@ -767,37 +935,50 @@ th.caption {
<tr>
<td><code>r1=<var>R1</var></code></td>
<td>required</td>
<td>starting revision or tag or the string "text" to indicate that <code><var>TR1</var></code> value (below) should override this one</td>
<td>starting revision or tag or the string "text" to indicate that
<code><var>TR1</var></code> value (below) should override this
one</td>
</tr>
<tr>
<td><code>r2=<var>R2</var></code></td>
<td>required</td>
<td>ending revision or tag or the string "text" to indicate that <code><var>TR2</var></code> value (below) should override this one</td>
<td>ending revision or tag or the string "text" to indicate that
<code><var>TR2</var></code> value (below) should override this
one</td>
</tr>
<tr>
<td><code>tr1=<var>TR1</var></code></td>
<td>depends</td>
<td>starting revision or tag, only used if <var>r1</var> parameter is present and set to "text"</td>
<td>starting revision or tag, only used if <var>r1</var> parameter
is present and set to "text"</td>
</tr>
<tr>
<td><code>tr2=<var>TR2</var></code></td>
<td>depends</td>
<td>ending revision or tag, only used if <var>r2</var> parameter is present and set to "text"</td>
<td>ending revision or tag, only used if <var>r2</var> parameter
is present and set to "text"</td>
</tr>
<tr>
<td><code>p1=<var>P1</var></code></td>
<td>optional</td>
<td>starting file path that can override the <code><var>PATH</var></code> value to allow files at two different paths to be compared</td>
<td>starting file path that can override the
<code><var>PATH</var></code> value to allow files at two different
paths to be compared</td>
</tr>
<tr>
<td><code>p2=<var>P2</var></code></td>
<td>optional</td>
<td>ending file path that can override the <code><var>PATH</var></code> value to allow files at two different paths to be compared</td>
<td>ending file path that can override the
<code><var>PATH</var></code> value to allow files at two different
paths to be compared</td>
</tr>
<tr>
<td><code>diff_format=<var>DIFF_FORMAT</var></code></td>
<td>optional</td>
<td>value specifying the type of patch to display. Can be "u" for unified diff or "c" for context diff. If no value is specified the default depends on the <code>diff_format</code> configuration option.
<td>value specifying the type of patch to display. Can be "u" for
unified diff or "c" for context diff. If no value is specified the
default depends on the <code>diff_format</code> configuration
option.
</td>
</tr>
<tr>
@@ -859,7 +1040,8 @@ th.caption {
<tr>
<td><code>branch_match=BRANCH_MATCH</code></td>
<td>optional</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type of branch match</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type
of branch match</td>
</tr>
<tr>
<td><code>dir=<var>DIR</var></code></td>
@@ -872,9 +1054,10 @@ th.caption {
<td>file query string</td>
</tr>
<tr>
<td><code>file_match=FILE_MATCH</code></td>
<td><code>file_match=<var>FILE_MATCH</var></code></td>
<td>optional</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type of file match</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type
of file match</td>
</tr>
<tr>
<td><code>who=<var>WHO</var></code></td>
@@ -882,39 +1065,57 @@ th.caption {
<td>author query string</td>
</tr>
<tr>
<td><code>who_match=WHO_MATCH</code></td>
<td><code>who_match=<var>WHO_MATCH</var></code></td>
<td>optional</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type of author match</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type
of author match</td>
</tr>
<tr>
<td><code>querysort=SORT</code></td>
<td><code>comment=<var>COMMENT</var></code></td>
<td>optional</td>
<td>log message query string</td>
</tr>
<tr>
<td><code>comment_match=<var>COMMENT_MATCH</var></code></td>
<td>optional</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type
of log message match</td>
</tr>
<tr>
<td><code>querysort=<var>SORT</var></code></td>
<td>optional</td>
<td>"date" "author" or "file" determining order of query results</td>
</tr>
<tr>
<td><code>date=DATE</code></td>
<td><code>date=<var>DATE</var></code></td>
<td>optional</td>
<td>"hours" "day" "week" "month" "all" or "explicit" to filter query results by date</td>
<td>"hours" "day" "week" "month" "all" or "explicit" to filter
query results by date</td>
</tr>
<tr>
<td><code>hours=HOURS</code></td>
<td><code>hours=<var>HOURS</var></code></td>
<td>optional</td>
<td>number of hours back to include results from when <code><var>DATE</var></code> is "hours"</td>
<td>number of hours back to include results from when
<code><var>DATE</var></code> is "hours"</td>
</tr>
<tr>
<td><code>mindate=MINDATE</code></td>
<td><code>mindate=<var>MINDATE</var></code></td>
<td>optional</td>
<td>earliest date to include results from when <code><var>DATE</var></code> is "explicit"</td>
<td>earliest date to include results from when
<code><var>DATE</var></code> is "explicit"</td>
</tr>
<tr>
<td><code>maxdate=MAXDATE</code></td>
<td><code>maxdate=<var>MAXDATE</var></code></td>
<td>optional</td>
<td>latest date to include results from when <code><var>DATE</var></code> is "explicit"</td>
<td>latest date to include results from when
<code><var>DATE</var></code> is "explicit"</td>
</tr>
<tr>
<td><code>limit_changes=LIMIT_CHANGES</code></td>
<td><code>limit_changes=<var>LIMIT_CHANGES</var></code></td>
<td>optional</td>
<td>maximum number of files to list per commit in query results. Default is value of <code>limit_changes</code> configuration option</td>
<td>maximum number of files to list per commit in query
results. Default is value of <code>limit_changes</code>
configuration option</td>
</tr>
<tr>
<td><code>root=<var>ROOT</var></code></td>
@@ -970,9 +1171,10 @@ th.caption {
<td>branch query string</td>
</tr>
<tr>
<td><code>branch_match=BRANCH_MATCH</code></td>
<td><code>branch_match=<var>BRANCH_MATCH</var></code></td>
<td>optional</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type of branch match</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type
of branch match</td>
</tr>
<tr>
<td><code>dir=<var>DIR</var></code></td>
@@ -985,9 +1187,10 @@ th.caption {
<td>file query string</td>
</tr>
<tr>
<td><code>file_match=FILE_MATCH</code></td>
<td><code>file_match=<var>FILE_MATCH</var></code></td>
<td>optional</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type of file match</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type
of file match</td>
</tr>
<tr>
<td><code>who=<var>WHO</var></code></td>
@@ -995,49 +1198,64 @@ th.caption {
<td>author query string</td>
</tr>
<tr>
<td><code>who_match=WHO_MATCH</code></td>
<td><code>who_match=<var>WHO_MATCH</var></code></td>
<td>optional</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type of author match</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type
of author match</td>
</tr>
<tr>
<td><code>querysort=SORT</code></td>
<td><code>comment=<var>COMMENT</var></code></td>
<td>optional</td>
<td>log message query string</td>
</tr>
<tr>
<td><code>comment_match=<var>COMMENT_MATCH</var></code></td>
<td>optional</td>
<td>"exact" "like" "glob" "regex" or "notregex" determining type
of log message match</td>
</tr>
<tr>
<td><code>querysort=<var>SORT</var></code></td>
<td>optional</td>
<td>"date" "author" or "file" determining order of query results</td>
</tr>
<tr>
<td><code>date=DATE</code></td>
<td><code>date=<var>DATE</var></code></td>
<td>optional</td>
<td>"hours" "day" "week" "month" "all" or "explicit" to filter query results by date</td>
<td>"hours" "day" "week" "month" "all" or "explicit" to filter
query results by date</td>
</tr>
<tr>
<td><code>hours=HOURS</code></td>
<td><code>hours=<var>HOURS</var></code></td>
<td>optional</td>
<td>number of hours back to include results from when <code><var>DATE</var></code> is "hours"</td>
<td>number of hours back to include results from when
<code><var>DATE</var></code> is "hours"</td>
</tr>
<tr>
<td><code>mindate=MINDATE</code></td>
<td><code>mindate=<var>MINDATE</var></code></td>
<td>optional</td>
<td>earliest date to include results from when <code><var>DATE</var></code> is "explicit"</td>
<td>earliest date to include results from when
<code><var>DATE</var></code> is "explicit"</td>
</tr>
<tr>
<td><code>maxdate=MAXDATE</code></td>
<td><code>maxdate=<var>MAXDATE</var></code></td>
<td>optional</td>
<td>latest date to include results from when <code><var>DATE</var></code> is "explicit"</td>
<td>latest date to include results from when
<code><var>DATE</var></code> is "explicit"</td>
</tr>
<tr>
<td><code>format=FORMAT</code></td>
<td><code>format=<var>FORMAT</var></code></td>
<td>optional</td>
<td>"rss" or "backout" values to generate an rss feed or list of commands to back out changes instead showing a normal query result page</td>
<td>"rss" or "backout" values to generate an rss feed or list of
commands to back out changes instead showing a normal query result
page</td>
</tr>
<tr>
<td><code>limit=LIMIT</code></td>
<td><code>limit_changes=<var>LIMIT_CHANGES</var></code></td>
<td>optional</td>
<td>maximum number of file-revisions to process during a query. Default is value of <code>row_limit</code> configuration option</td>
</tr>
<tr>
<td><code>limit_changes=LIMIT_CHANGES</code></td>
<td>optional</td>
<td>maximum number of files to list per commit in query results. Default is value of <code>limit_changes</code> configuration option</td>
<td>maximum number of files to list per commit in query
results. Default is value of <code>limit_changes</code>
configuration option</td>
</tr>
<tr>
<td><code>root=<var>ROOT</var></code></td>
@@ -1077,7 +1295,7 @@ th.caption {
</thead>
<tbody>
<tr>
<td><code>view=rev</code></td>
<td><code>view=revision</code></td>
<td>required</td>
<td><a href="#view-param"><code>view</code> parameter</a></td>
</tr>
@@ -1087,9 +1305,10 @@ th.caption {
<td><a href="#revision-param"><code>revision</code> parameter</a></td>
</tr>
<tr>
<td><code>limit_changes=LIMIT_CHANGES</code></td>
<td><code>limit_changes=<var>LIMIT_CHANGES</var></code></td>
<td>optional</td>
<td>maximum number of files to list per commit. Default is value of <code>limit_changes</code> configuration option</td>
<td>maximum number of files to list per commit. Default is value
of <code>limit_changes</code> configuration option</td>
</tr>
<tr>
<td><code>root=<var>ROOT</var></code></td>
@@ -1130,7 +1349,10 @@ th.caption {
<tr>
<td><code>view=roots</code></td>
<td>depends</td>
<td><a href="#view-param"><code>view</code> parameter</a>. Not required if the <code>root_as_url_component</code> configuration is enabled or the <code>default_root</code> option is not set. </td>
<td><a href="#view-param"><code>view</code> parameter</a>. Not
required if the <code>root_as_url_component</code> configuration
is enabled or the <code>default_root</code> option is not
set. </td>
</tr>
</table>
@@ -1157,7 +1379,11 @@ th.caption {
<tr>
<td><code>.tar.gz</code></td>
<td>depends</td>
<td>magic suffix. Only required when the name of the directory being downloaded ends in ".tar.gz" and the <code>parent</code> parameter not is present. But it is recommended to add the magic suffix to all tarball URLs to avoid this special case and give the downloaded files sensible default names.</td>
<td>magic suffix. Only required when the name of the directory
being downloaded ends in ".tar.gz" and the <code>parent</code>
parameter not is present. But it is recommended to add the magic
suffix to all tarball URLs to avoid this special case and give the
downloaded files sensible default names.</td>
</tr>
</table>
<br />
@@ -1181,7 +1407,12 @@ th.caption {
<tr>
<td><code>parent=1</code></td>
<td>optional</td>
<td>If the <code>parent</code> parameter is specified, the last component of the <code><var>PATH</var></code> is discarded before it is ever looked up in the repository. This feature is used when the <code>root_as_url_component</code> configuration option is disabled to allow root tarball URLs to be saved with names like "ROOT-root.tar.gz".</td>
<td>If the <code>parent</code> parameter is specified, the last
component of the <code><var>PATH</var></code> is discarded before
it is ever looked up in the repository. This feature is used when
the <code>root_as_url_component</code> configuration option is
disabled to allow root tarball URLs to be saved with names like
"ROOT-root.tar.gz".</td>
</tr>
<tr>
<td><code>pathrev=<var>PATHREV</var></code></td>
@@ -1198,46 +1429,111 @@ th.caption {
<div class="h2">
<h2 id="compat">Backwards Compatibility</h2>
<p>ViewVC's URL format has changed a lot over time, but ViewVC goes out of its way to support URLs using older formats so there aren't broken links when an installation of ViewVC is upgraded. The support is implemented as a set of URL transformations that recognize elements of old-style URLs and convert them to newer equivalents. If any transformations are applied (with some exceptions, mentioned below), ViewVC will issue a single redirect to the transformed URL. Descriptions of the transformations follow.</p>
<p>ViewVC's URL format has changed a lot over time, but ViewVC goes
out of its way to support URLs using older formats so there aren't
broken links when an installation of ViewVC is upgraded. The
support is implemented as a set of URL transformations that
recognize elements of old-style URLs and convert them to newer
equivalents. If any transformations are applied (with some
exceptions, mentioned below), ViewVC will issue a single redirect
to the transformed URL. Descriptions of the transformations
follow.</p>
<h3 id="compat-viewrev">'<code>view=rev</code>' Parameter &rArr; '<code>view=revision</code>'</h3>
<p>URLs with a <code>view=rev</code> parameter will automatically be
redirected to URLs with a <code>view=revision</code> parameter
instead.</p>
<h3 id="compat-cvsroot">'<code>cvsroot</code>' Parameter &rArr; '<code>root</code>'</h3>
<p>URLs with a <code>cvsroot</code> parameter will automatically be redirected to URLs with a <code>root</code> parameter instead.</p>
<p>URLs with a <code>cvsroot</code> parameter will automatically be
redirected to URLs with a <code>root</code> parameter instead.</p>
<h3 id="compat-only_with_tag">'<code>only_with_tag</code>' Parameter &rArr; '<code>pathrev</code>'</h3>
<p>URLs with an <code>only_with_tag</code> parameter will automatically be redirected to URLs with a <code>pathrev</code> parameter instead.</p>
<p>URLs with an <code>only_with_tag</code> parameter will
automatically be redirected to URLs with a <code>pathrev</code>
parameter instead.</p>
<h3 id="compat-oldcheckout">'<code>~checkout~</code>' Magic Path Prefix &rArr; '<code>*checkout*</code>'</h3>
<p>URLs with a <code>~checkout~</code> path prefix get interpreted just like URLs with a '*checkout*' prefix. There is currently no redirect, but there could be in the future.</p>
<p>URLs with a <code>~checkout~</code> path prefix get interpreted
just like URLs with a '*checkout*' prefix. There is currently no
redirect, but there could be in the future.</p>
<h3 id="compat-checkout">'<code>*checkout*</code>' Magic Path Prefix &rArr; '<code>view=co</code>'</h3>
<p>When the <code>checkout_magic</code> configuration option is disabled, URLs with a <code>*checkout*</code> magic prefix will redirect to an equivalent URL that does not use the prefix.</p>
<p>When the <code>checkout_magic</code> configuration option is
disabled, URLs with a <code>*checkout*</code> magic prefix will
redirect to an equivalent URL that does not use the prefix.</p>
<h3 id="compat-root">'<code>root</code>' Parameter &rArr; Root Path Component</h3>
<p>When the <code>root_as_url_component</code> configuration option is enabled, URLs with a <code>root</code> parameter will redirect to an equivalent URL with the root name embedded in the path.</p>
<p>When the <code>root_as_url_component</code> configuration option is
enabled, URLs with a <code>root</code> parameter will redirect to
an equivalent URL with the root name embedded in the path.</p>
<h3 id="compat-rev">'<code>rev</code>' Parameter &rArr; '<code>revision</code>' and '<code>pathrev</code>'</h3>
<p>CVS URLs with a <code>rev</code> parameter will redirect to URLs with a <code>revision</code> parameter instead. Subversion URLs with a <code>rev</code> parameter will redirect to URLs with a <code>pathrev</code> parameter, in order to account for the how the Subversion backend used to look up paths before <code>pathrev</code> was introduced.</p>
<p>CVS URLs with a <code>rev</code> parameter will redirect to URLs
with a <code>revision</code> parameter instead. Subversion URLs
with a <code>rev</code> parameter will redirect to URLs with a
<code>pathrev</code> parameter, in order to account for the how the
Subversion backend used to look up paths before
<code>pathrev</code> was introduced.</p>
<h3 id="compat-diff">'<code>.diff</code>' Suffix &rArr; Diff View</h3>
<p>When ViewVC encounters a invalid repository path that ends in <code>.diff</code>, and stripping that ending yields a valid file path, it will redirect to a diff view of the file.</p>
<p>When ViewVC encounters a invalid repository path that ends in
<code>.diff</code>, and stripping that ending yields a valid file
path, it will redirect to a diff view of the file.</p>
<h3 id="compat-tgz">'<code>.tar.gz</code>' Suffix &rArr; '<code>view=tar</code>'</h3>
<p>When ViewVC encounters a invalid repository path that ends in <code>.tar.gz</code>, <code>/root.tar.gz</code>, or <code>/REPOS-root.tar.gz</code>, and stripping the ending yields a valid directory path, it will redirect to a URL to download a tarball of the directory.</p>
<p>When ViewVC encounters a invalid repository path that ends in
<code>.tar.gz</code>, <code>/root.tar.gz</code>, or
<code>/REPOS-root.tar.gz</code>, and stripping the ending yields a
valid directory path, it will redirect to a URL to download a
tarball of the directory.</p>
<h3 id="compat-tarball">'<code>tarball=1</code>' Parameter &rArr; '<code>view=tar</code>'</h3>
<p>A <code>tarball=1</code> parameter is treated pretty much like a <code>view=tar</code> parameter. There is no redirect when it is encountered, but there could be in the future.</p>
<p>A <code>tarball=1</code> parameter is treated pretty much like a
<code>view=tar</code> parameter. There is no redirect when it is
encountered, but there could be in the future.</p>
<h3 id="compat-graph">'<code>graph=1</code>' Parameter &rArr; '<code>view=graph</code>'</h3>
<p>A <code>graph=1</code> parameter is treated like a <code>view=graph</code> parameter. There is currently no redirect when it is encountered, but there could be one in the future.</p>
<p>A <code>graph=1</code> parameter is treated like a
<code>view=graph</code> parameter. There is currently no redirect
when it is encountered, but there could be one in the future.</p>
<h3 id="compat-makeimage">'<code>graph=1&amp;makeimage=1</code>' Parameters &rArr; '<code>view=graphimg</code>'</h3>
<p>A <code>graph=1&amp;makeimage=1</code> parameter is treated like a <code>view=graph</code> parameter. There is currently no redirect when it is encountered, but there could be one in the future.</p>
<p>A <code>graph=1&amp;makeimage=1</code> parameter is treated like a
<code>view=graph</code> parameter. There is currently no redirect
when it is encountered, but there could be one in the future.</p>
<h3 id="compat-content_type">'<code>content_type=text/vnd.viewcvs-markup</code>' and '<code>content_type=text/x-cvsweb-markup</code>' Parameters&rArr; '<code>view=markup</code>'</h3>
<p><code>content_type=text/vnd.viewcvs-markup</code> and <code>content_type=text/x-cvsweb-markup</code> parameters are treated like a <code>view=markup</code> parameter. There is currently no redirect when it is encountered, but there could be one in the future.</p>
<p><code>content-type=text/vnd.viewcvs-markup</code> and
<code>content-type=text/x-cvsweb-markup</code> parameters are
treated like a <code>view=markup</code> parameter. There is
currently no redirect when it is encountered, but there could be
one in the future. Other values of the <code>content-type</code>
parameter, which were used to dictate the MIME type of files
displayed in the checkout/download view prior to ViewVC 1.0.6, are
ignored.</p>
<h3 id="compat-attic">'<code>Attic/FILE</code>' Paths &rArr; '<code>FILE</code>'</h3>
<p>When ViewVC encounters an invalid repository path whose last or second-to-last component is named <code>Attic</code>, and stripping the component yields a valid path, it will redirect to a URL with that path.</p>
<p>When ViewVC encounters an invalid repository path whose last or
second-to-last component is named <code>Attic</code>, and stripping
the component yields a valid path, it will redirect to a URL with
that path.</p>
</div>
</body>

View File

@@ -1,8 +0,0 @@
elx-java
j_keywords.c
j_keywords.h
j_scan.c
j_scan.h
java.c
java.h
*.output

View File

@@ -1,6 +0,0 @@
elx-python
py_keywords.c
py_keywords.h
python.c
python.h
*.output

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -15,7 +15,6 @@
# -----------------------------------------------------------------------
import re
import string
def language(hdr):
@@ -39,8 +38,8 @@ def _parse(hdr, result):
while pos < len(hdr):
name = _re_token.match(hdr, pos)
if not name:
raise AcceptParseError()
a = result.item_class(string.lower(name.group(1)))
raise AcceptLanguageParseError()
a = result.item_class(name.group(1).lower())
pos = name.end()
while 1:
# are we looking at a parameter?
@@ -56,7 +55,7 @@ def _parse(hdr, result):
# the "=" was probably missing
continue
pname = string.lower(match.group(1))
pname = match.group(1).lower()
if pname == 'q' or pname == 'qs':
try:
a.quality = float(match.group(2))
@@ -70,7 +69,7 @@ def _parse(hdr, result):
# bad float literal
pass
elif pname == 'charset':
a.charset = string.lower(match.group(2))
a.charset = match.group(2).lower()
result.append(a)
if hdr[pos:pos+1] == ',':
@@ -210,7 +209,7 @@ class _LanguageSelector:
def append(self, item):
self.requested.append(item)
class AcceptParseError(Exception):
class AcceptLanguageParseError(Exception):
pass
def _test():

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 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
@@ -26,15 +26,15 @@
#
# -----------------------------------------------------------------------
import string
import sys
import os
import re
import time
import math
import cgi
import vclib
import vclib.ccvs.blame
from common import _item
import vclib
import sapi
re_includes = re.compile('\\#(\\s*)include(\\s*)"(.*?)"')
@@ -42,25 +42,28 @@ def link_includes(text, repos, path_parts, include_url):
match = re_includes.match(text)
if match:
incfile = match.group(3)
include_path_parts = path_parts[:-1]
for part in filter(None, incfile.split('/')):
if part == "..":
if not include_path_parts:
# nothing left to pop; don't bother marking up this include.
return text
include_path_parts.pop()
elif part and part != ".":
include_path_parts.append(part)
# check current directory and parent directory for file
for depth in (-1, -2):
include_path = path_parts[:depth] + [incfile]
try:
# will throw if path doesn't exist
if repos.itemtype(include_path, None) == vclib.FILE:
break
except vclib.ItemNotFound:
pass
else:
include_path = None
include_path = None
try:
if repos.itemtype(include_path_parts, None) == vclib.FILE:
include_path = '/'.join(include_path_parts)
except vclib.ItemNotFound:
pass
if include_path:
url = string.replace(include_url, '/WHERE/',
string.join(include_path, '/'))
return '#%sinclude%s<a href="%s">"%s"</a>' % \
(match.group(1), match.group(2), url, incfile)
return '#%sinclude%s<a href="%s">"%s"</a>' % \
(match.group(1), match.group(2),
include_url.replace('/WHERE/', include_path), incfile)
return text
@@ -72,14 +75,15 @@ class HTMLBlameSource:
self.path_parts = path_parts
self.diff_url = diff_url
self.include_url = include_url
self.annotation, self.revision = self.repos.annotate(path_parts, opt_rev)
self.annotation, self.revision = self.repos.annotate(path_parts, opt_rev,
True)
def __getitem__(self, idx):
item = self.annotation.__getitem__(idx)
diff_url = None
if item.prev_rev:
diff_url = '%sr1=%s&amp;r2=%s' % (self.diff_url, item.prev_rev, item.rev)
thisline = link_includes(cgi.escape(item.text), self.repos,
thisline = link_includes(sapi.escape(item.text), self.repos,
self.path_parts, self.include_url)
return _item(text=thisline, line_number=item.line_number,
rev=item.rev, prev_rev=item.prev_rev,
@@ -91,79 +95,45 @@ def blame(repos, path_parts, diff_url, include_url, opt_rev=None):
return source, source.revision
class _item:
def __init__(self, **kw):
vars(self).update(kw)
def make_html(root, rcs_path):
import vclib.ccvs.blame
bs = vclib.ccvs.blame.BlameSource(os.path.join(root, rcs_path))
count = bs.num_lines
if count == 0:
count = 1
line_num_width = int(math.log10(count)) + 1
revision_width = 3
author_width = 5
line = 0
old_revision = 0
row_color = ''
inMark = 0
row_color = 'ffffff'
rev_count = 0
open_table_tag = '<table cellpadding="0" cellspacing="0">'
startOfRow = '<tr><td colspan="3"%s><pre>'
endOfRow = '</td></tr>'
print open_table_tag + (startOfRow % '')
align = ' style="text-align: %s;"'
sys.stdout.write('<table cellpadding="2" cellspacing="2" style="font-family: monospace; whitespace: pre;">\n')
for line_data in bs:
revision = line_data.rev
thisline = line_data.text
line = line_data.line_number
author = line_data.author
prev_rev = line_data.prev_rev
output = ''
if old_revision != revision and line != 1:
if row_color == '':
row_color = ' style="background-color:#e7e7e7"'
if row_color == 'ffffff':
row_color = 'e7e7e7'
else:
row_color = ''
row_color = 'ffffff'
if not inMark:
output = output + endOfRow + (startOfRow % row_color)
output = output + '<a name="%d">%*d</a>' % (line, line_num_width, line)
sys.stdout.write('<tr id="l%d" style="background-color: #%s; vertical-align: center;">' % (line, row_color))
sys.stdout.write('<td%s>%d</td>' % (align % 'right', line))
if old_revision != revision or rev_count > 20:
revision_width = max(revision_width, len(revision))
output = output + ' '
author_width = max(author_width, len(author))
output = output + ('%-*s ' % (author_width, author))
output = output + revision
if prev_rev:
output = output + '</a>'
output = output + (' ' * (revision_width - len(revision) + 1))
sys.stdout.write('<td%s>%s</td>' % (align % 'right', author or '&nbsp;'))
sys.stdout.write('<td%s>%s</td>' % (align % 'left', revision))
old_revision = revision
rev_count = 0
else:
output = output + ' ' + (' ' * (author_width + revision_width))
sys.stdout.write('<td>&nbsp;</td><td>&nbsp;</td>')
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>'
sys.stdout.write('<td%s>%s</td></tr>\n' % (align % 'left', thisline.rstrip() or '&nbsp;'))
sys.stdout.write('</table>\n')
def main():

60
lib/common.py Normal file
View File

@@ -0,0 +1,60 @@
# -*-python-*-
#
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
#
# common: common definitions for the viewvc library
#
# -----------------------------------------------------------------------
# Special type indicators for diff header processing and idiff return codes
_RCSDIFF_IS_BINARY = 'binary-diff'
_RCSDIFF_ERROR = 'error'
_RCSDIFF_NO_CHANGES = "no-changes"
class _item:
def __init__(self, **kw):
vars(self).update(kw)
class TemplateData:
"""A custom dictionary-like object that allows one-time definition
of keys, and only value fetches and changes, and key deletions,
thereafter.
EZT doesn't require the use of this special class -- a normal
dict-type data dictionary works fine. But use of this class will
assist those who want the data sent to their templates to have a
consistent set of keys."""
def __init__(self, initial_data={}):
self._items = initial_data
def __getitem__(self, key):
return self._items.__getitem__(key)
def __setitem__(self, key, item):
assert self._items.has_key(key)
return self._items.__setitem__(key, item)
def __delitem__(self, key):
return self._items.__delitem__(key)
def keys(self):
return self._items.keys()
def merge(self, template_data):
"""Merge the data in TemplataData instance TEMPLATA_DATA into this
instance. Avoid the temptation to use this conditionally in your
code -- it rather defeats the purpose of this class."""
assert isinstance(template_data, TemplateData)
self._items.update(template_data._items)

View File

@@ -1,166 +0,0 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
#
# compat.py: compatibility functions for operation across Python 1.5.x to 2.2.x
#
# -----------------------------------------------------------------------
import urllib
import string
import time
import calendar
import re
import os
import rfc822
import tempfile
import errno
#
# urllib.urlencode() is new to Python 1.5.2
#
try:
urlencode = urllib.urlencode
except AttributeError:
def urlencode(dict):
"Encode a dictionary as application/x-url-form-encoded."
if not dict:
return ''
quote = urllib.quote_plus
keyvalue = [ ]
for key, value in dict.items():
keyvalue.append(quote(key) + '=' + quote(str(value)))
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')[:-1] + (0,)
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.'
match = _re_rev_date.match(timestr)
if match:
return tuple(map(int, match.groups())) + (0, 1, 0)
else:
raise ValueError('date is not in cvs format')
#
# 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)
#
# rfc822.formatdate() is new to Python 1.6
#
try:
formatdate = rfc822.formatdate
except AttributeError:
def formatdate(timeval):
if timeval is None:
timeval = time.time()
timeval = time.gmtime(timeval)
return "%s, %02d %s %04d %02d:%02d:%02d GMT" % (
["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"][timeval[6]],
timeval[2],
["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][timeval[1]-1],
timeval[0], timeval[3], timeval[4], timeval[5])
#
# calendar.timegm() is new to Python 2.x and
# calendar.leapdays() was wrong in Python 1.5.2
#
try:
timegm = calendar.timegm
except AttributeError:
def leapdays(year1, year2):
"""Return number of leap years in range [year1, year2).
Assume year1 <= year2."""
year1 = year1 - 1
year2 = year2 - 1
return (year2/4 - year1/4) - (year2/100 -
year1/100) + (year2/400 - year1/400)
EPOCH = 1970
def timegm(tuple):
"""Unrelated but handy function to calculate Unix timestamp from GMT."""
year, month, day, hour, minute, second = tuple[:6]
# assert year >= EPOCH
# assert 1 <= month <= 12
days = 365*(year-EPOCH) + leapdays(EPOCH, year)
for i in range(1, month):
days = days + calendar.mdays[i]
if month > 2 and calendar.isleap(year):
days = days + 1
days = days + day - 1
hours = days*24 + hour
minutes = hours*60 + minute
seconds = minutes*60 + second
return seconds
#
# tempfile.mkdtemp() is new to Python 2.3
#
try:
mkdtemp = tempfile.mkdtemp
except AttributeError:
def mkdtemp():
for i in range(10):
dir = tempfile.mktemp()
try:
os.mkdir(dir, 0700)
return dir
except OSError, e:
if e.errno == errno.EEXIST:
continue # try again
raise
raise IOError, (errno.EEXIST, "No usable temporary directory name found")
#
# the following stuff is *ONLY* needed for standalone.py.
# For that reason I've encapsulated it into a function.
#
def for_standalone():
import SocketServer
if not hasattr(SocketServer.TCPServer, "close_request"):
#
# method close_request() was missing until Python 2.1
#
class TCPServer(SocketServer.TCPServer):
def process_request(self, request, client_address):
"""Call finish_request.
Overridden by ForkingMixIn and ThreadingMixIn.
"""
self.finish_request(request, client_address)
self.close_request(request)
def close_request(self, request):
"""Called to clean up an individual request."""
request.close()
SocketServer.TCPServer = TCPServer

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -16,64 +16,179 @@
import sys
import os
import string
import ConfigParser
import fnmatch
import vclib
import vclib.ccvs
import vclib.svn
import cvsdb
import viewvc
import copy
from viewvcmagic import ContentMagic
#########################################################################
#
# CONFIGURATION
# -------------
#
# There are three forms of configuration:
#
# 1) edit the viewvc.conf created by the viewvc-install(er)
# 2) as (1), but delete all unchanged entries from viewvc.conf
# 3) do not use viewvc.conf and just edit the defaults in this file
# 1. edit the viewvc.conf created by the viewvc-install(er)
# 2. as (1), but delete all unchanged entries from viewvc.conf
# 3. do not use viewvc.conf and just edit the defaults in this file
#
# Most users will want to use (1), but there are slight speed advantages
# to the other two options. Note that viewvc.conf values are a bit easier
# to work with since it is raw text, rather than python literal values.
#
#
# A WORD ABOUT OPTION LAYERING/OVERRIDES
# --------------------------------------
#
# ViewVC has three "layers" of configuration options:
#
# 1. base configuration options - very basic configuration bits
# found in sections like 'general', 'options', etc.
# 2. vhost overrides - these options overlay/override the base
# configuration on a per-vhost basis.
# 3. root overrides - these options overlay/override the base
# configuration and vhost overrides on a per-root basis.
#
# Here's a diagram of the valid overlays/overrides:
#
# PER-ROOT PER-VHOST BASE
#
# ,-----------. ,-----------.
# | vhost-*/ | | |
# | general | --> | general |
# | | | |
# `-----------' `-----------'
# ,-----------. ,-----------. ,-----------.
# | root-*/ | | vhost-*/ | | |
# | options | --> | options | --> | options |
# | | | | | |
# `-----------' `-----------' `-----------'
# ,-----------. ,-----------. ,-----------.
# | root-*/ | | vhost-*/ | | |
# | templates | --> | templates | --> | templates |
# | | | | | |
# `-----------' `-----------' `-----------'
# ,-----------. ,-----------. ,-----------.
# | root-*/ | | vhost-*/ | | |
# | utilities | --> | utilities | --> | utilities |
# | | | | | |
# `-----------' `-----------' `-----------'
# ,-----------. ,-----------.
# | vhost-*/ | | |
# | cvsdb | --> | cvsdb |
# | | | |
# `-----------' `-----------'
# ,-----------. ,-----------. ,-----------.
# | root-*/ | | vhost-*/ | | |
# | authz-* | --> | authz-* | --> | authz-* |
# | | | | | |
# `-----------' `-----------' `-----------'
# ,-----------.
# | |
# | vhosts |
# | |
# `-----------'
# ,-----------.
# | |
# | query |
# | |
# `-----------'
#
# ### TODO: Figure out what this all means for the 'kv' stuff.
#
#########################################################################
class Config:
_sections = ('general', 'options', 'cvsdb', 'templates')
_force_multi_value = ('cvs_roots', 'forbidden',
'svn_roots', 'languages', 'kv_files',
'root_parents')
_base_sections = (
# Base configuration sections.
'authz-*',
'cvsdb',
'general',
'options',
'query',
'templates',
'utilities',
)
_force_multi_value = (
# Configuration values with multiple, comma-separated values.
'allowed_views',
'binary_mime_types',
'custom_log_formatting',
'cvs_roots',
'kv_files',
'languages',
'mime_types_files',
'root_parents',
'svn_roots',
)
_allowed_overrides = {
# Mapping of override types to allowed overridable sections.
'vhost' : ('authz-*',
'cvsdb',
'general',
'options',
'templates',
'utilities',
),
'root' : ('authz-*',
'options',
'templates',
'utilities',
)
}
def __init__(self):
for section in self._sections:
self.__guesser = None
self.__root_configs = {}
self.__parent = None
self.root_options_overlayed = 0
for section in self._base_sections:
if section[-1] == '*':
continue
setattr(self, section, _sub_config())
def load_config(self, pathname, vhost=None):
"""Load the configuration file at PATHNAME, applying configuration
settings there as overrides to the built-in default values. If
VHOST is provided, also process the configuration overrides
specific to that virtual host."""
self.conf_path = os.path.isfile(pathname) and pathname or None
self.base = os.path.dirname(pathname)
self.parser = ConfigParser.ConfigParser()
self.parser.optionxform = lambda x: x # don't case-normalize option names.
self.parser.read(self.conf_path or [])
for section in self.parser.sections():
if self._is_allowed_section(section, self._base_sections):
self._process_section(self.parser, section, section)
parser = ConfigParser.ConfigParser()
parser.read(pathname)
for section in self._sections:
if parser.has_section(section):
self._process_section(parser, section, section)
if vhost and parser.has_section('vhosts'):
self._process_vhost(parser, vhost)
if vhost and self.parser.has_section('vhosts'):
self._process_vhost(self.parser, vhost)
def load_kv_files(self, language):
"""Process the key/value (kv) files specified in the
configuration, merging their values into the configuration as
dotted heirarchical items."""
kv = _sub_config()
for fname in self.general.kv_files:
if fname[0] == '[':
idx = string.index(fname, ']')
parts = string.split(fname[1:idx], '.')
fname = string.strip(fname[idx+1:])
idx = fname.index(']')
parts = fname[1:idx].split('.')
fname = fname[idx+1:].strip()
else:
parts = [ ]
fname = string.replace(fname, '%lang%', language)
fname = fname.replace('%lang%', language)
parser = ConfigParser.ConfigParser()
parser.optionxform = lambda x: x # don't case-normalize option names.
parser.read(os.path.join(self.base, fname))
for section in parser.sections():
for option in parser.options(section):
@@ -90,51 +205,169 @@ class Config:
return kv
def path(self, path):
"""Return PATH relative to the config file directory."""
return os.path.join(self.base, path)
def _process_section(self, parser, section, subcfg_name):
if not hasattr(self, subcfg_name):
setattr(self, subcfg_name, _sub_config())
sc = getattr(self, subcfg_name)
for opt in parser.options(section):
value = parser.get(section, opt)
if opt in self._force_multi_value:
value = map(string.strip, filter(None, string.split(value, ',')))
value = map(lambda x: x.strip(), filter(None, value.split(',')))
else:
try:
value = int(value)
except ValueError:
pass
### FIXME: This feels like unnecessary depth of knowledge for a
### semi-generic configuration object.
if opt == 'cvs_roots' or opt == 'svn_roots':
value = _parse_roots(opt, value)
setattr(sc, opt, value)
def _is_allowed_section(self, section, allowed_sections):
"""Return 1 iff SECTION is an allowed section, defined as being
explicitly present in the ALLOWED_SECTIONS list or present in the
form 'someprefix-*' in that list."""
for allowed_section in allowed_sections:
if allowed_section[-1] == '*':
if _startswith(section, allowed_section[:-1]):
return 1
elif allowed_section == section:
return 1
return 0
def _is_allowed_override(self, sectype, secspec, section):
"""Test if SECTION is an allowed override section for sections of
type SECTYPE ('vhosts' or 'root', currently) and type-specifier
SECSPEC (a rootname or vhostname, currently). If it is, return
the overridden base section name. If it's not an override section
at all, return None. And if it's an override section but not an
allowed one, raise IllegalOverrideSection."""
cv = '%s-%s/' % (sectype, secspec)
lcv = len(cv)
if section[:lcv] != cv:
return None
base_section = section[lcv:]
if self._is_allowed_section(base_section,
self._allowed_overrides[sectype]):
return base_section
raise IllegalOverrideSection(sectype, section)
def _process_vhost(self, parser, vhost):
# Find a vhost name for this VHOST, if any (else, we've nothing to do).
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)
# Overlay any option sections associated with this vhost name.
for section in parser.sections():
if section[:lcv] == cv:
self._process_section(parser, section, section[lcv:])
base_section = self._is_allowed_override('vhost', canon_vhost, section)
if base_section:
self._process_section(parser, section, base_section)
def _find_canon_vhost(self, parser, vhost):
vhost = string.lower(vhost)
# Strip (ignore) port number:
vhost = string.split(vhost, ':')[0]
vhost = vhost.lower().split(':')[0] # lower-case, no port
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, ','))))
patterns = map(lambda x: x.lower().strip(),
filter(None, value.split(',')))
for pat in patterns:
if fnmatch.fnmatchcase(vhost, pat):
return canon_vhost
return None
def get_root_config(self, rootname):
"""Get configuration object with per-root overrides for 'rootname'"""
if self.__parent:
return self.__parent.get_root_config(rootname)
elif rootname in self.__root_configs:
return self.__root_configs[rootname]
__guesser = self.__guesser
__root_configs = self.__root_configs
parser = self.parser
self.parser = None
self.__guesser = None
self.__root_configs = None
sub = copy.deepcopy(self)
sub.parser = parser
self.parser = parser
self.__guesser = __guesser
self.__root_configs = __root_configs
self.__root_configs[rootname] = sub
sub.__parent = self
sub.overlay_root_options(rootname)
return sub
def get_parent_config(self):
"""Get the parent non-overridden config."""
if self.__parent:
return self.__parent
return self
def overlay_root_options(self, rootname):
"""Overlay per-root options for ROOTNAME atop the existing option
set. This is a destructive change to the configuration."""
did_overlay = 0
if not self.conf_path:
return
for section in self.parser.sections():
base_section = self._is_allowed_override('root', rootname, section)
if base_section:
# We can currently only deal with root overlays happening
# once, so check that we've not yet done any overlaying of
# per-root options.
assert(self.root_options_overlayed == 0)
self._process_section(self.parser, section, base_section)
did_overlay = 1
# If we actually did any overlaying, remember this fact so we
# don't do it again later.
if did_overlay:
self.root_options_overlayed = 1
def _get_parser_items(self, parser, section):
"""Basically implement ConfigParser.items() for pre-Python-2.3 versions."""
try:
return self.parser.items(section)
except AttributeError:
d = {}
for option in parser.options(section):
d[option] = parser.get(section, option)
return d.items()
def get_authorizer_params(self, authorizer=None):
"""Return a dictionary of parameter names and values which belong
to the configured authorizer (or AUTHORIZER, if provided)."""
params = {}
if authorizer is None:
authorizer = self.options.authorizer
if authorizer:
authz_section = 'authz-%s' % (self.options.authorizer)
if hasattr(self, authz_section):
sub_config = getattr(self, authz_section)
for attr in dir(sub_config):
params[attr] = getattr(sub_config, attr)
params['__config'] = self
return params
def guesser(self):
if not self.__guesser:
self.__guesser = ContentMagic(self.options.encodings)
return self.__guesser
def set_defaults(self):
"Set some default values in the configuration."
@@ -142,112 +375,141 @@ class Config:
self.general.svn_roots = { }
self.general.root_parents = []
self.general.default_root = ''
self.general.rcs_path = ''
if sys.platform == "win32":
self.general.cvsnt_exe_path = 'cvs'
else:
self.general.cvsnt_exe_path = None
self.general.use_rcsparse = 0
self.general.svn_path = ''
self.general.mime_types_file = ''
self.general.address = '<a href="mailto:user@insert.your.domain.here">No admin address has been configured</a>'
self.general.forbidden = ()
self.general.mime_types_files = ["mimetypes.conf"]
self.general.address = ''
self.general.kv_files = [ ]
self.general.languages = ['en-us']
self.templates.directory = None
self.templates.log = None
self.templates.query = None
self.templates.diff = None
self.templates.graph = None
self.templates.annotate = None
self.templates.markup = None
self.templates.error = None
self.templates.query_form = None
self.templates.query_results = None
self.templates.roots = None
self.utilities.rcs_dir = ''
if sys.platform == "win32":
self.utilities.cvsnt = 'cvs'
else:
self.utilities.cvsnt = None
self.utilities.rcsfile_socket = ''
self.utilities.svn = ''
self.utilities.diff = ''
self.utilities.cvsgraph = ''
self.utilities.tika_server = ''
self.utilities.tika_mime_types = ''
self.cvsdb.enabled = 0
self.cvsdb.host = ''
self.cvsdb.port = 3306
self.cvsdb.database_name = ''
self.cvsdb.user = ''
self.cvsdb.passwd = ''
self.cvsdb.readonly_user = ''
self.cvsdb.readonly_passwd = ''
self.cvsdb.row_limit = 1000
self.cvsdb.rss_row_limit = 100
self.options.root_as_url_component = 0
self.options.default_file_view = "log"
self.options.root_as_url_component = 1
self.options.checkout_magic = 0
self.options.allowed_views = ['annotate', 'diff', 'markup', 'roots']
self.options.authorizer = None
self.options.mangle_email_addresses = 0
self.options.custom_log_formatting = []
self.options.default_file_view = "log"
self.options.binary_mime_types = []
self.options.http_expiration_time = 600
self.options.generate_etags = 1
self.options.svn_ignore_mimetype = 0
self.options.svn_config_dir = None
self.options.max_filesize_kbytes = 512
self.options.use_rcsparse = 0
self.options.sort_by = 'file'
self.options.sort_group_dirs = 1
self.options.hide_attic = 1
self.options.hide_errorful_entries = 0
self.options.log_sort = 'date'
self.options.diff_format = 'h'
self.options.hide_cvsroot = 1
self.options.hr_breakable = 1
self.options.hr_funout = 1
self.options.hr_ignore_white = 1
self.options.hr_ignore_white = 0
self.options.hr_ignore_keyword_subst = 1
self.options.hr_intraline = 0
self.options.allow_annotate = 1
self.options.allow_markup = 1
self.options.allow_compress = 1
self.options.template_dir = "templates"
self.options.allow_compress = 0
self.options.template_dir = "templates/default"
self.options.docroot = None
self.options.show_subdir_lastmod = 0
self.options.show_roots_lastmod = 0
self.options.show_logs = 1
self.options.show_log_in_markup = 1
self.options.cross_copies = 0
self.options.py2html_path = '.'
self.options.short_log_len = 80
self.options.use_enscript = 0
self.options.enscript_path = ''
self.options.use_highlight = 0
self.options.highlight_path = ''
self.options.highlight_line_numbers = 1
self.options.highlight_convert_tabs = 2
self.options.use_php = 0
self.options.php_exe_path = 'php'
self.options.allow_tar = 0
self.options.use_cvsgraph = 0
self.options.cvsgraph_path = ''
self.options.cvsgraph_conf = "cvsgraph.conf"
self.options.use_re_search = 0
self.options.use_pagesize = 0
self.options.limit_changes = 100
self.options.cross_copies = 1
self.options.use_localtime = 0
self.options.http_expiration_time = 600
self.options.generate_etags = 1
self.options.iso8601_timestamps = 0
self.options.short_log_len = 80
self.options.enable_syntax_coloration = 1
self.options.tabsize = 8
self.options.detect_encoding = 0
self.options.use_cvsgraph = 0
self.options.cvsgraph_conf = "cvsgraph.conf"
self.options.allowed_cvsgraph_useropts = []
self.options.use_re_search = 0
self.options.dir_pagesize = 0
self.options.log_pagesize = 0
self.options.log_pagesextra = 3
self.options.limit_changes = 100
self.options.cvs_ondisk_charset = 'cp1251'
self.options.encodings = 'cp1251:iso-8859-1'
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
self.templates.diff = None
self.templates.directory = None
self.templates.error = None
self.templates.file = None
self.templates.graph = None
self.templates.log = None
self.templates.query = None
self.templates.query_form = None
self.templates.query_results = None
self.templates.roots = None
self.cvsdb.enabled = 0
self.cvsdb.index_content = 0
self.cvsdb.enable_snippets = 1
self.cvsdb.content_max_size = 0
self.cvsdb.host = ''
self.cvsdb.port = 3306
self.cvsdb.socket = ''
self.cvsdb.database_name = ''
self.cvsdb.user = ''
self.cvsdb.passwd = ''
self.cvsdb.readonly_user = ''
self.cvsdb.readonly_passwd = ''
self.cvsdb.row_limit = 1000
self.cvsdb.rss_row_limit = 100
self.cvsdb.check_database_for_root = 0
self.cvsdb.fulltext_min_relevance = 0.2
self.cvsdb.sphinx_host = ''
self.cvsdb.sphinx_port = 3307
self.cvsdb.sphinx_socket = ''
self.cvsdb.sphinx_index = ''
self.cvsdb.sphinx_preformatted_mime = 'text/(?!html|xml).*'
self.cvsdb.sphinx_snippet_options = \
'around: 15\n'\
'limit: 200\n'\
'before_match: <span style="color:red">\n'\
'after_match: </span>\n'\
'chunk_separator: ... \n\n'
self.query.viewvc_base_url = None
def _startswith(somestr, substr):
return somestr[:len(substr)] == substr
def _parse_roots(config_name, config_value):
roots = { }
for root in config_value:
pos = string.find(root, ':')
if pos < 0:
try:
name, path = root.split(':', 1)
except:
raise MalformedRoot(config_name, root)
name, path = map(string.strip, (root[:pos], root[pos+1:]))
roots[name] = path
roots[name.strip()] = path.strip()
return roots
class ViewVCConfigurationError(Exception):
pass
class MalformedRoot(Exception):
class IllegalOverrideSection(ViewVCConfigurationError):
def __init__(self, override_type, section_name):
self.section_name = section_name
self.override_type = override_type
def __str__(self):
return "malformed configuration: illegal %s override section: %s" \
% (self.override_type, self.section_name)
class MalformedRoot(ViewVCConfigurationError):
def __init__(self, config_name, value_given):
Exception.__init__(self, config_name, value_given)
self.config_name = config_name
@@ -259,10 +521,3 @@ class MalformedRoot(Exception):
class _sub_config:
pass
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
+ ']*=\)\(.*\)$')

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -14,7 +14,7 @@ import sys
import time
import types
import re
import compat
import calendar
import MySQLdb
# set to 1 to store commit times in UTC, or 0 to use the ViewVC machine's
@@ -55,9 +55,17 @@ def TicksFromDateTime(datetime):
t = datetime.tuple()
if utc_time:
return compat.timegm(t)
return calendar.timegm(t)
else:
return time.mktime(t[:8] + (-1,))
def connect(host, port, user, passwd, db):
return MySQLdb.connect(host=host, port=port, user=user, passwd=passwd, db=db)
def connect(host, port, socket, user, passwd, db, charset = 'utf8'):
return MySQLdb.connect(
host = host,
port = port,
unix_socket = socket,
user = user,
passwd = passwd,
db = db,
charset = charset,
use_unicode = charset == 'utf8')

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -17,10 +17,20 @@
import sys
# Set to non-zero to track and print processing times
SHOW_TIMES = 0
# Set to non-zero to display child process info
SHOW_CHILD_PROCESSES = 0
# Set to a server-side path to force the tarball view to generate the
# tarball as a file on the server, instead of transmitting the data
# back to the browser. This enables easy display of error
# considitions in the browser, as well as tarball inspection on the
# server. NOTE: The file will be a TAR archive, *not* gzip-compressed.
TARFILE_PATH = ''
if SHOW_TIMES:
import time
@@ -38,13 +48,17 @@ if SHOW_TIMES:
else:
_times[which] = t
def dump():
for name, value in _times.items():
print '%s: %.6f<br />' % (name, value)
def t_dump(out):
out.write('<div>')
names = _times.keys()
names.sort()
for name in names:
out.write('%s: %.6fs<br/>\n' % (name, _times[name]))
out.write('</div>')
else:
t_start = t_end = dump = lambda *args: None
t_start = t_end = t_dump = lambda *args: None
class ViewVCException:

View File

@@ -189,9 +189,10 @@ Directives
templates are escaped before they are put into the output stream. It
has no effect on the literal text of the templates, only the output
from [QUAL_NAME ...] directives. STRING can be one of "raw" "html"
or "xml". The "raw" mode leaves the output unaltered. The "html" and
"xml" modes escape special characters using entity escapes (like
&quot; and &gt;)
"xml" or "uri". The "raw" mode leaves the output unaltered; the "html"
and "xml" modes escape special characters using entity escapes (like
&quot; and &gt;); the "uri" mode escapes characters using hexadecimal
escape sequences (like %20 and %7e).
[format CALLBACK]
@@ -200,7 +201,7 @@ Directives
equivalent to "[CALLBACK QUAL_NAME]"
"""
#
# Copyright (C) 2001-2005 Greg Stein. All Rights Reserved.
# Copyright (C) 2001-2007 Greg Stein. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -235,6 +236,7 @@ import re
from types import StringType, IntType, FloatType, LongType, TupleType
import os
import cgi
import urllib
try:
import cStringIO
except ImportError:
@@ -247,6 +249,7 @@ except ImportError:
FORMAT_RAW = 'raw'
FORMAT_HTML = 'html'
FORMAT_XML = 'xml'
FORMAT_URI = 'uri'
#
# This regular expression matches three alternatives:
@@ -344,7 +347,7 @@ class Template:
for_names = [ ]
if base_format:
program.append((self._cmd_format, _printers[base_format]))
program.append((self._cmd_format, _formatters[base_format]))
for i in range(len(parts)):
piece = parts[i]
@@ -402,13 +405,13 @@ class Template:
elif cmd == 'format':
if args[1][0]:
# argument is a variable reference
printer = args[1]
formatter = args[1]
else:
# argument is a string constant referring to built-in printer
printer = _printers.get(args[1][1])
if not printer:
# argument is a string constant referring to built-in formatter
formatter = _formatters.get(args[1][1])
if not formatter:
raise UnknownFormatConstantError(str(args[1:]))
program.append((self._cmd_format, printer))
program.append((self._cmd_format, formatter))
# remember the cmd, current pos, args, and a section placeholder
stack.append([cmd, len(program), args[1:], None])
@@ -457,15 +460,18 @@ class Template:
def _cmd_print(self, valrefs, ctx):
value = _get_value(valrefs[0], ctx)
args = map(lambda valref, ctx=ctx: _get_value(valref, ctx), valrefs[1:])
_write_value(value, args, ctx)
try:
_write_value(value, args, ctx)
except TypeError:
raise Exception("Unprintable value type for '%s'" % (str(valrefs[0][0])))
def _cmd_format(self, printer, ctx):
if type(printer) is TupleType:
printer = _get_value(printer, ctx)
ctx.printers.append(printer)
def _cmd_format(self, formatter, ctx):
if type(formatter) is TupleType:
formatter = _get_value(formatter, ctx)
ctx.formatters.append(formatter)
def _cmd_end_format(self, valref, ctx):
ctx.printers.pop()
ctx.formatters.pop()
def _cmd_include(self, (valref, reader), ctx):
fname = _get_value(valref, ctx)
@@ -519,7 +525,8 @@ class Template:
((valref,), unused, section) = args
list = _get_value(valref, ctx)
if isinstance(list, StringType):
raise NeedSequenceError()
raise NeedSequenceError("The value of '%s' is not a sequence"
% (valref[0]))
refname = valref[0]
ctx.for_iterators[refname] = iterator = _iter(list)
for unused in iterator:
@@ -630,14 +637,23 @@ def _get_value((refname, start, rest), ctx):
# string or a sequence
return ob
def _print_formatted(formatters, ctx, chunk):
# print chunk to ctx.fp after running it sequentially through formatters
for formatter in formatters:
chunk = formatter(chunk)
ctx.fp.write(chunk)
def _write_value(value, args, ctx):
# value is a callback function, generates its own output
if callable(value):
apply(value, [ctx] + list(args))
return
# pop printer in case it recursively calls _write_value
printer = ctx.printers.pop()
# squirrel away formatters in case one of them recursively calls
# _write_value() -- we'll use them (in reverse order) to format our
# output.
formatters = ctx.formatters[:]
formatters.reverse()
try:
# if the value has a 'read' attribute, then it is a stream: copy it
@@ -646,7 +662,7 @@ def _write_value(value, args, ctx):
chunk = value.read(16384)
if not chunk:
break
printer(ctx, chunk)
_print_formatted(formatters, ctx, chunk)
# value is a substitution pattern
elif args:
@@ -659,21 +675,23 @@ def _write_value(value, args, ctx):
piece = args[idx]
else:
piece = '<undef>'
printer(ctx, piece)
_print_formatted(formatters, ctx, piece)
# plain old value, write to output
else:
printer(ctx, value)
_print_formatted(formatters, ctx, value)
finally:
ctx.printers.append(printer)
# restore our formatters
formatters.reverse()
ctx.formatters = formatters
class Context:
"""A container for the execution context"""
def __init__(self, fp):
self.fp = fp
self.printers = []
self.formatters = []
def write(self, value, args=()):
_write_value(value, args, self)
@@ -786,16 +804,34 @@ class BaseUnavailableError(EZTException):
class UnknownFormatConstantError(EZTException):
"""The format specifier is an unknown value."""
def _raw_printer(ctx, s):
ctx.fp.write(s)
def _html_printer(ctx, s):
ctx.fp.write(cgi.escape(s))
def _raw_formatter(s):
try: s = s.encode('utf-8')
except: pass
return s
_printers = {
FORMAT_RAW : _raw_printer,
FORMAT_HTML : _html_printer,
FORMAT_XML : _html_printer,
def _html_formatter(s):
try: s = s.encode('utf-8')
except: pass
return cgi.escape(s)
def _xml_formatter(s):
try: s = s.encode('utf-8')
except: pass
s = s.replace('&', '&#x26;')
s = s.replace('<', '&#x3C;')
s = s.replace('>', '&#x3E;')
return s
def _uri_formatter(s):
try: s = s.encode('utf-8')
except: pass
return urllib.quote(s)
_formatters = {
FORMAT_RAW : _raw_formatter,
FORMAT_HTML : _html_formatter,
FORMAT_XML : _xml_formatter,
FORMAT_URI : _uri_formatter,
}
# --- standard test environment ---
@@ -813,7 +849,7 @@ def test_parse():
['', '["a \\"b[foo]" c.d f]', None, '']
def _test(argv):
import doctest, ezt
import doctest, ezt
verbose = "-v" in argv
return doctest.testmod(ezt, verbose=verbose)

283
lib/globalauth.py Normal file
View File

@@ -0,0 +1,283 @@
# -*-python-*-
# -----------------------------------------------------------------------
# Simple Global Authentication client for ViewVC
# License: GPLv2+
# Author: Vitaliy Filippov
# -----------------------------------------------------------------------
#
# USAGE:
#
# import globalauth
# c = globalauth.GlobalAuthClient()
# c.auth(server)
# user_name = c.user_name
# user_url = c.user_url
#
# auth() will call sys.exit() when it needs to stop request processing
#
# -----------------------------------------------------------------------
import os
import re
import sys
import struct
import cgi
import binascii
import time
import datetime
import urllib
import urllib2
import anyjson
import random
import Cookie
import ga_config
class FileCache:
def __init__(self, dir):
self.dir = dir
if not os.path.isdir(dir):
os.mkdir(dir)
def fn(self, key):
key = re.sub('([^a-zA-Z0-9_\-]+)', lambda x: binascii.hexlify(x.group(1)), key)
return self.dir+'/'+key
def clean(self):
t = time.time()
for fn in os.listdir(self.dir):
if t > os.stat(self.dir+'/'+fn).st_mtime:
os.unlink(self.dir+'/'+fn)
def set(self, key, value, expire = 86400):
fn = self.fn(key)
try:
f = open(fn,'w')
if not expire:
expire = 86400
expire = time.time()+expire
f.write(value)
f.close()
os.chmod(fn, 0600)
os.utime(fn, (expire, expire))
except:
raise
return 1
def get(self, key):
fn = self.fn(key)
try:
f = open(fn,'r')
value = f.read()
f.close()
if time.time() > os.stat(fn).st_mtime:
os.unlink(fn)
return ''
return value
except:
pass
return ''
def delete(self, key):
fn = self.fn(key)
try:
os.unlink(fn)
except:
pass
class GlobalAuthClient:
wd = { 0 : 'Mon', 1 : 'Tue', 2 : 'Wed', 3 : 'Thu', 4 : 'Fri', 5 : 'Sat', 6 : 'Sun' }
ms = { 1 : 'Jan', 2 : 'Feb', 3 : 'Mar', 4 : 'Apr', 5 : 'May', 6 : 'Jun', 7 : 'Jul', 8 : 'Aug', 9 : 'Sep', 10 : 'Oct', 11 : 'Nov', 12 : 'Dec' }
def __init__(self, server):
self.server = server
self.v = {}
for name, values in server.params().items():
self.v[name] = values[0]
fs = server.FieldStorage()
for name in fs:
self.v[name] = fs[name].value
self.cookies = Cookie.SimpleCookie()
# '' default value is needed here - else we die here under WSGI without any exception O_o
self.cookies.load(self.server.getenv('HTTP_COOKIE', ''))
self.user_name = ''
self.user_url = ''
if not ga_config.gac.get('globalauth_server', '') and not ga_config.gac.get('fof_sudo_server', ''):
raise Exception('ga_config.gac must contain at least globalauth_server="URL" or fof_sudo_server="URL"')
self.gac = {
'cookie_name' : 'simple_global_auth',
'cookie_expire' : 86400*7,
'cookie_path' : '/',
'cookie_domain' : '',
'globalauth_server' : '',
'cache_dir' : os.path.abspath(os.path.dirname(__file__))+'/cache',
'cut_email_at' : 0,
'ga_always_require' : 0,
'fof_sudo_server' : '',
'fof_sudo_cookie' : 'fof_sudo_id',
'gc_probability' : 20,
}
for i in self.gac:
if ga_config.gac.get(i, None) is not None:
self.gac[i] = ga_config.gac[i]
self.cache = FileCache(self.gac['cache_dir'])
def auth(self):
if self.gac['fof_sudo_server']:
self.auth_fof_sudo()
if not self.user_name and self.gac['globalauth_server']:
self.auth_ga()
def auth_ga(self):
i = random.randint(1, self.gac['gc_probability'])
if i == 1:
self.cache.clean()
r_id = self.cookies.get(self.gac['cookie_name'], '')
if r_id:
r_id = r_id.value
ga_id = self.v.get('ga_id', '')
if self.v.get('ga_client', ''):
self.ga_client(r_id, ga_id)
return
r_data = ''
if r_id == 'nologin':
r_data = 'nologin'
elif r_id != '':
r_data = self.cache.get('D'+r_id)
if r_data != 'nologin':
try: r_data = anyjson.deserialize(r_data)
except: r_data = ''
is_browser = re.match('opera|firefox|chrome|safari', self.server.getenv('HTTP_USER_AGENT'), re.I)
if not r_data and (is_browser or self.gac['ga_always_require']) or self.v.get('ga_require', None):
self.ga_begin()
elif r_data and r_data != 'nologin':
self.set_user(r_data)
def ga_client(self, r_id, ga_id):
ga_key = self.v.get('ga_key', '')
if ga_key and ga_key == self.cache.get('K'+ga_id):
# Server-to-server request
self.cache.delete('K'+ga_id)
data = ''
if self.v.get('ga_nologin','') != '':
data = 'nologin'
else:
try: data = anyjson.deserialize(self.v.get('ga_data',''))
except: raise
if data != '':
if data != 'nologin':
data = anyjson.serialize(data)
self.cache.set('D'+ga_id, data)
self.server.header('text/plain')
self.server.write('1')
sys.exit()
elif ga_key == '' and r_id != ga_id:
# User redirect with different key
d = self.cache.get('D'+ga_id)
if d != 'nologin' and d != '':
try: d = anyjson.deserialize(d)
except: d = ''
if d != '':
self.setcookie(ga_id)
self.redirect(self.clean_uri())
self.server.header('text/plain', status=404)
self.server.write('GlobalAuth key doesn\'t match')
sys.exit()
def ga_begin(self):
ga_id = binascii.hexlify(os.urandom(16))
ga_key = binascii.hexlify(os.urandom(16))
url = self.add_param(self.gac['globalauth_server'], '')
try:
resp = urllib2.urlopen(url+'ga_id='+urllib2.quote(ga_id)+'&ga_key='+urllib2.quote(ga_key))
resp.read()
if resp.code != 200:
raise Exception(resp)
except:
self.setcookie('nologin')
self.redirect(self.clean_uri())
return_uri = 'http://'+self.server.getenv('HTTP_HOST')+self.server.getenv('REQUEST_URI')
return_uri = self.add_param(return_uri, 'ga_client=1')
self.cache.set('K'+ga_id, ga_key)
url = url+'ga_id='+urllib2.quote(ga_id)+'&ga_url='+urllib2.quote(return_uri)
if self.v.get('ga_require', '') == '' and not self.gac['ga_always_require']:
url = url+'&ga_check=1'
self.redirect(url)
def add_param(self, url, param):
if url.find('?') != -1:
url = url+'&'
else:
url = url+'?'
return url+param
def auth_fof_sudo(self):
sudo_id = self.cookies.get(self.gac['fof_sudo_cookie'], '')
if sudo_id:
sudo_id = sudo_id.value
if sudo_id != '':
url = self.gac['fof_sudo_server']
if url.find('?') != -1:
url = url+'&'
else:
url = url+'?'
try:
resp = urllib2.urlopen(url+'id='+urllib2.quote(sudo_id))
d = resp.read()
if resp.code != 200:
raise Exception(resp)
d = anyjson.deserialize(d)
self.set_user(d)
except:
pass
def log(self, s):
sys.stderr.write(s+"\n")
sys.stderr.flush()
def redirect(self, url):
self.server.addheader('Location', url)
self.server.header(status='302 Moved Temporarily')
self.server.write('This document is located <a href="%s">here</a>.' % url)
sys.exit()
def setcookie(self, value):
dom = self.gac['cookie_domain']
if not dom:
dom = self.server.getenv('HTTP_HOST')
exp = ''
if self.gac['cookie_expire'] > 0:
tm = int(time.time()+self.gac['cookie_expire'])
tm = datetime.datetime.utcfromtimestamp(tm)
tm = "%s, %02d-%s-%04d %02d:%02d:%02d GMT" % (self.wd[tm.weekday()], tm.day, self.ms[tm.month], tm.year, tm.hour, tm.minute, tm.second)
exp = '; expires='+tm
self.server.addheader('Set-Cookie', "%s=%s; path=%s; domain=%s%s" % (self.gac['cookie_name'], value, self.gac['cookie_path'], dom, exp))
def clean_uri(self):
uriargs = self.v.copy()
for i in [ 'ga_id', 'ga_res', 'ga_key', 'ga_client', 'ga_nologin', 'ga_require' ]:
uriargs.pop(i, None)
uri = self.server.getenv('REQUEST_URI')
p = uri.find('?')
if p != -1:
uri = uri[0:p]
uri = 'http://'+self.server.getenv('HTTP_HOST')+uri+'?'+urllib.urlencode(uriargs)
return uri
def set_user(self, r_data):
r_email = r_data.get('user_email', '').encode('utf-8')
r_url = r_data.get('user_url', '').encode('utf-8')
if self.gac['cut_email_at']:
p = r_email.find('@')
if p != -1:
r_email = r_email[0:p]
self.user_name = r_email
self.user_url = r_url

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -19,8 +19,10 @@ from __future__ import generators
import difflib
import sys
import re
from common import _item, _RCSDIFF_NO_CHANGES
import ezt
import cgi
import sapi
def sidebyside(fromlines, tolines, context):
"""Generate side by side diff"""
@@ -29,6 +31,7 @@ def sidebyside(fromlines, tolines, context):
line_strip = lambda line: line.rstrip("\n")
fromlines = map(line_strip, fromlines)
tolines = map(line_strip, tolines)
had_changes = 0
gap = False
for fromdata, todata, flag in difflib._mdiff(fromlines, tolines, context):
@@ -37,8 +40,11 @@ def sidebyside(fromlines, tolines, context):
else:
from_item = _mdiff_split(flag, fromdata)
to_item = _mdiff_split(flag, todata)
yield _item(gap=ezt.boolean(gap), columns=(from_item, to_item))
had_changes = 1
yield _item(gap=ezt.boolean(gap), columns=(from_item, to_item), type="intraline")
gap = False
if not had_changes:
yield _item(type=_RCSDIFF_NO_CHANGES)
_re_mdiff = re.compile("\0([+-^])(.*?)\1")
@@ -49,18 +55,18 @@ def _mdiff_split(flag, (line_number, text)):
while True:
m = _re_mdiff.search(text, pos)
if not m:
segments.append(_item(text=cgi.escape(text[pos:]), type=None))
segments.append(_item(text=sapi.escape(text[pos:]), type=None))
break
if m.start() > pos:
segments.append(_item(text=cgi.escape(text[pos:m.start()]), type=None))
segments.append(_item(text=sapi.escape(text[pos:m.start()]), type=None))
if m.group(1) == "+":
segments.append(_item(text=cgi.escape(m.group(2)), type="add"))
segments.append(_item(text=sapi.escape(m.group(2)), type="add"))
elif m.group(1) == "-":
segments.append(_item(text=cgi.escape(m.group(2)), type="remove"))
segments.append(_item(text=sapi.escape(m.group(2)), type="remove"))
elif m.group(1) == "^":
segments.append(_item(text=cgi.escape(m.group(2)), type="change"))
segments.append(_item(text=sapi.escape(m.group(2)), type="change"))
pos = m.end()
@@ -71,19 +77,26 @@ def unified(fromlines, tolines, context):
diff = difflib.Differ().compare(fromlines, tolines)
lastrow = None
had_changes = 0
for row in _trim_context(diff, context):
if row[0].startswith("? "):
had_changes = 1
yield _differ_split(lastrow, row[0])
lastrow = None
else:
if lastrow:
had_changes = 1
yield _differ_split(lastrow, None)
lastrow = row
if lastrow:
had_changes = 1
yield _differ_split(lastrow, None)
if not had_changes:
yield _item(type=_RCSDIFF_NO_CHANGES)
def _trim_context(lines, context_size):
"""Trim context lines that don't surround changes from Differ results
@@ -166,20 +179,16 @@ def _differ_split(row, guide):
for m in _re_differ.finditer(guide, pos):
if m.start() > pos:
segments.append(_item(text=cgi.escape(line[pos:m.start()]), type=None))
segments.append(_item(text=cgi.escape(line[m.start():m.end()]),
segments.append(_item(text=sapi.escape(line[pos:m.start()]), type=None))
segments.append(_item(text=sapi.escape(line[m.start():m.end()]),
type="change"))
pos = m.end()
segments.append(_item(text=cgi.escape(line[pos:]), type=None))
segments.append(_item(text=sapi.escape(line[pos:]), type=None))
return _item(gap=ezt.boolean(gap), type=type, segments=segments,
left_number=left_number, right_number=right_number)
class _item:
def __init__(self, **kw):
vars(self).update(kw)
try:
### Using difflib._mdiff function here was the easiest way of obtaining
### intraline diffs for use in ViewVC, but it doesn't exist prior to

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -23,7 +23,6 @@ import os
import sys
import sapi
import threading
import string
if sys.platform == "win32":
import win32popen
@@ -36,7 +35,7 @@ def popen(cmd, args, mode, capture_err=1):
if sys.platform == "win32":
command = win32popen.CommandLine(cmd, args)
if string.find(mode, 'r') >= 0:
if mode.find('r') >= 0:
hStdIn = None
if debug.SHOW_CHILD_PROCESSES:
@@ -85,7 +84,7 @@ def popen(cmd, args, mode, capture_err=1):
# in the parent
# close the descriptor that we don't need and return the other one.
if string.find(mode, 'r') >= 0:
if mode.find('r') >= 0:
os.close(w)
return _pipe(os.fdopen(r, mode), pid)
os.close(r)
@@ -96,7 +95,7 @@ def popen(cmd, args, mode, capture_err=1):
# we'll need /dev/null for the discarded I/O
null = os.open('/dev/null', os.O_RDWR)
if string.find(mode, 'r') >= 0:
if mode.find('r') >= 0:
# hook stdout/stderr to the "write" channel
os.dup2(w, 1)
# "close" stdin; the child shouldn't use it
@@ -125,200 +124,12 @@ def popen(cmd, args, mode, capture_err=1):
os.execvp(cmd, (cmd,) + tuple(args))
except:
# aid debugging, if the os.execvp above fails for some reason:
print "<h2>exec failed:</h2><pre>", cmd, string.join(args), "</pre>"
print "<h2>exec failed:</h2><pre>", cmd, ' '.join(args), "</pre>"
raise
# crap. shouldn't be here.
sys.exit(127)
def pipe_cmds(cmds, out=None):
"""Executes a sequence of commands. The output of each command is directed to
the input of the next command. A _pipe object is returned for writing to the
first command's input. The output of the last command is directed to the
"out" file object or the standard output if "out" is None. If "out" is not an
OS file descriptor, a separate thread will be spawned to send data to its
write() method."""
if out is None:
out = sys.stdout
if sys.platform == "win32":
### FIXME: windows implementation ignores "out" argument, always
### writing last command's output to standard out
if debug.SHOW_CHILD_PROCESSES:
dbgIn = StringIO.StringIO()
hStdIn, handle = win32popen.MakeSpyPipe(1, 0, (dbgIn,))
i = 0
for cmd in cmds:
i = i + 1
dbgOut, dbgErr = StringIO.StringIO(), StringIO.StringIO()
if i < len(cmds):
nextStdIn, hStdOut = win32popen.MakeSpyPipe(1, 1, (dbgOut,))
x, hStdErr = win32popen.MakeSpyPipe(None, 1, (dbgErr,))
else:
ehandle = win32event.CreateEvent(None, 1, 0, None)
nextStdIn, hStdOut = win32popen.MakeSpyPipe(None, 1, (dbgOut, sapi.server.file()), ehandle)
x, hStdErr = win32popen.MakeSpyPipe(None, 1, (dbgErr,))
command = win32popen.CommandLine(cmd[0], cmd[1:])
phandle, pid, thandle, tid = win32popen.CreateProcess(command, hStdIn, hStdOut, hStdErr)
if debug.SHOW_CHILD_PROCESSES:
debug.Process(command, dbgIn, dbgOut, dbgErr)
dbgIn = dbgOut
hStdIn = nextStdIn
else:
hStdIn, handle = win32popen.CreatePipe(1, 0)
spool = None
i = 0
for cmd in cmds:
i = i + 1
if i < len(cmds):
nextStdIn, hStdOut = win32popen.CreatePipe(1, 1)
else:
# very last process
nextStdIn = None
if sapi.server.inheritableOut:
# send child output to standard out
hStdOut = win32popen.MakeInheritedHandle(win32popen.FileObject2File(sys.stdout),0)
ehandle = None
else:
ehandle = win32event.CreateEvent(None, 1, 0, None)
x, hStdOut = win32popen.MakeSpyPipe(None, 1, (sapi.server.file(),), ehandle)
command = win32popen.CommandLine(cmd[0], cmd[1:])
phandle, pid, thandle, tid = win32popen.CreateProcess(command, hStdIn, hStdOut, None)
hStdIn = nextStdIn
return _pipe(win32popen.File2FileObject(handle, 'wb'), phandle, ehandle)
# flush the stdio buffers since we are about to change the FD under them
sys.stdout.flush()
sys.stderr.flush()
prev_r, parent_w = os.pipe()
null = os.open('/dev/null', os.O_RDWR)
child_pids = []
for cmd in cmds[:-1]:
r, w = os.pipe()
pid = os.fork()
if not pid:
# in the child
# hook up stdin to the "read" channel
os.dup2(prev_r, 0)
# hook up stdout to the output channel
os.dup2(w, 1)
# toss errors
os.dup2(null, 2)
# close these extra descriptors
os.close(prev_r)
os.close(parent_w)
os.close(null)
os.close(r)
os.close(w)
# time to run the command
try:
os.execvp(cmd[0], cmd)
except:
pass
sys.exit(127)
# in the parent
child_pids.append(pid)
# we don't need these any more
os.close(prev_r)
os.close(w)
# the read channel of this pipe will feed into to the next command
prev_r = r
# no longer needed
os.close(null)
# done with most of the commands. set up the last command to write to "out"
if not hasattr(out, 'fileno'):
r, w = os.pipe()
pid = os.fork()
if not pid:
# in the child (the last command)
# hook up stdin to the "read" channel
os.dup2(prev_r, 0)
# hook up stdout to "out"
if hasattr(out, 'fileno'):
if out.fileno() != 1:
os.dup2(out.fileno(), 1)
out.close()
else:
# "out" can't be hooked up directly, so use a pipe and a thread
os.dup2(w, 1)
os.close(r)
os.close(w)
# close these extra descriptors
os.close(prev_r)
os.close(parent_w)
# run the last command
try:
os.execvp(cmds[-1][0], cmds[-1])
except:
pass
sys.exit(127)
child_pids.append(pid)
# not needed any more
os.close(prev_r)
if not hasattr(out, 'fileno'):
os.close(w)
thread = _copy(r, out)
thread.start()
else:
thread = None
# write into the first pipe, wait on the final process
return _pipe(os.fdopen(parent_w, 'w'), child_pids, thread=thread)
class _copy(threading.Thread):
def __init__(self, srcfd, destfile):
self.srcfd = srcfd
self.destfile = destfile
threading.Thread.__init__(self)
def run(self):
try:
while 1:
s = os.read(self.srcfd, 1024)
if not s:
break
self.destfile.write(s)
finally:
os.close(self.srcfd)
class _pipe:
"Wrapper for a file which can wait() on a child process at close time."
@@ -364,12 +175,12 @@ class _pipe:
else:
if self.thread:
self.thread.join()
if type(self.child_pid) == type([]):
if type(self.child_pid) == type([]):
for pid in self.child_pid:
exit = os.waitpid(pid, 0)[1]
return exit
else:
return os.waitpid(self.child_pid, 0)[1]
else:
return os.waitpid(self.child_pid, 0)[1]
return None
def __getattr__(self, name):

154
lib/pygments/lexers/sp4.py Executable file
View File

@@ -0,0 +1,154 @@
# -*- coding: utf-8 -*-
"""
pygments.lexers.sp4
~~~~~~~~~~~~~~~~~~~~~
Lexer for CustIS m4-preprocessed PL/SQL.
:copyright: 2009+ by Vitaliy Filippov <vitalif@mail.ru>.
:license: BSD, see LICENSE for more details.
,
'Sp4Lexer': ('pygments.lexers.sp4', 'SP4', ('sp4',), ('*.sp4'), ('text/x-sp4',))
"""
import re
from pygments.lexer import Lexer, RegexLexer, include, bygroups, using, this, \
do_insertions
from pygments.token import Error, Punctuation, \
Text, Comment, Operator, Keyword, Name, String, Number, Generic
from pygments.util import shebang_matches
__all__ = ['Sp4Lexer']
line_re = re.compile('.*?\n')
class Sp4Lexer(RegexLexer):
name = 'SP4'
aliases = ['sp4']
filenames = ['*.sp4']
mimetypes = ['text/x-sp4']
flags = re.IGNORECASE
tokens = {
'root': [
(r'\s+', Text),
(r'--.*?\n', Comment.Single),
(r'/\*', Comment.Multiline, 'multiline-comments'),
(r'(ABORT|ABS|ABSOLUTE|ACCESS|ADA|ADD|ADMIN|AFTER|AGGREGATE|'
r'ALIAS|ALL|ALLOCATE|ALTER|ANALYSE|ANALYZE|AND|ANY|ARE|AS|'
r'ASC|ASENSITIVE|ASSERTION|ASSIGNMENT|ASYMMETRIC|AT|ATOMIC|'
r'AUTHORIZATION|AVG|BACKWARD|BEFORE|BEGIN|BETWEEN|BITVAR|'
r'BIT_LENGTH|BOTH|BREADTH|BY|C|CACHE|CALL|CALLED|CARDINALITY|'
r'CASCADE|CASCADED|CASE|CAST|CATALOG|CATALOG_NAME|CHAIN|'
r'CHARACTERISTICS|CHARACTER_LENGTH|CHARACTER_SET_CATALOG|'
r'CHARACTER_SET_NAME|CHARACTER_SET_SCHEMA|CHAR_LENGTH|CHECK|'
r'CHECKED|CHECKPOINT|CLASS|CLASS_ORIGIN|CLOB|CLOSE|CLUSTER|'
r'COALSECE|COBOL|COLLATE|COLLATION|COLLATION_CATALOG|'
r'COLLATION_NAME|COLLATION_SCHEMA|COLUMN|COLUMN_NAME|'
r'COMMAND_FUNCTION|COMMAND_FUNCTION_CODE|COMMENT|COMMIT|'
r'COMMITTED|COMPLETION|CONDITION_NUMBER|CONNECT|CONNECTION|'
r'CONNECTION_NAME|CONSTRAINT|CONSTRAINTS|CONSTRAINT_CATALOG|'
r'CONSTRAINT_NAME|CONSTRAINT_SCHEMA|CONSTRUCTOR|CONTAINS|'
r'CONTINUE|CONVERSION|CONVERT|COPY|CORRESPONTING|COUNT|'
r'CREATE|CREATEDB|CREATEUSER|CROSS|CUBE|CURRENT|CURRENT_DATE|'
r'CURRENT_PATH|CURRENT_ROLE|CURRENT_TIME|CURRENT_TIMESTAMP|'
r'CURRENT_USER|CURSOR|CURSOR_NAME|CYCLE|DATA|DATABASE|'
r'DATETIME_INTERVAL_CODE|DATETIME_INTERVAL_PRECISION|DAY|'
r'DEALLOCATE|DECLARE|DEFAULT|DEFAULTS|DEFERRABLE|DEFERRED|'
r'DEFINED|DEFINER|DELETE|DELIMITER|DELIMITERS|DEREF|DESC|'
r'DESCRIBE|DESCRIPTOR|DESTROY|DESTRUCTOR|DETERMINISTIC|'
r'DIAGNOSTICS|DICTIONARY|DISCONNECT|DISPATCH|DISTINCT|DO|'
r'DOMAIN|DROP|DYNAMIC|DYNAMIC_FUNCTION|DYNAMIC_FUNCTION_CODE|'
r'EACH|ELSE|ENCODING|ENCRYPTED|END|END-EXEC|EQUALS|ESCAPE|EVERY|'
r'EXCEPT|ESCEPTION|EXCLUDING|EXCLUSIVE|EXEC|EXECUTE|EXISTING|'
r'EXISTS|EXPLAIN|EXTERNAL|EXTRACT|FALSE|FETCH|FINAL|FIRST|FOR|'
r'FORCE|FOREIGN|FORTRAN|FORWARD|FOUND|FREE|FREEZE|FROM|FULL|'
r'FUNCTION|G|GENERAL|GENERATED|GET|GLOBAL|GO|GOTO|GRANT|GRANTED|'
r'GROUP|GROUPING|HANDLER|HAVING|HIERARCHY|HOLD|HOST|IDENTITY|'
r'IGNORE|ILIKE|IMMEDIATE|IMMUTABLE|IMPLEMENTATION|IMPLICIT|IN|'
r'INCLUDING|INCREMENT|INDEX|INDITCATOR|INFIX|INHERITS|INITIALIZE|'
r'INITIALLY|INNER|INOUT|INPUT|INSENSITIVE|INSERT|INSTANTIABLE|'
r'INSTEAD|INTERSECT|INTO|INVOKER|IS|ISNULL|ISOLATION|ITERATE|JOIN|'
r'K|KEY|KEY_MEMBER|KEY_TYPE|LANCOMPILER|LANGUAGE|LARGE|LAST|'
r'LATERAL|LEADING|LEFT|LENGTH|LESS|LEVEL|LIKE|LILMIT|LISTEN|LOAD|'
r'LOCAL|LOCALTIME|LOCALTIMESTAMP|LOCATION|LOCATOR|LOCK|LOWER|M|'
r'MAP|MATCH|MAX|MAXVALUE|MESSAGE_LENGTH|MESSAGE_OCTET_LENGTH|'
r'MESSAGE_TEXT|METHOD|MIN|MINUTE|MINVALUE|MOD|MODE|MODIFIES|'
r'MODIFY|MONTH|MORE|MOVE|MUMPS|NAMES|NATIONAL|NATURAL|NCHAR|'
r'NCLOB|NEW|NEXT|NO|NOCREATEDB|NOCREATEUSER|NONE|NOT|NOTHING|'
r'NOTIFY|NOTNULL|NULL|NULLABLE|NULLIF|OBJECT|OCTET_LENGTH|OF|OFF|'
r'OFFSET|OIDS|OLD|ON|ONLY|OPEN|OPERATION|OPERATOR|OPTION|OPTIONS|'
r'OR|ORDER|ORDINALITY|OUT|OUTER|OUTPUT|OVERLAPS|OVERLAY|OVERRIDING|'
r'OWNER|PAD|PARAMETER|PARAMETERS|PARAMETER_MODE|PARAMATER_NAME|'
r'PARAMATER_ORDINAL_POSITION|PARAMETER_SPECIFIC_CATALOG|'
r'PARAMETER_SPECIFIC_NAME|PARAMATER_SPECIFIC_SCHEMA|PARTIAL|'
r'PASCAL|PENDANT|PLACING|PLI|POSITION|POSTFIX|PRECISION|PREFIX|'
r'PREORDER|PREPARE|PRESERVE|PRIMARY|PRIOR|PRIVILEGES|PROCEDURAL|'
r'PROCEDURE|PUBLIC|READ|READS|RECHECK|RECURSIVE|REF|REFERENCES|'
r'REFERENCING|REINDEX|RELATIVE|RENAME|REPEATABLE|REPLACE|RESET|'
r'RESTART|RESTRICT|RESULT|RETURN|RETURNED_LENGTH|'
r'RETURNED_OCTET_LENGTH|RETURNED_SQLSTATE|RETURNS|REVOKE|RIGHT|'
r'ROLE|ROLLBACK|ROLLUP|ROUTINE|ROUTINE_CATALOG|ROUTINE_NAME|'
r'ROUTINE_SCHEMA|ROW|ROWS|ROW_COUNT|RULE|SAVE_POINT|SCALE|SCHEMA|'
r'SCHEMA_NAME|SCOPE|SCROLL|SEARCH|SECOND|SECURITY|SELECT|SELF|'
r'SENSITIVE|SERIALIZABLE|SERVER_NAME|SESSION|SESSION_USER|SET|'
r'SETOF|SETS|SHARE|SHOW|SIMILAR|SIMPLE|SIZE|SOME|SOURCE|SPACE|'
r'SPECIFIC|SPECIFICTYPE|SPECIFIC_NAME|SQL|SQLCODE|SQLERROR|'
r'SQLEXCEPTION|SQLSTATE|SQLWARNINIG|STABLE|START|STATE|STATEMENT|'
r'STATIC|STATISTICS|STDIN|STDOUT|STORAGE|STRICT|STRUCTURE|STYPE|'
r'SUBCLASS_ORIGIN|SUBLIST|SUBSTRING|SUM|SYMMETRIC|SYSID|SYSTEM|'
r'SYSTEM_USER|TABLE|TABLE_NAME| TEMP|TEMPLATE|TEMPORARY|TERMINATE|'
r'THAN|THEN|TIMESTAMP|TIMEZONE_HOUR|TIMEZONE_MINUTE|TO|TOAST|'
r'TRAILING|TRANSATION|TRANSACTIONS_COMMITTED|'
r'TRANSACTIONS_ROLLED_BACK|TRANSATION_ACTIVE|TRANSFORM|'
r'TRANSFORMS|TRANSLATE|TRANSLATION|TREAT|TRIGGER|TRIGGER_CATALOG|'
r'TRIGGER_NAME|TRIGGER_SCHEMA|TRIM|TRUE|TRUNCATE|TRUSTED|TYPE|'
r'UNCOMMITTED|UNDER|UNENCRYPTED|UNION|UNIQUE|UNKNOWN|UNLISTEN|'
r'UNNAMED|UNNEST|UNTIL|UPDATE|UPPER|USAGE|USER|'
r'USER_DEFINED_TYPE_CATALOG|USER_DEFINED_TYPE_NAME|'
r'USER_DEFINED_TYPE_SCHEMA|USING|VACUUM|VALID|VALIDATOR|VALUES|'
r'VARIABLE|VERBOSE|VERSION|VIEW|VOLATILE|WHEN|WHENEVER|WHERE|'
r'WITH|WITHOUT|WORK|WRITE|YEAR|ZONE|BINARY_INTEGER|BODY|BREAK|'
r'CONSTANT|DEFINITION|DELETING|DLOB|DUMMY|ELSIF|ERRLVL|ERROR|'
r'EXCEPTION|EXIT|IF|INSERTING|ISOPEN|LOOP|NO_DATA_FOUND|NOTFOUND|'
r'OTHERS|PACKAGE|PRAGMA|RAISE|RECORD|RESTRICT_REFERENCES|RETURNING|'
r'RNDS|RNPS|ROWCOUNT|ROWNUM|ROWTYPE|SAVEPOINT|SQLERRM|TOO_MANY_ROWS|'
r'UPDATING|WHILE|WNDS|WNPS|BULK|CHR|COLLECT|GREATEST|INSTR|LEAST|'
r'LENGTHB|NOCOPY|NOWAIT|NVL|RPAD|SUBST|SUBSTB|SUBSTR|SYSDATE|'
r'TABLESPACE|TO_CHAR|TO_DATE|TO_NUMBER|TRUNC)\b', Keyword),
(r'(ARRAY|BIGINT|BINARY|BIT|BLOB|BOOLEAN|CHAR|CHARACTER|DATE|'
r'DEC|DECIMAL|FLOAT|INT|INTEGER|INTERVAL|NUMBER|NUMERIC|REAL|'
r'SERIAL|SMALLINT|VARCHAR|VARCHAR2|VARYING|INT8|SERIAL8|TEXT)\b',
Name.Builtin),
(r'(_5date_args|_actual_area|_ASSERT|_doc_code|_doc_var|_doc_var_list|'
r'_enforce|_ent|_enum|_enums_define|_enums_member_define|_field|'
r'_fields|_first|_FMT|_in_list|_index|_index_unique|_indexes'
r'_MAX_STRLEN|_MID_STRLEN|_param|_package|_pk|_plsql_param|_plsql_return|'
r'_private_function|_private_procedure|_private_type|_private_var|'
r'_protected_function|_protected_procedure|_protected_type|_protected_var|'
r'_public_function|_public_procedure|_public_type|_public_var|_quote|_RAISE|'
r'_RAISEW|_reference|_references|_request_arg|_request_define|'
r'_request_res|_STR_CONST|_substr|_table|_tail|builtin|cdr|changecom|'
r'changequote|changeword|debugfile|decr|define|divert|dummy_list|dumpdef|'
r'errprint|eval|foreach|forloop|GetNth|ifelse|include|incr|index|indir|'
r'len|lowcase|maketemp|Nth|patsubst|popdef|pushdef|regexp|'
r'remove_prefix|shift|sinclude|Size|syscmd|TRACE|traceoff|traceon|'
r'translit|undefine|undivert|upcase)\b',
Name.Function),
(r'[+*/<>=~!@#%^&|`?^-]', Operator),
(r'[0-9]+', Number.Integer),
(r"'(''|[^'\\]|\\\'|\\\\)*'", String.Single),
(r'"(""|[^"\\]|\\\"|\\\\)*"', String.Symbol),
(r'[a-zA-Z_][a-zA-Z0-9_]*', Name),
(r'[;:()\[\],\.]', Punctuation)
],
'multiline-comments': [
(r'/\*', Comment.Multiline, 'multiline-comments'),
(r'\*/', Comment.Multiline, '#pop'),
(r'[^/\*]+', Comment.Multiline),
(r'[/*]', Comment.Multiline)
]
}

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -23,11 +23,13 @@ import sys
import string
import time
from common import _item, TemplateData
import cvsdb
import viewvc
import ezt
import debug
import urllib
import fnmatch
class FormData:
def __init__(self, form):
@@ -39,6 +41,7 @@ class FormData:
self.file = ""
self.who = ""
self.sortby = ""
self.textquery = ""
self.date = ""
self.hours = 0
@@ -46,7 +49,7 @@ class FormData:
def decode_thyself(self, form):
try:
self.repository = string.strip(form["repository"].value)
self.textquery = string.strip(form["textquery"].value)
except KeyError:
pass
except TypeError:
@@ -55,7 +58,16 @@ class FormData:
self.valid = 1
try:
self.branch = string.strip(form["branch"].value)
self.repository = form["repository"].value.strip()
except KeyError:
pass
except TypeError:
pass
else:
self.valid = 1
try:
self.branch = form["branch"].value.strip()
except KeyError:
pass
except TypeError:
@@ -64,7 +76,7 @@ class FormData:
self.valid = 1
try:
self.directory = string.strip(form["directory"].value)
self.directory = form["directory"].value.strip()
except KeyError:
pass
except TypeError:
@@ -73,7 +85,7 @@ class FormData:
self.valid = 1
try:
self.file = string.strip(form["file"].value)
self.file = form["file"].value.strip()
except KeyError:
pass
except TypeError:
@@ -82,7 +94,7 @@ class FormData:
self.valid = 1
try:
self.who = string.strip(form["who"].value)
self.who = form["who"].value.strip()
except KeyError:
pass
except TypeError:
@@ -91,14 +103,14 @@ class FormData:
self.valid = 1
try:
self.sortby = string.strip(form["sortby"].value)
self.sortby = form["sortby"].value.strip()
except KeyError:
pass
except TypeError:
pass
try:
self.date = string.strip(form["date"].value)
self.date = form["date"].value.strip()
except KeyError:
pass
except TypeError:
@@ -157,7 +169,7 @@ def listparse_string(str):
## command; add the command and start over
elif c == ",":
## strip ending whitespace on un-quoted data
temp = string.rstrip(temp)
temp = temp.rstrip()
return_list.append( ("", temp) )
temp = ""
state = "eat leading whitespace"
@@ -216,8 +228,9 @@ def decode_command(cmd):
else:
return "exact"
def form_to_cvsdb_query(form_data):
def form_to_cvsdb_query(cfg, form_data):
query = cvsdb.CreateCheckinQuery()
query.SetLimit(cfg.cvsdb.row_limit)
if form_data.repository:
for cmd, str in listparse_string(form_data.repository):
@@ -244,10 +257,15 @@ def form_to_cvsdb_query(form_data):
cmd = decode_command(cmd)
query.SetAuthor(str, cmd)
if form_data.textquery:
query.SetTextQuery(form_data.textquery)
if form_data.sortby == "author":
query.SetSortMethod("author")
elif form_data.sortby == "file":
query.SetSortMethod("file")
elif form_data.sortby == "relevance" and form_data.textquery:
query.SetSortMethod("relevance")
else:
query.SetSortMethod("date")
@@ -265,27 +283,67 @@ def form_to_cvsdb_query(form_data):
def prev_rev(rev):
'''Returns a string representing the previous revision of the argument.'''
r = string.split(rev, '.')
r = rev.split('.')
# decrement final revision component
r[-1] = str(int(r[-1]) - 1)
# prune if we pass the beginning of the branch
if len(r) > 2 and r[-1] == '0':
r = r[:-2]
return string.join(r, '.')
return '.'.join(r)
def is_forbidden(cfg, cvsroot_name, module):
'''Return 1 if MODULE in CVSROOT_NAME is forbidden; return 0 otherwise.'''
# CVSROOT_NAME might be None here if the data comes from an
# unconfigured root. This interfaces doesn't care that the root
# isn't configured, but if that's the case, it will consult only
# the base and per-vhost configuration for authorizer and
# authorizer parameters.
if cvsroot_name:
cfg = cfg.get_root_config(cvsroot_name)
authorizer = cfg.options.authorizer
params = cfg.get_authorizer_params()
# If CVSROOT_NAME isn't configured to use an authorizer, nothing
# is forbidden. If it's configured to use something other than
# the 'forbidden' authorizer, complain. Otherwise, check for
# forbiddenness per the PARAMS as expected.
if not authorizer:
return 0
if authorizer != 'forbidden':
raise Exception("The 'forbidden' authorizer is the only one supported "
"by this interface. The '%s' root is configured to "
"use a different one." % (cvsroot_name))
forbidden = params.get('forbidden', '')
forbidden = map(lambda x: x.strip(), filter(None, forbidden.split(',')))
default = 0
for pat in forbidden:
if pat[0] == '!':
default = 1
if fnmatch.fnmatchcase(module, pat[1:]):
return 0
elif fnmatch.fnmatchcase(module, pat):
return 1
return default
def build_commit(server, cfg, desc, files, cvsroots, viewvc_link):
ob = _item(num_files=len(files), files=[])
if desc:
ob.log = string.replace(server.escape(desc), '\n', '<br />')
else:
ob.log = '&nbsp;'
ob.log = desc and server.escape(desc).replace('\n', '<br />') or '&nbsp;'
for commit in files:
dir_parts = filter(None, string.split(commit.GetDirectory(), '/'))
if dir_parts \
and ((dir_parts[0] == 'CVSROOT' and cfg.options.hide_cvsroot) \
or cfg.is_forbidden(dir_parts[0])):
repository = commit.GetRepository()
directory = commit.GetDirectory()
cvsroot_name = cvsroots.get(repository)
## find the module name (if any)
try:
module = filter(None, directory.split('/'))[0]
except IndexError:
module = None
## skip commits we aren't supposed to show
if module and ((module == 'CVSROOT' and cfg.options.hide_cvsroot) \
or is_forbidden(cfg, cvsroot_name, module)):
continue
ctime = commit.GetTime()
@@ -296,17 +354,18 @@ def build_commit(server, cfg, desc, files, cvsroots, viewvc_link):
ctime = time.strftime("%y/%m/%d %H:%M %Z", time.localtime(ctime))
else:
ctime = time.strftime("%y/%m/%d %H:%M", time.gmtime(ctime)) \
+ ' UTC'
+ ' UTC'
## make the file link
repository = commit.GetRepository()
directory = commit.GetDirectory()
file = (directory and directory + "/") + commit.GetFile()
cvsroot_name = cvsroots.get(repository)
try:
file = (directory and directory + "/") + commit.GetFile()
except:
raise Exception, str([directory, commit.GetFile()])
## if we couldn't find the cvsroot path configured in the
## viewvc.conf file, then don't make the link
if cvsroot_name:
## If we couldn't find the cvsroot path configured in the
## viewvc.conf file, or we don't have a VIEWVC_LINK, then
## don't make the link.
if cvsroot_name and viewvc_link:
flink = '[%s] <a href="%s/%s?root=%s">%s</a>' % (
cvsroot_name, viewvc_link, urllib.quote(file),
cvsroot_name, file)
@@ -320,6 +379,9 @@ def build_commit(server, cfg, desc, files, cvsroots, viewvc_link):
flink = '[%s] %s' % (repository, file)
dlink = None
ob.relevance = commit.GetRelevance()
ob.plus += int(commit.GetPlusCount())
ob.minus += int(commit.GetMinusCount())
ob.files.append(_item(date=ctime,
author=commit.GetAuthor(),
link=flink,
@@ -333,24 +395,27 @@ def build_commit(server, cfg, desc, files, cvsroots, viewvc_link):
return ob
def run_query(server, cfg, form_data, viewvc_link):
query = form_to_cvsdb_query(form_data)
db = cvsdb.ConnectDatabaseReadOnly(cfg)
def run_query(server, cfg, db, form_data, viewvc_link):
query = form_to_cvsdb_query(cfg, form_data)
db.RunQuery(query)
if not query.commit_list:
return [ ]
commit_list = query.GetCommitList()
if not commit_list:
return [ ], 0
row_limit_reached = query.GetLimitReached()
commits = [ ]
files = [ ]
cvsroots = {}
rootitems = cfg.general.cvs_roots.items() + cfg.general.svn_roots.items()
viewvc.expand_root_parents(cfg)
rootitems = cfg.general.svn_roots.items() + cfg.general.cvs_roots.items()
for key, value in rootitems:
cvsroots[cvsdb.CleanRepository(value)] = key
current_desc = query.commit_list[0].GetDescription()
for commit in query.commit_list:
current_desc = commit_list[0].GetDescription()
for commit in commit_list:
desc = commit.GetDescription()
if current_desc == desc:
files.append(commit)
@@ -366,7 +431,14 @@ def run_query(server, cfg, form_data, viewvc_link):
commits.append(build_commit(server, cfg, current_desc, files,
cvsroots, viewvc_link))
return commits
# Strip out commits that don't have any files attached to them. The
# files probably aren't present because they've been blocked via
# forbiddenness.
def _only_with_files(commit):
return len(commit.files) > 0
commits = filter(_only_with_files, commits)
return commits, row_limit_reached
def main(server, cfg, viewvc_link):
try:
@@ -374,47 +446,45 @@ def main(server, cfg, viewvc_link):
form = server.FieldStorage()
form_data = FormData(form)
db = cvsdb.ConnectDatabaseReadOnly(cfg, None)
if form_data.valid:
commits = run_query(server, cfg, form_data, viewvc_link)
commits, row_limit_reached = run_query(server, cfg, db, form_data, viewvc_link)
query = None
else:
commits = [ ]
row_limit_reached = 0
query = 'skipped'
script_name = server.getenv('SCRIPT_NAME', '')
data = {
docroot = cfg.options.docroot
if docroot is None and viewvc_link:
docroot = viewvc_link + '/' + viewvc.docroot_magic_path
data = TemplateData({
'cfg' : cfg,
'address' : cfg.general.address,
'vsn' : viewvc.__version__,
'repository' : server.escape(form_data.repository, 1),
'branch' : server.escape(form_data.branch, 1),
'directory' : server.escape(form_data.directory, 1),
'file' : server.escape(form_data.file, 1),
'who' : server.escape(form_data.who, 1),
'docroot' : cfg.options.docroot is None \
and viewvc_link + '/' + viewvc.docroot_magic_path \
or cfg.options.docroot,
'textquery' : server.escape(form_data.textquery),
'repository' : server.escape(form_data.repository),
'branch' : server.escape(form_data.branch),
'directory' : server.escape(form_data.directory),
'file' : server.escape(form_data.file),
'who' : server.escape(form_data.who),
'docroot' : docroot,
'sortby' : form_data.sortby,
'date' : form_data.date,
'query' : query,
'row_limit_reached' : ezt.boolean(row_limit_reached),
'commits' : commits,
'num_commits' : len(commits),
}
if form_data.hours:
data['hours'] = form_data.hours
else:
data['hours'] = 2
server.header()
'rss_href' : None,
'repositories' : db.GetRepositoryList(),
'hours' : form_data.hours and form_data.hours or 2,
})
# generate the page
server.header()
template = viewvc.get_view_template(cfg, "query")
template.generate(sys.stdout, data)
template.generate(server.file(), data)
except SystemExit, e:
pass
@@ -422,7 +492,3 @@ def main(server, cfg, viewvc_link):
exc_info = debug.GetExceptionData()
server.header(status=exc_info['status'])
debug.PrintException(server, exc_info)
class _item:
def __init__(self, **kw):
vars(self).update(kw)

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -16,17 +16,32 @@
# -----------------------------------------------------------------------
import types
import string
import os
import sys
import re
import cgi
# global server object. It will be either a CgiServer or a proxy to
# an AspServer or ModPythonServer object.
# global server object. It will be either a CgiServer, a WsgiServer,
# or a proxy to an AspServer or ModPythonServer object.
server = None
# Simple HTML string escaping. Note that we always escape the
# double-quote character -- ViewVC shouldn't ever need to preserve
# that character as-is, and sometimes needs to embed escaped values
# into HTML attributes.
def escape(s):
try: s = s.encode('utf8')
except: pass
s = str(s)
s = s.replace('&', '&amp;')
s = s.replace('>', '&gt;')
s = s.replace('<', '&lt;')
s = s.replace('"', "&quot;")
return s
class Server:
def __init__(self):
self.pageGlobals = {}
@@ -34,6 +49,9 @@ class Server:
def self(self):
return self
def escape(self, s):
return escape(s)
def close(self):
pass
@@ -129,13 +147,10 @@ class CgiServer(Server):
global server
server = self
global cgi
import cgi
def addheader(self, name, value):
self.headers.append((name, value))
def header(self, content_type='text/html', status=None):
def header(self, content_type='text/html; charset=UTF-8', status=None):
if not self.headerSent:
self.headerSent = 1
@@ -158,11 +173,7 @@ class CgiServer(Server):
if self.iis: url = fix_iis_url(self, url)
self.addheader('Location', url)
self.header(status='301 Moved')
print 'This document is located <a href="%s">here</a>.' % url
sys.exit(0)
def escape(self, s, quote = None):
return cgi.escape(s, quote)
sys.stdout.write('This document is located <a href="%s">here</a>.\n' % url)
def getenv(self, name, value=None):
ret = os.environ.get(name, value)
@@ -176,7 +187,7 @@ class CgiServer(Server):
def FieldStorage(fp=None, headers=None, outerboundary="",
environ=os.environ, keep_blank_values=0, strict_parsing=0):
return cgi.FieldStorage(fp, headers, outerboundary, environ,
keep_blank_values, strict_parsing)
keep_blank_values, strict_parsing)
def write(self, s):
sys.stdout.write(s)
@@ -188,6 +199,60 @@ class CgiServer(Server):
return sys.stdout
class WsgiServer(Server):
def __init__(self, environ, start_response):
Server.__init__(self)
self._environ = environ
self._start_response = start_response;
self._headers = []
self._wsgi_write = None
self.headerSent = False
global server
server = self
def addheader(self, name, value):
self._headers.append((name, value))
def header(self, content_type='text/html; charset=UTF-8', status=None):
if not status:
status = "200 OK"
if not self.headerSent:
self.headerSent = True
self._headers.insert(0, ("Content-Type", content_type),)
self._wsgi_write = self._start_response("%s" % status, self._headers)
def redirect(self, url):
"""Redirect client to url. This discards any data that has been queued
to be sent to the user. But there should never by any anyway.
"""
self.addheader('Location', url)
self.header(status='301 Moved')
self._wsgi_write('This document is located <a href="%s">here</a>.' % url)
def getenv(self, name, value=None):
return self._environ.get(name, value)
def params(self):
return cgi.parse(environ=self._environ, fp=self._environ["wsgi.input"])
def FieldStorage(self, fp=None, headers=None, outerboundary="",
environ=os.environ, keep_blank_values=0, strict_parsing=0):
return cgi.FieldStorage(self._environ["wsgi.input"], headers,
outerboundary, self._environ, keep_blank_values,
strict_parsing)
def write(self, s):
self._wsgi_write(s)
def flush(self):
pass
def file(self):
return File(self)
class AspServer(ThreadedServer):
def __init__(self, Server, Request, Response, Application):
ThreadedServer.__init__(self)
@@ -209,17 +274,16 @@ class AspServer(ThreadedServer):
if not self.headerSent:
try:
self.headerSent = 1
if content_type is not None: self.response.ContentType = content_type
if content_type is None:
self.response.ContentType = 'text/html; charset=UTF-8'
else:
self.response.ContentType = content_type
if status is not None: self.response.Status = status
except AttributeError:
pass
def redirect(self, url):
self.response.Redirect(url)
sys.exit()
def escape(self, s, quote = None):
return self.server.HTMLEncode(str(s))
def getenv(self, name, value = None):
ret = self.request.ServerVariables(name)()
@@ -282,15 +346,12 @@ class ModPythonServer(ThreadedServer):
self.request = request
self.headerSent = 0
global cgi
import cgi
def addheader(self, name, value):
self.request.headers_out.add(name, value)
def header(self, content_type=None, status=None):
if content_type is None:
self.request.content_type = 'text/html'
self.request.content_type = 'text/html; charset=UTF-8'
else:
self.request.content_type = content_type
self.headerSent = 1
@@ -305,11 +366,7 @@ class ModPythonServer(ThreadedServer):
self.request.headers_out['Location'] = url
self.request.status = mod_python.apache.HTTP_MOVED_TEMPORARILY
self.request.write("You are being redirected to <a href=\"%s\">%s</a>"
% (url, url))
sys.exit()
def escape(self, s, quote = None):
return cgi.escape(s, quote)
% (url, url))
def getenv(self, name, value = None):
try:

56
lib/vcauth/__init__.py Normal file
View File

@@ -0,0 +1,56 @@
# -*-python-*-
#
# Copyright (C) 2006-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
"""Generic API for implementing authorization checks employed by ViewVC."""
class GenericViewVCAuthorizer:
"""Abstract class encapsulating version control authorization routines."""
def __init__(self, username=None, params={}):
"""Create a GenericViewVCAuthorizer object which will be used to
validate that USERNAME has the permissions needed to view version
control repositories (in whole or in part). PARAMS is a
dictionary of custom parameters for the authorizer."""
pass
def check_root_access(self, rootname):
"""Return 1 iff the associated username is permitted to read ROOTNAME."""
pass
def check_universal_access(self, rootname):
"""Return 1 if the associated username is permitted to read every
path in the repository at every revision, 0 if the associated
username is prohibited from reading any path in the repository, or
None if no such determination can be made (perhaps because the
cost of making it is too great)."""
pass
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
"""Return 1 iff the associated username is permitted to read
revision REV of the path PATH_PARTS (of type PATHTYPE) in
repository ROOTNAME."""
pass
##############################################################################
class ViewVCAuthorizer(GenericViewVCAuthorizer):
"""The uber-permissive authorizer."""
def check_root_access(self, rootname):
return 1
def check_universal_access(self, rootname):
return 1
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
return 1

View File

@@ -0,0 +1,92 @@
# -*-python-*-
#
# Copyright (C) 2009 Vitaliy Filippov.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
import vcauth
import vclib
import string
from xml.dom.minidom import parse
class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
"""An authorizer which uses CVSnt access control lists (which are in form
of XML files in CVS/ subdirectories in the repository)."""
def __init__(self, username, params={}):
self.username = username
self.params = params
self.cfg = params['__config']
self.default = params.get('default', 0)
self.cached = {}
self.xmlcache = {}
def dom_rights(self, doc, rightname, filename, username):
result = None
if filename:
for node in doc.getElementsByTagName('file'):
if node.getAttribute('name') == filename:
for acl in node.getElementsByTagName('acl'):
if not acl.getAttribute('branch'):
u = acl.getAttribute('user')
if result is None and (not u or u == 'anonymous') or u == username:
for r in acl.getElementsByTag(rightname):
result = not r.getAttribute('deny')
break
if result is None:
for node in doc.getElementsByTagName('directory'):
for acl in node.getElementsByTagName('acl'):
if not acl.getAttribute('branch'):
u = acl.getAttribute('user')
if result is None and (not u or u == 'anonymous') or u == username:
for r in acl.getElementsByTag(rightname):
result = not r.getAttribute('deny')
return result
def check(self, rootname, path_parts, filename):
d = self.cfg.general.cvs_roots.get(rootname,None)
if not d:
return self.default
i = len(path_parts)
r = None
while i >= 0:
try:
xml = d
if len(path_parts):
xml = xml + '/' + string.join(path_parts, '/')
xml = xml + '/CVS/fileattr.xml'
if self.cached.get(xml, None) is not None:
return self.cached.get(xml, None)
doc = self.xmlcache.get(xml, None)
if doc is None:
doc = parse(xml)
self.xmlcache[xml] = doc
r = self.dom_rights(doc, 'read', filename, self.username)
if r is not None:
self.cached[xml] = r
return r
raise Exception(None)
except:
if len(path_parts) > 0:
path_parts = path_parts[:-1]
filename = ''
i = i-1
return self.default
def check_root_access(self, rootname):
return self.check(rootname, [], '')
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
if not path_parts:
return self.check(rootname, [], '')
if pathtype == vclib.DIR:
return self.check(rootname, path_parts, '')
f = path_parts[-1]
path_parts = path_parts[:-1]
return self.check(rootname, path_parts, f)

View File

@@ -0,0 +1,52 @@
# -*-python-*-
#
# Copyright (C) 2006-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
import vcauth
import vclib
import fnmatch
class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
"""A simple top-level module authorizer."""
def __init__(self, username, params={}):
forbidden = params.get('forbidden', '')
self.forbidden = map(lambda x: x.strip(),
filter(None, forbidden.split(',')))
def check_root_access(self, rootname):
return 1
def check_universal_access(self, rootname):
# If there aren't any forbidden paths, we can grant universal read
# access. Otherwise, we make no claim.
if not self.forbidden:
return 1
return None
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
# No path? No problem.
if not path_parts:
return 1
# Not a directory? We aren't interested.
if pathtype != vclib.DIR:
return 1
# At this point we're looking at a directory path.
module = path_parts[0]
default = 1
for pat in self.forbidden:
if pat[0] == '!':
default = 0
if fnmatch.fnmatchcase(module, pat[1:]):
return 1
elif fnmatch.fnmatchcase(module, pat):
return 0
return default

View File

@@ -0,0 +1,64 @@
# -*-python-*-
#
# Copyright (C) 2008-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
import vcauth
import vclib
import fnmatch
import re
def _split_regexp(restr):
"""Return a 2-tuple consisting of a compiled regular expression
object and a boolean flag indicating if that object should be
interpreted inversely."""
if restr[0] == '!':
return re.compile(restr[1:]), 1
return re.compile(restr), 0
class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
"""A simple regular-expression-based authorizer."""
def __init__(self, username, params={}):
forbidden = params.get('forbiddenre', '')
self.forbidden = map(lambda x: _split_regexp(x.strip()),
filter(None, forbidden.split(',')))
def _check_root_path_access(self, root_path):
default = 1
for forbidden, negated in self.forbidden:
if negated:
default = 0
if forbidden.search(root_path):
return 1
elif forbidden.search(root_path):
return 0
return default
def check_root_access(self, rootname):
return self._check_root_path_access(rootname)
def check_universal_access(self, rootname):
# If there aren't any forbidden regexps, we can grant universal
# read access. Otherwise, we make no claim.
if not self.forbidden:
return 1
return None
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
root_path = rootname
if path_parts:
root_path = root_path + '/' + '/'.join(path_parts)
if pathtype == vclib.DIR:
root_path = root_path + '/'
else:
root_path = root_path + '/'
return self._check_root_path_access(root_path)

View File

@@ -0,0 +1,62 @@
# -*-python-*-
#
# Copyright (C) 2009 Vitaliy Filippov.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
import vcauth
import vclib
import string
import grp
import re
class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
"""A simple authorizer checking system group membership for every
repository and every user."""
def __init__(self, username, params={}):
self.username = username
self.params = params
self.cfg = params['__config']
self.cached = {}
self.grp = {}
self.byroot = {}
self.fmt = map(lambda l: l.strip(), params.get('group_name_format', 'svn.%s|svn.%s.ro').split('|'))
byr = params.get('by_root', '')
for i in byr.split(','):
if i.find(':') < 0:
continue
(root, auth) = i.split(':', 2)
self.byroot[root.strip()] = map(lambda l: l.strip(), auth.split('|'))
def check_root_access(self, rootname):
r = self.cached.get(rootname, None)
if r is not None:
return r
grent = self.grp.get(rootname, None)
if grent is None:
grent = map(lambda grn: self.getgrnam(grn, rootname), self.byroot.get(rootname, self.fmt))
self.grp[rootname] = grent
r = 0
for i in grent:
if i and i.gr_mem and len(i.gr_mem) and self.username in i.gr_mem:
r = 1
break
self.cached[rootname] = r
return r
def getgrnam(self, grn, rootname):
try:
r = grp.getgrnam(grn.replace('%s', re.sub('[^\w\.\-]+', '', rootname)))
except KeyError:
r = None
return r
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
return self.check_root_access(rootname)

View File

@@ -0,0 +1,269 @@
# -*-python-*-
#
# Copyright (C) 2006-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
# (c) 2006 Sergey Lapin <slapin@dataart.com>
import vcauth
import os.path
import debug
from ConfigParser import ConfigParser
class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
"""Subversion authz authorizer module"""
def __init__(self, username, params={}):
self.rootpaths = { } # {root -> { paths -> access boolean for USERNAME }}
# Get the authz file location from a passed-in parameter.
self.authz_file = params.get('authzfile')
if not self.authz_file:
raise debug.ViewVCException("No authzfile configured")
if not os.path.exists(self.authz_file):
raise debug.ViewVCException("Configured authzfile file not found")
# See if the admin wants us to do case normalization of usernames.
self.force_username_case = params.get('force_username_case')
if self.force_username_case == "upper":
self.username = username and username.upper() or username
elif self.force_username_case == "lower":
self.username = username and username.lower() or username
elif not self.force_username_case:
self.username = username
else:
raise debug.ViewVCException("Invalid value for force_username_case "
"option")
def _get_paths_for_root(self, rootname):
if self.rootpaths.has_key(rootname):
return self.rootpaths[rootname]
paths_for_root = { }
# Parse the authz file, replacing ConfigParser's optionxform()
# method with something that won't futz with the case of the
# option names.
cp = ConfigParser()
cp.optionxform = lambda x: x
try:
cp.read(self.authz_file)
except:
raise debug.ViewVCException("Unable to parse configured authzfile file")
# Figure out if there are any aliases for the current username
aliases = []
if cp.has_section('aliases'):
for alias in cp.options('aliases'):
entry = cp.get('aliases', alias)
if entry == self.username:
aliases.append(alias)
# Figure out which groups USERNAME has a part of.
groups = []
if cp.has_section('groups'):
all_groups = []
def _process_group(groupname):
"""Inline function to handle groups within groups.
For a group to be within another group in SVN, the group
definitions must be in the correct order in the config file.
ie. If group A is a member of group B then group A must be
defined before group B in the [groups] section.
Unfortunately, the ConfigParser class provides no way of
finding the order in which groups were defined so, for reasons
of practicality, this function lets you get away with them
being defined in the wrong order. Recursion is guarded
against though."""
# If we already know the user is part of this already-
# processed group, return that fact.
if groupname in groups:
return 1
# Otherwise, ensure we don't process a group twice.
if groupname in all_groups:
return 0
# Store the group name in a global list so it won't be processed again
all_groups.append(groupname)
group_member = 0
groupname = groupname.strip()
entries = cp.get('groups', groupname).split(',')
for entry in entries:
entry = entry.strip()
if entry == self.username:
group_member = 1
break
elif entry[0:1] == "@" and _process_group(entry[1:]):
group_member = 1
break
elif entry[0:1] == "&" and entry[1:] in aliases:
group_member = 1
break
if group_member:
groups.append(groupname)
return group_member
# Process the groups
for group in cp.options('groups'):
_process_group(group)
def _userspec_matches_user(userspec):
# If there is an inversion character, recurse and return the
# opposite result.
if userspec[0:1] == '~':
return not _userspec_matches_user(userspec[1:])
# See if the userspec applies to our current user.
return userspec == '*' \
or userspec == self.username \
or (self.username is not None and userspec == "$authenticated") \
or (self.username is None and userspec == "$anonymous") \
or (userspec[0:1] == "@" and userspec[1:] in groups) \
or (userspec[0:1] == "&" and userspec[1:] in aliases)
def _process_access_section(section):
"""Inline function for determining user access in a single
config secction. Return a two-tuple (ALLOW, DENY) containing
the access determination for USERNAME in a given authz file
SECTION (if any)."""
# Figure if this path is explicitly allowed or denied to USERNAME.
allow = deny = 0
for user in cp.options(section):
user = user.strip()
if _userspec_matches_user(user):
# See if the 'r' permission is among the ones granted to
# USER. If so, we can stop looking. (Entry order is not
# relevant -- we'll use the most permissive entry, meaning
# one 'allow' is all we need.)
allow = cp.get(section, user).find('r') != -1
deny = not allow
if allow:
break
return allow, deny
# Read the other (non-"groups") sections, and figure out in which
# repositories USERNAME or his groups have read rights. We'll
# first check groups that have no specific repository designation,
# then superimpose those that have a repository designation which
# matches the one we're asking about.
root_sections = []
for section in cp.sections():
# Skip the "groups" section -- we handled that already.
if section == 'groups':
continue
if section == 'aliases':
continue
# Process root-agnostic access sections; skip (but remember)
# root-specific ones that match our root; ignore altogether
# root-specific ones that don't match our root. While we're at
# it, go ahead and figure out the repository path we're talking
# about.
if section.find(':') == -1:
path = section
else:
name, path = section.split(':', 1)
if name == rootname:
root_sections.append(section)
continue
# Check for a specific access determination.
allow, deny = _process_access_section(section)
# If we got an explicit access determination for this path and this
# USERNAME, record it.
if allow or deny:
if path != '/':
path = '/' + '/'.join(filter(None, path.split('/')))
paths_for_root[path] = allow
# Okay. Superimpose those root-specific values now.
for section in root_sections:
# Get the path again.
name, path = section.split(':', 1)
# Check for a specific access determination.
allow, deny = _process_access_section(section)
# If we got an explicit access determination for this path and this
# USERNAME, record it.
if allow or deny:
if path != '/':
path = '/' + '/'.join(filter(None, path.split('/')))
paths_for_root[path] = allow
# If the root isn't readable, there's no point in caring about all
# the specific paths the user can't see. Just point the rootname
# to a None paths dictionary.
root_is_readable = 0
for path in paths_for_root.keys():
if paths_for_root[path]:
root_is_readable = 1
break
if not root_is_readable:
paths_for_root = None
self.rootpaths[rootname] = paths_for_root
return paths_for_root
def check_root_access(self, rootname):
paths = self._get_paths_for_root(rootname)
return (paths is not None) and 1 or 0
def check_universal_access(self, rootname):
paths = self._get_paths_for_root(rootname)
if not paths: # None or empty.
return 0
# Search the access determinations. If there's a mix, we can't
# claim a universal access determination.
found_allow = 0
found_deny = 0
for access in paths.values():
if access:
found_allow = 1
else:
found_deny = 1
if found_allow and found_deny:
return None
# We didn't find both allowances and denials, so we must have
# found one or the other. Denials only is a universal denial.
if found_deny:
return 0
# ... but allowances only is only a universal allowance if read
# access is granted to the root directory.
if found_allow and paths.has_key('/'):
return 1
# Anything else is indeterminable.
return None
def check_path_access(self, rootname, path_parts, pathtype, rev=None):
# Crawl upward from the path represented by PATH_PARTS toward to
# the root of the repository, looking for an explicitly grant or
# denial of access.
paths = self._get_paths_for_root(rootname)
if paths is None:
return 0
parts = path_parts[:]
while parts:
path = '/' + '/'.join(parts)
if paths.has_key(path):
return paths[path]
del parts[-1]
return paths.get('/', 0)

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -14,7 +14,6 @@
such as CVS.
"""
import string
import types
@@ -27,11 +26,43 @@ UNIFIED = 1
CONTEXT = 2
SIDE_BY_SIDE = 3
# root types returned by Repository.roottype().
CVS = 'cvs'
SVN = 'svn'
# action kinds found in ChangedPath.action
ADDED = 'added'
DELETED = 'deleted'
REPLACED = 'replaced'
MODIFIED = 'modified'
# log sort keys
SORTBY_DEFAULT = 0 # default/no sorting
SORTBY_DATE = 1 # sorted by date, youngest first
SORTBY_REV = 2 # sorted by revision, youngest first
# ======================================================================
#
class Repository:
"""Abstract class representing a repository."""
def rootname(self):
"""Return the name of this repository."""
def roottype(self):
"""Return the type of this repository (vclib.CVS, vclib.SVN, ...)."""
def rootpath(self):
"""Return the location of this repository."""
def authorizer(self):
"""Return the vcauth.Authorizer object associated with this
repository, or None if no such association has been made."""
def open(self):
"""Open a connection to the repository."""
def itemtype(self, path_parts, rev):
"""Return the type of the item (file or dir) at the given path and revision
@@ -44,7 +75,7 @@ class Repository:
"""
pass
def openfile(self, path_parts, rev):
def openfile(self, path_parts, rev, options):
"""Open a file object to read file contents at a given path and revision.
The return value is a 2-tuple of containg the file object and revision
@@ -54,6 +85,8 @@ class Repository:
of the repository. e.g. ["subdir1", "subdir2", "filename"]
rev is the revision of the file to check out
options is a dictionary of implementation specific options
"""
def listdir(self, path_parts, rev, options):
@@ -75,7 +108,7 @@ class Repository:
New properties will be set on all of the DirEntry objects in the entries
list. At the very least, a "rev" property will be set to a revision
number or None if the entry doesn't have a number. Other properties that
may be set include "date", "author", and "log".
may be set include "date", "author", "log", "size", and "lockinfo".
The path is specified as a list of components, relative to the root
of the repository. e.g. ["subdir1", "subdir2", "filename"]
@@ -89,7 +122,7 @@ class Repository:
options is a dictionary of implementation specific options
"""
def itemlog(self, path_parts, rev, options):
def itemlog(self, path_parts, rev, sortby, first, limit, options):
"""Retrieve an item's log information
The result is a list of Revision objects
@@ -99,9 +132,28 @@ class Repository:
rev is the revision of the item to return information about
sortby indicates the way in which the returned list should be
sorted (SORTBY_DEFAULT, SORTBY_DATE, SORTBY_REV)
first is the 0-based index of the first Revision returned (after
sorting, if any, has occured)
limit is the maximum number of returned Revisions, or 0 to return
all available data
options is a dictionary of implementation specific options
"""
def itemprops(self, path_parts, rev):
"""Return a dictionary mapping property names to property values
for properties stored on an item.
The path is specified as a list of components, relative to the root
of the repository. e.g. ["subdir1", "subdir2", "filename"]
rev is the revision of the item to return information about.
"""
def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
"""Return a diff (in GNU diff format) of two file revisions
@@ -117,29 +169,70 @@ class Repository:
Return value is a python file object
"""
def annotate(self, path_parts, rev):
"""Return a list of annotate file content lines and a revision.
def annotate(self, path_parts, rev, include_text=False):
"""Return a list of Annotation object, sorted by their
"line_number" components, which describe the lines of given
version of a file.
The annotated lines are an collection of objects with the
following addressable members:
The file path is specified as a list of components, relative to
the root of the repository. e.g. ["subdir1", "subdir2", "filename"]
text - raw text of a line of file contents
line_number - line number on which the line is found
rev - revision in which the line was last modified
prev_rev - revision prior to 'rev'
author - author who last modified the line
date - date on which the line was last modified, in seconds
since the epoch, GMT
These object are sort by their line_number components.
"""
rev is the revision of the item to return information about.
If include_text is true, populate the Annotation objects' "text"
members with the corresponding line of file content; otherwise,
leave that member set to None."""
def revinfo(self, rev):
"""Return information about a global revision
rev is the revision of the item to return information about
Return value is a 5-tuple containing: the date, author, log
message, a list of ChangedPath items representing paths changed,
and a dictionary mapping property names to property values for
properties stored on an item.
Raise vclib.UnsupportedFeature if the version control system
doesn't support a global revision concept.
"""
def isexecutable(self, path_parts, rev):
"""Return true iff a given revision of a versioned file is to be
considered an executable program or script.
The path is specified as a list of components, relative to the root
of the repository. e.g. ["subdir1", "subdir2", "filename"]
rev is the revision of the item to return information about
"""
def filesize(self, path_parts, rev):
"""Return the size of a versioned file's contents if it can be
obtained without a brute force measurement; -1 otherwise.
NOTE: Callers that require a filesize answer when this function
returns -1 may obtain it by measuring the data returned via
openfile().
The path is specified as a list of components, relative to the root
of the repository. e.g. ["subdir1", "subdir2", "filename"]
rev is the revision of the item to return information about
"""
# ======================================================================
class DirEntry:
"Instances represent items in a directory listing"
"""Instances represent items in a directory listing"""
def __init__(self, name, kind, errors=[]):
"""Create a new DirEntry() item:
NAME: The name of the directory entry
KIND: The path kind of the entry (vclib.DIR, vclib.FILE)
ERRORS: A list of error strings representing problems encountered
while determining the other info about this entry
"""
self.name = name
self.kind = kind
self.errors = errors
@@ -147,16 +240,17 @@ class DirEntry:
class Revision:
"""Instances holds information about revisions of versioned resources"""
"""Create a new Revision() item:
NUMBER: Revision in an integer-based, sortable format
STRING: Revision as a string
DATE: Seconds since Epoch (GMT) that this revision was created
AUTHOR: Author of the revision
CHANGED: Lines-changed (contextual diff) information
LOG: Log message associated with the creation of this revision
SIZE: Size (in bytes) of this revision's fulltext (files only)
"""
def __init__(self, number, string, date, author, changed, log, size):
def __init__(self, number, string, date, author, changed, log, size, lockinfo):
"""Create a new Revision() item:
NUMBER: Revision in an integer-based, sortable format
STRING: Revision as a string
DATE: Seconds since Epoch (GMT) that this revision was created
AUTHOR: Author of the revision
CHANGED: Lines-changed (contextual diff) information
LOG: Log message associated with the creation of this revision
SIZE: Size (in bytes) of this revision's fulltext (files only)
LOCKINFO: Information about locks held on this revision
"""
self.number = number
self.string = string
self.date = date
@@ -164,23 +258,77 @@ class Revision:
self.changed = changed
self.log = log
self.size = size
self.lockinfo = lockinfo
def __cmp__(self, other):
return cmp(self.number, other.number)
class Annotation:
"""Instances represent per-line file annotation information"""
def __init__(self, text, line_number, rev, prev_rev, author, date):
"""Create a new Annotation() item:
TEXT: Raw text of a line of file contents
LINE_NUMBER: Line number on which the line is found
REV: Revision in which the line was last modified
PREV_REV: Revision prior to 'rev'
AUTHOR: Author who last modified the line
DATE: Date on which the line was last modified, in seconds since
the epoch, GMT
"""
self.text = text
self.line_number = line_number
self.rev = rev
self.prev_rev = prev_rev
self.author = author
self.date = date
class ChangedPath:
"""Instances represent changes to paths"""
def __init__(self, path_parts, rev, pathtype, base_path_parts,
base_rev, action, copied, text_changed, props_changed):
"""Create a new ChangedPath() item:
PATH_PARTS: Path that was changed
REV: Revision represented by this change
PATHTYPE: Type of this path (vclib.DIR, vclib.FILE, ...)
BASE_PATH_PARTS: Previous path for this changed item
BASE_REV: Previous revision for this changed item
ACTION: Kind of change (vclib.ADDED, vclib.DELETED, ...)
COPIED: Boolean -- was this path copied from elsewhere?
TEXT_CHANGED: Boolean -- did the file's text change?
PROPS_CHANGED: Boolean -- did the item's metadata change?
"""
self.path_parts = path_parts
self.rev = rev
self.pathtype = pathtype
self.base_path_parts = base_path_parts
self.base_rev = base_rev
self.action = action
self.copied = copied
self.text_changed = text_changed
self.props_changed = props_changed
# ======================================================================
class Error(Exception):
pass
class ReposNotFound(Error):
pass
class UnsupportedFeature(Error):
pass
class ItemNotFound(Error):
def __init__(self, path):
# use '/' rather than os.sep because this is for user consumption, and
# it was defined using URL separators
if type(path) in (types.TupleType, types.ListType):
path = string.join(path, '/')
path = '/'.join(path)
Error.__init__(self, path)
class InvalidRevision(Error):
def __init__(self, revision=None):
if revision is None:
@@ -188,10 +336,13 @@ class InvalidRevision(Error):
else:
Error.__init__(self, "Invalid revision " + str(revision))
class NonTextualFileContents(Error):
pass
# ======================================================================
# Implementation code used by multiple vclib modules
import popen
import tempfile
import os
import time
@@ -200,12 +351,18 @@ def _diff_args(type, options):
args = []
if type == CONTEXT:
if options.has_key('context'):
args.append('--context=%i' % options['context'])
if options['context'] is None:
args.append('--context=%i' % 0x01ffffff)
else:
args.append('--context=%i' % options['context'])
else:
args.append('-c')
elif type == UNIFIED:
if options.has_key('context'):
args.append('--unified=%i' % options['context'])
if options['context'] is None:
args.append('--unified=%i' % 0x01ffffff)
else:
args.append('--unified=%i' % options['context'])
else:
args.append('-u')
elif type == SIDE_BY_SIDE:
@@ -226,14 +383,18 @@ class _diff_fp:
"""File object reading a diff between temporary files, cleaning up
on close"""
def __init__(self, temp1, temp2, info1=None, info2=None, diff_opts=[]):
def __init__(self, temp1, temp2, info1=None, info2=None, diff_cmd='diff', diff_opts=[]):
self.temp1 = temp1
self.temp2 = temp2
self.temp3 = tempfile.mktemp()
args = diff_opts[:]
if info1 and info2:
args.extend(["-L", self._label(info1), "-L", self._label(info2)])
args.extend([temp1, temp2])
self.fp = popen.popen("diff", args, "r")
args.insert(0, diff_cmd)
os.system("'"+"' '".join(args)+"' > '"+self.temp3+"' 2> '"+self.temp3+"'")
self.fp = open(self.temp3, 'rb')
self.fp.seek(0)
def read(self, bytes):
return self.fp.read(bytes)
@@ -241,6 +402,9 @@ class _diff_fp:
def readline(self):
return self.fp.readline()
def readlines(self):
return self.fp.readlines()
def close(self):
try:
if self.fp:
@@ -248,13 +412,17 @@ class _diff_fp:
self.fp = None
finally:
try:
if self.temp1:
if self.temp1 and self.temp1 != '/dev/null':
os.remove(self.temp1)
self.temp1 = None
self.temp1 = None
finally:
if self.temp2:
if self.temp2 and self.temp2 != '/dev/null':
os.remove(self.temp2)
self.temp2 = None
self.temp2 = None
try:
os.remove(self.temp3)
finally:
self.temp3 = None
def __del__(self):
self.close()
@@ -262,3 +430,28 @@ class _diff_fp:
def _label(self, (path, date, rev)):
date = date and time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date))
return "%s\t%s\t%s" % (path, date, rev)
def check_root_access(repos):
"""Return 1 iff the associated username is permitted to read REPOS,
as determined by consulting REPOS's Authorizer object (if any)."""
auth = repos.authorizer()
if not auth:
return 1
return auth.check_root_access(repos.rootname())
def check_path_access(repos, path_parts, pathtype=None, rev=None):
"""Return 1 iff the associated username is permitted to read
revision REV of the path PATH_PARTS (of type PATHTYPE) in repository
REPOS, as determined by consulting REPOS's Authorizer object (if any)."""
auth = repos.authorizer()
if not auth:
return 1
if not pathtype:
pathtype = repos.itemtype(path_parts, rev)
if not path_parts:
return auth.check_root_access(repos.rootname())
return auth.check_path_access(repos.rootname(), path_parts, pathtype, rev)

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -9,343 +9,59 @@
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
"""
This is a Version Control library driver for locally accessible cvs-repositories.
"""
import os
import string
import re
import cStringIO
import tempfile
import vclib
import rcsparse
import blame
### The functionality shared with bincvs should probably be moved to a
### separate module
from vclib.bincvs import CVSRepository, Revision, Tag, \
_file_log, _log_path
class CCVSRepository(CVSRepository):
def dirlogs(self, path_parts, rev, entries, options):
"""see vclib.Repository.dirlogs docstring
rev can be a tag name or None. if set only information from revisions
matching the tag will be retrieved
Option values recognized by this implementation:
cvs_subdirs
boolean. true to fetch logs of the most recently modified file in each
subdirectory
Option values returned by this implementation:
cvs_tags, cvs_branches
lists of tag and branch names encountered in the directory
"""
subdirs = options.get('cvs_subdirs', 0)
dirpath = self._getpath(path_parts)
alltags = { # all the tags seen in the files of this dir
'MAIN' : '',
'HEAD' : '1.1'
}
for entry in entries:
entry.rev = entry.date = entry.author = entry.dead = entry.log = None
path = _log_path(entry, dirpath, subdirs)
if path:
entry.path = path
try:
rcsparse.Parser().parse(open(path, 'rb'), InfoSink(entry, rev, alltags))
except IOError, e:
entry.errors.append("rcsparse error: %s" % e)
except RuntimeError, e:
entry.errors.append("rcsparse error: %s" % e)
except rcsparse.RCSStopParser:
pass
branches = options['cvs_branches'] = []
tags = options['cvs_tags'] = []
for name, rev in alltags.items():
if Tag(None, rev).is_branch:
branches.append(name)
else:
tags.append(name)
def itemlog(self, path_parts, rev, options):
"""see vclib.Repository.itemlog docstring
rev parameter can be a revision number, a branch number, a tag name,
or None. If None, will return information about all revisions, otherwise,
will only return information about the specified revision or branch.
Option values returned by this implementation:
cvs_tags
dictionary of Tag objects for all tags encountered
"""
path = self.rcsfile(path_parts, 1)
sink = TreeSink()
rcsparse.Parser().parse(open(path, 'rb'), sink)
filtered_revs = _file_log(sink.revs.values(), sink.tags,
sink.default_branch, rev)
for rev in filtered_revs:
if rev.prev and len(rev.number) == 2:
rev.changed = rev.prev.next_changed
options['cvs_tags'] = sink.tags
return filtered_revs
def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
temp1 = tempfile.mktemp()
open(temp1, 'wb').write(self.openfile(path_parts1, rev1)[0].getvalue())
temp2 = tempfile.mktemp()
open(temp2, 'wb').write(self.openfile(path_parts2, rev2)[0].getvalue())
r1 = self.itemlog(path_parts1, rev1, {})[-1]
r2 = self.itemlog(path_parts2, rev2, {})[-1]
info1 = (self.rcsfile(path_parts1, root=1, v=0), r1.date, r1.string)
info2 = (self.rcsfile(path_parts2, root=1, v=0), r2.date, r2.string)
diff_args = vclib._diff_args(type, options)
return vclib._diff_fp(temp1, temp2, info1, info2, diff_args)
def annotate(self, path_parts, rev=None):
source = blame.BlameSource(self.rcsfile(path_parts, 1), rev)
return source, source.revision
def openfile(self, path_parts, rev=None):
path = self.rcsfile(path_parts, 1)
sink = COSink(rev)
rcsparse.Parser().parse(open(path, 'rb'), sink)
revision = sink.last and sink.last.string
return cStringIO.StringIO(string.join(sink.sstext.text, "\n")), revision
class MatchingSink(rcsparse.Sink):
"""Superclass for sinks that search for revisions based on tag or number"""
def __init__(self, find):
"""Initialize with tag name or revision number string to match against"""
if not find or find == 'MAIN' or find == 'HEAD':
self.find = None
else:
self.find = find
self.find_tag = None
def set_principal_branch(self, branch_number):
if self.find is None:
self.find_tag = Tag(None, branch_number)
def define_tag(self, name, revision):
if name == self.find:
self.find_tag = Tag(None, revision)
def admin_completed(self):
if self.find_tag is None:
if self.find is None:
self.find_tag = Tag(None, '')
else:
try:
self.find_tag = Tag(None, self.find)
except ValueError:
pass
class InfoSink(MatchingSink):
def __init__(self, entry, tag, alltags):
MatchingSink.__init__(self, tag)
self.entry = entry
self.alltags = alltags
self.matching_rev = None
self.perfect_match = 0
def define_tag(self, name, revision):
MatchingSink.define_tag(self, name, revision)
self.alltags[name] = revision
def admin_completed(self):
MatchingSink.admin_completed(self)
if self.find_tag is None:
# tag we're looking for doesn't exist
raise rcsparse.RCSStopParser
def define_revision(self, revision, date, author, state, branches, next):
if self.perfect_match:
return
tag = self.find_tag
rev = Revision(revision, date, author, state == "dead")
# perfect match if revision number matches tag number or if revision is on
# trunk and tag points to trunk. imperfect match if tag refers to a branch
# and this revision is the highest revision so far found on that branch
perfect = ((rev.number == tag.number) or
(not tag.number and len(rev.number) == 2))
if perfect or (tag.is_branch and tag.number == rev.number[:-1] and
(not self.matching_rev or
rev.number > self.matching_rev.number)):
self.matching_rev = rev
self.perfect_match = perfect
def set_revision_info(self, revision, log, text):
if self.matching_rev:
if revision == self.matching_rev.string:
self.entry.rev = self.matching_rev.string
self.entry.date = self.matching_rev.date
self.entry.author = self.matching_rev.author
self.entry.dead = self.matching_rev.dead
self.entry.log = log
raise rcsparse.RCSStopParser
else:
raise rcsparse.RCSStopParser
class TreeSink(rcsparse.Sink):
d_command = re.compile('^d(\d+)\\s(\\d+)')
a_command = re.compile('^a(\d+)\\s(\\d+)')
def __init__(self):
self.revs = { }
self.tags = { }
self.head = None
self.default_branch = None
def set_head_revision(self, revision):
self.head = revision
def set_principal_branch(self, branch_number):
self.default_branch = branch_number
def define_tag(self, name, revision):
# check !tags.has_key(tag_name)
self.tags[name] = revision
def define_revision(self, revision, date, author, state, branches, next):
# check !revs.has_key(revision)
self.revs[revision] = Revision(revision, date, author, state == "dead")
def set_revision_info(self, revision, log, text):
# check revs.has_key(revision)
rev = self.revs[revision]
rev.log = log
changed = None
added = 0
deled = 0
if self.head != revision:
changed = 1
lines = string.split(text, '\n')
idx = 0
while idx < len(lines):
command = lines[idx]
dmatch = self.d_command.match(command)
idx = idx + 1
if dmatch:
deled = deled + string.atoi(dmatch.group(2))
else:
amatch = self.a_command.match(command)
if amatch:
count = string.atoi(amatch.group(2))
added = added + count
idx = idx + count
elif command:
raise "error while parsing deltatext: %s" % command
if len(rev.number) == 2:
rev.next_changed = changed and "+%i -%i" % (deled, added)
else:
rev.changed = changed and "+%i -%i" % (added, deled)
class StreamText:
d_command = re.compile('^d(\d+)\\s(\\d+)')
a_command = re.compile('^a(\d+)\\s(\\d+)')
def __init__(self, text):
self.text = string.split(text, "\n")
def command(self, cmd):
adjust = 0
add_lines_remaining = 0
diffs = string.split(cmd, "\n")
if diffs[-1] == "":
del diffs[-1]
if len(diffs) == 0:
return
if diffs[0] == "":
del diffs[0]
for command in diffs:
if add_lines_remaining > 0:
# Insertion lines from a prior "a" command
self.text.insert(start_line + adjust, command)
add_lines_remaining = add_lines_remaining - 1
adjust = adjust + 1
continue
dmatch = self.d_command.match(command)
amatch = self.a_command.match(command)
if dmatch:
# "d" - Delete command
start_line = string.atoi(dmatch.group(1))
count = string.atoi(dmatch.group(2))
begin = start_line + adjust - 1
del self.text[begin:begin + count]
adjust = adjust - count
elif amatch:
# "a" - Add command
start_line = string.atoi(amatch.group(1))
count = string.atoi(amatch.group(2))
add_lines_remaining = count
else:
raise RuntimeError, 'Error parsing diff commands'
def secondnextdot(s, start):
# find the position the second dot after the start index.
return string.find(s, '.', string.find(s, '.', start) + 1)
import os.path
import time
class COSink(MatchingSink):
def __init__(self, rev):
MatchingSink.__init__(self, rev)
def cvs_strptime(timestr):
return time.strptime(timestr, '%Y/%m/%d %H:%M:%S')[:-1] + (0,)
def set_head_revision(self, revision):
self.head = Revision(revision)
self.last = None
self.sstext = None
def admin_completed(self):
MatchingSink.admin_completed(self)
if self.find_tag is None:
raise vclib.InvalidRevision(self.find)
def canonicalize_rootpath(rootpath):
assert os.path.isabs(rootpath)
return os.path.normpath(rootpath)
def set_revision_info(self, revision, log, text):
tag = self.find_tag
rev = Revision(revision)
if rev.number == tag.number:
self.log = log
def _is_cvsroot(path):
return os.path.exists(os.path.join(path, "CVSROOT", "config"))
depth = len(rev.number)
if rev.number == self.head.number:
assert self.sstext is None
self.sstext = StreamText(text)
elif (depth == 2 and tag.number and rev.number >= tag.number[:depth]):
assert len(self.last.number) == 2
assert rev.number < self.last.number
self.sstext.command(text)
elif (depth > 2 and rev.number[:depth-1] == tag.number[:depth-1] and
(rev.number <= tag.number or len(tag.number) == depth-1)):
assert len(rev.number) - len(self.last.number) in (0, 2)
assert rev.number > self.last.number
self.sstext.command(text)
else:
rev = None
def expand_root_parent(parent_path):
# Each subdirectory of PARENT_PATH that contains a child
# "CVSROOT/config" is added the set of returned roots. Or, if the
# PARENT_PATH itself contains a child "CVSROOT/config", then all its
# subdirectories are returned as roots.
assert os.path.isabs(parent_path)
roots = {}
subpaths = os.listdir(parent_path)
for rootname in subpaths:
rootpath = os.path.join(parent_path, rootname)
if _is_cvsroot(parent_path) or _is_cvsroot(rootpath):
roots[rootname] = canonicalize_rootpath(rootpath)
return roots
if rev:
#print "tag =", tag.number, "rev =", rev.number, "<br>"
self.last = rev
def find_root_in_parent(parent_path, rootname):
"""Search PARENT_PATH for a root named ROOTNAME, returning the
canonicalized ROOTPATH of the root if found; return None if no such
root is found."""
# Is PARENT_PATH itself a CVS repository? If so, we allow ROOTNAME
# to be any subdir within it. Otherwise, we expect
# PARENT_PATH/ROOTNAME to be a CVS repository.
assert os.path.isabs(parent_path)
rootpath = os.path.join(parent_path, rootname)
if (_is_cvsroot(parent_path) and os.path.exists(rootpath)) \
or _is_cvsroot(rootpath):
return canonicalize_rootpath(rootpath)
return None
def CVSRepository(name, rootpath, authorizer, utilities, use_rcsparse, charset_guesser = None):
rootpath = canonicalize_rootpath(rootpath)
if use_rcsparse:
import ccvs
return ccvs.CCVSRepository(name, rootpath, authorizer, utilities, charset_guesser)
else:
import bincvs
return bincvs.BinCVSRepository(name, rootpath, authorizer, utilities, charset_guesser)

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -13,65 +13,118 @@
"Version Control lib driver for locally accessible cvs-repositories."
import vclib
import vcauth
import os
import os.path
import sys
import stat
import string
import re
import time
import cvsdb
import socket
import calendar
# ViewVC libs
import compat
import popen
import vclib.ccvs
class CVSRepository(vclib.Repository):
def __init__(self, name, rootpath):
def _path_join(path_parts):
return '/'.join(path_parts)
class BaseCVSRepository(vclib.Repository):
def __init__(self, name, rootpath, authorizer, utilities, charset_guesser = None):
if not os.path.isdir(rootpath):
raise vclib.ReposNotFound(name)
self.name = name
self.rootpath = rootpath
self.auth = authorizer
self.utilities = utilities
self.guesser = charset_guesser
# See if this repository is even viewable, authz-wise.
if not vclib.check_root_access(self):
raise vclib.ReposNotFound(name)
def open(self):
# See if a universal read access determination can be made.
if self.auth and self.auth.check_universal_access(self.name) == 1:
self.auth = None
def rootname(self):
return self.name
def rootpath(self):
return self.rootpath
def roottype(self):
return vclib.CVS
def authorizer(self):
return self.auth
def itemtype(self, path_parts, rev):
basepath = self._getpath(path_parts)
kind = None
if os.path.isdir(basepath):
return vclib.DIR
if os.path.isfile(basepath + ',v'):
return vclib.FILE
atticpath = self._getpath(self._atticpath(path_parts))
if os.path.isfile(atticpath + ',v'):
return vclib.FILE
raise vclib.ItemNotFound(path_parts)
kind = vclib.DIR
elif os.path.isfile(basepath + ',v'):
kind = vclib.FILE
else:
atticpath = self._getpath(self._atticpath(path_parts))
if os.path.isfile(atticpath + ',v'):
kind = vclib.FILE
if not kind:
raise vclib.ItemNotFound(path_parts)
if not vclib.check_path_access(self, path_parts, kind, rev):
raise vclib.ItemNotFound(path_parts)
return kind
def itemprops(self, path_parts, rev):
self.itemtype(path_parts, rev) # does auth-check
return {} # CVS doesn't support properties
def listdir(self, path_parts, rev, options):
if self.itemtype(path_parts, rev) != vclib.DIR: # does auth-check
raise vclib.Error("Path '%s' is not a directory."
% (_path_join(path_parts)))
# Only RCS files (*,v) and subdirs are returned.
data = [ ]
full_name = self._getpath(path_parts)
for file in os.listdir(full_name):
name = None
kind, errors = _check_path(os.path.join(full_name, file))
if kind == vclib.FILE:
if file[-2:] == ',v':
data.append(CVSDirEntry(file[:-2], kind, errors, 0))
name = file[:-2]
elif kind == vclib.DIR:
if file != 'Attic' and file != 'CVS': # CVS directory is for fileattr
data.append(CVSDirEntry(file, kind, errors, 0))
name = file
else:
data.append(CVSDirEntry(file, kind, errors, 0))
name = file
if not name:
continue
if vclib.check_path_access(self, path_parts + [name], kind, rev):
data.append(CVSDirEntry(name, kind, errors, 0))
full_name = os.path.join(full_name, 'Attic')
if os.path.isdir(full_name):
for file in os.listdir(full_name):
name = None
kind, errors = _check_path(os.path.join(full_name, file))
if kind == vclib.FILE:
if file[-2:] == ',v':
data.append(CVSDirEntry(file[:-2], kind, errors, 1))
name = file[:-2]
elif kind != vclib.DIR:
data.append(CVSDirEntry(file, kind, errors, 1))
name = file
if not name:
continue
if vclib.check_path_access(self, path_parts + [name], kind, rev):
data.append(CVSDirEntry(name, kind, errors, 1))
return data
def _getpath(self, path_parts):
return apply(os.path.join, (self.rootpath,) + tuple(path_parts))
@@ -88,48 +141,64 @@ class CVSRepository(vclib.Repository):
ret_file = self._getpath(ret_parts)
if not os.path.isfile(ret_file + ',v'):
raise vclib.ItemNotFound(path_parts)
if root:
ret = ret_file
else:
ret = string.join(ret_parts, "/")
ret = _path_join(ret_parts)
if v:
ret = ret + ",v"
return ret
class BinCVSRepository(CVSRepository):
def __init__(self, name, rootpath, rcs_paths):
CVSRepository.__init__(self, name, rootpath)
self.rcs_paths = rcs_paths
def isexecutable(self, path_parts, rev):
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file." % (_path_join(path_parts)))
rcsfile = self.rcsfile(path_parts, 1)
return os.access(rcsfile, os.X_OK)
def filesize(self, path_parts, rev):
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file." % (_path_join(path_parts)))
return -1
class BinCVSRepository(BaseCVSRepository):
def _get_tip_revision(self, rcs_file, rev=None):
"""Get the (basically) youngest revision (filtered by REV)."""
args = rcs_file,
fp = self.rcs_popen('rlog', args, 'rt', 0)
filename, default_branch, tags, msg, eof = _parse_log_header(fp)
filename, default_branch, tags, lockinfo, msg, eof = _parse_log_header(fp)
revs = []
while not eof:
revision, eof = _parse_log_entry(fp)
revision, eof = _parse_log_entry(fp, self.guesser)
if revision:
revs.append(revision)
revs = _file_log(revs, tags, default_branch, rev)
revs = _file_log(revs, tags, lockinfo, default_branch, rev)
if revs:
return revs[-1]
return None
def openfile(self, path_parts, rev):
def openfile(self, path_parts, rev, options):
"""see vclib.Repository.openfile docstring
Option values recognized by this implementation:
cvs_oldkeywords
boolean. true to use the original keyword substitution values.
"""
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file." % (_path_join(path_parts)))
if not rev or rev == 'HEAD' or rev == 'MAIN':
rev_flag = '-p'
else:
rev_flag = '-p' + rev
if options.get('cvs_oldkeywords', 0):
kv_flag = '-ko'
else:
kv_flag = '-kkv'
full_name = self.rcsfile(path_parts, root=1, v=0)
used_rlog = 0
tip_rev = None # used only if we have to fallback to using rlog
fp = self.rcs_popen('co', (rev_flag, full_name), 'rb')
fp = self.rcs_popen('co', (kv_flag, rev_flag, full_name), 'rb')
try:
filename, revision = _parse_co_header(fp)
except COMissingRevision:
@@ -143,14 +212,14 @@ class BinCVSRepository(CVSRepository):
used_rlog = 1
if not tip_rev:
raise vclib.Error("Unable to find valid revision")
fp = self.rcs_popen('co', ('-p' + tip_rev.string, full_name), 'rb')
fp = self.rcs_popen('co', ('-p' + tip_rev.string, full_name), 'rb')
filename, revision = _parse_co_header(fp)
if filename is None:
# CVSNT's co exits without any output if a dead revision is requested.
# Bug at http://www.cvsnt.org/cgi-bin/bugzilla/show_bug.cgi?id=190
# As a workaround, we invoke rlog to find the first non-dead revision
# that precedes it and check out that revision instead. Of course,
# that precedes it and check out that revision instead. Of course,
# if we've already invoked rlog above, we just reuse its output.
if not used_rlog:
tip_rev = self._get_tip_revision(full_name + ',v', rev)
@@ -159,7 +228,7 @@ class BinCVSRepository(CVSRepository):
raise vclib.Error(
'Could not find non-dead revision preceding "%s"' % rev)
fp = self.rcs_popen('co', ('-p' + tip_rev.undead.string,
full_name), 'rb')
full_name), 'rb')
filename, revision = _parse_co_header(fp)
if filename is None:
@@ -189,11 +258,16 @@ class BinCVSRepository(CVSRepository):
cvs_tags, cvs_branches
lists of tag and branch names encountered in the directory
"""
if self.itemtype(path_parts, rev) != vclib.DIR: # does auth-check
raise vclib.Error("Path '%s' is not a directory."
% (_path_join(path_parts)))
subdirs = options.get('cvs_subdirs', 0)
dirpath = self._getpath(path_parts)
alltags = _get_logs(self, dirpath, entries, rev, subdirs)
entries_to_fetch = []
for entry in entries:
if vclib.check_path_access(self, path_parts + [entry.name], None, rev):
entries_to_fetch.append(entry)
alltags = _get_logs(self, path_parts, entries_to_fetch, rev, subdirs, self.guesser)
branches = options['cvs_branches'] = []
tags = options['cvs_tags'] = []
for name, rev in alltags.items():
@@ -202,7 +276,7 @@ class BinCVSRepository(CVSRepository):
else:
tags.append(name)
def itemlog(self, path_parts, rev, options):
def itemlog(self, path_parts, rev, sortby, first, limit, options):
"""see vclib.Repository.itemlog docstring
rev parameter can be a revision number, a branch number, a tag name,
@@ -222,6 +296,9 @@ class BinCVSRepository(CVSRepository):
dictionary of Tag objects for all tags encountered
"""
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file." % (_path_join(path_parts)))
# Invoke rlog
rcsfile = self.rcsfile(path_parts, 1)
if rev and options.get('cvs_pass_rev', 0):
@@ -230,35 +307,60 @@ class BinCVSRepository(CVSRepository):
args = rcsfile,
fp = self.rcs_popen('rlog', args, 'rt', 0)
filename, default_branch, tags, msg, eof = _parse_log_header(fp)
filename, default_branch, tags, lockinfo, msg, eof = _parse_log_header(fp)
# Retrieve revision objects
revs = []
while not eof:
revision, eof = _parse_log_entry(fp)
revision, eof = _parse_log_entry(fp, self.guesser)
if revision:
revs.append(revision)
filtered_revs = _file_log(revs, tags, default_branch, rev)
filtered_revs = _file_log(revs, tags, lockinfo, default_branch, rev)
options['cvs_tags'] = tags
if sortby == vclib.SORTBY_DATE:
filtered_revs.sort(_logsort_date_cmp)
elif sortby == vclib.SORTBY_REV:
filtered_revs.sort(_logsort_rev_cmp)
if len(filtered_revs) < first:
return []
if limit:
return filtered_revs[first:first+limit]
return filtered_revs
def rcs_popen(self, rcs_cmd, rcs_args, mode, capture_err=1):
if self.rcs_paths.cvsnt_exe_path:
cmd = self.rcs_paths.cvsnt_exe_path
a = []
if self.utilities.rcsfile_socket:
a = self.utilities.rcsfile_socket.split(':')
if len(a) == 2:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((a[0], int(a[1])))
s = s.makefile()
s.write('\''+rcs_cmd+'\' \''+'\' \''.join(rcs_args)+"\'\x0d\x0a")
s.flush()
return s
elif self.utilities.cvsnt:
cmd = self.utilities.cvsnt
args = ['rcsfile', rcs_cmd]
args.extend(list(rcs_args))
else:
cmd = os.path.join(self.rcs_paths.rcs_path, rcs_cmd)
cmd = os.path.join(self.utilities.rcs_dir, rcs_cmd)
args = rcs_args
return popen.popen(cmd, args, mode, capture_err)
def annotate(self, path_parts, rev=None):
def annotate(self, path_parts, rev=None, include_text=False):
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file." % (_path_join(path_parts)))
from vclib.ccvs import blame
source = blame.BlameSource(self.rcsfile(path_parts, 1), rev)
source = blame.BlameSource(self.rcsfile(path_parts, 1), rev, self.guesser, include_text)
return source, source.revision
def revinfo(self, rev):
raise vclib.UnsupportedFeature
def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
"""see vclib.Repository.rawdiff docstring
@@ -266,6 +368,17 @@ class BinCVSRepository(CVSRepository):
ignore_keyword_subst - boolean, ignore keyword substitution
"""
if not path_parts1:
path_parts1 = path_parts2
rev1 = '1.0'
if not path_parts2:
path_parts2 = path_parts1
rev2 = '1.0'
if self.itemtype(path_parts1, rev1) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file." % (_path_join(path_parts1)))
if self.itemtype(path_parts2, rev2) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file." % (_path_join(path_parts2)))
args = vclib._diff_args(type, options)
if options.get('ignore_keyword_subst', 0):
args.append('-kk')
@@ -273,8 +386,7 @@ class BinCVSRepository(CVSRepository):
rcsfile = self.rcsfile(path_parts1, 1)
if path_parts1 != path_parts2:
raise NotImplementedError, "cannot diff across paths in cvs"
args.extend(['-r' + rev1, '-r' + rev2, rcsfile])
args.extend(['-N', '-r' + rev1, '-r' + rev2, rcsfile])
fp = self.rcs_popen('rcsdiff', args, 'rt')
# Eat up the non-GNU-diff-y headers.
@@ -283,18 +395,18 @@ class BinCVSRepository(CVSRepository):
if not line or line[0:5] == 'diff ':
break
return fp
class CVSDirEntry(vclib.DirEntry):
def __init__(self, name, kind, errors, in_attic):
def __init__(self, name, kind, errors, in_attic, absent=0):
vclib.DirEntry.__init__(self, name, kind, errors)
self.in_attic = in_attic
self.absent = absent # meaning, no revisions found on requested tag
class Revision(vclib.Revision):
def __init__(self, revstr, date=None, author=None, dead=None,
changed=None, log=None):
vclib.Revision.__init__(self, _revision_tuple(revstr), revstr,
date, author, changed, log, None)
date, author, changed, log, None, None)
self.dead = dead
class Tag:
@@ -307,6 +419,14 @@ class Tag:
# ======================================================================
# Functions for dealing with Revision and Tag objects
def _logsort_date_cmp(rev1, rev2):
# sort on date; secondary on revision number
return -cmp(rev1.date, rev2.date) or -cmp(rev1.number, rev2.number)
def _logsort_rev_cmp(rev1, rev2):
# sort highest revision first
return -cmp(rev1.number, rev2.number)
def _match_revs_tags(revlist, taglist):
"""Match up a list of Revision objects with a list of Tag objects
@@ -336,9 +456,9 @@ def _match_revs_tags(revlist, taglist):
example: if revision is 1.2.3.4, parent is 1.2
"undead"
If the revision is dead, then this is a reference to the first
If the revision is dead, then this is a reference to the first
previous revision which isn't dead, otherwise it's a reference
to itself. If all the previous revisions are dead it's None.
to itself. If all the previous revisions are dead it's None.
"branch_number"
tuple representing branch number or empty tuple if on trunk
@@ -463,7 +583,7 @@ def _remove_tag(tag):
def _revision_tuple(revision_string):
"""convert a revision number into a tuple of integers"""
t = tuple(map(int, string.split(revision_string, '.')))
t = tuple(map(int, revision_string.split('.')))
if len(t) % 2 == 0:
return t
raise ValueError
@@ -471,10 +591,10 @@ def _revision_tuple(revision_string):
def _tag_tuple(revision_string):
"""convert a revision number or branch number into a tuple of integers"""
if revision_string:
t = map(int, string.split(revision_string, '.'))
t = map(int, revision_string.split('.'))
l = len(t)
if l == 1:
raise ValueError
return ()
if l > 2 and t[-2] == 0 and l % 2 == 0:
del t[-2]
return tuple(t)
@@ -534,30 +654,24 @@ def _parse_co_header(fp):
raise COMalformedOutput, "Unable to find filename in co output stream"
filename = match.group(1)
# look for a revision in the second line.
line = fp.readline()
if not line:
raise COMalformedOutput, "Missing second line from co output stream"
match = _re_co_revision.match(line)
if match:
return filename, match.group(1)
elif _re_co_missing_rev.match(line) or _re_co_side_branches.match(line):
raise COMissingRevision, "Got missing revision error from co output stream"
elif _re_co_warning.match(line):
pass
else:
raise COMalformedOutput, "Unable to find revision in co output stream"
# if we get here, the second line wasn't a revision, but it was a
# warning we can ignore. look for a revision in the third line.
line = fp.readline()
if not line:
raise COMalformedOutput, "Missing third line from co output stream"
match = _re_co_revision.match(line)
if match:
return filename, match.group(1)
raise COMalformedOutput, "Unable to find revision in co output stream"
# look through subsequent lines for a revision. we might encounter
# some ignorable or problematic lines along the way.
while 1:
line = fp.readline()
if not line:
break
# look for a revision.
match = _re_co_revision.match(line)
if match:
return filename, match.group(1)
elif _re_co_missing_rev.match(line) or _re_co_side_branches.match(line):
raise COMissingRevision, "Got missing revision error from co output stream"
elif _re_co_warning.match(line):
pass
else:
break
raise COMalformedOutput, "Unable to find revision in co output stream"
# if your rlog doesn't use 77 '=' characters, then this must change
LOG_END_MARKER = '=' * 77 + '\n'
@@ -577,7 +691,7 @@ _EOF_ERROR = 'error message found' # rlog issued an error
# ^rlog\: (.*)(?:\:\d+)?\: (.*)$
#
# But for some reason the windows version of rlog omits the "rlog: " prefix
# for the first error message when the standard error stream has been
# for the first error message when the standard error stream has been
# redirected to a file or pipe. (the prefix is present in subsequent errors
# and when rlog is run from the console). So the expression below is more
# complicated
@@ -603,13 +717,14 @@ def _parse_log_header(fp):
If there is no revision information (e.g. the "-h" switch was passed to
rlog), then fp will consumed the file separator line on exit.
Returns: filename, default branch, tag dictionary, rlog error message,
and eof flag
Returns: filename, default branch, tag dictionary, lock dictionary,
rlog error message, and eof flag
"""
filename = head = branch = msg = ""
taginfo = { } # tag name => number
parsing_tags = 0
filename = head = branch = msg = ""
taginfo = { } # tag name => number
lockinfo = { } # revision => locker
state = 0 # 0 = base, 1 = parsing symbols, 2 = parsing locks
eof = None
while 1:
@@ -619,24 +734,35 @@ def _parse_log_header(fp):
eof = _EOF_LOG
break
if parsing_tags:
if state == 1:
if line[0] == '\t':
[ tag, rev ] = map(string.strip, string.split(line, ':'))
[ tag, rev ] = map(lambda x: x.strip(), line.split(':'))
taginfo[tag] = rev
else:
# oops. this line isn't tag info. stop parsing tags.
parsing_tags = 0
state = 0
if not parsing_tags:
if state == 2:
if line[0] == '\t':
[ locker, rev ] = map(lambda x: x.strip(), line.split(':'))
lockinfo[rev] = locker
else:
# oops. this line isn't lock info. stop parsing tags.
state = 0
if state == 0:
if line[:9] == 'RCS file:':
filename = line[10:-1]
elif line[:5] == 'head:':
head = line[6:-1]
elif line[:7] == 'branch:':
branch = line[8:-1]
elif line[:6] == 'locks:':
# start parsing the lock information
state = 2
elif line[:14] == 'symbolic names':
# start parsing the tag information
parsing_tags = 1
state = 1
elif line == ENTRY_END_MARKER:
# end of the headers
break
@@ -665,15 +791,16 @@ def _parse_log_header(fp):
eof = _EOF_ERROR
break
return filename, branch, taginfo, msg, eof
return filename, branch, taginfo, lockinfo, msg, eof
_re_log_info = re.compile(r'^date:\s+([^;]+);'
r'\s+author:\s+([^;]+);'
r'\s+state:\s+([^;]+);'
r'(\s+lines:\s+([0-9\s+-]+))?\n$')
r'(\s+lines:\s+([0-9\s+-]+);?)?'
r'(\s+commitid:\s+([a-zA-Z0-9]+))?\n$')
### _re_rev should be updated to extract the "locked" flag
_re_rev = re.compile(r'^revision\s+([0-9.]+).*')
def _parse_log_entry(fp):
def _parse_log_entry(fp, guesser):
"""Parse a single log entry.
On entry, fp should point to the first line of the entry (the "revision"
@@ -726,7 +853,7 @@ def _parse_log_entry(fp):
return None, eof
# parse out a time tuple for the local time
tm = compat.cvs_strptime(match.group(1))
tm = vclib.ccvs.cvs_strptime(match.group(1))
# rlog seems to assume that two-digit years are 1900-based (so, "04"
# comes out as "1904", not "2004").
@@ -737,7 +864,10 @@ def _parse_log_entry(fp):
tm[0] = tm[0] + 100
if tm[0] < EPOCH:
raise ValueError, 'invalid year'
date = compat.timegm(tm)
date = calendar.timegm(tm)
if guesser:
log = guesser.utf8(log)
return Revision(rev, date,
# author, state, lines changed
@@ -764,7 +894,7 @@ def _paths_eq(path1, path2):
# ======================================================================
# Functions for interpreting and manipulating log information
def _file_log(revs, taginfo, cur_branch, filter):
def _file_log(revs, taginfo, lockinfo, cur_branch, filter):
"""Augment list of Revisions and a dictionary of Tags"""
# Add artificial ViewVC tag MAIN. If the file has a default branch, then
@@ -790,17 +920,21 @@ def _file_log(revs, taginfo, cur_branch, filter):
except ValueError:
view_tag = None
else:
tags.append(view_tag)
tags.append(view_tag)
# Match up tags and revisions
_match_revs_tags(revs, tags)
# Match up lockinfo and revision
for rev in revs:
rev.lockinfo = lockinfo.get(rev.string)
# Add artificial ViewVC tag HEAD, which acts like a non-branch tag pointing
# at the latest revision on the MAIN branch. The HEAD revision doesn't have
# anything to do with the "head" revision number specified in the RCS file
# and in rlog output. HEAD refers to the revision that the CVS and RCS co
# commands will check out by default, whereas the "head" field just refers
# to the highest revision on the trunk.
# to the highest revision on the trunk.
taginfo['HEAD'] = _add_tag('HEAD', taginfo['MAIN'].co_rev)
# Determine what revisions to return
@@ -838,10 +972,10 @@ def _file_log(revs, taginfo, cur_branch, filter):
_remove_tag(view_tag)
else:
filtered_revs = revs
return filtered_revs
def _get_logs(repos, dirpath, entries, view_tag, get_dirs):
def _get_logs(repos, dir_path_parts, entries, view_tag, get_dirs, guesser):
alltags = { # all the tags seen in the files of this dir
'MAIN' : '',
'HEAD' : '1.1'
@@ -856,14 +990,15 @@ def _get_logs(repos, dirpath, entries, view_tag, get_dirs):
while len(chunk) < max_args and entries_idx < entries_len:
entry = entries[entries_idx]
path = _log_path(entry, dirpath, get_dirs)
path = _log_path(entry, repos._getpath(dir_path_parts), get_dirs)
if path:
entry.path = path
entry.idx = entries_idx
chunk.append(entry)
# set properties even if we don't retrieve logs
entry.rev = entry.date = entry.author = entry.dead = entry.log = None
entry.rev = entry.date = entry.author = None
entry.dead = entry.log = entry.lockinfo = None
entries_idx = entries_idx + 1
@@ -883,10 +1018,11 @@ def _get_logs(repos, dirpath, entries, view_tag, get_dirs):
chunk_idx = 0
while chunk_idx < len(chunk):
file = chunk[chunk_idx]
filename, default_branch, taginfo, msg, eof = _parse_log_header(rlog)
filename, default_branch, taginfo, lockinfo, msg, eof \
= _parse_log_header(rlog)
if eof == _EOF_LOG:
# the rlog output ended early. this can happen on errors that rlog
# the rlog output ended early. this can happen on errors that rlog
# thinks are so serious that it stops parsing the current file and
# refuses to parse any of the files that come after it. one of the
# errors that triggers this obnoxious behavior looks like:
@@ -922,20 +1058,20 @@ def _get_logs(repos, dirpath, entries, view_tag, get_dirs):
file.errors.append("rlog error: %s" % msg)
continue
tag = None
if view_tag == 'MAIN' or view_tag == 'HEAD':
tag = Tag(None, default_branch)
elif taginfo.has_key(view_tag):
tag = Tag(None, taginfo[view_tag])
elif view_tag:
# the tag wasn't found, so skip this file
elif view_tag and (eof != _EOF_FILE):
# the tag wasn't found, so skip this file (unless we already
# know there's nothing left of it to read)
_skip_file(rlog)
eof = 1
else:
tag = None
eof = _EOF_FILE
# we don't care about the specific values -- just the keys and whether
# the values point to branches or revisions. this the fastest way to
# merge the set of keys and keep values that allow us to make the
# the values point to branches or revisions. this the fastest way to
# merge the set of keys and keep values that allow us to make the
# distinction between branch tags and normal tags
alltags.update(taginfo)
@@ -944,7 +1080,7 @@ def _get_logs(repos, dirpath, entries, view_tag, get_dirs):
while not eof:
# fetch one of the log entries
entry, eof = _parse_log_entry(rlog)
entry, eof = _parse_log_entry(rlog, guesser)
if not entry:
# parsing error
@@ -971,12 +1107,15 @@ def _get_logs(repos, dirpath, entries, view_tag, get_dirs):
file.date = wanted_entry.date
file.author = wanted_entry.author
file.dead = file.kind == vclib.FILE and wanted_entry.dead
file.absent = 0
file.log = wanted_entry.log
file.lockinfo = lockinfo.get(file.rev)
# suppress rlog errors if we find a usable revision in the end
del file.errors[:]
elif file.kind == vclib.FILE:
file.dead = 1
file.errors.append("No revisions exist on %s" % (view_tag or "MAIN"))
file.dead = 0
#file.errors.append("No revisions exist on %s" % (view_tag or "MAIN"))
file.absent = 1
# done with this file now, skip the rest of this file's revisions
if not eof:
@@ -1089,6 +1228,8 @@ def _newest_file(dirpath):
newest_file = None
newest_time = 0
### FIXME: This sucker is leaking unauthorized paths! ###
for subfile in os.listdir(dirpath):
### filter CVS locks? stale NFS handles?
if subfile[-2:] != ',v':

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 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
@@ -26,11 +26,12 @@
#
# -----------------------------------------------------------------------
import string
import re
import time
import math
import rcsparse
import vclib
import cvsdb
class CVSParser(rcsparse.Sink):
# Precompiled regular expressions
@@ -99,7 +100,7 @@ class CVSParser(rcsparse.Sink):
# Split deltatext specified by rev to each line.
def deltatext_split(self, rev):
lines = string.split(self.revision_deltatext[rev], '\n')
lines = self.revision_deltatext[rev].split('\n')
if lines[-1] == '':
del lines[-1]
return lines
@@ -138,16 +139,16 @@ class CVSParser(rcsparse.Sink):
adjust = adjust + 1
elif dmatch:
# "d" - Delete command
start_line = string.atoi(dmatch.group(1))
count = string.atoi(dmatch.group(2))
start_line = int(dmatch.group(1))
count = int(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))
start_line = int(amatch.group(1))
count = int(amatch.group(2))
add_lines_remaining = count
lines_added_now = lines_added_now + count
else:
@@ -267,7 +268,7 @@ class CVSParser(rcsparse.Sink):
raise RuntimeError, ('error: %s appeared to be under CVS control, ' +
'but the RCS file is inaccessible.') % rcs_pathname
rcsparse.Parser().parse(rcsfile, self)
rcsparse.parse(rcsfile, self)
rcsfile.close()
if opt_rev in [None, '', 'HEAD']:
@@ -310,13 +311,13 @@ class CVSParser(rcsparse.Sink):
skip = skip - 1
elif dmatch:
# "d" - Delete command
start_line = string.atoi(dmatch.group(1))
count = string.atoi(dmatch.group(2))
start_line = int(dmatch.group(1))
count = int(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))
start_line = int(amatch.group(1))
count = int(amatch.group(2))
skip = count
line_count = line_count + count
else:
@@ -346,7 +347,7 @@ class CVSParser(rcsparse.Sink):
is_trunk_revision = self.trunk_rev.match(revision) is not None
if is_trunk_revision:
diffs = self.deltatext_split(last_revision)
diffs = self.deltatext_split(last_revision)
# Revisions on the trunk specify deltas that transform a
# revision into an earlier revision, so invert the translation
@@ -358,8 +359,8 @@ class CVSParser(rcsparse.Sink):
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))
start_line = int(dmatch.group(1))
count = int(dmatch.group(2))
temp = []
while count > 0:
temp.append(revision)
@@ -367,8 +368,8 @@ class CVSParser(rcsparse.Sink):
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))
start_line = int(amatch.group(1))
count = int(amatch.group(2))
del self.revision_map[start_line:start_line + count]
skip = count
else:
@@ -379,7 +380,7 @@ class CVSParser(rcsparse.Sink):
# the trunk. They specify deltas that transform a revision
# into a later revision.
adjust = 0
diffs = self.deltatext_split(revision)
diffs = self.deltatext_split(revision)
for command in diffs:
if skip > 0:
skip = skip - 1
@@ -387,15 +388,15 @@ class CVSParser(rcsparse.Sink):
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))
start_line = int(dmatch.group(1))
count = int(dmatch.group(2))
adj_begin = start_line + adjust - 1
adj_end = start_line + adjust - 1 + count
del self.revision_map[adj_begin:adj_end]
adjust = adjust - count
elif amatch:
start_line = string.atoi(amatch.group(1))
count = string.atoi(amatch.group(2))
start_line = int(amatch.group(1))
count = int(amatch.group(2))
skip = count
temp = []
while count > 0:
@@ -413,7 +414,7 @@ class CVSParser(rcsparse.Sink):
class BlameSource:
def __init__(self, rcs_file, opt_rev=None):
def __init__(self, rcs_file, opt_rev=None, charset_guesser=None, include_text=False):
# Parse the CVS file
parser = CVSParser()
revision = parser.parse_cvs_file(rcs_file, opt_rev)
@@ -427,6 +428,8 @@ class BlameSource:
self.lines = lines
self.num_lines = count
self.parser = parser
self.guesser = charset_guesser
self.include_text = include_text
# keep track of where we are during an iteration
self.idx = -1
@@ -445,10 +448,16 @@ class BlameSource:
prev_rev = self.parser.prev_revision.get(rev)
line_number = idx + 1
author = self.parser.revision_author[rev]
thisline = self.lines[idx]
if not self.include_text:
thisline = None
elif self.guesser:
thisline = self.guesser.utf8(self.lines[idx])
else:
thisline = self.lines[idx]
### TODO: Put a real date in here.
item = _item(text=thisline, line_number=line_number, rev=rev,
prev_rev=prev_rev, author=author, date=None)
item = vclib.Annotation(thisline, line_number, rev, prev_rev, author, None)
self.last = item
self.idx = idx
return item
@@ -456,9 +465,3 @@ class BlameSource:
class BlameSequencingError(Exception):
pass
class _item:
def __init__(self, **kw):
vars(self).update(kw)

417
lib/vclib/ccvs/ccvs.py Normal file
View File

@@ -0,0 +1,417 @@
# -*-python-*-
#
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
import os
import re
import cStringIO
import tempfile
import vclib
import rcsparse
import blame
import cvsdb
### The functionality shared with bincvs should probably be moved to a
### separate module
from bincvs import BaseCVSRepository, Revision, Tag, _file_log, _log_path, _logsort_date_cmp, _logsort_rev_cmp, _path_join
class CCVSRepository(BaseCVSRepository):
def dirlogs(self, path_parts, rev, entries, options):
"""see vclib.Repository.dirlogs docstring
rev can be a tag name or None. if set only information from revisions
matching the tag will be retrieved
Option values recognized by this implementation:
cvs_subdirs
boolean. true to fetch logs of the most recently modified file in each
subdirectory
Option values returned by this implementation:
cvs_tags, cvs_branches
lists of tag and branch names encountered in the directory
"""
if self.itemtype(path_parts, rev) != vclib.DIR: # does auth-check
raise vclib.Error("Path '%s' is not a directory."
% (part2path(path_parts)))
entries_to_fetch = []
for entry in entries:
if vclib.check_path_access(self, path_parts + [entry.name], None, rev):
entries_to_fetch.append(entry)
subdirs = options.get('cvs_subdirs', 0)
dirpath = self._getpath(path_parts)
alltags = { # all the tags seen in the files of this dir
'MAIN' : '',
'HEAD' : '1.1'
}
for entry in entries_to_fetch:
entry.rev = entry.date = entry.author = None
entry.dead = entry.absent = entry.log = entry.lockinfo = None
path = _log_path(entry, dirpath, subdirs)
if path:
entry.path = path
try:
rcsparse.parse(open(path, 'rb'), InfoSink(entry, rev, alltags))
if self.guesser:
entry.log = self.guesser.utf8(entry.log)
except IOError, e:
entry.errors.append("rcsparse error: %s" % e)
except RuntimeError, e:
entry.errors.append("rcsparse error: %s" % e)
except rcsparse.RCSStopParser:
pass
branches = options['cvs_branches'] = []
tags = options['cvs_tags'] = []
for name, rev in alltags.items():
if Tag(None, rev).is_branch:
branches.append(name)
else:
tags.append(name)
def itemlog(self, path_parts, rev, sortby, first, limit, options):
"""see vclib.Repository.itemlog docstring
rev parameter can be a revision number, a branch number, a tag name,
or None. If None, will return information about all revisions, otherwise,
will only return information about the specified revision or branch.
Option values returned by this implementation:
cvs_tags
dictionary of Tag objects for all tags encountered
"""
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file." % (_path_join(path_parts)))
path = self.rcsfile(path_parts, 1)
sink = TreeSink()
rcsparse.parse(open(path, 'rb'), sink)
filtered_revs = _file_log(sink.revs.values(), sink.tags, sink.lockinfo,
sink.default_branch, rev)
for rev in filtered_revs:
if rev.prev and len(rev.number) == 2:
rev.changed = rev.prev.next_changed
options['cvs_tags'] = sink.tags
if sortby == vclib.SORTBY_DATE:
filtered_revs.sort(_logsort_date_cmp)
elif sortby == vclib.SORTBY_REV:
filtered_revs.sort(_logsort_rev_cmp)
if len(filtered_revs) < first:
return []
if limit:
return filtered_revs[first:first+limit]
return filtered_revs
def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
if path_parts1 and self.itemtype(path_parts1, rev1) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file." % (_path_join(path_parts1)))
if path_parts2 and self.itemtype(path_parts2, rev2) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file." % (_path_join(path_parts2)))
if not path_parts1 and not path_parts2:
raise vclib.Error("Nothing to diff.")
if path_parts1:
temp1 = tempfile.mktemp()
open(temp1, 'wb').write(self.openfile(path_parts1, rev1, {})[0].getvalue())
r1 = self.itemlog(path_parts1, rev1, vclib.SORTBY_DEFAULT, 0, 0, {})[-1]
info1 = (self.rcsfile(path_parts1, root=1, v=0), r1.date, r1.string)
else:
temp1 = '/dev/null'
info1 = ('/dev/null', '', '')
if path_parts2:
temp2 = tempfile.mktemp()
open(temp2, 'wb').write(self.openfile(path_parts2, rev2, {})[0].getvalue())
r2 = self.itemlog(path_parts2, rev2, vclib.SORTBY_DEFAULT, 0, 0, {})[-1]
info2 = (self.rcsfile(path_parts2, root=1, v=0), r2.date, r2.string)
else:
temp2 = '/dev/null'
info2 = ('/dev/null', '', '')
diff_args = vclib._diff_args(type, options)
return vclib._diff_fp(temp1, temp2, info1, info2,
self.utilities.diff or 'diff', diff_args)
def annotate(self, path_parts, rev=None, include_text=False):
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file." % (_path_join(path_parts)))
source = blame.BlameSource(self.rcsfile(path_parts, 1), rev, self.guesser, include_text)
return source, source.revision
def revinfo(self, rev):
raise vclib.UnsupportedFeature
def openfile(self, path_parts, rev, options):
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file." % (_path_join(path_parts)))
path = self.rcsfile(path_parts, 1)
sink = COSink(rev)
rcsparse.parse(open(path, 'rb'), sink)
revision = sink.last and sink.last.string
return cStringIO.StringIO('\n'.join(sink.sstext.text)), revision
class MatchingSink(rcsparse.Sink):
"""Superclass for sinks that search for revisions based on tag or number"""
def __init__(self, find):
"""Initialize with tag name or revision number string to match against"""
if not find or find == 'MAIN' or find == 'HEAD':
self.find = None
else:
self.find = find
self.find_tag = None
def set_principal_branch(self, branch_number):
if self.find is None:
self.find_tag = Tag(None, branch_number)
def define_tag(self, name, revision):
if name == self.find:
self.find_tag = Tag(None, revision)
def admin_completed(self):
if self.find_tag is None:
if self.find is None:
self.find_tag = Tag(None, '')
else:
try:
self.find_tag = Tag(None, self.find)
except ValueError:
pass
class InfoSink(MatchingSink):
def __init__(self, entry, tag, alltags):
MatchingSink.__init__(self, tag)
self.entry = entry
self.alltags = alltags
self.matching_rev = None
self.perfect_match = 0
self.lockinfo = { }
self.saw_revision = False
def define_tag(self, name, revision):
MatchingSink.define_tag(self, name, revision)
self.alltags[name] = revision
def admin_completed(self):
MatchingSink.admin_completed(self)
if self.find_tag is None:
# tag we're looking for doesn't exist
if self.entry.kind == vclib.FILE:
self.entry.absent = 1
raise rcsparse.RCSStopParser
def parse_completed(self):
if not self.saw_revision:
#self.entry.errors.append("No revisions exist on %s" % (view_tag or "MAIN"))
self.entry.absent = 1
def set_locker(self, rev, locker):
self.lockinfo[rev] = locker
def define_revision(self, revision, date, author, state, branches, next):
self.saw_revision = True
if self.perfect_match:
return
tag = self.find_tag
rev = Revision(revision, date, author, state == "dead")
rev.lockinfo = self.lockinfo.get(revision)
# perfect match if revision number matches tag number or if
# revision is on trunk and tag points to trunk. imperfect match
# if tag refers to a branch and either a) this revision is the
# highest revision so far found on that branch, or b) this
# revision is the branchpoint.
perfect = ((rev.number == tag.number) or
(not tag.number and len(rev.number) == 2))
if perfect or (tag.is_branch and \
((tag.number == rev.number[:-1] and
(not self.matching_rev or
rev.number > self.matching_rev.number)) or
(rev.number == tag.number[:-1]))):
self.matching_rev = rev
self.perfect_match = perfect
def set_revision_info(self, revision, log, text):
if self.matching_rev:
if revision == self.matching_rev.string:
self.entry.rev = self.matching_rev.string
self.entry.date = self.matching_rev.date
self.entry.author = self.matching_rev.author
self.entry.dead = self.matching_rev.dead
self.entry.lockinfo = self.matching_rev.lockinfo
self.entry.absent = 0
self.entry.log = log
raise rcsparse.RCSStopParser
else:
raise rcsparse.RCSStopParser
class TreeSink(rcsparse.Sink):
d_command = re.compile('^d(\d+)\\s(\\d+)')
a_command = re.compile('^a(\d+)\\s(\\d+)')
def __init__(self):
self.revs = { }
self.tags = { }
self.head = None
self.default_branch = None
self.lockinfo = { }
def set_head_revision(self, revision):
self.head = revision
def set_principal_branch(self, branch_number):
self.default_branch = branch_number
def set_locker(self, rev, locker):
self.lockinfo[rev] = locker
def define_tag(self, name, revision):
# check !tags.has_key(tag_name)
self.tags[name] = revision
def define_revision(self, revision, date, author, state, branches, next):
# check !revs.has_key(revision)
self.revs[revision] = Revision(revision, date, author, state == "dead")
def set_revision_info(self, revision, log, text):
# check revs.has_key(revision)
rev = self.revs[revision]
rev.log = log
changed = None
added = 0
deled = 0
if self.head != revision:
changed = 1
lines = text.split('\n')
idx = 0
while idx < len(lines):
command = lines[idx]
dmatch = self.d_command.match(command)
idx = idx + 1
if dmatch:
deled = deled + int(dmatch.group(2))
else:
amatch = self.a_command.match(command)
if amatch:
count = int(amatch.group(2))
added = added + count
idx = idx + count
elif command:
raise "error while parsing deltatext: %s" % command
if len(rev.number) == 2:
rev.next_changed = changed and "+%i -%i" % (deled, added)
else:
rev.changed = changed and "+%i -%i" % (added, deled)
class StreamText:
d_command = re.compile('^d(\d+)\\s(\\d+)')
a_command = re.compile('^a(\d+)\\s(\\d+)')
def __init__(self, text):
self.text = text.split('\n')
def command(self, cmd):
adjust = 0
add_lines_remaining = 0
diffs = cmd.split('\n')
if diffs[-1] == "":
del diffs[-1]
if len(diffs) == 0:
return
if diffs[0] == "":
del diffs[0]
for command in diffs:
if add_lines_remaining > 0:
# Insertion lines from a prior "a" command
self.text.insert(start_line + adjust, command)
add_lines_remaining = add_lines_remaining - 1
adjust = adjust + 1
continue
dmatch = self.d_command.match(command)
amatch = self.a_command.match(command)
if dmatch:
# "d" - Delete command
start_line = int(dmatch.group(1))
count = int(dmatch.group(2))
begin = start_line + adjust - 1
del self.text[begin:begin + count]
adjust = adjust - count
elif amatch:
# "a" - Add command
start_line = int(amatch.group(1))
count = int(amatch.group(2))
add_lines_remaining = count
else:
raise RuntimeError, 'Error parsing diff commands'
def secondnextdot(s, start):
# find the position the second dot after the start index.
return s.find('.', s.find('.', start) + 1)
class COSink(MatchingSink):
def __init__(self, rev):
MatchingSink.__init__(self, rev)
def set_head_revision(self, revision):
self.head = Revision(revision)
self.last = None
self.sstext = None
def admin_completed(self):
MatchingSink.admin_completed(self)
if self.find_tag is None:
raise vclib.InvalidRevision(self.find)
def set_revision_info(self, revision, log, text):
tag = self.find_tag
rev = Revision(revision)
if rev.number == tag.number:
self.log = log
depth = len(rev.number)
if rev.number == self.head.number:
assert self.sstext is None
self.sstext = StreamText(text)
elif (depth == 2 and tag.number and rev.number >= tag.number[:depth]):
assert len(self.last.number) == 2
assert rev.number < self.last.number
self.sstext.command(text)
elif (depth > 2 and rev.number[:depth-1] == tag.number[:depth-1] and
(rev.number <= tag.number or len(tag.number) == depth-1)):
assert len(rev.number) - len(self.last.number) in (0, 2)
assert rev.number > self.last.number
self.sstext.command(text)
else:
rev = None
if rev:
#print "tag =", tag.number, "rev =", rev.number, "<br>"
self.last = rev

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -10,8 +10,17 @@
#
# -----------------------------------------------------------------------
"""This package provides parsing tools for RCS files."""
"""This package provides parsing tools for RCS files.
To use this package, first create a subclass of Sink. This should
declare all the callback methods you care about. Create an instance
of your class, and open() the RCS file you want to read. Then call
parse() to parse the file.
"""
# Make the "Sink" class and the various exception classes visible in this
# scope. That way, applications never need to import any of the
# sub-packages.
from common import *
try:
@@ -23,4 +32,13 @@ except ImportError:
from default import Parser
def parse(file, sink):
"""Parse an RCS file.
Parameters: FILE is the file object to parse. (I.e. an object of the
built-in Python type "file", usually created using Python's built-in
"open()" function). It should be opened in binary mode.
SINK is an instance of (some subclass of) Sink. It's methods will be
called as the file is parsed; see the definition of Sink for the
details.
"""
return Parser().parse(file, sink)

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -12,46 +12,203 @@
"""common.py: common classes and functions for the RCS parsing tools."""
import time
import calendar
import string
### compat isn't in vclib right now. need to work up a solution
import compat
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_access(self, accessors):
pass
def set_expansion(self, mode):
pass
def set_locking(self, mode):
"""Used to signal locking mode.
"""Interface to be implemented by clients. The RCS parser calls this as
it parses the RCS file.
Called with mode argument 'strict' if strict locking
Not called when no locking used."""
All these methods have stub implementations that do nothing, so you only
have to override the callbacks that you care about.
"""
def set_head_revision(self, revision):
"""Reports the head revision for this RCS file.
This is the value of the 'head' header in the admin section of the RCS
file. This function can only be called before admin_completed().
Parameter: REVISION is a string containing a revision number. This is
an actual revision number, not a branch number.
"""
pass
def set_principal_branch(self, branch_name):
"""Reports the principal branch for this RCS file. This is only called
if the principal branch is not trunk.
This is the value of the 'branch' header in the admin section of the RCS
file. This function can only be called before admin_completed().
Parameter: BRANCH_NAME is a string containing a branch number. If this
function is called, the parameter is typically "1.1.1", indicating the
vendor branch.
"""
pass
def set_access(self, accessors):
"""Reports the access control list for this RCS file. This function is
only called if the ACL is set. If this function is not called then
there is no ACL and all users are allowed access.
This is the value of the 'access' header in the admin section of the RCS
file. This function can only be called before admin_completed().
Parameter: ACCESSORS is a list of strings. Each string is a username.
The user is allowed access if and only if their username is in the list,
OR the user owns the RCS file on disk, OR the user is root.
Note that CVS typically doesn't use this field.
"""
pass
def define_tag(self, name, revision):
"""Reports a tag or branch definition. This function will be called
once for each tag or branch.
This is taken from the 'symbols' header in the admin section of the RCS
file. This function can only be called before admin_completed().
Parameters: NAME is a string containing the tag or branch name.
REVISION is a string containing a revision number. This may be
an actual revision number (for a tag) or a branch number.
The revision number consists of a number of decimal components separated
by dots. There are three common forms. If there are an odd number of
components, it's a branch. Otherwise, if the next-to-last component is
zero, it's a branch (and the next-to-last component is an artifact of
CVS and should not be shown to the user). Otherwise, it's a tag.
This function is called in the order that the tags appear in the RCS
file header. For CVS, this appears to be in reverse chronological
order of tag/branch creation.
"""
pass
def set_locker(self, revision, locker):
"""Reports a lock on this RCS file. This function will be called once
for each lock.
This is taken from the 'locks' header in the admin section of the RCS
file. This function can only be called before admin_completed().
Parameters: REVISION is a string containing a revision number. This is
an actual revision number, not a branch number.
LOCKER is a string containing a username.
"""
pass
def set_locking(self, mode):
"""Signals strict locking mode. This function will be called if and
only if the RCS file is in strict locking mode.
This is taken from the 'strict' header in the admin section of the RCS
file. This function can only be called before admin_completed().
Parameters: MODE is always the string 'strict'.
"""
pass
def set_comment(self, comment):
"""Reports the comment for this RCS file.
This is the value of the 'comment' header in the admin section of the
RCS file. This function can only be called before admin_completed().
Parameter: COMMENT is a string containing the comment. This may be
multi-line.
This field does not seem to be used by CVS.
"""
pass
def set_description(self, description):
def set_expansion(self, mode):
"""Reports the keyword expansion mode for this RCS file.
This is the value of the 'expand' header in the admin section of the
RCS file. This function can only be called before admin_completed().
Parameter: MODE is a string containing the keyword expansion mode.
Possible values include 'o' and 'b', amongst others.
"""
pass
def admin_completed(self):
"""Reports that the initial RCS header has been parsed. This function is
called exactly once.
"""
pass
def define_revision(self, revision, timestamp, author, state,
branches, next):
"""Reports metadata about a single revision.
This function is called for each revision. It is called later than
admin_completed() and earlier than tree_completed().
Parameter: REVISION is a revision number, as a string. This is an
actual revision number, not a branch number.
TIMESTAMP is the date and time that the revision was created, as an
integer number of seconds since the epoch. (I.e. "UNIX time" format).
AUTHOR is the author name, as a string.
STATE is the state of the revision, as a string. Common values are
"Exp" and "dead".
BRANCHES is a list of strings, with each string being an actual
revision number (not a branch number). For each branch which is based
on this revision and has commits, the revision number of the first
branch commit is listed here.
NEXT is either None or a string representing an actual revision number
(not a branch number).
When on trunk, NEXT points to what humans might consider to be the
'previous' revision number. For example, 1.3's NEXT is 1.2.
However, on a branch, NEXT really does point to what humans would
consider to be the 'next' revision number. For example, 1.1.2.1's
NEXT would be 1.1.2.2.
In other words, NEXT always means "where to find the next deltatext
that you need this revision to retrieve".
"""
pass
def set_revision_info(self, revision, log, text):
pass
def admin_completed(self):
pass
def tree_completed(self):
"""Reports that the RCS revision tree has been parsed. This function is
called exactly once. This function will be called later than
admin_completed().
"""
pass
def set_description(self, description):
"""Reports the description from the RCS file. This is set using the
"-m" flag to "cvs add". However, many CVS users don't use that option,
so this is often empty.
This function is called once, after tree_completed().
Parameter: DESCRIPTION is a string containing the description. This may
be multi-line.
"""
pass
def set_revision_info(self, revision, log, text):
"""Reports the log message and contents of a CVS revision.
This function is called for each revision. It is called later than
set_description().
Parameters: REVISION is a string containing the actual revision number.
LOG is a string containing the log message. This may be multi-line.
TEXT is the contents of the file in this revision, either as full-text or
as a diff. This is usually multi-line, and often quite large and/or
binary.
"""
pass
def parse_completed(self):
"""Reports that parsing an RCS file is complete.
This function is called once. After it is called, no more calls will be
made via this interface.
"""
pass
@@ -62,97 +219,205 @@ class Sink:
class RCSParseError(Exception):
pass
class RCSIllegalCharacter(RCSParseError):
pass
### need more work on this one
class RCSExpected(RCSParseError):
def __init__(self, got, wanted):
RCSParseError.__init__(self, got, wanted)
RCSParseError.__init__(
self,
'Unexpected parsing error in RCS file.\n'
'Expected token: %s, but saw: %s'
% (wanted, got)
)
class RCSStopParser(Exception):
pass
# --------------------------------------------------------------------------
#
# STANDARD TOKEN STREAM-BASED PARSER
#
class _Parser:
stream_class = None # subclasses need to define this
stream_class = None # subclasses need to define this
def _read_until_semicolon(self):
"""Read all tokens up to and including the next semicolon token.
Return the tokens (not including the semicolon) as a list."""
tokens = []
while 1:
token = self.ts.get()
if token == ';':
break
tokens.append(token)
return tokens
def _parse_admin_head(self, token):
rev = self.ts.get()
if rev == ';':
# The head revision is not specified. Just drop the semicolon
# on the floor.
pass
else:
self.sink.set_head_revision(rev)
self.ts.match(';')
def _parse_admin_branch(self, token):
branch = self.ts.get()
if branch != ';':
self.sink.set_principal_branch(branch)
self.ts.match(';')
def _parse_admin_access(self, token):
accessors = self._read_until_semicolon()
if accessors:
self.sink.set_access(accessors)
def _parse_admin_symbols(self, token):
while 1:
tag_name = self.ts.get()
if tag_name == ';':
break
self.ts.match(':')
tag_rev = self.ts.get()
self.sink.define_tag(tag_name, tag_rev)
def _parse_admin_locks(self, token):
while 1:
locker = self.ts.get()
if locker == ';':
break
self.ts.match(':')
rev = self.ts.get()
self.sink.set_locker(rev, locker)
def _parse_admin_strict(self, token):
self.sink.set_locking("strict")
self.ts.match(';')
def _parse_admin_comment(self, token):
self.sink.set_comment(self.ts.get())
self.ts.match(';')
def _parse_admin_expand(self, token):
expand_mode = self.ts.get()
self.sink.set_expansion(expand_mode)
self.ts.match(';')
admin_token_map = {
'head' : _parse_admin_head,
'branch' : _parse_admin_branch,
'access' : _parse_admin_access,
'symbols' : _parse_admin_symbols,
'locks' : _parse_admin_locks,
'strict' : _parse_admin_strict,
'comment' : _parse_admin_comment,
'expand' : _parse_admin_expand,
'desc' : None,
}
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":
semi, rev = self.ts.mget(2)
self.sink.set_head_revision(rev)
if semi != ';':
raise RCSExpected(semi, ';')
elif token == "branch":
semi, branch = self.ts.mget(2)
if semi == ';':
self.sink.set_principal_branch(branch)
try:
f = self.admin_token_map[token]
except KeyError:
# We're done once we reach the description of the RCS tree
if token[0] in string.digits:
self.ts.unget(token)
return
else:
if branch == ';':
self.ts.unget(semi);
else:
raise RCSExpected(semi, ';')
elif token == "symbols":
while 1:
tag = self.ts.get()
if tag == ';':
break
self.ts.match(':')
tag_name = tag
tag_rev = self.ts.get()
self.sink.define_tag(tag_name, tag_rev)
elif token == "comment":
semi, comment = self.ts.mget(2)
self.sink.set_comment(comment)
if semi != ';':
raise RCSExpected(semi, ';')
elif token == "expand":
semi, expand_mode = self.ts.mget(2)
self.sink.set_expansion(expand_mode)
if semi != ';':
raise RCSExpected(semi, ';')
elif token == "locks":
while 1:
tag = self.ts.get()
if tag == ';':
break
(locker, rev) = string.split(tag,':')
self.sink.set_locker(rev, locker)
tag = self.ts.get()
if tag == "strict":
self.sink.set_locking("strict")
self.ts.match(';')
else:
self.ts.unget(tag)
elif token == "access":
accessors = []
while 1:
tag = self.ts.get()
if tag == ';':
if accessors != []:
self.sink.set_access(accessors)
break
accessors = accessors + [ tag ]
# Chew up "newphrase"
# Chew up "newphrase"
# warn("Unexpected RCS token: $token\n")
while self.ts.get() != ';':
pass
else:
pass
# warn("Unexpected RCS token: $token\n")
if f is None:
self.ts.unget(token)
return
else:
f(self, token)
raise RuntimeError, "Unexpected EOF"
def _parse_rcs_tree_entry(self, revision):
# Parse date
self.ts.match('date')
date = self.ts.get()
self.ts.match(';')
# Convert date into standard UNIX time format (seconds since epoch)
date_fields = string.split(date, '.')
# According to rcsfile(5): the year "contains just the last two
# digits of the year for years from 1900 through 1999, and all the
# digits of years thereafter".
if len(date_fields[0]) == 2:
date_fields[0] = '19' + date_fields[0]
date_fields = map(string.atoi, date_fields)
EPOCH = 1970
if date_fields[0] < EPOCH:
raise ValueError, 'invalid year for revision %s' % (revision,)
try:
timestamp = calendar.timegm(tuple(date_fields) + (0, 0, 0,))
except ValueError, e:
raise ValueError, 'invalid date for revision %s: %s' % (revision, e,)
# Parse author
### NOTE: authors containing whitespace are violations of the
### RCS specification. We are making an allowance here because
### CVSNT is known to produce these sorts of authors.
self.ts.match('author')
author = ' '.join(self._read_until_semicolon())
# 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 = self._read_until_semicolon()
# 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@;
# commitid mLiHw3bulRjnTDGr;
# 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
self._read_until_semicolon()
self.sink.define_revision(revision, timestamp, author, state, branches,
next)
def parse_rcs_tree(self):
while 1:
@@ -163,86 +428,7 @@ class _Parser:
self.ts.unget(revision)
return
# Parse date
semi, date, sym = self.ts.mget(3)
if sym != 'date':
raise RCSExpected(sym, 'date')
if semi != ';':
raise RCSExpected(semi, ';')
# Convert date into timestamp
date_fields = string.split(date, '.') + ['0', '0', '0']
date_fields = map(string.atoi, date_fields)
# need to make the date four digits for timegm
EPOCH = 1970
if date_fields[0] < EPOCH:
if date_fields[0] < 70:
date_fields[0] = date_fields[0] + 2000
else:
date_fields[0] = date_fields[0] + 1900
if date_fields[0] < EPOCH:
raise ValueError, 'invalid year'
timestamp = compat.timegm(tuple(date_fields))
# Parse author
### NOTE: authors containing whitespace are violations of the
### RCS specification. We are making an allowance here because
### CVSNT is known to produce these sorts of authors.
self.ts.match('author')
author = ''
while 1:
token = self.ts.get()
if token == ';':
break
author = author + token + ' '
author = author[:-1] # toss the trailing space
# 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
next, sym = self.ts.mget(2)
if sym != 'next':
raise RCSExpected(sym, 'next')
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)
self._parse_rcs_tree_entry(revision)
def parse_rcs_description(self):
self.ts.match('desc')
@@ -264,6 +450,15 @@ class _Parser:
self.sink.set_revision_info(revision, log, text)
def parse(self, file, sink):
"""Parse an RCS file.
Parameters: FILE is the file object to parse. (I.e. an object of the
built-in Python type "file", usually created using Python's built-in
"open()" function).
SINK is an instance of (some subclass of) Sink. It's methods will be
called as the file is parsed; see the definition of Sink for the
details.
"""
self.ts = self.stream_class(file)
self.sink = sink

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -19,14 +19,18 @@ import string
import common
class _TokenStream:
token_term = string.whitespace + ';'
token_term = string.whitespace + ";:"
try:
token_term = frozenset(token_term)
except NameError:
pass
# the algorithm is about the same speed for any CHUNK_SIZE chosen.
# grab a good-sized chunk, but not too large to overwhelm memory.
# note: we use a multiple of a standard block size
CHUNK_SIZE = 192 * 512 # about 100k
# CHUNK_SIZE = 5 # for debugging, make the function grind...
# CHUNK_SIZE = 5 # for debugging, make the function grind...
def __init__(self, file):
self.rcsfile = file
@@ -44,15 +48,17 @@ class _TokenStream:
# out more complex solutions.
buf = self.buf
lbuf = len(buf)
idx = self.idx
while 1:
if idx == len(buf):
if idx == lbuf:
buf = self.rcsfile.read(self.CHUNK_SIZE)
if buf == '':
# signal EOF by returning None as the token
del self.buf # so we fail if get() is called again
del self.buf # so we fail if get() is called again
return None
lbuf = len(buf)
idx = 0
if buf[idx] not in string.whitespace:
@@ -60,27 +66,28 @@ class _TokenStream:
idx = idx + 1
if buf[idx] == ';':
if buf[idx] in ';:':
self.buf = buf
self.idx = idx + 1
return ';'
return buf[idx]
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:
while end < lbuf and buf[end] not in self.token_term:
end = end + 1
token = token + buf[idx:end]
if end < len(buf):
if end < lbuf:
# 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)
lbuf = len(buf)
idx = end = 0
self.buf = buf
@@ -94,22 +101,24 @@ class _TokenStream:
chunks = [ ]
while 1:
if idx == len(buf):
if idx == lbuf:
idx = 0
buf = self.rcsfile.read(self.CHUNK_SIZE)
if buf == '':
raise RuntimeError, 'EOF'
lbuf = len(buf)
i = string.find(buf, '@', idx)
if i == -1:
chunks.append(buf[idx:])
idx = len(buf)
idx = lbuf
continue
if i == len(buf) - 1:
if i == lbuf - 1:
chunks.append(buf[idx:i])
idx = 0
buf = '@' + self.rcsfile.read(self.CHUNK_SIZE)
if buf == '@':
raise RuntimeError, 'EOF'
lbuf = len(buf)
continue
if buf[i + 1] == '@':
chunks.append(buf[idx:i+1])
@@ -134,8 +143,7 @@ class _TokenStream:
token = self.get()
if token != match:
raise RuntimeError, ('Unexpected parsing error in RCS file.\n' +
'Expected token: %s, but saw: %s' % (match, token))
raise common.RCSExpected(token, match)
def unget(self, token):
"Put this token back, for the next get() to return."
@@ -166,75 +174,3 @@ class _TokenStream:
class Parser(common._Parser):
stream_class = _TokenStream
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":
semi, rev = self.ts.mget(2)
self.sink.set_head_revision(rev)
if semi != ';':
raise common.RCSExpected(semi, ';')
elif token == "branch":
semi, branch = self.ts.mget(2)
if semi == ';':
self.sink.set_principal_branch(branch)
else:
if branch == ';':
self.ts.unget(semi);
else:
raise common.RCSExpected(semi, ';')
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":
semi, comment = self.ts.mget(2)
self.sink.set_comment(comment)
if semi != ';':
raise common.RCSExpected(semi, ';')
elif token == "expand":
semi, expand_mode = self.ts.mget(2)
self.sink.set_expansion(expand_mode)
if semi != ';':
raise RCSExpected(semi, ';')
elif token == "locks":
while 1:
tag = self.ts.get()
if tag == ';':
break
(locker, rev) = string.split(tag,':')
self.sink.set_locker(rev, locker)
tag = self.ts.get()
if tag == "strict":
self.sink.set_locking("strict")
self.ts.match(';')
else:
self.ts.unget(tag)
elif token == "access":
accessors = []
while 1:
tag = self.ts.get()
if tag == ';':
if accessors != []:
self.sink.set_access(accessors)
break
accessors = accessors + [ tag ]
# Chew up "newphrase".
else:
pass
# warn("Unexpected RCS token: $token\n")
raise RuntimeError, "Unexpected EOF"

View File

@@ -0,0 +1,73 @@
#! /usr/bin/python
# (Be in -*- python -*- mode.)
#
# ====================================================================
# Copyright (c) 2006-2007 CollabNet. All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://subversion.tigris.org/license-1.html.
# If newer versions of this license are posted there, you may use a
# newer version instead, at your option.
#
# This software consists of voluntary contributions made by many
# individuals. For exact contribution history, see the revision
# history and logs, available at http://cvs2svn.tigris.org/.
# ====================================================================
"""Parse an RCS file, showing the rcsparse callbacks that are called.
This program is useful to see whether an RCS file has a problem (in
the sense of not being parseable by rcsparse) and also to illuminate
the correspondence between RCS file contents and rcsparse callbacks.
The output of this program can also be considered to be a kind of
'canonical' format for RCS files, at least in so far as rcsparse
returns all relevant information in the file and provided that the
order of callbacks is always the same."""
import sys
import os
class Logger:
def __init__(self, f, name):
self.f = f
self.name = name
def __call__(self, *args):
self.f.write(
'%s(%s)\n' % (self.name, ', '.join(['%r' % arg for arg in args]),)
)
class LoggingSink:
def __init__(self, f):
self.f = f
def __getattr__(self, name):
return Logger(self.f, name)
if __name__ == '__main__':
# Since there is nontrivial logic in __init__.py, we have to import
# parse() via that file. First make sure that the directory
# containing this script is in the path:
sys.path.insert(0, os.path.dirname(sys.argv[0]))
from __init__ import parse
if sys.argv[1:]:
for path in sys.argv[1:]:
if os.path.isfile(path) and path.endswith(',v'):
parse(
open(path, 'rb'), LoggingSink(sys.stdout)
)
else:
sys.stderr.write('%r is being ignored.\n' % path)
else:
parse(sys.stdin, LoggingSink(sys.stdout))

View File

@@ -0,0 +1,73 @@
#! /usr/bin/python
# (Be in -*- python -*- mode.)
#
# ====================================================================
# Copyright (c) 2007 CollabNet. All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://subversion.tigris.org/license-1.html.
# If newer versions of this license are posted there, you may use a
# newer version instead, at your option.
#
# This software consists of voluntary contributions made by many
# individuals. For exact contribution history, see the revision
# history and logs, available at http://viewvc.tigris.org/.
# ====================================================================
"""Run tests of rcsparse code."""
import sys
import os
import glob
from cStringIO import StringIO
from difflib import Differ
# Since there is nontrivial logic in __init__.py, we have to import
# parse() via that file. First make sure that the directory
# containing this script is in the path:
script_dir = os.path.dirname(sys.argv[0])
sys.path.insert(0, script_dir)
from __init__ import parse
from parse_rcs_file import LoggingSink
test_dir = os.path.join(script_dir, 'test-data')
filelist = glob.glob(os.path.join(test_dir, '*,v'))
filelist.sort()
all_tests_ok = 1
for filename in filelist:
sys.stderr.write('%s: ' % (filename,))
f = StringIO()
try:
parse(open(filename, 'rb'), LoggingSink(f))
except Exception, e:
sys.stderr.write('Error parsing file: %s!\n' % (e,))
all_tests_ok = 0
else:
output = f.getvalue()
expected_output_filename = filename[:-2] + '.out'
expected_output = open(expected_output_filename, 'rb').read()
if output == expected_output:
sys.stderr.write('OK\n')
else:
sys.stderr.write('Output does not match expected output!\n')
differ = Differ()
for diffline in differ.compare(
expected_output.splitlines(1), output.splitlines(1)
):
sys.stderr.write(diffline)
all_tests_ok = 0
if all_tests_ok:
sys.exit(0)
else:
sys.exit(1)

View File

@@ -0,0 +1,102 @@
head 1.2;
access;
symbols
B_SPLIT:1.2.0.4
B_MIXED:1.2.0.2
T_MIXED:1.2
B_FROM_INITIALS_BUT_ONE:1.1.1.1.0.4
B_FROM_INITIALS:1.1.1.1.0.2
T_ALL_INITIAL_FILES_BUT_ONE:1.1.1.1
T_ALL_INITIAL_FILES:1.1.1.1
vendortag:1.1.1.1
vendorbranch:1.1.1;
locks; strict;
comment @# @;
1.2
date 2003.05.23.00.17.53; author jrandom; state Exp;
branches
1.2.2.1
1.2.4.1;
next 1.1;
1.1
date 98.05.22.23.20.19; author jrandom; state Exp;
branches
1.1.1.1;
next ;
1.1.1.1
date 98.05.22.23.20.19; author jrandom; state Exp;
branches;
next ;
1.2.2.1
date 2003.05.23.00.31.36; author jrandom; state Exp;
branches;
next ;
1.2.4.1
date 2003.06.03.03.20.31; author jrandom; state Exp;
branches;
next ;
desc
@@
1.2
log
@Second commit to proj, affecting all 7 files.
@
text
@This is the file `default' in the top level of the project.
Every directory in the `proj' project has a file named `default'.
This line was added in the second commit (affecting all 7 files).
@
1.2.4.1
log
@First change on branch B_SPLIT.
This change excludes sub3/default, because it was not part of this
commit, and sub1/subsubB/default, which is not even on the branch yet.
@
text
@a5 2
First change on branch B_SPLIT.
@
1.2.2.1
log
@Modify three files, on branch B_MIXED.
@
text
@a5 2
This line was added on branch B_MIXED only (affecting 3 files).
@
1.1
log
@Initial revision
@
text
@d4 2
@
1.1.1.1
log
@Initial import.
@
text
@@

View File

@@ -0,0 +1,26 @@
set_head_revision('1.2')
define_tag('B_SPLIT', '1.2.0.4')
define_tag('B_MIXED', '1.2.0.2')
define_tag('T_MIXED', '1.2')
define_tag('B_FROM_INITIALS_BUT_ONE', '1.1.1.1.0.4')
define_tag('B_FROM_INITIALS', '1.1.1.1.0.2')
define_tag('T_ALL_INITIAL_FILES_BUT_ONE', '1.1.1.1')
define_tag('T_ALL_INITIAL_FILES', '1.1.1.1')
define_tag('vendortag', '1.1.1.1')
define_tag('vendorbranch', '1.1.1')
set_locking('strict')
set_comment('# ')
admin_completed()
define_revision('1.2', 1053649073, 'jrandom', 'Exp', ['1.2.2.1', '1.2.4.1'], '1.1')
define_revision('1.1', 895879219, 'jrandom', 'Exp', ['1.1.1.1'], None)
define_revision('1.1.1.1', 895879219, 'jrandom', 'Exp', [], None)
define_revision('1.2.2.1', 1053649896, 'jrandom', 'Exp', [], None)
define_revision('1.2.4.1', 1054610431, 'jrandom', 'Exp', [], None)
tree_completed()
set_description('')
set_revision_info('1.2', 'Second commit to proj, affecting all 7 files.\n', "This is the file `default' in the top level of the project.\n\nEvery directory in the `proj' project has a file named `default'.\n\nThis line was added in the second commit (affecting all 7 files).\n")
set_revision_info('1.2.4.1', 'First change on branch B_SPLIT.\n\nThis change excludes sub3/default, because it was not part of this\ncommit, and sub1/subsubB/default, which is not even on the branch yet.\n', 'a5 2\n\nFirst change on branch B_SPLIT.\n')
set_revision_info('1.2.2.1', 'Modify three files, on branch B_MIXED.\n', 'a5 2\n\nThis line was added on branch B_MIXED only (affecting 3 files).\n')
set_revision_info('1.1', 'Initial revision\n', 'd4 2\n')
set_revision_info('1.1.1.1', 'Initial import.\n', '')
parse_completed()

View File

@@ -0,0 +1,10 @@
head ;
access;
symbols;
locks; strict;
comment @# @;
desc
@@

View File

@@ -0,0 +1,6 @@
set_locking('strict')
set_comment('# ')
admin_completed()
tree_completed()
set_description('')
parse_completed()

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -25,7 +25,7 @@ _tt = TextTools
_idchar_list = map(chr, range(33, 127)) + map(chr, range(160, 256))
_idchar_list.remove('$')
_idchar_list.remove(',')
#_idchar_list.remove('.') leave as part of 'num' symbol
#_idchar_list.remove('.') # leave as part of 'num' symbol
_idchar_list.remove(':')
_idchar_list.remove(';')
_idchar_list.remove('@')
@@ -41,10 +41,10 @@ _T_STRING_START = 40
_T_STRING_SPAN = 60
_T_STRING_END = 70
_E_COMPLETE = 100 # ended on a complete token
_E_TOKEN = 110 # ended mid-token
_E_STRING_SPAN = 130 # ended within a string
_E_STRING_END = 140 # ended with string-end ('@') (could be mid-@@)
_E_COMPLETE = 100 # ended on a complete token
_E_TOKEN = 110 # ended mid-token
_E_STRING_SPAN = 130 # ended within a string
_E_STRING_END = 140 # ended with string-end ('@') (could be mid-@@)
_SUCCESS = +100
@@ -65,7 +65,7 @@ class _mxTokenStream:
# note: we use a multiple of a standard block size
CHUNK_SIZE = 192 * 512 # about 100k
# CHUNK_SIZE = 5 # for debugging, make the function grind...
# CHUNK_SIZE = 5 # for debugging, make the function grind...
def __init__(self, file):
self.rcsfile = file
@@ -83,40 +83,84 @@ class _mxTokenStream:
# construct a tag table which refers to the buffer we need to parse.
table = (
# ignore whitespace. with or without whitespace, move to the next rule.
#1: ignore whitespace. with or without whitespace, move to the next rule.
(None, _tt.AllInSet, _tt.whitespace_set, +1),
#2
(_E_COMPLETE, _tt.EOF + _tt.AppendTagobj, _tt.Here, +1, _SUCCESS),
# accumulate token text and exit, or move to the next rule.
#3: accumulate token text and exit, or move to the next rule.
(_UNUSED, _tt.AllInSet + _tt.AppendMatch, _idchar_set, +2),
#4
(_E_TOKEN, _tt.EOF + _tt.AppendTagobj, _tt.Here, -3, _SUCCESS),
# single character tokens exit immediately, or move to the next rule
#5: single character tokens exit immediately, or move to the next rule
(_UNUSED, _tt.IsInSet + _tt.AppendMatch, _onechar_token_set, +2),
#6
(_E_COMPLETE, _tt.EOF + _tt.AppendTagobj, _tt.Here, -5, _SUCCESS),
# if this isn't an '@' symbol, then we have a syntax error (go to a
#7: if this isn't an '@' symbol, then we have a syntax error (go to a
# negative index to indicate that condition). otherwise, suck it up
# and move to the next rule.
(_T_STRING_START, _tt.Is + _tt.AppendTagobj, '@'),
#8
(None, _tt.Is, '@', +4, +1),
#9
(buf, _tt.Is, '@', +1, -1),
#10
(_T_STRING_END, _tt.Skip + _tt.AppendTagobj, 0, 0, +1),
#11
(_E_STRING_END, _tt.EOF + _tt.AppendTagobj, _tt.Here, -10, _SUCCESS),
#12
(_E_STRING_SPAN, _tt.EOF + _tt.AppendTagobj, _tt.Here, +1, _SUCCESS),
# suck up everything that isn't an AT. go to next rule to look for EOF
#13: suck up everything that isn't an AT. go to next rule to look for EOF
(buf, _tt.AllInSet, _not_at_set, 0, +1),
# go back to look for double AT if we aren't at the end of the string
#14: go back to look for double AT if we aren't at the end of the string
(_E_STRING_SPAN, _tt.EOF + _tt.AppendTagobj, _tt.Here, -6, _SUCCESS),
)
# Fast, texttools may be, but it's somewhat lacking in clarity.
# Here's an attempt to document the logic encoded in the table above:
#
# Flowchart:
# _____
# / /\
# 1 -> 2 -> 3 -> 5 -> 7 -> 8 -> 9 -> 10 -> 11
# | \/ \/ \/ /\ \/
# \ 4 6 12 14 /
# \_______/_____/ \ / /
# \ 13 /
# \__________________________________________/
#
# #1: Skip over any whitespace.
# #2: If now EOF, exit with code _E_COMPLETE.
# #3: If we have a series of characters in _idchar_set, then:
# #4: Output them as a token, and go back to #1.
# #5: If we have a character in _onechar_token_set, then:
# #6: Output it as a token, and go back to #1.
# #7: If we do not have an '@', then error.
# If we do, then log a _T_STRING_START and continue.
# #8: If we have another '@', continue on to #9. Otherwise:
# #12: If now EOF, exit with code _E_STRING_SPAN.
# #13: Record the slice up to the next '@' (or EOF).
# #14: If now EOF, exit with code _E_STRING_SPAN.
# Otherwise, go back to #8.
# #9: If we have another '@', then we've just seen an escaped
# (by doubling) '@' within an @-string. Record a slice including
# just one '@' character, and jump back to #8.
# Otherwise, we've *either* seen the terminating '@' of an @-string,
# *or* we've seen one half of an escaped @@ sequence that just
# happened to be split over a chunk boundary - in either case,
# we continue on to #10.
# #10: Log a _T_STRING_END.
# #11: If now EOF, exit with _E_STRING_END. Otherwise, go back to #1.
success, taglist, idx = _tt.tag(buf, table, start)
if not success:
@@ -279,16 +323,11 @@ class _mxTokenStream:
def match(self, match):
if self.tokens:
token = self.tokens.pop()
if token != match:
raise RuntimeError, ('Unexpected parsing error in RCS file.\n'
'Expected token: %s, but saw: %s'
% (match, token))
else:
token = self.get()
if token != match:
raise RuntimeError, ('Unexpected parsing error in RCS file.\n'
'Expected token: %s, but saw: %s'
% (match, token))
if token != match:
raise common.RCSExpected(token, match)
def unget(self, token):
self.tokens.append(token)

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -10,695 +10,94 @@
#
# -----------------------------------------------------------------------
"Version Control lib driver for locally accessible Subversion repositories"
"Version Control lib driver for Subversion repositories"
import vclib
import os
import os.path
import string
import cStringIO
import signal
import time
import tempfile
import popen
import re
from svn import fs, repos, core, delta
import urllib
_re_url = re.compile('^(http|https|file|svn|svn\+[^:]+)://')
### Require Subversion 1.2.0 or better.
if (core.SVN_VER_MAJOR, core.SVN_VER_MINOR, core.SVN_VER_PATCH) < (1, 2, 0):
raise Exception, "Version requirement not met (needs 1.2.0 or better)"
def _allow_all(root, path, pool):
"""Generic authz_read_func that permits access to all paths"""
return 1
def _fs_path_join(base, relative):
# Subversion filesystem paths are '/'-delimited, regardless of OS.
joined_path = base + '/' + relative
parts = filter(None, string.split(joined_path, '/'))
return string.join(parts, '/')
def _cleanup_path(path):
"""Return a cleaned-up Subversion filesystem path"""
return string.join(filter(None, string.split(path, '/')), '/')
def _compare_paths(path1, path2):
path1_len = len (path1);
path2_len = len (path2);
min_len = min(path1_len, path2_len)
i = 0
# Are the paths exactly the same?
if path1 == path2:
return 0
# Skip past common prefix
while (i < min_len) and (path1[i] == path2[i]):
i = i + 1
# Children of paths are greater than their parents, but less than
# greater siblings of their parents
char1 = '\0'
char2 = '\0'
if (i < path1_len):
char1 = path1[i]
if (i < path2_len):
char2 = path2[i]
if (char1 == '/') and (i == path2_len):
return 1
if (char2 == '/') and (i == path1_len):
return -1
if (i < path1_len) and (char1 == '/'):
return -1
if (i < path2_len) and (char2 == '/'):
return 1
# Common prefix was skipped above, next character is compared to
# determine order
return cmp(char1, char2)
def _datestr_to_date(datestr, pool):
if datestr is None:
return None
return core.svn_time_from_cstring(datestr, pool) / 1000000
def _fs_rev_props(fsptr, rev, pool):
author = fs.revision_prop(fsptr, rev, core.SVN_PROP_REVISION_AUTHOR, pool)
msg = fs.revision_prop(fsptr, rev, core.SVN_PROP_REVISION_LOG, pool)
date = fs.revision_prop(fsptr, rev, core.SVN_PROP_REVISION_DATE, pool)
return date, author, msg
def date_from_rev(svnrepos, rev):
if (rev < 0) or (rev > svnrepos.youngest):
raise vclib.InvalidRevision(rev)
datestr = fs.revision_prop(svnrepos.fs_ptr, rev,
core.SVN_PROP_REVISION_DATE, svnrepos.pool)
return _datestr_to_date(datestr, svnrepos.pool)
def get_location(svnrepos, path, rev, old_rev):
def _canonicalize_path(path):
import svn.core
try:
results = repos.svn_repos_trace_node_locations(svnrepos.fs_ptr, path,
rev, [old_rev],
_allow_all, svnrepos.pool)
except core.SubversionException, e:
if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
raise vclib.ItemNotFound(path)
raise
try:
old_path = results[old_rev]
except KeyError:
raise vclib.ItemNotFound(path)
return _cleanup_path(old_path)
def last_rev(svnrepos, path, peg_revision, limit_revision=None):
"""Given PATH, known to exist in PEG_REVISION, find the youngest
revision older than, or equal to, LIMIT_REVISION in which path
exists. Return that revision, and the path at which PATH exists in
that revision."""
# Here's the plan, man. In the trivial case (where PEG_REVISION is
# the same as LIMIT_REVISION), this is a no-brainer. If
# LIMIT_REVISION is older than PEG_REVISION, we can use Subversion's
# history tracing code to find the right location. If, however,
# LIMIT_REVISION is younger than PEG_REVISION, we suffer from
# Subversion's lack of forward history searching. Our workaround,
# ugly as it may be, involves a binary search through the revisions
# between PEG_REVISION and LIMIT_REVISION to find our last live
# revision.
peg_revision = svnrepos._getrev(peg_revision)
limit_revision = svnrepos._getrev(limit_revision)
try:
if peg_revision == limit_revision:
return peg_revision, path
elif peg_revision > limit_revision:
fsroot = svnrepos._getroot(peg_revision)
history = fs.node_history(fsroot, path, svnrepos.scratch_pool)
while history:
path, peg_revision = fs.history_location(history,
svnrepos.scratch_pool);
if peg_revision <= limit_revision:
return max(peg_revision, limit_revision), _cleanup_path(path)
history = fs.history_prev(history, 1, svnrepos.scratch_pool)
return peg_revision, _cleanup_path(path)
return svn.core.svn_path_canonicalize(path)
except AttributeError: # svn_path_canonicalize() appeared in 1.4.0 bindings
# There's so much more that we *could* do here, but if we're
# here at all its because there's a really old Subversion in
# place, and those older Subversion versions cared quite a bit
# less about the specifics of path canonicalization.
if re.search(_re_url, path):
return path.rstrip('/')
else:
### Warning: this is *not* an example of good pool usage.
orig_id = fs.node_id(svnrepos._getroot(peg_revision), path,
svnrepos.scratch_pool)
while peg_revision != limit_revision:
mid = (peg_revision + 1 + limit_revision) / 2
try:
mid_id = fs.node_id(svnrepos._getroot(mid), path,
svnrepos.scratch_pool)
except core.SubversionException, e:
if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
cmp = -1
else:
raise
else:
### Not quite right. Need a comparison function that only returns
### true when the two nodes are the same copy, not just related.
cmp = fs.compare_ids(orig_id, mid_id)
if cmp in (0, 1):
peg_revision = mid
else:
limit_revision = mid - 1
return peg_revision, path
finally:
svnrepos._scratch_clear()
return os.path.normpath(path)
def created_rev(svnrepos, full_name, rev):
fsroot = svnrepos._getroot(rev)
return fs.node_created_rev(fsroot, full_name, svnrepos.pool)
class Revision(vclib.Revision):
"Hold state for each revision's log entry."
def __init__(self, rev, date, author, msg, size,
filename, copy_path, copy_rev):
vclib.Revision.__init__(self, rev, str(rev), date, author, None, msg, size)
self.filename = filename
self.copy_path = copy_path
self.copy_rev = copy_rev
class NodeHistory:
def __init__(self, fs_ptr, show_all_logs):
self.histories = {}
self.fs_ptr = fs_ptr
self.show_all_logs = show_all_logs
def add_history(self, path, revision, pool):
# If filtering, only add the path and revision to the histories
# list if they were actually changed in this revision (where
# change means the path itself was changed, or one of its parents
# was copied). This is useful for omitting bubble-up directory
# changes.
if not self.show_all_logs:
rev_root = fs.revision_root(self.fs_ptr, revision, pool)
changed_paths = fs.paths_changed(rev_root, pool)
paths = changed_paths.keys()
if path not in paths:
# Look for a copied parent
test_path = path
found = 0
subpool = core.svn_pool_create(pool)
while 1:
core.svn_pool_clear(subpool)
off = string.rfind(test_path, '/')
if off < 0:
break
test_path = test_path[0:off]
if test_path in paths:
copyfrom_rev, copyfrom_path = \
fs.copied_from(rev_root, test_path, subpool)
if copyfrom_rev >= 0 and copyfrom_path:
found = 1
break
core.svn_pool_destroy(subpool)
if not found:
return
self.histories[revision] = _cleanup_path(path)
def canonicalize_rootpath(rootpath):
# Try to canonicalize the rootpath using Subversion semantics.
rootpath = _canonicalize_path(rootpath)
def _get_history(svnrepos, full_name, rev, options={}):
fsroot = svnrepos._getroot(rev)
show_all_logs = options.get('svn_show_all_dir_logs', 0)
if not show_all_logs:
# See if the path is a file or directory.
kind = fs.check_path(fsroot, full_name, svnrepos.pool)
if kind is core.svn_node_file:
show_all_logs = 1
# Instantiate a NodeHistory collector object.
history = NodeHistory(svnrepos.fs_ptr, show_all_logs)
# ViewVC's support for local repositories is more complete and more
# performant than its support for remote ones, so if we're on a
# Unix-y system and we have a file:/// URL, convert it to a local
# path instead.
if os.name == 'posix':
rootpath_lower = rootpath.lower()
if rootpath_lower in ['file://localhost',
'file://localhost/',
'file://',
'file:///'
]:
return '/'
if rootpath_lower.startswith('file://localhost/'):
rootpath = os.path.normpath(urllib.unquote(rootpath[16:]))
elif rootpath_lower.startswith('file:///'):
rootpath = os.path.normpath(urllib.unquote(rootpath[7:]))
# Do we want to cross copy history?
cross_copies = options.get('svn_cross_copies', 0)
# Get the history items for PATH.
repos.svn_repos_history(svnrepos.fs_ptr, full_name, history.add_history,
1, rev, cross_copies, svnrepos.pool)
return history.histories
# Ensure that we have an absolute path (or URL), and return.
if not re.search(_re_url, rootpath):
assert os.path.isabs(rootpath)
return rootpath
class ChangedPath:
def __init__(self, filename, pathtype, prop_mods, text_mods,
base_path, base_rev, action, is_copy):
self.filename = filename
self.pathtype = pathtype
self.prop_mods = prop_mods
self.text_mods = text_mods
self.base_path = base_path
self.base_rev = base_rev
self.action = action
self.is_copy = is_copy
class ChangedPathSet:
def __init__(self):
self.changes = { }
def add_change(self, change):
if change.path:
change.path = _cleanup_path(change.path)
if change.base_path:
change.base_path = _cleanup_path(change.base_path)
path = change.path
action = 'modified'
is_copy = 0
if not change.path:
action = 'deleted'
path = change.base_path
elif change.added:
action = 'added'
replace_check_path = path
if change.base_path and change.base_rev:
is_copy = 1
replace_check_path = change.base_path
if self.changes.has_key(replace_check_path) \
and self.changes[replace_check_path].action == 'deleted':
action = 'replaced'
if change.item_kind == core.svn_node_dir:
pathtype = vclib.DIR
elif change.item_kind == core.svn_node_file:
pathtype = vclib.FILE
else:
pathtype = None
self.changes[path] = ChangedPath(path, pathtype, change.prop_changes,
change.text_changed, change.base_path,
change.base_rev, action, is_copy)
def get_changes(self):
changes = self.changes.values()
changes.sort(lambda a, b: _compare_paths(a.filename, b.filename))
return changes
def get_revision_info(svnrepos, rev):
fsroot = svnrepos._getroot(rev)
# Get the changes for the revision
cps = ChangedPathSet()
editor = repos.ChangeCollector(svnrepos.fs_ptr, fsroot,
svnrepos.pool, cps.add_change)
e_ptr, e_baton = delta.make_editor(editor, svnrepos.pool)
repos.svn_repos_replay(fsroot, e_ptr, e_baton, svnrepos.pool)
# Now get the revision property info. Would use
# editor.get_root_props(), but something is broken there...
datestr, author, msg = _fs_rev_props(svnrepos.fs_ptr, rev, svnrepos.pool)
date = _datestr_to_date(datestr, svnrepos.pool)
return date, author, msg, cps.get_changes()
def _log_helper(svnrepos, rev, path, pool):
rev_root = fs.revision_root(svnrepos.fs_ptr, rev, pool)
# Was this path@rev the target of a copy?
copyfrom_rev, copyfrom_path = fs.copied_from(rev_root, path, pool)
# Assemble our LogEntry
datestr, author, msg = _fs_rev_props(svnrepos.fs_ptr, rev, pool)
date = _datestr_to_date(datestr, pool)
if fs.is_file(rev_root, path, pool):
size = fs.file_length(rev_root, path, pool)
def expand_root_parent(parent_path):
roots = {}
if re.search(_re_url, parent_path):
pass
else:
size = None
entry = Revision(rev, date, author, msg, size, path,
copyfrom_path and _cleanup_path(copyfrom_path),
copyfrom_rev)
return entry
# Any subdirectories of PARENT_PATH which themselves have a child
# "format" are returned as roots.
assert os.path.isabs(parent_path)
subpaths = os.listdir(parent_path)
for rootname in subpaths:
rootpath = os.path.join(parent_path, rootname)
if os.path.exists(os.path.join(rootpath, "format")):
roots[rootname] = canonicalize_rootpath(rootpath)
return roots
def find_root_in_parent(parent_path, rootname):
"""Search PARENT_PATH for a root named ROOTNAME, returning the
canonicalized ROOTPATH of the root if found; return None if no such
root is found."""
if not re.search(_re_url, parent_path):
assert os.path.isabs(parent_path)
rootpath = os.path.join(parent_path, rootname)
format_path = os.path.join(rootpath, "format")
if os.path.exists(format_path):
return canonicalize_rootpath(rootpath)
return None
def _fetch_log(svnrepos, full_name, which_rev, options, pool):
revs = []
if options.get('svn_latest_log', 0):
rev = _log_helper(svnrepos, which_rev, full_name, pool)
if rev:
revs.append(rev)
def SubversionRepository(name, rootpath, authorizer, utilities, config_dir):
rootpath = canonicalize_rootpath(rootpath)
if re.search(_re_url, rootpath):
import svn_ra
return svn_ra.RemoteSubversionRepository(name, rootpath, authorizer,
utilities, config_dir)
else:
history_set = _get_history(svnrepos, full_name, which_rev, options)
history_revs = history_set.keys()
history_revs.sort()
history_revs.reverse()
subpool = core.svn_pool_create(pool)
for history_rev in history_revs:
core.svn_pool_clear(subpool)
rev = _log_helper(svnrepos, history_rev, history_set[history_rev],
subpool)
if rev:
revs.append(rev)
core.svn_pool_destroy(subpool)
return revs
def _get_last_history_rev(fsroot, path, pool):
history = fs.node_history(fsroot, path, pool)
history = fs.history_prev(history, 0, pool)
history_path, history_rev = fs.history_location(history, pool);
return history_rev
def get_logs(svnrepos, full_name, rev, files):
fsroot = svnrepos._getroot(rev)
subpool = core.svn_pool_create(svnrepos.pool)
for file in files:
core.svn_pool_clear(subpool)
path = _fs_path_join(full_name, file.name)
rev = _get_last_history_rev(fsroot, path, subpool)
datestr, author, msg = _fs_rev_props(svnrepos.fs_ptr, rev, subpool)
date = _datestr_to_date(datestr, subpool)
file.rev = str(rev)
file.date = date
file.author = author
file.log = msg
if file.kind == vclib.FILE:
file.size = fs.file_length(fsroot, path, subpool)
core.svn_pool_destroy(subpool)
def get_youngest_revision(svnrepos):
return svnrepos.youngest
def temp_checkout(svnrepos, path, rev, pool):
"""Check out file revision to temporary file"""
temp = tempfile.mktemp()
fp = open(temp, 'wb')
try:
root = svnrepos._getroot(rev)
stream = fs.file_contents(root, path, pool)
try:
while 1:
chunk = core.svn_stream_read(stream, core.SVN_STREAM_CHUNK_SIZE)
if not chunk:
break
fp.write(chunk)
finally:
core.svn_stream_close(stream)
finally:
fp.close()
return temp
class FileContentsPipe:
def __init__(self, root, path, pool):
self._pool = core.svn_pool_create(pool)
self._stream = fs.file_contents(root, path, self._pool)
self._eof = 0
def __del__(self):
core.svn_pool_destroy(self._pool)
def read(self, len=None):
chunk = None
if not self._eof:
if len is None:
buffer = cStringIO.StringIO()
try:
while 1:
hunk = core.svn_stream_read(self._stream, 8192)
if not hunk:
break
buffer.write(hunk)
chunk = buffer.getvalue()
finally:
buffer.close()
else:
chunk = core.svn_stream_read(self._stream, len)
if not chunk:
self._eof = 1
return chunk
def readline(self):
chunk = None
if not self._eof:
chunk, self._eof = core.svn_stream_readline(self._stream, '\n',
self._pool)
if not self._eof:
chunk = chunk + '\n'
if not chunk:
self._eof = 1
return chunk
def readlines(self):
lines = []
while True:
line = self.readline()
if not line:
break
lines.append(line)
return lines
def close(self):
return core.svn_stream_close(self._stream)
def eof(self):
return self._eof
_re_blameinfo = re.compile(r"\s*(\d+)\s*(.*)")
class BlameSource:
def __init__(self, svn_client_path, rootpath, fs_path, rev, first_rev):
self.idx = -1
self.line_number = 1
self.last = None
self.first_rev = first_rev
rootpath = os.path.abspath(rootpath)
url = 'file://' + string.join([rootpath, fs_path], "/")
fp = popen.popen(svn_client_path,
('blame', "-r%d" % int(rev), "%s@%d" % (url, int(rev))),
'rb', 1)
self.fp = fp
def __getitem__(self, idx):
if idx == self.idx:
return self.last
if idx != self.idx + 1:
raise BlameSequencingError()
line = self.fp.readline()
if not line:
raise IndexError("No more annotations")
m = _re_blameinfo.match(line[:17])
if not m:
raise vclib.Error("Could not parse blame output at line %i\n%s"
% (idx+1, line))
rev, author = m.groups()
text = line[18:]
rev = int(rev)
prev_rev = None
if rev > self.first_rev:
prev_rev = rev - 1
item = _item(text=text, line_number=idx+1, rev=rev,
prev_rev=prev_rev, author=author, date=None)
self.last = item
self.idx = idx
return item
class BlameSequencingError(Exception):
pass
class SubversionRepository(vclib.Repository):
def __init__(self, name, rootpath, svn_path):
if not os.path.isdir(rootpath):
raise vclib.ReposNotFound(name)
# Initialize some stuff.
self.pool = None
self.apr_init = 0
self.rootpath = rootpath
self.name = name
self.svn_client_path = os.path.normpath(os.path.join(svn_path, 'svn'))
# Register a handler for SIGTERM so we can have a chance to
# cleanup. If ViewVC takes too long to start generating CGI
# output, Apache will grow impatient and SIGTERM it. While we
# don't mind getting told to bail, we want to gracefully close the
# repository before we bail.
def _sigterm_handler(signum, frame, self=self):
self._close()
sys.exit(-1)
try:
signal.signal(signal.SIGTERM, _sigterm_handler)
except ValueError:
# This is probably "ValueError: signal only works in main
# thread", which will get thrown by the likes of mod_python
# when trying to install a signal handler from a thread that
# isn't the main one. We'll just not care.
pass
# Initialize APR and get our top-level pool.
core.apr_initialize()
self.apr_init = 1
self.pool = core.svn_pool_create(None)
self.scratch_pool = core.svn_pool_create(self.pool)
# Open the repository and init some other variables.
self.repos = repos.svn_repos_open(rootpath, self.pool)
self.fs_ptr = repos.svn_repos_fs(self.repos)
self.youngest = fs.youngest_rev(self.fs_ptr, self.pool)
self._fsroots = {}
def __del__(self):
self._close()
def _close(self):
if self.pool:
core.svn_pool_destroy(self.pool)
self.pool = None
if self.apr_init:
core.apr_terminate()
self.apr_init = 0
def _scratch_clear(self):
core.svn_pool_clear(self.scratch_pool)
def itemtype(self, path_parts, rev):
rev = self._getrev(rev)
basepath = self._getpath(path_parts)
kind = fs.check_path(self._getroot(rev), basepath, self.scratch_pool)
self._scratch_clear()
if kind == core.svn_node_dir:
return vclib.DIR
if kind == core.svn_node_file:
return vclib.FILE
raise vclib.ItemNotFound(path_parts)
def openfile(self, path_parts, rev):
path = self._getpath(path_parts)
rev = self._getrev(rev)
fsroot = self._getroot(rev)
revision = str(_get_last_history_rev(fsroot, path, self.scratch_pool))
self._scratch_clear()
fp = FileContentsPipe(fsroot, path, self.pool)
return fp, revision
def listdir(self, path_parts, rev, options):
basepath = self._getpath(path_parts)
if self.itemtype(path_parts, rev) != vclib.DIR:
raise vclib.Error("Path '%s' is not a directory." % basepath)
rev = self._getrev(rev)
fsroot = self._getroot(rev)
dirents = fs.dir_entries(fsroot, basepath, self.scratch_pool)
entries = [ ]
for entry in dirents.values():
if entry.kind == core.svn_node_dir:
kind = vclib.DIR
elif entry.kind == core.svn_node_file:
kind = vclib.FILE
entries.append(vclib.DirEntry(entry.name, kind))
self._scratch_clear()
return entries
def dirlogs(self, path_parts, rev, entries, options):
get_logs(self, self._getpath(path_parts), self._getrev(rev), entries)
def itemlog(self, path_parts, rev, options):
"""see vclib.Repository.itemlog docstring
Option values recognized by this implementation
svn_show_all_dir_logs
boolean, default false. if set for a directory path, will include
revisions where files underneath the directory have changed
svn_cross_copies
boolean, default false. if set for a path created by a copy, will
include revisions from before the copy
svn_latest_log
boolean, default false. if set will return only newest single log
entry
"""
path = self._getpath(path_parts)
rev = self._getrev(rev)
revs = _fetch_log(self, path, rev, options, self.scratch_pool)
self._scratch_clear()
revs.sort()
prev = None
for rev in revs:
rev.prev = prev
prev = rev
return revs
def annotate(self, path_parts, rev):
path = self._getpath(path_parts)
rev = self._getrev(rev)
fsroot = self._getroot(rev)
history_set = _get_history(self, path, rev, {'svn_cross_copies': 1})
history_revs = history_set.keys()
history_revs.sort()
revision = history_revs[-1]
first_rev = history_revs[0]
source = BlameSource(self.svn_client_path, self.rootpath,
path, rev, first_rev)
return source, revision
def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
p1 = self._getpath(path_parts1)
p2 = self._getpath(path_parts2)
r1 = self._getrev(rev1)
r2 = self._getrev(rev2)
args = vclib._diff_args(type, options)
try:
temp1 = temp_checkout(self, p1, r1, self.pool)
temp2 = temp_checkout(self, p2, r2, self.pool)
info1 = p1, date_from_rev(self, r1), r1
info2 = p2, date_from_rev(self, r2), r2
return vclib._diff_fp(temp1, temp2, info1, info2, args)
except vclib.svn.core.SubversionException, e:
if e.apr_err == vclib.svn.core.SVN_ERR_FS_NOT_FOUND:
raise vclib.InvalidRevision
raise
def _getpath(self, path_parts):
return string.join(path_parts, '/')
def _getrev(self, rev):
if rev is None or rev == 'HEAD':
return self.youngest
try:
rev = int(rev)
except ValueError:
raise vclib.InvalidRevision(rev)
if (rev < 0) or (rev > self.youngest):
raise vclib.InvalidRevision(rev)
return rev
def _getroot(self, rev):
try:
return self._fsroots[rev]
except KeyError:
r = self._fsroots[rev] = fs.revision_root(self.fs_ptr, rev, self.pool)
return r
class _item:
def __init__(self, **kw):
vars(self).update(kw)
import svn_repos
return svn_repos.LocalSubversionRepository(name, rootpath, authorizer,
utilities, config_dir)

812
lib/vclib/svn/svn_ra.py Normal file
View File

@@ -0,0 +1,812 @@
# -*-python-*-
#
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
"Version Control lib driver for remotely accessible Subversion repositories."
import vclib
import sys
import os
import re
import tempfile
import time
import urllib
from svn_repos import Revision, SVNChangedPath, _datestr_to_date, \
_compare_paths, _path_parts, _cleanup_path, \
_rev2optrev, _fix_subversion_exception, \
_split_revprops, _canonicalize_path
from svn import core, delta, client, wc, ra
### Require Subversion 1.3.1 or better. (for svn_ra_get_locations support)
if (core.SVN_VER_MAJOR, core.SVN_VER_MINOR, core.SVN_VER_PATCH) < (1, 3, 1):
raise Exception, "Version requirement not met (needs 1.3.1 or better)"
### BEGIN COMPATABILITY CODE ###
try:
SVN_INVALID_REVNUM = core.SVN_INVALID_REVNUM
except AttributeError: # The 1.4.x bindings are missing core.SVN_INVALID_REVNUM
SVN_INVALID_REVNUM = -1
def list_directory(url, peg_rev, rev, flag, ctx):
try:
dirents, locks = client.svn_client_ls3(url, peg_rev, rev, flag, ctx)
except TypeError: # 1.4.x bindings are goofed
dirents = client.svn_client_ls3(None, url, peg_rev, rev, flag, ctx)
locks = {}
return dirents, locks
def get_directory_props(ra_session, path, rev):
try:
dirents, fetched_rev, props = ra.svn_ra_get_dir(ra_session, path, rev)
except ValueError: # older bindings are goofed
props = ra.svn_ra_get_dir(ra_session, path, rev)
return props
def client_log(url, start_rev, end_rev, log_limit, include_changes,
cross_copies, cb_func, ctx):
include_changes = include_changes and 1 or 0
cross_copies = cross_copies and 1 or 0
try:
client.svn_client_log4([url], start_rev, start_rev, end_rev,
log_limit, include_changes, not cross_copies,
0, None, cb_func, ctx)
except AttributeError:
# Wrap old svn_log_message_receiver_t interface with a
# svn_log_entry_t one.
def cb_convert(paths, revision, author, date, message, pool):
class svn_log_entry_t:
pass
log_entry = svn_log_entry_t()
log_entry.changed_paths = paths
log_entry.revision = revision
log_entry.revprops = { core.SVN_PROP_REVISION_LOG : message,
core.SVN_PROP_REVISION_AUTHOR : author,
core.SVN_PROP_REVISION_DATE : date,
}
cb_func(log_entry, pool)
client.svn_client_log2([url], start_rev, end_rev, log_limit,
include_changes, not cross_copies, cb_convert, ctx)
def setup_client_ctx(config_dir):
# Ensure that the configuration directory exists.
core.svn_config_ensure(config_dir)
# Fetch the configuration (and 'config' bit thereof).
cfg = core.svn_config_get_config(config_dir)
config = cfg.get(core.SVN_CONFIG_CATEGORY_CONFIG)
# Here's the compat-sensitive part: try to use
# svn_cmdline_create_auth_baton(), and fall back to making our own
# if that fails.
try:
auth_baton = core.svn_cmdline_create_auth_baton(1, None, None, config_dir,
1, 1, config, None)
except AttributeError:
auth_baton = core.svn_auth_open([
client.svn_client_get_simple_provider(),
client.svn_client_get_username_provider(),
client.svn_client_get_ssl_server_trust_file_provider(),
client.svn_client_get_ssl_client_cert_file_provider(),
client.svn_client_get_ssl_client_cert_pw_file_provider(),
])
if config_dir is not None:
core.svn_auth_set_parameter(auth_baton,
core.SVN_AUTH_PARAM_CONFIG_DIR,
config_dir)
# Create, setup, and return the client context baton.
ctx = client.svn_client_create_context()
ctx.config = cfg
ctx.auth_baton = auth_baton
return ctx
### END COMPATABILITY CODE ###
class LogCollector:
def __init__(self, path, show_all_logs, lockinfo, access_check_func):
# This class uses leading slashes for paths internally
if not path:
self.path = '/'
else:
self.path = path[0] == '/' and path or '/' + path
self.logs = []
self.show_all_logs = show_all_logs
self.lockinfo = lockinfo
self.access_check_func = access_check_func
self.done = False
def add_log(self, log_entry, pool):
if self.done:
return
paths = log_entry.changed_paths
revision = log_entry.revision
msg, author, date, revprops = _split_revprops(log_entry.revprops)
# Changed paths have leading slashes
changed_paths = paths.keys()
changed_paths.sort(lambda a, b: _compare_paths(a, b))
this_path = None
if self.path in changed_paths:
this_path = self.path
change = paths[self.path]
if change.copyfrom_path:
this_path = change.copyfrom_path
for changed_path in changed_paths:
if changed_path != self.path:
# If a parent of our path was copied, our "next previous"
# (huh?) path will exist elsewhere (under the copy source).
if (self.path.rfind(changed_path) == 0) and \
self.path[len(changed_path)] == '/':
change = paths[changed_path]
if change.copyfrom_path:
this_path = change.copyfrom_path + self.path[len(changed_path):]
if self.show_all_logs or this_path:
if self.access_check_func is None \
or self.access_check_func(self.path[1:], revision):
entry = Revision(revision, date, author, msg, None, self.lockinfo,
self.path[1:], None, None)
self.logs.append(entry)
else:
self.done = True
if this_path:
self.path = this_path
def cat_to_tempfile(svnrepos, path, rev):
"""Check out file revision to temporary file"""
temp = tempfile.mktemp()
stream = core.svn_stream_from_aprfile(temp)
url = svnrepos._geturl(path)
client.svn_client_cat(core.Stream(stream), url, _rev2optrev(rev),
svnrepos.ctx)
core.svn_stream_close(stream)
return temp
class SelfCleanFP:
def __init__(self, path):
self._fp = open(path, 'r')
self._path = path
self._eof = 0
def read(self, len=None):
if len:
chunk = self._fp.read(len)
else:
chunk = self._fp.read()
if chunk == '':
self._eof = 1
return chunk
def readline(self):
chunk = self._fp.readline()
if chunk == '':
self._eof = 1
return chunk
def readlines(self):
lines = self._fp.readlines()
self._eof = 1
return lines
def close(self):
self._fp.close()
os.remove(self._path)
def __del__(self):
self.close()
def eof(self):
return self._eof
class RemoteSubversionRepository(vclib.Repository):
def __init__(self, name, rootpath, authorizer, utilities, config_dir):
self.name = name
self.rootpath = rootpath
self.auth = authorizer
self.diff_cmd = utilities.diff or 'diff'
self.config_dir = config_dir or None
# See if this repository is even viewable, authz-wise.
if not vclib.check_root_access(self):
raise vclib.ReposNotFound(name)
def open(self):
# Setup the client context baton, complete with non-prompting authstuffs.
self.ctx = setup_client_ctx(self.config_dir)
ra_callbacks = ra.svn_ra_callbacks_t()
ra_callbacks.auth_baton = self.ctx.auth_baton
self.ra_session = ra.svn_ra_open(self.rootpath, ra_callbacks, None,
self.ctx.config)
self.youngest = ra.svn_ra_get_latest_revnum(self.ra_session)
self._dirent_cache = { }
self._revinfo_cache = { }
# See if a universal read access determination can be made.
if self.auth and self.auth.check_universal_access(self.name) == 1:
self.auth = None
def rootname(self):
return self.name
def rootpath(self):
return self.rootpath
def roottype(self):
return vclib.SVN
def authorizer(self):
return self.auth
def itemtype(self, path_parts, rev):
pathtype = None
if not len(path_parts):
pathtype = vclib.DIR
else:
path = self._getpath(path_parts)
rev = self._getrev(rev)
try:
kind = ra.svn_ra_check_path(self.ra_session, path, rev)
if kind == core.svn_node_file:
pathtype = vclib.FILE
elif kind == core.svn_node_dir:
pathtype = vclib.DIR
except:
pass
if pathtype is None:
raise vclib.ItemNotFound(path_parts)
if not vclib.check_path_access(self, path_parts, pathtype, rev):
raise vclib.ItemNotFound(path_parts)
return pathtype
def openfile(self, path_parts, rev, options):
path = self._getpath(path_parts)
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file." % path)
rev = self._getrev(rev)
url = self._geturl(path)
### rev here should be the last history revision of the URL
fp = SelfCleanFP(cat_to_tempfile(self, path, rev))
lh_rev, c_rev = self._get_last_history_rev(path_parts, rev)
return fp, lh_rev
def listdir(self, path_parts, rev, options):
path = self._getpath(path_parts)
if self.itemtype(path_parts, rev) != vclib.DIR: # does auth-check
raise vclib.Error("Path '%s' is not a directory." % path)
rev = self._getrev(rev)
entries = []
dirents, locks = self._get_dirents(path, rev)
for name in dirents.keys():
entry = dirents[name]
if entry.kind == core.svn_node_dir:
kind = vclib.DIR
elif entry.kind == core.svn_node_file:
kind = vclib.FILE
else:
kind = None
entries.append(vclib.DirEntry(name, kind))
return entries
def dirlogs(self, path_parts, rev, entries, options):
path = self._getpath(path_parts)
if self.itemtype(path_parts, rev) != vclib.DIR: # does auth-check
raise vclib.Error("Path '%s' is not a directory." % path)
rev = self._getrev(rev)
dirents, locks = self._get_dirents(path, rev)
for entry in entries:
entry_path_parts = path_parts + [entry.name]
dirent = dirents.get(entry.name, None)
# dirents is authz-sanitized, so ensure the entry is found therein.
if dirent is None:
continue
# Get authz-sanitized revision metadata.
entry.date, entry.author, entry.log, revprops, changes = \
self._revinfo(dirent.created_rev)
entry.rev = str(dirent.created_rev)
entry.size = dirent.size
entry.lockinfo = None
if locks.has_key(entry.name):
entry.lockinfo = locks[entry.name].owner
def itemlog(self, path_parts, rev, sortby, first, limit, options):
assert sortby == vclib.SORTBY_DEFAULT or sortby == vclib.SORTBY_REV
path_type = self.itemtype(path_parts, rev) # does auth-check
path = self._getpath(path_parts)
rev = self._getrev(rev)
url = self._geturl(path)
# If this is a file, fetch the lock status and size (as of REV)
# for this item.
lockinfo = size_in_rev = None
if path_type == vclib.FILE:
basename = path_parts[-1]
list_url = self._geturl(self._getpath(path_parts[:-1]))
dirents, locks = list_directory(list_url, _rev2optrev(rev),
_rev2optrev(rev), 0, self.ctx)
if locks.has_key(basename):
lockinfo = locks[basename].owner
if dirents.has_key(basename):
size_in_rev = dirents[basename].size
# Special handling for the 'svn_latest_log' scenario.
### FIXME: Don't like this hack. We should just introduce
### something more direct in the vclib API.
if options.get('svn_latest_log', 0):
dir_lh_rev, dir_c_rev = self._get_last_history_rev(path_parts, rev)
date, author, log, revprops, changes = self._revinfo(dir_lh_rev)
return [vclib.Revision(dir_lh_rev, str(dir_lh_rev), date, author,
None, log, size_in_rev, lockinfo)]
def _access_checker(check_path, check_rev):
return vclib.check_path_access(self, _path_parts(check_path),
path_type, check_rev)
# It's okay if we're told to not show all logs on a file -- all
# the revisions should match correctly anyway.
lc = LogCollector(path, options.get('svn_show_all_dir_logs', 0),
lockinfo, _access_checker)
cross_copies = options.get('svn_cross_copies', 0)
log_limit = 0
if limit:
log_limit = first + limit
client_log(url, _rev2optrev(rev), _rev2optrev(1), log_limit, 1,
cross_copies, lc.add_log, self.ctx)
revs = lc.logs
revs.sort()
prev = None
for rev in revs:
# Swap out revision info with stuff from the cache (which is
# authz-sanitized).
rev.date, rev.author, rev.log, revprops, changes \
= self._revinfo(rev.number)
rev.prev = prev
prev = rev
revs.reverse()
if len(revs) < first:
return []
if limit:
return revs[first:first+limit]
return revs
def itemprops(self, path_parts, rev):
path = self._getpath(path_parts)
path_type = self.itemtype(path_parts, rev) # does auth-check
rev = self._getrev(rev)
url = self._geturl(path)
pairs = client.svn_client_proplist2(url, _rev2optrev(rev),
_rev2optrev(rev), 0, self.ctx)
return pairs and pairs[0][1] or {}
def annotate(self, path_parts, rev, include_text=False):
path = self._getpath(path_parts)
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file." % path)
rev = self._getrev(rev)
url = self._geturl(path)
# Examine logs for the file to determine the oldest revision we are
# permitted to see.
log_options = {
'svn_cross_copies' : 1,
'svn_show_all_dir_logs' : 1,
}
revs = self.itemlog(path_parts, rev, vclib.SORTBY_REV, 0, 0, log_options)
oldest_rev = revs[-1].number
# Now calculate the annotation data. Note that we'll not
# inherently trust the provided author and date, because authz
# rules might necessitate that we strip that information out.
blame_data = []
def _blame_cb(line_no, revision, author, date,
line, pool, blame_data=blame_data):
prev_rev = None
if revision > 1:
prev_rev = revision - 1
# If we have an invalid revision, clear the date and author
# values. Otherwise, if we have authz filtering to do, use the
# revinfo cache to do so.
if revision < 0:
date = author = None
elif self.auth:
date, author, msg, revprops, changes = self._revinfo(revision)
# Strip text if the caller doesn't want it.
if not include_text:
line = None
blame_data.append(vclib.Annotation(line, line_no + 1, revision, prev_rev,
author, date))
client.blame2(url, _rev2optrev(rev), _rev2optrev(oldest_rev),
_rev2optrev(rev), _blame_cb, self.ctx)
return blame_data, rev
def revinfo(self, rev):
return self._revinfo(rev, 1)
def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
if path_parts1 is not None:
p1 = self._getpath(path_parts1)
r1 = self._getrev(rev1)
if not vclib.check_path_access(self, path_parts1, vclib.FILE, rev1):
raise vclib.ItemNotFound(path_parts1)
else:
p1 = None
if path_parts2 is not None:
if not p1:
raise vclib.ItemNotFound(parh_parts2)
p2 = self._getpath(path_parts2)
r2 = self._getrev(rev2)
if not vclib.check_path_access(self, path_parts2, vclib.FILE, rev2):
raise vclib.ItemNotFound(path_parts2)
else:
p2 = None
args = vclib._diff_args(type, options)
def _date_from_rev(rev):
date, author, msg, revprops, changes = self._revinfo(rev)
return date
try:
info1 = p1, _date_from_rev(r1), r1
info2 = p2, _date_from_rev(r2), r2
if p1:
temp1 = cat_to_tempfile(self, p1, r1)
else:
temp1 = '/dev/null'
if p2:
temp2 = cat_to_tempfile(self, p2, r2)
else:
temp2 = '/dev/null'
return vclib._diff_fp(temp1, temp2, info1, info2, self.diff_cmd, args)
except core.SubversionException, e:
_fix_subversion_exception(e)
if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
raise vclib.InvalidRevision
raise
def isexecutable(self, path_parts, rev):
props = self.itemprops(path_parts, rev) # does authz-check
return props.has_key(core.SVN_PROP_EXECUTABLE)
def filesize(self, path_parts, rev):
path = self._getpath(path_parts)
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file." % path)
rev = self._getrev(rev)
dirents, locks = self._get_dirents(self._getpath(path_parts[:-1]), rev)
dirent = dirents.get(path_parts[-1], None)
return dirent.size
def _getpath(self, path_parts):
return '/'.join(path_parts)
def _getrev(self, rev):
if rev is None or rev == 'HEAD':
return self.youngest
try:
if type(rev) == type(''):
while rev[0] == 'r':
rev = rev[1:]
rev = int(rev)
except:
raise vclib.InvalidRevision(rev)
if (rev < 0) or (rev > self.youngest):
raise vclib.InvalidRevision(rev)
return rev
def _geturl(self, path=None):
if not path:
return self.rootpath
path = self.rootpath + '/' + urllib.quote(path)
return _canonicalize_path(path)
def _get_dirents(self, path, rev):
"""Return a 2-type of dirents and locks, possibly reading/writing
from a local cache of that information. This functions performs
authz checks, stripping out unreadable dirents."""
dir_url = self._geturl(path)
path_parts = _path_parts(path)
if path:
key = str(rev) + '/' + path
else:
key = str(rev)
# Ensure that the cache gets filled...
dirents_locks = self._dirent_cache.get(key)
if not dirents_locks:
tmp_dirents, locks = list_directory(dir_url, _rev2optrev(rev),
_rev2optrev(rev), 0, self.ctx)
dirents = {}
for name, dirent in tmp_dirents.items():
dirent_parts = path_parts + [name]
kind = dirent.kind
if (kind == core.svn_node_dir or kind == core.svn_node_file) \
and vclib.check_path_access(self, dirent_parts,
kind == core.svn_node_dir \
and vclib.DIR or vclib.FILE, rev):
lh_rev, c_rev = self._get_last_history_rev(dirent_parts, rev)
dirent.created_rev = lh_rev
dirents[name] = dirent
dirents_locks = [dirents, locks]
self._dirent_cache[key] = dirents_locks
# ...then return the goodies from the cache.
return dirents_locks[0], dirents_locks[1]
def _get_last_history_rev(self, path_parts, rev):
"""Return the a 2-tuple which contains:
- the last interesting revision equal to or older than REV in
the history of PATH_PARTS.
- the created_rev of of PATH_PARTS as of REV."""
path = self._getpath(path_parts)
url = self._geturl(self._getpath(path_parts))
optrev = _rev2optrev(rev)
# Get the last-changed-rev.
revisions = []
def _info_cb(path, info, pool, retval=revisions):
revisions.append(info.last_changed_rev)
client.svn_client_info(url, optrev, optrev, _info_cb, 0, self.ctx)
last_changed_rev = revisions[0]
# Now, this object might not have been directly edited since the
# last-changed-rev, but it might have been the child of a copy.
# To determine this, we'll run a potentially no-op log between
# LAST_CHANGED_REV and REV.
lc = LogCollector(path, 1, None, None)
client_log(url, optrev, _rev2optrev(last_changed_rev), 1, 1, 0,
lc.add_log, self.ctx)
revs = lc.logs
if revs:
revs.sort()
return revs[0].number, last_changed_rev
else:
return last_changed_rev, last_changed_rev
def _revinfo_fetch(self, rev, include_changed_paths=0):
need_changes = include_changed_paths or self.auth
revs = []
def _log_cb(log_entry, pool, retval=revs):
# If Subversion happens to call us more than once, we choose not
# to care.
if retval:
return
revision = log_entry.revision
msg, author, date, revprops = _split_revprops(log_entry.revprops)
action_map = { 'D' : vclib.DELETED,
'A' : vclib.ADDED,
'R' : vclib.REPLACED,
'M' : vclib.MODIFIED,
}
# Easy out: if we won't use the changed-path info, just return a
# changes-less tuple.
if not need_changes:
return revs.append([date, author, msg, revprops, None])
# Subversion 1.5 and earlier didn't offer the 'changed_paths2'
# hash, and in Subversion 1.6, it's offered but broken.
try:
changed_paths = log_entry.changed_paths2
paths = (changed_paths or {}).keys()
except:
changed_paths = log_entry.changed_paths
paths = (changed_paths or {}).keys()
paths.sort(lambda a, b: _compare_paths(a, b))
# If we get this far, our caller needs changed-paths, or we need
# them for authz-related sanitization.
changes = []
found_readable = found_unreadable = 0
for path in paths:
change = changed_paths[path]
# svn_log_changed_path_t (which we might get instead of the
# svn_log_changed_path2_t we'd prefer) doesn't have the
# 'node_kind' member.
pathtype = None
if hasattr(change, 'node_kind'):
if change.node_kind == core.svn_node_dir:
pathtype = vclib.DIR
elif change.node_kind == core.svn_node_file:
pathtype = vclib.FILE
# svn_log_changed_path2_t only has the 'text_modified' and
# 'props_modified' bits in Subversion 1.7 and beyond. And
# svn_log_changed_path_t is without.
text_modified = props_modified = 0
if hasattr(change, 'text_modified'):
if change.text_modified == core.svn_tristate_true:
text_modified = 1
if hasattr(change, 'props_modified'):
if change.props_modified == core.svn_tristate_true:
props_modified = 1
# Wrong, diddily wrong wrong wrong. Can you say,
# "Manufacturing data left and right because it hurts to
# figure out the right stuff?"
action = action_map.get(change.action, vclib.MODIFIED)
if change.copyfrom_path and change.copyfrom_rev:
is_copy = 1
base_path = change.copyfrom_path
base_rev = change.copyfrom_rev
elif action == vclib.ADDED or action == vclib.REPLACED:
is_copy = 0
base_path = base_rev = None
else:
is_copy = 0
base_path = path
base_rev = revision - 1
# Check authz rules (sadly, we have to lie about the path type)
parts = _path_parts(path)
if vclib.check_path_access(self, parts, vclib.FILE, revision):
if is_copy and base_path and (base_path != path):
parts = _path_parts(base_path)
if not vclib.check_path_access(self, parts, vclib.FILE, base_rev):
is_copy = 0
base_path = None
base_rev = None
found_unreadable = 1
changes.append(SVNChangedPath(path, revision, pathtype, base_path,
base_rev, action, is_copy,
text_modified, props_modified))
found_readable = 1
else:
found_unreadable = 1
# If our caller doesn't want changed-path stuff, and we have
# the info we need to make an authz determination already,
# quit this loop and get on with it.
if (not include_changed_paths) and found_unreadable and found_readable:
break
# Filter unreadable information.
if found_unreadable:
msg = None
if not found_readable:
author = None
date = None
# Drop unrequested changes.
if not include_changed_paths:
changes = None
# Add this revision information to the "return" array.
retval.append([date, author, msg, revprops, changes])
optrev = _rev2optrev(rev)
client_log(self.rootpath, optrev, optrev, 1, need_changes, 0,
_log_cb, self.ctx)
return tuple(revs[0])
def _revinfo(self, rev, include_changed_paths=0):
"""Internal-use, cache-friendly revision information harvester."""
# Consult the revinfo cache first. If we don't have cached info,
# or our caller wants changed paths and we don't have those for
# this revision, go do the real work.
rev = self._getrev(rev)
cached_info = self._revinfo_cache.get(rev)
if not cached_info \
or (include_changed_paths and cached_info[4] is None):
cached_info = self._revinfo_fetch(rev, include_changed_paths)
self._revinfo_cache[rev] = cached_info
return cached_info
##--- custom --##
def get_youngest_revision(self):
return self.youngest
def get_location(self, path, rev, old_rev):
try:
results = ra.get_locations(self.ra_session, path, rev, [old_rev])
except core.SubversionException, e:
_fix_subversion_exception(e)
if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
raise vclib.ItemNotFound(path)
raise
try:
old_path = results[old_rev]
except KeyError:
raise vclib.ItemNotFound(path)
old_path = _cleanup_path(old_path)
old_path_parts = _path_parts(old_path)
# Check access (lying about path types)
if not vclib.check_path_access(self, old_path_parts, vclib.FILE, old_rev):
raise vclib.ItemNotFound(path)
return old_path
def created_rev(self, path, rev):
lh_rev, c_rev = self._get_last_history_rev(_path_parts(path), rev)
return lh_rev
def last_rev(self, path, peg_revision, limit_revision=None):
"""Given PATH, known to exist in PEG_REVISION, find the youngest
revision older than, or equal to, LIMIT_REVISION in which path
exists. Return that revision, and the path at which PATH exists in
that revision."""
# Here's the plan, man. In the trivial case (where PEG_REVISION is
# the same as LIMIT_REVISION), this is a no-brainer. If
# LIMIT_REVISION is older than PEG_REVISION, we can use Subversion's
# history tracing code to find the right location. If, however,
# LIMIT_REVISION is younger than PEG_REVISION, we suffer from
# Subversion's lack of forward history searching. Our workaround,
# ugly as it may be, involves a binary search through the revisions
# between PEG_REVISION and LIMIT_REVISION to find our last live
# revision.
peg_revision = self._getrev(peg_revision)
limit_revision = self._getrev(limit_revision)
if peg_revision == limit_revision:
return peg_revision, path
elif peg_revision > limit_revision:
path = self.get_location(path, peg_revision, limit_revision)
return limit_revision, path
else:
direction = 1
while peg_revision != limit_revision:
mid = (peg_revision + 1 + limit_revision) / 2
try:
path = self.get_location(path, peg_revision, mid)
except vclib.ItemNotFound:
limit_revision = mid - 1
else:
peg_revision = mid
return peg_revision, path
def get_symlink_target(self, path_parts, rev):
"""Return the target of the symbolic link versioned at PATH_PARTS
in REV, or None if that object is not a symlink."""
path = self._getpath(path_parts)
path_type = self.itemtype(path_parts, rev) # does auth-check
rev = self._getrev(rev)
url = self._geturl(path)
# Symlinks must be files with the svn:special property set on them
# and with file contents which read "link SOME_PATH".
if path_type != vclib.FILE:
return None
pairs = client.svn_client_proplist2(url, _rev2optrev(rev),
_rev2optrev(rev), 0, self.ctx)
props = pairs and pairs[0][1] or {}
if not props.has_key(core.SVN_PROP_SPECIAL):
return None
pathspec = ''
### FIXME: We're being a touch sloppy here, first by grabbing the
### whole file and then by checking only the first line
### of it.
fp = SelfCleanFP(cat_to_tempfile(self, path, rev))
pathspec = fp.readline()
fp.close()
if pathspec[:5] != 'link ':
return None
return pathspec[5:]

979
lib/vclib/svn/svn_repos.py Normal file
View File

@@ -0,0 +1,979 @@
# -*-python-*-
#
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
"Version Control lib driver for locally accessible Subversion repositories"
import vclib
import os
import os.path
import cStringIO
import time
import tempfile
import popen
import re
import urllib
from svn import fs, repos, core, client, delta, diff
### Require Subversion 1.3.1 or better.
if (core.SVN_VER_MAJOR, core.SVN_VER_MINOR, core.SVN_VER_PATCH) < (1, 3, 1):
raise Exception, "Version requirement not met (needs 1.3.1 or better)"
### Pre-1.5 Subversion doesn't have SVN_ERR_CEASE_INVOCATION
try:
_SVN_ERR_CEASE_INVOCATION = core.SVN_ERR_CEASE_INVOCATION
except:
_SVN_ERR_CEASE_INVOCATION = core.SVN_ERR_CANCELLED
### Pre-1.5 SubversionException's might not have the .msg and .apr_err members
def _fix_subversion_exception(e):
if not hasattr(e, 'apr_err'):
e.apr_err = e[1]
if not hasattr(e, 'message'):
e.message = e[0]
### Pre-1.4 Subversion doesn't have svn_path_canonicalize()
def _canonicalize_path(path):
try:
return core.svn_path_canonicalize(path)
except AttributeError:
return path
def _allow_all(root, path, pool):
"""Generic authz_read_func that permits access to all paths"""
return 1
def _path_parts(path):
return filter(None, path.split('/'))
def _cleanup_path(path):
"""Return a cleaned-up Subversion filesystem path"""
return '/'.join(_path_parts(path))
def _fs_path_join(base, relative):
return _cleanup_path(base + '/' + relative)
def _compare_paths(path1, path2):
path1_len = len (path1);
path2_len = len (path2);
min_len = min(path1_len, path2_len)
i = 0
# Are the paths exactly the same?
if path1 == path2:
return 0
# Skip past common prefix
while (i < min_len) and (path1[i] == path2[i]):
i = i + 1
# Children of paths are greater than their parents, but less than
# greater siblings of their parents
char1 = '\0'
char2 = '\0'
if (i < path1_len):
char1 = path1[i]
if (i < path2_len):
char2 = path2[i]
if (char1 == '/') and (i == path2_len):
return 1
if (char2 == '/') and (i == path1_len):
return -1
if (i < path1_len) and (char1 == '/'):
return -1
if (i < path2_len) and (char2 == '/'):
return 1
# Common prefix was skipped above, next character is compared to
# determine order
return cmp(char1, char2)
def _rev2optrev(rev):
assert type(rev) is int
rt = core.svn_opt_revision_t()
rt.kind = core.svn_opt_revision_number
rt.value.number = rev
return rt
def _rootpath2url(rootpath, path):
rootpath = os.path.abspath(rootpath)
drive, rootpath = os.path.splitdrive(rootpath)
if os.sep != '/':
rootpath = rootpath.replace(os.sep, '/')
rootpath = urllib.quote(rootpath)
path = urllib.quote(path)
if drive:
url = 'file:///' + drive + rootpath + '/' + path
else:
url = 'file://' + rootpath + '/' + path
return _canonicalize_path(url)
# Given a dictionary REVPROPS of revision properties, pull special
# ones out of them and return a 4-tuple containing the log message,
# the author, the date (converted from the date string property), and
# a dictionary of any/all other revprops.
def _split_revprops(revprops):
if not revprops:
return None, None, None, {}
special_props = []
for prop in core.SVN_PROP_REVISION_LOG, \
core.SVN_PROP_REVISION_AUTHOR, \
core.SVN_PROP_REVISION_DATE:
if revprops.has_key(prop):
special_props.append(revprops[prop])
del(revprops[prop])
else:
special_props.append(None)
msg, author, datestr = tuple(special_props)
date = _datestr_to_date(datestr)
return msg, author, date, revprops
def _datestr_to_date(datestr):
try:
return core.svn_time_from_cstring(datestr) / 1000000
except:
return None
class Revision(vclib.Revision):
"Hold state for each revision's log entry."
def __init__(self, rev, date, author, msg, size, lockinfo,
filename, copy_path, copy_rev):
vclib.Revision.__init__(self, rev, str(rev), date, author, None,
msg, size, lockinfo)
self.filename = filename
self.copy_path = copy_path
self.copy_rev = copy_rev
class NodeHistory:
"""An iterable object that returns 2-tuples of (revision, path)
locations along a node's change history, ordered from youngest to
oldest."""
def __init__(self, fs_ptr, show_all_logs, limit=0):
self.histories = []
self.fs_ptr = fs_ptr
self.show_all_logs = show_all_logs
self.oldest_rev = None
self.limit = limit
def add_history(self, path, revision, pool):
# If filtering, only add the path and revision to the histories
# list if they were actually changed in this revision (where
# change means the path itself was changed, or one of its parents
# was copied). This is useful for omitting bubble-up directory
# changes.
if not self.oldest_rev:
self.oldest_rev = revision
else:
assert(revision < self.oldest_rev)
if not self.show_all_logs:
rev_root = fs.revision_root(self.fs_ptr, revision)
changed_paths = fs.paths_changed(rev_root)
paths = changed_paths.keys()
if path not in paths:
# Look for a copied parent
test_path = path
found = 0
while 1:
off = test_path.rfind('/')
if off < 0:
break
test_path = test_path[0:off]
if test_path in paths:
copyfrom_rev, copyfrom_path = fs.copied_from(rev_root, test_path)
if copyfrom_rev >= 0 and copyfrom_path:
found = 1
break
if not found:
return
self.histories.append([revision, _cleanup_path(path)])
if self.limit and len(self.histories) == self.limit:
raise core.SubversionException("", _SVN_ERR_CEASE_INVOCATION)
def __getitem__(self, idx):
return self.histories[idx]
def _get_last_history_rev(fsroot, path):
history = fs.node_history(fsroot, path)
history = fs.history_prev(history, 0)
history_path, history_rev = fs.history_location(history)
return history_rev
def temp_checkout(svnrepos, path, rev):
"""Check out file revision to temporary file"""
temp = tempfile.mktemp()
fp = open(temp, 'wb')
try:
root = svnrepos._getroot(rev)
stream = fs.file_contents(root, path)
try:
while 1:
chunk = core.svn_stream_read(stream, core.SVN_STREAM_CHUNK_SIZE)
if not chunk:
break
fp.write(chunk)
finally:
core.svn_stream_close(stream)
finally:
fp.close()
return temp
class FileContentsPipe:
def __init__(self, root, path):
self._stream = fs.file_contents(root, path)
self._eof = 0
def read(self, len=None):
chunk = None
if not self._eof:
if len is None:
buffer = cStringIO.StringIO()
try:
while 1:
hunk = core.svn_stream_read(self._stream, 8192)
if not hunk:
break
buffer.write(hunk)
chunk = buffer.getvalue()
finally:
buffer.close()
else:
chunk = core.svn_stream_read(self._stream, len)
if not chunk:
self._eof = 1
return chunk
def readline(self):
chunk = None
if not self._eof:
chunk, self._eof = core.svn_stream_readline(self._stream, '\n')
if not self._eof:
chunk = chunk + '\n'
if not chunk:
self._eof = 1
return chunk
def readlines(self):
lines = []
while True:
line = self.readline()
if not line:
break
lines.append(line)
return lines
def close(self):
return core.svn_stream_close(self._stream)
def eof(self):
return self._eof
class BlameSource:
def __init__(self, local_url, rev, first_rev, include_text, config_dir):
self.idx = -1
self.first_rev = first_rev
self.blame_data = []
self.include_text = include_text
ctx = client.svn_client_create_context()
core.svn_config_ensure(config_dir)
ctx.config = core.svn_config_get_config(config_dir)
ctx.auth_baton = core.svn_auth_open([])
try:
### TODO: Is this use of FIRST_REV always what we want? Should we
### pass 1 here instead and do filtering later?
client.blame3(local_url, _rev2optrev(rev), _rev2optrev(first_rev),
_rev2optrev(rev), diff.svn_diff_file_options_t(), True, self._blame_cb, ctx)
except core.SubversionException, e:
_fix_subversion_exception(e)
if e.apr_err == core.SVN_ERR_CLIENT_IS_BINARY_FILE:
raise vclib.NonTextualFileContents
raise
def _blame_cb(self, line_no, rev, author, date, text, pool):
prev_rev = None
if rev > self.first_rev:
prev_rev = rev - 1
if not self.include_text:
text = None
self.blame_data.append(vclib.Annotation(text, line_no + 1, rev,
prev_rev, author, None))
def __getitem__(self, idx):
if idx != self.idx + 1:
raise BlameSequencingError()
self.idx = idx
return self.blame_data[idx]
class BlameSequencingError(Exception):
pass
class SVNChangedPath(vclib.ChangedPath):
"""Wrapper around vclib.ChangedPath which handles path splitting."""
def __init__(self, path, rev, pathtype, base_path, base_rev,
action, copied, text_changed, props_changed):
path_parts = _path_parts(path or '')
base_path_parts = _path_parts(base_path or '')
vclib.ChangedPath.__init__(self, path_parts, rev, pathtype,
base_path_parts, base_rev, action,
copied, text_changed, props_changed)
class LocalSubversionRepository(vclib.Repository):
def __init__(self, name, rootpath, authorizer, utilities, config_dir):
if not (os.path.isdir(rootpath) \
and os.path.isfile(os.path.join(rootpath, 'format'))):
raise vclib.ReposNotFound(name)
# Initialize some stuff.
self.rootpath = rootpath
self.name = name
self.auth = authorizer
self.diff_cmd = utilities.diff or 'diff'
self.config_dir = config_dir or None
# See if this repository is even viewable, authz-wise.
if not vclib.check_root_access(self):
raise vclib.ReposNotFound(name)
def open(self):
# Open the repository and init some other variables.
self.repos = repos.svn_repos_open(self.rootpath)
self.fs_ptr = repos.svn_repos_fs(self.repos)
self.youngest = fs.youngest_rev(self.fs_ptr)
self._fsroots = {}
self._revinfo_cache = {}
# See if a universal read access determination can be made.
if self.auth and self.auth.check_universal_access(self.name) == 1:
self.auth = None
def rootname(self):
return self.name
def rootpath(self):
return self.rootpath
def roottype(self):
return vclib.SVN
def authorizer(self):
return self.auth
def itemtype(self, path_parts, rev):
rev = self._getrev(rev)
basepath = self._getpath(path_parts)
pathtype = self._gettype(basepath, rev)
if pathtype is None:
raise vclib.ItemNotFound(path_parts)
if not vclib.check_path_access(self, path_parts, pathtype, rev):
raise vclib.ItemNotFound(path_parts)
return pathtype
def openfile(self, path_parts, rev, options):
path = self._getpath(path_parts)
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file." % path)
rev = self._getrev(rev)
fsroot = self._getroot(rev)
revision = str(_get_last_history_rev(fsroot, path))
fp = FileContentsPipe(fsroot, path)
return fp, revision
def listdir(self, path_parts, rev, options):
path = self._getpath(path_parts)
if self.itemtype(path_parts, rev) != vclib.DIR: # does auth-check
raise vclib.Error("Path '%s' is not a directory." % path)
rev = self._getrev(rev)
fsroot = self._getroot(rev)
dirents = fs.dir_entries(fsroot, path)
entries = [ ]
for entry in dirents.values():
if entry.kind == core.svn_node_dir:
kind = vclib.DIR
elif entry.kind == core.svn_node_file:
kind = vclib.FILE
if vclib.check_path_access(self, path_parts + [entry.name], kind, rev):
entries.append(vclib.DirEntry(entry.name, kind))
return entries
def dirlogs(self, path_parts, rev, entries, options):
path = self._getpath(path_parts)
if self.itemtype(path_parts, rev) != vclib.DIR: # does auth-check
raise vclib.Error("Path '%s' is not a directory." % path)
fsroot = self._getroot(self._getrev(rev))
rev = self._getrev(rev)
for entry in entries:
entry_path_parts = path_parts + [entry.name]
if not vclib.check_path_access(self, entry_path_parts, entry.kind, rev):
continue
path = self._getpath(entry_path_parts)
entry_rev = _get_last_history_rev(fsroot, path)
date, author, msg, revprops, changes = self._revinfo(entry_rev)
entry.rev = str(entry_rev)
entry.date = date
entry.author = author
entry.log = msg
if entry.kind == vclib.FILE:
entry.size = fs.file_length(fsroot, path)
lock = fs.get_lock(self.fs_ptr, path)
entry.lockinfo = lock and lock.owner or None
def itemlog(self, path_parts, rev, sortby, first, limit, options):
"""see vclib.Repository.itemlog docstring
Option values recognized by this implementation
svn_show_all_dir_logs
boolean, default false. if set for a directory path, will include
revisions where files underneath the directory have changed
svn_cross_copies
boolean, default false. if set for a path created by a copy, will
include revisions from before the copy
svn_latest_log
boolean, default false. if set will return only newest single log
entry
"""
assert sortby == vclib.SORTBY_DEFAULT or sortby == vclib.SORTBY_REV
path = self._getpath(path_parts)
path_type = self.itemtype(path_parts, rev) # does auth-check
rev = self._getrev(rev)
revs = []
lockinfo = None
# See if this path is locked.
try:
lock = fs.get_lock(self.fs_ptr, path)
if lock:
lockinfo = lock.owner
except NameError:
pass
# If our caller only wants the latest log, we'll invoke
# _log_helper for just the one revision. Otherwise, we go off
# into history-fetching mode. ### TODO: we could stand to have a
# 'limit' parameter here as numeric cut-off for the depth of our
# history search.
if options.get('svn_latest_log', 0):
revision = self._log_helper(path, rev, lockinfo)
if revision:
revision.prev = None
revs.append(revision)
else:
history = self._get_history(path, rev, path_type, first + limit, options)
if len(history) < first:
history = []
if limit:
history = history[first:first+limit]
for hist_rev, hist_path in history:
revision = self._log_helper(hist_path, hist_rev, lockinfo)
if revision:
# If we have unreadable copyfrom data, obscure it.
if revision.copy_path is not None:
cp_parts = _path_parts(revision.copy_path)
if not vclib.check_path_access(self, cp_parts, path_type,
revision.copy_rev):
revision.copy_path = revision.copy_rev = None
revision.prev = None
if len(revs):
revs[-1].prev = revision
revs.append(revision)
return revs
def itemprops(self, path_parts, rev):
path = self._getpath(path_parts)
path_type = self.itemtype(path_parts, rev) # does auth-check
rev = self._getrev(rev)
fsroot = self._getroot(rev)
return fs.node_proplist(fsroot, path)
def annotate(self, path_parts, rev, include_text=False):
path = self._getpath(path_parts)
path_type = self.itemtype(path_parts, rev) # does auth-check
if path_type != vclib.FILE:
raise vclib.Error("Path '%s' is not a file." % path)
rev = self._getrev(rev)
fsroot = self._getroot(rev)
history = self._get_history(path, rev, path_type, 0,
{'svn_cross_copies': 1})
youngest_rev, youngest_path = history[0]
oldest_rev, oldest_path = history[-1]
source = BlameSource(_rootpath2url(self.rootpath, path), youngest_rev,
oldest_rev, include_text, self.config_dir)
return source, youngest_rev
def revinfo(self, rev):
return self._revinfo(rev, 1)
def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
if path_parts1:
p1 = self._getpath(path_parts1)
r1 = self._getrev(rev1)
if not vclib.check_path_access(self, path_parts1, vclib.FILE, rev1):
raise vclib.ItemNotFound(path_parts1)
else:
p1 = None
if path_parts2:
p2 = self._getpath(path_parts2)
r2 = self._getrev(rev2)
if not vclib.check_path_access(self, path_parts2, vclib.FILE, rev2):
raise vclib.ItemNotFound(path_parts2)
else:
if not p1:
raise vclib.ItemNotFound(path_parts2)
p2 = None
args = vclib._diff_args(type, options)
def _date_from_rev(rev):
date, author, msg, revprops, changes = self._revinfo(rev)
return date
try:
if p1:
temp1 = temp_checkout(self, p1, r1)
info1 = p1, _date_from_rev(r1), r1
else:
temp1 = '/dev/null'
info1 = '/dev/null', _date_from_rev(rev1), rev1
if p2:
temp2 = temp_checkout(self, p2, r2)
info2 = p2, _date_from_rev(r2), r2
else:
temp2 = '/dev/null'
info2 = '/dev/null', _date_from_rev(rev2), rev2
return vclib._diff_fp(temp1, temp2, info1, info2, self.diff_cmd, args)
except core.SubversionException, e:
_fix_subversion_exception(e)
if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
raise vclib.InvalidRevision
if e.apr_err != _SVN_ERR_CEASE_INVOCATION:
raise
def isexecutable(self, path_parts, rev):
props = self.itemprops(path_parts, rev) # does authz-check
return props.has_key(core.SVN_PROP_EXECUTABLE)
def filesize(self, path_parts, rev):
path = self._getpath(path_parts)
if self.itemtype(path_parts, rev) != vclib.FILE: # does auth-check
raise vclib.Error("Path '%s' is not a file." % path)
fsroot = self._getroot(self._getrev(rev))
return fs.file_length(fsroot, path)
##--- helpers ---##
def _revinfo(self, rev, include_changed_paths=0):
"""Internal-use, cache-friendly revision information harvester."""
def _get_changed_paths(fsroot):
"""Return a 3-tuple: found_readable, found_unreadable, changed_paths."""
editor = repos.ChangeCollector(self.fs_ptr, fsroot)
e_ptr, e_baton = delta.make_editor(editor)
repos.svn_repos_replay(fsroot, e_ptr, e_baton)
changedpaths = {}
changes = editor.get_changes()
# Copy the Subversion changes into a new hash, checking
# authorization and converting them into ChangedPath objects.
found_readable = found_unreadable = 0
for path in changes.keys():
change = changes[path]
if change.path:
change.path = _cleanup_path(change.path)
if change.base_path:
change.base_path = _cleanup_path(change.base_path)
is_copy = 0
if not hasattr(change, 'action'): # new to subversion 1.4.0
action = vclib.MODIFIED
if not change.path:
action = vclib.DELETED
elif change.added:
action = vclib.ADDED
replace_check_path = path
if change.base_path and change.base_rev:
replace_check_path = change.base_path
if changedpaths.has_key(replace_check_path) \
and changedpaths[replace_check_path].action == vclib.DELETED:
action = vclib.REPLACED
else:
if change.action == repos.CHANGE_ACTION_ADD:
action = vclib.ADDED
elif change.action == repos.CHANGE_ACTION_DELETE:
action = vclib.DELETED
elif change.action == repos.CHANGE_ACTION_REPLACE:
action = vclib.REPLACED
else:
action = vclib.MODIFIED
if (action == vclib.ADDED or action == vclib.REPLACED) \
and change.base_path \
and change.base_rev:
is_copy = 1
if change.item_kind == core.svn_node_dir:
pathtype = vclib.DIR
elif change.item_kind == core.svn_node_file:
pathtype = vclib.FILE
else:
pathtype = None
parts = _path_parts(path)
if vclib.check_path_access(self, parts, pathtype, rev):
if is_copy and change.base_path and (change.base_path != path):
parts = _path_parts(change.base_path)
if not vclib.check_path_access(self, parts, pathtype,
change.base_rev):
is_copy = 0
change.base_path = None
change.base_rev = None
found_unreadable = 1
changedpaths[path] = SVNChangedPath(path, rev, pathtype,
change.base_path,
change.base_rev, action,
is_copy, change.text_changed,
change.prop_changes)
found_readable = 1
else:
found_unreadable = 1
return found_readable, found_unreadable, changedpaths.values()
def _get_change_copyinfo(fsroot, path, change):
# If we know the copyfrom info, return it...
if hasattr(change, 'copyfrom_known') and change.copyfrom_known:
copyfrom_path = change.copyfrom_path
copyfrom_rev = change.copyfrom_rev
# ...otherwise, if this change could be a copy (that is, it
# contains an add action), query the copyfrom info ...
elif (change.change_kind == fs.path_change_add or
change.change_kind == fs.path_change_replace):
copyfrom_rev, copyfrom_path = fs.copied_from(fsroot, path)
# ...else, there's no copyfrom info.
else:
copyfrom_rev = core.SVN_INVALID_REVNUM
copyfrom_path = None
return copyfrom_path, copyfrom_rev
def _simple_auth_check(fsroot):
"""Return a 2-tuple: found_readable, found_unreadable."""
found_unreadable = found_readable = 0
if hasattr(fs, 'paths_changed2'):
changes = fs.paths_changed2(fsroot)
else:
changes = fs.paths_changed(fsroot)
paths = changes.keys()
for path in paths:
change = changes[path]
pathtype = None
if hasattr(change, 'node_kind'):
if change.node_kind == core.svn_node_file:
pathtype = vclib.FILE
elif change.node_kind == core.svn_node_dir:
pathtype = vclib.DIR
parts = _path_parts(path)
if pathtype is None:
# Figure out the pathtype so we can query the authz subsystem.
if change.change_kind == fs.path_change_delete:
# Deletions are annoying, because they might be underneath
# copies (make their previous location non-trivial).
prev_parts = parts
prev_rev = rev - 1
parent_parts = parts[:-1]
while parent_parts:
parent_path = '/' + self._getpath(parent_parts)
parent_change = changes.get(parent_path)
if not (parent_change and \
(parent_change.change_kind == fs.path_change_add or
parent_change.change_kind == fs.path_change_replace)):
del(parent_parts[-1])
continue
copyfrom_path, copyfrom_rev = \
_get_change_copyinfo(fsroot, parent_path, parent_change)
if copyfrom_path:
prev_rev = copyfrom_rev
prev_parts = _path_parts(copyfrom_path) + \
parts[len(parent_parts):]
break
del(parent_parts[-1])
pathtype = self._gettype(self._getpath(prev_parts), prev_rev)
else:
pathtype = self._gettype(self._getpath(parts), rev)
if vclib.check_path_access(self, parts, pathtype, rev):
found_readable = 1
copyfrom_path, copyfrom_rev = \
_get_change_copyinfo(fsroot, path, change)
if copyfrom_path and copyfrom_path != path:
parts = _path_parts(copyfrom_path)
if not vclib.check_path_access(self, parts, pathtype,
copyfrom_rev):
found_unreadable = 1
else:
found_unreadable = 1
if found_readable and found_unreadable:
break
return found_readable, found_unreadable
def _revinfo_helper(rev, include_changed_paths):
# Get the revision property info. (Would use
# editor.get_root_props(), but something is broken there...)
revprops = fs.revision_proplist(self.fs_ptr, rev)
msg, author, date, revprops = _split_revprops(revprops)
# Optimization: If our caller doesn't care about the changed
# paths, and we don't need them to do authz determinations, let's
# get outta here.
if self.auth is None and not include_changed_paths:
return date, author, msg, revprops, None
# If we get here, then we either need the changed paths because we
# were asked for them, or we need them to do authorization checks.
#
# If we only need them for authorization checks, though, we
# won't bother generating fully populated ChangedPath items (the
# cost is too great).
fsroot = self._getroot(rev)
if include_changed_paths:
found_readable, found_unreadable, changedpaths = \
_get_changed_paths(fsroot)
else:
changedpaths = None
found_readable, found_unreadable = _simple_auth_check(fsroot)
# Filter our metadata where necessary, and return the requested data.
if found_unreadable:
msg = None
if not found_readable:
author = None
date = None
return date, author, msg, revprops, changedpaths
# Consult the revinfo cache first. If we don't have cached info,
# or our caller wants changed paths and we don't have those for
# this revision, go do the real work.
rev = self._getrev(rev)
cached_info = self._revinfo_cache.get(rev)
if not cached_info \
or (include_changed_paths and cached_info[4] is None):
cached_info = _revinfo_helper(rev, include_changed_paths)
self._revinfo_cache[rev] = cached_info
return tuple(cached_info)
def _log_helper(self, path, rev, lockinfo):
rev_root = fs.revision_root(self.fs_ptr, rev)
copyfrom_rev, copyfrom_path = fs.copied_from(rev_root, path)
date, author, msg, revprops, changes = self._revinfo(rev)
if fs.is_file(rev_root, path):
size = fs.file_length(rev_root, path)
else:
size = None
return Revision(rev, date, author, msg, size, lockinfo, path,
copyfrom_path and _cleanup_path(copyfrom_path),
copyfrom_rev)
def _get_history(self, path, rev, path_type, limit=0, options={}):
if self.youngest == 0:
return []
rev_paths = []
fsroot = self._getroot(rev)
show_all_logs = options.get('svn_show_all_dir_logs', 0)
if not show_all_logs:
# See if the path is a file or directory.
kind = fs.check_path(fsroot, path)
if kind is core.svn_node_file:
show_all_logs = 1
# Instantiate a NodeHistory collector object, and use it to collect
# history items for PATH@REV.
history = NodeHistory(self.fs_ptr, show_all_logs, limit)
try:
repos.svn_repos_history(self.fs_ptr, path, history.add_history,
1, rev, options.get('svn_cross_copies', 0))
except core.SubversionException, e:
_fix_subversion_exception(e)
if e.apr_err != _SVN_ERR_CEASE_INVOCATION:
raise
# Now, iterate over those history items, checking for changes of
# location, pruning as necessitated by authz rules.
for hist_rev, hist_path in history:
path_parts = _path_parts(hist_path)
if not vclib.check_path_access(self, path_parts, path_type, hist_rev):
break
rev_paths.append([hist_rev, hist_path])
return rev_paths
def _getpath(self, path_parts):
return '/'.join(path_parts)
def _getrev(self, rev):
if rev is None or rev == 'HEAD':
return self.youngest
try:
if type(rev) == type(''):
while rev[0] == 'r':
rev = rev[1:]
rev = int(rev)
except:
raise vclib.InvalidRevision(rev)
if (rev < 0) or (rev > self.youngest):
raise vclib.InvalidRevision(rev)
return rev
def _getroot(self, rev):
try:
return self._fsroots[rev]
except KeyError:
r = self._fsroots[rev] = fs.revision_root(self.fs_ptr, rev)
return r
def _gettype(self, path, rev):
# Similar to itemtype(), but without the authz check. Returns
# None for missing paths.
try:
kind = fs.check_path(self._getroot(rev), path)
except:
return None
if kind == core.svn_node_dir:
return vclib.DIR
if kind == core.svn_node_file:
return vclib.FILE
return None
##--- custom ---##
def get_youngest_revision(self):
return self.youngest
def get_location(self, path, rev, old_rev):
try:
results = repos.svn_repos_trace_node_locations(self.fs_ptr, path,
rev, [old_rev], _allow_all)
except core.SubversionException, e:
_fix_subversion_exception(e)
if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
raise vclib.ItemNotFound(path)
raise
try:
old_path = results[old_rev]
except KeyError:
raise vclib.ItemNotFound(path)
return _cleanup_path(old_path)
def created_rev(self, full_name, rev):
return fs.node_created_rev(self._getroot(rev), full_name)
def last_rev(self, path, peg_revision, limit_revision=None):
"""Given PATH, known to exist in PEG_REVISION, find the youngest
revision older than, or equal to, LIMIT_REVISION in which path
exists. Return that revision, and the path at which PATH exists in
that revision."""
# Here's the plan, man. In the trivial case (where PEG_REVISION is
# the same as LIMIT_REVISION), this is a no-brainer. If
# LIMIT_REVISION is older than PEG_REVISION, we can use Subversion's
# history tracing code to find the right location. If, however,
# LIMIT_REVISION is younger than PEG_REVISION, we suffer from
# Subversion's lack of forward history searching. Our workaround,
# ugly as it may be, involves a binary search through the revisions
# between PEG_REVISION and LIMIT_REVISION to find our last live
# revision.
peg_revision = self._getrev(peg_revision)
limit_revision = self._getrev(limit_revision)
try:
if peg_revision == limit_revision:
return peg_revision, path
elif peg_revision > limit_revision:
fsroot = self._getroot(peg_revision)
history = fs.node_history(fsroot, path)
while history:
path, peg_revision = fs.history_location(history)
if peg_revision <= limit_revision:
return peg_revision, _cleanup_path(path)
history = fs.history_prev(history, 1)
return peg_revision, _cleanup_path(path)
else:
orig_id = fs.node_id(self._getroot(peg_revision), path)
while peg_revision != limit_revision:
mid = (peg_revision + 1 + limit_revision) / 2
try:
mid_id = fs.node_id(self._getroot(mid), path)
except core.SubversionException, e:
_fix_subversion_exception(e)
if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
cmp = -1
else:
raise
else:
### Not quite right. Need a comparison function that only returns
### true when the two nodes are the same copy, not just related.
cmp = fs.compare_ids(orig_id, mid_id)
if cmp in (0, 1):
peg_revision = mid
else:
limit_revision = mid - 1
return peg_revision, path
finally:
pass
def get_symlink_target(self, path_parts, rev):
"""Return the target of the symbolic link versioned at PATH_PARTS
in REV, or None if that object is not a symlink."""
path = self._getpath(path_parts)
rev = self._getrev(rev)
path_type = self.itemtype(path_parts, rev) # does auth-check
fsroot = self._getroot(rev)
# Symlinks must be files with the svn:special property set on them
# and with file contents which read "link SOME_PATH".
if path_type != vclib.FILE:
return None
props = fs.node_proplist(fsroot, path)
if not props.has_key(core.SVN_PROP_SPECIAL):
return None
pathspec = ''
### FIXME: We're being a touch sloppy here, only checking the first line
### of the file.
stream = fs.file_contents(fsroot, path)
try:
pathspec, eof = core.svn_stream_readline(stream, '\n')
finally:
core.svn_stream_close(stream)
if pathspec[:5] != 'link ':
return None
return pathspec[5:]

View File

@@ -1,444 +0,0 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
"Version Control lib driver for remotely accessible Subversion repositories."
import vclib
import sys
import os
import string
import re
import tempfile
import popen2
import time
from vclib.svn import Revision, ChangedPath, _datestr_to_date, _compare_paths, _cleanup_path
from svn import core, delta, client, wc, ra
### Require Subversion 1.3.0 or better. (for svn_ra_get_locations support)
if (core.SVN_VER_MAJOR, core.SVN_VER_MINOR, core.SVN_VER_PATCH) < (1, 3, 0):
raise Exception, "Version requirement not met (needs 1.3.0 or better)"
def _rev2optrev(rev):
assert type(rev) is int
rt = core.svn_opt_revision_t()
rt.kind = core.svn_opt_revision_number
rt.value.number = rev
return rt
def date_from_rev(svnrepos, rev):
datestr = ra.svn_ra_rev_prop(svnrepos.ra_session, rev,
'svn:date', svnrepos.pool)
return _datestr_to_date(datestr, svnrepos.pool)
def get_location(svnrepos, path, rev, old_rev):
try:
results = ra.get_locations(svnrepos.ra_session, path, rev,
[old_rev], svnrepos.pool)
except core.SubversionException, e:
if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
raise vclib.ItemNotFound(path)
raise
try:
old_path = results[old_rev]
except KeyError:
raise vclib.ItemNotFound(path)
return _cleanup_path(old_path)
def last_rev(svnrepos, path, peg_revision, limit_revision=None):
"""Given PATH, known to exist in PEG_REVISION, find the youngest
revision older than, or equal to, LIMIT_REVISION in which path
exists. Return that revision, and the path at which PATH exists in
that revision."""
# Here's the plan, man. In the trivial case (where PEG_REVISION is
# the same as LIMIT_REVISION), this is a no-brainer. If
# LIMIT_REVISION is older than PEG_REVISION, we can use Subversion's
# history tracing code to find the right location. If, however,
# LIMIT_REVISION is younger than PEG_REVISION, we suffer from
# Subversion's lack of forward history searching. Our workaround,
# ugly as it may be, involves a binary search through the revisions
# between PEG_REVISION and LIMIT_REVISION to find our last live
# revision.
peg_revision = svnrepos._getrev(peg_revision)
limit_revision = svnrepos._getrev(limit_revision)
if peg_revision == limit_revision:
return peg_revision, path
elif peg_revision > limit_revision:
path = get_location(svnrepos, path, peg_revision, limit_revision)
return limit_revision, path
else:
### Warning: this is *not* an example of good pool usage.
direction = 1
while peg_revision != limit_revision:
mid = (peg_revision + 1 + limit_revision) / 2
try:
path = get_location(svnrepos, path, peg_revision, mid)
except vclib.ItemNotFound:
limit_revision = mid - 1
else:
peg_revision = mid
return peg_revision, path
def created_rev(svnrepos, full_name, rev):
kind = ra.svn_ra_check_path(svnrepos.ra_session, full_name, rev,
svnrepos.pool)
if kind == core.svn_node_dir:
props = ra.svn_ra_get_dir(svnrepos.ra_session, full_name,
rev, svnrepos.pool)
return int(props[core.SVN_PROP_ENTRY_COMMITTED_REV])
return core.SVN_INVALID_REVNUM
class LastHistoryCollector:
def __init__(self):
self.has_history = 0
def add_history(self, paths, revision, author, date, message, pool):
if not self.has_history:
self.has_history = 1
self.revision = revision
self.author = author
self.date = date
self.message = message
self.changes = []
if not paths:
return
changed_paths = paths.keys()
changed_paths.sort(lambda a, b: _compare_paths(a, b))
action_map = { 'D' : 'deleted',
'A' : 'added',
'R' : 'replaced',
'M' : 'modified',
}
for changed_path in changed_paths:
change = paths[changed_path]
action = action_map.get(change.action, 'modified')
### Wrong, diddily wrong wrong wrong. Can you say,
### "Manufacturing data left and right because it hurts to
### figure out the right stuff?"
if change.copyfrom_path and change.copyfrom_rev:
self.changes.append(ChangedPath(changed_path[1:], None, 0, 0,
change.copyfrom_path,
change.copyfrom_rev, action, 1))
else:
self.changes.append(ChangedPath(changed_path[1:], None, 0, 0,
changed_path[1:], 0, action, 0))
def get_history(self):
if not self.has_history:
return None, None, None, None, None
return self.revision, self.author, self.date, self.message, self.changes
def _get_rev_details(svnrepos, rev, pool):
lhc = LastHistoryCollector()
client.svn_client_log([svnrepos.rootpath],
_rev2optrev(rev), _rev2optrev(rev),
1, 0, lhc.add_history, svnrepos.ctx, pool)
return lhc.get_history()
def get_revision_info(svnrepos, rev):
rev, author, date, log, changes = \
_get_rev_details(svnrepos, rev, svnrepos.pool)
return _datestr_to_date(date, svnrepos.pool), author, log, changes
class LogCollector:
def __init__(self, path, show_all_logs):
# This class uses leading slashes for paths internally
if not path:
self.path = '/'
else:
self.path = path[0] == '/' and path or '/' + path
self.logs = []
self.show_all_logs = show_all_logs
def add_log(self, paths, revision, author, date, message, pool):
# Changed paths have leading slashes
changed_paths = paths.keys()
changed_paths.sort(lambda a, b: _compare_paths(a, b))
this_path = None
if self.path in changed_paths:
this_path = self.path
change = paths[self.path]
if change.copyfrom_path:
this_path = change.copyfrom_path
for changed_path in changed_paths:
if changed_path != self.path:
# If a parent of our path was copied, our "next previous"
# (huh?) path will exist elsewhere (under the copy source).
if (string.rfind(self.path, changed_path) == 0) and \
self.path[len(changed_path)] == '/':
change = paths[changed_path]
if change.copyfrom_path:
this_path = change.copyfrom_path + self.path[len(changed_path):]
if self.show_all_logs or this_path:
date = _datestr_to_date(date, pool)
entry = Revision(revision, date, author, message, None,
self.path[1:], None, None)
self.logs.append(entry)
if this_path:
self.path = this_path
def get_logs(svnrepos, full_name, rev, files):
dirents = svnrepos._get_dirents(full_name, rev)
subpool = core.svn_pool_create(svnrepos.pool)
rev_info_cache = { }
for file in files:
core.svn_pool_clear(subpool)
entry = dirents[file.name]
if rev_info_cache.has_key(entry.created_rev):
rev, author, date, log = rev_info_cache[entry.created_rev]
else:
### i think this needs some get_last_history action to be accurate
rev, author, date, log, changes = \
_get_rev_details(svnrepos, entry.created_rev, subpool)
rev_info_cache[entry.created_rev] = rev, author, date, log
file.rev = rev
file.author = author
file.date = _datestr_to_date(date, subpool)
file.log = log
file.size = entry.size
core.svn_pool_destroy(subpool)
def get_youngest_revision(svnrepos):
return svnrepos.youngest
def temp_checkout(svnrepos, path, rev, pool):
"""Check out file revision to temporary file"""
temp = tempfile.mktemp()
stream = core.svn_stream_from_aprfile(temp, pool)
url = svnrepos.rootpath + (path and '/' + path)
client.svn_client_cat(core.Stream(stream), url, _rev2optrev(rev),
svnrepos.ctx, pool)
core.svn_stream_close(stream)
return temp
class SelfCleanFP:
def __init__(self, path):
self._fp = open(path, 'r')
self._path = path
self._eof = 0
def read(self, len):
if len:
chunk = self._fp.read(len)
else:
chunk = self._fp.read()
if chunk == '':
self._eof = 1
return chunk
def readline(self):
chunk = self._fp.readline()
if chunk == '':
self._eof = 1
return chunk
def close(self):
self._fp.close()
os.remove(self._path)
def __del__(self):
self.close()
def eof(self):
return self._eof
class SubversionRepository(vclib.Repository):
def __init__(self, name, rootpath):
# Init the client app
core.apr_initialize()
pool = core.svn_pool_create(None)
core.svn_config_ensure(None, pool)
# Start populating our members
self.pool = pool
self.name = name
self.rootpath = rootpath
# Setup the client context baton, complete with non-prompting authstuffs.
ctx = client.svn_client_ctx_t()
providers = []
providers.append(client.svn_client_get_simple_provider(pool))
providers.append(client.svn_client_get_username_provider(pool))
providers.append(client.svn_client_get_ssl_server_trust_file_provider(pool))
providers.append(client.svn_client_get_ssl_client_cert_file_provider(pool))
providers.append(client.svn_client_get_ssl_client_cert_pw_file_provider(pool))
ctx.auth_baton = core.svn_auth_open(providers, pool)
ctx.config = core.svn_config_get_config(None, pool)
self.ctx = ctx
ra_callbacks = ra.svn_ra_callbacks_t()
ra_callbacks.auth_baton = ctx.auth_baton
self.ra_session = ra.svn_ra_open(self.rootpath, ra_callbacks, None,
ctx.config, pool)
self.youngest = ra.svn_ra_get_latest_revnum(self.ra_session, pool)
self._dirent_cache = { }
def __del__(self):
core.svn_pool_destroy(self.pool)
core.apr_terminate()
def itemtype(self, path_parts, rev):
path = self._getpath(path_parts[:-1])
rev = self._getrev(rev)
if not len(path_parts):
return vclib.DIR
dirents = self._get_dirents(path, rev)
try:
entry = dirents[path_parts[-1]]
if entry.kind == core.svn_node_dir:
return vclib.DIR
if entry.kind == core.svn_node_file:
return vclib.FILE
except KeyError:
raise vclib.ItemNotFound(path_parts)
def openfile(self, path_parts, rev):
rev = self._getrev(rev)
url = self.rootpath
if len(path_parts):
url = self.rootpath + '/' + self._getpath(path_parts)
tmp_file = tempfile.mktemp()
stream = core.svn_stream_from_aprfile(tmp_file, self.pool)
### rev here should be the last history revision of the URL
client.svn_client_cat(core.Stream(stream), url,
_rev2optrev(rev), self.ctx, self.pool)
core.svn_stream_close(stream)
return SelfCleanFP(tmp_file), rev
def listdir(self, path_parts, rev, options):
path = self._getpath(path_parts)
rev = self._getrev(rev)
entries = [ ]
dirents = self._get_dirents(path, rev)
for name in dirents.keys():
entry = dirents[name]
if entry.kind == core.svn_node_dir:
kind = vclib.DIR
elif entry.kind == core.svn_node_file:
kind = vclib.FILE
entries.append(vclib.DirEntry(name, kind))
return entries
def dirlogs(self, path_parts, rev, entries, options):
get_logs(self, self._getpath(path_parts), self._getrev(rev), entries)
def itemlog(self, path_parts, rev, options):
full_name = self._getpath(path_parts)
rev = self._getrev(rev)
# It's okay if we're told to not show all logs on a file -- all
# the revisions should match correctly anyway.
lc = LogCollector(full_name, options.get('svn_show_all_dir_logs', 0))
dir_url = self.rootpath
if full_name:
dir_url = dir_url + '/' + full_name
cross_copies = options.get('svn_cross_copies', 0)
client.svn_client_log([dir_url], _rev2optrev(rev), _rev2optrev(1),
1, not cross_copies, lc.add_log,
self.ctx, self.pool)
revs = lc.logs
revs.sort()
prev = None
for rev in revs:
rev.prev = prev
prev = rev
return revs
def annotate(self, path_parts, rev):
path = self._getpath(path_parts)
rev = self._getrev(rev)
url = self.rootpath + (path and '/' + path)
blame_data = []
def _blame_cb(line_no, revision, author, date,
line, pool, blame_data=blame_data):
prev_rev = None
if revision > 1:
prev_rev = revision - 1
blame_data.append(_item(text=line, line_number=line_no+1,
rev=revision, prev_rev=prev_rev,
author=author, date=None))
client.svn_client_blame(url, _rev2optrev(1), _rev2optrev(rev),
_blame_cb, self.ctx, self.pool)
return blame_data, rev
def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
p1 = self._getpath(path_parts1)
p2 = self._getpath(path_parts2)
r1 = self._getrev(rev1)
r2 = self._getrev(rev2)
args = vclib._diff_args(type, options)
try:
temp1 = temp_checkout(self, p1, r1, self.pool)
temp2 = temp_checkout(self, p2, r2, self.pool)
info1 = p1, date_from_rev(self, r1), r1
info2 = p2, date_from_rev(self, r2), r2
return vclib._diff_fp(temp1, temp2, info1, info2, args)
except vclib.svn.core.SubversionException, e:
if e.apr_err == vclib.svn.core.SVN_ERR_FS_NOT_FOUND:
raise vclib.InvalidRevision
raise
def _getpath(self, path_parts):
return string.join(path_parts, '/')
def _getrev(self, rev):
if rev is None or rev == 'HEAD':
return self.youngest
try:
rev = int(rev)
except ValueError:
raise vclib.InvalidRevision(rev)
if (rev < 0) or (rev > self.youngest):
raise vclib.InvalidRevision(rev)
return rev
def _get_dirents(self, path, rev):
if path:
key = str(rev) + '/' + path
dir_url = self.rootpath + '/' + path
else:
key = str(rev)
dir_url = self.rootpath
dirents = self._dirent_cache.get(key)
if dirents:
return dirents
dirents = client.svn_client_ls(dir_url, _rev2optrev(rev), 0,
self.ctx, self.pool)
self._dirent_cache[key] = dirents
return dirents
class _item:
def __init__(self, **kw):
vars(self).update(kw)

File diff suppressed because it is too large Load Diff

75
lib/viewvcmagic.py Normal file
View File

@@ -0,0 +1,75 @@
#!/usr/bin/python
import mimetypes
import magic
have_chardet = 0
try:
import chardet
have_chardet = 1
except: pass
class ContentMagic:
def __init__(self, encodings):
self.encodings = encodings.split(':')
self.mime_magic = None
self.errors = []
# Try to load magic
self.mime_magic = magic.open(magic.MAGIC_MIME_TYPE)
self.mime_magic.load()
# returns MIME type
def guess_mime(self, mime, filename, tempfile):
if mime == 'application/octet-stream':
mime = ''
if not mime and filename:
mime = mimetypes.guess_type(filename)[0]
if not mime and tempfile and self.mime_magic:
if type(tempfile) == type(''):
mime = self.mime_magic.file(tempfile)
else:
c = tempfile.read(4096)
mime = self.mime_magic.buffer(c)
return mime
# returns (utf8_content, charset)
def guess_charset(self, content):
# Try UTF-8
charset = 'utf-8'
try: content = content.decode('utf-8')
except: charset = None
if charset is None and have_chardet and len(content) > 64:
# Try to guess with chardet
try:
# Only detect on first 256KB if content is longer
if len(content) > 256*1024:
charset = chardet.detect(content[0:256*1024])
else:
charset = chardet.detect(content)
if charset and charset['encoding']:
charset = charset['encoding']
if charset == 'MacCyrillic':
# Silly MacCyr, try cp1251
try:
content = content.decode('windows-1251')
charset = 'windows-1251'
except: content = content.decode(charset)
else:
content = content.decode(charset)
except: charset = None
# Then try to guess primitively
if charset is None:
for charset in self.encodings:
try:
content = content.decode(charset)
break
except: charset = None
return (content, charset)
# guess and encode return value into UTF-8
def utf8(self, content):
(uni, charset) = self.guess_charset(content)
if charset:
return uni.encode('utf-8')
return content

View File

@@ -1,6 +1,6 @@
# -*-python-*-
#
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
@@ -14,9 +14,19 @@
#
# -----------------------------------------------------------------------
import os, sys, traceback, string, thread
import os, sys, traceback, thread
try:
import win32api
except ImportError, e:
raise ImportError, str(e) + """
Did you install the Python for Windows Extensions?
http://sourceforge.net/projects/pywin32/
"""
import win32process, win32pipe, win32con
import win32event, win32file, win32api, winerror
import win32event, win32file, winerror
import pywintypes, msvcrt
# Buffer size for spooling
@@ -30,9 +40,9 @@ def CommandLine(command, args):
"""Convert an executable path and a sequence of arguments into a command
line that can be passed to CreateProcess"""
cmd = "\"" + string.replace(command, "\"", "\"\"") + "\""
cmd = "\"" + command.replace("\"", "\"\"") + "\""
for arg in args:
cmd = cmd + " \"" + string.replace(arg, "\"", "\"\"") + "\""
cmd = cmd + " \"" + arg.replace("\"", "\"\"") + "\""
return cmd
def CreateProcess(cmd, hStdInput, hStdOutput, hStdError):
@@ -99,13 +109,13 @@ def CreatePipe(readInheritable, writeInheritable):
def File2FileObject(pipe, mode):
"""Make a C stdio file object out of a win32 file handle"""
if string.find(mode, 'r') >= 0:
if mode.find('r') >= 0:
wmode = os.O_RDONLY
elif string.find(mode, 'w') >= 0:
elif mode.find('w') >= 0:
wmode = os.O_WRONLY
if string.find(mode, 'b') >= 0:
if mode.find('b') >= 0:
wmode = wmode | os.O_BINARY
if string.find(mode, 't') >= 0:
if mode.find('t') >= 0:
wmode = wmode | os.O_TEXT
return os.fdopen(msvcrt.open_osfhandle(pipe.Detach(),wmode),mode)

View File

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

Some files were not shown because too many files have changed in this diff Show More